微信 Tinker 負責人張紹文關於 Android 熱修復直播分享記錄
以下來內均來自 騰訊 DEV CLUB 微信直播群,整理髮佈於diycode分享給大家。大家可以去關注微信技術團隊的公眾號WeMobileDev
hello,大家好。我是張紹文,目前在微信主要負責Android的效能優化以及終端質量平臺相關工作。首先非常抱歉由於本週版本上線,可能準備的不是太充分。若有任何疑問,歡迎在分享結束後提問。
下面開始我們今天的分享,熱補丁技術是當前非常熱門的Android開發技術,其中比較出名的方案有支付寶的AndFix以及QZone的超級熱補丁方案。微信大約在2015年6月開始嘗試應用,經過研究與嘗試現有的各個方案,我們發現它們都有著自身的一些侷限性。我們最終採用不同於它們的技術方案,也就是微信熱補丁開源框架Tinker。
我們先來講講現有框架的一些侷限性:
Andfix是阿里推出的開源框架,它在github的地址是:https://github.com/alibaba/AndFix
它的技術原理如下圖:它採用native hook的方式,這套方案直接使用dalvik_replaceMethod
替換class中方法的實現。
它的缺點主要包括以下幾個:
- 相容性不佳;由於它採用native替換的方式,在github Issue中也有大量崩潰的反饋;
- 成功率不高;不支援修改inline方法,不支援修改引數超過8個或帶有long,double或者float的方法。跟一些使用Andfix的產品討論過,它們的成功率不超過40%;
- 開發不透明;由於它還不支援增加filed,我們需要為了補丁而補丁,無法採用這個技術釋出需求。 Andfix的好處是可以立刻生效,但它可以支援的補丁場景非常有限,僅僅可以使用它來修復特定問題。所以我們不考慮採用這個方案。
現在我們講講Qzone超級補丁方案
這個方案使用classloader的方式,能實現更加友好的類替換。而且這與我們載入Multidex的做法相似,能基本保證穩定性與相容性。它主要的面臨問題有兩個:
1、為了解決unexpected
DEX problem
異常,而採用插樁的方式給所有類插入不會真正執行的程式碼,防止類打上preverify標誌。
採用插樁導致所有類都非preverify,導致上圖中的verify與optimize操作會在載入類時觸發。這會有一定的效能損耗,微信分別採用插樁與不插樁兩種方式做過兩種測試,一是連續載入700個50行左右的類,一是統計微信整個啟動完成的耗時。
2、在art平臺,若補丁中的類出現Field、Method或Interface變化,可能會導致出現記憶體地址錯亂的問題。為了解決這個問題,我們最後補丁中的類要有以下規則:
a. 修改跟新增的class;
b. 若class有field,method或interface數量變化,它們所有的子類;
c. 若class有field,method或interface數量變化,它們以及它們所有子類的呼叫類。如果採用ClassN方式,即需要多個dex一起處理。
Qzone的方案最為簡單,而且開發透明,補丁的成功率也是非常高的。但由於微信對於執行效能以及補丁大小都比較敏感,我們最終也沒有采用這套方案。
那麼微信希望的是一套怎麼樣的熱補丁框架呢,我們認為主要的目標有以下幾個:
- 開發透明;開發者無需關心是否在補丁版本,他可以隨意修改,不由框架限制;
- 效能無影響;補丁框架不能對應用帶來效能損耗;
- 完整支援;支援程式碼,So庫以及資源的修復,可以做到釋出功能;
- 補丁大小較小;補丁大小應該儘量的小,提高升級率。
- 穩定,相容性好;保證微信的數億使用者的使用,儘量減少反射;
現在我們來講講微信熱補丁框架Tinker的實現
它的名字來至Dota中的地精修補匠,我們希望發版本可以像它一樣做到無限重新整理。
Tinker的方案來源gradle編譯的instant run與buck編譯的exopackage。它們的思想都是全量替換新的Dex,即我們完全使用了新的Dex或者資源,那樣既不出現Art地址錯亂的問題,在Dalvik也無須插樁。
但是instant run針對的是編譯期,它可以直接將最後生成的所有變化都直接拷到手機端。對於線上方案,這肯定是不可行的。所以當前核心問題是找到合適的,使補丁結果更小的差分演算法。
微信首先demo中採用的是bsdiff,它無關檔案格式,但對於Dex效果不是特別好,而且非常不穩定。當前微信對於so,依然使用bsdiff演算法。資源也部分使用了bsdiff演算法。
然後我們想到dexmerge演算法,把修改跟新增的類通過dexmerge方式與原來的dex合併,從而得到最終的完整Dex。經過實踐,dexmerge的核心問題有兩個:
- 無法刪除class;導致在Dalvik平臺會出現載入類重複的情況,這要求我們只能採用miniloader載入方案來避免;
- 合成時記憶體佔用過大;dexmerge庫使用場景在PC,它沒有太多的考慮記憶體問題。它的峰值記憶體可以達到輸入dex的大小的4倍-6倍。一個12M的dex,峰值記憶體可能達到70多M。
最後我們決定基於dex的格式,自研出一種Dexdiff演算法,它需要達到以下目標;
- diff結果小;
- 合成過程佔用記憶體小;
- 支援刪除、新增、修改dex中的class。
這裡面主要的原理是深度利用原來dex中的資訊,對於dex的每一個section做處理。這塊在今天不再深入,感興趣的同學可以交流或者閱讀原始碼。
記憶體方面dexdiff峰值記憶體是dex的兩倍左右,達到預期的結果。
對於微信熱補丁的更多資訊,可以閱讀我之前發的一篇文章。微信Android熱補丁實踐演進之路
然後我們來看看Tinker的框架設計,它主要包括以下幾部分:
- 補丁合成;這些都在單獨的patch程式工作,這裡包括dex,so還有資源,主要完成補丁包的合成以及升級;
- 補丁的載入;如果通過反射系統載入我們合成好的dex,so與資源;
- 監控回撥;在合成與載入過程中,出現問題及時回撥;
- 版本管理;Tinker支援補丁升級,甚至是多個補丁不停的切換。這裡我們需要保證所有程式版本的一致性;
- 安全校驗;無論在補丁合成還是載入,我們都需要有必要的安全校驗。
在微信中,我們為Tinker框架加入了100多個實時上報,監控著在每個過程可能出現的問題:
接著我們來看看在開發Tinker過程中,遇到的一些問題:
1、廠商OTA;對於Art平臺,dex2oat時間較長。特別是廠商OTA之後,所有動態載入的程式碼都需要重新執行dex2oat。這是因為boot image已經改變,但是系統在升級時只會給ClassN.dex重新oat。
對於補丁dex會出現主程式同步執行dex2oat,這個時間非常久,很有可能會出現ANR,對於小米等一些產品的開發版更是如此。
這也是我們現在努力在實現分平臺合成的原因,即在Art平臺,只合成規則下需要的class。只要不是全量替換,重新dex2oat的時間是可以接受的。
2、Android N混合編譯導致補丁機制失效;這塊花了一定的時間重新梳理了Android N art的程式碼,詳細的分析可以檢視之前我發的一篇文章。Android N混合編譯與對熱補丁影響解析
3、Dex反射成功但是不生效;開始的時候,我們載入補丁dex採用的是makedexElement的方式。但是發現大約有幾十萬臺機器,補丁載入成功了,但是使用的還是舊版本的程式碼。某些機器類似三星s6 502系統,儘管反射pathList成功,查詢順序依然以base.apk優先。
這裡採取的解決方法是類似instant run,採用反射parent classloader的方式。這裡不得不提,instant run的increaseClassLoader實現非常精妙。
4、Xposed等微信外掛; 市面上有各種各樣的微信外掛,它們在微信啟動前會提前載入微信中的類,這會導致兩個問題:
a. 在Dalvik平臺,直接出現'Class ref in pre-verified class resolved to unexpected implementation'的crash;
b. 在Art平臺,由於出現部分類使用了舊的程式碼,這可能導致補丁無效,或者地址錯亂的問題。
它們根本的原因都是Xposed反射呼叫,提前匯入了我們的某些類。
事實上,由於可能存在補丁使用不當或者其他問題,我們的確需要有一個安全模式。即在應用啟動不起來或多次crash時,進入補丁清理或者升級的流程。
也許有人覺得Tinker過於臃腫,過於複雜。這是因為熱補丁並不是僅僅載入一個dex或者so檔案,事實上它要關心的細節有很多。程式的一致性,控制可修改類的範圍, 版本的管理,擴充套件性等等。
Tinker的未來規劃是真正的開源出去,大約下週會提交分平臺合成以及資源相關的所有程式碼。然後等公司的開源審計結束後將在github開源
對於So,資源的合成方式,dexdiff的技術細節,若大家感興趣可以'read the ** source code'或者與我們交流。
由於時間有限,今天的分享就到這裡,由於準備倉促,再次給大家致歉。
Q0:大神請教下patch程式和主程式是怎麼通訊的?
Q0:是通過intent service通訊的,主程式一個接受補丁結果的intent service,patch程式是一個接受不請求的intent service
Q1:分平臺合成 沒聽太明白,能再仔細說下麼。
Q1:分平臺合成就是在Dalvik平臺,我們合成全量的dex,這可以避免我們插樁的要求。在Art平臺,我們只合成上述三個條件下的類。這裡的難點是同一份diff程式碼,可以做到不同的合成方式。
Q2:對於內部空間不足引起的patch失敗現在有什麼好的解決辦法?
Q2: 對於我們的方案,空間佔用的確比較大。我們解決的方法有兩個,1. 在patch之前提前檢查使用者的剩餘空間,如果使用者剩餘空間過少,即不嘗試。 2. 若本次失敗,我們會有回撥,然後我們會定期重試三次。你也可以採用提示使用者的方式
B0: 程式碼完全開源嗎?
B0:對的,所有程式碼都會開源,從編譯到各個模組。
B1: 微信安卓版現在有幾個activity? 是一個activity 加 多個fragment嗎?
B1:非常抱歉,這個問題跟本次分享無關。事實上,我更建議你反編譯微信的程式碼來研究。
b2:xposed框架的那些外掛,是通過反射呼叫替換值?那一般有啥方式保證安全性?保證app資料的安全性
B2: 它們只要是反射呼叫微信的某些類,達到某些功能的篡改。事實上,如果在root下,單純的保護是比較難的。
B3:為什麼要在補丁成功的時候加結果回撥是為了啟動程式麼,但是和您剛才說的為了實時上報
B3:回撥結果是為了給使用者一個回撥,在這個回撥裡面它可以做各種各樣的工作。例如我彈出升級完成的dialog。我設定鎖屏或者程式進入後臺後自殺,這可以加快補丁的應用
B4:既然能載入so和資源,Tinker能用於外掛化嗎?
B4:Tinker當前沒有做四大元件程式碼,但是Tinker未來絕對是具備這個能力的
B7:這套框架目前是多少個人在維護呢
B7: Tinker當前有3個人在開發維護
b8:請問資源是編譯到arsc中還是反射載入二進位制流?
B8: 你的問題我不太明白,資源我們採用的是全量替換,即完全使用新的資源包
Q6:patchCoreSDK怎麼繞過 換classloader後跨 dex載入類 accesserror的問題?有對patchcoreSDK做強制訪問隔離嗎?
Q6: 是的,Tinker框架分為兩部分,核心載入程式碼,成為loader類,這裡大概有十幾個類,他們是不允許修改的。其他大部分Tinker的類也是可以通過補丁修改的,這裡Tinker框架已經做了處理,即在新合成的Dex,我們已經刪除了loader相關的類,從而徹底避免了這個問題
Q7:patch成功後怎麼及時重啟其他程式?
Q7: 為了保證各個程式的唯一性,我們有一個版本管理檔案用於記錄當前補丁的版本。它分為old與new兩個欄位。同時做了約定,只有patch程式可以修改new欄位,只有主程式可以修改old欄位,其他所有程式啟動時都只會載入old欄位的補丁版本。然後主要主程式可以發起版本升級,即把new欄位賦值給old欄位,這個時候主程式要殺掉其他所有的程式,以保證統一性
以上來內均來自 DEV CLUB 微信直播群,整理髮佈於diycode分享給大家。大家可以去關注微信技術團隊的公眾號WeMobileDev
相關文章
- Android 熱修復 Tinker Gradle Plugin 解析AndroidGradlePlugin
- Android熱修復之Tinker整合最新詳解Android
- Android tinker熱修復——實戰接入專案Android
- Tinker熱修復整合總結
- Android 熱修復 Tinker 接入及原始碼淺析Android原始碼
- Android 熱修復 Tinker 原始碼分析之DexDiff / DexPatchAndroid原始碼
- Android 熱修復 Tinker接入及原始碼淺析Android原始碼
- Android tinker熱修復——從執行demo開始Android
- 你期待已久的熱修復—Tinker熱修復整合總結
- Android進階之Walle多渠道打包&Tinker熱修復Android
- Android 熱修復 - Tinker 實現及踩過的坑Android
- Tinker 熱修復框架 簡單上手教程框架
- tinker熱修復——補丁載入合成
- 簡單易懂的tinker熱修復原理分析
- 自建服務端實現Tinker熱修復服務端
- 深入探索Android熱修復技術原理讀書筆記 —— 熱修復技術介紹Android筆記
- tinker熱修復——dex補丁載入過程
- tinker熱修復——資源補丁載入過程
- Android 熱修復Android
- oracle實驗記錄 (恢復-關於熱備份)Oracle
- Android熱修復原理Android
- Android熱修復原理(一)熱修復框架對比和程式碼修復Android框架
- 【Android 熱修復】美團Robust熱修復框架原理解析Android框架
- 你值得知道的Android 熱修復,以及熱修復原理Android
- 深入探索Android熱修復技術原理讀書筆記 —— 程式碼熱修復技術Android筆記
- 深入探索Android熱修復技術原理讀書筆記 —— 資源熱修復技術Android筆記
- Android 熱修復總結Android
- 筆記 深入探索Android熱修復技術原理筆記Android
- 虎牙直播運維負責人張觀石 | 解密SRE的六種能力及虎牙運維實踐運維解密
- 張紹文android開發高手課讀書筆記1Android筆記
- Flutter Android 端熱修復(熱更新)實踐FlutterAndroid
- Android 熱更新 Tinker 整合配置【詳細】Android
- Android熱修復簡單總結Android
- 研發效能負責人/研發效能1號位 |DevOps負責人dev
- 怎麼檢視已經跟別人聊很久迪士尼平臺修復的微信聊天記錄?
- Android 熱修復其實很簡單Android
- 淺談Android主流熱修復技術Android
- 熱修復初探