【追根究底】Android的startActivity源码到底咋写的?

it2024-10-12  35

最近出于提升专业技能水平和深入了解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

同上。

最新回复(0)