正常開發流程:
新版本上線,發現問題或用戶反饋bug,緊急修復,上線版本,用戶重新安裝。
熱修復流程:
新版本上線,發現問題或用戶反饋,緊急修復,上線補丁,自動修復
Thinker解決思路?
在android5.0之前,每個android應用只含有一個dex文件,dex的方法數量被限制在了65535之內,導致apk引入大量第三方sdk后方法數量超過限制無法編譯通過。為了解決這個問題,Google推出多dex文件的解決方案multidex,一個apk可以包含多個dex文件。通過Multidex.install(this)完成dex文件的加載。
Tinker方案參考multidex實現原理,在編譯時通過新舊兩個Dex生成差異patch.dex。在運行時,將差異patch.dex重新和原始安裝包的舊Dex合並還原為新的Dex。這個過程可能比較耗費時間與內存,所以tinker單獨放在一個后台進程:patch中處理。為了補丁包盡量的小,微信自研了DexDiff算法,它深度利用Dex的格式來減少差異的大小。由於采用ClassLoader機制,所以需要app重啟。
Tinker基於基版本利用自研的DexDiff算法生成差分包,放在后台。App啟動時下載差分包,與原dex重新合並,解壓縮,並參考MultiDex.install()流程,重新安裝app。
由於類加載實現原理涉及dex文件的重新解壓縮合並等處理,消耗內存大,耗時長,在系統低內存時容易導致熱更新失敗,騰訊測試成功率大概為95%。實際熱部署時,差分包應文件大小最小。
綜上沒有完美的熱更新方案,沒有100%的熱更新成功率。目前,騰訊tinker基本可以滿足app的熱更新需求,但隨着app用戶規模不斷增大,業務需求日益復雜,可考慮阿里的sophix商業方案,sophix同時應用類加載和底層替換兩種方案,具有底層替換的修改及時性,和類加載方案的兼容性等優點。而且sophix采用非侵入打包,圖形化的生成補丁,用阿里的原話說就是“傻瓜式接入”,點一點鼠標就能生成補丁文件,而且阿里提供了后台補丁管理系統,幫助開發者在生成補丁后直接上傳至阿里的后台,無需開發者在自己的app和服務端做任何的操作。
“熱部署” – 方法內的簡單修改,無需重啟app和Activity。 “暖部署” – app無需重啟,但是activity需要重啟,比如資源的修改。 “冷部署” – app需要重啟,比如繼承關系的改變或方法的簽名變化等。
熱更新究竟是什么?
有一些這樣的情況, 當一個App發布之后,突然發現了一個嚴重bug需要進行緊急修復,這時候公司各方就會忙得焦頭爛額:重新打包App、測試、向各個應用市場和渠道換包、提示用戶升級、用戶下載、覆蓋安裝。有時候僅僅是為了修改了一行代碼,也要付出巨大的成本進行換包和重新發布。
這種需要替換運行時新的類和資源文件的加載,就可以認為是熱操作了。而在熱更新出現之前,通過反射注解、反射調用和反射注入等方式已經可以實現類的動態加載了。而熱更新框架的出現就是為了解決這樣一個問題的。從某種意義上來說,熱更新就是要做一件事,替換。當替換的東西屬於大塊內容的時候,就是模塊化了,當你去替換方法的時候,叫熱更新,當你替換類的時候,加熱插件,而且重某種意義上講,所有的熱更新方案,都是一種熱插件,因為熱更新方案就是在app之外去干這個事。就這么簡單的理解。無論是替換一個類,還是一個方法,都是在干替換這件事請。。這里的替換,也算是幾種hook操作,無論在什么代碼等級上,都是一種侵入性的操作。
所以總結一句話簡單理解熱更新 HotFix 就是改變app運行行為的技術!(或者說就是對已發布app進行bug修復的技術)
目前存在的主流框架?
先后出現了Dexposed、AndFix,Qzone超級補丁的類Nuwa方式,微信的Tinker, 大眾點評的nuwa、百度金融的rocooFix, 餓了么的amigo以及美團的robust.以及阿里的Sophix.騰訊的內部方案KKFix.
框架橫向對比?

實現套路?

對比點評?
AndFix作為native解決方案,首先面臨的是穩定性與兼容性問題,更重要的是它無法實現類替換,它是需要大量額外的開發成本的;
Robust兼容性與成功率較高,但是它與AndFix一樣,無法新增變量與類只能用做的bugFix方案;
Qzone方案可以做到發布產品功能,但是它主要問題是插樁帶來Dalvik的性能問題,以及為了解決Art下內存地址問題而導致補丁包急速增大的。
特別是在Android N之后,由於混合編譯的inline策略修改,對於市面上的各種方案都不太容易解決。而Tinker熱補丁方案不僅支持類、So以及資源的替換,它還是2.X-8.X(1.9.0以上支持8.X)的全平台支持。利用Tinker我們不僅可以用做bugfix,甚至可以替代功能的發布
類加載機制?
我們知道Android系統也是仿照java搞了一個虛擬機,不過它不叫JVM,它叫Dalvik/ART VM他們還是有很大區別的(這是不是我們的重點, 點開是個拓展閱讀)。我們只需要知道,Dalvik/ART VM 虛擬機加載類和資源也是要用到ClassLoader,不過Jvm通過ClassLoader加載的class字節碼,而Dalvik/ART VM通過ClassLoader加載則是dex。
Android的類加載器分為兩種,PathClassLoader和DexClassLoader,兩者都繼承自BaseDexClassLoader
PathClassLoader代碼位於libcore\dalvik\src\main\Java\dalvik\system\PathClassLoader.java
DexClassLoader代碼位於libcore\dalvik\src\main\java\dalvik\system\DexClassLoader.java
BaseDexClassLoader代碼位於libcore\dalvik\src\main\java\dalvik\system\BaseDexClassLoader.java
PathClassLoader
用來加載系統類和應用類
DexClassLoader
用來加載jar、apk、dex文件.加載jar、apk也是最終抽取里面的Dex文件進行加載.

歸納一下就是:ClassLoader會遍歷這個數組,然后加載這個數組中的dex文件.
而ClassLoader在加載到正確的類之后,就不會再去加載有Bug的那個類了,我們把這個正確的類放在Dex文件中,讓這個Dex文件排在dexElements數組前面即可.

為什么推薦Sophix?
為了提升產品在敏捷開發下的最佳發布體驗,分別嘗試了備受關注的阿里和微信兩大派系的熱更新方案(支付寶的Andfix和微信的Tinker),但在探索的過程中,發現兩種方案都存在弊端,如使用場景有限,修復成功率低,存在兼容問題。加之各方案還在內部快速迭代,均未能達到商業化的標准,所以熱修復在項目中的應用被暫時擱置了。
直到最近,看到阿里推出了非侵入式熱修復框架Sophix。Sophix對其前輩Andfix,阿里百川Hotfix等方案進行了升級改造,打破了舊方案諸多限制,涵蓋了代碼修復,資源修復,So庫修復。加上阿里雲平台的支持,經過簡單的配置就可接入使用,目之所及,Sophix已經成為目前成熟度最高的熱修復框架。這也讓我重新燃起了對熱更新及底層技術探索的熱情。所以我想以此為契機,用系列文章的形式,圍繞熱點技術所涉獵的知識進行由淺入深的持續挖掘。

修復立即生效,是熱修復所追求的,底層替換方案通過在運行時利用hook操作native指針實現“熱”的特性。但這里有一個關鍵點,底層替換所操作的指針,實際上是ArtMethod,在類被加載,類中的每個方法都會有對應的ArtMethod,它記錄了方法包括所屬類和內存地址信息,Andfix正是通過篡改ArtMethod,將補丁方法ArtMethod的成員值逐一賦給舊方法,實現替換。問題就出現在這個逐一上。因為Andfix的ArtMethod方法結構是根據Android開源代碼寫死的,面對國內廠商的定制,經常會導致兩者ArtMethod方法結構不一致,這也是兼容問題產生的根本原因。
為了解決這個問題,Sophix采用了對舊ArtMethod進行完整替換,通過動態測量ArtMethod的size(通過c層的mempy(dest ,src ,size)方法),進行全量拷貝。這樣做無論ArtMethod被修改成什么樣,只需要統一執行拷貝,就可以完成替換,完全無視修改虛擬機導致的ArtMethod結構差異.
底層替換雖能使修復即時生效,但由於類加載后,方法結構已固定,這就造成使用上會有諸多限制。相反類加載方案的使用場景更為廣泛。Sophix使用類加載作為兜底方案。在熱部署無法使用的情況下,自動降級為冷部署方案。
無論是冷部署還是熱部署,都需要通過同一套補丁兼顧,在Art虛擬機下,默認支持多dex加載,虛擬機會優先加載命名為classes.dex的文件。Sophix利用了這一點,將補丁文件命名為classes.dex,並對原有dex文件進行排序。這樣一來,art虛擬機就會先加載補丁文件,后續加載的同類名的類會被忽略,最后將加載得到的dexFile把dexElements整體替換。

Dalvik虛擬機下情況則有些不同,Dalvik默認只加載classes.dex,其他dex則被忽略。那么,Sophix就需要一個全量dex,前面提到tinker采用自主研發的dexDiff技術,從方法和指令的維度進行dex合成,但Dex合成過程發生在虛擬機堆內存上,修復的成功率極大的受到性能問題的影響。為了解決這個問題,Sophix換了一種思路,從類的維度,對照補丁包中出現的類,在原有包中做刪除操作,如圖。

為了避免刪除整個類信息而導致dex結構發生偏移,所以只對舊包中類的入口進行刪除,實際上類的信息還在dex包中。這樣一來,冷啟動后,原有的類就不會被加載,相比Tinker的合成方案,Sophix的思路更為輕量化。
至此,對Sophix對類文件修復的基本原理描述完畢。可以說Sophix吸取了百家之長,對問題的解決之法堪稱巧妙。但在驚嘆阿里技術底蘊的同時,也展現出底層技術的重要性,若沒有對虛擬機等底層技術的深耕探索,在系統框架的紛繁規則面前,也只能至於庭前止步。
作者:哥哥是歐巴Vitory
鏈接:https://www.jianshu.com/p/e6fd2adafaac
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。