筆記 深刻探索Android熱修復技術原理

阿里電子書《深刻探索Android熱修復技術原理》整理的筆記java


1.熱修復技術介紹

  1. 代碼修復兩大主要方案
    • 底層替換方案:限制較多,但時效性好,當即見效
    • 類加載方案時效性差,須要從新冷啓動才能見效,但限制少
  2. 代碼修復底層替換方案
    • 底層替換方案是在已經加載了的類中直接替換掉原有方法.
    • 不能對原有類進行方法和字段的增減,由於這樣將破壞原有類的結構.
    • 方法增減將致使這個類及整個Dex方法數的變化,伴隨着方法索引的變化,這樣訪問方法時就沒法正常的索引到正確的方法;
    • 字段增長或減小,全部字段的索引都會發生變化;
    • 傳統底層替換方案,都是直接依賴修改虛擬機方法實體中的具體字段.依據的是Android開源版本.若是廠商修改了虛擬機方法實體,替換機制就可能出問題;
  3. 代碼修復類加載方案
    • 類加載方案的原理是在app從新啓動後讓Classloader去加載新的類.
    • 在app運行到一半的時候,全部須要發生變動的類都已經被加載過,Android沒法對一個類進行卸載.若是不重啓,原來的類還在虛擬機中,就沒法加載新類.
    • 只有在下次重啓時候,在尚未走到業務邏輯前搶先加載補丁中的新類,後續訪問纔是新的類.
    • dex比較的最佳粒度,應該是在類的粒度
    • Sophix採用的也是全量合成dex的技術.能夠看作是dex文件級別的類插裝方案.Sophix對舊包與補丁包中classes.dex的順序進行了打破與重組,使得系統能夠天然地識別到這個順序,以實現類覆蓋的目的
  4. 資源修復
    • 市面上不少資源熱修復方案都採用了Instant Run的實現
    • Instant Run中資源修復步驟:
      1. 構造一個新的AssetManager,經過反射調用addAssetPath,把這個完整的新資源包加到AssetManager中.這樣就獲得一個含有全部新資源的AssetManager.
      2. 找到全部以前引用到AssetManager的地方,經過反射,將引用出替換爲AssetManager.
    • Sophix資源熱修復沒有采用Instant Run的技術,而是構造了一個package id 爲 0x66 的資源包,這個包裏只包含改變了的資源項,而後直接在原有AssetManager中addAssetPath這個包便可.無需變動AssetManager對象的引用.
      1. Sophix構造的補丁包的 package id 爲0x66,不與已經加載的 0x7f衝突,因此直接加入到已有的AssetManager中能夠直接使用.
      2. Sophix資源補丁包中,只包含新增資源,以及原有內容發生了改變的資源.
  5. SO庫修復:本質上是對native方法的修復和替換

Sophix採用的是相似類修復反射注入方式,把補丁so庫的路徑插入到nativeLibraryDirectories數組的最前面, 這樣加載so庫的時候就是補丁so庫而不是原來的so庫android

2.代碼熱修復技術

  1. 底層熱替換原理
    • Android的java運行環境,在4.4如下用的是dalvik虛擬機,4.4以上是art虛擬機.
    • 在各類Android熱修復方案中,Andfix即時生效.Andfix採用的方法是,在已經加載了的類中直接在native層替換掉全部方法,是在原來的類的基礎上進行修改的.
    • 以art,Android6.0爲例,每個Java方法在art中都對應着一個ArtMethod對象,ArtMethod記錄了這個Java方法的全部信息,包括所屬類,訪問權限,代碼執行地址等.
    • Andfix會將一箇舊Java方法對應的ArtMethod實例中的全部字段值替換爲新方法的值,這樣全部執行到舊方法的地方,都會取得新方法的執行入口,所屬class,方法索引,所屬dex.像調用舊方法同樣執行了新方法的邏輯.
  2. 底層熱替換兼容性根源
    • 市面上幾乎全部的native替換替換,都是寫死了ArtMethod結構體
    • 寫死的ArtMethod結構和Android開源版本中徹底一致,但各個廠家能夠對ArtMethod進行修改,那麼在修改過的設備上,市面上的native替換方案(將方案中寫死了的ArtMethod關聯的新方法的屬性賦值到設備中的ArtMethod實例)就會出現問題,由於兩個ArtMethod中相同字段的索引不一樣
  3. 突破底層熱替換兼容問題
    • native層面替換,實質是替換ArtMethod實例的全部字段.
    • 只要把ArtMethod做爲總體進行替換,便可解決兼容問題.
    • ArtMethod實例之間,是緊密線形排列的,因此一個ArtMethod的大小,就是其相鄰的兩個方法對應的ArtMethod實例的起始地址的差值.
  4. 包括Sophix在內的底層替換方案,都只能支持方法的替換,不支持補丁類中增減方法和字段
    • 補丁類中增減方法,會致使這個類及整個dex方法數的變化,方法數的變化伴隨方法索引的變化,這樣在調用方法時沒法正常的所引導正確的方法.
    • 補丁類中增減字段,也會致使全部字段的索引起生變化.
  5. 你說不知的Java
    • 內部類在編譯期會被編譯爲根外部類同樣的頂級類;
    • 非靜態內部類持有外部類的引用,靜態內部類不持有外部類的引用.因此android性能優化中建議自定義Handler的實現儘可能使用靜態內部類,防止外部類Activity類不能被回收致使內存泄漏. 自定義Handler使用靜態內部類避免內存泄漏
    • 內部類和外部類之間,訪問彼此的private屬性及方法,編譯期間:
      • 外部類訪問內部類的私有成員及方法,編譯期間自動爲內部類生成access&**方法
      • 內部類訪問外部類的private屬性及方法,編譯期間也會生成access&**方法提供給內部類
    • 同一個類及其內部類,若是老代碼沒有訪問對方的私有屬性/方法,新代碼有訪問對方的私有屬性/方法,若是不能避免生成access&的生成,就會致使方法數的變化,致使熱修復失敗.避免生成access&方法須要:
      • 外部類全部的屬性及方法改成public或protected;
      • 內部類全部的屬性及方法改成public或protected;
    • 在編譯期間,根據匿名內部類在外部類中出現的前後順序,匿名內部類的名稱依次累加:外部類名稱&數字
      • 外部類名稱是OutClass,其中對應的內部類在編譯期間的名稱依次是:OutClass&1,OutClass&2,-----
      • 爲了實現熱修復,外部類應該極力避免新增及減小匿名內部類;
      • 除非是新增匿名內部類到外部類的尾部,不會影響以前添加過的匿名內部類的名稱,否則會致使熱修復失效;
    • Java原始類型:double、float、byte、short、int、long、char、boolean
      • 若是一個常量的類型是Java原始類型,或String,爲了優化性能,應該用static final修飾;
      • static final 引用類型,沒有任何優化效果.
      • 由於 static final 修飾的原始類型及String常量,是在所屬類的初始化時賦值,直接在內存中讀取;
      • 而 static final 引用類型常量,初始化是在clinit方法中,本質上是經過sget-object指令去獲取值,從虛擬機運行性能上無任何優化;
  6. 市面上的冷啓動類加載實現方案
    • 1:採用dex插樁的方式,單獨放一個幫助類在獨立的dex中讓其餘類調用.最後加載補丁dex獲得dexFile對象,將dexFile做爲參數構建一個Element對象插入到dexElements數組最前面
    • 2:提供dex差量包,總體替換dex的方案:差量patch.dex和應用的classes.dex合成完整dex.加載完整dex獲得dexFile對象,做爲參數構建一個Element對象,而後總體替換掉舊的dexElements數組
    • 1的缺點是:Dalvik下影響類加載性能,Art下類地址寫死,致使必須包含父類及引用,補丁包很大
    • 2的缺點是:dex的合併,內存消耗在 vm heap 上,容易致使OOM,合併失敗
  7. Sophix採用的代碼修復冷啓動方案
    • Dalvik下使用全量Dex方案;
    • Art下本質上虛擬機已經支持多dex的加載,只要把補丁dex做爲主dex(classes)便可
  8. Sophix在Dalvik下全量Dex方案思路
    • 基線包dex裏面,去掉補丁包dex中包含的class;這樣補丁+去除了補丁中包含類的基線包,就等於新app中全部類;
    • Sophix並無把某個class的全部信息從基線dex中移除,僅僅移除了定義的入口,讓解析基線dex時候找不到這個class的定義便可;這樣不會致使dex的各個部分都發生變化,防止大量調整offset.
    • 只要把全部的dex都load進去,單個dex中不存在的類就能夠在運行期間在其餘dex中找到.補丁中的類和基線中的類能夠互相訪問到

3.資源熱修復技術

Android資源的熱修復,就是在app不從新安裝的狀況下,利用下發的補丁包直接更新app中的資源 Sophix的資源熱修復方案數組

1:構造一個 package id 爲0x66的資源包,這個包裏只含有變動的資源,以及新增資源;
2:而後直接在原有AssetManager上調用addAssetPath加入這個資源包便可;

由於咱們補丁包的id和已經加載的0x7f衝突,因此直接加入原有AssetManager便可直接使用
複製代碼

4.SO庫熱修復技術

性能優化

相關文章
相關標籤/搜索