熱修復(fù)介紹

目錄

1什么是熱修復(fù)

2.為什么需要熱修復(fù)

3.目前存在的解決方案

4.各自?xún)?yōu)缺點(diǎn)

5.如何應(yīng)用和取舍


1.什么是熱修復(fù)

傳統(tǒng)發(fā)版流程民逼。


傳統(tǒng)發(fā)版流程

在這個(gè)流程當(dāng)中發(fā)版重新上線(xiàn)需要用戶(hù)重新下載覆蓋安裝無(wú)法做到全面替換,而且一次安裝包較大用戶(hù)安裝的成本較高。

替代方案之一:Hybird.

缺點(diǎn)是采用H5以后性能與原生相比相差甚遠(yuǎn)。

更優(yōu)的解決方案:熱修復(fù).

熱修復(fù)的出現(xiàn)將傳統(tǒng)發(fā)版流程修改成如下流程:


熱修復(fù)流程

熱修復(fù)流程在修復(fù)bug以后采用無(wú)感知方式直接推送給所有用戶(hù)無(wú)需安裝即可修復(fù),有點(diǎn)是覆蓋面廣修復(fù)成功率高益眉,且比下載一個(gè)apk安裝成本要低。

2.為什么需要熱修復(fù)

上面實(shí)際上已經(jīng)解答了這個(gè)問(wèn)題。

3.目前存在的解決方案:

阿里:andFix HotFix sophix

騰訊:Tinker? qq空間熱補(bǔ)丁方案?

美團(tuán):Robust

根據(jù)不同技術(shù)方案實(shí)現(xiàn)重新對(duì)上述方案進(jìn)行分類(lèi):

底層替換方案:AndFix

multidex方案:Tinker qq空間熱補(bǔ)丁方案郭脂,nuwa等

基于instant run方案:robust.

3.1底層替換方案:

AndFix主要是在native層使用指針替換的方式替換bug方法年碘,通過(guò)自定義注解找到需要修復(fù)的類(lèi)和方法。首先類(lèi)加載其方法都放在方法區(qū)展鸡,在native層中有相應(yīng)的結(jié)構(gòu)體描述對(duì)應(yīng)的方法和執(zhí)行邏輯屿衅,一旦某個(gè)方法出現(xiàn)bug,可以新建一個(gè)類(lèi)然后把修復(fù)后的方法放進(jìn)來(lái)莹弊,把原來(lái)的那個(gè)類(lèi)的方法的指針指向新的類(lèi)方法就完成了bug修復(fù)涤久。


Sophix:是在A(yíng)ndFix進(jìn)一步優(yōu)化產(chǎn)生的,由于不同廠(chǎng)商的底層結(jié)構(gòu)體不同忍弛,按照AndFix的方式很難兼容所有平臺(tái)响迂。而Sophix很巧妙的解決了這個(gè)問(wèn)題,結(jié)構(gòu)體的替換例如修改指針细疚,改訪(fǎng)問(wèn)權(quán)限其前提是Android手機(jī)的結(jié)構(gòu)體與AndFix的結(jié)構(gòu)體要一致才能才能完好的進(jìn)行替換蔗彤,所以Sophix另辟蹊徑采用整體替換的方式,

同包名訪(fǎng)問(wèn)權(quán)限問(wèn)題采用classloader進(jìn)行替換將新的替換為老的即可疯兼。


QQ超級(jí)補(bǔ)丁方案:

基于A(yíng)ndroid dex分包機(jī)制完成


dex分包

QQ超級(jí)補(bǔ)丁的原理基于A(yíng)ndroid dex加載原理幕与,新修復(fù)的類(lèi)放在patch.dex中插樁到dexElements最前面,就算是完成了bug熱修復(fù)镇防,虛擬機(jī)優(yōu)先加載patch.dex中的qzone.class啦鸣,為解決不在不同一個(gè)dex的兩個(gè)調(diào)用類(lèi)關(guān)系。也就是防止類(lèi)被打上CLASS_ISPREVERIFIED標(biāo)志来氧,設(shè)計(jì)一個(gè)AntilazyLoad類(lèi)诫给,然后在所有類(lèi)的構(gòu)造方法中加入

if (ClassVerifier.PREVENT_VERIFY) {?

????System.out.println(AntilazyLoad.class);

?}

同時(shí)AntilazyLoad類(lèi)會(huì)單獨(dú)打包成hack.dex,這樣所有的類(lèi)都會(huì)引用不同的dex

qq超級(jí)補(bǔ)丁

修復(fù)的步驟為:

1.獲取當(dāng)前用的Classloader啦扬,即為BaseDexClassloader中狂,目的會(huì)為了獲取其pathlist

2.分別獲取程序和補(bǔ)丁的pathList得到兩者的dexElements然后進(jìn)行合并,將補(bǔ)丁放到最前面

Tinker:

dalvik由于插樁導(dǎo)致耗時(shí)扑毡,性能損耗大胃榕,在art狀態(tài)下修改方法和filed會(huì)導(dǎo)致內(nèi)存指針異常,為了解決這個(gè)問(wèn)題我們需要將修改了變量瞄摊、方法以及接口的類(lèi)的父類(lèi)以及調(diào)用這個(gè)類(lèi)的所有類(lèi)都加入到補(bǔ)丁包中勋又。這可能會(huì)帶來(lái)補(bǔ)丁包大小的急劇增加。

全量替換新dex换帜,對(duì)比新舊dex楔壤,在運(yùn)行時(shí)將path.dex與舊dex還原成新的dex,DexDiff的細(xì)粒度是dex中每一項(xiàng)

缺點(diǎn):

占用Rom體積惯驼;這邊大約是你修改Dex數(shù)量的1.5倍(dexopt與dex壓縮成jar)的大小蹲嚣。

一個(gè)額外的合成過(guò)程递瑰;雖然我們單獨(dú)放在一個(gè)進(jìn)程上處理,但是合成時(shí)間的長(zhǎng)短與內(nèi)存消耗也會(huì)影響最終的成功率隙畜。

難點(diǎn):

Dex格式復(fù)雜抖部;Dex大致分為像StringID,TypeID這些Index區(qū)域以及使用Offset的Data區(qū)域议惰。它們有大量的互相引用慎颗,一個(gè)小小的改變可能導(dǎo)致大量的Index與Offset變化;

dex2opt與dex2oat校驗(yàn)换淆;在這兩個(gè)過(guò)程系統(tǒng)會(huì)做例如四字節(jié)對(duì)齊哗总,部分元素排序等校驗(yàn),例如StringID按照內(nèi)容的Unicode排序倍试,TypeID按照StringID排序...

低內(nèi)存讯屈,快速;這要求我們對(duì)Dex每一塊做到一次讀寫(xiě)县习,無(wú)法像baksmali與dexmerge那樣完全結(jié)構(gòu)化涮母。


robust


robust原理

遇到的難點(diǎn):混淆以及super函數(shù)

缺點(diǎn):太過(guò)復(fù)雜。無(wú)法做到資源.so庫(kù)替換和AndFix類(lèi)似也是方法替換


1.DexClassLoader和PathClassLoader.

DexClasLoader加載jar躁愿,dex以及apk的classes.dex文件叛本,可以執(zhí)行非安裝程序代碼

PathClassLoader是Android使用這個(gè)類(lèi)作為系統(tǒng)和應(yīng)用類(lèi)的加載器。

#DexPathList

public Class findClass(String name) {

????for(Element element : dexElements) {

????????DexFile dex = element.dexFile;

????????if(dex !=null) {

? ? ? ?????Class clazz = dex.loadClassBinaryName(name, definingContext);

????????????if(clazz !=null) {

????????????????return clazz;

????????????}

????????}

????}

????return null;

}

將dex轉(zhuǎn)化成odex的過(guò)程中彤钟,會(huì)在DexVerify.cpp進(jìn)行校驗(yàn)来候,驗(yàn)證如果直接引用到的類(lèi)和clazz是否在同一個(gè)dex,如果是逸雹,則會(huì)打上CLASS_ISPREVERIFIED標(biāo)志营搅,需要阻止打上這個(gè)標(biāo)記。


instant run原理


ART所使用的AOT(Ahead-Of-Time)編譯梆砸,在應(yīng)用首次安裝時(shí)转质,字節(jié)碼預(yù)編譯成機(jī)器碼存儲(chǔ)在本地,也就是說(shuō)在程序運(yùn)行前編譯帖世。而Dalvik是典型的JIT(Just_In_Time)休蟹,此模式下,應(yīng)用每次運(yùn)行的時(shí)候日矫,字節(jié)碼都需要即時(shí)編譯器轉(zhuǎn)換為機(jī)器碼再執(zhí)行赂弓,也就是在程序運(yùn)行時(shí)編譯。因此在A(yíng)pp運(yùn)行時(shí)搬男,ART模式相對(duì)于Dalvik省去了解釋字節(jié)碼的過(guò)程拣展,占用內(nèi)存也相應(yīng)減少,進(jìn)而提高App缔逛。

? ?public int getIndex() {

? ? return 105;

}

public static ChangeQuickRedirect changeQuickRedirect;

public long getIndex() {

if(changeQuickRedirect != null) {

//PatchProxy中封裝了獲取當(dāng)前className和methodName的邏輯,并在其內(nèi)部最終調(diào)用了changeQuickRedirect的對(duì)應(yīng)函數(shù)

if(PatchProxy.isSupport(new Object[0], this, changeQuickRedirect, false)) {

return ((Long)PatchProxy.accessDispatch(new Object[0], this, changeQuickRedirect, false)).longValue();

}

}

return 100L;

}

public class PatchesInfoImpl implements PatchesInfo { public ListgetPatchedClassesInfo() { ListpatchedClassesInfos = new ArrayList();

PatchedClassInfo patchedClass = new PatchedClassInfo("com.meituan.sample.d", StatePatch.class.getCanonicalName());

patchedClassesInfos.add(patchedClass);

return patchedClassesInfos;

}

}


public class StatePatch implements ChangeQuickRedirect {

@Override

public Object accessDispatch(String methodSignature, Object[] paramArrayOfObject) {

String[] signature = methodSignature.split(":");

if (TextUtils.equals(signature[1], "a")) {//long getIndex() -> a

return 106;

}

return null;

}

@Override

public boolean isSupport(String methodSignature, Object[] paramArrayOfObject) {

String[] signature = methodSignature.split(":");

if (TextUtils.equals(signature[1], "a")) {//long getIndex() -> a

return true;

}

return false;

}

}


直接用DexClassLoader加載修復(fù)包,然后用loadClass方法加載修復(fù)類(lèi)褐奴,new出新對(duì)象按脚,在用反射把這新的修復(fù)對(duì)象設(shè)置到指定類(lèi)的changeQuickRedirect靜態(tài)變量中即可。


第一次編譯apk:

1.把Instant-Run.jar和instant-Run-bootstrap.jar打包到主dex中

2.替換AndroidManifest.xml中的application配置

3.使用asm工具敦冬,在每個(gè)類(lèi)中添加$change辅搬,在每個(gè)方法前加邏輯

4.把源代碼編譯成dex,然后存放到壓縮包instant-run.zip中

app運(yùn)行期:

1.獲取更改后資源resource.ap_的路徑

2.設(shè)置ClassLoader脖旱。setupClassLoader:

使用IncrementalClassLoader加載apk的代碼堪遂,將原有的BootClassLoader → PathClassLoader改為BootClassLoader → IncrementalClassLoader → PathClassLoader繼承關(guān)系。

3.createRealApplication:

創(chuàng)建apk真實(shí)的application

4.monkeyPatchApplication

反射替換ActivityThread中的各種Application成員變量

5.monkeyPatchExistingResource

反射替換所有存在的AssetManager對(duì)象

6.調(diào)用realApplication的onCreate方法

7.啟動(dòng)Server萌庆,Socket接收patch列表

有代碼修改時(shí)

1.生成對(duì)應(yīng)的$override類(lèi)

2.生成AppPatchesLoaderImpl類(lèi)溶褪,記錄修改的類(lèi)列表

3.打包成patch,通過(guò)socket傳遞給app

4.app的server接收到patch之后践险,分別按照handleColdSwapPatch猿妈、handleHotSwapPatch、handleResourcePatch等待對(duì)patch進(jìn)行處理

5.restart使patch生效

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末巍虫,一起剝皮案震驚了整個(gè)濱河市彭则,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌占遥,老刑警劉巖俯抖,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異瓦胎,居然都是意外死亡芬萍,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)凛捏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)担忧,“玉大人,你說(shuō)我怎么就攤上這事坯癣∑渴ⅲ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵示罗,是天一觀(guān)的道長(zhǎng)惩猫。 經(jīng)常有香客問(wèn)我,道長(zhǎng)蚜点,這世上最難降的妖魔是什么轧房? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮绍绘,結(jié)果婚禮上奶镶,老公的妹妹穿的比我還像新娘迟赃。我一直安慰自己,他們只是感情好厂镇,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布纤壁。 她就那樣靜靜地躺著,像睡著了一般捺信。 火紅的嫁衣襯著肌膚如雪酌媒。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 50,084評(píng)論 1 291
  • 那天迄靠,我揣著相機(jī)與錄音秒咨,去河邊找鬼。 笑死掌挚,一個(gè)胖子當(dāng)著我的面吹牛雨席,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播疫诽,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼舅世,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了奇徒?” 一聲冷哼從身側(cè)響起雏亚,我...
    開(kāi)封第一講書(shū)人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎摩钙,沒(méi)想到半個(gè)月后罢低,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡胖笛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年网持,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片长踊。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡功舀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出身弊,到底是詐尸還是另有隱情辟汰,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布阱佛,位于F島的核電站帖汞,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏凑术。R本人自食惡果不足惜翩蘸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望淮逊。 院中可真熱鬧催首,春花似錦扶踊、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)命满。三九已至涝滴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間胶台,已是汗流浹背歼疮。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诈唬,地道東北人韩脏。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像铸磅,于是被迫代替她去往敵國(guó)和親赡矢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

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