Closed w4lle closed 6 years ago
看起来跟 #240 很像
问题分析:
首先贴下未混淆的代码:
MainFragmentActivity.class
static final void onCreate_aroundBody2(MainFragmentActivity mainFragmentActivity, Bundle bundle, JoinPoint joinPoint) {
onCreate_aroundBody1$advice(mainFragmentActivity, bundle, joinPoint, MainFragmentActivity$$Injector.aspectOf(), (ProceedingJoinPoint) joinPoint);
}
private static final void onCreate_aroundBody1$advice(MainFragmentActivity mainFragmentActivity, Bundle bundle, JoinPoint joinPoint, MainFragmentActivity$$Injector mainFragmentActivity$$Injector, ProceedingJoinPoint proceedingJoinPoint) {
if (!PatchProxy.proxy(new Object[]{mainFragmentActivity, bundle, joinPoint, mainFragmentActivity$$Injector, proceedingJoinPoint}, null, changeQuickRedirect, true, 11888, new Class[]{MainFragmentActivity.class, Bundle.class, JoinPoint.class, MainFragmentActivity$$Injector.class, ProceedingJoinPoint.class}, Void.TYPE).isSupported) {
MainFragmentActivity mainFragmentActivity2 = (MainFragmentActivity) proceedingJoinPoint.getTarget();
onCreate_aroundBody0(mainFragmentActivity, bundle, proceedingJoinPoint);
}
}
public void onCreate(Bundle bundle) {
if (!PatchProxy.proxy(new Object[]{bundle}, this, changeQuickRedirect, false, 11849, new Class[]{Bundle.class}, Void.TYPE).isSupported) {
JoinPoint makeJP = Factory.makeJP(ajc$tjp_0, this, this, bundle);
MainFragmentActivity$$Injector.aspectOf().onCreate(new AjcClosure3(new Object[]{this, bundle, makeJP}).linkClosureAndJoinPoint(69648));
}
}
private static final void onCreate_aroundBody0(MainFragmentActivity mainFragmentActivity, Bundle bundle, JoinPoint joinPoint) {
if (!PatchProxy.proxy(new Object[]{mainFragmentActivity, bundle, joinPoint}, null, changeQuickRedirect, true, 11887, new Class[]{MainFragmentActivity.class, Bundle.class, JoinPoint.class}, Void.TYPE).isSupported) {
super.onCreate(bundle);
JudgeEmulatorUtil.uploadEmulatorInfoIfNeed(mainFragmentActivity);
instance = mainFragmentActivity;
mainFragmentActivity.setContentView(R.layout.main_activity);
ButterKnife.bind((Activity) mainFragmentActivity);
mainFragmentActivity.initUserCenterManager();
mainFragmentActivity.mainPagerAdapter = new MainPagerAdapter(mainFragmentActivity, mainFragmentActivity.getSupportFragmentManager());
mainFragmentActivity.userInfoPresenter = new UserInfoPresenter();
mainFragmentActivity.refreshOldDataPresenter = new RefreshOldDataPresenter();
mainFragmentActivity.tabRedPointPresenter = new TabRedPointPresenter(mainFragmentActivity);
mainFragmentActivity.getMsgCenterRedPresenter = new GetMsgCenterRedPresenter(mainFragmentActivity);
mainFragmentActivity.userInfoPresenter.setUserInfoView(mainFragmentActivity);
mainFragmentActivity.userInfoPresenter.startGetCurUserInfoDBUseCase();
INSTANCE_FLAG = 1;
BaiduLocation.getInstance(ZhangdanApplication.getInstance()).start();
mainFragmentActivity.initToolBar();
mainFragmentActivity.showImportBillDialog();
mainFragmentActivity.onLoginCreate(bundle);
mainFragmentActivity.getLoggerABConfig();
}
}
对应的patch 文件:
public class MainFragmentActivityPatch {
MainFragmentActivity originClass;
public MainFragmentActivityPatch(Object obj) {
this.originClass = (MainFragmentActivity) obj;
}
protected void onCreate(Bundle savedInstanceState) {
StaticPart staticPart = (StaticPart) EnhancedRobustUtils.getStaticFieldValue("ajc$tjp_0", MainFragmentActivity.class);
Log.d("robust", "get static value is ajc$tjp_0 No: 1");
JoinPoint joinPoint = (JoinPoint) EnhancedRobustUtils.invokeReflectStaticMethod("makeJP", Factory.class, getRealParameter(new Object[]{staticPart, this, this, savedInstanceState}), new Class[]{StaticPart.class, Object.class, Object.class, Object.class});
Object obj = (Injector) EnhancedRobustUtils.invokeReflectStaticMethod("aspectOf", Injector.class, getRealParameter(new Object[0]), null);
Object[] objArr = new Object[]{this, savedInstanceState, joinPoint};
Log.d("robust", " inner Class new No: 2");
Object obj2 = (AjcClosure3) EnhancedRobustUtils.invokeReflectConstruct("com.zhangdan.app.activities.MainFragmentActivity$AjcClosure3", getRealParameter(new Object[]{objArr}), new Class[]{Object[].class});
if (obj2 == this) {
obj2 = ((MainFragmentActivityPatch) obj2).originClass;
}
ProceedingJoinPoint proceedingJoinPoint = (ProceedingJoinPoint) EnhancedRobustUtils.invokeReflectMethod("linkClosureAndJoinPoint", obj2, getRealParameter(new Object[]{new Integer(69648)}), new Class[]{Integer.TYPE}, AroundClosure.class);
Log.d("robust", "invoke method is No: 3 linkClosureAndJoinPoint");
if (obj == this) {
obj = ((MainFragmentActivityPatch) obj).originClass;
}
EnhancedRobustUtils.invokeReflectMethod("onCreate", obj, getRealParameter(new Object[]{proceedingJoinPoint}), new Class[]{ProceedingJoinPoint.class}, Injector.class);
Log.d("robust", "invoke method is No: 4 onCreate");
}
}
MainFragmentActivity.onCreate方法,
我们往下跟下 Aspectj 的调用流程。MainFragmentActivity$$Injector.aspectOf().onCreate(new AjcClosure3(new Object[]{this, bundle, makeJP}).linkClosureAndJoinPoint(69648));
调用了Injector 对象的onCreate 方法,参数是一个AjcClosure.linkClosureAndJoinPoint后获得的对象。
AjcClosure 类
public abstract class AroundClosure {
...
protected Object[] state;
public AroundClosure(Object[] state) {
this.state = state;
}
public Object[] getState() {
return state;
}
/**
* This takes in the same arguments as are passed to the proceed
* call in the around advice (with primitives coerced to Object types)
*/
public abstract Object run(Object[] args) throws Throwable;
public ProceedingJoinPoint linkClosureAndJoinPoint(int flags) {
//TODO is this cast safe ?
ProceedingJoinPoint jp = (ProceedingJoinPoint)state[state.length-1];
jp.set$AroundClosure(this);
this.bitflags = flags;
return jp;
}
}
AjcClosure 接收一个 Object 的对象数组,在基础包中,它的实现是
new Object[]{this, bundle, makeJP}
注意这个 this
,代表的是MainFragmentActivity 对象。
相对应的看下patch包中的实现
Object[] objArr = new Object[]{this, savedInstanceState, joinPoint};
注意这个
这里调用了下 this
代表的是MainFragmentActivityPatch 对象。getRealParameter(new Object[]{objArr})
进行了 this 转换,所以这里的this 也是MainFragmentActivity对象,这里是没问题的。
然后调用 linkClosureAndJoinPoint
方法得到 ProceedingJoinPoint 对象,当做参数传递给 MainFragmentActivity$$Injector.onCreate(ProceedingJoinPoint joinPoint) 方法,看下这个方法的实现:
MainFragmentActivity$$Injector.class
@Aspect
public class MainFragmentActivity$$Injector {
@Around("execution(* com.zhangdan.app.activities.MainFragmentActivity.onCreate(..))")
public void onCreate(ProceedingJoinPoint joinPoint) throws Throwable {
MainFragmentActivity target = (MainFragmentActivity)joinPoint.getTarget();
...
joinPoint.proceed();
}
调用了ProceedingJoinPoint.proceed抽象方法,实现在
JoinPointImpl.java
public Object proceed() throws Throwable {
// when called from a before advice, but be a no-op
return arc.run(arc.getState());
}
这里的 arc
是 AroundClosure,arc.getState()
返回的是构造AroundClosure时传递过来的对象数组。
最后调用了抽象方法 run(Object[] args)
,实现在
public class MainFragmentActivity$AjcClosure3 extends AroundClosure {
public static ChangeQuickRedirect changeQuickRedirect;
public MainFragmentActivity$AjcClosure3(Object[] objArr) {
super(objArr);
}
public Object run(Object[] objArr) {
PatchProxyResult proxy = PatchProxy.proxy(new Object[]{objArr}, this, changeQuickRedirect, false, 11911, new Class[]{Object[].class}, Object.class);
if (proxy.isSupported) {
return proxy.result;
}
Object[] objArr2 = this.state;
MainFragmentActivity.onCreate_aroundBody2((MainFragmentActivity) objArr2[0], (Bundle) objArr2[1], (JoinPoint) objArr2[2]);
return null;
}
}
最后调用 MainFragmentActivity.onCreate_aroundBody2((MainFragmentActivity) objArr2[0], (Bundle) objArr2[1], (JoinPoint) objArr2[2]);
,整个 AOP 的流程就走通了。
~~关注这个方法的第一个参数,从对象数组中拿出第一个对象,将其强转为 MainFragmentActivity
,但是这个参数在 Patch 中传递过来的是MainFragmentActivityPatch对象,所以出现了强转错误。
也可以说,由于在Patch中提前把还未转换的patch对象传递到了Aspectj 中,Aspectj 使用了缓存的patch对象,导致出现了强转的错误。~~
最后总结下 Aspectj 的调用流程:
MainFragmentActivity.onCreate ->
MainFragmentActivity$$Injector.onCreate(ProceedingJoinPoint joinPoint) ->
ProceedingJoinPoint.proceed() ->
AroundClosure.run(Object[] args) ->
MainFragmentActivity$AjcClosure3.run(Object[] objArr) ->
MainFragmentActivity.onCreate_aroundBody2((MainFragmentActivity) objArr2[0], (Bundle) objArr2[1], (JoinPoint) objArr2[2]); ->
MainFragmentActivity.onCreate_aroundBody1$advice ->
MainFragmentActivity.onCreate_aroundBody0();
最后的 MainFragmentActivity.onCreate_aroundBody0();
方法实际上就是onCreate()的原始方法逻辑。
~~根据上面的分析,也就能找到解决办法了。
Object[] objArr = new Object[]{this, savedInstanceState, joinPoint};
->
Object[] objArr = getRealParameter(new Object[]{this, savedInstanceState, joinPoint});
~~
上面已经调了 getRealParameter(new Object[]{this, savedInstanceState, joinPoint});
所以还是没有找到问题所在啊 😢
另外,对于修改后的代码,没有被打入补丁,也是可以解释的。 对于auto-path-plugin,Transform 的顺序是 Aspectj -> auto-patch. 那么,对于标记修改的onCreate方法来说,Aspectj 处理完后,onCreate 方法被替换成了代理,真正的方法实现被新生成的方法隐藏起来了。 而我们仅仅标记了旧的onCreate 方法,其结果就是,Aspectj 的代理onCreate方法被patch了,而实际的方法虽然方法体内有我们的修复,但是由于没有标记@Modify 而被忽略。
因为是强转crash,所以在 $$Injector 代码中插入一些 Log
MainFragmentActivity$$Injector.class
@Around("execution(* com.zhangdan.app.activities.MainFragmentActivity.onCreate(..))")
public void onCreate(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
if (!PatchProxy.proxy(new Object[]{proceedingJoinPoint}, this, changeQuickRedirect, false, 11892, new Class[]{ProceedingJoinPoint.class}, Void.TYPE).isSupported) {
MainFragmentActivity target = (MainFragmentActivity) proceedingJoinPoint.getTarget();
...
Log.d("robust-wll", "test for aspectj start ");
...
Log.d("robust-wll", "getTarget : " + proceedingJoinPoint.getTarget().getClass().getSimpleName());
Log.d("robust-wll", "getThis : " + proceedingJoinPoint.getThis().getClass().getSimpleName());
Log.d("robust-wll", "getArgs[0] : " + (proceedingJoinPoint.getArgs()[0] != null ? proceedingJoinPoint.getArgs()[0].getClass().getSimpleName() : null));
Field arcField = proceedingJoinPoint.getClass().getDeclaredField("arc");
arcField.setAccessible(true);
AroundClosure arc = (AroundClosure) arcField.get(proceedingJoinPoint);
if (!(arc == null || arc.getState() == null || arc.getState().length < 3)) {
Object[] states = arc.getState();
Log.d("robust-wll", "states[0] : " + (states[0] != null ? states[0].getClass().getSimpleName() : null));
Log.d("robust-wll", "states[1] : " + (states[1] != null ? states[1].getClass().getSimpleName() : null));
Log.d("robust-wll", "states[2] : " + (states[2] != null ? states[2].getClass().getSimpleName() : null));
}
Log.d("robust-wll", "test for aspectj end ");
proceedingJoinPoint.proceed();
}
}
在不加载补丁情况下的 log 如下:
04-03 17:13:41.184 15469 15469 D robust-wll: test for aspectj start
04-03 17:13:41.184 15469 15469 D robust-wll: getTarget : MainFragmentActivity
04-03 17:13:41.185 15469 15469 D robust-wll: getThis : MainFragmentActivity
04-03 17:13:41.185 15469 15469 D robust-wll: getArgs[0] : null
04-03 17:13:41.185 15469 15469 D robust-wll: states[0] : MainFragmentActivity
04-03 17:13:41.185 15469 15469 D robust-wll: states[1] : null
04-03 17:13:41.186 15469 15469 D robust-wll: states[2] : JoinPointImpl
04-03 17:13:41.186 15469 15469 D robust-wll: test for aspectj end
加载补丁后,log 如下:
04-03 17:27:41.885 18490 18490 D robust-wll: test for aspectj start
04-03 17:27:41.885 18490 18490 D robust-wll: getTarget : MainFragmentActivity
04-03 17:27:41.886 18490 18490 D robust-wll: getThis : MainFragmentActivity
04-03 17:27:41.886 18490 18490 D robust-wll: getArgs[0] : null
04-03 17:27:41.886 18490 18490 D robust-wll: states[0] : MainFragmentActivityPatch
04-03 17:27:41.886 18490 18490 D robust-wll: states[1] : null
04-03 17:27:41.886 18490 18490 D robust-wll: states[2] : JoinPointImpl
04-03 17:27:41.886 18490 18490 D robust-wll: test for aspectj end
states[0] : MainFragmentActivityPatch 这个明显是不对的,所以我们知道了原因,是因为在构造 AroundClosure
时候传进来的参数不对。
报错地方对应于上面的分析,也就是
Object[] objArr = new Object[]{this, savedInstanceState, joinPoint};
Object obj2 = (AjcClosure3) EnhancedRobustUtils.invokeReflectConstruct("com.zhangdan.app.activities.MainFragmentActivity$AjcClosure3", getRealParameter(new Object[]{objArr}), new Class[]{Object[].class});
结果就是,把一个含有3个对象的一维数据,编程了含有一个对象的二维数组,然后去 getRealParameter。
public Object[] getRealParameter(Object[] objArr) {
if (objArr == null || objArr.length < 1) {
return objArr;
}
Object[] objArr2 = new Object[objArr.length];
for (int i = 0; i < objArr.length; i++) {
if (objArr[i] == this) {
objArr2[i] = this.originClass;
} else {
objArr2[i] = objArr[i];
}
}
return objArr2;
}
而这个方法只判断了一维数组的情况,没有判断二维或多维数组的情况。终于找到原因了 😃 对应的修改方法:
public Object[] getRealParameter(Object[] objArr) {
if (objArr == null || objArr.length < 1) {
return objArr;
}
Object[] objArr2 = new Object[objArr.length];
for (int i = 0; i < objArr.length; i++) {
if (objArr[i] instanceof Object[]) {
objArr2[i] = getRealParameter(((Object[]) objArr[i]));
} else {
if (objArr[i] == this) {
objArr2[i] = this.originClass;
} else {
objArr2[i] = objArr[i];
}
}
}
return objArr2;
}
castException 终于是搞定了。mr #259 但是还有个问题没有想明白,就是明明是个二维数组,为什么反射构造 AroundClosure 时,结果就把二维数组转为一维数组了??debug 跟了下,反射构造方法那里,传进去的就是个二维数组,反射完 AroundClosure 中由构造方法传递进来的数组参数,就变成一维的了。想不通啊想不通。@hedex 可以解释下吗?
至于被Aspectj 处理过的方法无法被打入patch的问题,理论上来说跟泛型的桥方法是类似的,具体参考 Android热更新方案Robust开源,新增自动化补丁工具——Java编译器的优化一节 解决方案也是 @Modify -> RobustModify.modify();
,待验证
经验证,会报错。log如下
Caused by: javassist.CannotCompileException: [source error] not-available: this
at javassist.expr.MethodCall.replace(MethodCall.java:241)
at javassist.expr.MethodCall$replace$2.call(Unknown Source)
at com.meituan.robust.autopatch.PatchesFactory$1.edit(PatchesFactory.groovy:144)
at javassist.expr.ExprEditor.loopBody(ExprEditor.java:224)
at javassist.expr.ExprEditor.doit(ExprEditor.java:91)
at javassist.CtBehavior.instrument(CtBehavior.java:712)
at javassist.CtBehavior$instrument$1.call(Unknown Source)
at com.meituan.robust.autopatch.PatchesFactory.createPatchClass(PatchesFactory.groovy:76)
at com.meituan.robust.autopatch.PatchesFactory.createPatch(PatchesFactory.groovy:310)
at com.meituan.robust.autopatch.PatchesFactory$createPatch.call(Unknown Source)
at robust.gradle.plugin.AutoPatchTransform.generatPatch(AutoPatchTransform.groovy:190)
at robust.gradle.plugin.AutoPatchTransform$generatPatch$0.callCurrent(Unknown Source)
at robust.gradle.plugin.AutoPatchTransform.autoPatch(AutoPatchTransform.groovy:138)
at robust.gradle.plugin.AutoPatchTransform$autoPatch.callCurrent(Unknown Source)
at robust.gradle.plugin.AutoPatchTransform.transform(AutoPatchTransform.groovy:97)
at com.android.build.api.transform.Transform.transform(Transform.java:290)
at com.android.build.gradle.internal.pipeline.TransformTask$2.call(TransformTask.java:185)
at com.android.build.gradle.internal.pipeline.TransformTask$2.call(TransformTask.java:181)
at com.android.builder.profile.ThreadRecorder.record(ThreadRecorder.java:102)
... 27 more
Caused by: compile error: not-available: this
at javassist.compiler.CodeGen.atKeyword(CodeGen.java:1908)
at javassist.compiler.ast.Keyword.accept(Keyword.java:35)
at javassist.compiler.JvstCodeGen.atMethodArgs(JvstCodeGen.java:358)
at javassist.compiler.MemberCodeGen.atMethodCallCore(MemberCodeGen.java:569)
at javassist.compiler.MemberCodeGen.atCallExpr(MemberCodeGen.java:537)
at javassist.compiler.JvstCodeGen.atCallExpr(JvstCodeGen.java:244)
at javassist.compiler.ast.CallExpr.accept(CallExpr.java:46)
at javassist.compiler.CodeGen.atStmnt(CodeGen.java:338)
at javassist.compiler.ast.Stmnt.accept(Stmnt.java:50)
at javassist.compiler.CodeGen.atStmnt(CodeGen.java:351)
at javassist.compiler.ast.Stmnt.accept(Stmnt.java:50)
at javassist.compiler.Javac.compileStmnt(Javac.java:569)
at javassist.expr.MethodCall.replace(MethodCall.java:235)
... 45 more
问题分析,根据堆栈显示,这里是在做替换super 方法的逻辑,跟了下plugin 的 debug,生成需要replace 的javassist 代码为 {staticRobustonCreate(this,originClass,$$);}
,然后在replace 后,javac编译这条语句的时候跪了。
分析下需要替换的super的方法,这个方法实际上是Aspectj 处理后的方法,根据上面分析的Aspectj的调用流程得知,该方法实际上是onCreate方法原始的逻辑,反编译出来如下:
private static final void onCreate_aroundBody0(MainFragmentActivity mainFragmentActivity, Bundle bundle, JoinPoint joinPoint) {
if (!PatchProxy.proxy(new Object[]{mainFragmentActivity, bundle, joinPoint}, null, changeQuickRedirect, true, 11887, new Class[]{MainFragmentActivity.class, Bundle.class, JoinPoint.class}, Void.TYPE).isSupported) {
super.onCreate(bundle);//这里是需要替换的地方
...
}
}
而auto-patch做的工作是将super.onCreate
方法包装成 static 方法,正常生成的patch代码如下:
public class SecondActivityPatch {
SecondActivity originClass;
public SecondActivityPatch(Object obj) {
this.originClass = (SecondActivity) obj;
}
public void onCreate(Bundle bundle) {
staticRobustonCreate(this,originClass,bundle);
...
}
public static void staticRobustonCreate(SecondActivityPatch secondActivityPatch, SecondActivity secondActivity, Bundle bundle) {
SecondActivityPatchRobustAssist.staticRobustonCreate(secondActivityPatch, secondActivity, bundle);
}
public class SecondActivityPatchRobustAssist extends Activity {
public static void staticRobustonCreate(SecondActivityPatch secondActivityPatch, SecondActivity secondActivity, Bundle bundle) {
super.onCreate(bundle);
}
}
而对于已经被Aspectj处理过的方法,是这样的:
private static final void onCreate_aroundBody0(MainFragmentActivity mainFragmentActivity, Bundle bundle, JoinPoint joinPoint) {
if (!PatchProxy.proxy(new Object[]{mainFragmentActivity, bundle, joinPoint}, null, changeQuickRedirect, true, 11887, new Class[]{MainFragmentActivity.class, Bundle.class, JoinPoint.class}, Void.TYPE).isSupported) {
//super.onCreate(bundle);//这里是需要替换的地方
staticRobustonCreate(this,originClass,bundle);
...
}
}
在static 方法中使用了 this
关键字,当然编译出错啦。同理这个 originClass
也不可以出现,因为它是非static变量。
由于 xxPatchRobustAssist.staticRobustonCreate() 方法并没有用到前两个变量(patch, activity),直接传 null 行不行呢?经验证是不行的,原因如下。
看了下生成xxxPatchRobustAssist类的代码:
class PatchesAssistFactory {
def
static createAssistClass(CtClass modifiedClass, String patchClassName, CtMethod removeMethod) {
....
StringBuilder staticMethodBuidler = new StringBuilder();
if (removeMethod.parameterTypes.length > 0) {
staticMethodBuidler.append("public static " + removeMethod.returnType.name + " " + ReflectUtils.getStaticSuperMethodName(removeMethod.getName())
+ "(" + patchClassName + " patchInstance," + modifiedClass.getName() + " modifiedInstance," + JavaUtils.getParameterSignure(removeMethod) + "){");
} else {
staticMethodBuidler.append("public static " + removeMethod.returnType.name + " " + ReflectUtils.getStaticSuperMethodName(removeMethod.getName())
+ "(" + patchClassName + " patchInstance," + modifiedClass.getName() + " modifiedInstance){");
}
staticMethodBuidler.append(" return patchInstance." + removeMethod.getName() + "(" + JavaUtils.getParameterValue(removeMethod.getParameterTypes().length) + ");");
staticMethodBuidler.append("}");
...
return assistClass;
}
}
实际上,最终生成的调用是 xxPatch.superMethod($$);
,$$代表全部参数。对于与上面的onCreate方法就是 xxPatch.onCreate(bundle);
。
所以,patch 应该不能传 null了,否则运行时会报空指针,那第二个参数activity 能不能传 null呢?继续往下看。
首先,根据常识,static 方法中肯定是不能调用 super方法的。从最终生成的代码也能看出,这并不是最终反编译出的的 super.onCreate(bundle)
方法调用。所以处理的地方肯定在javassist修改编译之后,对应处理的地方在smali 层,代码:
SmaliTool.java
private String invokeSuperMethodInSmali(final String line, String fullClassName) {
...
result = line.replace(Constants.SMALI_INVOKE_VIRTUAL_COMMAND, Constants.SMALI_INVOKE_SUPER_COMMAND);
try {
if (!ctMethod.getReturnType().isPrimitive()) {
returnType = "L" + ctMethod.getReturnType().getName().replaceAll("\\.", "/");
} else {
returnType = String.valueOf(((CtPrimitiveType) ctMethod.getReturnType()).getDescriptor());
}
if (NameManger.getInstance().getPatchNameMap().get(fullClassName).equals(fullClassName)) {
result = result.replace("p0", "p1");
}
...
} catch (Exception e) {
throw new RuntimeException(e);
}
...
}
实际上就是把方法调用从 invoke-invoke-virtual {p0, p2}, Lcom/meituan/robust/patch/SecondActivityPatch;->onCreate(Landroid/os/Bundle;)
V 转换成 invoke-super {p1, p2}, Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V
,这步处理完才会真正的调用父类的super方法。
也就是说,在smali 处理完后,参数从 p0 -> p1,也就是参数从 xxpatch 换成了 Activity,第二个参数会在运行时用到,所以也不能传null。
分析完了总结下,第二个参数 originClass 肯定不能传 null,否则会空指针;第一个参数 xxPatch,由于在smali 被替换成了第二个参数,所以有可能是可以传 null 的。
关于super 方法的处理,参考官方文章 Android热更新方案Robust
解决方案:
.method private static final onCreate_aroundBody0(Lcom/zhangdan/app/activities/MainFragmentActivity;Landroid/os/Bundle;Lorg/aspectj/lang/JoinPoint;)V
...
invoke-super {p0, p1}, Lcom/zhangdan/app/activities/WrapperAppCompatFragmentActivity;->onCreate(Landroid/os/Bundle;)V
所以只要不处理就好了,需要做的就是在auto-plugin 中增加条件判断,符合 static 方法中带有super 的不处理,一共有三处,一处是生成 xxPatchRobustAssist辅助类,第二处在javassit替换super方法,第三处在smali处理补丁中的super方法。
对于方案1,问题: 如果patch 和 originClass 都是static ,那么就会有内存泄露的风险。 并且如果被 patch 方法是static 方法,那么在初始化 patch 时,originClass 会传 null。
public Object accessDispatch(String methodName, Object[] paramArrayOfObject) {
try {
Log.d("robust", new StringBuffer().append("arrivied in AccessDispatch ").append(methodName).append(" paramArrayOfObject ").append(paramArrayOfObject).toString());
MainFragmentActivityPatch mainFragmentActivityPatch;
if (!methodName.split(":")[2].equals("false")) {
Log.d("robust", "static method forward ");
mainFragmentActivityPatch = new MainFragmentActivityPatch(null);
同样应该也是为了避免内存泄露,每修复一个方法就会生成一个 patch 对象并持有static 的originClass引用。 对于方案2 ,问题: 首先,Aspectj 在static 方法中插了个super方法,这个是怎么做到的暂时不知道,直接写的话编译时会报错,smaili 处理吧还没到这一步。不管Aspectj怎么处理的,被修复后,这个static方法是在xxPatch类中的,auto-patch即使不处理,运行时也不能正常运行,因为xxPatch 不是originClass 父类的子类,不能调用super 方法。
观察Aspectj生成的方法,所有的static 方法,第一个参数都是当前类的引用,比如 private static final void onCreate_aroundBody0(MainFragmentActivity mainFragmentActivity, Bundle bundle, JoinPoint joinPoint) {
。
所以比如根据上面的分析,得出一个可行的方案:
def static String invokeSuperString(MethodCall m, String originClass) {
...
stringBuilder.append(getStaticSuperMethodName(m.methodName) + "(" + null + "," + originClass + ",\$\$);");
...
}
如果是static 方法中含有 super 方法,就如下处理。
第一个xxPatch 对象传空,最后在smali 处理的时候会被替换掉。
第二个参数是从类似onCreate_aroundBody0()
中传过来的,后面的是其他参数。
最终结果:
public static void staticRobustonCreate(MainFragmentActivityPatch mainFragmentActivityPatch, MainFragmentActivity mainFragmentActivity, Bundle bundle) {
MainFragmentActivityPatchRobustAssist.staticRobustonCreate(mainFragmentActivityPatch, mainFragmentActivity, bundle);
}
private static final void onCreate_aroundBody0(MainFragmentActivity ajc$this, Bundle savedInstanceState, JoinPoint joinPoint) {
...
staticRobustonCreate(null, ajc$this, savedInstanceState);
}
我们看看哈~ 感谢反馈
@hedex 已经解决,见pr #265
👍
异常类型:app运行时异常
手机型号:Nexus6
手机系统版本:Android 8.0
Robust版本:0.4.78
Gradle版本:gradle 3.3,build:gradle:2.2.3
系统:Mac
堆栈/日志:
aspectj 声明代码,其中的
MainFragmentActivity$$Injector
是APT生成的代码:基础包反编译后代码:
patch 包代码