Android 热修复 技术浅析
一、Android 中的两大流派:
1、Native Hook 流派:改写 方法:淘宝的Dexposed,支付宝的AndFix 、Rebust、instantRun ?
Dexposed只只吃Android 5.0之下,不支持全平台。
2、dex hack 流派:QQ超级补丁,Tinker 。
二、方案分析
http://www.chinaz.com/news/2016/0912/579753.shtml
1、QQ空间超级补丁:
(1)mutilDex机制。QQ空间超级补丁方案是基于android dex分包方案。
分包机制的来由(?)dexopt 、65K限制。
当一个apk在安装的时候,apk中的classes.dex会被虚拟机(dexopt)优化成odex文件,然后才会拿去执行。
(2)ClassLoader 类加载机制。ClassLoader机制是QQ空间超级补丁方案的基石。
tm一个ClassLoader可以包含多个dex文件,每个dex文件就是一个 Element,多个dex文件排列形成一个有序的数组DexElements,当查找某个类时会按照顺序遍历dex文件,然后从当前遍历的dex文件中找类,如果找到了则返回,如果找不到则从下一个dex查找。理论上,如果在不同的dex中有相同的类存在,那么优先选择排在前面的dex文件的类。
(3)副作用:CLASS_ISPREVERIFIED 标志。
防止类被打上CLASS_ISPREVERIFIED标志。
最终空间的方案是往所有类的构造函数里面插入了一段代码,如下:
if (ClassVerifier.PREVENT_VERIFY) {
System.out.println(AntilazyLoad.class);
}
这样当安装apk的时候,classes.dex内的类都会引用一个在不相同dex中的AntilazyLoad类,这样就防止了类被打上CLASS_ISPREVERIFIED的标志了,只要没被打上这个标志的类都可以进行打补丁操作。
优势:
1. 没有合成整包(和微信Tinker比起来),产物比较小,比较灵活
2. 可以实现类替换,兼容性高。(某些三星手机不起作用)
不足:
1. 不支持即时生效,必须通过重启才能生效。
2. 为了实现修复这个过程,必须在应用中加入两个dex!dalvikhack.dex中只有一个类,对性能影响不大,但是对于patch.dex来说,修复的类到了一定数量,就需要花不少的时间加载。对手淘这种航母级应用来说,启动耗时增加2s以上是不能够接受的事。
3. 在ART模式下,如果类修改了结构,就会出现内存错乱的问题。为了解决这个问题,就必须把所有相关的调用类、父类子类等等全部加载到patch.dex中,导致补丁包异常的大,进一步增加应用启动加载的时候,耗时更加严重。
2、微信 Tinker
在编译时通过新旧两个Dex生成差异path.dex。在运行时,将差异patch.dex重新跟原始安装包的旧Dex还原为新的Dex。这个过程可能比较耗费时间与内存,所以我们是单独放在一个后台进程:patch中。
优势:
1. 合成整包,不用在构造函数插入代码,防止verify,verify和opt在编译期间就已经完成,不会在运行期间进行。
2. 性能提高。兼容性和稳定性比较高。
3. 开发者透明,不需要对包进行额外处理。
不足:
1. 与超级补丁技术一样,不支持即时生效,必须通过重启应用的方式才能生效。
2. 需要给应用开启新的进程才能进行合并,并且很容易因为内存消耗等原因合并失败。
3. 合并时占用额外磁盘空间(占用Rom体积),这边大约是你修改Dex数量的1.5倍(dexopt与dex压缩成jar)的大小)。
微信的这套方案并非没有优缺点,它带来的问题有两个:
占用Rom体积;这边大约是你修改Dex数量的1.5倍(dexopt与dex压缩成jar)的大小。
一个额外的合成过程;虽然我们单独放在一个进程上处理,但是合成时间的长短与内存消耗也会影响最终的成功率
四、AndFix:
AndFix 提供一种运行时在Native修改Field指针的方式,实现方法的替换,达到即时生效无需重启,对应用无性能损耗的目的。
1、原理如图:
2、实现过程: