1. 程式人生 > >Android熱更新技術——Tinker、nuwa、AndFix、Dexposed

Android熱更新技術——Tinker、nuwa、AndFix、Dexposed

一、熱修復技術作用

  線上app BUG緊急修復,不重新發版,不重新安裝,線上遠端修復問題

二、侷限性與適用場景

  • 補丁只能針對單一客戶端版本,隨著版本差異變大補丁體積也會增大;
  • 補丁不能支援所有的修改,例如AndroidManifest;
  • 補丁無論對程式碼還是資源的更新成功率都無法達到100%。

既然補丁技術無法完全代替升級,那它適合使用在哪些場景呢?

1. 輕量而快速的升級

2.遠端除錯

3.資料統計

4.其他(Instant Run)

Android官方也使用熱補丁技術實現Instant Run。它分為Hot Swap、Warm Swap與Cold Swap三種方式。

三、熱修復的原理

1、通過更改dex載入順序實現熱修復

通過更改含有bug的dex檔案的載入順序;在dex的載入中,若已找到方法則不會繼續查詢,所以如果能讓修復之後的方法在含有bug的方法之前載入就能達到修復bug的目的。把有問題的類修復後,放到一個單獨的dex,通過反射插入到dexElements陣列的最前面,讓虛擬機器優先載入打完補丁的class。

實踐中,會發現執行載入類的時候報preverified錯誤,原來在DexPrepare.cpp,將dex轉化成odex的過程中,會在DexVerify.cpp進行校驗,驗證直接引用的類和clazz是否在同一個dex,如果是,則會打上CLASS_ISPREVERIFIED標誌。通過在所有類(Application除外,當時還沒載入自定義類的程式碼)的建構函式插入一個對在單獨的dex的類的引用,就可以解決這個問題。空間使用了javaassist進行編譯時位元組碼插入。

隱患:虛擬機器在安裝期間為類打上CLASS_ISPREVERIFIED標誌是為了提高效能的,我們強制防止類被打上標誌多少會影響app的效能。但是在大專案中拆分dex的問題已經比較嚴重,很多類都沒有被打上這個標誌。

開源實現有Nuwa, HotFix, DroidFix。實際應用案例:QQ空間

2、通過Native替換方法指標的方式實現熱修復

主要是阿里開源的兩個熱修復框架:Dexpost AndFix。它們都是通過Native層使用指標替換的方法替換bug,達到修復bug的目的,具體可參考其github文章。

(1)基於Xposed的AOP框架,方法級粒度,可以進行AOP程式設計、插樁、熱補丁、SDK hook等功能。

Xposed需要Root許可權,是因為它要修改其他應用、系統的行為,而對單個應用來說,其實不需要root。 Xposed通過修改Android Dalvik執行時的Zygote程序,並使用Xposed Bridge來hook方法並注入自己的程式碼,實現非侵入式的runtime修改。

我們知道,應用啟動的時候,都會fork zygote程序,裝載class和invoke各種初始化方法,Xposed就是在這個過程中,替換了app_process,hook了各種入口級方法(比如handleBindApplication、ServerThread、ActivityThread、ApplicationPackageManager的getResourcesForApplication等),載入XposedBridge.jar提供動態hook基礎。

方法級的替換是指,可以在方法前、方法後插入程式碼,或者直接替換方法。只能針對java方法做攔截,不支援C的方法。

硬傷是不支援art,不支援art,不支援art。

(2)AndFix同樣是方法的hook,AndFix不像Dexposed從Method入手,而是以Field為切入點。dalvik和art都支援

使用上,直接寫一個新的類,會由補丁工具會生成註解,描述其與要打補丁的類和方法的對應關係。

3、微信熱補丁方案

思想是全量替換新的Dex。即完全使用新的Dex,這樣既不出現Art地址錯亂的問題,在Dalvik也無須插樁。考慮到補丁包的體積,不能直接將新的Dex放在裡面。但可以將新舊兩個Dex的差異放到補丁包中,最簡單可以採用BsDiff演算法。

簡單來說,在編譯時通過新舊兩個Dex生成差異path.dex。在執行時,將差異patch.dex重新跟原始安裝包的舊Dex還原為新的Dex。這個過程可能比較耗費時間與記憶體,所以我們是單獨放在一個後臺程序:patch中。為了補丁包儘量的小,微信自研了DexDiff演算法,它深度利用Dex的格式來減少差異的大小。它的粒度是Dex格式的每一項,可以充分利用原本Dex的資訊,而BsDiff的粒度是檔案,AndFix/QZone的粒度為class

在最極端的情況,由於利用了原本dex的資訊完全替換一個13M的Dex,我們的補丁大小也僅僅只有6.6M。

但是這套方案並非沒有缺點,它帶來的問題有兩個:

(1)佔用Rom體積;這邊大約是你修改Dex數量的1.5倍(dexopt與dex壓縮成jar)的大小。
(2)一個額外的合成過程;雖然我們單獨放在一個程序上處理,但是合成時間的長短與記憶體消耗也會影響最終的成功率。

微信的熱補丁方案叫做Tinker,也算緬懷一下Dota中的地精修補匠,希望能做到無限重新整理。

若不care效能損耗與補丁包大小,QZone方案是最簡單且成功率最高的方案(沒有單獨的合成過程)。相對Tinker來說,它的佔用Rom體積也更小。另一方面,QZone與Tinker的成功率大約相差3%左右。

事實上,一個完整的框架應該也是一個容易使用的框架。Tinker對補丁版本管理、程序管理、安全校驗等都有著很好的支援。同時我們也支援gradle與命名行兩種接入方式。希望在不久的將來,它可以很快的跟大家見面。

 

 

https://www.cnblogs.com/aademeng/articles/6883861.html

http://www.bbs0101.com/archives/1437.html

https://www.jianshu.com/p/52cacc0f23fa

https://www.cnblogs.com/fanfu1/p/5506149.html