筆記 深入探索Android熱修復(fù)技術(shù)原理

阿里電子書《深入探索Android熱修復(fù)技術(shù)原理》整理的筆記


1.熱修復(fù)技術(shù)介紹

  1. 代碼修復(fù)兩大主要方案
    • 底層替換方案:限制較多,但時效性好,立即見效
    • 類加載方案時效性差,需要重新冷啟動才能見效,但限制少
  2. 代碼修復(fù)底層替換方案
    • 底層替換方案是在已經(jīng)加載了的類中直接替換掉原有方法.
    • 不能對原有類進行方法和字段的增減,因為這樣將破壞原有類的結(jié)構(gòu).
    • 方法增減將導(dǎo)致這個類及整個Dex方法數(shù)的變化,伴隨著方法索引的變化,這樣訪問方法時就無法正常的索引到正確的方法;
    • 字段增加或減少,所有字段的索引都會發(fā)生變化;
    • 傳統(tǒng)底層替換方案,都是直接依賴修改虛擬機方法實體中的具體字段.依據(jù)的是Android開源版本.如果廠商修改了虛擬機方法實體,替換機制就可能出問題;
  3. 代碼修復(fù)類加載方案
    • 類加載方案的原理是在app重新啟動后讓Classloader去加載新的類.
    • 在app運行到一半的時候,所有需要發(fā)生變更的類都已經(jīng)被加載過,Android無法對一個類進行卸載.如果不重啟,原來的類還在虛擬機中,就無法加載新類.
    • 只有在下次重啟時候,在還沒有走到業(yè)務(wù)邏輯前搶先加載補丁中的新類,后續(xù)訪問才是新的類.
    • dex比較的最佳粒度,應(yīng)該是在類的粒度
    • Sophix采用的也是全量合成dex的技術(shù).可以看做是dex文件級別的類插裝方案.Sophix對舊包與補丁包中classes.dex的順序進行了打破與重組,使得系統(tǒng)可以自然地識別到這個順序,以實現(xiàn)類覆蓋的目的
  4. 資源修復(fù)
    • 市面上很多資源熱修復(fù)方案都采用了Instant Run的實現(xiàn)
    • Instant Run中資源修復(fù)步驟:
      1. 構(gòu)造一個新的AssetManager,通過反射調(diào)用addAssetPath,把這個完整的新資源包加到AssetManager中.這樣就得到一個含有所有新資源的AssetManager.
      2. 找到所有之前引用到AssetManager的地方,通過反射,將引用出替換為AssetManager.
    • Sophix資源熱修復(fù)沒有采用Instant Run的技術(shù),而是構(gòu)造了一個package id 為 0x66 的資源包,這個包里只包含改變了的資源項,然后直接在原有AssetManager中addAssetPath這個包即可.無需變更AssetManager對象的引用.
      1. Sophix構(gòu)造的補丁包的 package id 為0x66,不與已經(jīng)加載的 0x7f沖突,所以直接加入到已有的AssetManager中可以直接使用.
      2. Sophix資源補丁包中,只包含新增資源,以及原有內(nèi)容發(fā)生了改變的資源.
  5. SO庫修復(fù):本質(zhì)上是對native方法的修復(fù)和替換

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

2.代碼熱修復(fù)技術(shù)

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

3.資源熱修復(fù)技術(shù)

Android資源的熱修復(fù),就是在app不重新安裝的情況下,利用下發(fā)的補丁包直接更新app中的資源
Sophix的資源熱修復(fù)方案

1:構(gòu)造一個 package id 為0x66的資源包,這個包里只含有變更的資源,以及新增資源;
2:然后直接在原有AssetManager上調(diào)用addAssetPath加入這個資源包即可;

因為我們補丁包的id和已經(jīng)加載的0x7f沖突,所以直接加入原有AssetManager即可直接使用

4.SO庫熱修復(fù)技術(shù)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末斤彼,一起剝皮案震驚了整個濱河市分瘦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌畅卓,老刑警劉巖擅腰,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異翁潘,居然都是意外死亡趁冈,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門拜马,熙熙樓的掌柜王于貴愁眉苦臉地迎上來渗勘,“玉大人,你說我怎么就攤上這事俩莽⊥梗” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我土铺,道長,這世上最難降的妖魔是什么璧疗? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮馁龟,結(jié)果婚禮上崩侠,老公的妹妹穿的比我還像新娘。我一直安慰自己坷檩,他們只是感情好却音,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著矢炼,像睡著了一般系瓢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上句灌,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天八拱,我揣著相機與錄音,去河邊找鬼涯塔。 笑死,一個胖子當(dāng)著我的面吹牛清蚀,可吹牛的內(nèi)容都是我干的匕荸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼枷邪,長吁一口氣:“原來是場噩夢啊……” “哼榛搔!你這毒婦竟也來了诺凡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤践惑,失蹤者是張志新(化名)和其女友劉穎腹泌,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體尔觉,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡凉袱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了侦铜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片专甩。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖钉稍,靈堂內(nèi)的尸體忽然破棺而出涤躲,到底是詐尸還是另有隱情,我是刑警寧澤贡未,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布种樱,位于F島的核電站,受9級特大地震影響俊卤,放射性物質(zhì)發(fā)生泄漏嫩挤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一瘾蛋、第九天 我趴在偏房一處隱蔽的房頂上張望俐镐。 院中可真熱鬧,春花似錦哺哼、人聲如沸佩抹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽棍苹。三九已至,卻和暖如春茵汰,著一層夾襖步出監(jiān)牢的瞬間枢里,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工蹂午, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留栏豺,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓豆胸,卻偏偏與公主長得像奥洼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子晚胡,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容