安卓虛擬機(jī)
Dalvik:Dalvik是Google公司用于android平臺(tái)的java虛擬機(jī)衬鱼。支持已轉(zhuǎn)化為.dex格式的java應(yīng)用程序的運(yùn)行钦听。.dex格式是專門為Dalvik應(yīng)用設(shè)計(jì)的一種壓縮格式墩崩,適合內(nèi)存和處理器速度有限的系統(tǒng)应媚。
ART:Android Runtime,Android 4.4中引入的一個(gè)開發(fā)者選項(xiàng)扣讼,也是Android 5.0及更高版本的默認(rèn)模式弥雹。在應(yīng)用安裝的時(shí)候Ahead-Of-Time(AOT)預(yù)編譯字節(jié)碼到機(jī)器語(yǔ)言垃帅。這一機(jī)制叫AOT預(yù)編譯。應(yīng)用程序安裝會(huì)變慢剪勿,但是執(zhí)行將更有效率贸诚,啟動(dòng)更快。
在Dalvik下厕吉,應(yīng)用程序需要解釋運(yùn)行酱固,常用熱點(diǎn)代碼通過(guò)即時(shí)編譯器(JIT)將字節(jié)碼轉(zhuǎn)換為機(jī)器碼,運(yùn)行效率低头朱。在ART環(huán)境中运悲,應(yīng)用在安裝時(shí),字節(jié)碼預(yù)編譯(AOT)成機(jī)器碼项钮,安裝慢了班眯,但是運(yùn)行效率會(huì)變高。
格式
ART會(huì)執(zhí)行AOT烁巫,但在Dalvik開發(fā)的應(yīng)用也可以在ART環(huán)境下運(yùn)作署隘。
dexopt:對(duì)dex文件進(jìn)行驗(yàn)證和優(yōu)化生成odex(Optimized dex)文件
dexAot:在安裝時(shí)對(duì)dex文件文件進(jìn)行dex優(yōu)化后為odex文件再進(jìn)行AOT提前編譯操作,編譯為OAT可執(zhí)行文件(機(jī)器碼)亚隙。
ClassLoader
繼承關(guān)系如圖:
` BootClassLoader:
用于加載Android Framework層的class文件磁餐。
` PathClassLoader:
用與android應(yīng)用程序內(nèi)的類加載器∈研可以加載指定的dex崖媚,以及jar/zip/apk中的classes.dex亦歉,主要的實(shí)現(xiàn)實(shí)在BaseDexClassLoader中。
` DexClassLoader
加載指定的dex畅哑,以及jar/zip/apk中的classes.dex肴楷,主要的實(shí)現(xiàn)實(shí)在BaseDexClassLoader中。
在任意的Activity加入如下代碼
ClassLoader classLoader = getClassLoader();
ClassLoader classLoader1 = Activity.class.getClassLoader();
System.out.println("getClassLoader:"+classLoader);
System.out.println("getClassLoader 的父親 :"+classLoader.getParent());
System.out.println("Activity.class :"+classLoader1);
運(yùn)行結(jié)果
getClassLoader:dalvik.system.PathClassLoader[DexPathList[```]]
getClassLoader 的父親 :java.lang.BootClassLoader@1d467fc
Activity.class :java.lang.BootClassLoader@1d467fc
雙親委托機(jī)制
某個(gè)類加載器在加載類時(shí)荠呐,首先將加載任務(wù)委托給parent加載器赛蔫。依次遞歸,如果parent加載器可以完成類加載任務(wù)泥张,就成功返回呵恢;只有parent加載器無(wú)法加載任務(wù)或者沒有parent加載器時(shí),才自己去加載媚创。
分析:loadClass在ClassLoader和BootClassLoader才有實(shí)現(xiàn)渗钉。
protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
//如果被加載過(guò),直接返回钞钙,這就是熱更新的原理鳄橘。
//將新的dex文件傳到dexPathList前面。
Class<?> clazz = findLoadedClass(className);
if (clazz == null) {
ClassNotFoundException suppressed = null;
try {
//遞歸調(diào)用父親的loadClass
clazz = parent.loadClass(className, false);
} catch (ClassNotFoundException e) {
suppressed = e;
}
if (clazz == null) {
try {
//父親找不到芒炼,則自己去加載
clazz = findClass(className);
} catch (ClassNotFoundException e) {
e.addSuppressed(suppressed);
throw e;
}
}
}
return clazz;
}
看看BootClassLoader的loadClass():
protected Class<?> loadClass(String className, boolean resolve)
throws ClassNotFoundException {
//找到后直接返回
Class<?> clazz = findLoadedClass(className);
if (clazz == null) {
//為空則自己去加載
clazz = findClass(className);
}
return clazz;
}
可以看出瘫怜,BootClassLoader重寫了loadClass方法,這里沒有parent屬性本刽。
具體思路
1.首先拿到BaseDexClassLoader里的pathList屬性鲸湃。
···示例代碼
Field pathList= classLoader.getDeclaredField("pathList");
2.找到pathList的makePathElements()方法并調(diào)用子寓,生成新的dexElements暗挑;
···示例代碼
Method method = clazz.getDeclaredMethod("makeDexElements", parameterTypes);
private static Element[] makeDexElements(List<File> files,File optimizedDirectory,
List<IOException> suppressdExceptions,classLoader loader,boolean is Trussed){
Element[] elements = new Element[file.size];
}
makeDexElements()中,files就是dex文件别瞭。
3.將原本的 dexElements 與 makePathElements生成的數(shù)組合并窿祥,修改dexElement的值
//合并后的數(shù)組
Object[] combined ;
System.arraycopy(NewElements, 0, combined, 0, NewElements.length);
System.arraycopy(OldElements, 0, combined, NewElements.length, OldElements.length);