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?

基线与官方资料

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