本文来自于腾讯bugly开发者社区,非经做者赞成,请勿转载,原文地址:http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=1264&extra=page%3D1php
继插件化后,热补丁技术在2015年开始爆发,目前已是很是热门的Android开发技术。其中比较著名的有淘宝的Dexposed、支付宝的AndFix以及QZone的超级热补丁方案。微信对热补丁技术的研究并不算早,大约开始于2015年6月。通过研究与尝试现有的各个方案,咱们发现它们都有着自身的一些局限性。微信最终采用不一样于它们的技术方案,走出了本身的实践演进之路。html
另一方面,技术应当只是热补丁方案中的一环。随着对热补丁的屡次尝试与应用,微信创建起自身的流程规范,同时也不断的尝试拓展它的应用场景。经过本文,我但愿你们不只可以全面的了解各项热补丁技术的优缺点,同时也能对它的应用场景有着更加全面的认识。在此基础上,你们或许能更容易的决定是否在本身的项目中使用热补丁技术,以及应当如何使用它。git
热补丁:让应用可以在无需从新安装的状况实现更新,帮助应用快速创建动态修复能力。github
从上面的定义来看,热补丁节省Android大量应用市场发布的时间。同时用户也无需从新安装,只要上线就能无感知的更新。看起来很美好,这是否能够意味咱们能够尽可能使用补丁来代替发布呢?事实上,热补丁技术当前依然存在它的局限性,主要表如今如下几点:算法
既然补丁技术没法彻底代替升级,那它适合使用在哪些场景呢?安全
###一. 轻量而快速的升级 ###微信
热补丁技术也能够理解为一个动态修改代码与资源的通道,它适合于修改量较少的状况。以微信的屡次发布为例,补丁大小均在300K之内,它相对于传统的发布有着很大的优点。网络
以Android用户的升级习惯,即便是相对活跃的微信也须要10天以上的时间去覆盖50%的用户。使用补丁技术,咱们能作到1天覆盖70%以上。这也是基于补丁体积较小,能够直接使用移动网络下载更新。框架
正因如此,补丁技术很是适合使用在灰度阶段。在过去,咱们须要在正式发布前保证全部严重的问题都已经获得修复,这一般须要咱们通过三次以上的灰度过程,并且没法快速的验证这些问题在同一批用户的修复效果。利用热补丁技术,咱们能够快速对同一批用户验证修复效果,这大大缩短了咱们的发布流程。ide
若发布版本出现问题或紧急漏洞,传统方式须要单独灰度验证修改,而后从新发布新的版本。利用补丁技术,咱们只须要先上线小部分用户验证修改的效果,最后再全量上线便可。可是此种发布对线上用户影响较大, 咱们须要谨慎而为。本着对用户负责的态度,发布补丁等同于发布版本,它也应该严格执行完整的测试与上线流程。
总的来讲,补丁技术能够下降开发成本,缩短开发周期,实现轻量而快速的升级。
###二. 远端调试###
一入Android深似海,Android开发的另一个痛是机型的碎片化。咱们也许都会遇到"本地不复现","日志查不出","联系用户不鸟你"的烦恼。因此补丁机制很是适合使用在远端调试上。即咱们须要具有只特定用户发送补丁的能力,这对咱们查找问题很是有帮助。
利用补丁技术,咱们避免了骚扰用户而默默的为用户解决问题。固然这也须要很是严格的权限管理,以防恶意或随意使用。
###三. 数据统计###
数据统计在微信中也占据着很是重要的位置,咱们也很是但愿将热补丁与数据统计结合的更好。事实上,热补丁不管在普通的数据统计仍是ABTest都有着很是大的优点。例如若我想对同一批用户作两种test, 传统方式没法让这批用户去安装两个版本。使用补丁技术,咱们能够方便的对同一批用户不停的更换补丁。
在数据统计之路,如何与补丁技术结合的更好,更加精准的控制样本人数与比例,这也是微信当前努力发展的一个方向。
###四. 其余### 事实上,Android官方也使用热补丁技术实现Instant Run。它分为Hot Swap、Warm Swap与Cold Swap三种方式,你们能够参考英文介绍,也能够看参考文章中的翻译稿。最新的Instant App应该也是采用相似的原理,可是Google Play是不容许下发代码的,这个海外App须要注意一下。
在了解补丁技术能够与适合作什么以后,咱们回到技术自己。因为Dexposed没法支持全平台,并不适合应用到商业产品中。因此这里咱们只简单介绍Andfix、QZone、微信几套方案的实现,以及它们方案面临着的问题,你们也能够参考资料中的各大热补丁方案分析和比较一文。
###一. AndFix### AndFix采用native hook的方式,这套方案直接使用dalvik_replaceMethod
替换class中方法的实现。因为它并无总体替换class, 而field在class中的相对地址在class加载时已肯定,因此AndFix没法支持新增或者删除filed的状况(经过替换init
与clinit
只能够修改field的数值)。
也正因如此,Andfix能够支持的补丁场景相对有限,仅仅可使用它来修复特定问题。结合以前的发布流程,咱们更但愿补丁对开发者是不感知的,即他不须要清楚这个修改是对补丁版本仍是正式发布版本(事实上咱们也是使用git分支管理+cherry-pick方式)。另外一方面,使用native替换将会面临比较复杂的兼容性问题。
相比其余方案,AndFix的最大优势在于当即生效。事实上,AndFix的实现与Instant Run的热插拔有点相似,可是因为使用场景的限制,微信在最初期已排除使用这一方案。
###二. QZone### QZone方案并无开源,但在github上的Nuwa采用了相同的方式。这个方案使用classloader的方式,能实现更加友好的类替换。并且这与咱们加载Multidex的作法类似,能基本保证稳定性与兼容性。具体原理在这里再也不细说,你们能够参考这篇文章。
本方案为了解决unexpected DEX problem
异常而采用插桩的方式,从而规避问题的出现。事实上,Android系统的这些检查规则是很是有意义的,这会致使QZone方案在Dalvik与Art都会产生一些问题。
若采用插桩致使全部类都非preverify,这致使verify与optimize操做会在加载类时触发。这会有必定的性能损耗,微信分别采用插桩与不插桩两种方式作过两种测试,一是连续加载700个50行左右的类,一是统计微信整个启动完成的耗时。
平均每一个类verify+optimize(跟类的大小有关系)的耗时并不长,并且这个耗时每一个类只有一次。但因为启动时会加载大量的类,在这个状况影响仍是比较大的。
这里是由于在dex2oat时fast*
已经将类能肯定的各个地址写死。若是运行时补丁包的地址出现改变,原始类去调用时就会出现地址错乱。这里说的可能不够详细,事实上微信当时为了查清这两个问题,也花费了必定的时间将Dalvik跟Art的流程基本搞透。若你们对这里感兴趣,后续在单独的文章详细论述。
总的来讲,Qzone方案好处在于开发透明,简单,这一套方案目前的应用成功率也是最高的,但在补丁包大小与性能损耗上有必定的局限性。特别是不管咱们是否真正应用补丁,都会由于插桩致使对程序运行时的性能产生影响。微信对于性能要求较高,因此咱们也没有采用这套方案。
###三. 微信热补丁方案###
有没有那么一种方案,能作到开发透明,可是却没有QZone方案的缺陷呢?Instant Run的冷插拔与buck的exopackage或许能给咱们灵感,它们的思想都是全量替换新的Dex。即咱们彻底使用了新的Dex,那样既不出现Art地址错乱的问题,在Dalvik也无须插桩。固然考虑到补丁包的体积,咱们不能直接将新的Dex放在里面。但咱们能够将新旧两个Dex的差别放到补丁包中,最简单咱们能够采用BsDiff算法。
简单来讲,在编译时经过新旧两个Dex生成差别path.dex。在运行时,将差别patch.dex从新跟原始安装包的旧Dex还原为新的Dex。这个过程可能比较耗费时间与内存,因此咱们是单独放在一个后台进程:patch中。为了补丁包尽可能的小,微信自研了DexDiff算法,它深度利用Dex的格式来减小差别的大小。它的粒度是Dex格式的每一项,能够充分利用本来Dex的信息,而BsDiff的粒度是文件,AndFix/QZone的粒度为class。
这块后面我但愿后面用单独的文章来说述,这里先作一个铺垫,大体的效果以下图。在最极端的状况,因为利用了本来dex的信息彻底替换一个13M的Dex,咱们的补丁大小也仅仅只有6.6M。
可是这套方案并不是没有缺点,它带来的问题有两个:
微信的热补丁方案叫作Tinker,也算缅怀一下Dota中的地精修补匠,但愿能作到无限刷新。
限于篇幅,这里对Dex、library以及资源的更多技术细节并无详细的论述,这里但愿放在后面的单独文章中。咱们最后从总体比较一下这几种方案:
若不care性能损耗与补丁包大小,QZone方案是最简单且成功率最高的方案(没有单独的合成过程)。相对Tinker来讲,它的占用Rom体积也更小。另外一方面,QZone与Tinker的成功率大约相差3%左右。
事实上,一个完整的框架应该也是一个容易使用的框架。Tinker对补丁版本管理、进程管理、安全校验等都有着很好的支持。同时咱们也支持gradle与命名行两种接入方式。但愿在不久的未来,它能够很快的跟你们见面。
上一章节咱们简单比较了各个热补丁的技术方案,它们解决了如何生成与加载补丁包的问题。但一个完善的热补丁系统不该该仅限于此,它还须要包括如下几个方面:
###一. 网络通道现状###
网络通道负责的将补丁包交付给用户,这个包括特定用户与全量用户两种状况。事实上,微信当前针对热补丁有如下三种通道更新:
事实上,对于大部分的应用来讲,假设不实现push通道,CDN+pull通道实现起来仍是较为容易。
###二. 上线与管理平台现状###
上线与管理平台主要为了快速上线,管理历史记录,以及监控补丁的运行状况等。
事实上,微信发布热补丁是很是慎重的。它整个发布流程与升级版本是保持一致的,也必须修改版本号、通过严格的完整测试流程等。咱们也会经过灰度的方式上线,同时监控补丁版本的各个指标。这里的为了完整的监控补丁的状况,咱们作的工做有:
###三. 补丁成功率现状###
应用成功率= 补丁版本人数/补丁发布前该版本人数 因为可能存在基准或补丁版本用户安装了其余版本,因此本统计结果应略为偏低,但它能现实的反应补丁的线上覆盖状况。
使用Qzone方案,微信补丁在10天后的应用成功率大约在98.5%左右。使用Tinker大约只有95.5%左右,主要缘由在于空间不足以及后台进程被杀。在这里咱们也在尝试使用重试的方式以及下降合成的耗时与内存,从而提高成功率。
热补丁技术发展的很快,Android推出的Instant App也使人期待。可是在国内,彷佛咱们仍是期望本身更靠谱一点。每个的应用的需求都不太一致,这里大体讲了一些微信的实践经验,但愿对你们有帮助。
随着微信部门内从“单APP”向“多APP”演进,微信也正在迈入开源化的开发实践。咱们但愿将各个功能组件化,从而作能够到快速复制与应用。微信的热补丁框架“Tinker”当前也在经历从微信分离,又合入到微信的过程。但愿在不久的未来,咱们也能够将“Tinker”以及微信中一些其余的组件开源出去。
咱们也但愿能够找一个App做为内测,给咱们提供宝贵的意见。若对微信的Tinker方案感兴趣的用户,能够单独发消息或在文章末留言。注明姓名、所在公司以及负责的App,咱们但愿挑选部分产品做为内测。
更多精彩内容欢迎关注bugly的微信公众帐号:
腾讯 Bugly是一款专为移动开发者打造的质量监控工具,帮助开发者快速,便捷的定位线上应用崩溃的状况以及解决方案。智能合并功能帮助开发同窗把天天上报的数千条 Crash 根据根因合并分类,每日日报会列出影响用户数最多的崩溃,精准定位功能帮助开发同窗定位到出问题的代码行,实时上报能够在发布后快速的了解应用的质量状况,适配最新的 iOS, Android 官方操做系统,鹅厂的工程师都在使用,快来加入咱们吧!