Tinker熱修復(fù)原理探究

默認(rèn)已知:Android Apk的打包過程。

Tinker熱修復(fù)分三部分:

class文件修復(fù)、資源文件修復(fù)和so文件修復(fù)。


一、class文件修復(fù)(代碼修復(fù))原理

1. ClassLoader源碼解讀,局部的繼承關(guān)系:

ClassLoader->BaseDexClassLoader->DexClassLoader->DexClassLoaderProvider

2. Android Dex文件的加載過程:

我們會使用DexClassLoader去加載dex文件,DexClassLoader會將這個任務(wù)委派給DexPathList中的makeDexElements方法,在makeDexElements中調(diào)用了native層的 c++方法去真正的加載dex文件,然后返回DexFile的對象,通過這個對象構(gòu)建一個Element的對象,然后將這個Element添加到dexElements的數(shù)組中。

3. class文件的查找過程:

DexClassLoader通過findClass去查找一個類,同樣它也是委派給DexPathList的findClass去查找,在DexPathList的findClass中會去遍歷我們上面創(chuàng)建的dexElements數(shù)組,然后在每個dex中去查找相應(yīng)的類,找到之后就返回,不再向后查找。

4. 補(bǔ)丁包的合并過程:

Patch拿下來之后,會開啟一個Service,把Patch包和Bug Dex合并,并置于tinker的文件加載路徑中。

5. 補(bǔ)丁包的加載流程:

讀取到有合并后的補(bǔ)丁dex,通過反射得到DexPathList中的dexElements數(shù)組,并將新的dex放在數(shù)組的最前面,完成修復(fù)。

二、 資源文件修復(fù)

1. Resource類對象的構(gòu)建過程:

所有的資源文件是通過Resource類獲取到的,創(chuàng)建一個Resource對象需要三個參數(shù)AssetManager、DisplayMetrics和Configuration,后兩個參數(shù)都是全局單例的,直接通過getResources().getDisplayMetrics(),

getResources().getConfiguration()就可以,而一個AssetManager對象的關(guān)鍵就在于addAssetPath方法以指定resource目錄的路徑,直接newInstance后通過反射拿到addAssetPath,invoke傳參一個resDir目錄即可得到對應(yīng)的AssetManager對象。


2. 補(bǔ)丁加載過程:

先將Patch中的Resource和原有Resource合并,而后保存到本地->

通過當(dāng)前的Activity線程去獲取到所有已加載的apk(loadedApk)->

將所有l(wèi)oadedApk的resDir目錄都替換成新的Resource目錄->

創(chuàng)建新的resDir目錄對應(yīng)的AssetManager對象->

替換原有全部的Resource對象里的AssetManager,即可完成修復(fù)。

三、 動態(tài)鏈接庫修復(fù)

Android里面關(guān)于so的加載的兩種方式:

1.? ? System.loadLibrary

這種方式傳入的是so的名字,會直接從系統(tǒng)的目錄去加載so文件,系統(tǒng)的路徑包括/data/data/${package_name}/lib、/system/lib、/vender/lib等這類路徑。

2.? ? System.load

這種方式傳入的是so的絕對路徑,直接從這個路徑加載so文件。

Tinker的so文件熱更新的原理就是通過方式二,直接加載新的so實現(xiàn)的。


1. 補(bǔ)丁生成:

生成補(bǔ)丁時比較新舊so文件使用BSdiff算法生成補(bǔ)丁包。

2. 補(bǔ)丁合成:

下發(fā)補(bǔ)丁成功后根據(jù)BSpatch算法將補(bǔ)丁包和舊的library合成新的library并保存在tinker下面的目錄下:/data/data/${package_name}/tinker/lib。

3. 補(bǔ)丁加載:

通過System.load加載該目錄下面的so文件。


注意:Tinker中so的熱更新對用戶并不是無感的,需要用戶自發(fā)的去加載自己需要的庫文件。

下面是tinker的wiki里關(guān)于這方面的描述:

Tinker并沒有直接將補(bǔ)丁的lib路徑添加到DexPathList中,理論上這樣可以做到程序完全沒有感知的對Library文件作補(bǔ)丁。這里主要是因為在多abi的情況下,某些機(jī)器獲取的并不準(zhǔn)確。

所以想要加載最新的庫,需要自己使用TinkerInstaller.load*Library去加載庫文件,它會自動嘗試先去Tinker中的庫文件加載,加載不成功會調(diào)用System.loadLibrary調(diào)用系統(tǒng)的庫文件。如TinkerInstaller.loadArmLibrary()或TinkerInstaller.loadArmV7Library()

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容