震驚连锯!阿里熱更新框架 Sophix 背后隱藏的真相竟然是……

? ? ? 移動互聯(lián)網(wǎng)市場日趨成熟归苍,移動產(chǎn)品研發(fā)進入平穩(wěn)發(fā)展階段,這意味著開發(fā)者的思維和研發(fā)模式也應(yīng)轉(zhuǎn)入下半程运怖。安全領(lǐng)域技術(shù)在開發(fā)中的應(yīng)用一直是操作系統(tǒng)平臺發(fā)展周期中的重要一環(huán)拼弃。熱修復(fù),作為安全領(lǐng)域技術(shù)的衍生品摇展,自2016年開始吻氧,持續(xù)受到關(guān)注,并不斷演進吗购。

? ? ? ?2016年上半年医男,為了提升產(chǎn)品在敏捷開發(fā)下的最佳發(fā)布體驗,分別嘗試了備受關(guān)注的阿里和微信兩大派系的熱更新方案(支付寶的Andfix和微信的Tinker)捻勉,但在探索的過程中镀梭,發(fā)現(xiàn)兩種方案都存在弊端,如使用場景有限踱启,修復(fù)成功率低报账,存在兼容問題。加之各方案還在內(nèi)部快速迭代埠偿,均未能達到商業(yè)化的標(biāo)準透罢,所以熱修復(fù)在項目中的應(yīng)用被暫時擱置了。

? ? ? ?直到最近冠蒋,看到阿里推出了非侵入式熱修復(fù)框架Sophix羽圃。Sophix對其前輩Andfix,阿里百川Hotfix等方案進行了升級改造抖剿,打破了舊方案諸多限制朽寞,涵蓋了代碼修復(fù),資源修復(fù)斩郎,So庫修復(fù)脑融。加上阿里云平臺的支持,經(jīng)過簡單的配置就可接入使用缩宜,目之所及肘迎,Sophix已經(jīng)成為目前成熟度最高的熱修復(fù)框架。這也讓我重新燃起了對熱更新及底層技術(shù)探索的熱情锻煌。所以我想以此為契機妓布,用系列文章的形式,圍繞熱點技術(shù)所涉獵的知識進行由淺入深的持續(xù)挖掘宋梧。

熱修復(fù)的價值

? ? ? ?新技術(shù)的層出不窮匣沼,適時合理的應(yīng)用,有助于產(chǎn)品演進并提高生產(chǎn)力乃秀。同時肛著,我們應(yīng)保持冷靜,適合自己的才是最好的跺讯,避免新技術(shù)解決了老問題枢贿,卻帶來更多新問題的尷尬,所以我先從以往應(yīng)用發(fā)布流程入手刀脏,通過分析和比較局荚,逐步了解熱修復(fù)的技術(shù)原理,為項目是否引入做參考愈污。常規(guī)發(fā)布流程如下耀态,

這種發(fā)布流程的存在的問題:

1.重新發(fā)版,需要重新上架審核暂雹,耗時費力

2.用戶需要重新下載安裝首装,用戶體驗差

3.Bug修復(fù)不及時,成本高

使用熱更新杭跪,流程如下

? ? ? ?可見仙逻,熱更新能夠以更低的成本,更靈活的方式應(yīng)對Bug修復(fù)涧尿。

? ? ? ?非侵入式一直以來都是框架設(shè)計的最佳實踐系奉,Sophix同樣以此為核心賣點,它不關(guān)心APK build過程姑廉,只關(guān)注修復(fù)后的新包缺亮,和原有包,通過可視化的補丁工具桥言,生成補丁萌踱。這一點極大地降低了接入成本,整體流程如下:

? ? ? ?可以看出限书,Sophix無論對于開發(fā)者還是用戶虫蝶,幾乎沒有侵入。Sophix團隊在文檔中提到倦西,他們用巧妙的方式能真,將低層替換和類加載兩個方案聯(lián)合起來,各取所長扰柠。我們知道粉铐,將某個框架接入項目時,通常會有官方文檔會幫助你完成卤档。但隨著框架使用的深入蝙泼,若總是浮于表面,那么在出現(xiàn)問題時劝枣,則會手足無措汤踏。加強對底層技術(shù)的探索织鲸,對程序員來說也是十分有益的。

? ? ? ?前面提到溪胶,Sophix是從兩種熱修復(fù)方案中演進搂擦,那么我將分別以阿里系低層替換方案和騰訊系的類加載方案為例,從類修復(fù)的角度進行分析哗脖。

底層替換方案

代表:支付寶的Andfix瀑踢,話不多說,先上圖才避,

? ? ? ?如圖橱夭,修復(fù)bug后,會構(gòu)建出一個新的apk桑逝,通過Andfix框架提供的工具對比出新舊apk classes.dex文件的差異棘劣,并生成patch壓縮包,壓縮包中比較關(guān)鍵的是PATCH.MF文件和diff.dex楞遏,虛擬機通過jarFile讀取PATCH.MF文件得到補丁類名呈础,dexFile讀取diff.dex,獲得補丁方法橱健。使用補丁類名和補丁方法通過classLoader而钞,找到要修復(fù)的bug類名及方法。最后利用hook技術(shù)(關(guān)于hook會在之后的Dalvik文章中詳述)拘荡,在native修改指ArtMethod針變量臼节,使其指向補丁方法,從而完成bug修復(fù)珊皿。

? ? ? ?底層替換的方案的優(yōu)點是网缝,在類加載后,動態(tài)修改native指針蟋定,修復(fù)即時生效粉臊,無需冷啟動。但缺點就是驶兜,正因為類已經(jīng)被加載扼仲,內(nèi)存中方法描述符(結(jié)構(gòu)體)已經(jīng)固定,所以只能替換抄淑,不能做新增修復(fù)屠凶。同時,在Native操作指針時肆资,強轉(zhuǎn)ArtMethod的類型是AndFix寫死的矗愧,無法保證是運行時的ArtMethod結(jié)構(gòu),這會產(chǎn)生十分嚴重的兼容問題郑原。

? ? ? ?通過實踐唉韭,發(fā)現(xiàn)Andfix修復(fù)成功率非常低夜涕,時常出現(xiàn)崩潰,補丁無效的現(xiàn)象属愤,經(jīng)查證钠乏,主要還是因為兼容問題。而且不能新增field也是主要問題春塌,新增field會破壞序列,這樣一來簇捍,調(diào)用方法時會造成地址混亂只壳。

類加載方案

同樣請先看圖

? ? ? ?不得不承認,Tinker中用了很多巧妙的方法暑塑。為了減少補丁大小吼句,Tinker需要通過新舊包生成差量包diff.dex。不同于其他類加載方案事格,Tinker采用全量更新惕艳。客戶端在獲得diff.dex后驹愚,會開啟一個service進行dex文件的合成远搪,合成的全量dex文件插入到dexElements的第一個位置,dexElements里面的每個Element實際上就是Dex文件逢捺,classLoader在啟動時谁鳍,會按順序加載dex文件,使修復(fù)類所在的全量dex包被優(yōu)先加載劫瞳,從而完成替換倘潜。

? ? ? ?相比較早的增量Dex替換方案(如Qzone超級補丁),Tinker的全量替換很好的規(guī)避了觸犯Vm的規(guī)則:“當(dāng)一個類中引用了另外一個類志于,則一般要求兩個類來自同一個Dex文件”涮因。增量方案為解決這個問題,需要進行“打樁”伺绽,所謂打樁养泡,就是在所有類中分別引用另外Dex文件中的類,通常的做法是在每一個類中增加構(gòu)造器并引用另外一個dex中的類(這個dex是為了打樁特意封裝的)奈应。這樣做是防止類被打上CLASS_ISPREVERIFIED標(biāo)簽瓤荔,CLASS_ISPREVERIFIED是觸發(fā)Vm判定規(guī)則的前提。但是钥组,在類加載的最后階段输硝,虛擬機會對未打上標(biāo)簽的類‘再次進行校驗和優(yōu)化,如果在同一時間點加載大量類程梦,那么就會出現(xiàn)嚴重的性能問題点把,如啟動時白屏橘荠。

? ? ? ?雖然Tinker用全量替換的方式避免了上述問題,但補丁全量合并的過程發(fā)生在虛擬機堆內(nèi)存上郎逃,極易造成OOM哥童,導(dǎo)致修復(fù)失敗。

? ? ? ?在了解兩種熱修復(fù)方案之后褒翰,我們再次總結(jié)一下兩種方案的優(yōu)缺點贮懈,底層替換存在不同定制Rom的兼容性問題,同時不能做新增field的修復(fù)优训,但修復(fù)可以即可生效朵你。類加載方案在合成全量補丁的時候存在性能問題,修復(fù)需要重啟應(yīng)用(冷啟動)揣非,但是兼容性較好抡医。Sophix采用底層替換方案為主,類加載方案為次的模式早敬,將二者結(jié)合起來忌傻。接下來我們來看看Sophix是如何進行雙劍合璧的。

基于底層替換方案的突破

? ? ? ?修復(fù)立即生效搞监,是熱修復(fù)所追求的水孩,底層替換方案通過在運行時利用hook操作native指針實現(xiàn)“熱”的特性。但這里有一個關(guān)鍵點琐驴,底層替換所操作的指針荷愕,實際上是ArtMethod,在類被加載棍矛,類中的每個方法都會有對應(yīng)的ArtMethod安疗,它記錄了方法包括所屬類和內(nèi)存地址信息,Andfix正是通過篡改ArtMethod够委,將補丁方法ArtMethod的成員值逐一賦給舊方法荐类,實現(xiàn)替換。問題就出現(xiàn)在這個逐一上茁帽。因為Andfix的ArtMethod方法結(jié)構(gòu)是根據(jù)Android開源代碼寫死的玉罐,面對國內(nèi)廠商的定制,經(jīng)常會導(dǎo)致兩者ArtMethod方法結(jié)構(gòu)不一致潘拨,這也是兼容問題產(chǎn)生的根本原因吊输。

? ? ? ?為了解決這個問題,Sophix采用了對舊ArtMethod進行完整替換铁追,通過動態(tài)測量ArtMethod的size(通過c層的mempy(dest ,src ,size)方法)季蚂,進行全量拷貝。這樣做無論ArtMethod被修改成什么樣,只需要統(tǒng)一執(zhí)行拷貝扭屁,就可以完成替換算谈,完全無視修改虛擬機導(dǎo)致的ArtMethod結(jié)構(gòu)差異。

另辟蹊徑的冷啟動修復(fù)

? ? ? ?底層替換雖能使修復(fù)即時生效料滥,但由于類加載后然眼,方法結(jié)構(gòu)已固定,這就造成使用上會有諸多限制葵腹。相反類加載方案的使用場景更為廣泛高每。Sophix使用類加載作為兜底方案。在熱部署無法使用的情況下践宴,自動降級為冷部署方案鲸匿。

? ? ? ?無論是冷部署還是熱部署,都需要通過同一套補丁兼顧浴井,在Art虛擬機下,默認支持多dex加載霉撵,虛擬機會優(yōu)先加載命名為classes.dex的文件磺浙。Sophix利用了這一點,將補丁文件命名為classes.dex徒坡,并對原有dex文件進行排序撕氧。這樣一來,art虛擬機就會先加載補丁文件喇完,后續(xù)加載的同類名的類會被忽略伦泥,最后將加載得到的dexFile把dexElements整體替換。

? ? ? Dalvik虛擬機下情況則有些不同锦溪,Dalvik默認只加載classes.dex不脯,其他dex則被忽略。那么刻诊,Sophix就需要一個全量dex防楷,前面提到tinker采用自主研發(fā)的dexDiff技術(shù),從方法和指令的維度進行dex合成则涯,但Dex合成過程發(fā)生在虛擬機堆內(nèi)存上复局,修復(fù)的成功率極大的受到性能問題的影響。為了解決這個問題粟判,Sophix換了一種思路亿昏,從類的維度,對照補丁包中出現(xiàn)的類档礁,在原有包中做刪除操作角钩,如圖。

? ? ? ?為了避免刪除整個類信息而導(dǎo)致dex結(jié)構(gòu)發(fā)生偏移,所以只對舊包中類的入口進行刪除彤断,實際上類的信息還在dex包中野舶。這樣一來,冷啟動后宰衙,原有的類就不會被加載平道,相比Tinker的合成方案,Sophix的思路更為輕量化供炼。

? ? ? ?至此一屋,對Sophix對類文件修復(fù)的基本原理描述完畢〈撸可以說Sophix吸取了百家之長冀墨,對問題的解決之法堪稱巧妙。但在驚嘆阿里技術(shù)底蘊的同時涛贯,也展現(xiàn)出底層技術(shù)的重要性诽嘉,若沒有對虛擬機等底層技術(shù)的深耕探索,在系統(tǒng)框架的紛繁規(guī)則面前弟翘,也只能至于庭前止步虫腋。

? ? ?僅以此篇作為引導(dǎo),未來將結(jié)合源碼稀余,探索更多底層實現(xiàn)細節(jié)悦冀。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市睛琳,隨后出現(xiàn)的幾起案子盒蟆,更是在濱河造成了極大的恐慌,老刑警劉巖师骗,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件历等,死亡現(xiàn)場離奇詭異,居然都是意外死亡辟癌,警方通過查閱死者的電腦和手機募闲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來愿待,“玉大人浩螺,你說我怎么就攤上這事∪越模” “怎么了要出?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長农渊。 經(jīng)常有香客問我患蹂,道長或颊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任传于,我火速辦了婚禮囱挑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘沼溜。我一直安慰自己平挑,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布系草。 她就那樣靜靜地躺著通熄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪找都。 梳的紋絲不亂的頭發(fā)上唇辨,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音能耻,去河邊找鬼赏枚。 笑死,一個胖子當(dāng)著我的面吹牛晓猛,可吹牛的內(nèi)容都是我干的饿幅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鞍帝,長吁一口氣:“原來是場噩夢啊……” “哼诫睬!你這毒婦竟也來了煞茫?” 一聲冷哼從身側(cè)響起帕涌,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎续徽,沒想到半個月后蚓曼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡钦扭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年纫版,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片客情。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡其弊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出膀斋,到底是詐尸還是另有隱情梭伐,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布仰担,位于F島的核電站糊识,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赂苗,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一愉耙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拌滋,春花似錦朴沿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吠卷,卻和暖如春锡垄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背祭隔。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工货岭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人疾渴。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓千贯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親搞坝。 傳聞我的和親對象是個殘疾皇子搔谴,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

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