我系蒼王,歡迎關(guān)注的源碼分析的第五節(jié)。
歡迎瀏覽我之前的文章,有興趣可以參考一下,可以給個(gè)喜歡或者關(guān)注我的文章,謝謝。
[Android]如何做一個(gè)崩潰率少于千分之三噶應(yīng)用app(9)-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)期待?。?!