设为首页 加入收藏

TOP

【腾讯Bugly干货分享】微信热补丁Tinker的实践演进之路(一)
2017-10-13 10:47:26 】 浏览:2154
Tags:腾讯 Bugly 干货 分享 补丁 Tinker 实践 演进

本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57ad7a70eaed47bb2699e68e

Dev Club 是一个交流移动开发技术,结交朋友,扩展人脉的社群,成员都是经过审核的移动开发工程师。每周都会举行嘉宾分享,话题讨论等活动。

本期,我们邀请了腾讯WXG Android开发工程师——张绍文,为大家分享《微信热补丁Tinker的实践演进之路》


分享内容简介:
Tinker 是微信官方的 Android 热补丁解决方案,它支持动态下发代码、So库以及资源,让应用能够在不需要重新安装的情况下实现更新。这里大致介绍 Tinker 的实现原理,当时遇到的各种坑以及对它各个方面性能的优化工作。

内容大体框架:

  1. 当前各种热补丁框架的比较以及 Tinker 的设计目标
  2. Tinker的实践演进
  3. Tinker在实现中遇到的困难

下面是本期分享内容整理


hello,大家好。我是张绍文,目前在微信主要负责 Android 的性能优化以及终端质量平台相关工作。

下面开始我们今天的分享。

1. 当前各种热补丁框架对比 & Tinker 的设计目标

热补丁技术是当前非常热门的 Android 开发技术,其中比较出名的方案有支付宝的 AndFix以及 QZone 的超级热补丁方案。

微信大约在2015年6月开始尝试应用,经过研究与尝试现有的各个方案,我们发现它们都有着自身的一些局限性。我们最终采用不同于它们的技术方案,自研微信热补丁开源框架 Tinker。

下面我们先来讲讲先有框架的一些局限性。

1.1 AndFix

Andfix 是阿里推出的开源框架,它在 github 的地址是:

https://github.com/alibaba/AndFix

它的技术原理如下图:它采用 native hook 的方式,这套方案直接使用 dalvik_replaceMethod 替换 class 中方法的实现。

它的缺点主要包括以下几个:

  1. 兼容性不佳;由于它采用 native 替换的方式,在 github Issue 中也有大量崩溃的反馈;

  2. 成功率不高;不支持修改 inline 方法,不支持修改方法参数超过8个或参数中带有 long, double 或者 float。跟一些使用 Andfix 的产品讨论过,它们的成功率不超过40%;

    原因:只替换了 DexCache 中的 ArtMethod 结构体,对于 Art 中一些 compiledCode 是直接通过 bx 过去

  3. 开发不透明;由于它还不支持增加 filed,我们需要为了补丁而补丁,无法采用这个技术发布需求。

    Andfix 的好处是可以立刻生效,但它可以支持的补丁场景非常有限,仅仅可以使用它来修复特定问题。

    所以我们不考虑采用这个方案。

    1.2 Qzone 超级补丁方案

    现在我们讲讲 Qzone 超级补丁方案,在腾讯内部已开源。

    这个方案使用 classloader 的方式,能实现更加友好的类替换。而且这与我们加载 Multidex 的做法相似,能基本保证稳定性与兼容性。

    它主要的面临问题有两个:

  4. 为了解决 unexpected DEX problem 异常,而采用插桩的方式给所有类插入不会真正运行的代码,防止类打上 preverify 标志。

    采用插桩导致所有类都非 preverify,导致上图中的 verify 与 optimize 操作会在加载类时触发。这会有一定的性能损耗,微信分别采用插桩与不插桩两种方式做过两种测试,一是连续加载700个50行左右的类,一是统计微信整个启动完成的耗时。

  5. 在 art 平台,若补丁中的类出现 Field、Method 或 Interface 变化,可能会导致出现内存地址错乱的问题。为了解决这个问题,我们最后补丁中的类要有以下规则:
    a. 修改跟新增的 class;
    b. 若 class 有 field,method 或 interface 数量变化,它们所有的子类;
    c. 若 class 有 field,method 或 interface 数量变化,它们以及它们所有子类的调用类。如果采用 ClassN 方式,即需要多个 dex 一起处理。

    Qzone 的方案最为简单,而且开发透明,补丁的成功率也是非常高的。

    但由于微信对于运行性能以及补丁大小都比较敏感,我们最终也没有采用这套方案。

    1.3 Tinker 的设计目标

    那么微信希望的是一套怎么样的热补丁框架呢,我们认为主要的目标有以下几个:

  6. 开发透明;开发者无需关心是否在补丁版本,他可以随意修改,不由框架限制;

  7. 性能无影响;补丁框架不能对应用带来性能损耗;
  8. 完整支持;支持代码,So 库以及资源的修复,可以发布功能。
  9. 补丁大小较小;补丁大小应该尽量的小,提高升级率。
  10. 稳定,兼容性好;保证微信的数亿用户的使用,尽量减少反射;

2. 3. Tinker 的实践演进

现在我们来讲讲微信热补丁框架 Tinker 的实现,目前在腾讯内部已开源。

它的名字来至 Dota 中的地精修补匠,我们希望发版本可以像它一样做到无限刷新。

Tinker 的方案来源 gradle 编译的 instant run 与 buck 编译的 exopackage。它们的思想都是全量替换新的 Dex。即我们完全使用了新的 Dex,那样既不出现 Art 地址错乱的问题,在 Dalvik 也无须插桩。

但是 instant run 针对的是编译期,它可以直接将最后生成的所有变化都直接拷到手机端。对于线上方案,这肯定是不可行的。所以当前核心问题是找到合适的,使补丁结果更小的差分算法。

微信首先 demo 中采用的是 bsdiff,它无关文件格式,但对于dex效果不是特别好,而且非常不稳定。当前微信对于 so,依然使用 bsdiff 算法。

然后我们想到 dexmerge 算法,把修改跟新增的类通过 dexmerge 方式与原来的 dex 合并,从而得到最终的完整 Dex。

经过实践,dexmerge 的核心问题有两个:

  1. 无法删除 class;导致在 Dalvik 平台会出现加载类重复的情况,这要求我们只能采用 miniloader 加载方案来避免;
  2. 合成时内存占用过大;dexmerge 库使用场景在 pc,它没有太多的考虑内存问题。它的峰值内存可以达到输入 dex 的大小的4倍-6倍。一个12M的 dex,峰值内存可能达到70多M。

    最后我们决定基于 dex 的格式,自研出一种 Dexdiff 算法,它需要达到以下目标;

  3. diff 结果小;

  4. 合成过程占用内存小;
  5. 支持删除、新增、修改 dex 中的 class。

    这里面主要的原理是深度利用原来 dex 中的信息,对于 dex 的每一个 section 做处理。这块在今天不再深入,感兴趣的同学可以交流。

    内存方面 dexdiff 峰值内存是 dex 的两倍左右,达到预期的结果。

    对于微信热补丁的更多信息,可以阅读我之前发的一篇文章。

    微信Android热补丁实践演进之路

然后我们来看看 Tinker 的框架设计,它主要包括以下几部分:

  1. 补丁合成;这些都在单独的 patch 进程工作,这里包括 dex,so 还有资源,主要完成补丁包的合成以及升级;
  2. 补丁的加载;如果通过反射系统加载我们合成好的 dex,so 与资源;
  3. 监控回调;在合成与加载过程中,出现问题及时回调;
  4. 版本管理; Tinker 支持补丁升级,甚至是多个补丁不停的切换。这里我们需要保证所有进程版本的一致性;
  5. 安全校验;无论在补丁合成还是加载,我们都需要有必要的安全校验。

    在微信中,我们为 Ti
    编程开发网

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇结合Retrofit,RxJava,Okhttp,Fast.. 下一篇Android与单片机通信常用数据转换..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

array(4) { ["type"]=> int(8) ["message"]=> string(24) "Undefined variable: jobs" ["file"]=> string(32) "/mnt/wp/cppentry/do/bencandy.php" ["line"]=> int(214) }