App 启动流程(一):从点击到请求 Zygote 笔记
一、 核心重点提炼 (Key Takeaways)
-
四大核心进程:App 启动至少涉及四个进程的协作:
Launcher进程:用户交互的起点,本质是一个 App,负责显示桌面图标并监听点击事件。SystemServer进程:Android 系统的核心服务中枢,ActivityTaskManagerService(ATMS, 在旧版中是 AMS) 在此运行,是启动流程的“总指挥”。Zygote进程:所有 App 进程的“孵化器”,负责fork()创建新的 App 进程。App进程:最终运行我们应用代码的目标进程。
-
两种通信机制:整个流程依赖两种不同的 IPC (进程间通信) 方式:
- Binder:用于
Launcher->SystemServer以及SystemServer<->App进程之间。这是 Android 中最主要、功能最丰富的 IPC 机制,适用于复杂的业务通信。 - Socket:仅用于
SystemServer->Zygote之间。这是一种更底层、更简单的通信方式,非常适合system_server向Zygote发送创建进程的简单指令。
- Binder:用于
-
启动的责任链:请求的传递是一个清晰的责任链条。
- 用户点击,
LauncherActivity响应。 Activity的startActivity()调用并非直接执行,而是通过Instrumentation类作为“中间人”。Instrumentation将请求通过 Binder 发送给SystemServer进程中的ActivityTaskManagerService(ATMS)。- ATMS 内部经过
ActivityStartController->ActivityStarter等一系列的检查和准备。 - 最终发现需要创建新进程时,通过
Process.start()调用,切换到 Socket 通信,向 Zygote 发出指令。
- 用户点击,
-
最终目标:第一阶段所有工作的最终目标,是向 Zygote 进程成功发送一条创建新进程的 Socket 消息,并明确告知新进程的入口点是
android.app.ActivityThread。
二、 详细流程图
sequenceDiagram
participant Launcher Process
participant System Server Process (ATMS)
participant Zygote Process
Note over Launcher Process: 用户点击桌面 App 图标
Launcher Process->>Launcher Process: onListItemClick() -> startActivity()
Launcher Process->>Launcher Process: startActivityForResult() -> mInstrumentation.execStartActivity()
Note over Launcher Process, System Server Process (ATMS): --- Binder IPC ---
Launcher Process->>System Server Process (ATMS): ActivityTaskManager.getService().startActivity()
System Server Process (ATMS)->>System Server Process (ATMS): startActivityAsUser()
System Server Process (ATMS)->>System Server Process (ATMS): ActivityStartController.obtainStarter().execute()
System Server Process (ATMS)->>System Server Process (ATMS): ActivityStarter.startActivityInner()
System Server Process (ATMS)->>System Server Process (ATMS): RootWindowContainer.resumeFocusedTasksTopActivities()
System Server Process (ATMS)->>System Server Process (ATMS): ActivityTaskSupervisor.startSpecificActivity()
Note over System Server Process (ATMS): 发现目标进程不存在, 准备创建...
System Server Process (ATMS)->>System Server Process (ATMS): Process.startProcessLocked()
System Server Process (ATMS)->>System Server Process (ATMS): Process.start()
Note over System Server Process (ATMS), Zygote Process: --- Socket Communication ---
System Server Process (ATMS)->>Zygote Process: ZygoteProcess.startViaZygote()<br/>(发送包含 "android.app.ActivityThread" 等参数的 Socket 消息)
Zygote Process->>Zygote Process: fork() a new App Process
Note left of Zygote Process: (后续流程进入第二篇)
三、 详细流程笔记梳理
阶段一:Launcher 进程 - 发起启动请求
- 起点:用户点击桌面图标。这个桌面是由
LauncherActivity构成的,图标点击事件被onListItemClick捕获。 - 意图创建:通过
intentForPosition()方法创建一个包含目标 App 包名和类名的Intent。 - 调用
startActivity:LauncherActivity调用startActivity(),这会层层深入到Activity#startActivityForResult()。- 关键点:
Activity本身不具备与系统服务直接通信的能力。它委托其成员变量mInstrumentation(一个Instrumentation实例) 来完成这个任务。
Instrumentation.execStartActivity():- 这是 App 框架层到系统服务层的桥梁。
- 它内部通过
ActivityTaskManager.getService()获取到ActivityTaskManagerService(ATMS) 的 Binder 代理对象。 - 调用 ATMS 的
startActivity()方法,请求正式通过 Binder IPC 从 Launcher 进程发送到 SystemServer 进程。
阶段二:SystemServer 进程 - 处理请求与决策
- ATMS 接收请求:
ActivityTaskManagerService的startActivity()方法被调用。 ActivityStarter的介入:- ATMS 不会立即处理,而是通过
ActivityStartController创建一个ActivityStarter对象来专门负责这次启动。 - 设计思想:将复杂的启动逻辑(如权限检查、任务栈管理、参数解析等)封装在
ActivityStarter类中,使 ATMS 的职责更清晰。
- ATMS 不会立即处理,而是通过
- 执行启动:
ActivityStarter.execute()被调用,经过一系列内部方法如startActivityUnchecked()->startActivityInner()。 - 窗口与任务栈处理:
- 启动流程与窗口管理(WMS)紧密相关。代码会深入到
RootWindowContainer(窗口容器的根)、Task(任务栈) 等类。 resumeFocusedTasksTopActivities()方法被调用,目的是将要启动的Activity所在的任务栈恢复到前台并获取焦点。
- 启动流程与窗口管理(WMS)紧密相关。代码会深入到
- 检查进程是否存在:在
ActivityTaskSupervisor.startSpecificActivity()中,系统会检查要启动的ActivityRecord(r)所对应的ProcessRecord(proc)是否存在。如果proc为null或已死亡,就需要创建新进程。 - 创建进程的决策:通过
mService.startProcessAsync()->startProcessLocked(),系统最终决定需要启动一个新进程。
阶段三:SystemServer 到 Zygote - 发送创建指令
- 准备参数:在
startProcessLocked系列方法中,系统会准备好创建新进程所需的所有参数,其中最关键的是 入口类entryPoint = "android.app.ActivityThread"。 - 获取 Zygote 通信句柄:在
Process.start()方法中,系统判断这是一个普通应用启动,会通过appZygote.getProcess().start()来执行。 - 切换到 Socket 通信:
ZygoteProcess.startViaZygote()是核心方法。- 它将所有参数(包括入口类、uid、gid、seInfo 等)格式化成一个字符串列表。
- 通过
openZygoteSocketIfNeeded()方法,与 Zygote 进程建立一个 Unix Domain Socket 连接。
- 发送指令并等待结果:
zygoteSendArgsAndGetResult()将参数列表拼接成一个字符串,通过 Socket 的输出流写入。- 写入后,它会阻塞并等待 Zygote 从输入流返回结果,结果中包含了新进程的
pid。 system_server进程拿到pid后,这个阶段的任务就完成了。后续将等待 App 进程反向连接(attach)。
四、 核心面试问题与答案
问题 1:请简述一下从点击桌面图标到 App 进程开始创建的完整流程。
答:
- Launcher 进程:用户点击图标,LauncherApp 的
Activity响应点击事件,通过startActivity()调用到Instrumentation类。- Binder IPC 到 SystemServer:
Instrumentation类通过 Binder IPC,向SystemServer进程中的ActivityTaskManagerService(ATMS) 发起startActivity请求。- SystemServer 处理:ATMS 接收请求后,交由
ActivityStarter进行处理,包括权限检查、任务栈管理等。在ActivityTaskSupervisor中,系统发现目标Activity所在的进程不存在。- Socket IPC 到 Zygote:
SystemServer决定创建新进程,于是通过Process.start()方法,切换到 Socket 通信,向Zygote进程发起fork进程的请求,并传递了新进程的入口类android.app.ActivityThread等参数。- Zygote 创建进程:Zygote 进程接收到 Socket 消息后,执行
fork()操作,创建出新的 App 进程。
问题 2:为什么 Launcher 和 SystemServer 之间用 Binder 通信,而 SystemServer 和 Zygote 之间用 Socket?
答: 这是由它们各自的职责和技术限制决定的。
- Binder:功能强大但复杂,支持面向对象的接口调用,非常适合
Launcher和SystemServer之间复杂的业务通信。但 Binder 的实现是多线程的,而 Zygote 的核心是fork()。如果 Zygote 使用 Binder,fork()出的子进程无法正确继承父进程的多线程状态(如锁),会导致死锁等严重问题。- Socket:是一种非常基础、简单的 Linux IPC 机制。
SystemServer对Zygote的请求非常单一,就是“给我创建一个进程”。使用 Socket 可以让 Zygote 的实现非常简洁、稳定、可靠,并且完美避开了fork和多线程的冲突问题。
问题 3:在 App 启动流程中,Instrumentation 类扮演了什么角色?
答:
Instrumentation类扮演着 “桥梁” 和 “监控者” 的角色。
- 桥梁:它是应用程序代码和系统服务(ATMS)之间的桥梁。
Activity的startActivity等请求都是委托给Instrumentation实例,由它来真正地通过 Binder IPC 与系统服务进行通信。- 监控者:它的设计初衷是为了监控应用与系统的交互,这也是为什么所有
Activity的生命周期回调(如onCreate,onResume)实际上都是由Instrumentation来间接调用的。这使得 Android 的测试框架可以通过替换Instrumentation实现对应用生命周期的完全控制和模拟。
问题 4:当 ATMS 收到 startActivity 请求后,它会立即开始创建进程吗?中间经过了哪些重要环节?
答: 不会立即创建。中间会经过一系列复杂的检查和准备工作,主要由
ActivityStarter类负责,包括:
- 权限检查:检查调用者是否有权限启动目标
Activity。- Intent 解析:解析 Intent,找到最匹配的
ActivityInfo。- 任务栈(Task)处理:决定这个
Activity应该放在哪个任务栈中,是新建任务栈还是复用现有任务栈,并根据launchMode和Intent Flags对栈内Activity进行相应处理(如CLEAR_TOP等)。- 进程检查:在确定了所有信息后,才会检查目标
Activity所在的进程是否存在。只有在进程不存在时,才会触发后续的创建流程。