一. AndFix
AndFix 的原理就是方法的替换, 把有 bug 的方法替换成补丁文件中的方法.
注: 在 Native 层使用指针替换的方式替换 bug 方法, 已达到修复 bug 的目的.
AndFix 采用 native hook 的方式, 这套方案直接使用 dalvik_replaceMethod 替换 class 中方法的实现. 由于它并没有整体替换 class, 而 field 在 class 中的相对地址在 class 加载时已确定, 所以 AndFix 无法支持新增或者删除 filed 的情况(通过替换 init 与 clinit 只可以修改 field 的数值).Andfix 可以支持的补丁场景相对有限, 仅仅可以使用它来修复特定问题.
二. QZone(插桩方式)
该方案基于的是 Android dex 分包方案的, 简单的概括一下, 就是把多个 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 的最前面, 如下图:
三. 微信 Tinker(差量包)
Instant Run 的冷插拔与 buck 的 exopackage 或许能给我们灵感, 它们的思想都是全量替换新的 Dex.
我们可以将新旧两个 Dex 的差异放到补丁包中, 最简单我们可以采用 BsDiff 算法.
简单来说, 在编译时通过新旧两个 Dex 生成差异 path.dex. 在运行时, 将差异 patch.dex 重新跟原始安装包的旧 Dex 还原为新的 Dex. 这个过程可能比较耗费时间与内存, 所以我们是单独放在一个后台进程: patch 中. 为了补丁包尽量的小, 微信自研了 DexDiff 算法, 它深度利用 Dex 的格式来减少差异的大小.
四, 阿里 Sophix
原理(双剑合璧):
1. 优化 Andfix(突破底层结构差异, 解决稳定性问题):
Andfix 底层 ArtMethod 结构时采用内部变量一一替换, 倒是这个各个厂商是会修改的, 所以兼容性不好.
Sophix 改变了一下思路, 采用整体替换方法结构, 忽略底层实现, 从而解决兼容稳定性问题.
2. 突破 QQ 和 Tinker 的缺陷
QQ 和 Tinker 的缺陷
Sophix 对 dex 的解决方案
Dalvik 下采用阿里自研的全量 dex 方案: 不是考虑把补丁包的 dex 插到所有 dex 前面 (dex 插桩), 而是想办法在原理的 dex 中删除(只是删除了类的定义) 补丁 dex 中存在的类, 这样让系统查找类的时候在原来的 dex 中找不到, 那么只有补丁中的 dex 加载到系统中, 系统自然就会从补丁包中找到对应的类.
Art 下本质上虚拟机以及支持多 dex 的加载, Sophix 的做法仅仅是把补丁 dex 作为主 dex(classes.dex)而已, 相当于重新组织了所有的 dex 文件: 把补丁包的 dex 改名为 classes.dex, 以前 apk 的所有 dex 依次改为 classes2.dex,classes3.dex ... classesx.dex, 如下图所示.
3. 资源修复另辟蹊径
常用方案(Instant Run 技术): 这种方案的兼容问题在于替换 AssetManager 的地方
Sophix 资源修复方案
4.SO 修复另辟蹊径
更多 Android 开发资料 + 面试架构资料 免费分享 点击链接 即可领取
《Android 架构师必备学习资源免费领取(架构视频 + 面试专题文档 + 学习笔记)》
来源: http://www.jianshu.com/p/e0b4cb424b05