Android 系统启动机制导读:从 init 到 system_server,谁创建谁?

Android 启动经常被画成一条箭头:

csharp 复制代码
Kernel → init → Zygote → system_server → System Service → Launcher

这张图适合记顺序,却不足以解释源码。因为相邻两个名字之间,可能发生的是完全不同的变化:创建新进程、执行另一个程序、从 Native 进入 Java,或者只是在同一进程里创建一个服务对象。

这个系列不追完整 Bootloader、Kernel 和 Launcher 首帧,而是回答一个更窄、也更容易混乱的问题:

Android 的关键用户空间进程是谁创建的,它们各自建立了什么,核心系统能力又怎样从"进程存在"走到"可以使用"?

导读只负责建立地图。init 怎样 fork/exec、ZygoteInit 怎样进入、App socket 协议怎样解析、SystemServiceManager 怎样分发 phase,都留给对应正文用源码证明。

一、先划边界:这不是完整"开机流程"

系列从 Kernel 已经准备启动首个 Android 用户空间程序开始:

csharp 复制代码
Kernel 已完成基本初始化
        ↓
init 成为 Android 用户空间 PID 1

系列在 Framework 已建立核心服务与启动阶段语义后收束:

arduino 复制代码
system_server 已出生
        ↓
核心服务逐步创建、发布、ready
        ↓
Framework 进入可以继续建立用户体验的状态

以下内容只标位置,不在主线下钻:

  • Boot ROM、Bootloader 与 Kernel 详细启动;
  • 驱动 probe、完整 SELinux 策略与全部 HAL/Vendor Service;
  • 单个 AMS、PMS、WMS 的内部业务;
  • 普通 App 的完整 Activity 启动与 Launcher 首帧。

还要明确这条图的性质:Kernel → init → Zygote → system_server 是"进程出生与 Framework 能力"的投影,不是完整启动依赖 DAG。真实设备上,servicemanager/hwservicemanager、SurfaceFlinger、vold/installd、Native daemon、HAL/vendor service、文件系统与用户数据准备等多条前置路径并行推进,并在不同位置与 Framework 相交。主线适合回答"谁创建谁、能力走到哪",不能据此推断所有组件都严格串行。

固定源码基线: 全系列统一使用 Android 16 QPR2 android-16.0.0_r4。固定 tag 用于证明调用边界;设备上的 Zygote 组合、厂商 rc、模块版本和服务清单仍须以目标构建为准。

二、为什么一条启动链不够?

读图时从左到右分别问三个问题,不要把三列压成一条函数调用链。

主线 A:谁创建谁?

csharp 复制代码
Kernel
  └─ init
       └─ Zygote
            ├─ system_server
            └─ 后续 App 进程

这条线只讨论 Linux 进程家谱。它最需要守住的边界是:

csharp 复制代码
init 建立 Zygote 进程
Zygote 直接创建 system_server
system_server 决定何时需要普通 App,实际孵化仍由 Zygote 体系完成

至于"建立"具体是 fork、exec 还是 fork 后的父子分支,正文再展开。

主线 B:Native 进程怎样开始执行 Java?

scss 复制代码
app_process
    ↓
AndroidRuntime / ART / Framework JNI
    ↓
ZygoteInit.main()

这条线讨论运行环境和语言边界。Native 调用 Java main() 不等于又创建了一个进程;可执行文件、运行时和 Java 入口也不是三个并列进程。

主线 C:进程存在以后,能力怎样 ready?

复制代码
SystemServer
    ↓
建立服务容器
    ↓
创建并发布服务
    ↓
推进生命周期阶段
    ↓
进入全局与用户级启动里程碑

这条线讨论的是同一进程内对象和能力状态。它不能被"system_server 已经在 ps 中"替代。

三条线的关系可以压成一句话:

进程出生线提供执行容器,运行环境线让容器能执行 Framework Java,能力就绪线再把 Java 对象组织成可被系统使用的服务。

三、先把文件、进程、类和服务分开

名字 它是什么 容易被误认成什么
/init/system/bin/init Native 可执行文件 "Android 所有代码的总 main"
init PID 1 进程 普通 Native daemon 或 Java Service
service zygote ... init rc 中的进程配置单元 Binder Service、四大组件 Service
app_process64 Native 可执行文件 与 Zygote 并列的另一个长期进程
Zygote app_process 进入特定模式后的进程角色 模板文件、Java 类名
ZygoteInit Java 启动类 Linux 进程
system_server Linux 进程 单个系统服务
SystemServer system_server 中的 Java 启动组织类 Binder Service 或 SystemService 子类
SystemServiceManager system_server 内的生命周期管理对象 全系统服务依赖求解器
Binder Service 发布给 ServiceManager 的 Binder 对象 必然独占一个进程

后文每次遇到关键名词,都可以先做这个检查:

复制代码
当前说的是文件、进程、线程、Java 类、Java 对象、Binder 接口,还是配置项?

身份一旦错位,后面的"谁调用谁"通常也会跟着错。

四、为什么不能用一个瞬间定义"启动完成"?

这个系列使用四层完成语义:

层级 典型观察 只说明什么
进程存在 Zygote、system_server PID 出现 对应进程在采样时存在
对象创建 某个 System Service 已构造/启动 服务生命周期已开始
能力可发现或 ready Binder 名称、Boot Phase、专用 ready 状态 对应接口或依赖到达某个明确层级
用户路径可用 显示、SystemUI、Home、用户广播、目标功能 需要按具体用户体验继续验证

因此这些判断不能互换:

ini 复制代码
进程存在 ≠ Java 主流程已走完
对象创建 ≠ Binder 接口已发布
接口可发现 ≠ 服务内部依赖 ready
Current phase=N ≠ phase N 的同步与异步工作都完成
sys.boot_completed=1 ≠ 所有用户、UI、HAL 和业务持续健康

第八、九篇会分别解释"服务怎样 ready"和"完成语义为什么分层"。导读到这里不提前给出 phase 顺序和属性写入细节。

五、遇到不同问题,应该从哪篇开始?

编号表示主题位置,不要求机械顺序通读。第一次阅读可先建立主线,再按兴趣补充性能模型和运行期进程工厂。

首读主线:先建立不会混乱的启动模型

  1. (一)init 到底是什么?
  2. (二)init.rc 怎样变成进程?
  3. (三)app_process 怎样成为 Zygote?
  4. (五)system_server 到底由谁创建?
  5. (七)SystemServer 怎样建立服务容器?
  6. (八)系统服务怎样从创建走到可用?
  7. (九)Android 什么时候才算启动完成?

这条路线刻意跳过两个深入机制,先回答"谁创建谁"和"能力怎样就绪"。

二刷深入:补齐性能模型和运行期进程工厂

  1. (四)preload、fork/COW 与 specialize
  2. (六)Zygote 创建 App 为什么走 Socket?

第四篇解释"为什么不从零创建每个 Java 进程",第六篇解释"系统运行后怎样把普通 App 创建请求交给 Zygote"。它们重要,但不是第一次建立进程家谱的前置条件。

工程使用:先速查,再下钻命令手册

  1. 实战(一):五分钟建立 Android 开机故障区间
  2. 实战(二):Android 启动故障证据与命令手册

实战一只负责建立相邻里程碑区间;确认区间后,再进入完整命令手册,查日志、线程、权限和构建差异。

六、读完整个系列,应该能回答什么?

不是背下一串 main(),而是能稳定回答:

csharp 复制代码
1. init、app_process、ZygoteInit、Zygote 分别属于哪一层?
2. init rc 的 service 与 Binder Service 有什么区别?
3. 哪些调用创建新进程,哪些只是同一进程继续执行?
4. system_server 为什么不是 init 直接 exec,也不是通过普通 App socket 请求创建自己?
5. system_server 与 SystemServer 有什么区别?
6. 服务对象创建、接口发布、Boot Phase 和业务 ready 有什么区别?
7. 一个 PID、一个服务名或一个 property 分别能证明到哪里?
8. 开机异常时,最后成立和第一个缺失的里程碑是什么?

如果这些问题能够被清楚回答,后续再进入任意源码函数,读者都有坐标:当前是谁、在哪个进程、是否发生线程或进程边界、这一行究竟创建了什么,以及它离"能力可用"还有多远。

首次阅读可从第一篇开始:init 到底是什么,为什么它不是普通 Native Service?

基线与官方资料

相关推荐
淡淡的香烟1 小时前
Android视频直播播放器简单封装
android·物联网·音视频
爱笑鱼1 小时前
Android 系统启动机制(一):init 到底是什么?为什么它不是普通 Native Service?
android
必须会一定会2 小时前
GLM-5.3 迁移实战:强制思考、1M 上下文与官方编程基准
android·开发语言·kotlin
小孔龙2 小时前
Android MessageQueue:从单锁队列到 DeliQueue
android
math_hongfan2 小时前
事务下单与状态流转:ArkTS 的 JOIN 联表在鸿蒙订单里实战
android·学习·华为·harmonyos
嘟哩DuliDuli2 小时前
AI 账单变高的技术原因:重复上下文和用量归属
android·人工智能·安全·ai·软件工程
阿pin17 小时前
Android随笔-kotlin withContext
android·kotlin·withcontext
树码小子18 小时前
开启 IDEA 中的断言功能
android·java·intellij-idea
Kslient18 小时前
HeaderBehavior
android