双亲机制原理
- ClassLoader使用的是双亲委托模型来搜索类的
- 每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系
- 虚拟机内置的类加载器(Bootstrap ClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。4) 当一个ClassLoader实例需要加载某个类时,它会试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的
- 首先由最顶层的类加载器Bootstrap ClassLoader试图加载
- 如果没加载到,则把任务转交给Extension ClassLoader试图加载7) 如果也没加载到,则转交给App ClassLoader 进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。
- 如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。
- 否则将这个找到的类生成一个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象。
Android类加机制(热更新的机制hotFix\andFix机制)
- 对于Android而言,最终的apk文件包含的是dex类型的文件
- dex文件是将class文件重新打包
- 打包的规则又不是简单地压缩,而是完全对class文件内部的各种函数表,变量表进行优化,产生一个新的文件,即dex文件。
- 因此加载这种特殊的Class文件就需要特殊的类加载器DexClassLoader
- 热更新就是把多个dex文件塞入到app的classloader之中,但是android dex拆包方案中的类是没有重复的,如果classes.dex和classes1.dex中有重复的类,当用到这个重复的类的时候,系统就会选择其中一个类。
- 一个ClassLoader可以包含多个dex文件,每个dex文件是一个Element,多个dex文件排列成一个有序的数组dexElements,当找类的时候,会按顺序遍历dex文件,然后从当前遍历的dex文件中找类,如果找类则返回,如果找不到从下一个dex文件继续查找。理论上,如果在不同的dex中有相同的类存在,那么会优先选择排在前面的dex文件的类
- 在此基础上,我们构想了热补丁的方案,把有问题的类打包到一个dex(patch.dex)中去,然后把这个dex插入到Elements的最前面,当然系统就就会选择我们要更新的类了
- 当然每个热更新框架都会有差异
- 比如说QZone就是严格按照上述思路进行的
- 而hotFix\andFix采用native hook的方式,这套方案直接使用dalvik_replaceMethod替换class中方法的实现。由于它并没有整体替换class, 而field在class中的相对地址在class加载时已确定,所以AndFix无法支持新增或者删除filed的情况(通过替换init与clinit只可以修改field的数值)。Andfix可以支持的补丁场景相对有限,仅仅可以使用它来修复特定问题。
- 微信Tinker就要高明一些,在编译时通过新旧两个Dex生成差异path.dex。在运行时,将差异patch.dex重新跟原始安装包的旧Dex还原为新的Dex。这个过程可能比较耗费时间与内存,所以我们是单独放在一个后台进程:patch中。为了补丁包尽量的小,微信自研了DexDiff算法,它深度利用Dex的格式来减少差异的大小。当然看起来很美好的总有些差强人意的事情出现,比如tinker对小米的支持就不太好。