Android熱補丁原理簡單分析與問題思考

Android熱補丁(熱修復)從2016年微信的Tinker開源後掀起了一個熱潮。時隔一年,阿里推出《深入探索android熱修復技術原理》技術書籍,在推廣其Sophix的同時非常詳細地描述了其方案的實現過程,以及遇到的各種坑,引來大家的關注與分析。可以看到大公司紛紛推出自己的熱補丁方案,大大小小的應用,都開始嘗試在現有產品中集成或修改使用。

面對熱補丁給人的美好願景,相信大多數開發、運維人員都會爲之所動。我們的產品也期望加入這一功能,但是在一段時間的測試和方案分析後,發現理想很豐滿,現實卻很骨感。本文在簡單分析主流的熱補丁原理後,拋出一些自己想到或遇到的問題作爲思考點,供看到的人蔘考。

熱補丁概念

熱補丁,百科中定義爲“熱補丁(hotfix),又稱爲patch,指能夠修復軟件漏洞的一些代碼,是一種快速、低成本修復產品軟件版本缺陷的方式。”,微信開發者定義爲,“讓應用能夠在無需重新安裝的情況實現更新,幫助應用快速建立動態修復能力”。總的來說,在Android上的期望是,在無需打擾用戶手動安裝的情況下,實現應用的更新。

從字面理解來看,當應用出現嚴重問題需要立即修復,只需下發補丁包,即可快速將問題修復,既不打擾用戶,也可快速修復問題。然後各種減少崩潰率,提升用戶留存等等。再激進一些,直接引申爲熱更新,快速升級應用,豈不是更美好。但你大致理解熱補丁的原理和限制後,再結合應用的實際情況,看看這些方案對你的實際意義。《微信Android熱補丁實踐演進之路》也給了很好的分析和說明。

分類對比

從目前看到的較大的幾個熱補丁方案的技術原理來看,大體可以分爲兩類:
Java層:大部分僅在Java層修改,通過動態加載代碼和資源來實現
Native層:在Java層做處理的同時,Native層做了大量改動來實現代碼替換

先來看看我瞭解到的幾家方案,僅包含目前可用和自認爲比較流行的(如有遺漏,歡迎補充)
Native層修改:
阿里百川Sophix:從AndFix發展而來,但做了大量修改和完善(可以說和AndFix基本不同)。基本包含了Java層動態加載的方案,同時具有底層替換方案,部分情況可在無需重啓動應用的情況下實現修復。定位在緊急修復線上問題和快速發佈新鮮功能。不過不開源,作爲阿里百川的產品服務在提供。

Java層修改:
大體思想都是動態加載,區別在於Multidex中dex如何替換和加載,application類如何替換,so庫如何替換等細節上,也都借鑑了InstantRun的實現。

微信Tinker:重點放在性能上,大量精力集中在盡力減少補丁包體積,定位不只在緊急問題修復,同時認爲可使用在A/B Test上
QQ空間QFix:主要就是熱修復,也沒有開源
美團Robust:重在補丁成功率高,實時修復緊急問題,暫時不支持資源和so的修復
餓了麼Amigo:定位支持熱更新,支持熱修復

借用阿里文章的對比圖:
熱補丁對比圖
由上圖可見,阿里的Sophix功能最強大,另外從其推出的原理解釋書籍也可知它最複雜,而且不開源,一旦出問題,我們就得相信阿里的服務態度(提工單處理服務器的問題還是很快很好的)。Tinker的大量精力在性能上,如怎樣減少補丁包的體積,增加在本地合成Dex的成功率上。對於如何替換Application和so反而需要改動代碼,不太友好。下面我從最簡單的Amigo的實現來看看熱修復在Java層修改的基本原理,同時穿插的說說微信Tinker上的一些不同之處。

原理分析

1.先從整體上簡單看Android應用安裝及運行過程:
(1)應用的apk包被安裝器調用,檢查應用簽名後,解析apk中的AndroidManifest,記錄權限聲明和四大組件等信息,解壓出lib中的so庫;
(2)桌面應用收到應用安裝信息,解析apk獲得應用圖標顯示出來,並存儲啓動Activity信息;
(3)當桌面點擊該應用運行時,調用啓動Activity
(4)由系統啓動應用的進程,默認進程名是應用安裝時寫在AndroidManifest中的包名
(5)應用進程加載apk中dex裏的代碼,加載必要的資源
(6)顯示啓動Activity頁面

2.熱補丁運行流程
熱補丁所做的改動都集中在應用進程啓動後,在加載代碼和資源時做必要的替換,大體流程是引導類,檢查是否有必要升級,需要的話替換代碼和資源。
(1)引導類Application
應用進程能控制的代碼入口是Application,一般在attachBaseContext中和onCreate中處理。Amigo提供編譯插件,在基本不改變現有代碼的情況下,替換Application類爲Amigo類,在attachBaseContext中校驗當前正在使用的版本,判斷是否需要升級,從新apk中解壓代碼和so,最後再調用應用原Application;而Tinker也替換Application,但通過提供註解,生成類似的代理來實現,需要修改使用了自己Application類的代碼。另外在Tinker中dex是補丁包,需要在獨立進程中重新合成新dex,之後才能使用。
(2)代碼替換
在attachBaseContext中反射獲取LoadedApk,並替換mClassloader爲AmigoClassLoader,繼承DexClassLoader,在創建時添加了新的dex,並指定了新so的路徑,覆寫了findResource,loadClass方法。
(3)資源替換
在attachBaseContext中反射獲取資源引用,創建新的AssetManager並替換。

最後,執行attachPatchedApplication,加載補丁apk中的Application,並在onCreate中將Amigo類替換。
需要說明的是這僅是Java層方案的大體流程。阿里Sophix在融合了Java層方案的同時還增加了Native層的實時替換

問題思考

現在來思考熱補丁的定位,是能動態修復問題,但能作爲新應用不斷升級麼?
1.先看限制:
(1)不支持AndroidManifest的修改,新增組件、權限成爲問題;當然如果在裏面設置的各種圖標也被限制到舊的資源文件上(Amigo支持增加組件)
(2)notification & widget中RemoteViews的自定義佈局不支持修改,只支持內容修復

2.再看問題
(1)版本維護問題:
當定位在熱補丁,僅修復緊急問題,之後很快升級到正式版,這樣不會打亂原有的發版計劃和流程,基本問題不大。但是定位成熱更新,頻繁熱修復升級,需要考慮補丁的版本,原版本的不同組合;隨着新版本和新補丁不斷髮布,維護交叉升級,可能會給測試人員和開發人員一定負擔;另外熱補丁的成功率不能做到100%,又涉及到版本回退的問題,當補丁多次後,還能正常回退麼,需要考慮。
(2)熱補丁包問題
Tinker主要精力放在如何縮小補丁包,而Amigo則是全包下發。因此不得不考慮補丁包的大小,以及對流量造成的影響;另外由於添加了proguard等需要保留部分信息,也需要考慮;而原應用有動態加載的,也得考慮相關策略;對於多渠道包,定製版本等,就需要額外考慮
(3)升級控制權問題
個人應用升級控制權都在自己手中,而企業用戶,應用的升級都有客戶參與,這種熱補丁的修復又多了一個去考慮的方面

文章最後,補充下自己選擇Amigo的原因:
(1)雖然Amigo需要下發完整apk,增加了補丁包體積,但是不需要額外維護版本,保持正常的發版流程即可;
(2)對Application的修改比較簡單,不像Tinker那樣無法使用原有的自定義Application類
(3)支持透明的so替換,Tinker需要修改代碼
(4)不用擔心proguard,保留R.txt等
(5)話說Sophix都滿足,但是不開源啊

轉載請註明出處:http://blog.csdn.net/w7849516230,歡迎關注微信公衆號“編程陽光”
“編程陽光”微信公衆號

參考文章:
1.微信Android熱補丁實踐演進之路
2.深入探索android熱修復技術原理
3.QFix探索之路—手Q熱補丁輕量級方案
4.Android熱更新方案Robust

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章