首先工程的编译环境的是API 28,startActivity的源码跳转到Activity.java的方法中:
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
// 这里的局部变量是关键
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
// Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
代码跳转到 Instrumentation.java
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= 0 ? am.getResult() : null;
}
break;
}
}
}
}
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
// 这里这里 这将是检查Activity的地方,所以下一步是去ActivityManager,注意是API 28
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
/**
* @hide
*/
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;
}
};
hook点的选择原则上选单例和静态变量,所以这里就是被选中的hook点 IActivityManagerSingleton变量。IActivityManager根据源码IActivityManager.aidl,中的第三个参数是Intent.
IActivityManager.aidl源码
int startActivity(in IApplicationThread caller, in String callingPackage, in Intent intent,
in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode,
int flags, in ProfilerInfo profilerInfo, in Bundle options);
占坑Activity
到这里就是启动activity到校验这个被启动的activity是否在AndroidManifest.xml中被注册,只要把没有注册的activity换成占坑的Activity。hook的代码:
try {
Field enterField = null;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
Class activityManagerClass = Class.forName("android.app.ActivityManager");
//Field IActivityManagerSingleton
enterField = activityManagerClass.getDeclaredField("IActivityManagerSingleton");
} else {
Class activityManagerNative = Class.forName("android.app.ActivityManagerNative");
enterField = activityManagerNative.getDeclaredField("gDefault");
}
enterField.setAccessible(true);
//Singleton的实例,因为IActivityManagerSingleton是静态的
Object singletonObject = enterField.get(null);
Class singletonClass = Class.forName("android.util.Singleton");
Field mInstanceField = singletonClass.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
// 获取singletonObject中变量mInstance的值即IActivityManager类型的实例
final Object mIActivityManagerObject = mInstanceField.get(singletonObject);
//IActivityManager 是接口,通过动态代理来处理
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class iActivityManagerInterface = Class.forName("android.app.IActivityManager");
//生产IActivityManager的代理对象
Object mIActivityManagerProxy = Proxy.newProxyInstance(
classLoader, new Class[]{iActivityManagerInterface}, new InvocationHandler() {
@Override public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Log.e(TAG, "invoke: ~~~~~~ " + method.getName());
if ("startActivity".equals(method.getName())) {
Log.i(TAG, "准备启动activity");
Intent rawIntent = null;
int index = 0;
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof Intent) {
rawIntent = (Intent) args[i];
index = i;
break;
}
}
// 将需要被启动的Activity替换成StubActivity
Intent newIntent = new Intent();
String stubPackage = "per.zkingcobra.demo.proxyapp";
newIntent.setComponent(new ComponentName(stubPackage, StubActivity.class.getName()));
// newIntent.setClassName(rawIntent.getComponent().getPackageName(), StubActivity.class.getName());
//把这个newIntent放回到args,达到了一个欺骗AMS的目的
newIntent.putExtra(EXTRA_TARGET_INTENT, rawIntent);
args[index] = newIntent;
}
return method.invoke(mIActivityManagerObject, args);
}
});
//把我们的代理对象融入到framework
//IActivityManager 在源码中是AIDL
mInstanceField.set(singletonObject, mIActivityManagerProxy);
} catch (Exception e) {
Log.e(TAG, "hookIActivityManager: " + e.getMessage());
e.printStackTrace();
}
在执行startActivity之前运行,这个时候跳转就会跳转到StubActivity。所以,需要在校验完成之后换回想要启动的Activity,根据后面的Activity启动流程由ApplicationThread—>ActivityThread.mH ----> sendMessage 启动Activity。因为版本的变化
//已经没有了
public static final int LAUNCH_ACTIVITY = 100;
.....
//Api 28中
public static final int EXECUTE_TRANSACTION = 159;
这个已经没有了。这一部分重构成了状态模式。
class H extends Handler{
.....
public void handleMessage(Message msg) {
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
if (isSystem()) {
// Client transactions inside system process are recycled on the client side
// instead of ClientLifecycleManager to avoid being cleared before this
// message is handled.
transaction.recycle();
}
// TODO(lifecycler): Recycle locally scheduled transactions.
break;
.....
}
.....
}
所以,恢复Activity的hook处理也要做版本的兼容
try {
Class launchActivityClass = Class.forName("android.app.ActivityThread");
Field mCurrentActivityThreadFiled = launchActivityClass.getDeclaredField("sCurrentActivityThread");
// 获取ActivityThread的实例
mCurrentActivityThreadFiled.setAccessible(true);
Object currentActivityThreadObject = mCurrentActivityThreadFiled.get(null);
//获取H
Field mHFiled = launchActivityClass.getDeclaredField("mH");
//H的实例
mHFiled.setAccessible(true);
Handler hObject = (Handler) mHFiled.get(currentActivityThreadObject);
//获取callback
Field mCallbackField = Handler.class.getDeclaredField("mCallback");
mCallbackField.setAccessible(true);
// TODO 为什么不需要动态代理了?
mCallbackField.set(hObject, new Handler.Callback() {
@Override public boolean handleMessage(Message msg) {
Log.e(TAG, "handleMessage: " + msg.what);
switch (msg.what) {
case 100:
// TODO 需要处理
break;
case 159:
//恢复真身
Object obj = msg.obj;
Log.i(TAG, "handleMessage: obj=" + obj);
try {
Field mActivityCallbacksField = obj.getClass().getDeclaredField("mActivityCallbacks");
mActivityCallbacksField.setAccessible(true);
List mActivityCallbacks = (List) mActivityCallbacksField.get(obj);
Log.i(TAG, "handleMessage: mActivityCallbacks= " + mActivityCallbacks);
if (mActivityCallbacks.size() > 0) {
Log.i(TAG, "handleMessage: size= " + mActivityCallbacks.size());
String className = "android.app.servertransaction.LaunchActivityItem";
if (mActivityCallbacks.get(0).getClass().getCanonicalName().equals(className)) {
Object object = mActivityCallbacks.get(0);
Field intentField = object.getClass().getDeclaredField("mIntent");
intentField.setAccessible(true);
Intent intent = (Intent) intentField.get(object);
Intent targetIntent = intent.getParcelableExtra(EXTRA_TARGET_INTENT);
intent.setComponent(targetIntent.getComponent());
}
}
} catch (Exception e) {
e.printStackTrace();
}
break;
}
return false;
}
});
} catch (Exception e) {
Log.e(TAG, "hookHandler: " + e.getMessage());
e.printStackTrace();
}
到现在就完成了API28下的无注册Activity启动,分析时序图,还有一种hook的方式,就是校验前和校验后都会经过Instrumentation.java,也可以实现无注册Activity启动,就不写了。