本届课程主要讲解了 startActivity 启动过程源码分析,引用的源码版本是 android-28。
假设 ActivityA 跳转到另一个App中的 ActivityB,过程如下图所示:
整个 startActivity 的流程分为 3 大部分,也涉及 3 个进程之间的交互:
- ActivityA --> ActivityManagerService(简称 AMS)
- ActivityManagerService --> ApplicationThread
- ApplicationThread --> Activity
ActivityA --> ActivityManagerService 阶段
这一过程并不复杂,用一张图表示具体过程如下:
Activity 的 startActivity
这里最终调用了 startActivityForResult 方法,传入的 -1 表示不需要获取 startActivity 的结果。
Activity 的 startActivityForResult
startActivityForResult 也很简单,调用 Instrumentation.execStartActivity 方法。剩下的交给 Instrumentation 类去处理。
解释说明:
- Instrumentation 类主要用来监控应用程序与系统交互。
- 蓝框中的 mMainThread 是 ActivityThread 类型,ActivityThread 可以理解为一个进程,在这就是 A 所在的进程。
- 通过 mMainThread 获取一个 ApplicationThread 的引用,这个引用就是用来实现进程间通信的,具体来说就是 AMS 所在系统进程通知应用程序进程进行的一系列操作。
Instrumentation 的 execStartActivity
这里获取了AMS,然后调用了startActivity方法。实际上这里就是通过 AIDL 来调用 AMS 的 startActivity 方法,至此,startActivity 的工作重心成功地从进程 A 转移到了系统进程 AMS 中。
ActivityManagerService --> ApplicationThread
接下来就看下在 AMS 中是如何一步一步执行到 B 进程的。
注:刚才在看 Instrumentation 的时候,讲过一个 ApplicationThread 类,这个类是负责进程间通信的,这里 AMS 最终其实就是调用了 B 进程中的一个 ApplicationThread 引用,从而间接地通知 B 进程进行相应操作。
相比于 startActivity-->AMS,AMS-->ApplicationThread 流程看起来复杂好多了,实际上这里面就干了 2 件事:
- 综合处理 launchMode 和 Intent 中的 Flag 标志位,并根据处理结果生成一个目标 Activity B 的对象(ActivityRecord)。
- 判断是否需要为目标 Activity B 创建一个新的进程(ProcessRecord)、新的任务栈(TaskRecord)。
AMS 的 startActivity
经过多个方法的调用,最终通过 obtainStarter 方法获取了 ActivityStarter 类型的对象,然后调用其 execute 方法。在 execute 方法中,会再次调用其内部的 startActivityMayWait 方法。
ActivityStarter 的 startActivityMayWait
ActivityStarter 这个类看名字就知道它专门负责一个 Activity 的启动操作。它的主要作用包括解析 Intent、创建 ActivityRecord、如果有可能还要创建 TaskRecord。startActivityMayWait 方法的部分实现如下:
这里的mSupervisor主要是负责 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 内部维护的数据结构,可以用一张图来描述它们之间的关系。
如:这次课程是 ActivityA 跳转到另一个App中的 ActivityB,所以如果ActivityB所在的App没有启动。这里会先在AMS中的 ActivityStackSupervisor 中创建 ActivityStack,并且通过创建的 ActivityStack 来管理 TaskRecord。Task会入栈,然后Activity入栈,不同启动模式所放入的栈的方式也是不一样的。如果是 singleTask 或 singleInstance 启动模式,则会另外创建TaskRecord,并添加到 ActivityStack 进行管理。
ActivityStack 的 resumeFocusedStackTopActivityLocked
经过一系列调用,最终代码又回到了 ActivityStackSupervisor 中的 startSpecificActivityLocked 方法。
ActivityStackSupervisor 的 startSpecificActivityLocked
解释说明:
- 图中 1 处根据进程名称和 Application 的 uid 来判断目标进程是否已经创建,如果没有则代表进程未创建。
- 图中 2 处调用 AMS 创建 Activity 所在进程。创建进程也就进而创建了ActivityThread对象,AMS 最终也就是调用了 B 进程中的这个 ApplicationThread 引用。
不管是目标进程已经存在还是新建目标进程,最终都会调用图中红线标记的 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 的生命周期方法。而这里的app.thread也是在startSpecificActivityLocked中创建进程时所创建的。
ApplicationThread -> Activity
在 ClientLifecycleManager 中会调用 ClientTransaction的schedule() 方法
而 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 方法
在创建 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 已经被成功创建并执行生命周期方法。