根Activity的启动过程
根Activity 是应用程序第一个Activity,相比普通的Activity的启动过程,一般用根Activity 的启动过程来指代应用程序的启动过程,更具有参考意义。根Activity 的启动过程比较复杂,这里分为3个部分来讲:Launcher 请求AMS 过程、AMS 到ApplicaitonThread 的调用过程 以及 ActivityThread 启动Activity。
Launcher 请求AMS 过程
当我们点击桌面上某个应用的快捷图标时,就会通过Launcher 请求AMS 来启动该应用程序,过程的时序图如下:
点击桌面图标,会调用 Launcher 的startActivitySafely方法:
1 | // packages/apps/Launcher3/src/com/android/launcher3/Launcher.java |
因为是启动新的应用,所以注释1处将根Activity 在新的任务栈启动,应用启动会执行到注释2处的startActivity 方法,最终会在Activity 中调用 startActivityForResult 方法:
1 | // frameworks/base/core/java/and oid/app/Activity.java |
注释1的mParent 是Activity 类型,表示当前Activity 的父类(个人理解,这里应该说是当前Activity的前一个Activity),因此mParent == null 成立,最后由 Instrumentation 的execStartActivity方法来执行启动操作。 Instrumentation 主要用于监控应用程序和系统的交互。主要代码如下:
1 | // frameworks/base/core/java/android/app/Instrumentation.java |
由代码可知,首先通过 ActivityManager 获取 AMS 的代理对象,接着调用代理对象的 startActivity 方法。AMS 的代理对象是一个 IActivityManager(该类由AIDL在工具编译时自动生成的)对象,这个对象封装了 IBinder 类型的 AMS 的引用。通过一系列进程间通信,最终调用 AMS 的 startActivity 方法。
AMS 到 ApplicationThread 的调用过程
Launcher 请求进入AMS 后,接着是AMS 到 ApplicationThread 调用流程,时序图如下所示:
在AMS 的startActivity 会使用 startActivityAsUser 实现功能,并获取UserHandle.getCallingUserld() 即 调用者的UserId 作为参数传入。之后,startActivityAsUser 中会判断调用者进程是否被隔离,如果隔离则抛出SecurityException异常;接着,根据UserId 等参数检查调用者权限,如果没权限也抛出 SecurityException 异常。
AMS 中最终调用ActivityStater 的 startActivityLocked 方法,并且如果有 TaskRecord(代表启动的Activity所在的栈),则将其也作为参数传入;startActivityLocked 中会收集所有逻辑来决定如何将Intent 和Flags 转换为Activity(生成用于描述Activity 的 ActivityRecord 对象),并且将Activity 与Task 及 Stack 关联。
TaskRecord 用于描述一个 Activity 任务栈,Activity 任务栈其实是一个假想模型,并不真实存在。
最终调用到 ActivityStackSupervisor 的 startSpecificActivityLocked 方法时,会判断要启动的Activity 所在的应用程序进程是否已经运行,已经运行则调用 realStartActivityLocked 方法,并传入代表应用程序进程的 ProcessRecord。之后会调用 ApplicationThread 的 scheduleLaunchActivity 方法。当前代码逻辑运行在AMS所在进程(即SystemServer进程)中,通过 ApplicationThread 进程间通信,将程序执行到应用程序进程,ApplicationThread是AMS 进程与应用程序进程的通信桥梁,如下图所示:
ActivityThread 启动Activity 的过程
由前面的知识可知,目前的代码逻辑已经运行到应用程序进程中,先查看下ActivityThread 启动Activity 的时序图:
ApplicationThread 是 ActivityThread 的内部类,前面讲过应用程序进程创建完成后,会运行代表主线程的实例 ActivityThread 。接着上一节的内容查看 ApplicationThread.scheduleLaunchActivity 方法:
1 | // frameworks/base/core/java/android/app/ActivityThread.java |
在把启动Activity 必要的数据封装成 ActivityClientRecord 后,通过 sendMessage 方法将封装的数据以 H.LAUNCH_ACTIVITY 类型发送了出去,这里可以大胆地猜测sendMessage方法是通过handler的 sendMessage 执行的,果不其然,sendMessage 有多个重载方法,最终调用到如下代码:
1 | // frameworks/base/core/java/android/app/ActivityThread.java |
这里的mH指的是 ActivityThread 的内部类 H,前面讲过,这个H是集成Handler,是应用进程中主线程的消息管理类,因为ApplicationThread 是一个Binder,它的调用逻辑都运行在Binder 线程池中,所以这里需要使用H将代码的逻辑切换到主线程中。这样一来,我们只需要看 H 的handleMessage 方法即可知道具体的执行操作:
1 | private class H extends Handler { |
在注释1处将传过来的 msg 的成员变量 obj 还原成 ActivityClientRecord,注释2获得LoadApk 类型的对象。应用程序进程要启动Activity时需要将该Activity 所属的APK 加载进来,而LoadApk 就是用来描述已经加载的APK 文件的。注释3处调用 handleLaunchActivity 方法,代码如下:
1 | // frameworks/base/core/java/android/app/ActivityThread.java |
注释1处performLaunchActivity 方法启动了 Activity,注释2处将Activity的状态设置为 Resume ,如果该Activity 为null,则会通知AMS 停止启动Activity。我们来看看 performLaunchActivity 方法做了什么:
1 | // frameworks/base/core/java/android/app/ActivityThread.java |
注释1处获取 Activityinfo,用于存储AndroidManifest 以及 代码中设置的Activity 和 Receiver 节点的信息,比如Activity 的theme 和launchMode 。注释3中获取要启动的Activity 的 ComponentName 对象,该对象中保存了该Activity 的包名和类名。注释4中启动了Activity的上下文,注释5根据 Activity 的类名,用类加载器创建该 Activity 的实例。之后,注释6中创建了Application ,并且会调用 Application 的 onCreate方法。注释7中调用 Activity 的attach 方法初始化Activity,并且创建Window 对象(PhoneWindow)与Activity 自身关联。注释8中正式启动Activity,并调用Activity 的onCreate 方法。
至此,根Activity 就启动了,即应用程序启动了。
根Activity 启动过程中涉及的进程
根Activity 启动过程中涉及的4个进程之间关系如下:
首先Launcher 进程向 AMS 请求创建根 Activity ,AMS 会判断根Activity 所需要的应用程序进程是否存在,不存在就请求 Zygote 进程创建应用程序进程;之后,AMS 请求创建根Activity。上图中步骤 2 采用Socket 通信,步骤 1 和4采用Binder 通信。
读完书本,虽然各个点清晰,但是未能完整总结,以下 桌面点击图标 启动流程总结参考自他人博客
- 点击桌面图标,Launcher 采用Binder IPC 方式向system_server 发起startActivity 请求。
- system_server 进程接收到请求后,向 zygote 进程发送创建进程请求。
- zygote 进程fork 出新进程,即App进程。
- App 进程通过 Binder IPC 向 system_server 发起 attachApplication 请求。
- system_server收到请求做一系列准备后,通过 Binder IPC 向App 进程发送 scheduleLauncherActivity请求。
- App 进程的Binder 线程(ApplicationThread)收到请求后,通过Handler 向主线程发送 LAUNCH_ACTIVITY 消息。
- 主线程收到Message 后,通过反射机制创建目标Activity ,并回调Activity.onCreate 等方法。
- 至此,App启动,开始Activity 生命周期。
这个过程示意图如下所示:
Service 启动过程
Service 的启动过程和根Activity 的启动过程有部分相似知识点。Service 的启动过程可以分为两个部分讲解:分别是ContextImpl 到ActivityManageService 的调用过程,以及 ActivityThread 启动 Service。
ContextImpl 到 AMS 的调用过程
首先上时序图:
调用startService方法启动service,这个方法在 ContextWrapper 中实现