Android热补丁原理简单分析与问题思考

Android热补丁(热修复)从2016年微信的Tinker开源后掀起了一个热潮。时隔一年,阿里推出《深入探索android热修复技术原理》技术书籍,在推广其Sophix的同时非常详细地描述了其方案的实现过程,以及遇到的各种坑,引来大家的关注与分析。可以看到大公司纷纷推出自己的热补丁方案,大大小小的应用,都开始尝试在现有产品中集成或修改使用。

面对热补丁给人的美好愿景,相信大多数开发、运维人员都会为之所动。我们的产品也期望加入这一功能,但是在一段时间的测试和方案分析后,发现理想很丰满,现实却很骨感。本文在简单分析主流的热补丁原理后,抛出一些自己想到或遇到的问题作为思考点,供看到的人参考。

热补丁概念

热补丁,百科中定义为“热补丁(hotfix),又称为patch,指能够修复软件漏洞的一些代码,是一种快速、低成本修复产品软件版本缺陷的方式。”,微信开发者定义为,“让应用能够在无需重新安装的情况实现更新,帮助应用快速建立动态修复能力”。总的来说,在Android上的期望是,在无需打扰用户手动安装的情况下,实现应用的更新。

从字面理解来看,当应用出现严重问题需要立即修复,只需下发补丁包,即可快速将问题修复,既不打扰用户,也可快速修复问题。然后各种减少崩溃率,提升用户留存等等。再激进一些,直接引申为热更新,快速升级应用,岂不是更美好。但你大致理解热补丁的原理和限制后,再结合应用的实际情况,看看这些方案对你的实际意义。《微信Android热补丁实践演进之路》也给了很好的分析和说明。

分类对比

从目前看到的较大的几个热补丁方案的技术原理来看,大体可以分为两类:
Java层:大部分仅在Java层修改,通过动态加载代码和资源来实现
Native层:在Java层做处理的同时,Native层做了大量改动来实现代码替换

先来看看我了解到的几家方案,仅包含目前可用和自认为比较流行的(如有遗漏,欢迎补充)
Native层修改:
阿里百川Sophix:从AndFix发展而来,但做了大量修改和完善(可以说和AndFix基本不同)。基本包含了Java层动态加载的方案,同时具有底层替换方案,部分情况可在无需重启动应用的情况下实现修复。定位在紧急修复线上问题和快速发布新鲜功能。不过不开源,作为阿里百川的产品服务在提供。

Java层修改:
大体思想都是动态加载,区别在于Multidex中dex如何替换和加载,application类如何替换,so库如何替换等细节上,也都借鉴了InstantRun的实现。

微信Tinker:重点放在性能上,大量精力集中在尽力减少补丁包体积,定位不只在紧急问题修复,同时认为可使用在A/B Test上
QQ空间QFix:主要就是热修复,也没有开源
美团Robust:重在补丁成功率高,实时修复紧急问题,暂时不支持资源和so的修复
饿了么Amigo:定位支持热更新,支持热修复

借用阿里文章的对比图:
热补丁对比图
由上图可见,阿里的Sophix功能最强大,另外从其推出的原理解释书籍也可知它最复杂,而且不开源,一旦出问题,我们就得相信阿里的服务态度(提工单处理服务器的问题还是很快很好的)。Tinker的大量精力在性能上,如怎样减少补丁包的体积,增加在本地合成Dex的成功率上。对于如何替换Application和so反而需要改动代码,不太友好。下面我从最简单的Amigo的实现来看看热修复在Java层修改的基本原理,同时穿插的说说微信Tinker上的一些不同之处。

原理分析

1.先从整体上简单看Android应用安装及运行过程:
(1)应用的apk包被安装器调用,检查应用签名后,解析apk中的AndroidManifest,记录权限声明和四大组件等信息,解压出lib中的so库;
(2)桌面应用收到应用安装信息,解析apk获得应用图标显示出来,并存储启动Activity信息;
(3)当桌面点击该应用运行时,调用启动Activity
(4)由系统启动应用的进程,默认进程名是应用安装时写在AndroidManifest中的包名
(5)应用进程加载apk中dex里的代码,加载必要的资源
(6)显示启动Activity页面

2.热补丁运行流程
热补丁所做的改动都集中在应用进程启动后,在加载代码和资源时做必要的替换,大体流程是引导类,检查是否有必要升级,需要的话替换代码和资源。
(1)引导类Application
应用进程能控制的代码入口是Application,一般在attachBaseContext中和onCreate中处理。Amigo提供编译插件,在基本不改变现有代码的情况下,替换Application类为Amigo类,在attachBaseContext中校验当前正在使用的版本,判断是否需要升级,从新apk中解压代码和so,最后再调用应用原Application;而Tinker也替换Application,但通过提供注解,生成类似的代理来实现,需要修改使用了自己Application类的代码。另外在Tinker中dex是补丁包,需要在独立进程中重新合成新dex,之后才能使用。
(2)代码替换
在attachBaseContext中反射获取LoadedApk,并替换mClassloader为AmigoClassLoader,继承DexClassLoader,在创建时添加了新的dex,并指定了新so的路径,覆写了findResource,loadClass方法。
(3)资源替换
在attachBaseContext中反射获取资源引用,创建新的AssetManager并替换。

最后,执行attachPatchedApplication,加载补丁apk中的Application,并在onCreate中将Amigo类替换。
需要说明的是这仅是Java层方案的大体流程。阿里Sophix在融合了Java层方案的同时还增加了Native层的实时替换

问题思考

现在来思考热补丁的定位,是能动态修复问题,但能作为新应用不断升级么?
1.先看限制:
(1)不支持AndroidManifest的修改,新增组件、权限成为问题;当然如果在里面设置的各种图标也被限制到旧的资源文件上(Amigo支持增加组件)
(2)notification & widget中RemoteViews的自定义布局不支持修改,只支持内容修复

2.再看问题
(1)版本维护问题:
当定位在热补丁,仅修复紧急问题,之后很快升级到正式版,这样不会打乱原有的发版计划和流程,基本问题不大。但是定位成热更新,频繁热修复升级,需要考虑补丁的版本,原版本的不同组合;随着新版本和新补丁不断发布,维护交叉升级,可能会给测试人员和开发人员一定负担;另外热补丁的成功率不能做到100%,又涉及到版本回退的问题,当补丁多次后,还能正常回退么,需要考虑。
(2)热补丁包问题
Tinker主要精力放在如何缩小补丁包,而Amigo则是全包下发。因此不得不考虑补丁包的大小,以及对流量造成的影响;另外由于添加了proguard等需要保留部分信息,也需要考虑;而原应用有动态加载的,也得考虑相关策略;对于多渠道包,定制版本等,就需要额外考虑
(3)升级控制权问题
个人应用升级控制权都在自己手中,而企业用户,应用的升级都有客户参与,这种热补丁的修复又多了一个去考虑的方面

文章最后,补充下自己选择Amigo的原因:
(1)虽然Amigo需要下发完整apk,增加了补丁包体积,但是不需要额外维护版本,保持正常的发版流程即可;
(2)对Application的修改比较简单,不像Tinker那样无法使用原有的自定义Application类
(3)支持透明的so替换,Tinker需要修改代码
(4)不用担心proguard,保留R.txt等
(5)话说Sophix都满足,但是不开源啊

转载请注明出处:http://blog.csdn.net/w7849516230,欢迎关注微信公众号“编程阳光”
“编程阳光”微信公众号

参考文章:
1.微信Android热补丁实践演进之路
2.深入探索android热修复技术原理
3.QFix探索之路—手Q热补丁轻量级方案
4.Android热更新方案Robust

猜你喜欢

转载自blog.csdn.net/w7849516230/article/details/77737374
今日推荐