《深入探索Android熱修復技術原理》讀後感以及插件化思考

最近編輯於2019/02/17

主要介紹了阿里Sophix方案。

熱修復的概念:

AndroidManifest出現BUG是無法修復的,想增加四大組件,可通過預先在安裝包的AndroidManifest裏面埋入代理的組件,在每次新增組件時,通過預埋的代理組件實現與系統進程間的通信。

熱修復需要在補丁包中包含一個新邏輯的dex文件。

資源的修復,主要通過修改資源包的內容。

so庫修復是通過在加載時優先加載補丁包的so庫。

 

熱替換代碼修復:

Andfix底層替換的侷限性:Andfix是根據公開的Android源碼對ArtMethod結構體裏面的字段進行的修改。如果手機廠商修改了ArtMethod的結構體(其實是在結構體前面增加字段,編譯爲AOT機器碼後發生替換錯位),就會導致機型不支持。

而Sophix採用了整體替換ArtMethod的方案,就避免了手機廠商修改結構體的問題。但也帶來需要計算ArtMethod大小的問題,後來發現ArtMethod Array的地址是緊密排列的,通過相鄰兩個ArtMethod的起始地址的差值計算出ArtMethod的大小。優點只要以後ArtMethod數組仍是以線性結構排列,該方案仍能適用。

訪問權限的問題:通常是因爲類是由不同的Classloader加載導致的,可以通過反射或者採用冷啓動的方式來解決。

熱替換的侷限:因爲熱替換需要原有的類實例的結構不變。因此使用Sophix進行熱修復,想讓用戶體驗到熱替換,只能在原有類的方法裏修改或者新增一個原包不存在的新類(PS這樣會使代碼變亂,在上升級包前應該重新整理代碼)。還有其他一些侷限:比如儘量不要增加非靜態內部類、需要混淆配置加上-dontoptimize防止方法裁剪與內聯、防止因泛型類型擦除與多態矛盾而產生的橋接方法、基本不支持Lambda表達式、補丁類不能引用非public類。

 

冷啓動代碼修復:

QQ空間和Tinker的冷啓動方案與前面的熱部署模式不兼容,Sophix尋求一種既能無侵入打包又能做熱部署的補充解決方案。QQ空間使用的插樁(需要增加一個含有無關幫助類的dex,原dex中所有類的構造函數都引用這個類)會影響類加載效率。Tinker採用了把原有dex和補丁包裏的dex重新合併的方案,Sophix則採用去除基線包中的補丁類再加上補丁。Tinker對Application的處理是需要開發者將自己的Application替換成TinkerApplication,而Sophix直接再JNI層去除Application類的pre-verified標誌(需要Application用到的所有非系統類都和Application位於同一個dex裏,因爲Android官方multi-dex機制會自動將Application用到的類都打包到主dex中,所以只要把熱修復初始化放在attachBaseContext的最前面就行),同時Sophix提供了指定AndroidManifest的Application爲SophixStubApplication的方案(會解決一些入口類的問題,同時也不影響用戶通過設置SophixEntry自定義Application)。

Android APP的啓動順序:Application.attachBaseContext——>ContentProvider.onCreate——>Application.onCreate——>Activity.onCreate。

 

資源熱修復技術:

普遍的做法是參考Instant Run,把資源熱修復分爲兩步:

1、構造一個新的AssetManager,並通過反射調用addAssetPath,把這個完整的新資源包加入到AssetManager中。這樣就得到了一個含有所有新資源的AssetManager。

2、找到所有之前引用到原有AssetManager的地方,通過反射,把引用處替換爲新的AssetManager。

Sophix採用了另闢蹊徑的方案,主要是使補丁包的pacakage id爲0x66,使其不與已經加載的資源衝突(修改資源時,還需在代碼引用處做出相應修改,因爲原先的資源還是存在的)。

 

so庫熱修復技術:

由於so庫熱部署的種種限制,Sophix採用了反射注入重啓生效的冷啓動方案。

 

 

編輯於2019/02/18

插件化思考

插件化技術類似於熱修復技術,插件化更注重於多個插件的版本控制,也更注重於插件的即插即用(無需冷啓動更新),但也由於不涉及原類的修改使得即插即用成爲可能。

插件化也分爲so庫的加載、資源的加載、代碼的加載。

so庫的加載使用了System.load或者System.loadLibrary的方案,如同上面那本書中所講,實際是存在一定限制的。

資源的加載也是從參照Instant Run的方案(我的一個無侵入支持應用內以及插件式的安卓應用換膚框架就是採用的這種方案)到修改資源id的技術衍變。

由於無需修改原類,使得代碼的即插即用成爲可能。這是插件化着重研究的方面。簡單一點的如同上面熱修復技術提到的預先在安裝包的AndroidManifest裏面埋入代理的組件,在每次新增組件時,通過預埋的代理組件實現與系統進程間的通信。複雜一點主要是運用靜態代理進行Hook,或者動態代理進行Hook(Shawn_Dut 講解了Android 動態代理以及利用動態代理實現 ServiceHookGitHub上的源碼,只不過插件化需要Hook的對象很多以及一些其他細節問題需要考慮)。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章