App 启动流程:从 Launcher 点击到 Activity 创建(跨进程通信与 AMS 全链路分析)
本文梳理一次完整冷启动所经历的三个阶段: ① Launcher 发起启动请求(Binder 跨进程)→ ② SystemServer 中 AMS 启动 App 进程(socket + Zygote fork)→ ③ Activity 创建三步(Binder 回调 → H 切主线程 → performLaunchActivity)。
一、核心流程速览
一次冷启动涉及 4 个进程:
| 进程 | 角色 | 关键类 |
|---|---|---|
| Launcher(桌面) | 发起方:响应图标点击 | Launcher、Instrumentation、ActivityTaskManager |
| SystemServer | 调度中枢:解析 Intent、管理进程与 Activity 栈 | ActivityTaskManagerService(ATMS)、ActivityManagerService(AMS)、ZygoteProcess |
| Zygote | 进程孵化器:fork 出新进程 | ZygoteInit、RuntimeInit |
| App 进程 | 执行方:初始化主线程并创建 Activity | ActivityThread、ApplicationThread、H、Instrumentation |
一个关键认知:启动的"指挥权"始终在 SystemServer(AMS/ATMS),App 进程只是被动响应------这也是为什么 Launcher 和 App 都只是客户端,而 AMS 是系统服务的 Binder 服务端。
二、第一阶段:Launcher 发起启动请求(Binder 跨进程通信)
2.1 源码调用链
scss
Launcher.startActivitySafely() // 桌面进程, 响应图标点击
└─ Activity.startActivity()
└─ Activity.startActivityForResult()
└─ Instrumentation.execStartActivity()
└─ ActivityTaskManager.getService().startActivity(...)
└─ [跨进程] ATMS.startActivity() // SystemServer 进程
2.2 关键源码
java
// Instrumentation.java
public ActivityResult execStartActivity(Context who, IBinder contextThread, ...) {
...
int result = ActivityTaskManager.getService()
.startActivity(whoThread, who.getBasePackageName(), who.getAttributionTag(),
intent, intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target, requestCode, 0, null, options);
checkStartActivityResult(result, intent); // 异常如 ActivityNotFound 在此抛出
...
}
// ActivityTaskManager.java ------ 获取 ATMS 的 Binder 代理
public static IActivityTaskManager getService() {
return IActivityTaskManagerSingleton.get();
}
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
new Singleton<IActivityTaskManager>() {
@Override
protected IActivityTaskManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
return IActivityTaskManager.Stub.asInterface(b);
}
};
要点:
ServiceManager.getService()从 ServiceManager 中拿到"activity_task"服务的 Binder 句柄,Stub.asInterface()将其包装成本地可调用的代理对象IActivityTaskManager------真正的执行体在 SystemServer 进程的ActivityTaskManagerService中。- 每一次
startActivity都是一次 Binder IPC(一次跨进程调用 + 一次内核拷贝),这也是 Launcher 进程不直接创建 Activity 的原因:Activity 的栈管理、进程调度全部由系统服务统一负责。 - Android 10 起,原 AMS 中负责 Activity 启动的职责被拆分到 ATMS(ActivityTaskManagerService),AMS 保留进程/广播/Service 等职责。
三、第二阶段:SystemServer 中 AMS 启动 App 进程
3.1 ATMS 处理启动请求
scss
ATMS.startActivity()
└─ ActivityStarter.execute() → startActivityUnchecked()
├─ 解析 Intent / 目标 Activity 信息(ActivityInfo)
├─ 检查目标进程 ProcessRecord 是否已存在
│ ├─ 已存在(热启动/温启动) → 直接走调度阶段(见第四阶段)
│ └─ 不存在(冷启动) → startProcessLocked() 创建进程
└─ 栈管理: 复用/新建 Task(ActivityRecord 挂到栈上, 状态 LAUNCHING)
3.2 fork 进程:为什么用 socket 而不是 Binder
java
// ActivityManagerService.startProcessLocked()
// └─ ProcessList.startProcessLocked()
// └─ ZygoteProcess.start() // SystemServer 内
// └─ 通过 LocalSocket 连接 Zygote 进程, 发送参数:
// (uid, gid, seInfo, entryPoint = "android.app.ActivityThread", ...)
java
// ZygoteInit.java ------ Zygote 侧
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
...
Runnable caller = zygoteServer.runSelectLoop(); // 阻塞等待 socket 消息
if (caller != null) caller.run();
}
// 收到 fork 请求后:
int pid = Zygote.forkAndSpecialize(...); // native fork
if (pid == 0) {
// 子进程: 调用 RuntimeInit → findStaticMain
// → 反射执行 android.app.ActivityThread.main()
}
为什么用 socket 通信?
- fork 一个"干净"的单线程进程最安全。Binder 通信依赖多线程线程池,若在 Zygote 里初始化 Binder 线程池再 fork,线程状态、锁状态会被复制到子进程,极易死锁;
- socket 简单可靠,且 Zygote 只需要一个"传参数 + fork"的入口,不需要双向高频 IPC。
3.3 App 进程初始化:ActivityThread.main() 与反向注册
java
// ActivityThread.java ------ 新进程的入口
public static void main(String[] args) {
...
Looper.prepareMainLooper(); // ① 准备主线程消息循环
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq); // ② 向 AMS 注册
...
Looper.loop(); // ③ 进入消息循环, 等待 AMS 回调
}
private void attach(boolean system, long startSeq) {
...
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq); // ★ 反向注册
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...
}
反向注册是启动链路中最容易忽略的一环:
mAppThread是ApplicationThread(ActivityThread的内部类),它是 App 进程侧的 Binder 服务端 (IApplicationThread.Stub);- 此前一直是 App 单向调用 AMS(Binder 客户端 → 服务端),AMS 无法"主动"通知 App;
attachApplication把 App 的 Binder 句柄交给 AMS,从此 AMS 持有IApplicationThread,可以反向回调 App 进程 ------第四阶段的scheduleLaunchActivity正是走这条反向通道。
AMS 收到 attachApplication 后,在 attachApplicationLocked() 中确认进程可用,然后继续完成启动调度(realStartActivityLocked)。
四、第三阶段:Activity 创建三步(本文核心)
参考:《Android 进阶解密》与掘金专栏 Android App 启动流程
AMS 决定启动 Activity 后,把参数跨进程发回 App 进程。App 进程侧从收到 Binder 回调到 Activity 真正创建,共分三步:
4.1 第 1 步:AMS 通过 ApplicationThread.scheduleLaunchActivity 发起启动
java
// ActivityThread$ApplicationThread.java ------ App 进程侧的 Binder 服务端
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, ...) {
...
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.activityInfo = info;
...
sendMessage(H.LAUNCH_ACTIVITY, r);
}
这一步的关键陷阱 :ApplicationThread 是 Binder 服务端,AMS 的跨进程调用是在 Binder 线程池的线程 中执行的,不是主线程 。因此这里不能直接创建 Activity,只能把参数封装成 ActivityClientRecord(App 进程侧对 Activity 的记录,与 AMS 侧的 ActivityRecord 一一对应),通过 sendMessage 转交主线程。
4.2 第 2 步:H 切回主线程,处理 LAUNCH_ACTIVITY 消息
java
// ActivityThread$H.java ------ 主线程 Handler
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
// 获得 LoadedApk: 描述已加载的 APK 文件(代码、资源、ClassLoader)
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
} break;
...
}
}
H 是 ActivityThread 的内部类,继承自 Handler,绑定主线程 Looper (main() 中的 prepareMainLooper())。它像一位"大堂经理":所有需要主线程执行的操作,先由各线程(Binder 线程池、子线程)发消息入队,再由 H 统一在主线程分发执行。
4.3 第 3 步:handleLaunchActivity → performLaunchActivity 真正创建
java
// ActivityThread.java
public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions,
Intent customIntent) {
...
// 1. 初始化 WindowManagerGlobal(全局唯一的 Window 管理器)
WindowManagerGlobal.initialize();
// 2. 真正启动 Activity
final Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
...
handleResumeActivity(r.token, ...); // → onStart / onResume
} else {
// 创建失败, 反向通知 AMS 结束启动
ActivityManager.getService().finishActivity(r.token, Activity.RESULT_CANCELED, null, ...);
}
return a;
}
performLaunchActivity 内部是核心,按序完成 5 件事:
java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo; // ① 获取 ActivityInfo
...
ContextImpl appContext = createBaseContextForActivity(r); // ② 创建上下文 ContextImpl
java.lang.ClassLoader cl = appContext.getClassLoader();
Activity activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent); // ③ 反射创建 Activity 实例
...
Application app = r.packageInfo.makeApplication(false, mInstrumentation); // ④ 创建 Application
...
activity.attach(appContext, this, getInstrumentation(), r.token, ...); // ⑤ 绑定
...
mInstrumentation.callActivityOnCreate(activity, r.state); // → onCreate()
return activity;
}
| 序号 | 动作 | 说明 |
|---|---|---|
| ① | 获取 ActivityInfo |
从 ActivityClientRecord 中取出解析好的组件信息 |
| ② | createBaseContextForActivity |
创建 ContextImpl------Activity 所有上下文能力的载体 |
| ③ | mInstrumentation.newActivity |
通过类加载器反射创建 Activity 实例 (默认调 cl.loadClass(className) + 无参构造) |
| ④ | r.packageInfo.makeApplication |
创建 Application(若进程首个 Activity,还走 H.BIND_APPLICATION 回调 Application.onCreate)------先于 Activity.onCreate 执行 |
| ⑤ | activity.attach + callActivityOnCreate |
绑定 Window/Token/资源管理器,然后回调 onCreate() |
至此 Activity 创建完成,handleResumeActivity 继续完成 onStart/onResume 与首帧绘制,用户看到界面。
4.4 Android 10+ 的新链路:ClientTransaction
Android 10 起,scheduleLaunchActivity 的直连方式被 ClientTransaction 事务机制取代(底层仍是 Binder 回调 + H 切主线程,三步骨架不变):
css
AMS: ClientLifecycleManager.scheduleTransaction(transaction)
transaction.addCallback(LaunchActivityItem) // 也可能附加 ResumeActivityItem
└─ IApplicationThread.scheduleTransaction(transaction) // 反向 Binder 调用
App: ApplicationThread.scheduleTransaction()
└─ TransactionExecutor.execute()
└─ LaunchActivityItem.execute(client, ...)
└─ client.handleLaunchActivity(...) // 与旧链路汇合
好处:把"启动 Activity""Resume Activity"等动作抽象为可组合的事务项(TransactionItem),AMS 可以一次事务下发多个动作,减少跨进程往返。
五、面试考点速查
Q1:为什么 Activity 的创建要经过这么多跨进程调用?App 进程不能自己 new 吗?
不能。Activity 的栈管理、生命周期调度、进程管理都是系统级能力 ,必须由 SystemServer 统一裁决(多窗口、分屏、任务栈回收都依赖它)。App 进程只持有自己这一端的"视图"(ActivityClientRecord),权威数据在 AMS 侧(ActivityRecord)。
Q2:为什么 Zygote 用 socket 而不用 Binder?
fork 前 Zygote 是单线程的,Binder 线程池一旦初始化再 fork,子进程会带着复制来的锁/线程状态,极易死锁。socket 简单可靠,且 fork 请求只是"传参 + 一次性返回",不需要 Binder 那样高频的双向 IPC。
Q3:为什么 scheduleLaunchActivity 之后必须经过 H 切回主线程?
ApplicationThread 的 Binder 方法跑在 Binder 线程池线程 ,而创建 Activity、操作 Window 都必须在主线程 。sendMessage(H.LAUNCH_ACTIVITY) 本质是把工作从 Binder 线程投递到主线程消息队列。
Q4:Application 和 Activity 谁先创建?
Application 先创建。performLaunchActivity 内部先调 makeApplication(首个 Activity 时创建 Application 并回调 onCreate),之后才 activity.attach + callActivityOnCreate。
Q5:冷启动 / 温启动 / 热启动怎么区分?
| 类型 | 进程 | Activity | 开销 |
|---|---|---|---|
| 冷启动 | 不存在 → Zygote fork | 不存在 | 最大:进程创建 + Application + Activity |
| 温启动 | 存在 | 已销毁(onDestroy) | 中:只重建 Activity |
| 热启动 | 存在 | 在后台 | 最小:onRestart → onStart → onResume |
Q6:ActivityRecord 和 ActivityClientRecord 有什么区别?
ActivityRecord 在 AMS 侧 (SystemServer 进程),记录 Activity 的权威状态(栈位置、生命周期状态);ActivityClientRecord 在 App 侧 ,是 AMS 下发参数在客户端的封装。两者通过 token(Binder 句柄)一一对应------AMS 回调 App 时都带 token,App 请求 AMS 时也带 token。
参考
- 掘金专栏:Android App 启动流程
- 《Android 进阶解密》(刘望舒)--- AMS 创建 Activity 章节
- AOSP 源码:
ActivityThread.java、ActivityTaskManagerService.java、ActivityManagerService.java、ZygoteInit.java、ZygoteProcess.java