Android热更新七:Tinker热更新原理

很早之前就想深入的研究和学习一下热修复,由于时间的原因一直拖着,现在才执笔弄起来。


Android而更新系列:
Android热更新一:JAVA的类加载机制
Android热更新二:理解Java反射
Android热更新三:Android类加载机制
Android热更新四:热修复机制
Android热更新五:四大热修复方案分析
Android热更新六:Qzone热更新原理
Android热更新七:Tinker热更新原理
Android热更新八:AndFix热更新原理
Android热更新九:Robust热更新原理
Android热更新十:自己写一个Android热修复


微信针对QQ空间超级补丁技术的不足提出了一个提供DEX差量包,整体替换DEX的方案。主要的原理是与QQ空间超级补丁技术基本相同,区别在于不再将patch.dex增加到elements数组中,而是差量的方式给出patch.dex,然后将patch.dex与应用的classes.dex合并,然后整体替换掉旧的DEX文件,以达到修复的目的。


我们来逆向微信的APK看一下具体的实现:

先找到应用入口TinkerApplication,在onBaseContextAttached()调用了loadTinker(),

进入TinkerLoader的tryLoad()方法中,


从方法名可以预见,在tryLoadPatchFilesInternal()中尝试加载本地的补丁,再经过跳转进入核心修复功能类SystemClassLoaderAdder.class中。


代码中可以看出,根据Android版本的不同,分别采取具体的修复操作,不过原理都是一样的。我们以V19为例,


从代码中可以看到,通过反射操作得到PathClassLoader的DexPatchList,反射调用patchlist的makeDexElements()方法吧本地的dex文件直接替换到Element[]数组中去,达到修复的目的。

对于如何进行patch.dex与classes.dex的合并操作,这里微信开启了一个新的进程,开启新进程的服务TinkerPatchService进行合并。


整体的流程如下:


从流程图来看,同样可以很明显的找到这种方式的特点:

优势:

合成整包,不用在构造函数插入代码,防止verify,verify和opt在编译期间就已经完成,不会在运行期间进行。
性能提高。兼容性和稳定性比较高。
开发者透明,不需要对包进行额外处理。
不足:

  1. 与超级补丁技术一样,不支持即时生效,必须通过重启应用的方式才能生效。

  2. 需要给应用开启新的进程才能进行合并,并且很容易因为内存消耗等原因合并失败。

  3. 合并时占用额外磁盘空间,对于多DEX的应用来说,如果修改了多个DEX文件,就需要下发多个patch.dex与对应的classes.dex进行合并操作时这种情况会更严重,因此合并过程的失败率也会更高。