免費專欄推薦:小米 MIUI 系統工程師 的《從源碼角度看 Android》
今天推薦的是小米MIUI系統工程師 YogiAi 開設的《從源碼角度看 Android》免費專欄。
關於專欄介紹,作者是這麼寫的:
從源碼的角度看 Android,關注本專欄,你將可以同我一起遨遊其樂無窮的源碼世界。閱讀源碼的重要性我就不多言了,大家都懂。不過你可以想像有朝一日,通過自己對AOSP源碼的理解,讓自己口袋中的手機運行著自己修改編譯的系統,還是蠻激動的吧
以下為目前發布的從《源碼角度看 Android》 的九個文章標題和簡介,作者後續還將會不斷更新中(訂閱方式看文章末尾):
1、Android SharedPreferences 源碼視角
SharedPreferences是Android里最常用的數據持久化方式,其原理是在shared_prefs目錄下讀寫xml文件來存取數據的。關於這塊網上的文章很多,我就不重述了。簡單列舉下我自己畫的時序圖和一些我的使用建議,最後是容易發生ANR的總結。
2、從源碼角度看 traces.txt 是如何生成的
traces.txt 位於安卓系統下/data/anr目錄下,當系統中有應用出現ANR時,framework會在彈出Dialog的同時dump出當前各線程的堆棧情況,方便開發者分析出ANR的root cause。
ANR是Application Not Responsing 的簡稱,簡而言之,就是安卓系統內置提示用戶應用界面沒有反應的機制,是用來避免應用界面一直卡頓,增加系統用戶友好度的一種方式。
造成ANR的原因很多,都是因為在主線程執行任務太久阻塞了界面更新導致的,主要有以下幾類:
- Broadcast Timeout: 前台廣播執行超過10s, 後台廣播執行超過60s (要注意的是,只有串列的廣播才有超時機制,並行的廣播並不會超時,也就是說,如果廣播是動態註冊的,直接調用sendBroadcast觸發,如果主線程Looper中排在後面的Message不會觸發超時機制,那麼即時這個廣播是前台廣播,系統也永遠不會彈出框提示用戶超時了)
- Service Timeout: 前台服務之星超過20s, 後台服務之星超過200s
- Provider Timeout: 內容提供者,publish超過10s
- Input Timeout: 按鍵觸摸事件分發超過5s
能夠造成ANR的前提是任務是在主線程上執行的,執行什麼樣的任務主要有以下幾點:
- 執行耗時任務過久,如文件讀取或存儲,網路訪問獲取文件太耗時
- 線程被阻塞過久,或者乾脆出現了死鎖
- 線程飢餓,如Binder線程總共16個,Binder主線程佔有一個,剩餘的15個工作線程都被佔滿
- CPU飢餓,負載值過大,雖然代碼正常額但任務一直沒有來得及執行
那麼回到traces.txt文件,它到底包含了什麼信息可以幫助開發者找到ANR問題的根源呢。
在這篇文章,我先從一份traces.txt的日誌實例開始解析,然後再通過追蹤源碼來解釋traces.txt是如何生成的。
3、從源碼層解析 ContentService 如何實現數據變化監聽
ContentService 是 ContentResolver 的服務端,運行在 system_server 進程,為所有應用提供訪問 ContentProvider 數據介面。同時 ContentService 也提供監聽數據變化的介面,這篇文章將從源碼的角度去解析registerContentObserver 和 unregisterContentObserver 的流程。
4、從源碼角度看各種 Context
做應用開發的對Context的熟悉度應該是僅次於Activity和Service的。Context,英文名上下文場景,代表著對當前運行場景下的各種信息的一種封裝。例如,需要調用四大組件進行工作都要調用到Context,同時,通過Context也可以獲取到Resource, Display, Theme, AssetManager, WallPaperManager這些資源對象。
5、從源碼角度看 AMS.startProcessLocked
眾所周知,Android 系統是基於 Linux 內核的移動操作系統。而 Linux 又是通過 fork 來複制進程,複製的時候只是創建唯一識別符等輕量操作,真正對於資源的使用是藉助了寫時複製的機制(copy-on-write)。進程與線程的概念在 Linux 的世界中只有資源擁有的差別,本質上它們的內核實現都使用了 task_struct 這同一個結構體,都擁有著各自的 PID, PPID。
在 Android 自成的上層 framework 世界中,進程的概念被層層的封裝後已經很模糊了,基本開發者完成開發過程只需熟悉Activity, BroadcastReceiver, Service等四大組件的作用與使用場景,再加上網路訪問、數據存儲、UI 繪製等等組合而成的業務邏輯即可完成一個很不錯的應用。
然而研究 Android 的進程啟動時機與實現原理對於進階學習還是大有裨益的,不僅能夠學到進程線程的內功知識,也能夠學到設計大師的封裝奧妙。Android 應用進程的創建是通過 fork Zygote 進程來實現的,所以所有的應用進程的 PPID 都是 Zygote 的 PID。複製 Zygote 的實例後會得到一個虛擬機實例,除此之外,新建的進程還會獲取到一個消息循環、 Binder 的進程通信池以及一個 Binder 主線程。
在這一篇文章中,我將詳細解析Android 進程的創建過程。
6、從源碼角度看 Binder.linkToDeath
Android系統當中的Binder消息傳遞無處不在,從運行一個新應用到發送一個常見的TIME PICK廣播,再到註冊一個ContentObserver去監聽簡訊數據的變化,這些功能都需要使用到Binder通信。正如"凡人必有一死",system_server進程雖然只要手機保持開機狀態就會存在,但是普通應用無論優先順序多麼高,當系統內存匱乏、用戶手動殺死應用進程又或者是應用出現不能解決的BUG直接Force Close了。這時,作為進程通信服務端的應用既然死亡了,那麼對應的客戶端相應的服務端之前保存下來的數據就沒有必要保存了。否則的話,應用生老病死之間,如果手機一直不關機,system_server一直在存活期間也不清除死亡進程的遺留信息,那麼這樣的手機系統使用起來會造成內存泄露,系統資源會慢慢被耗盡直至用戶能察覺到的系統卡頓出現。
所以Binder進程通信必然需要一種死亡回調的機制,當通信服務端死亡後可以通知客戶端們來進行相關的清理工作。Android已經實現好了一套DeathRecipient機制,客戶端只要實現死亡回調binderDied方法並且調用linkToDeath方法,當服務端死亡時binderDied將會被調用。
7、從源碼角度看 CPU 相關日誌
安卓系統中,普通開發者常常遇到的是ANR(Application Not Responding)問題,即應用主線程沒有相應。根本的原因在於安卓框架特殊設定,將專門做UI相關的、用戶能夠敏銳察覺到的操作放在了一個專門的線程中,即主線程。一旦這個線程在規定的時間內沒有完成某個任務,如廣播onReceive,Activity跳轉,或者bindApplication,那麼框架就會產生所謂的ANR,彈出對話框,讓用戶選擇繼續等待或者殺死沒有完成任務的應用進程。
老生常談的說法是開發者在主線程中執行了耗時操作導致了任務執行時間太久,這樣的問題通常很好定位與解決,往往打個bugreport這個ANR的root cause就原形畢露了,再不濟我們也能夠通過LOG定位到耗時點。
今天我們講的是另一種常見的情況,這種情況往往是由於CPU硬體設備的落後、底層CPU調控策略不當導致的。這種問題很惱人,明明按照常理絕對不會出現耗時的地方因為它也能夠出現ANR和卡頓,給用戶帶來極其糟糕的體驗。
8、從源碼角度看廣播
幾乎每個安卓應用都無可避免的使用到廣播。例如監聽WIFI的開啟狀態、時間的獲取,甚至是我們最常用的鬧鐘功能,都是結合著AlarmManager與廣播來實現的。理解廣播的註冊、發送與接收實現源碼將使我們更加懂安卓系統,同時,基於對廣播的理解,我們也能很快的掌握AMS中其它組件的實現原理。
9、從源碼角度看 Activity 生命周期
Activity是幾乎所有初級安卓程序員必學的一個知識點。我們都知道安卓最大的特色就是它能夠呈現給用戶界面,使用戶能夠與應用程序交互,這其中最重要的基本類就是各個Activity。然而,很多安卓開發者以為自己熟知了Activity的生命周期與launchMode等等知識點,就以為自己理解了它們。然而事實上並不,安卓源碼中潛藏著十分複雜的邏輯支撐著Activity生命周期的變化。
本專欄是免費的,如果大家覺得好,給本文點贊。
轉後如何訂閱專欄呢?關注小專欄平台(點擊這裡掃描二維碼:),或者微信搜索小專欄平台,關注。然後回復「從源碼角度看 Android」或者回復「源碼」可以獲取本專欄訂閱地址。
推薦閱讀: