热修复方案-设计思想

什么是热修复?存在的意义?

简单来讲,热修复就是为了修复线上问题而提出的修补方案,程序修补过程无需重新发版,软件发布之后,总会出现一些Bug,这个时候就需要去解决bug然后测试,并打渠道包在各大应用市场上发布,这样就会耗费大量的人力物力。

几种热修复方案

1、底层替换方案
底层替换方案限制颇多,但时效性最好,加载轻快,立即见效。
代表:支付宝的Andfix
2、类加载方案
类加载方案时效性差,需要重新冷启动才能见效,但修复范围广,限制少。
百度实现的HotFix、QQ空间补丁技术、Qfix方案、微信的Tinker方案
3、融合方案
两种方案的结合,优势互补。
Sophix

实现原理

(1)AndFix的思想

直接更改修复的方法,就是找到这个类中需要修复的函数然后调用replaceMethod方法。在Native层使用指针替换的方式替换bug方法,以达到修复bug的目的。

优点:

BUG修复的即时性,补丁包同样采用差量技术,生成的PATCH体积小,对应用无侵入,几乎无性能损耗

局限性:

只能基于方法修复,而且对平台的兼容性不佳,不支持新增字段,以及修改方法,也不支持对资源的替换。

(2)超级补丁技术原理

是基于Android Dex分包方案的,而Dex分包方案的关键就是Android的ClassLoader体系。
关键点:DexClassLoader可以用来执行没有安装的程序代码
除了类加载问题之外还存在CLASS_ISPREVERIFIED标记的问题:
只要在static方法,构造方法,private方法,override方法中直接引用了其他dex中的类,那么这个类就不会被打上CLASS_ISPREVERIFIED标记。
解决方案:在所有类的构造函数中插入这行代码 System.out.println(AntilazyLoad.class);
超级补丁技术原理是基于Android Dex分包方案的,而Dex分包方案的关键就是Android的ClassLoader体系。把多个dex文件塞入到app的classloader之中android加载的时候,如果有多个dex文件中有相同的类,就会加载前面的类,原理就是把有问题的类替换掉,把需要的类放到最前面,达到热补的目的。

优势:

没有合成整包(和微信Tinker比起来),产物比较小,比较灵活,可以实现类替换,兼容性高

不足:

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

Tinker

也是Dex加载原理, 不同是,Tinker 下发新旧DEX的差异包,优化了DexDiff算法实现dexPatch体积更小。然后将差异包和旧包合成新dex之后进行dex的全量替换,避免了QQ补丁中的插桩操作。
全量合成新dex,消除重复class重复带来的冲突

优势:

合成整包,不用在构造函数插入代码。性能提高。兼容性和稳定性比较高。开发者透明,不需要对包进行额外处理。

不足:

不支持即时生效,必须通过重启应用的方式才能生效。开启新的进程才能进行合并,并且很容易因为内存消耗等原因合并失败。合并时占用额外磁盘空间,对于多DEX的应用来说,如果修改了多个DEX文件,就需要下发多个patch.dex与对应的classes.dex进行合并操作时这种情况会更严重,因此合并过程的失败率也会更高。

Sophix

同时涵盖底层替换方案和类加载方案。在补丁生成阶段,补丁工具会根据实际代码变动情况进行自动选择,针对小修改,在底层替换方案限制范围内的,就直接采用底层替换修复方案,而对于代码修改超出底层替换限制的,会使用类加载替换,此时及时性没那么好。另外,运行时阶段,Sophix还会再判断所运行的机型是否支持热修复,这样即使补丁支持热修复,但由于机型底层虚拟机构造不支持,还是会走类加载修复,从而达到最好的兼容性。

So修复

类似类修复反射注入方式。把补丁so库的路径插入到nativeLibraryDirectories数组的最前面,就能够达到加载so库的时候是补丁so库,而不是原来so库的目录,从而达到修复的目的。采用这种方案,完全由Sophix在启动期间反射注入patch中的so库

优点:

1、Sophix集成简单,不需要配置繁琐的各种参数。
  2、Sophix支持即时生效(事实上我第一次运行first版本后,直接就弹出了toast,而此时后台数据显示设备加载成功数为1,设备推送成功数为0)。
  3、Sophix支持run instant,而tinker不支持。编译中不支持run instant,速度大大降低!
  4、Sophix的补丁是基于阿里自身的SophixPatchTool打包生成,不是在AS中生成的,有种解耦的感觉,而且不需要备份太多的版本。
  5、Sophix资源修复方案,优越性超过了Google官方的Instant Run方案。整个资源替换的方案优势在于:
不修改AssetManager的引用处,替换更快更完全。(对比Instanat Run以及所有copycat的实现),不必下发完整包,补丁包中只包含有变动的资源。(对比Instanat Run、Amigo等方式的实现),不需要在运行时合成完整包。不占用运行时计算和内存资源。(对比Tinker的实现)

缺点:

处于公测阶段,可能面临收费
在这里插入图片描述

涉及的知识—dex分包原理:

单个Dex文件里面方法数不能超过65536个方法。
(1)原因:
在打包apk的时候,会把java文件通过类加载器编译成class文件,然后把class文件组合成class.dex文件,目的是把不同class文件重复的东西只需保留一份,dex文件。因为android会把每一个类的方法id检索起来,存在一个链表结构里面。但是这个链表的长度是用一个short类型来保存的, short占两个字节(保存-2的15次方到2的15次方-1,即-32768~32767),最大保存的数量就是65536。方法数包括引用的framwork方法,library方法,还有自己写的代码方法。因为在生成.dex文件之后会生成一些多余的资源,所以系统会对dex文件进行优化,会分配一个缓冲区,缓冲区大小的限制:在android2.x的系统上缓冲区只有5MB,android4.x为8MB或者16MB,如果方法数量超过缓冲区的大小时,会造成dexopt崩溃,所以我们一般apk的方法数要控制在65536以内,如果超出,就要考虑dex分包,api14(Android5.0)之前是不支持分包的
(2)解决方案:
精简方法数量,删除没用到的类、方法、第三方库。
使用ProGuard去掉一些未使用的代码
对部分模块采用本地插件化的方式。
分割Dex
Dex分包方案主要做的是在打包时将应用代码分成多个Dex,将应用启动时必须用到的类和这些类的直接引用类放到主Dex中,其他代码放到次Dex中。当应用启动时先加载主Dex,等到应用启动后再动态的加载次Dex。

类加载器:

java的类加载器是加载class文件,而Android的虚拟机无论是dvm还是art都只能识别dex文件,所以java的类加载器在Android中不适用,Android中的 Java.lang.ClassLoader类也不同与java中的Java.lang.ClassLoader类。

Android虚拟机类加载机制:

Android虚拟机是从dex文件里面去加载一个类,虚拟机定义的关于类的加载规范必须被实现,他规定每个ClassLoader都得有一个父亲ClassLoader,以此形成一个父子的多层级关系,利用这个层级关系实现了类的双亲委派机制, 在Android虚拟机里的ClassLoader层级关系为ClassLoader—>BaseDexClassLoader —>Dex ClassLoader和PathClassLoader,其中PathClassLoader是用来加载Android系统类和应用的类DexClassLoader支持加载APK、DEX和JAR,也可以从SD卡进行加载 ClassLoader类根据一个指定的类名称,找到或者生成相应的字节码,然后从这些字节码中定义出一个java类 DexClassLoader和PathClassLoader都属于符合双亲委派模型的类加载器(因为它们没有重载loadClass方法)。也就是说,它们在加载一个类之前,回去检查自己以及自己以上的类加载器是否已经加载了这个类。如果已经加载过了,就会直接将之返回,而不会重复加载

类加载热修复:当分包完成之后,会形成一个dex包的有序数组,当需要加载类加载器的时候,会从数组中第一个dex包开始加载,直到找到这个类为止,当多个dex包中都有这个文件的时候,就取第一个文件,热修复是通过将已经修复了的bug包打成dex包,并将这个dex包放在有序数组的第一个,当加载类文件的时候,首先会找到修改好的dex包去替换之前存在bug的dex包,而排在后面的存在bug的dex包根据类加载器的双亲委派机制不会被加载,这就是类加载热修复方法的实现。

参考:
https://mp.weixin.qq.com/s/txpZP5MqPZj0EULCzCRetg
https://blog.csdn.net/www851903307/article/details/87728975

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值