最近出于提升专业技能水平和深入了解Android系统的目的,进行了插件化相关的学习并简单写了一些demo。但是在写动态hook系统SDK实现启动插件化activity的过程当中遇到了一些问题,特此记录,与大家一起分享我的学习经验。
首先先放一张图,图片来自:https://juejin.im/post/6844903965679681549
类似的图片只要使用搜索引擎检索startactivity源码分析,很容易找到许多类似的图片。但是很多图片往往都在细节上有所不同,这不禁引发了博主的好奇心:为啥这么多大佬画的图还能出现各种版本呢?
经过https://cs.android.com/检索源码发现,主要是Android版本之间的差异。
很多大佬写文章或者画图的时候其实都是出于记录,没有详细地说明查阅的源码版本,而Android的版本更新迭代速度非常之快,造成了各种startactivity的流程之间有所差异,以下记录若干版本的startactivity的流程供参考。
此处引用https://blog.csdn.net/qianxiangsen/article/details/81352563的图片:
不难发现其实执行activity的startactivity方法在我查阅的版本当中都会走向ContextImpl的startactivity方法,而该方法都会调用mInstrumentation的execStartActivity方法,关于Instrumentation是如何创建的此处不展开,请自行查阅。
execStartActivity方法开始,不同的Android版本出现了许多不同的实现,特此记录若干博主选取的经典版本。
版本1:android-5.1.1_r38
该版本Instrumentation总共包含三个参数列表不同的execStartActivity方法,最终都指向ActivityManagerNative,截取代码示例如下:
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
if (am.match(who, null, intent)) {
am.mHits++;
if (am.isBlocking()) {
return requestCode >= 0 ? am.getResult() : null;
}
break;
}
}
}
}
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess();
int result = ActivityManagerNative.getDefault()
.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) {
}
return null;
}
可以明显看到ActivityManagerNative是真正的执行者,查阅ActivityManagerNative的方法得到不同参数列表的方法最后都走了mRemote的方法执行,选取代码示例如下:
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(callingPackage);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(startFlags);
if (profilerInfo != null) {
data.writeInt(1);
profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
if (options != null) {
data.writeInt(1);
options.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
查阅mRemote发现使用了Binder进行通信,通信对象为AMS。
版本2:android-6.0.1_r82
同上。
版本3:android-7.1.2_r36
同上。
版本4:android-8.1.0-r62
出现差异,instrumentaion和AMS的通信方法修改为:
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
可以看到不再直接使用Binder通信,而是通过标准化的service来进行对AMS的获取。
版本5:android-9.0.0_r34
同上。
版本6:android-10.0.0_r30
int result = ActivityTaskManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
出现差异,可以看到ActivityManager被ActivityTaskManager取代。
版本7:android-11.0.0_r3
同上。