写这篇文章之前,也阅读了好几篇关于hook startActivity的文章, 因为各位大佬写的比较早了, Android Q又是19年出来的, 这里我加了Android Q的适配, 并通过hook startActivity来拦截登录跳转
一.startActivity在不同android 版本下的区别
启动Activity的通用入口
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
那么 Instrumentation的execStartActivity方法是如何执行的?
情景一. Android sdk < O(26)
int result = ActivityManagerNative.getDefault()//方式一
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
情景二. Android sdk >= O(26) 并且 sdk <= P(28)
int result = ActivityManager.getService()//方式二
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
情景三. Android sdk >= Q(29)
int result = ActivityTaskManager.getService() //方式三
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
很明显, 调用getService()的类不相同, 关键就在这里, 进这个类看下区别
Android sdk < O(26)
static public IActivityManager getDefault() {
return gDefault.get();
}
private static final Singleton gDefault = new Singleton() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
Android sdk >= O(26) 并且 sdk <= P(28)
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;
}
};
Android sdk >= Q(29)
public static IActivityTaskManager getService() {
return IActivityTaskManagerSingleton.get();
}
@UnsupportedAppUsage(trackingBug = 129726065)
private static final Singleton IActivityTaskManagerSingleton =
new Singleton() {
@Override
protected IActivityTaskManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
return IActivityTaskManager.Stub.asInterface(b);
}
};
这里再贴出Singleton的源码
package android.util;
/**
* Singleton helper class for lazily initialization.
*
* Modeled after frameworks/base/include/utils/Singleton.h
*
* @hide
*/
public abstract class Singleton {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
由以上代码可看出不管是哪个Android版本, 都会将xxManager类作为Singleton的参数类型, 要达成我们的hook startActivity的目标, 我们要获取并修改xxManager的相关信息, 先讲下为什么要这么做,再具体该怎么做?
在调用startActivity过程中,会先后执行
Activity.java
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
Instrumentation.java
int result = ActivityTaskManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
ActivityTaskManager.getService()(这里是Android Q)这个类,将startActivity方法调用起来了,说明获取到这个ActivityTaskManager.getService()对象,并拦截它的startActivity方法,即可实现startActivity的hook.这里ActivityTaskManager.getService()对象就是xxManager对象
类似上一篇hook Activity的生命周期,
Step1.我们得获取xxManager对象; Step2. 需要创建持有xxManager对象的代理; Step3. 将xxManager代理对象取代xxManager对象
二.hook流程
1.获取Singleton对象, 通过Singleton获取xxManager对象
Android sdk < O(26)
//得到ActivityManagerNative的class
Class> activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
//获取gDefault属性
Field iActivityManagerSingletonField = activityManagerNativeClass.getDeclaredField("gDefault");
iActivityManagerSingletonField.setAccessible(true);
//因为是静态变量,可以get直接得到属性值
Object iActivityManagerSingleton = iActivityManagerSingletonField.get("");
//得到IActivityManager属性所在的class
Class> singletonClass = Class.forName("android.util.Singleton");
//得到IActivityManager属性
Field mInstanceField = singletonClass.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
//singletonClass获取get()方法
Method getMethod = singletonClass.getDeclaredMethod("get");
getMethod.setAccessible(true);
//获取mInstanceField的值
final Object mInstance = getMethod.invoke(iActivityManagerSingleton);
Android sdk >= O(26) 并且 sdk <= P(28)
//得到IActivityManagerSingleton属性
Field iActivityManagerSingletonField = ActivityManager.class.getDeclaredField("IActivityManagerSingleton");
Object iActivityManagerSingletonField.setAccessible(true);
//因为是静态变量,可以get直接得到属性值
iActivityManagerSingleton = iActivityManagerSingletonField.get("");
//得到IActivityManager属性所在的class
Class> singletonClass = Class.forName("android.util.Singleton");
//得到IActivityManager属性
Field mInstanceField = singletonClass.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
//singletonClass获取get()方法
Method getMethod = singletonClass.getDeclaredMethod("get");
getMethod.setAccessible(true);
//获取mInstanceField的值
final Object mInstance = getMethod.invoke(iActivityManagerSingleton);
Android sdk >= Q(29)
// 得到ActivityTaskManager的class
Class> activityTaskManagerClass = Class.forName("android.app.ActivityTaskManager");
//得到IActivityTaskManagerSingleton属性
iActivityManagerSingletonField = activityTaskManagerClass.getDeclaredField("IActivityTaskManagerSingleton");
iActivityManagerSingletonField.setAccessible(true);
//因为是静态变量,可以get直接得到属性值
iActivityManagerSingleton = iActivityManagerSingletonField.get("");
//得到IActivityTaskManager属性所在的class
Class> singletonClass = Class.forName("android.util.Singleton");
//得到IActivityTaskManager属性
Field mInstanceField = singletonClass.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
//singletonClass获取get()方法
Method getMethod = singletonClass.getDeclaredMethod("get");
getMethod.setAccessible(true);
//获取mInstanceField的值
final Object mInstance = getMethod.invoke(iActivityManagerSingleton);
2.通过动态代理获取xxManager的代理对象
Object proxy = Proxy.newProxyInstance(singletonClass.getClassLoader(), new Class[]{activityManagerClass}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.i(TAG, "invoke: methodName=" + method.getName());
if ("startActivity".equals(method.getName())) {
if (!isLogin) { //未登录
Intent intent = null;
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof Intent) {
intent = (Intent) args[i];
break;
}
}
if (intent != null) {
intent.setClassName("com.wislie.hook",
"com.wislie.hook.LoginActivity");
}
}
}
return method.invoke(mInstance, args);
}
});
3.xxManager代理对象代替xxManager对象
mInstanceField.set(iActivityManagerSingleton, proxy);
代码链接:https://github.com/A18767101271/HookDemo.git