zoukankan      html  css  js  c++  java
  • Android热更新技术——Tinker、nuwa、AndFix、Dexposed

    一、热修复技术作用

      线上app BUG紧急修复,不重新发版,不重新安装,在线远程修复问题

    二、局限性与适用场景

    • 补丁只能针对单一客户端版本,随着版本差异变大补丁体积也会增大;
    • 补丁不能支持所有的修改,例如AndroidManifest;
    • 补丁无论对代码还是资源的更新成功率都无法达到100%。

    既然补丁技术无法完全代替升级,那它适合使用在哪些场景呢?

    1.轻量而快速的升级

    2.远端调试

    3.数据统计

    4.其他(Instant Run)

    Android官方也使用热补丁技术实现Instant Run。它分为Hot Swap、Warm Swap与Cold Swap三种方式。

    三、热修复的原理

    1、通过更改dex加载顺序实现热修复(下载补丁后app需要重启,而后才会加载补丁生效)

    通过更改含有bug的dex文件的加载顺序;在dex的加载中,若已找到方法则不会继续查找,所以如果能让修复之后的方法在含有bug的方法之前加载就能达到修复bug的目的。把有问题的类修复后,放到一个单独的dex,通过反射插入到dexElements数组的最前面,让虚拟机优先加载打完补丁的class。

    实践中,会发现运行加载类的时候报preverified错误,原来在DexPrepare.cpp,将dex转化成odex的过程中,会在DexVerify.cpp进行校验,验证直接引用的类和clazz是否在同一个dex,如果是,则会打上CLASS_ISPREVERIFIED标志。通过在所有类(Application除外,当时还没加载自定义类的代码)的构造函数插入一个对在单独的dex的类的引用,就可以解决这个问题。空间使用了javaassist进行编译时字节码插入。

    隐患:虚拟机在安装期间为类打上CLASS_ISPREVERIFIED标志是为了提高性能的,我们强制防止类被打上标志多少会影响app的性能。但是在大项目中拆分dex的问题已经比较严重,很多类都没有被打上这个标志。

    开源实现有Nuwa, HotFix, DroidFix。实际应用案例:QQ空间

    2、通过Native替换方法指针的方式实现热修复(下载补丁后app不需要重启,即可加载补丁生效)

    主要是阿里开源的两个热修复框架:Dexpost AndFix。它们都是通过Native层使用指针替换的方法替换bug,达到修复bug的目的,具体可参考其github文章。

    (1)基于Xposed的AOP框架,方法级粒度,可以进行AOP编程、插桩、热补丁、SDK hook等功能。

    Xposed需要Root权限,是因为它要修改其他应用、系统的行为,而对单个应用来说,其实不需要root。 Xposed通过修改Android Dalvik运行时的Zygote进程,并使用Xposed Bridge来hook方法并注入自己的代码,实现非侵入式的runtime修改。

    我们知道,应用启动的时候,都会fork zygote进程,装载class和invoke各种初始化方法,Xposed就是在这个过程中,替换了app_process,hook了各种入口级方法(比如handleBindApplication、ServerThread、ActivityThread、ApplicationPackageManager的getResourcesForApplication等),加载XposedBridge.jar提供动态hook基础。

    方法级的替换是指,可以在方法前、方法后插入代码,或者直接替换方法。只能针对java方法做拦截,不支持C的方法。

    硬伤是不支持art,不支持art,不支持art。

    (2)AndFix同样是方法的hook,AndFix不像Dexposed从Method入手,而是以Field为切入点。dalvik和art都支持

    使用上,直接写一个新的类,会由补丁工具会生成注解,描述其与要打补丁的类和方法的对应关系。

    3、微信热补丁方案(下载补丁后app需要重启,而后才会加载补丁生效)

    思想是全量替换新的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。

    但是这套方案并非没有缺点,它带来的问题有两个:

    (1)占用Rom体积;这边大约是你修改Dex数量的1.5倍(dexopt与dex压缩成jar)的大小。
    (2)一个额外的合成过程;虽然我们单独放在一个进程上处理,但是合成时间的长短与内存消耗也会影响最终的成功率。

    微信的热补丁方案叫做Tinker,也算缅怀一下Dota中的地精修补匠,希望能做到无限刷新。

    若不care性能损耗与补丁包大小,QZone方案是最简单且成功率最高的方案(没有单独的合成过程)。相对Tinker来说,它的占用Rom体积也更小。另一方面,QZone与Tinker的成功率大约相差3%左右。

    事实上,一个完整的框架应该也是一个容易使用的框架。Tinker对补丁版本管理、进程管理、安全校验等都有着很好的支持。同时我们也支持gradle与命名行两种接入方式。希望在不久的将来,它可以很快的跟大家见面。

    https://www.cnblogs.com/aademeng/articles/6883861.html

    http://www.bbs0101.com/archives/1437.html(讲解和总结的很好,包含是否需要重启)

    https://www.jianshu.com/p/52cacc0f23fa

    https://www.cnblogs.com/fanfu1/p/5506149.html

  • 相关阅读:
    HDU 1058 Humble Numbers
    HDU 1160 FatMouse's Speed
    HDU 1087 Super Jumping! Jumping! Jumping!
    HDU 1003 Max Sum
    HDU 1297 Children’s Queue
    UVA1584环状序列 Circular Sequence
    UVA442 矩阵链乘 Matrix Chain Multiplication
    DjangoModels修改后出现You are trying to add a non-nullable field 'download' to book without a default; we can't do that (the database needs something to populate existing rows). Please select a fix:
    opencv做的简单播放器
    c++文件流输入输出
  • 原文地址:https://www.cnblogs.com/genggeng/p/9915293.html
Copyright © 2011-2022 走看看