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
相关推荐
千里马学框架2 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台2 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone2 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc2 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo2 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077002 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼2 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone2 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen2 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone2 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui