App 启动流程:从 Launcher 点击到 Activity 创建

App 启动流程:从 Launcher 点击到 Activity 创建(跨进程通信与 AMS 全链路分析)

本文梳理一次完整冷启动所经历的三个阶段: ① Launcher 发起启动请求(Binder 跨进程)→ ② SystemServer 中 AMS 启动 App 进程(socket + Zygote fork)→ ③ Activity 创建三步(Binder 回调 → H 切主线程 → performLaunchActivity)。

一、核心流程速览

一次冷启动涉及 4 个进程

进程 角色 关键类
Launcher(桌面) 发起方:响应图标点击 LauncherInstrumentationActivityTaskManager
SystemServer 调度中枢:解析 Intent、管理进程与 Activity 栈 ActivityTaskManagerService(ATMS)、ActivityManagerService(AMS)、ZygoteProcess
Zygote 进程孵化器:fork 出新进程 ZygoteInitRuntimeInit
App 进程 执行方:初始化主线程并创建 Activity ActivityThreadApplicationThreadHInstrumentation
sequenceDiagram participant L as Launcher 进程 participant S as SystemServer(ATMS/AMS) participant Z as Zygote participant A as App 进程(ActivityThread) L->>S: 1. Binder IPC: ATMS.startActivity() S->>S: 2. ActivityStarter 解析 Intent<br/>检查目标进程 ProcessRecord 是否存活 S->>Z: 3. socket: fork 请求(进程不存在时) Z->>A: 4. fork 出新进程 → 反射调用 ActivityThread.main() A->>A: 5. prepareMainLooper + attach() A->>S: 6. Binder IPC: attachApplication(mAppThread) 反向注册 S->>A: 7. Binder IPC: scheduleLaunchActivity ★第1步 A->>A: 8. H 切回主线程处理 LAUNCH_ACTIVITY ★第2步 A->>A: 9. handleLaunchActivity → performLaunchActivity → onCreate ★第3步

一个关键认知:启动的"指挥权"始终在 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);
            }
        };

要点

  1. ServiceManager.getService() 从 ServiceManager 中拿到 "activity_task" 服务的 Binder 句柄,Stub.asInterface() 将其包装成本地可调用的代理对象 IActivityTaskManager------真正的执行体在 SystemServer 进程的 ActivityTaskManagerService
  2. 每一次 startActivity 都是一次 Binder IPC(一次跨进程调用 + 一次内核拷贝),这也是 Launcher 进程不直接创建 Activity 的原因:Activity 的栈管理、进程调度全部由系统服务统一负责
  3. 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();
    }
    ...
}

反向注册是启动链路中最容易忽略的一环

  • mAppThreadApplicationThreadActivityThread 的内部类),它是 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 真正创建,共分三步:

sequenceDiagram participant AMS as AMS(SystemServer) participant AT as ApplicationThread<br/>(Binder 线程池) participant H as H<br/>(主线程 Handler) participant T as ActivityThread<br/>(主线程) AMS->>AT: scheduleLaunchActivity(intent, token, ...) Note over AT: ★第1步 Binder 线程池中执行<br/>封装 ActivityClientRecord AT->>H: sendMessage(H.LAUNCH_ACTIVITY, r) Note over H: ★第2步 切回主线程<br/>handleMessage 取出 r → LoadedApk H->>T: handleLaunchActivity(r) Note over T: ★第3步 performLaunchActivity<br/>ContextImpl → newActivity → makeApplication<br/>→ attach → onCreate

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;
        ...
    }
}

HActivityThread 的内部类,继承自 Handler,绑定主线程 Loopermain() 中的 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 有什么区别?

ActivityRecordAMS 侧 (SystemServer 进程),记录 Activity 的权威状态(栈位置、生命周期状态);ActivityClientRecordApp 侧 ,是 AMS 下发参数在客户端的封装。两者通过 token(Binder 句柄)一一对应------AMS 回调 App 时都带 token,App 请求 AMS 时也带 token。


参考

  • 掘金专栏:Android App 启动流程
  • 《Android 进阶解密》(刘望舒)--- AMS 创建 Activity 章节
  • AOSP 源码:ActivityThread.javaActivityTaskManagerService.javaActivityManagerService.javaZygoteInit.javaZygoteProcess.java
相关推荐
小孔龙1 小时前
BufferQueue 对象交接与同步
android
XiaoLeisj1 小时前
Kotlin Flow 常用操作符:数据变换 map、filter、onEach,时间控制 debounce、sample,终端聚合 reduce、fold
android·kotlin·android jetpack·协程·响应式编程·flow
EQ-雪梨蛋花汤2 小时前
Android 3D 开发教程(三):Sceneform-EQR 配置 PBR 材质、光照、相机与实时阴影
android·3d·材质
Dovis(誓平步青云)2 小时前
《 固井工程软件 Cemsol 的数据管理与国产化适配实践》
android·java·开发语言·人工智能
Kapaseker2 小时前
小白都看得懂的 Skill 教程 - 创建第一个 Skill
android·kotlin·vibecoding
zhangphil3 小时前
Android BitmapFactory实现AOSP ContentResolver.loadThumbnail快速取小缩略图,Kotlin
android·kotlin
weixin_440784113 小时前
【OkHttp实现原理】
android·java·okhttp
恋猫de小郭3 小时前
Jetpack Compose 8 月版正式发布,核心模块 1.12
android·前端·flutter
delta_hell3 小时前
【阅读源码--Android】动画之AnimatorSet--1
android·源码·animatorset