// 由于这个方法是隐藏的,因此需要使用反射调用;首先找到这个方法
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”);
}
}
}
可以看到在 ApplicationInstrumentation 里面,我们只是打印出 startActivity 中各个方法参数的值。
运行以下测试代码
try {
HookHelper.attachContext();
} catch (Exception e) {
e.printStackTrace();
}
Intent intent = new Intent(this, TestActivityStart.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);
将看到以下 log
上面 hook activity 的两种方法其实都有一定缺陷,比如,第一种方法,只能 hook 住通过 Activity startActivity 的 activity。第二种方法,只能 hook 住通过 getApplicationContext().startActivity 启动的 activity。那有没有一种方法能 hook 上述两种的,其实是有的,那就是 hook AMS。下面让我们一起来看一下。
上面 hook startActivity 其实都是 hook 相应的 mInstrumentation.execStartActivity 方法,因此,我们可以从这里下手,看 mInstrumentation.execStartActivity 里面有没有一些共性的东西,可以 hook。
我们先来 mInstrumentation.execStartActivity 方法
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
Uri referrer = target != null ? target.onProvideReferrer() : null;
if (referrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
result = am.onStartActivity(intent);
}
if (result != null) {
am.mHits++;
return result;
} else if (am.match(who, null, intent)) {
am.mHits++;
if (am.isBlocking()) {
return requestCode >= 0 ? am.getResult() : null;
}
break;
}
}
}
}
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException(“Failure from system”, e);
}
return null;
}
这里我们留意 ActivityManager.getService().startActivity 这个方法
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton IActivityManagerSingleton =
new Singleton() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
可以看到 IActivityManagerSingleton 是一个单例对象,因此,我们可以 hook 它。
public static void hookAMSAfter26() throws Exception {
// 第一步:获取 IActivityManagerSingleton
Class<?> aClass = Class.forName(“android.app.ActivityManager”);
Field declaredField = aClass.getDeclaredField(“IActivityManagerSingleton”);
declaredField.setAccessible(true);
Object value = declaredField.get(null);
Class<?> singletonClz = Class.forName(“android.util.Singleton”);
Field instanceField = singletonClz.getDeclaredField(“mInstance”);
instanceField.setAccessible(true);
Object iActivityManagerObject = instanceField.get(value);
// 第二步:获取我们的代理对象,这里因为 IActivityManager 是接口,我们使用动态代理的方式
Class<?> iActivity = Class.forName(“android.app.IActivityManager”);
InvocationHandler handler = new AMSInvocationHandler(iActivityManagerObject);
Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new
Class<?>[]{iActivity}, handler);
// 第三步:偷梁换柱,将我们的 proxy 替换原来的对象
instanceField.set(value, proxy);
}
public class AMSInvocationHandler implements InvocationHandler {
private static final String TAG = “AMSInvocationHandler”;
Object iamObject;
public AMSInvocationHandler(Object iamObject) {
this.iamObject = iamObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Log.e(TAG, method.getName());
if (“startActivity”.equals(method.getName())) {
Log.i(TAG, “ready to startActivity”);
for (Object object : args) {
Log.d(TAG, “invoke: object=” + object);
}
}
return method.invoke(iamObject, args);
}
}
执行以下测试代码
try {
HookHelper.hookAMS();
} catch (Exception e) {
e.printStackTrace();
}
startActivity(new Intent(this,TestActivityStart.class));
将会看到以下 log
I/AMSInvocationHandler: ready to startActivity
接下来我们一起来看一下 API 25 Instrumentation 的代码(自 API 26 开始 ,Instrumentation execStartActivity 方法有所改变)
public ActivityResult e