Activity启动流程分析
我们来看一下 startActivity 过程的具体流程。在手机桌面应用中点击某一个 icon 之后,实际上最终就是通过 startActivity 去打开某一个 Activity 页面。我们知道 Android 中的一个 App 就相当于一个进程,所以 startActivity 操作中还需要判断,目标 Activity 的进程是否已经创建,如果没有,则在显示 Activity 之前还需要将进程 Process 提前创建出来。假设是从 ActivityA 跳转到另一个 App 中的 ActivityB,过程如下图所示:
整个 startActivity 的流程分为 3 大部分,也涉及 3 个进程之间的交互:
- ActivityA --> ActivityManagerService(简称 AMS)
- ActivityManagerService --> ApplicationThread
- ApplicationThread --> Activity
ActivityA --> ActivityManagerService 阶段
这一过程并不复杂,用一张图表示具体过程如下:
接下来看下源码中做了哪些操作。
Activity 的 startActivity方法
@Override public void startActivity(Intent intent, @Nullable Bundle options) { if (options != null) { startActivityForResult(intent, -1, options); } else { // Note we want to go through this call for compatibility with // applications that may have overridden the method. startActivityForResult(intent, -1); } }
最终调用了 startActivityForResult 方法,传入的 -1 表示不需要获取 startActivity 的结果。
Activity 的 startActivityForResult
具体代码如下所示:
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); } } }
startActivityForResult 也很简单,调用 Instrumentation.execStartActivity 方法。剩下的交给 Instrumentation 类去处理。
解释说明:
- Instrumentation 类主要用来监控应用程序与系统交互。
- 代码中的mMainThread 是 ActivityThread 类型,ActivityThread 可以理解为一个进程,在这就是 A 所在的进程。
- 通过 mMainThread 获取一个 ApplicationThread 的引用,这个引用就是用来实现进程间通信的,具体来说就是 AMS 所在系统进程通知应用程序进程进行的一系列操作。
Instrumentation 的 execStartActivity
方法如下:
try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(who); int result = ActivityTaskManager.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;
通过ActivityTaskManager.getService()获取获取ATMS的服务代理,跨进程调用ATMS的startActivity方法,下一步就ATMS内部startActivityAsUser()方法处理。
int startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) { enforceNotIsolatedCaller("startActivityAsUser"); userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser, Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser"); // TODO: Switch to user app stacks here. return getActivityStartController().obtainStarter(intent, "startActivityAsUser") .setCaller(caller) .setCallingPackage(callingPackage) .setResolvedType(resolvedType) .setResultTo(resultTo) .setResultWho(resultWho) .setRequestCode(requestCode) .setStartFlags(startFlags) .setProfilerInfo(profilerInfo) .setActivityOptions(bOptions) .setMayWait(userId) .execute(); }
经过多个方法的调用,最终通过 obtainStarter 方法获取了 ActivityStarter 类型的对象,然后调用其 execute 方法。在 execute 方法中,会再次调用其内部的 startActivityMayWait 方法。
ActivityStarter 的 startActivityMayWait
ActivityStarter 这个类看名字就知道它专门负责一个 Activity 的启动操作。它的主要作用包括解析 Intent、创建 ActivityRecord、如果有可能还要创建 TaskRecord。startActivityMayWait 方法的部分实现如下:
private int startActivityMayWait(IApplicationThread caller, int callingUid, String callingPackage, int requestRealCallingPid, int requestRealCallingUid, Intent intent, String resolvedType, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, WaitResult outResult, Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity, int userId, TaskRecord inTask, String reason, boolean allowPendingRemoteAnimationRegistryLookup, PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); } ...
ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
0 /* matchFlags */,
computeResolveFilterUid(
callingUid, realCallingUid, mRequest.filterCallingUid));
if (rInfo == null) {
UserInfo userInfo = mSupervisor.getUserInfo(userId);
if (userInfo != null && userInfo.isManagedProfile()) {
// Special case for managed profiles, if attempting to launch non-cryto aware
// app in a locked managed profile from an unlocked parent allow it to resolve
// as user will be sent via confirm credentials to unlock the profile.
UserManager userManager = UserManager.get(mService.mContext);
boolean profileLockedAndParentUnlockingOrUnlocked = false;
long token = Binder.clearCallingIdentity();
try {
UserInfo parent = userManager.getProfileParent(userId);
profileLockedAndParentUnlockingOrUnlocked = (parent != null)
&& userManager.isUserUnlockingOrUnlocked(parent.id)
&& !userManager.isUserUnlockingOrUnlocked(userId);
} finally {
Binder.restoreCallingIdentity(token);
}
if (profileLockedAndParentUnlockingOrUnlocked) {
rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
computeResolveFilterUid(
callingUid, realCallingUid, mRequest.filterCallingUid));
}
}
}
// Collect information about the target of the Intent.
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
...
从上图可以看出获取目标 Activity 信息的操作由 mSupervisor 来实现,它是 ActivityStackSupervisor 类型,从名字也能猜出它主要是负责 Activity 所处栈的管理类。
resolveIntent 中实际上是调用系统 PackageManagerService 来获取最佳 Activity。有时候我们通过隐式 Intent 启动 Activity 时,系统中可能存在多个 Activity 可以处理 Intent,此时会弹出一个选择框让用户选择具体需要打开哪一个 Activity 界面,就是此处的逻辑处理结果。
在 startActivityMayWait 方法中调用了一个重载的 startActivity 方法,而最终会调用的 ActivityStarter 中的 startActivityUnchecked 方法来获取启动 Activity 的结果。
ActivityStarter 的 startActivityUnchecked
解释说明:
- 图中 1 处计算启动 Activity 的 Flag 值。
- 注释 2 处处理 Task 和 Activity 的进栈操作。
- 注释 3 处启动栈中顶部的 Activity。
computeLaunchingTaskFlags 方法具体如下:
这个方法的主要作用是计算启动 Activity 的 Flag,不同的 Flag 决定了启动 Activity 最终会被放置到哪一个 Task 集合中。
- 图中 1 处 mInTask 是 TaskRecord 类型,此处为 null,代表 Activity 要加入的栈不存在,因此需要判断是否需要新建 Task。
- 图中 2 处的 mSourceRecord 的类型 ActivityRecord 类型,它是用来描述“初始 Activity”,什么是“初始 Activity”呢?比如 ActivityA 启动了ActivityB,ActivityA 就是初始 Activity。当我们使用 Context 或者 Application 启动 Activity 时,此 SourceRecord 为 null。
- 图中 3 处表示初始 Activity 如果是在 SingleInstance 栈中的 Activity,这种需要添加 NEW_TASK 的标识。因为 SingleInstance 栈只能允许保存一个 Activity。
- 图中 4 处表示如果 Launch Mode 设置了 singleTask 或 singleInstance,则也要创建一个新栈。
ActivityStackSupervisor 的 startActivityLocked
方法中会调用 insertTaskAtTop 方法尝试将 Task 和 Activity 入栈。如果 Activity 是以 newTask 的模式启动或者 TASK 堆栈中不存在该 Task id,则 Task 会重新入栈,并且放在栈的顶部。需要注意的是:Task 先入栈,之后才是 Activity 入栈,它们是包含关系。
这里一下子涌出了好几个概念 Stack、Task、Activity,其实它们都是在 AMS 内部维护的数据结构,可以用一张图来描述它们之间的关系。
ActivityStack 的 resumeFocusedStackTopActivityLocked
经过一系列调用,最终代码又回到了 ActivityStackSupervisor 中的 startSpecificActivityLocked 方法。
ActivityStackSupervisor 的 startSpecificActivityLocked
解释说明:
- 图中 1 处根据进程名称和 Application 的 uid 来判断目标进程是否已经创建,如果没有则代表进程未创建。
- 图中 2 处调用 AMS 创建 Activity 所在进程。
不管是目标进程已经存在还是新建目标进程,最终都会调用图中红线标记的 realStartActivityLocked 方法来执行启动 Activity 的操作。
ActivityStackSupervisor 的 realStartActivityLocked
这个方法在 android-27 和 android-28 版本的区别很大,从 android-28 开始 Activity 的启动交给了事务(Transaction)来完成。
- 图中 1 处创建 Activity 启动事务,并传入 app.thread 参数,它是 ApplicationThread 类型。在上文 startActivity 阶段已经提过 ApplicationThread 是为了实现进程间通信的,是 ActivityThread 的一个内部类。
- 图中 2 处执行 Activity 启动事务。
Activity 启动事务的执行是由 ClientLifecycleManager 来完成的,具体代码如下:
可以看出实际上是调用了启动事务 ClientTransaction 的 schedule 方法,而这个 transaction 实际上是在创建 ClientTransaction 时传入的 app.thread 对象,也就是 ApplicationThread。如下所示:
解释说明:
- 这里传入的 app.thread 会赋值给 ClientTransaction 的成员变量 mClient,ClientTransaction 会调用 mClient.scheduleTransaction(this) 来执行事务。
- 这个 app.thread 是 ActivityThread 的内部类 ApplicationThread,所以事务最终是调用 app.thread 的 scheduleTransaction 执行。
到这为止 startActivity 操作就成功地从 AMS 转移到了另一个进程 B 中的 **ApplicationThread **中,剩下的就是 AMS 通过进程间通信机制通知 ApplicationThread 执行 ActivityB 的生命周期方法。
ApplicationThread -> Activity
刚才我们已近分析了 AMS 将启动 Activity 的任务作为一个事务 ClientTransaction 去完成,在 ClientLifecycleManager 中会调用 ClientTransaction的schedule() 方法,如下:
public void schedule() throws RemoteException { mClient.scheduleTransaction(this); }
而 mClient 是一个 IApplicationThread 接口类型,具体实现是 ActivityThread 的内部类 ApplicationThread。因此后续执行 Activity 生命周期的过程都是由 ApplicationThread 指导完成的,scheduleTransaction 方法如下:
可以看出,这里还是调用了ActivityThread 的 scheduleTransaction 方法。但是这个方法实际上是在 ActivityThread 的父类 ClientTransactionHandler 中实现,具体如下:
调用 sendMessage 方法,向 Handler 中发送了一个 EXECUTE_TRANSACTION 的消息,并且 Message 中的 obj 就是启动 Activity 的事务对象。而这个 Handler 的具体实现是 ActivityThread 中的 mH 对象。具体如下:
最终调用了事务的 execute 方法,execute 方法如下:
在 executeCallback 方法中,会遍历事务中的 callback 并执行 execute 方法,这些 callbacks 是何时被添加的呢?
还记得 ClientTransaction 是如何创建被创建的吗?重新再看一遍:
在创建 ClientTransaction 时,通过 addCallback 方法传入了 Callback 参数,从图中可以看出其实是一个 LauncherActivityItem 类型的对象。
LaunchActivityItem 的 execute()
终于到了跟 Activity 生命周期相关的方法了,图中 client 是 ClientTransationHandler 类型,实际实现类就是 ActivityThread。因此最终方法又回到了 ActivityThread。
ActivityThread 的 handleLaunchActivity
这是一个比较重要的方法,Activity 的生命周期方法就是在这个方法中有序执行,具体如下:
解释说明:
- 图中 1 处初始化 Activity 的 WindowManager,每一个 Activity 都会对应一个“窗口”。
- 图中 2 处调用 performLaunchActivity 创建并显示 Activity。
- 图中 3 处通过反射创建目标 Activity 对象。
- 图中 4 处调用 attach 方法建立 Activity 与 Context 之间的联系,创建 PhoneWindow 对象,并与 Activity 进行关联操作。
- 图中 5 处通过 Instrumentation 最终调用 Activity 的 onCreate 方法。
至此,目标 Activity 已经被成功创建并执行生命周期方法。
总结
详细查看了 Activity 的启动在源码中的实现流程(不同版本sdk源码还是挺大变化的,自己可以去查看)。这一过程主要涉及 3 个进程间的通信过程:
1》首先进程 A 通过 Binder 调用 AMS 的 startActivity 方法。
2》然后 AMS 通过一系列的计算构造目标 Intent,然后在 ActivityStack 与 ActivityStackSupervisor 中处理 Task 和 Activity 的入栈操作。
3》最后 AMS 通过 Binder 机制,调用目标进程中 ApplicationThread 的方法来创建并执行 Activity 生命周期方法,实际上 ApplicationThread 是 ActivityThread 的一个内部类,它的执行最终都调用到了 ActivityThread 中的相应方法。
————来自拉勾教育笔记