安卓虚拟机
Dalvik:Dalvik是Google公司用于android平台的java虚拟机。支持已转化为.dex格式的java应用程序的运行。.dex格式是专门为Dalvik应用设计的一种压缩格式,适合内存和处理器速度有限的系统。
ART:Android Runtime,Android 4.4中引入的一个开发者选项,也是Android 5.0及更高版本的默认模式。在应用安装的时候Ahead-Of-Time(AOT)预编译字节码到机器语言。这一机制叫AOT预编译。应用程序安装会变慢,但是执行将更有效率,启动更快。
在Dalvik下,应用程序需要解释运行,常用热点代码通过即时编译器(JIT)将字节码转换为机器码,运行效率低。在ART环境中,应用在安装时,字节码预编译(AOT)成机器码,安装慢了,但是运行效率会变高。
格式
ART会执行AOT,但在Dalvik开发的应用也可以在ART环境下运作。
dexopt:对dex文件进行验证和优化生成odex(Optimized dex)文件
dexAot:在安装时对dex文件文件进行dex优化后为odex文件再进行AOT提前编译操作,编译为OAT可执行文件(机器码)。
ClassLoader
继承关系如图:
` BootClassLoader:
用于加载Android Framework层的class文件。
` PathClassLoader:
用与android应用程序内的类加载器。可以加载指定的dex,以及jar/zip/apk中的classes.dex,主要的实现实在BaseDexClassLoader中。
` DexClassLoader
加载指定的dex,以及jar/zip/apk中的classes.dex,主要的实现实在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);
运行结果
getClassLoader:dalvik.system.PathClassLoader[DexPathList[```]]
getClassLoader 的父亲 :java.lang.BootClassLoader@1d467fc
Activity.class :java.lang.BootClassLoader@1d467fc
双亲委托机制
某个类加载器在加载类时,首先将加载任务委托给parent加载器。依次递归,如果parent加载器可以完成类加载任务,就成功返回;只有parent加载器无法加载任务或者没有parent加载器时,才自己去加载。
分析:loadClass在ClassLoader和BootClassLoader才有实现。
protected Class loadClass(String className, boolean resolve) throws ClassNotFoundException {
//如果被加载过,直接返回,这就是热更新的原理。
//将新的dex文件传到dexPathList前面。
Class clazz = findLoadedClass(className);
if (clazz == null) {
ClassNotFoundException suppressed = null;
try {
//递归调用父亲的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()方法并调用,生成新的dexElements;
···示例代码
Method method = clazz.getDeclaredMethod("makeDexElements", parameterTypes);
private static Element[] makeDexElements(List files,File optimizedDirectory,
List suppressdExceptions,classLoader loader,boolean is Trussed){
Element[] elements = new Element[file.size];
}
makeDexElements()中,files就是dex文件。
3.将原本的 dexElements 与 makePathElements生成的数组合并,修改dexElement的值
//合并后的数组
Object[] combined ;
System.arraycopy(NewElements, 0, combined, 0, NewElements.length);
System.arraycopy(OldElements, 0, combined, NewElements.length, OldElements.length);