热修复技术学习总结

注明:

本文章是对阿里开放出的《深入探索Android热修复技术原理7.3Q.pdf》进行阅读后的总结性文章,只包含个人认为有用的内容,目的是方便以后回忆或者分析问题,想深入学习可自行研究。附上原书http://pan.baidu.com/s/1dE7i8NJ

三大修复原理简要

1.代码修复

1.1 即时生效:底层替代类中的老代码,并且无视底层的具体结构。
1.2 重启生效:基于类加载机制,重新编排了包中dex的顺序。

2.资源修复

2.1 传统的资源修复是基于InstantRun的原理,就是构造一个新的AssetManager,将新的资源进行addAssetPath,然后通过反射替换掉系统中的原理的AssetManager的引用。
2.2 阿里采用的是直接将一个比系统资源包的packageId 0x7F小的packageId为0x66的资源addAssetPath到原来的AssetManager对象上即可,这个补丁资源包只包含新添加,和已修改的。

3.so修复

本质是对native方法的修复和替换,阿里采用的是类似类修复反射注入的方式,把补丁so路径插入到nativeLibrary数组的最前面。

代码热修复

  1. 底层热替换原理

1.1 Andfix 原理:通过jni的replaceMethod(Method src ,Method des )->通过 env的FromReflectMethod得到ArtMethod地址,转为ArtMethod指针->挨个替换ArtMethod的中字段.

1.2 虚拟机调用方法的原理 : 最终ArtMethod中的字段(例如entry_point_from_interpreter)找到最终要执行的方法的入口地址,art可以采用解释模式或者AOT机器码模式执行。

1.3 Andfix原理兼容性的根源 : ArtMethod的结构厂商可以自己改变,就会导致替换字段信息不是代码中指定的信息,导致替换错乱

1.4 突破底层ArtMethod结构的差异 : 将ArtMethod整体替换,阿里的核心方法是memcry(smeth,dmeth,sizeOf(ArtMethod))。这里面的关键是sizeOf(ArtMethod)的实现,其原理是ArtMethod的存储接口是线性的,通过两个ArtMethod的地址差就可以。这种方式的适配不受系统的影响,稳定且兼容。

1.5 访问权限的问题 :
* 方法时访问权限 : 机器码中不存在检查权限的相关代码
* 同包名下访问权限的问题 : 由于补丁包的ClassLoader与原来的ClassLoader不一致,导致虚拟机代码的Class::IsInSamePackage校验失败。解决方案就是通过反射让补丁包的ClassLoader为系统原来的ClassLoader即可。
* 被反射调用的方法问题 : 由于ArtMethod中的declaring_class_被替换成了新的类,而反射得到的还是原来的老类,这会导致invoke时VerifyObjectClass()方法失败,而直接报错。所以这种热修复方案不能修复这种方法。

1.6 即时生效的限制:
引起类中发生结构变化的修改 : 因为一旦引起修改ArtMethod的位置将发生变化,就找不到地址了。
修复了的非静态方法被反射调用。

2 java中的秘密

2.1 内部编译类
* 内部类在编译器会被编译为跟外部类一样的类
* 静态内部类与非静态内部类,在smali中非静态内部类会自动合成this$0 域标示的是外部类的引用。
* 外部类为了访问内部类(或内部类访问外部类)的私有域,编译期间会自动为内部类(或外部类)生成access&XXX方法。
* 热修复替换时,要避免生成access&XXX方法,就要求内/外部类不能存在private的method/field。

2.2 匿名内部类
* 匿名内部类的名称格式一般为外部类&number,number根据匿名内部类出现的顺序累加记名。
* 如果在之前增加一个匿名内部类 则会导致原来的匿名内部类名称不对应。也就无法使用热修复。
* 应当极力避免插入新匿名内部类,特别是向前插。

2.3 域编译
* 热替换不支持 clint方法
* 静态域和静态代码块在clint方法中
* 非静态在init方法中
* 静态域和静态代码块不支持热替换

2.4 final static 域
* final static 原始类型和字符串在initSField而不是在clint中
* final static 引用类型在 clint方法中初始化
* 优化时final static 对于原始类型和字符串有用,引用类型其实没有用。

2.5 方法编译
* 混淆可能导致方法的内联和裁剪
* 被内联:方法没被用过,方法只有一行代码,方法只被一个地方引用过。
* 被裁剪:方法中有参数没被使用。
* 热替换解决方法:在混淆是加上配置 -dontoptimize

2.6 switch case 语句编译
* 连续几个相近的值会被编译为packed-switch指令,中间差值用pswitch-0补齐。
* 不连续边被编译为sparse-switch指令
* 热替换方案:资源id为const final static 会被编译为packed-switch指令,会存在资源id替换不完全的问题,解决方案就是修改smali反编译流程,碰到packed-switch指令强替换为sparse-switch指令,:pswitch-N标签强改为sswitch-N标签,然后做资源id的强替换,在回编译smali为dex。

2.7 泛型编译
* 泛型在编译器中实现,虚拟机无感知
* 泛型类型擦除:编译器在编译期间将泛型转为目标类型的字节码,对于虚拟机来说得到的是目标类型的字节码文件,无感知泛型。
* 泛型与多态冲突的原理及方案:

*类型擦除后 原来的set(T t)的字节码会是set(Object t) 而其子类为set(Number t),从重写的定义上来看这不是重写而是重载。这也就导致泛型和多态有冲突了
*而实际是可以重写的,其本质原因是JVM采用了bridge方法。子类真正重写父类方法是bridge方法,而在bridge方法中调用了子类的方法而已。@override只是个假象。

*泛型不需要强制类型转换的原因是:编译器如果返现有一个变量申明加上了泛型的话,编译器会自动加上chceck-cast类型转换。

2.8 Lambda 表达
* Lambda 会被;;其内部this指的是外部类对象,这点区别于内部类的this。
* 函数式接口 : 只有一个方法的接口
* 函数式接口调用时,最终会增加一个辅助方法。不能走热替换
* 修改函数式接口内部逻辑可以走热替换

2.9 访问权限检查对热替换的影响
*补丁类如果引用了非public类,最终会抛dvmThrowException

2.10 Clint方法
* 不支持clint方法的热替换

3 冷启动方案

3.1 传统实现方式的利弊
* QQ控件的插庄方案:

原理:单独放一个类在dex中,让其它类调用,防止打上CLASS_ISPREVERIFIED标志,再加载补丁dex得到dexFile对象作为参数构建一个Element对象插入到dex-Elements数组的前面。
缺点: Dalvik下影响类加载性能,Art下类地址写死,导致必须包含父类或引用,最后导致补丁包很大

*Tinker方案:

原理:提供dex差量包,整体替换dex的方案。差量的方式给出patch.dexm,然后将patch.dex和应用的classes.dex合并成一个完整的dex,完整的dex加载得到的dexFile对象作为参数构建一个Elements对象然后整体替换掉旧的dex-Elements数组。
缺点: dex合并内存消耗在Vm heap上,容易OOM,最后导致dex合并失败

3.2 插桩实现的前因后果
默认一个dex时所有类会打上CLASS_ISPREVERIFIED标志,新的补丁类不在原dex中时,被调用会报dvmThrowllegalAccessError。一个单独的辅助类放到一个单独的dex中,原dex的所有类的构造函数都引用这个类,dexopt时原Dex所有类不会被打上CLASS_ISPREVERIFIED这个标志。

3.3 插桩导致类加载性能影响
采用插桩,导致所有类都是非preverify,这就使得dexopt和load class时频繁的verify和optimize。当类很多时这个操作会相当耗时,导致启动时长时间白屏。

3.4 避免插桩的QFix方案
在dexopt后进行检查绕过,会存在潜在的Bug

3.5 Art下冷启动实现
将补丁直接命名为classes.dex 将原来的一次命名为classes1.dex …classes2.dex…等。然后一起打包为一个apk。然后DexFile.loadDex得到DexFile对象,最后把该DexFile对象整体替换旧的dexElements数组

未完待续

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
----《深入探索Android修复技术原理》高清完整版PDF---- 2017年6月,阿里巴巴手淘技术团队推出了史上首个非侵入式移动更新解决方案——Sophix。在Android修复的三大领域:代码修复资源修复、SO修复方面,以及方案的安全性和易用性方面,Sophix都做到了业界领先。 《深入探索Android修复技术原理》从阿里Sophix方案开发过程入手权威解读,分享了阿里巴巴手淘技术团队对系统底层的原创性发现,是业界首部全方位完整介绍修复原理的书籍。 阿里技术大牛联袂推荐 自 2014 年至今,手淘定义和引领了业界 Android 组件化和修复技术风潮,至于后来者 Instant App 或多或少也受了国内技术风气影响。今天看到团队同学将这块技术认真系统化整理成书,非常欣喜。在这本书里,既能看到对修复技术风潮的发展历史系统深入总结,看到国内程序员在Android系统级技术持续突破上的不懈努力,更看到国内程序员坚持打造世界级优秀专业移动技术产品的雄心壮志! 手机淘宝基础平台部负责人,阿里巴巴资深技术专家 吴天华(天施) 业内少有的讲解 Android 修复的深度书籍,对于原理、代码讲解得非常的清晰和深入,值得 Android 工程师研读。 手机淘资深专家,倪生华(玄黎) 应用修复是一项略带神秘而又颇具争议的技术,但是它的确赋予应用开发者“驾着飞机修引擎”的能力。本书从 Android 应用修复技术的原理及代码实现、多种方案进行比较的角度,系统化地阐述了 Android 平台上的应用修复技术。对 Android 应用修复有好奇心的技术人员,这本专题书不容错过。 计算机技术领域著名作家,阿里巴巴飞猪事业部首席架构师 潘爱民

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值