深入學習Android:虛擬機&運行時
經常在知乎上看到一些「如何深入學習Android」之類的問題,我也曾經寫過一些答案:
- Android 程序猿如何繼續深入的研究技術層的知識?請教各位前輩指條明路
- Android Framework 如何學習,如何從應用深入到Framework
也有很多別的優秀的回答,但是我總覺得少了點什麼。相比於調像素改顏色做動畫,了解一些系統原理性的知識確實已經深入一步了,但是這還遠遠不夠:我們寫的Apk運行在虛擬機上,而虛擬機又運行在Linux內核上,如果就在虛擬機給我們提供的溫室裡面轉悠,怎麼能算是深入理解呢?
打個比方,談到Android View系統的原理,很多人或許會想到,布局解析流程,View繪製流程,事件傳遞機制,動畫實現原理,等等。但是,從根本上來講,我們App的Activity界面,是如何呈現在用戶面前的?那些個View,又是如何渲染到屏幕上的呢?我們事件的源頭是Window,那Window的事件又是怎麼來的?還有,我們經常講Binder通信機制,我也寫過一些文章(Binder學習指南)這些講解很多都只說明了通信的過程和大致原理,至於數據是如何從一個進程傳輸到另外一個進程的,這些細節我們都不清楚。
說到這裡,已經很清楚了:如果僅僅學習了Android Framework的Java層,並不能算作是「深入Android」,必須深入native層,才能把握整個系統的來龍去脈。眾所周知,Android開發已經趨於飽和,而Android系統上技術的應用也已經進入深水區,如要想提升自己的核心競爭力,必須花心思、花時間,去學習Android的虛擬機 & 運行時。
我相信,有很多小夥伴跟蹤Android Framwork源碼的時候跟著跟著就翻車了——一個native方法掛在那,並不知道裡面幹了些什麼。其實,你離系統真正的原理之間只有一步之遙,就如native和naive一樣;native方法有什麼可怕的呢?照跟不誤。下面,我給出一些我的學習路徑和學習經驗吧,希望能有幫助。
- Dex文件格式以及dalvik虛擬機指令。那些知名的反編譯工具smali/baksmali, apktool, dex2jar, jdgui, jadx, jeb...它們是如何工作的,原理是什麼?學完Dex文件格式以及dalvik虛擬機指令,再結合開源項目 jadx ,你會發現自己寫一個反編譯工具也並不是什麼難事。
- 類載入。也許你知道ClassLoader機制,了解雙親委派模型,但那不過是皮毛而已。你寫的代碼被打包進Apk之後,系統是如何把這個類載入到內存中並使用的?一個Apk中數萬個方法,查找會有效率問題嗎,如何提高查找以及載入速度?ClassNotFoundException,NoClassDefFoundError是怎麼發生的,他們有啥區別?QQ空間的插件機制preverify又是什麼,redex為什麼可以優化啟動速度?
- 進程管理 & 進程通信。當你按下電源鍵開機的時候,發生了什麼?當你點擊桌面App圖標的時候又發生了什麼?各式各樣的系統服務是如何工作的?系統殺進程的時候發生了什麼?從一個App切換到另外一個App又發生了什麼?進程優先順序又是如何確定的?也許你通過學習Java層的framework可以對這些問題說出個一二,但這些最終實現是在虛擬機裡面,在這裡你可以揭開它最神秘的面紗。
- 線程調度 你在Java層new Thread的時候發生了什麼?`Process.setThreadPriority` 與 `Thread.setPriority`有什麼區別?虛擬機線程與Linux內核線程有什麼關係,如何協調?如何讓一個線程獲取更多的調度時間?
- 內存管理 包括內存分配和垃圾回收(GC);創建一個對象的時候,背後發生了什麼?Java層可以操作內存嘛?Unsafe的原理又是啥?OOM是如何發生的,如何避免內存泄漏?當我們說對象已死的時候我們在說什麼?作為一個自動內存管理的平台,談性能優化怎麼能不談GC?GC會對應用程序的啟動有多大影響,如何減少甚至避免GC?
- 反射機制 一個對象是如何知道自己是誰,擁有哪些成員和方法的?為什麼大家都說避免使用反射,反射的開銷真的很大嗎?
- 本地介面(JNI) 我們使用native函數,那麼Java層到底是如何與C/C++通信的?我們在framework裡面見到的Java類裡面大量的`long mObject`有什麼作用(比如AssetManager/DisplayEventReceiver) ?native方法和別的方法調用有何不同,開銷如何呢?加密放so里就真的安全了?
- 虛擬機執行流程 這裡面的知識就相當有意思了,我們寫的代碼歸根結底是如何執行的?在Android上調用一個方法的開銷有多大?為什麼感覺TraceView不準?ART虛擬機上的那個AOT又是什麼,為什麼要這麼做?即時編譯又是個啥,為什麼dexposed對ART支持不好?熱更新在Android7上又會遇到什麼困難?如何實現native層的Hook?等等等等。
上面列舉了一些關鍵詞,你可以把這些關鍵詞拿去google,然後自己對著源碼尋找答案;也許你對C++很陌生,那麼就先了解一下C++的知識,特別智能指針,模版(不然根本看不懂)。如果你依然感覺陌生和恐懼,建議閱讀一下《彙編語言》以及《CSAPP》這兩本書,消除一下神秘感和陌生感;當然,我個人不太贊同未雨綢繆,既然決定了,天亮就出發吧,一邊學一邊打基礎,然後真正滴」深入」Android ^_^,如果依然有問題,歡迎與我交流 & 討論。
附參考資料:
- 《彙編語言(第3版)》 王爽【摘要 書評 試讀】圖書 這本書非常不錯,作者寫書的理念我非常認同,真正的循循善誘,循序漸進,學習起來非常舒服。看這本書並不意味著你真的要去寫彙編,讀彙編,而是培養一種底層的思維習慣——計算機的原理實際上非常簡單和樸素,這本書幫你消除對2進位,指令,數據,寄存器等的陌生感和恐懼感。
- 《C++ Primer(中文版)(第5版)》 斯坦利·李普曼 (Stanley B. Lippman), 約瑟·拉喬伊 (Josee Lajoie), 芭芭拉·默 (Barbara E. Moo), 王剛, 楊巨峰【摘要 書評 試讀】圖書 嗯,要學底層,怎麼能不懂C++呢?我覺得這是每一個程序員必須學習的一門語言,不懂C/C++,永遠無法深入底層。
- Dex文件格式
- Dalvik虛擬機指令
- JNI Tips
- 《深入理解Java虛擬機:JVM高級特性與最佳實踐(第2版)》 周志明【摘要 書評 試讀】圖書
- Dalvik源碼
- ART源碼
- 《Android Dalvik虛擬機結構及機制剖析(第2卷):Dalvik虛擬機各模塊機制分析》 吳艷霞, 張國印【摘要 書評 試讀】圖書 這本書怎麼說呢?dalvik已經成為歷史,而且書中措辭和用語也有很多不恰當的地方甚至有謬誤,但還是一本不錯的入門書。雖然dalvik已經廢棄,但是dalvik指令集長存,並且dalvik的實現相對簡單,可以先從dalvik入手來學習Android的運行時。
- 讀源碼mac可以選擇understand,當然AndroidXRef 也很不錯,但是它的回退和歷史功能堪憂,還是習慣understand/sourceinsight.
推薦閱讀: