在《Android插件化原理解析——Hook机制之动态代理》一文中,hook了ContextImpl的mInstrumentation变量,我实现了下hook activity的mInstrumentation变量,原理见
http://weishu.me/2016/01/28/understand-plugin-framework-proxy-hook/
。
直接上代码:在Activity的onCreate()中
private void testHook() {
Field instrumentationField = null;
try {
// 此处使用Activity,不能使用this
// this指向继承于BaseActivity的类,如NewsDetailActivity,getDeclaredField获取到的是声明的域
instrumentationField = Activity.class.getDeclaredField("mInstrumentation");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
AppLogUtils.e("mInstrumentationField:" + instrumentationField);
if (instrumentationField != null) {
// 设置为可访问,否则IllegalAccessException
instrumentationField.setAccessible(true);
Instrumentation originInstrumentation = null;
try {
// 获取Activity对象的Instrumentation对象
originInstrumentation = (Instrumentation) instrumentationField.get(this);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (BuildConfig.DEBUG) {
// 通过打印发现每个Activity的Instrumentation对象都是一个,所以应该是可以用Activity中的mainThread的Instrumentation来获取即可
AppLogUtils.e("originInstrumentation:" + originInstrumentation);
}
// 通过查找想要“包装”的方法是否存在,判断能否可以被hook
Method execStartActivityMethod = null;
try {
execStartActivityMethod = Instrumentation.class.getDeclaredMethod("execStartActivity", Context.class, IBinder.class, IBinder.class, Activity.class, Intent.class, int.class, Bundle.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// hook
if (originInstrumentation != null && execStartActivityMethod != null) {
try {
instrumentationField.set(this, new TestInstrumentation(originInstrumentation));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
class TestInstrumentation extends Instrumentation {
private Instrumentation mOriginInstrumentation;
public TestInstrumentation(Instrumentation instrumentation) {
mOriginInstrumentation = instrumentation;
}
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
try {
AppLogUtils.e("my instrumentation start activity");
// 查找当前方法
Method execStartActivityMethod = null;
try {
execStartActivityMethod = Instrumentation.class.getDeclaredMethod("execStartActivity", Context.class, IBinder.class, IBinder.class, Activity.class, Intent.class, int.class, Bundle.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
ActivityResult result = null;
if (execStartActivityMethod != null) {
execStartActivityMethod.setAccessible(true);
try {
// 执行activity启动
result = (ActivityResult) execStartActivityMethod.invoke(mOriginInstrumentation, who, contextThread, token, target, intent, requestCode, options);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return result;
} catch (Throwable t) {
t.printStackTrace();
}
return null;
}
}
通过测试发现,进入不同activity,activity的mInstrumentation变量都是一样的,应该是使用mainThread的mInstrumentation的变量,因此可以改进成在Application的onCreate()中进行hook。