浅探热修复技术

热修复是一个为了即时解决紧急bug的技术。
从传统的开发流程看 修复一个bug 的流程:
重新发布版本 ——> 用户下载安装 —–> bug 修复
此流程 存在 bug修复的不及时、且用户下载安装成本较高 等缺陷。

热更新修复一个bug 的流程:
检测服务端是否存在 patch —存在—>下载 patch 到本地
|
|
|
加载本地patch
|
|
修复完成
由此可以看出 热修复 去修复一个bug 较为灵活,具有:无需重新发版,用户无感知修复,实时高效热修复 等优势,(热修复 更新的内容绕过了 应用市场的检测,具有一定的风险)
目前市面可供选择的热修复方案较多:HotFix、AndFix、sopHix,还有微信与美团推出的各自的热修复方案, 网上也有较多文章介绍各个热修复方案的优缺点, 在此是将网上的方案进行总结一下,做个备份。
市面上热修复方案虽然较多,但其内部实现依赖的是这两种技术:

1、art_method 替换技术
2、class 类加载技术

采用 art_method 替换技术的方案,具有以下优点:

1、可以即时修复 bug方法,无需冷启动应用
2、因为patch是以 method 为单位 生成的,所以补丁包较小
3、对应用无侵入,几乎无性能损耗

但其缺点也较为显著:

1、不支持新增字段,以及修改<init>方法,也不支持对资源的替换。
2、如果厂商修改了art,有可能导致 修复失效。

市面上使用art_method 替换技术的方案为: AndFix, 阿里百川的热修复方案与 SopHix
采用class 类加载技术 方案的优点为:

1、可以实现类的替换,兼容性高。
2、可以修复资源与so库

不足:

1、不支持即时生效,必须通过重启才能生效。
2、为了实现修复这个过程,必须在应用中加入两个dex,对于patch.dex来说,修复的类到了一定数量,就需要花不少的时间加载。
3、在ART模式下,如果类修改了结构,就会出现内存错乱的问题。为了解决这个问题,就必须把所有相关的调用类、父类子类等等全部加载到patch.dex中,导致补丁包异常的大,进一步增加应用启动加载的时候,耗时更加严重。

市面上使用 类加载技术的方案较多,且各自都针对与 类加载的方案进行了不同的优化:
微信Tinker、HotFix 与 SopHix 应该都用到此方案。

在此将通过对比 HotFix、AndFix、SopHix,来看起优缺点:

方案对比Andfix开源版本HotFix阿里最新版(Sophix)
方法替换支持,除部分情况[0]支持支持
方法增加减少不支持支持以冷启动方式支持[1]
方法反射调用只支持静态方法支持以冷启动方式支持
即时生效支持不支持视情况支持[2]
多DEX不支持支持
资源更新不支持支持
so库更新不支持支持
Android版本支持2.3~7.0全部支持全部支持包含7.0以上
已有机型大部分支持[3]支持全部支持
安全机制加密传输及签名校验加密传输及签名校验
性能损耗低,几乎无损耗低,仅冷启动情况下有些损耗
生成补丁繁琐,命令行操作繁琐,命令行操作便捷,图形化界面
补丁大小不大,仅变动的类较大不大,仅变动的资源和代码[3]
服务端支持支持服务端控制[4]
是否开源开源开源不开源

[0] 部分情况指的是构造方法、参数数目大于8或者参数包括long,double,float基本类型的方法。
[1] 冷启动方式,指的是需要重启app在下次启动时才能生效。
[2] 对于Andfix能够支持的代码变动情况,都能做到即时生效。而对于Andfix不支持的代码变动情况,会走冷启动方式,此时就无法做到即时生效。
[3] 由于支持了资源和库,如果有这些方面的更新,就会导致的补丁变大一些,这个是很正常的。并且由于只包含差异的部分,所以补丁已经是最大程度的小了。
[4] 提供服务端的补丁发布和停发、版本控制和灰度功能,存储开发者上传的补丁包。

AndFix
开源:https://github.com/alibaba/AndFix
AndFix 是阿里最早出的 一个热更新的框架,art_methods 的修复技术就是由此而来的,他的是在native 层实现方法的修复的,他的流程大概为:
1、从服务端获取patch 包
2、 解析patch 包,获取new方法,与要替换的类,并以此获取old 方法。
3、在native 层,使用jni 的 FromReflectedMethod 方法,获取old 、new 在内存中的方法指针
4、将new 、old 方法指针 中的数据对掉。
由此实现了方法替换修复。
他的关键方法为:

   void replace_6_0(JNIEnv* env, jobject src, jobject dest) {
//通过Method对象得到底层Java函数对应ArtMethod的真实地址。
art::mirror::ArtMethod* smeth =
        (art::mirror::ArtMethod*) env->FromReflectedMethod(src);
art::mirror::ArtMethod* dmeth =
        (art::mirror::ArtMethod*) env->FromReflectedMethod(dest);
... ...
//把旧函数的所有成员变量都替换为新函数的。
smeth->declaring_class_ = dmeth->declaring_class_;
smeth->dex_cache_resolved_methods_ = dmeth->dex_cache_resolved_methods_;
smeth->dex_cache_resolved_types_ = dmeth->dex_cache_resolved_types_;
smeth->access_flags_ = dmeth->access_flags_;
smeth->dex_code_item_offset_ = dmeth->dex_code_item_offset_;
smeth->dex_method_index_ = dmeth->dex_method_index_;
smeth->method_index_ = dmeth->method_index_;

smeth->ptr_sized_fields_.entry_point_from_interpreter_ =
dmeth->ptr_sized_fields_.entry_point_from_interpreter_;

smeth->ptr_sized_fields_.entry_point_from_jni_ =
dmeth->ptr_sized_fields_.entry_point_from_jni_;

smeth->ptr_sized_fields_.entry_point_from_quick_compiled_code_ =
dmeth->ptr_sized_fields_.entry_point_from_quick_compiled_code_;
}

由此可知 AndFix 是在methods 层级进行修复的,可以即时修复,且对apk性能影响较小,因为其开源,可控性较高,且针对业务需要,可以自己进行定制。但其缺陷也较为明显,如果厂商对art 进行的修改,那么此 热修复框架,不会生效, 无法进行 资源与so的修复,且缺少 服务端控制,需要自己搭建服务端, 因为 此方法的局限性 , 仅能进行方法层级修复,缺少patch 的安全验证,无法添加新的方法与字段,缺陷较多

HotFix
开源:http://www.jianshu.com/p/6f0ae1e364d9
他使用的class 类加载方案, 此方案依赖的 dex 分包技术,他的流程为:
1、下载云端的patch 包
2、冷启动应用
3、在打开引用时,加载本地 patch 包,解析出 patch 包中 dex 文件
4、将dex 文件加载到内存中
到此修复完成, patch 包中的 dex 文件,包含了需要修复的类与文件,因为 如果应用存在多个dex包,系统在调用方法时,会遍历dex 文件,查找到对应类,然后去调用方法,
class 类加载方案是 将 需要修复的 类抢先加载到,ClassLoader 中的dex 数组中,遍历时 会先遍历到修复后的类,并将其返回,以此达到修复的目的。 其核心是依赖系统的此方法:

/* package */final class DexPathList {
...
public Class findClass(String name, List<Throwable> suppressed) {
        //遍历该数组
    for (Element element : dexElements) {
        //初始化DexFile
        DexFile dex = element.dexFile;
        if (dex != null) {
            //调用DexFile类的loadClassBinaryName方法返回Class实例
            Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
            if (clazz != null) {
                return clazz;
            }
        }
    }       
    return null;
}
...
} 

用class 类加载技术,是类层级上的 修复技术,可以新加字段,新加方法,且也是开源的,可控性也较高,可以针对需求 自己定制,例如微信的Tinker 方案就是 此技术结合差分包技术实现的,但此方案的缺陷也 较为明显, 修复的类,会在内存中存在2份 ,如果修复的类较多,那么对内存有影响, 且因为是以类为单位制作patch的,patch 较大, 需要冷启动,且也缺少服务端,需要自己实现。

Sophix
Sophix 是 阿里2017年6月份推出的一款商业化的 热更新修复方案, 他是从AndFix后的第三次改进更新(第二次为阿里百川的方案),虽然不开源,但从其介绍来看 应该是在 art_method 替换技术上进行升级并结合 class 加载技术来实现的,在生成patch时 判断使用那种方案, 在apk 加载patch包时,解析patch包,根据当前patch 包的方案,判断是否 需要冷启动。
SopHix 对art_method 替换技术 进行的升级,不再进行old、new 方法指针的繁琐的替换操作了,直接进行 memcpy操作,将之前一大堆的替换操作凝缩为了:

memcpy(smeth, dmeth, sizeof(ArtMethod));

而获取 ArtMethod 的大小sizeof(ArtMethod),是通过自己写两个连续的方法,通过方法指针的差值来实现的。
改进后的 art_method 的替换,即使厂商修改art 后也不会有影响,依然会替换成功。

且较为称道的是,他存在完善的后台服务端,可以对指定patch 包进行灰度测试,或直接发布。
但可惜的是不开源啊。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值