mToken, child.mEmbeddedID, requestCode,
ar.getResultCode(), ar.getResultData());
}
cancelInputsAndStartExitTransition(options);
}
可以看到 startActivityFromChild 中也会调用 mInstrumentation.execStartActivity 方法。因此,即我们通过 Activity startActivity 的方法启动 activity,最终都会调用到 mInstrumentation.execStartActivity 方法。因此,如果我们想要拦截的话,可以 hook 住 mInstrumentation。
由于 mInstrumentation 是类,不是 interface,不能使用动态代理的方式,因此,这里我们使用静态代理的方式。
下面让我们一起看一下 怎样 hook activity 的 mInstrumentation
-
第一步:拿到当前 activity 的 mInstrumentation
-
第二步:创建代理对象
-
第三步:将我们的代理替换原 activity 的 mInstrumentation
public static void replaceInstrumentation(Activity activity) throws Exception {
Class<?> k = Activity.class;
//通过Activity.class 拿到 mInstrumentation字段
Field field = k.getDeclaredField(“mInstrumentation”);
field.setAccessible(true);
//根据activity内mInstrumentation字段 获取Instrumentation对象
Instrumentation instrumentation = (Instrumentation) field.get(activity);
//创建代理对象
Instrumentation instrumentationProxy = new ActivityProxyInstrumentation(instrumentation);
//进行替换
field.set(activity, instrumentationProxy);
}
public class ActivityProxyInstrumentation extends Instrumentation {
private static final String TAG = “ActivityProxyInstrumentation”;
// ActivityThread中原始的对象, 保存起来
Instrumentation mBase;
public ActivityProxyInstrumentation(Instrumentation base) {
mBase = base;
}
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
// Hook之前, 可以输出你想要的!
Log.d(TAG,"xxxx: 执行了startActivity, 参数如下: " + “who = [” + who + "], " +
“contextThread = [” + contextThread + “], token = [” + token + "], " +
“target = [” + target + “], intent = [” + intent +
“], requestCode = [” + requestCode + “], options = [” + options + “]”);
// 开始调用原始的方法, 调不调用随你,但是不调用的话, 所有的startActivity都失效了.
// 由于这个方法是隐藏的,因此需要使用反射调用;首先找到这个方法
try {
Method execStartActivity = Instrumentation.class.getDeclaredMethod(
“execStartActivity”,
Context.class, IBinder.class, IBinder.class, Activity.class,
Intent.class, int.class, Bundle.class);
execStartActivity.setAccessible(true);
return (ActivityResult) execStartActivity.invoke(mBase, who,
contextThread, token, target, intent, requestCode, options);
} catch (Exception e) {
// rom修改了 需要手动适配
throw new RuntimeException(“do not support!!! pls adapt it”);
}
}
}
在 ActivityProxyInstrumentation 里面,我们打印相应的 log。
运行以下测试代码
try {
HookHelper.replaceInstrumentation(this);
} catch (Exception e) {
e.printStackTrace();
}
startActivity(new Intent(this,TestActivityStart.class));
将会看到输出以下 log
hook activity 的第二种方法
我们先来看一下 getApplicationContext startActivity 的调用关系
因此,这里我们要 hook 的是 ActivityThread 的 mInstru
mentation
public static void attachContext() throws Exception {
Log.i(TAG, "attachContext: ");
// 先获取到当前的ActivityThread对象
Class<?> activityThreadClass = Class.forName(“android.app.ActivityThread”);
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod(“currentActivityThread”);
currentActivityThreadMethod.setAccessible(true);
//currentActivityThread是一个static函数所以可以直接invoke,不需要带实例参数
Object currentActivityThread = currentActivityThreadMethod.invoke(null);
// 拿到原始的 mInstrumentation字段
Field mInstrumentationField = activityThreadClass.getDeclaredField(“mInstrumentation”);
mInstrumentationField.setAccessible(true);
Instrumentation mInstrumentation = (Instrumentation) mInstrumentationField.get(currentActivityThread);
// 创建代理对象
Instrumentation evilInstrumentation = new ApplicationInstrumentation(mInstrumentation);
// 偷梁换柱
mInstrumentationField.set(currentActivityThread, evilInstrumentation);
}
public class ApplicationInstrumentation ext