robust原理解析
robust原理解析
接上一篇
robust使用
打基础包的时候,每个类都会被添加
public static ChangeQuickRedirect u;静态成员变量
查看这个类的源码发现这个是一个接口
public interface ChangeQuickRedirect {Object accessDispatch(String methodName, Object[] paramArrayOfObject);boolean isSupport(String methodName, Object[] paramArrayOfObject);
}
反编译基本包能看到每个方法当中都被添加了这个判断
public static PatchProxyResult proxy(Object[] paramsArray, Object current, ChangeQuickRedirect changeQuickRedirect, boolean isStatic, int methodNumber, Class[] paramsClassTypes, Class returnType) {PatchProxyResult patchProxyResult = new PatchProxyResult();if (PatchProxy.isSupport(paramsArray, current, changeQuickRedirect, isStatic, methodNumber, paramsClassTypes, returnType)) {patchProxyResult.isSupported = true;patchProxyResult.result = PatchProxy.accessDispatch(paramsArray, current, changeQuickRedirect, isStatic, methodNumber, paramsClassTypes, returnType);}return patchProxyResult;}public static boolean isSupport(Object[] paramsArray, Object current, ChangeQuickRedirect changeQuickRedirect, boolean isStatic, int methodNumber, Class[] paramsClassTypes, Class returnType) {//Robust补丁优先执行,其他功能靠后if (changeQuickRedirect == null) {//不执行补丁,轮询其他监听者if (registerExtensionList == null || registerExtensionList.isEmpty()) {return false;}for (RobustExtension robustExtension : registerExtensionList) {if (robustExtension.isSupport(new RobustArguments(paramsArray, current, isStatic, methodNumber, paramsClassTypes, returnType))) {robustExtensionThreadLocal.set(robustExtension);return true;}}return false;}String classMethod = getClassMethod(isStatic, methodNumber);if (TextUtils.isEmpty(classMethod)) {return false;}Object[] objects = getObjects(paramsArray, current, isStatic);try {return changeQuickRedirect.isSupport(classMethod, objects);} catch (Throwable t) {return false;}}
如果PatchProxy.isSupport返回true
就执行PatchProxy.accessDispatch
查看源码
public static Object accessDispatch(Object[] paramsArray, Object current, ChangeQuickRedirect changeQuickRedirect, boolean isStatic, int methodNumber, Class[] paramsClassTypes, Class returnType) {if (changeQuickRedirect == null) {RobustExtension robustExtension = robustExtensionThreadLocal.get();robustExtensionThreadLocal.remove();if (robustExtension != null) {notify(robustExtension.describeSelfFunction());return robustExtension.accessDispatch(new RobustArguments(paramsArray, current, isStatic, methodNumber, paramsClassTypes, returnType));}return null;}String classMethod = getClassMethod(isStatic, methodNumber);if (TextUtils.isEmpty(classMethod)) {return null;}notify(Constants.PATCH_EXECUTE);Object[] objects = getObjects(paramsArray, current, isStatic);return changeQuickRedirect.accessDispatch(classMethod, objects);}
最后调用的就是changeQuickRedirect的accessDispatch
那实际调用的就是这个接口的实现类的方法
接下来看补丁文件
PatchesInfoImpl
根据我的上篇使用文章,我反编译出patchesinfoimpl的代码为
public class PatchesInfoImpl implements PatchesInfo {public List getPatchedClassesInfo() {ArrayList<PatchedClassInfo> arrayList = new ArrayList();arrayList.add(new PatchedClassInfo("com.freebrio.robustdemo.MainActivity", "com.freebrio.robustdemo.MainActivityPatchControl"));EnhancedRobustUtils.isThrowable = false;return arrayList;}
}
里面列出了我修改的类和对应的修改方法
MainActivity ->MainActivityPatchControl
打开这个类
package com.freebrio.robustdemo;import android.view.View;
import com.meituan.robust.ChangeQuickRedirect;
import java.util.Map;
import java.util.WeakHashMap;public class MainActivityPatchControl implements ChangeQuickRedirect {public static final String MATCH_ALL_PARAMETER = "(\\w*\\.)*\\w*";private static final Map<Object, Object> keyToValueRelation = new WeakHashMap<Object, Object>();private static Object fixObj(Object paramObject) {Object object = paramObject;if (paramObject instanceof Byte) {boolean bool;if (((Byte)paramObject).byteValue() != 0) {bool = true;} else {bool = false;} object = new Boolean(bool);} return object;}public Object accessDispatch(String paramString, Object[] paramArrayOfObject) {try {MainActivityPatch mainActivityPatch;if (paramString.split(":")[2].equals("false")) {if (keyToValueRelation.get(paramArrayOfObject[paramArrayOfObject.length - 1]) == null) {mainActivityPatch = new MainActivityPatch(paramArrayOfObject[paramArrayOfObject.length - 1]);keyToValueRelation.put(paramArrayOfObject[paramArrayOfObject.length - 1], null);} else {mainActivityPatch = (MainActivityPatch)keyToValueRelation.get(paramArrayOfObject[paramArrayOfObject.length - 1]);} } else {mainActivityPatch = new MainActivityPatch(null);} if ("5".equals(paramString.split(":")[3])) {mainActivityPatch.setTV((View)paramArrayOfObject[0]);return null;} } catch (Throwable throwable) {throwable.printStackTrace();return null;} return null;}public Object getRealParameter(Object paramObject) {Object object = paramObject;if (paramObject instanceof MainActivity)object = new MainActivityPatch(paramObject); return object;}public boolean isSupport(String paramString, Object[] paramArrayOfObject) {paramString = paramString.split(":")[3];return ":5:".contains(":" + paramString + ":");}
}
他实现的就是ChangeQuickRedirect
也就是说如果ChangeQuickRedirect不等于null那就会执行MainActivityPatchControl中的accessDispatch
可以看到这一行关键代码
if ("5".equals(paramString.split(":")[3])) {mainActivityPatch.setTV((View)paramArrayOfObject[0]);return null;}
在mainactivitypatch的settv方法中
public final void setTV(View paramView) {MainActivityPatch mainActivityPatch;MainActivity mainActivity1;CharSequence charSequence;MainActivity mainActivity2;new IntrinsicsInLinePatch(getRealParameter(new Object[] { null })[0]);EnhancedRobustUtils.invokeReflectStaticMethod("checkParameterIsNotNull", IntrinsicsInLinePatch.class, getRealParameter(new Object[] { paramView, "view" }, ), new Class[] { Object.class, String.class });if (this instanceof MainActivityPatch) {mainActivity1 = this.originClass;} else {mainActivityPatch = this;} TextView textView2 = (TextView)EnhancedRobustUtils.getFieldValue("q", mainActivityPatch, MainActivity.class);if (textView2 == null) {new IntrinsicsInLinePatch(getRealParameter(new Object[] { null })[0]);EnhancedRobustUtils.invokeReflectStaticMethod("throwUninitializedPropertyAccessException", IntrinsicsInLinePatch.class, getRealParameter(new Object[] { "textView" }, ), new Class[] { String.class });} String str = (String)EnhancedRobustUtils.invokeReflectMethod("getString1", new MainActivityInLinePatch(getRealParameter(new Object[] { this }, )[0]), getRealParameter(new Object[0]), null, null);if (str == this) {mainActivity1 = ((MainActivityPatch)str).originClass;} else {charSequence = (CharSequence)mainActivity1;} TextView textView1 = textView2;if (textView2 == this)mainActivity2 = ((MainActivityPatch)textView2).originClass; EnhancedRobustUtils.invokeReflectMethod("setText", mainActivity2, getRealParameter(new Object[] { charSequence }, ), new Class[] { CharSequence.class }, TextView.class);}
可以看到这一行关键代码
String str = (String)EnhancedRobustUtils.invokeReflectMethod("getString1", new MainActivityInLinePatch(getRealParameter(new Object[] { this }, )[0]), getRealParameter(new Object[0]), null, null);
最后调用的是我修改后的getString1方法,达到了修复的目的
接下来看一下加载过程
new PatchExecutor(getApplicationContext(), new PatchManipulateImp(), new Callback()).start();
在PatchExecutor的patch方法中
ClassLoader classLoader = null;try {File dexOutputDir = getPatchCacheDirPath(context, patch.getName() + patch.getMd5());classLoader = new DexClassLoader(patch.getTempPath(), dexOutputDir.getAbsolutePath(),null, PatchExecutor.class.getClassLoader());} catch (Throwable throwable) {throwable.printStackTrace();}if (null == classLoader) {return false;}try {Log.d("robust", "patch patch_info_name:" + patch.getPatchesInfoImplClassFullName());patchesInfoClass = classLoader.loadClass(patch.getPatchesInfoImplClassFullName());patchesInfo = (PatchesInfo) patchesInfoClass.newInstance();} catch (Throwable t) {Log.e("robust", "patch failed 188 ", t);}Field[] fields = sourceClass.getDeclaredFields();Log.d("robust", "oldClass :" + sourceClass + " fields " + fields.length);Field changeQuickRedirectField = null;for (Field field : fields) {if (TextUtils.equals(field.getType().getCanonicalName(), ChangeQuickRedirect.class.getCanonicalName()) && TextUtils.equals(field.getDeclaringClass().getCanonicalName(), sourceClass.getCanonicalName())) {changeQuickRedirectField = field;break;}}
创建了DexClassLoader,根据dexclassloader去加载dex文件,
classLoader.loadClass(patch.getPatchesInfoImplClassFullName())
getPatchesInfoImplClassFullName就是PatchesInfoImpl类,里面记录了修改的类的信息
加载完类之后
changeQuickRedirectField = field;将这个静态变量赋值接下来就走上面的步骤了
插件代码
https://github.com/Meituan-Dianping/Robust/tree/master/gradle-plugin
用AsmInsertImpl和JavaAssistInsertImpl
插桩核心代码
createInsertCode
位于https://github.com/Meituan-Dianping/Robust/blob/master/gradle-plugin/src/main/groovy/robust/gradle/plugin/asm/RobustAsmUtils.java
类中
robust原理解析相关推荐
- Spark Shuffle原理解析
Spark Shuffle原理解析 一:到底什么是Shuffle? Shuffle中文翻译为"洗牌",需要Shuffle的关键性原因是某种具有共同特征的数据需要最终汇聚到一个计算节 ...
- 秋色园QBlog技术原理解析:性能优化篇:用户和文章计数器方案(十七)
2019独角兽企业重金招聘Python工程师标准>>> 上节概要: 上节 秋色园QBlog技术原理解析:性能优化篇:access的并发极限及分库分散并发方案(十六) 中, 介绍了 ...
- Tomcat 架构原理解析到架构设计借鉴
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 Tomcat 架构原理解析到架构设计借鉴 Tomcat 发展这 ...
- 秋色园QBlog技术原理解析:性能优化篇:数据库文章表分表及分库减压方案(十五)...
文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 3: 秋色 ...
- CSS实现元素居中原理解析
原文:CSS实现元素居中原理解析 在 CSS 中要设置元素水平垂直居中是一个非常常见的需求了.但就是这样一个从理论上来看似乎实现起来极其简单的,在实践中,它往往难住了很多人. 让元素水平居中相对比较简 ...
- 秋色园QBlog技术原理解析:Web之页面处理-内容填充(八)
文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 3: 秋色 ...
- 秋色园QBlog技术原理解析:UrlRewrite之无后缀URL原理(三)
文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 本节,将从 ...
- Android之Butterknife原理解析
转载请标明出处:[顾林海的博客] 个人开发的微信小程序,目前功能是书籍推荐,后续会完善一些新功能,希望大家多多支持! ##前言 Butterknife是一个专注于Android系统的View注入框架, ...
- 【深度学习】谷歌大脑EfficientNet的工作原理解析
[深度学习]谷歌大脑EfficientNet的工作原理解析 文章目录 1 知识点准备1.1 卷积后通道数目是怎么变多的1.2 EfficientNet 2 结构2.1 方式2.2 MBConv卷积块2 ...
最新文章
- 2022年了,PyTorch和TensorFlow选哪个?
- python中模块和函数_Python中函数和模块的体验与使用
- 用C#操作word替换字符,用spire
- app调html页面,app界面管理(风格色调).html
- pandas 对某一行标准化_Python中的神器Pandas,但是有人说Pandas慢...
- MySQL数据库服务器搭建及基本管理
- 《C和指针》——C语言字符串操作
- 好用的文件批量改名工具推荐
- 红色学校网站模板_学校网站源码_适用高中,中学,小学学校网站建设
- 如何在Cell里画出虚线?
- Oracle数据库常用的管理工具介绍
- Java的class是什么意思?
- Win10 如何在系统内用cmd命令查看系统详细信息
- 祝萍:后疫情时代,医美运营既要走心也要反套路
- python+html实现前后端数据交互界面显示
- html如何设置ie6兼容性视图,IE6浏览器兼容性视图设置在哪里
- 编辑python用什么输入法_微信Python输入法, 两个地球首发!
- Cesium基础知识-加载json数据
- 地理坐标系之间的转换及经纬度、方位角、距离之间的计算!
- 【洛谷】P1830 轰炸III 题解 代码+详解
热门文章
- Java 并发编程解析 | 如何正确理解Java领域中的内存模型,主要是解决了什么问题?
- 基于js的网页计算器实现
- leetcode【排序】这个自定义排序的比较器感觉不好直接想出来,需要多练欸
- 可以去看阿哲演唱会咯~
- linux驱动由浅入深系列:tinyalsa(tinymix/tinycap/tinyplay/tinypcminfo)音频子系统之一【转】...
- web项目:智能出行规划网站——爬虫+flask+echarts+基础前端(html、css、js、jq)
- Quidem repellendus similique reiciendis quas.ExTable blond sorte bcepturi voluptatibus ipsa aliquid.
- Server U 的使用
- 如何判断模型过拟合?那些手段解决过拟合?
- CentOS install PHP