2019独角兽企业重金招聘Python工程师标准>>>

微信 Tinker 负责人张绍文关于 Android 热修复直播分享记录

来源:微信技术团队的公众号WeMobileDev

热补丁技术是当前非常热门的Android开发技术,其中比较出名的方案有支付宝的AndFix以及QZone的超级热补丁方案。微信大约在2015年6月开始尝试应用,经过研究与尝试现有的各个方案,我们发现它们都有着自身的一些局限性。我们最终采用不同于它们的技术方案,也就是微信热补丁开源框架Tinker。

我们先来讲讲现有框架的一些局限性:

Andfix是阿里推出的开源框架,它在github的地址是:https://github.com/alibaba/AndFix

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

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

  1. 兼容性不佳;由于它采用native替换的方式,在github Issue中也有大量崩溃的反馈;
  2. 成功率不高;不支持修改inline方法,不支持修改参数超过8个或带有long,double或者float的方法。跟一些使用Andfix的产品讨论过,它们的成功率不超过40%;
  3. 开发不透明;由于它还不支持增加filed,我们需要为了补丁而补丁,无法采用这个技术发布需求。 Andfix的好处是可以立刻生效,但它可以支持的补丁场景非常有限,仅仅可以使用它来修复特定问题。所以我们不考虑采用这个方案。

现在我们讲讲Qzone超级补丁方案

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

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

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

2、在art平台,若补丁中的类出现Field、Method或Interface变化,可能会导致出现内存地址错乱的问题。为了解决这个问题,我们最后补丁中的类要有以下规则:

a. 修改跟新增的class;
b. 若class有field,method或interface数量变化,它们所有的子类;
c. 若class有field,method或interface数量变化,它们以及它们所有子类的调用类。如果采用ClassN方式,即需要多个dex一起处理。

Qzone的方案最为简单,而且开发透明,补丁的成功率也是非常高的。但由于微信对于运行性能以及补丁大小都比较敏感,我们最终也没有采用这套方案。

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

  1. 开发透明;开发者无需关心是否在补丁版本,他可以随意修改,不由框架限制;
  2. 性能无影响;补丁框架不能对应用带来性能损耗;
  3. 完整支持;支持代码,So库以及资源的修复,可以做到发布功能;
  4. 补丁大小较小;补丁大小应该尽量的小,提高升级率。
  5. 稳定,兼容性好;保证微信的数亿用户的使用,尽量减少反射;

现在我们来讲讲微信热补丁框架Tinker的实现

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

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

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

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

然后我们想到dexmerge算法,把修改跟新增的类通过dexmerge方式与原来的dex合并,从而得到最终的完整Dex。经过实践,dexmerge的核心问题有两个:

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

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

  1. diff结果小;
  2. 合成过程占用内存小;
  3. 支持删除、新增、修改dex中的class。

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

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

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

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

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

在微信中,我们为Tinker框架加入了100多个实时上报,监控着在每个过程可能出现的问题:

接着我们来看看在开发Tinker过程中,遇到的一些问题:

1、厂商OTA;对于Art平台,dex2oat时间较长。特别是厂商OTA之后,所有动态加载的代码都需要重新执行dex2oat。这是因为boot image已经改变,但是系统在升级时只会给ClassN.dex重新oat。

对于补丁dex会出现主进程同步执行dex2oat,这个时间非常久,很有可能会出现ANR,对于小米等一些产品的开发版更是如此。

这也是我们现在努力在实现分平台合成的原因,即在Art平台,只合成规则下需要的class。只要不是全量替换,重新dex2oat的时间是可以接受的。

2、Android N混合编译导致补丁机制失效;这块花了一定的时间重新梳理了Android N art的代码,详细的分析可以查看之前我发的一篇文章。Android N混合编译与对热补丁影响解析

3、Dex反射成功但是不生效;开始的时候,我们加载补丁dex采用的是makedexElement的方式。但是发现大约有几十万台机器,补丁加载成功了,但是使用的还是旧版本的代码。某些机器类似三星s6 502系统,尽管反射pathList成功,查找顺序依然以base.apk优先。

这里采取的解决方法是类似instant run,采用反射parent classloader的方式。这里不得不提,instant run的increaseClassLoader实现非常精妙。

4、Xposed等微信插件; 市面上有各种各样的微信插件,它们在微信启动前会提前加载微信中的类,这会导致两个问题:

a. 在Dalvik平台,直接出现'Class ref in pre-verified class resolved to unexpected implementation'的crash;
b. 在Art平台,由于出现部分类使用了旧的代码,这可能导致补丁无效,或者地址错乱的问题。

它们根本的原因都是Xposed反射调用,提前导入了我们的某些类。

事实上,由于可能存在补丁使用不当或者其他问题,我们的确需要有一个安全模式。即在应用启动不起来或多次crash时,进入补丁清理或者升级的流程。

也许有人觉得Tinker过于臃肿,过于复杂。这是因为热补丁并不是仅仅加载一个dex或者so文件,事实上它要关心的细节有很多。进程的一致性,控制可修改类的范围, 版本的管理,扩展性等等。

Tinker的未来规划是真正的开源出去,大约下周会提交分平台合成以及资源相关的所有代码。然后等公司的开源审计结束后将在github开源
对于So,资源的合成方式,dexdiff的技术细节,若大家感兴趣可以'read the ** source code'或者与我们交流。

由于时间有限,今天的分享就到这里,由于准备仓促,再次给大家致歉。

Q0:大神请教下patch进程和主进程是怎么通信的?
Q0:是通过intent service通信的,主进程一个接受补丁结果的intent service,patch进程是一个接受不请求的intent service
Q1:分平台合成 没听太明白,能再仔细说下么。
Q1:分平台合成就是在Dalvik平台,我们合成全量的dex,这可以避免我们插桩的要求。在Art平台,我们只合成上述三个条件下的类。这里的难点是同一份diff代码,可以做到不同的合成方式。

Q2:对于内部空间不足引起的patch失败现在有什么好的解决办法?
Q2: 对于我们的方案,空间占用的确比较大。我们解决的方法有两个,1. 在patch之前提前检查用户的剩余空间,如果用户剩余空间过少,即不尝试。 2. 若本次失败,我们会有回调,然后我们会定期重试三次。你也可以采用提示用户的方式
B0: 代码完全开源吗?
B0:对的,所有代码都会开源,从编译到各个模块。

B1: 微信安卓版现在有几个activity? 是一个activity 加 多个fragment吗?
B1:非常抱歉,这个问题跟本次分享无关。事实上,我更建议你反编译微信的代码来研究。

b2:xposed框架的那些插件,是通过反射调用替换值?那一般有啥方式保证安全性?保证app数据的安全性
B2: 它们只要是反射调用微信的某些类,达到某些功能的篡改。事实上,如果在root下,单纯的保护是比较难的。

B3:为什么要在补丁成功的时候加结果回调是为了启动程序么,但是和您刚才说的为了实时上报
B3:回调结果是为了给使用者一个回调,在这个回调里面它可以做各种各样的工作。例如我弹出升级完成的dialog。我设置锁屏或者程序进入后台后自杀,这可以加快补丁的应用

B4:既然能加载so和资源,Tinker能用于插件化吗?
B4:Tinker当前没有做四大组件代码,但是Tinker未来绝对是具备这个能力的

B7:这套框架目前是多少个人在维护呢
B7: Tinker当前有3个人在开发维护

b8:请问资源是编译到arsc中还是反射加载二进制流?
B8: 你的问题我不太明白,资源我们采用的是全量替换,即完全使用新的资源包

Q6:patchCoreSDK怎么绕过 换classloader后跨 dex加载类 accesserror的问题?有对patchcoreSDK做强制访问隔离吗?
Q6: 是的,Tinker框架分为两部分,核心加载代码,成为loader类,这里大概有十几个类,他们是不允许修改的。其他大部分Tinker的类也是可以通过补丁修改的,这里Tinker框架已经做了处理,即在新合成的Dex,我们已经删除了loader相关的类,从而彻底避免了这个问题

Q7:patch成功后怎么及时重启其他进程?
Q7: 为了保证各个进程的唯一性,我们有一个版本管理文件用于记录当前补丁的版本。它分为old与new两个字段。同时做了约定,只有patch进程可以修改new字段,只有主进程可以修改old字段,其他所有进程启动时都只会加载old字段的补丁版本。然后主要主进程可以发起版本升级,即把new字段赋值给old字段,这个时候主进程要杀掉其他所有的进程,以保证统一性

转载于:https://my.oschina.net/dolphinboy/blog/743015

微信 Tinker 负责人张绍文关于 Android 热修复直播分享记录相关推荐

  1. Android 热修复方案Tinker(五) SO补丁加载

    基于Tinker V1.7.5 Android 热修复方案Tinker(一) Application改造 Android 热修复方案Tinker(二) 补丁加载流程 Android 热修复方案Tink ...

  2. android revre view,Android热修复之微信Tinker使用初探

    前几天,万众期待的微信团队的Android热修复框架tinker终于在GitHub上开源了.java 今天拿下来集成使用了一下,发现md上对集成使用的过程介绍的比较精简(后来发现wiki上面却是很详细 ...

  3. Android 热修复Tinker接入实战

    1 热修复原理 热修复的原理一句话总结就是:就是dex的动态替换. 首先,我们知道PC上的JVM是直接解析class字节码的,而android上的JVM是解析dex文件的,因此Android程序要运行 ...

  4. Android 热修复 Tinker Gradle Plugin解析

    本文已在我的公众号hongyangAndroid原创首发. 转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/72667669 本文 ...

  5. 深入解析阿里Android热修复技术原理

    前言:本文框架 什么是热修复? 热修复框架分类 技术原理及特点 Tinker框架解析 各框架对比图 总结 通过阅读本文,你会对热修复技术有更深的认知,本文会列出各类框架的优缺点以及技术原理,文章末尾简 ...

  6. Android热修复技术原理详解(最新最全版本)

    本文框架 什么是热修复? 热修复框架分类 技术原理及特点 Tinker框架解析 各框架对比图 总结   通过阅读本文,你会对热修复技术有更深的认知,本文会列出各类框架的优缺点以及技术原理,文章末尾简单 ...

  7. [读书笔记] 深入探索Android热修复技术原理 (手淘技术团队)

    热修复技术介绍 探索之路 最开始,手淘是基于Xposed进行了改进,产生了针对Android Dalvik虚拟机运行时的Java Method Hook技术--Dexposed. 但该方案对于底层Da ...

  8. android热补丁作用,Android热修复之 - 阿里开源的热补丁

    这里就有一个概念那就AndFix.apatch补丁用来修复方法,接下来我们看看到底是怎么实现的. 1.2 生成apatch包 假如我们收到了用户上传的崩溃信息,我们改完需要修复的Bug,这个时候就会有 ...

  9. 动态化部署:Android热修复之代码修复(一)

    前记 传统发版要经过应用市场审核这一过程,但面对需要紧急修复的bug时无疑会增加时间成本,并且为了应对现在日渐强烈的运营需求,动态化部署应运而生,包括插件化和热修复,当然插件化和热修复充满了黑科技,包 ...

最新文章

  1. 6.:first-child子元素过滤选择器
  2. MySQL 表中添加 时间戳 字段
  3. 【例题收藏】◇例题·6◇ 电压机制(voltage)
  4. Windows下命令行连接mysql及导入sql文件
  5. angular 指令渲染_Angularjs渲染的 using 指令的星级评分系统示例
  6. 每天学习一点,坚持学习!!
  7. Android APK反编译详解(附图)(转)
  8. Windows优化大师的一点研究
  9. kettle根据参数动态派生列
  10. 机器学习降维算法一:PCA(主成分分析算法)
  11. 会议交流 | “数据智能与知识服务”研讨会的专家报告题目已更新!
  12. 什么是Servlet类
  13. lora网关软件设计_Semtech发布用于LoRa网关的开源软件 实现安全通信管理
  14. 带有H5标签的字符串
  15. mysql轮播图表设计_制作一个简单的轮播图
  16. mysql001课程成绩002,6、MySQL测试题
  17. Genlovy_Hoo大神的杰作
  18. Unity基本认识——走进Unity
  19. USA gov data from Bitly
  20. NodeMCU文档中文翻译 5 上传代码

热门文章

  1. 【AR】开始使用Vuforia开发iOS(2)
  2. 阿里云CentOS7安装Oracle11GR2
  3. Exchange-OWA与域控集成-实现单点登录
  4. 初学git:用git bash往github push代码
  5. 2009年依然兑现不了的10大IT安全预期
  6. AWS — 重塑混合云
  7. stm32 TIM2 重映射
  8. 程序员大牛必备的装逼神器
  9. 迪拜测试世界上首款自动驾驶出租车,距离2030年的自动驾驶目标又进一步
  10. 什么是事务(transaction)?它有什么好处