本文框架
什么是热修复?
热修复框架分类
技术原理及特点
Tinker 框架解析
各框架对比图
总结
通过阅读本文, 你会对热修复技术有更深的认知, 本文会列出各类框架的优缺点以及技术原理, 文章末尾简单描述一下 Tinker 的框架结构
一什么是热修复?
正常开发流程
热修复开发流程
热修复优势
修复什么?
二热修复框架分类
现状: 百花齐放百家争鸣
简单分类
更合理的分类
三技术原理及特点
3.1 阿里 Dexposed -- native 解决方案
原理:
直接在 native 层进行方法的结构体信息对换, 从而实现完美的方法新旧替换, 从而实现热修复功能
他的思想完全来源于 Xposed 框架, 完美诠释了 AOP 编程, 这里用到最核心的知识点就是在 native 层获取到指定方法的结构体, 然后改变他的 nativeFunc 字段值, 而这个值就是可以指定这个方法对应的 native 函数指针, 所以先从 Java 层跳到 native 层, 改变指定方法的 nativeFunc 值, 然后在改变之后的函数中调用 Java 层的回调即可实现了方法的拦截功能
基于开源框架 Xposed 实现, 是一种 AOP 解决方案
只 Hook App 本身的进程, 不需要 Root 权限
优点:
即时生效
不需要任何编译器的插桩或者代码改写, 对正常运行不引入任何性能开销这是 AspectJ 之类的框架没法比拟的优势;
对所改写方法的性能开销也极低(微秒级), 基本可以忽略不计;
从工程的角度来看, 热补丁仅仅是牛刀小试, 它真正的威力在于线上调试;
基于 Xposed 原理实现的 AOP 不仅可以 hook 自己的代码, 还可以 hook 同进程的 Android SDK 代码, 这也就可以让我们有能力在 App 中填上 Google 自己挖的坑
缺点:
Dalvik 上近乎完美, 不支持 ART(需要另外的实现方式), 所以 5.0 以上不能用了;
最大挑战在于稳定性与兼容性, 而且 native 异常排查难度更高;
由于无法增加变量与类等限制, 无法做到功能发布级别;
相关链接:
文章: https://www.zhihu.com/question/31894163
文章:
http://www.wjdiankong.cn/android中免root实现hook的dexposed框架实现原理解析以及如何实现/
Dexposed 源码: https://github.com/alibaba/dexposed
Xposed 源码: https://github.com/rovo89/Xposed
3.2 阿里 AndFix -- native 解决方案
原理:
与 Dexposed 一样都基于开源框架 Xposed 实现, 是一种 AOP 解决方案
优点:
即时生效
支持 dalvik 和 art(AndFix supports Android version from 2.3 to 7.0, both ARM and X86 architecture, both Dalvik and ART runtime, both 32bit and 64bit.)
与 Dexposed 框架相比 AndFix 框架更加轻便好用, 在进行热修复的过程中更加方便了
缺点:
面临稳定性与兼容性问题
AndFix 不支持新增方法, 新增类, 新增 field 等
AndFix(Dexpsed)框架不稳定的原因(痛点)
相关链接:
文章: https://zhuanlan.zhihu.com/p/23935568
AndFix 源码: https://github.com/alibaba/AndFix
3.3 QQ 空间 --Dex 插桩方案(大众点评的 Nuwa 参考其实现并开源)
原理:
原理是 Hook 了 ClassLoader.pathList.dexElements[]因为 ClassLoader 的 findClass 是通过遍历 dexElements[]中的 dex 来寻找类的当然为了支持 4.x 的机型, 需要打包的时候进行插桩
越靠前的 Dex 优先被系统使用, 基于类级别的修复
优点:
不需要考虑对 dalvik 虚拟机和 art 虚拟机做适配
代码是非侵入式的, 对 apk 体积影响不大
缺点:
需要下次启动才会生效
最大挑战在于性能, 即 Dalvik 平台存在插桩导致的性能损耗, Art 平台由于地址偏移问题导致补丁包可能过大的问题
虚拟机在安装期间为类打上 CLASS_ISPREVERIFIED 标志是为了提高性能的, 我们强制防止类被打上标志是否会影响性能? 这里我们会做一下更加详细的性能测试.但是在大项目中拆分 dex 的问题已经比较严重, 很多类都没有被打上这个标志
插桩方案性能上的痛点:
相关链接:
文章: https://zhuanlan.zhihu.com/magilu/20308548
文章: http://blog.csdn.net/sbsujjbcy/article/details/50812674
Nuwa 源码: https://github.com/jasonross/Nuwa
HotFix 源码: https://github.com/dodola/HotFix
DroidFix 源码: https://github.com/bunnyblue/DroidFix
3.4 美团 Robust -- Instant Run 热插拔原理
原理:
Robust 插件对每个产品代码的每个函数都在编译打包阶段自动的插入了一段代码, 插入过程对业务开发是完全透明
编译打包阶段自动为每个 class 都增加了一个类型为 ChangeQuickRedirect 的静态成员, 而在每个方法前都插入了使用 changeQuickRedirect 相关的逻辑, 当 changeQuickRedirect 不为 null 时, 可能会执行到 accessDispatch 从而替换掉之前老的逻辑, 达到 fix 的目的
优点:
几乎不会影响性能(方法调用, 冷启动)
支持 Android2.3-8.x 版本
高兼容性 (Robust 只是在正常的使用 DexClassLoader) 高稳定性, 修复成功率高达 99.9%
补丁实时生效, 不需要重新启动
支持方法级别的修复, 包括静态方法
支持增加方法和类
支持 ProGuard 的混淆内联优化等操作
缺点:
代码是侵入式的, 会在原有的类中加入相关代码
so 和资源的替换暂时不支持
会增大 apk 的体积, 平均一个函数会比原来增加 17.47 个字节, 10 万个函数会增加 1.67M
会增加少量方法数, 使用了 Robust 插件后, 原来能被 ProGuard 内联的函数不能被内联了
相关链接:
美团技术文章: https://tech.meituan.com/android_robust.html
美团技术文章: https://tech.meituan.com/android_autopatch.html
Robust 源码: https://github.com/Meituan-Dianping/Robust
3.5 微信 Tinker
原理:
服务端做 dex 差量, 将差量包下发到客户端, 在 ART 模式的机型上本地跟原 apk 中的 classes.dex 做 merge,merge 成为一个新的 merge.dex 后将 merge.dex 插入 pathClassLoader 的 dexElement, 原理类同 Q-Zone, 为了实现差量包的最小化, Tinker 自研了 DexDiff/DexMerge 算法 Tinker 还支持资源和 So 包的更新, So 补丁包使用 BsDiff 来生成, 资源补丁包直接使用文件 md5 对比来生成, 针对资源比较大的 (默认大于 100KB 属于大文件) 会使用 BsDiff 来对文件生成差量补丁
优点:
支持动态下发代码
支持替换 So 库以及资源
缺点:
不能即时生效, 需要下次启动
Tinker 已知问题:
Tinker 不支持修改 AndroidManifest.xml,Tinker 不支持新增四大组件(1.9.0 支持新增非 export 的 Activity);
由于 Google Play 的开发者条款限制, 不建议在 GP 渠道动态更新代码;
在 Android N 上, 补丁对应用启动时间有轻微的影响;
不支持部分三星 android-21 机型, 加载补丁时会主动抛出 "TinkerRuntimeException:checkDexInstall failed";
对于资源替换, 不支持修改 remoteView 例如 transition 动画, notification icon 以及桌面图标
Tinker 性能痛点:
Dex 合并内存消耗在 vm head 上, 容易 OOM, 最后导致合并失败
如果本身 app 占用内存已经比较高, 可能容易导致 app 本系统杀掉
相关链接:
文章: http://geek.csdn.net/news/detail/104000
文章: Tinker 官方文章
Tinker 源码: https://github.com/Tencent/tinker
3.6 阿里 Sophix
原理(双剑合璧):
优化 Andfix(突破底层结构差异, 解决稳定性问题):
Andfix 底层 ArtMethod 结构时采用内部变量一一替换, 倒是这个各个厂商是会修改的, 所以兼容性不好
Sophix 改变了一下思路, 采用整体替换方法结构, 忽略底层实现, 从而解决兼容稳定性问题
突破 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.dexclasses3.dex ... classesx.dex, 如下图所示
资源修复另辟蹊径
常用方案(Instant Run 技术): 这种方案的兼容问题在于替换 AssetManager 的地方
Sophix 资源修复方案
SO 修复另辟蹊径
四 Tinker 框架解析
之所以只贴了 Tinker 的代码框架, 是因为目前开源的方案中是最好的, 当然除了 Robust
代码结构
修复流程
这里后续再补一个详细的源码分析, 敬请期待
五对比图(来自不同的地方)
来自 Tinker 的对比
来自 Sophix 的对比
来自蘑菇街 Android 热修复探索之路
其他文章
浅谈 Android 热修复:
http://blog.csdn.net/caihongdao123/article/details/52051799
Android 热修复专题: 支付宝淘宝微信 QQ 空间饿了么美丽说蘑菇街美团大众点评方案集 https://zhuanlan.zhihu.com/p/25863920
六总结
如果不考虑增大 apk 的体积, 只是简单的修复代码, 不修复 so 和资源, 选择 Robust 是最稳定的, 否则的话选择 Tinker 是一个不错的方案虽然阿里 Sophix 横空出世, 但是它不开源, 而且商业收费, 所以一般不是很赚钱的 app 选择收费的可能就很小了不过它确实各方面都做了大量的优化, 本文中的很多知识点也来源于阿里的 Android 热修复技术原理. pdf 一书, 本书值得一读, 里面就是基于 Sophix 框架来编排的
来源: https://www.cnblogs.com/popfisher/p/8543973.html