Small插件化源碼分析--ReflectAccelerator的奏曲

我系蒼王,歡迎關(guān)注的源碼分析的第五節(jié)。

歡迎瀏覽我之前的文章,有興趣可以參考一下,可以給個(gè)喜歡或者關(guān)注我的文章,謝謝。

[Android]如何做一個(gè)崩潰率少于千分之三噶應(yīng)用app(9)-Small插件化

Small插件化源碼分析--啟動(dòng)流程

Small插件化源碼分析--熱更流程

Small插件化源碼分析--InstumentationWrapper生命周期


五.ReflectAccelerator的奏曲

這一節(jié),我們要分析Small真正實(shí)現(xiàn)的核心代碼

這個(gè)文件就是ReflectAccelerator的代碼。

其相關(guān)到resource,dex,lib替換的相關(guān)流程

1.這里需要大家對(duì)classloader有一個(gè)基本的認(rèn)識(shí)

Dalvik虛擬機(jī)如同其他Java虛擬機(jī)一樣,在運(yùn)行程序時(shí)首先需要將對(duì)應(yīng)的類加載到內(nèi)存中。而在Java標(biāo)準(zhǔn)的虛擬機(jī)中,類加載可以從class文件中讀取,也可以是其他形式的二進(jìn)制流。

? PathClassLoader:它只能加載已經(jīng)安裝到 Android 系統(tǒng)中的 apk 文件,也就是 /data/app 目錄下的 apk 文件

? DexClassLoader: 可以加載 apk, jar 或者 dex 文件

而插件化真正用到的就是DexClassLoader,其繼承于ClassLoader。

源碼在DexClassLoader源碼,其源碼在dalvik虛擬機(jī)的目錄里面,所以platform里面無法看到全部的源碼。

我們從第一節(jié)啟動(dòng)流程中有一個(gè)初略的說明,還是分別從resource,dex,lib的替換流程來分析吧

(1)我們首先是利用mergeResouce這個(gè)函數(shù)來加載資源resource的

我們需要自己新建一個(gè)AssetManager或者獲取Aplication的AssetManager。

addAssetPaths中,通過反射的方式來把資源路徑和assetManager替換成我們自己定義的資源

ensureStringBlocks來創(chuàng)建字符串資源池

新建弱引用集合Resources資源

4.4以上的版本,通過反射一個(gè)新的ResourcesManager,用數(shù)組表獲取現(xiàn)在啟動(dòng)應(yīng)用的資源列表。如果獲取不了會(huì)取出reourcesManager里面的mResourceReferences資源指向

4.4以下的版本,使用哈希表來獲取mActiviteResources活躍資源

通過遍歷資源Resources,來替換newAssetManger到mAssets屬性里面

異常會(huì)反射mResourcesImpl代理接口,來替換到mAssets里面

替換后,觸發(fā)資源的配置刷新,讓其可以生效

如果是5.0以上的系統(tǒng),就需要清除應(yīng)用資源每個(gè)字節(jié)池里面的內(nèi)容。

Small里面,并沒有提供移除資源的方法,如果需要改寫,可以自己去添加一個(gè)方法。


(2)添加Dex的時(shí)候,使用的是expandDexPathList的方法

其有少于9到13可以調(diào)用的方法,還有4.0以上所調(diào)用的方法

先看一下9到13的方法

首先獲取mFiles mPaths mZips mDexs的屬性

替換掉全部的這些屬性的變量

通過expandArray調(diào)用System.arraycopy,來添加dexclassloader里面的這些屬性值,

當(dāng)push為true時(shí),其排序是先將目標(biāo)的長度的elements寫入,再寫入原來已經(jīng)加載好的elements到后面

當(dāng)push為false時(shí),是先將已有elements寫入,然后將自己的寫到已有的之后

這里和MultiDex.java使用的是類似的替換方法

這里System.arraycopy的方法是會(huì)調(diào)用到native層去運(yùn)行的,從參數(shù)可以看出其運(yùn)行規(guī)則

再看一下Android4.0以上的添加Dex方法,

其需要的是將Elemets的變量封裝一個(gè)Object的數(shù)組里面

Android4.0以上有DexPathList.java里面封裝了一個(gè)Element的類,用于保存Dex的信息

其makeDexElement的方法,就是用來封裝Element的表

獲取DexPathsList的Delement的類來動(dòng)態(tài)新建一個(gè)Element。

使用fillDexPathList來反射pathList和dexElements的屬性,再使用expandArray來添加資源到尾部

(3)通過expandNativeLibraryDirectories來添加lib的.so文件

android 9~13中,只是獲取libraryPathDeements的屬性,然后獲取加載路徑列表,然后把自定義的列表添加到原來的列表里面,需要用“/”來分隔

android14~22中,是使用反射nativeLibraryDirectories的接口,然后通過expandArray來寫入到library列表之后

android23以上,稍顯復(fù)雜,需要先索引到nativeLibraryDirectories目錄,然后再獲取natveLibraryPathElements的Element對(duì)象列表,然后通過封裝Element的列表對(duì)象,然后再通過expandArray放到末尾

其加載的方法就到這里,然而RefectAccelerator還有一些比較特殊的方法

獲取ActvityThread,如果currentActivityThread存在就返回這個(gè)屬性,否則通過讀取mLoadedApk里面的mActivityThread來獲取

上一節(jié)InstrumentationWrapper的execStartActivity實(shí)際上也是通過ReflectAccelerator封裝的

android 9~20 包裝好types,然后通過getMethod反射獲取execStartActivity的方法,然后再通過反射再次自己的屬性值

反射獲取方法

android21以上原理和以上的以上,只是參數(shù)不同而已


*****************這里是最后的福利******************

這里提供了sliceArray的方法,這個(gè)方法是用來刪除array里面的某個(gè)項(xiàng)的資源的。這個(gè)有什么用,這個(gè)對(duì)對(duì)自定義刪除dex,library都起到至關(guān)重要的作用,如果利用這個(gè)源碼就得大家深入去探究啦。我這邊已經(jīng)是完成了刪除resource,dex,library的源碼修改。


這節(jié)課程就到這里。

Small源碼分析暫時(shí)就到這里。

如果以后有時(shí)間會(huì)再去查看一下aapt等資源打包的流程。

下一節(jié),敬請(qǐng)期待?。?!

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

相關(guān)閱讀更多精彩內(nèi)容

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