热修复框架研究之Robust原理
Robust是美团点评团队在2017年3月开源的热修复框架,和阿里的AndFix不同,Robust不用依赖JNI层,直接通过Java层代码就可以实现热修复。相比于其他热修复框架,官方给出Robust的优势有以下几点
- 支持Android2.3-7.X版本
- 高兼容性、高稳定性,修复成功率高达三个九
- 补丁下发立即生效,不需要重新启动
- 支持方法级别的修复,包括静态方法
- 支持增加方法和类
- 支持ProGuard的混淆、内联、优化等操作
不接触JNI层,Robust是如何添加方法与类、立即生效其补丁的呢?
Robust一共分为四个模块,分别为:
- autopatchbase(热补丁基类)
- gradle-plugin(负责apk包的插桩)
- auto-patch-plugin(负责提取制作patch包)
- patch(负责补丁包的补丁工作)
我们一个一个来分析
AutoPatchBase
作为热补丁的基类,主要类是有几个:
2个注解分别为@Add(添加新的类)和@Modify(修改当前类的方法);
一个Constant类用来保存固定的字符串;
一个ChangeQuickRedirect接口,用来给plugin确认当前类是否需要patch
Gradle-Plugin
用于插桩的工具。首先进行对Apk检查防止包被篡改,然后在RobustTransform.groovy中
- 执行apply(...)方法,读取项目目录下的robust.xml加载热补丁的配置
- 进入transform(...)方法,依次读取bootClasspath下的所有class文件并加入ClassPool中
- 进入insertRobustCode方法,然后做了以下几件微小的工作:
- 将class设置为public
- 当class为接口/无方法类时,执行5
- 给class插入一个public static的ChangeQuickRedirect对象
- 对所有方法使用Javassist插入代码:当该方法的changeQuickRedirect不为空时,直接将参数直接传入PatchProxy的accessDispatchVoid/accessDispatch方法并返回,这样做跳过了原方法后面的代码,从而实现了方法的替换
- 写入原来的class文件中
- 打包压缩生成apk
由此,就实现了插桩的工作
Auto-Patch-Plugin
制作patch包的工具。主要逻辑在AutoPatchTransform.groovy中,
- 执行apply(…)方法,初始化参数
- 跳到transform(…)中,又做了细微的工作
- 复制项目中的LIB_NAME_ARRAY中的3个jar包到./robust/文件夹下(unknown why)
- 读取bootClasspath路径下的class文件并转换为CtClass对象数组
- 执行打包autoPatch(…)
- 首先执行ReadAnnonation(…)去读取CtClass数组中的注解,然后把注解的方法/类放在Config中保存
- 执行ReadMapping.initMappingInfo(),读取mapping.txt将被ProGuard混淆了的类的对象还原成原来的类
- 通过InlineClassFactory构造新加的类
- 处理super的方法调用
- 针对每一个有补丁方法的类,使用PatchesFactory.createPatch构造出Patch实现类
- 使用PatchesControlFactory.createPatchesControl构造PatchControl类
- 使用PatchesInfoFactory.createPatchesInfo构造PatchInfo类
- 重新打包,优化smali
Patch
在activity中,通过执行以下代码运行了补丁
new PatchExecutor(getApplicationContext(), new PatchManipulateImp(), new Callback()).start();
PatchExecutor是一个Thread的子类,通过PatchManipulateImp指定的路径去读patch文件,然后给DexClassLoader加载并读取PatchInfo,然后通过PatchInfo中的信息获得需要补丁的类,通过反射修改其changeQuickRedirect对象的值,做到修改函数运行的路径
总结
用一张图来总结robust原理
当然原理看起来简单,其中还是有很多难点在其中,例如
- 如何解决patch中涉及到的包访问权限
- 如何解决super的问题
- …
各位对具体实现有兴趣的,可以通过解压官方demo中的补丁包,用JD-GUI来看看patch包中各种patchInfo、patchControl是如何处理的
原贴地址:https://zhuanlan.zhihu.com/p/26036302