资源修复
资源热修复原理:
1)创建新的AssetManager,通过反射调用addAssetPath方法加载外部的资源,这样新建的AssetManager就含有了外部资源。
2)将AssetManager类型的mAssets字段引用全部替换为新创建的AssetManager。
代码修复
代码修复主要有三个方案,分别是底层替换方案、类加载方案和Instant Run方案
类加载方案
类加载方案基于Dex分包方案.Dex分包方案主要做的是在打包时将应用代码分成多个Dex,将应用启动时必须要用到的类和这些类的直接引用类放到主Dex中,其他代码放次Dex中。当应用启动时先加载主Dex,等到应用启动后再动态加载次Dex,从而缓解主Dex的65536限制和LinearAlloc限制。
Element内部封装了DexFile,DexFile用于加载dex文件,因此每个dex文件对应一个Element。
多个Element组成了有序的Element数组dexElements。当要查找类时,会在注释1处遍历Element数组dexElements(相当于遍历dex文件数组),注释2处调用Element的findClass方法,其方法内部会调用DexFile的loadClassBinaryName方法查找类。如果在Element中(dex文件)找到了该类就返回,如果没有找到就接着在下一个Element中进行查找。
根据上面的查找流程,我们将有bug的类Key.class进行修改,再将Key.class打包成包含dex的补丁包Patch.jar,放在Element数组dexElements的第一个元素,这样会首先找到Patch.dex中的Key.class去替换之前存在bug的Key.class,排在数组后面的dex文件中的存在bug的Key.class根据ClassLoader的双亲委托模式就不会被加载,这就是类加载方案,如下图所示。
类加载方案需要重启App后让ClassLoader重新加载新的类,为什么需要重启呢?这是因为类是无法被卸载的,因此要想重新加载新的类就需要重启App,因此采用类加载方案的热修复框架是不能即时生效的。
底层替换方案
一个方法在ART虚拟机中对应的一个ArtMethod指针,ArtMethod结构体中包含了Java方法的所有信息,包括执行入口、访问权限、所属类和代码执行地址等等,
ArtMethod结构中比较重要的字段是注释1处的dexcache_resolved_methods和注释2处的entrypoint_from_quick_compiled_code,它们是方法的执行入口,当我们调用某一个方法时(比如Key的show方法),就会取得show方法的执行入口,通过执行入口就可以跳过去执行show方法。
替换ArtMethod结构体中的字段或者替换整个ArtMethod结构体,这就是底层替换方案。
AndFix采用的是替换ArtMethod结构体中的字段,这样会有兼容问题,因为厂商可能会修改ArtMethod结构体,导致方法替换失败。Sophix采用的是替换整个ArtMethod结构体,这样不会存在兼容问题。
底层替换方案直接替换了方法,可以立即生效不需要重启。采用底层替换方案主要是阿里系为主,包括AndFix、Dexposed、阿里百川、Sophix。