startActivity():揭秘 Android 跨进程调度的幕后指挥官

462 阅读3分钟

一句话总结 startActivity() 调用的背后,是一个由应用进程、system_serverZygote 共同协作的复杂跨进程调度系统。

一、发起启动:应用进程的代理人

startActivity() 调用的起点是应用进程,它通过 Instrumentation 作为代理,向系统发起启动请求。当开发者调用 Activity.startActivity() 时,这个请求被封装成一个 IntentInstrumentation 作为核心中间件,负责获取 ActivityManagerService(AMS) 在本地的 Binder 代理(IActivityTaskManager ,并利用它发起一次跨进程调用。这个过程就像是应用进程通过一条专线电话,向系统的总调度中心(AMS)汇报:“我要启动一个 Activity!”

二、AMS:总调度中心的决策与任务分发

运行在 system_server 进程中的 AMS,是整个 Activity 启动流程的“总指挥”。它接收到请求后,会扮演以下几个关键角色:

  • 安全与合法性审查: AMS 会首先校验调用者的权限,并检查 Intent 中包含的信息是否合法。

  • 进程管理: 这是 AMS 的核心职能之一。它会检查目标 Activity 所在的进程是否已经存在。

    • 如果进程不存在,AMS 会通过一个特殊的 Socket 通道,向 Zygote 进程发送指令。Zygote 随即通过 fork() 机制,快速复制出一个新的应用进程。这里使用 Socket 的原因在于,Zygote 主要负责进程的创建,而非复杂的方法调用,Socket 这种简单的通信机制足以完成“唤醒”任务。
    • 如果进程已存在,AMS 会直接准备下一步的启动指令。
  • 创建 ActivityRecord 为了管理 Activity 的生命周期和状态,AMS 会为即将创建的 Activity 实例在内存中生成一个“档案卡”—— ActivityRecord。这个对象包含了 Intent、所在的任务栈等所有元数据,并最终被添加到任务栈(ActivityTask)中。这确保了 Activity 的状态在跨进程的生命周期中得到统一管理。

三、逆向通信:AMS 回调应用进程

在 AMS 完成所有准备工作后,它需要将控制权交还给应用进程,告知其可以创建 Activity 实例了。这个过程并非简单的信号,而是一次完整的 Binder 逆向调用

  • ApplicationThread 的作用: 应用进程在启动之初,就在 ActivityThread 中注册了一个特殊的 Binder 实体—— IApplicationThread。AMS 就像是拥有这个“逆向电话号码”一样,可以随时发起对应用进程的调用。
  • 发起回调: AMS 通过 IApplicationThread 的 Binder 代理,调用 scheduleLaunchActivity() 方法。这次调用将 ActivityRecord 等关键信息从 system_server 进程传递回应用进程。

四、Activity 的诞生:应用进程的线程调度

应用进程接收到 AMS 的回调后,ActivityThread 将迎来最繁忙的时刻。

  • Handler 消息机制: 接收到 scheduleLaunchActivity() 调用后,应用进程的主线程(ActivityThread)并不会立即创建 Activity。它会通过 LooperHandler 机制,将一个 LAUNCH_ACTIVITY 消息添加到主线程的消息队列中。这种设计确保了 UI 操作总是在主线程上按序执行,避免了并发问题。
  • 实例创建与生命周期: 当主线程的 Handler 处理到这条消息时,它会通过反射创建 Activity 实例,并依次调用 onCreate()onStart()onResume() 等生命周期方法。
  • UI 绘制: Activity 实例创建并完成生命周期后,它的根视图(DecorView)会被添加到 WindowManager,最终通过 SurfaceFlinger 服务,呈现在用户的屏幕上。

希望这些建议能帮助你把文章提升到一个新的水平。你对 startActivity() 的核心流程还有哪些好奇的地方?例如,不同启动模式(launchMode)会如何影响任务栈的调度?