阿里HotFix2.0升级详解 畅谈热修复领域那些事

简介: 本文所介绍的阿里Hotfix 2.x是在1.x版本进行了优化和创新,不仅支持灵活切换热部署和冷部署的方案;同时,实现了资源、SO文件、类修复的实时生效;整体接入过程采用傻瓜式方法,完全不侵入打包过程,为用户提供了可视化的UI界面。

摘要:

热修复领域充斥着各大流派,如阿里AndFix、美团Robust、QQ空间、微信Tinker等,每种方法各有优劣。本文所介绍的阿里Hotfix 2.x是在1.x版本进行了优化和创新,不仅支持灵活切换热部署和冷部署的方案;同时,实现了资源、SO文件、类修复的实时生效;整体接入过程采用傻瓜式方法,完全不侵入打包过程,为用户提供了可视化的UI界面。


在阿里HotFix2.0升级详解直播中,阿里HotFix核心开发工程师悟二从热修复背景、常见的热修复方案、阿里HotFix历程及2.0的突破与创新三个方面展开了详细的演讲。分享中,他重点介绍了阿里Hotfix2.X 类、SO文件、资源文件修复方案以及管理后台服务,并对阿里Hotfix 2.X将来需要新增的功能也做了展望。

热修复背景

image.png

正常Bug修复流畅包括版本上线、用户安装、发现Bug、紧急修复、重新发版、用户安装六步。该流程中存在着明显的不足,首先重新发布版本代价太大,由于APK是通过多渠道发布的,重新发版时,需要再次对每个渠道推送新的APK包;其次,用户下载安装成本也随之增高;此外,由于需要重新发版、安装,导致Bug修复不及时,用户体验较差。

热修复流程的前四步同正常修复流程相同,但在热修复中,不再进行重新发版,取而代之的是生成上传补丁;此后,SDK拉取加载补丁,完成Bug修复。在热修复过程中,无需重新发版,能够实时高效热修复;同时实现了用户无感知修复,无需下载新的应用,代价小。相比于正常修复过程,热修复的成功率更高,将损失降到了最低。

热修复的几大流派

常见的热修复流派包括阿里AndFix、美团Robust、QQ空间、微信Tinker等,下面来一一介绍。

阿里AndFix

image.png

阿里andfix 热修复方案通过Hook本地方法. 并没有整体替换class,整体流程如下:第一步,打开链接库得到操作句柄, 获取native层内部函数, 得到classobject对象;第二步,修复访问权限属性为Public ;第三步,得到新旧方法的指针,新方法指向目标方法,实现方法的替换。

整个过程中不侵入打包,性能无损耗;同时可以即时生效。其缺点同样明显:兼容性方面很不稳定,需要针对Dalvik虚拟机和Art虚拟机做适配;不支持新增类方法/字段,以及修改方法,也不支持对资源的替换;运行时方法被Patch,有Crash风险。

美团Robust

美团热修复方案Robust 的原理类似Instant Run,每个产品代码的每个函数都在编译打包阶段自动的插入了一段代码。客户端拿到Patch.Dex后,用DexClassLoader加载Patch.Dex。其中的changeQuickRedirect字段赋值为用Patch.Dex中的StatePatch.java这个Class New出来的对象。

在整个打Patch过程中,该方案正常的使用DexClassLoader,兼容性高;未反射注入,能够实时生效。该方案的缺点在于:因为在每端函数前插入代码,需要侵入打包过程;原来能被ProGuard内联的函数不能被内联了,所以可能导致方法数的增加,可能会超过65536限制,同时也会导致APK体积增大;该方案不支持SO文件和资源文件的修复。

手机QQ空间

image.png

手机QQ空间热修复方案可以用注入和插桩概括。其大致过程是:把Bug方法修复之后,放到一个单独的DEX内,插入到Dex Elements数组的最前面,让虚拟机去加载修复完后的方法。

该方案类似谷歌的Multidex ,在保障稳定性的前提下兼容性很高。缺点是:不支持实时生效;在Davilk下,类加载存在性能问题;Art下,补丁包涵有类、父类以及引用该类的所有类,因此补丁包较大;由于原DEX中的类需要引用额外的DEX类,需要侵入式打包。

微信Tinker

微信Tinker为了解决QQ空间补丁技术由于插桩带来的效率问题,引入DEX差量包。其主要的原理与QQ空间超级补丁技术基本相同,最大区别在于:不再将Patch.dex增加到Elements数组中,而是差量的方式给出Patch.Dex;然后将Patch.Dex与应用的Classes.Dex合并,然后整体替换掉旧的DEX,达到修复的目的。

该方案中通过自研DexDiff算法,深度利用Dex的格式来减少差异的大小,从而做到补丁包足够小。其缺点在于:不支持实时生效;由于补丁DEX需要和原DEX合并,需要占用额外内存和磁盘空间,并且很容易因为内存消耗等原因合并失败;与QQ空间补丁技术相同,同样需要侵入式打包。

image.png

上图是Hotfix和主流的热修复方案的效果对比。可以看出,在即时生效、性能消耗、Rom体积、接入复杂度、补丁包大小、类替换、SO文件替换、资源方案等方面,Hotfix都具有相对的优势。

阿里Hotfix 1.x版本

image.png

阿里Hotfix 1.x在AndFix的基础上,增加了补丁管理后台;同时基于手淘的实践,针对AndFix做了大量优化, 性能上提高了兼容和稳定性;功能上支持新增类并提供了更小的补丁包(这是因为基于类方法作为粒度)。

从图中可以看到阿里Hotfix 1.x服务后台功能,用户可以新建应用版本,然后根据版本号上传补丁;此外,还提供了补丁控制功能,比如停止发布、继续发布、灰度/全量发布等功能。

但阿里Hotfix 1.x仍存在很多限制:

不支持资源、So文件修复;不支持新增类方法/类字段,这是因为Hotfix 1.x本质上是Hook一个已存在的的方法;

参数包括Long、Double、Float基本类型的方法不能被Patch,同时参数超过8的方法不能被Patch;

被反射调用的方法不能被Patch,具体来说是非静态方法的反射调用会提示IllegalArgumentException 异常,当静态方法被反射调用,如果反射调用不涉及类对象,则可以被Patch;

构造方法不能被Patch,实际上不允许修改一个类字段(包括静态的和非静态的);

正在运行的方法不能被Patch,也就是说如果一个方法正在运行,然后方法的在Native层的结构被替换, 那么就很可能导致Crash。

阿里Hotfix2.0方案

image.png

相比于1.X版本,阿里Hotfix 2.x版本将上面的限制完全取消,不仅仅只基于AndFix,而是灵活切换热部署和冷部署的方案;实现了资源、SO文件、类修复的实时生效,同时采用了傻瓜式接入方案,完全不侵入打包过程,对用户提供了可视化的UI界面打补丁。

阿里Hotfix 2.x版本由于相比于1.x版本,变更很大,,因此需要预先做大规模的集成测试才会正式上线。

阿里Hotfix2.X 类修复方案

Hotfix2.X在热修复过程中是不侵入打包过程的,而是通过补丁工具生成补丁。由于热部署Andfix修复正在运行的方法有Crash的风险, 所以补丁工具提供参数由业务方来决定是否尝试走热部署;如果用户Patch的方法没有被高频调用同时又有实时生效的需求,那么可以优先选择走热部署方案;但这并非绝对,当代码变更导致热部署不支持时,还是会转向冷部署。

热部署

热部署就是AndFix支持的代码变更,此时走优化后的AndFix方案,也就是Hotfix1.X方案。

冷部署

冷部署就是AndFix不支持的代码变更。冷部署针对Davilk和Art分别做了不同的处理:

  • Davilk下,注入追加到PathClassLoader的dexElements,但无需不插桩,通过Hack本地方法从而绕过dvmresolveclass;
  • Art下直接合成一个完整dex,采用手淘目前成熟的art动态部署方案,最后替换PathClassLoader的dexElements即可。

阿里Hotfix2.X SO文件修复方案

  • Davilk和ART下SO文件加载的方式不一样,导致了需要区分Art和Davilk做不同的处理:
  • ART下预Load原来的SO文件,再加载补丁SO文件;
  • Davilk下预Load补丁SO文件,再加载原来的SO文件。

这里的关键是:综合机型支持的Abis和补丁包中的Abis共同决定补丁SO的新LibPath。这两种加载方式都需要对加载两次SO文件,势必会增加一次本地内存的消耗,因此为了达到更好的性能,在Hotfix2.X中提供了下面两个接口替换掉系统加载SO文件的接口:

  • SOPatchManager.load(String libPath) 代替 System.load(String pathName)
  • SOPatchManager.loadLibrary(String libName)代替 System.loadLibrary(String libName)

阿里Hotfix2.X 资源文件修复方案

在资源文件中,资源ID编码于Resources.arsc文件中,排布紧密,并按照排布顺序进行自动编号;RES目录保存所有带ID的资源文件。布局文件为二进制形式的XML文件,XML以资源ID的方式引用其他资源;Assets目录存放所有原始文件,不带ID;Aapt进行资源的构造,包括自动分配资源ID与R文件的生成,默认情况下,每次编译不保证和之前包中的ID一致。

目前市面上普遍采用的三种资源修复方案:

  • 差量合成完整的资源包,运行时完整加载资源;这种方案的缺点是:合成资源占用时间和内存,容易引起卡顿。
  • 修改aapt,对以后可能新增的资源提前留空,运行时Patch包中新增资源ID对应留出的位置;该方案的缺点是:需改变打包流程,修改代码并编译替换SDK中的Aapt;打包侵入太强,且留空占用一定磁盘空间。留空多少是预先定好的,无法改变。
  • 插件化,组件化资源;这种方式的缺点是:资源需要划分模块,提前规划。

百川资源文件修复方案直接基于新旧两个APK来构造补丁包,不需要改造AAPT,对编译过程无要求;同时,精确比较各个资源ID的使用情况,最大程度利用原先基线包资源,补丁包中只包含新增和修改的资源;在运行时无需合成操作,快速应用生效,不影响性能。

百川资源文件修复方案不仅仅是简单修复,对于任意程度、乃至天翻地覆的修改都能适用,但补丁文件会比较大,该方案兼容Android所有机型,只需选取新旧两个APK,一键快捷生成补丁,并且稳定性较好;配合类修复方案,能够做到资源修复的实时生效。在使用百川资源文件修复方案,需要注意以下地方:

(1)如果事先自己做了资源混淆,需要保证新旧包混淆的关系保持一致,否则打补丁时会找不到原来基线包中资源,而将非新增资源视为新增资源,导致补丁包变大。

(2)建议每次打包时设置去除无用的资源。这样即可以减小包大小,同时也保证补丁包中新增资源都是有用的。

(3)AndroidManifest中引用的资源无法改变。有些资源如icon是安装时固定的,目前所有补丁方案都无法进行改变。而另一些资源,如Theme,我们可以提取AndroidManifest中的资源信息,通过代码的方式进行设置。

阿里Hotfix管理后台服务

阿里Hotfix后台目前提供的服务主要有:补丁灰度发布/正式发布、补丁回滚和补丁安全。

  • 补丁灰度发布/正式发布,在发布前可以通过本地或扫码两种方式验证之后再发布上线; 本地补丁模式是指补丁可以放到任何一个指定的目录下即可;扫码模式是扫描二维码生成一个下载URL,然后直接下载,此时不需同服务器验证身份;灰度发布指定具体的用户数然后随机推送。
  • 补丁回滚是指发生错误时可以回滚到目标补丁版本,同时该应用版本下的所有设备都会回滚到目标补丁的版本。
  • 补丁安全方面,HotFix后台托管了RSA密钥,同在在补丁加载时需要进行安全签名校验。

在不远的将来未来,将在阿里HotFix平台上推出以下服务:

  • 补丁自定义平台无关AES秘钥。在打补丁时,用户可以自定义AES密码,然后在SDK初始化时填入这个秘钥即可。阿里百川平台对该秘钥完全无感知,做到补丁在后台的绝对安全。
  • 补丁条件下发,支持分系统版本、分渠道以及自定义TAG的方式下发补丁到目标位置。
  • 实时显示补丁加载成功率等数据,后续可能会上报补丁加载失败详情, 方便排查问题。
  • 一键清除补丁,使用回滚功能必需要具备两个条件:①当前的版本已停止发布;②- 该版本之前存在至少一个历史版本。所以如果第一个补丁就下发错误的话,补丁回滚就无能为力了,所以需要提供一键清除补丁的功能。

在Swift Hot Patch上的进展

在Swift 3推出之后,也是有越来越多的项目转向了Swift。那么,在业界技术分享言必称Swift的时代,Hot Patch对Swift的支持情况又是怎样呢?

image.png

目前业界已有两种成熟的产品:WAX和JSPatch。前者是基于Lua语言的Patch方案;后者是基于JavaScript语言的Patch方案。两者都依托于Objective-C的Runtime,通过Method Swizzling将待Patch方法的实现替换为_objc_msgForward/_objc_msgForward_stret,再替换forwardInvocation:为特定语言的桥接方法来调用补丁实现。

由于两者都强依赖Objective-C的Runtime和NSObject的forward机制,它们在支持Swift Hot Patch时就会受到相应约束。

image.png

相比于WAX和JSPatch,Rollout.io是更面向Swift的Hot Patch方案。它在编译器swiftc前增加了代码注入逻辑,修改swift相关的代码。这样,swiftc在编译时使用的就是经过注入的代码了。这里以viewDidLoad方法为例,说明代码的注入:首先,根据方法ID取出Patch所需的数据;接着,判断是否应该Patch;如果应该Patch,则以Patch数据、target、方法入参和方法调用closure为参数执行Patch。经过注入,Patch就可以替代任何方法的原始实现。

然而,Rollout.io的实现有很多问题:它支持的Patch非常受限,只能patch class instance function;此外,它并不支持在Patch中调用Swift方法,调用Objective-C方法时,它的语法也非常繁琐。

image.png

HotFix的Swift Hot Patch融合了WAX/JSPatch和Rollout.io的优长,并补足了Rollout.io在Patch方面的短板。具体来说,除了在class function patch时没有WAX/JSPatch和Rollout.io的诸多限制外,也同时支持global function、struct function和enum function的Patch。在调用Objective-C方法时,维持了简短的语法;同时,也正在研究动态调用Swift方法的方式。

image.png

SteveMcConnell在《CodeComplete》中曾说过“Program into your language, not in it”。希望Swift Hot Patch工具能够帮助更多的开发者深入Swift,自由地使用语言去表达自己的思想,而不只是停留在语法层面。

相关文章
|
7月前
|
IDE 小程序 开发工具
【社区每周】商家平台数据中心功能升级;IDE 3.4.1 Beta 版本上线(1月第一期)
【社区每周】商家平台数据中心功能升级;IDE 3.4.1 Beta 版本上线(1月第一期)
67 11
|
7月前
|
供应链 安全 IDE
重磅发布|OpenSCA SaaS全新上线
OpenSCA SaaS全新上线!
93 0
|
数据可视化 前端开发 JavaScript
【技术战疫】G2 4.0 正式版发布!
![image.png](https://ata2-img.cn-hangzhou.oss-pub.aliyun-inc.com/b38d8b3099e0f743dffb1e0f535b0f0c.png) > G2 是一套面向常规统计图表,以数据驱动的高交互可视化图形语法。 经历了为期半年的大规模底层重构和开发迭代,G2 4.0 终于和大家见面了。作为继 2017 年 11 月 2
【技术战疫】G2 4.0 正式版发布!
在EMAS应用研发平台上进行热修复补丁的生成可能遇到的问题
在EMAS应用研发平台上进行热修复补丁的生成可能遇到的问题
81 1
|
开发工具 git
《百度万人研发团队 Git 工具链建设的挑战与思考》电子版地址
百度万人研发团队 Git 工具链建设的挑战与思考
80 0
《百度万人研发团队 Git 工具链建设的挑战与思考》电子版地址
|
数据采集 监控 Dubbo
官宣!Hippo4j 1.4.x 新版本正式发布,探索更多玩法
官宣!Hippo4j 1.4.x 新版本正式发布,探索更多玩法
336 0
|
存储 数据可视化 中间件
|
监控 人机交互 持续交付
低调不了!最佳体验尽在 Erda 2.0 版本
大家期待已久的 Erda V2.0 带着全新界面风格和特性改进震撼发布! 本次版本升级也意味着 Erda 在技术层面不断提升的同时,在用户体验上也投入了大量精力。界面作为人机交互的重要“桥梁”,我们希望用户感受到的不仅仅是 Erda 的强大功能,更希望给大家呈现优雅、舒适的操作体验!那么下面我们一起来看看本次新版本将会有哪些亮点和大家见面~
178 0
低调不了!最佳体验尽在 Erda 2.0 版本
|
存储 敏捷开发 运维
记一次某官网商城改造升级项目出现的重量级BUG修复总结与复盘
印象中最深刻的一次BUG是N年前在为某保险公司官网商城改造升级项目中出现的故障,也付出了非常昂贵的代价,作为回顾总结分享描述一下当时线上出现的问题现象及分析解决过程,避免再次发生类似故障,并以此长文记录,引以为戒,警钟常鸣。
1196 0
|
安全 AndFix 测试技术
阿里HotFix2.0升级详解——技术运营小二畅谈热修复领域那些事
热修复领域充斥着各大流派,如阿里AndFix、美团Robust、微信Tinker等,每种方法各有优劣。本文介绍的百川Hotfix 2.x是在1.x版本进行了优化和创新,不仅支持灵活切换热部署和冷部署的方案;实现了资源、SO文件、类修复的实时生效;接入时不侵入打包过程,并为用户提供了可视化的UI界面。
10071 3