第十二板块:Android 系统启动与初始化 | 第二十九篇:Init 进程、RC 脚本与属性服务(Property Service)
所属板块:第十二板块 --- Android 系统启动与初始化
前置知识:第十一板块中的 Binder IPC、mmap 机制、Linux 内核启动流程、文件系统挂载(Mount)、SELinux 初始化
本篇定位 :这是 Android 系统从无到有、从内核态到用户态的创世纪篇章 。如果说 Kernel 是种子,那么 Init 进程 就是 破土而出的第一株幼苗 。本篇将彻底拆解 Init 进程的双分叉(Fork)机制 、RC 脚本的解析与执行引擎 、Service 的重生(Restart)策略 、属性服务(Property Service)的内存映射(ashmem)与权限控制 。我们将深入
init.cpp、property_service.cpp、selinux.cpp,揭示 Android 如何在启动初期构建用户空间的世界。全程无 ROM 移植教程、无开机优化建议,仅保留 Android 系统初始化的底层定义与调度规范。
1. 核心结论先行(Thesis Statement)
Android 的启动过程是一个基于事件的责任链构建过程。
- Init 进程的本质 :用户空间的始祖(PID 1) 。它是内核启动的第一个用户态进程,负责挂载文件系统 、设置 SELinux 策略 、解析 RC 脚本 、启动核心守护进程(Daemons) 。它永不退出,负责收养孤儿进程(Orphan Processes)。
- RC 脚本的本质 :声明式的系统配置语言。它定义了系统启动时需要创建的设备节点、挂载的分区、启动的服务(Services)以及执行的命令(Actions)。它不是 Shell 脚本,而是由 Init 解析的配置文件。
- 属性服务(Property Service)的本质 :系统级的全局键值存储(Key-Value Store) 。它运行在 Init 进程中,通过 共享内存(ashmem) 暴露给所有进程,并通过 SELinux 上下文 严格控制读写权限。
- 双分叉(Fork/Exec)的本质 :进程诞生的标准范式 。Init 通过
fork()创建子进程,通过execve()替换为目标程序,从而启动系统服务。
2. Init 进程的启动全景图
2.1 从 Kernel 到 Init 的完整链路
#mermaid-svg-1ZyURi0FI99z5kbl{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-1ZyURi0FI99z5kbl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-1ZyURi0FI99z5kbl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-1ZyURi0FI99z5kbl .error-icon{fill:#552222;}#mermaid-svg-1ZyURi0FI99z5kbl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1ZyURi0FI99z5kbl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-1ZyURi0FI99z5kbl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1ZyURi0FI99z5kbl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1ZyURi0FI99z5kbl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-1ZyURi0FI99z5kbl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1ZyURi0FI99z5kbl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1ZyURi0FI99z5kbl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1ZyURi0FI99z5kbl .marker.cross{stroke:#333333;}#mermaid-svg-1ZyURi0FI99z5kbl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1ZyURi0FI99z5kbl p{margin:0;}#mermaid-svg-1ZyURi0FI99z5kbl .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-1ZyURi0FI99z5kbl .cluster-label text{fill:#333;}#mermaid-svg-1ZyURi0FI99z5kbl .cluster-label span{color:#333;}#mermaid-svg-1ZyURi0FI99z5kbl .cluster-label span p{background-color:transparent;}#mermaid-svg-1ZyURi0FI99z5kbl .label text,#mermaid-svg-1ZyURi0FI99z5kbl span{fill:#333;color:#333;}#mermaid-svg-1ZyURi0FI99z5kbl .node rect,#mermaid-svg-1ZyURi0FI99z5kbl .node circle,#mermaid-svg-1ZyURi0FI99z5kbl .node ellipse,#mermaid-svg-1ZyURi0FI99z5kbl .node polygon,#mermaid-svg-1ZyURi0FI99z5kbl .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1ZyURi0FI99z5kbl .rough-node .label text,#mermaid-svg-1ZyURi0FI99z5kbl .node .label text,#mermaid-svg-1ZyURi0FI99z5kbl .image-shape .label,#mermaid-svg-1ZyURi0FI99z5kbl .icon-shape .label{text-anchor:middle;}#mermaid-svg-1ZyURi0FI99z5kbl .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-1ZyURi0FI99z5kbl .rough-node .label,#mermaid-svg-1ZyURi0FI99z5kbl .node .label,#mermaid-svg-1ZyURi0FI99z5kbl .image-shape .label,#mermaid-svg-1ZyURi0FI99z5kbl .icon-shape .label{text-align:center;}#mermaid-svg-1ZyURi0FI99z5kbl .node.clickable{cursor:pointer;}#mermaid-svg-1ZyURi0FI99z5kbl .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-1ZyURi0FI99z5kbl .arrowheadPath{fill:#333333;}#mermaid-svg-1ZyURi0FI99z5kbl .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1ZyURi0FI99z5kbl .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1ZyURi0FI99z5kbl .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1ZyURi0FI99z5kbl .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-1ZyURi0FI99z5kbl .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1ZyURi0FI99z5kbl .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-1ZyURi0FI99z5kbl .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1ZyURi0FI99z5kbl .cluster text{fill:#333;}#mermaid-svg-1ZyURi0FI99z5kbl .cluster span{color:#333;}#mermaid-svg-1ZyURi0FI99z5kbl div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1ZyURi0FI99z5kbl .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-1ZyURi0FI99z5kbl rect.text{fill:none;stroke-width:0;}#mermaid-svg-1ZyURi0FI99z5kbl .icon-shape,#mermaid-svg-1ZyURi0FI99z5kbl .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1ZyURi0FI99z5kbl .icon-shape p,#mermaid-svg-1ZyURi0FI99z5kbl .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-1ZyURi0FI99z5kbl .icon-shape .label rect,#mermaid-svg-1ZyURi0FI99z5kbl .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1ZyURi0FI99z5kbl .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-1ZyURi0FI99z5kbl .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-1ZyURi0FI99z5kbl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 核心守护进程
Init 进程 (PID 1)
Linux 内核
Bootloader
Kernel Init (start_kernel)
挂载根文件系统 (rootfs)
执行 /init (PID 1)
第一阶段 (First Stage)
SELinux 初始化
第二阶段 (Second Stage)
启动属性服务
解析 *.rc 文件
执行 Action (early-boot, boot)
启动核心服务
Zygote (孵化器)
SurfaceFlinger (显示合成)
Vold (存储管理)
Netd (网络管理)
Healthd (电池管理)
2.2 核心组件职责表
| 组件 | 层级 | 职责 | 学术定义 |
|---|---|---|---|
| First Stage Init | Early Boot | 基础建设 | 挂载 /system, /vendor, /data 等关键分区,加载 SELinux 策略。 |
| Second Stage Init | Late Boot | 系统构建 | 解析 RC 脚本,启动属性服务,拉起系统核心守护进程。 |
| Action Manager | Init | 调度器 | 管理 RC 脚本中的 Action(如 on boot),按序执行 Command。 |
| Service List | Init | 服务注册表 | 维护所有需要启动的 Service 及其状态(Running, Stopped, Restarting)。 |
| Property Service | Init | 全局存储 | 管理系统属性(如 ro.build.version, persist.sys.usb.config)。 |
3. Init 进程的双分叉与孤儿收养
3.1 进程诞生的标准范式
Init 启动服务采用标准的 Unix 进程创建方式。
学术定义:
- fork(): 创建当前进程的一个副本。子进程获得父进程的地址空间、文件描述符等的拷贝。
- execve() : 将当前进程映像替换为新的程序。子进程调用此函数,加载目标可执行文件(如
/system/bin/zygote)。
源码解析:
cpp
// system/core/init/service.cpp
bool Service::Start() {
pid_t pid = fork(); // 1. 分叉
if (pid == 0) { // 子进程
// 设置环境变量、UID/GID、SELinux 上下文
execve(args_[0], args_.data(), envp); // 2. 执行
} else if (pid > 0) { // 父进程 (Init)
pid_ = pid;
status_ = Status::RUNNING;
}
}
3.2 孤儿进程的收养(Subreaper)
Init 进程有一个特殊使命:收养孤儿进程。
学术定义:
- 孤儿进程:父进程先于子进程退出,子进程成为孤儿。
- Subreaper : Init 设置自己为
subreaper。当任何子进程变成孤儿时,内核会将其 PPID 设置为 Init 的 PID(1),由 Init 负责回收其资源(waitpid),防止僵尸进程。
4. RC 脚本解析与执行引擎
4.1 RC 脚本的结构
RC 脚本不是 Shell 脚本,而是 Init 的配置语言。
示例(init.rc):
rc
# Action: 定义何时执行
on boot
chmod 0666 /dev/null
start servicemanager
# Service: 定义如何启动
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root system
oneshot
4.2 解析与执行逻辑
Init 内部维护三个核心数据结构:
| 数据结构 | 作用 | 学术定义 |
|---|---|---|
| Action | 动作 | 包含触发器(Trigger)和命令列表(Commands)。 |
| Service | 服务 | 包含可执行文件路径、参数、环境变量、权限、重启策略。 |
| Import | 导入 | 引入其他 RC 文件(如 init.${ro.hardware}.rc)。 |
执行流程:
- ParseConfig(): 读取并解析 RC 文件,构建 Action 和 Service 链表。
- ActionManager::ExecuteOneCommand(): 从队列中取出 Action,执行其 Commands。
- Service::StartIfNotDisabled() : 检查 Service 是否满足启动条件,调用
fork/exec。
5. 属性服务(Property Service)深度解析
5.1 属性存储的内存布局
属性服务使用 共享内存(ashmem) 来存储属性,以便所有进程都能访问。
学术定义:
- Property Area : 一块共享内存区域。Init 进程创建,其他进程通过
mmap映射。 - Property Trie : 字典树结构。用于快速查找属性值。前缀(如
ro.,persist.)决定了存储位置和权限。
5.2 属性类型与持久化
| 属性前缀 | 特性 | 持久化 | 学术定义 |
|---|---|---|---|
| ro. | 只读 | 是(重启不变) | Read Only。系统属性,只能在 Init 阶段设置。 |
| persist. | 持久 | 是(写入 /data/property) |
Persistent。重启后保留。 |
| sys. | 系统 | 否 | System。运行时可变。 |
| ctl. | 控制 | 否 | Control。用于启动/停止服务(如 ctl.start zygote)。 |
5.3 权限控制
属性服务通过 SELinux 和 UID 控制访问。
学术定义:
- selinux_check_access(): 在设置属性前,Init 调用 SELinux 检查调用者是否有权限修改该属性。
- UID 限制 : 只有特定 UID(如 System UID)才能设置某些属性(如
sys.usb.config)。
源码解析:
cpp
// system/core/init/property_service.cpp
uint32_t PropertySet(const std::string& name, const std::string& value) {
// 1. 检查 SELinux 权限
if (!SelinuxCheckAccess(source_ctx, target_ctx, "property_service", "set", name.c_str())) {
return PROP_ERROR_PERM_DENIED;
}
// 2. 检查只读属性
if (StartsWith(name, "ro.")) {
return PROP_ERROR_READ_ONLY_PROPERTY;
}
// 3. 更新属性值
UpdateProperty(name, value);
}
6. 关键守护进程的启动
6.1 Servicemanager
Servicemanager 是 Binder 机制的 DNS 服务器。
- 启动时机: 最早启动的守护进程之一。
- 职责: 管理 Binder 服务的注册与查询。
- 特殊性 : 它是一个 Binder 上下文管理器,其句柄固定为 0。
6.2 Zygote
Zygote 是 Java 世界的孵化器。
- 启动参数 :
--start-system-server。 - 职责: 预加载 Framework 类和资源,等待 AMS 请求孵化应用进程。
6.3 SurfaceFlinger
SurfaceFlinger 是图形显示的心脏。
- 启动时机: 较早启动,因为动画和开机 Logo 需要它。
- 依赖: 依赖 HWC (Hardware Composer) 和 Gralloc。
7. 关键源码深度解析
7.1 Init 的 main 函数
cpp
// system/core/init/init.cpp
int main(int argc, char** argv) {
// 1. 第一阶段
if (bootscript.empty()) {
FirstStageMain(argc, argv);
}
// 2. 第二阶段
SecondStageMain(argc, argv);
}
void SecondStageMain(int argc, char** argv) {
// 初始化属性服务
PropertyInit();
// 解析 RC 文件
ActionManager::GetInstance().AddAction(action);
// 启动循环
while (true) {
// 处理信号、重启服务、执行命令
HandleControlMessages();
ExecuteOneCommand();
}
}
7.2 Service 的重启策略
Init 负责在服务崩溃时重启它。
学术定义:
- Critical Service : 关键服务(如
surfaceflinger)。如果它在 4 分钟内重启 4 次,系统会进入 Recovery Mode 或 重启。 - Restart Delay: 普通服务崩溃后,Init 会延迟 5 秒再重启,防止频繁重启导致系统负载过高。
8. 启动过程的常见误区
| 误区 | 学术解释 |
|---|---|
| Init 是 Shell 脚本 | 错误。Init 是 C++ 编译的二进制程序,RC 是配置文件。 |
| 属性是环境变量 | 错误。属性是独立的 Key-Value 存储,通过共享内存访问。 |
| Zygote 是 Init 的子进程 | 正确。但 Zygote 又孵化了 System Server 和应用进程。 |
| 开机慢都是 Init 的锅 | 错误。通常是 Service 启动慢(如 dex2oat)或 IO 瓶颈。 |
9. 本篇总结(Knowledge Closure)
| 关键点 | 纯学术定义 |
|---|---|
| Init 的本质 | 用户空间始祖(PID 1),负责构建系统基础环境。 |
| RC 脚本的本质 | 声明式配置语言,定义设备、挂载点和服务的生命周期。 |
| 属性服务 | 基于共享内存的全局 KV 存储,受 SELinux 严格保护。 |
| 双分叉机制 | fork() 创建进程,execve() 加载程序的标准范式。 |
| 孤儿收养 | Init 作为 subreaper,负责回收所有孤儿进程。 |
10. 第十二板块结语
至此,第十二板块:Android 系统启动与初始化 的第一篇已完成。
我们从 Kernel 的交棒 出发,深入 Init 进程的双分叉机制 ,探索 RC 脚本的解析引擎 ,最终抵达 属性服务的全局控制。
我们揭示了 Android 系统启动的核心逻辑:用 Init 构建骨架,用 RC 填充血肉,用属性服务维持神经冲动。
下一篇预告 :第十二板块:Android 系统启动与初始化 | 第三十篇:Zygote 孵化机制与 System Server 的启动