第十二板块:Android 系统启动与初始化 | 第二十九篇:Init 进程、RC 脚本与属性服务(Property Service)

第十二板块:Android 系统启动与初始化 | 第二十九篇:Init 进程、RC 脚本与属性服务(Property Service)

所属板块:第十二板块 --- Android 系统启动与初始化

前置知识:第十一板块中的 Binder IPC、mmap 机制、Linux 内核启动流程、文件系统挂载(Mount)、SELinux 初始化

本篇定位 :这是 Android 系统从无到有、从内核态到用户态的创世纪篇章 。如果说 Kernel 是种子,那么 Init 进程 就是 破土而出的第一株幼苗 。本篇将彻底拆解 Init 进程的双分叉(Fork)机制RC 脚本的解析与执行引擎Service 的重生(Restart)策略属性服务(Property Service)的内存映射(ashmem)与权限控制 。我们将深入 init.cppproperty_service.cppselinux.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)。

执行流程

  1. ParseConfig(): 读取并解析 RC 文件,构建 Action 和 Service 链表。
  2. ActionManager::ExecuteOneCommand(): 从队列中取出 Action,执行其 Commands。
  3. 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 权限控制

属性服务通过 SELinuxUID 控制访问。

学术定义

  • 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 的启动

相关推荐
故渊at1 小时前
第十三板块:Android 综合架构与未来演进 | 第三十二篇:Android 内存管理与 LMK 机制的深度剖析
android·架构·内存管理·内存回收·lmk机制·收割算法
故渊at1 小时前
第十一板块:Android 跨进程通信与 Binder 深度剖析 | 第二十七篇:Binder 线程池与死亡通知(Death Recipient)机制
android·binder·线程池·死亡通知·跨进程通讯
jushi89991 小时前
FB Neo 街机模拟器全游戏整合版 含25000+街机游戏怀旧复古街机游戏 解压即玩 热门怀旧街机游戏全集安卓+PC电脑版
android·游戏·电脑
vensli1 小时前
体验专题——Android 应用瘦身实战
android·网络
AFinalStone1 小时前
Android12 U盘插拔链路源码全解析(七):应用层 —— MediaScanner与SAF
android·frameworks
某林2121 小时前
ROS2 并行编译死锁与 Linux 后台声卡/提权踩坑实录:大型轮足机器人架构复盘
linux·架构·机器人·iassc
无足鸟ICT1 小时前
【RHCA+】末行模式
linux
AI玫瑰助手1 小时前
Python模块:import导入模块与模块的搜索路径
android·开发语言·python
拼搏的小浣熊2 小时前
【通用教程】Windows\+Linux\+银河麒麟系统 固定静态IP地址|解决打印机扫描IP变动、网络掉线问题
linux·网络·windows·麒麟·固定ip·麒麟系统·统信系统