阿里HotFix2.0升级详解——技术运营小二畅谈热修复领域那些事-阿里云开发者社区

开发者社区> 场景研读> 正文

阿里HotFix2.0升级详解——技术运营小二畅谈热修复领域那些事

简介: 热修复领域充斥着各大流派,如阿里AndFix、美团Robust、微信Tinker等,每种方法各有优劣。本文介绍的百川Hotfix 2.x是在1.x版本进行了优化和创新,不仅支持灵活切换热部署和冷部署的方案;实现了资源、SO文件、类修复的实时生效;接入时不侵入打包过程,并为用户提供了可视化的UI界面。
+关注继续查看

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

以下内容根据直播视频和PPT整理而成。


热修复背景

4e3141b45dffd07d28954faaecdb5c9bdbccdf79

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

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

热修复的几大流派

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

阿里AndFix

 

 

58fc2453156105deafc6ef9c0e86957f8f8c3938

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

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

 

22b4141f07a6d1f8a96d46febfa5da1318bdf4f4

手机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空间补丁技术相同,同样需要侵入式打包。

de8f0d747e030a132ca292a98f50aa1bc2cce9b5

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

阿里百川Hotfix 1.x版本

f2f895ab3a6b15a5864e2dd9d9188c5b5ff75f13

百川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方案

1368a95bb06821b873dac06d8ecd22ddbb274ccb

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

百川Hotfix 2.x版本预计在明年一月中旬正式上线,实际上目前已经完成了90%开发工作。 但是由于相比于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的支持情况又是怎样呢?

0e7ca6732f3d2bbef58f961788545307219dd88f

目前业界已有两种成熟的产品: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时就会受到相应约束。

a67f9bb8a384c28c8c16d7b395b2088ceca73cb5

相比于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方法时,它的语法也非常繁琐。

a4fccc178368259653997238d2885da980497a01

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方法的方式。

9fcabd20ec49ebe80883c2bbfd6dc6c1269b9033

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


相关服务

阿里百川HotFix:http://baichuan.taobao.com/product/hotfix.htm

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
centos 7 升级后yum install出现Exiting on user cancel
centos 7 升级后yum install出现Exiting on user cancel centos 7.x升级后用yum install进行安装时经常出现Exiting on user cancel,例如: [root@localhost ~]# yum install logstash ...
1718 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
4486 0
【阿里云资讯】最前沿人工智能,助力双11搜索推荐技术再升级——深度增强学习大规模在线应用
11月12日消息,天猫“双11”销售额6分58秒破百亿;前30分钟内交易峰值17.5万笔/秒,支付峰值12万笔/秒,24小时实现销售额1207亿元。用户更快、更准购物体验来自于搜索和推荐的数据智能的提升。
3182 0
阿里云物联网平台基于iOS Link kit SDK做OTA升级
第一次在平台写文章,如有错误,请多多包涵
194 0
android 标准OTA升级流程
标准的OTA升级流程包括一下几个步骤: 1.Android设备首先会与OTA服务器进行交互,如果有更新会推送给客户。推送的信息常常会包含OTA更新包的下载地址和一些版本信息。 2.Update程序会将更新包下载到cache分区下,并提醒用户安装更新。
1725 0
+关注
场景研读
技术学习永无止境
476
文章
8
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载