下面为你通俗易懂且详尽地总结 Android 系统启动中 Init 进程的启动过程,带你深入了解这个用户空间首个进程的关键作用:
一、内核启动 Init 进程:从内核到用户空间的「交接」
当 Linux 内核完成初始化后,会通过 run_init_process 函数寻找并启动用户空间的第一个进程 ——init 进程(进程号永远为 1)。
-
查找路径:内核会按顺序在以下路径寻找 init 可执行文件:
- 根文件系统中的
/init(Android 设备通常放在这里)。 - 其他备用路径:
/sbin/init→/etc/init→/bin/init→/bin/sh。
- 根文件系统中的
-
执行逻辑:找到后直接执行,例如 AOSP 系统中 init 程序位于
/init,内核会加载并运行它。
二、Init 进程的入口:main 函数的「参数判断」
Init 进程的源码位于 system/core/init/main.cpp,其 main 函数会根据启动参数决定执行路径:
- 参数为
ueventd:启动内核事件守护进程(处理硬件热插拔事件)。 - 参数为
subcontext:处理子上下文环境(如特定服务的初始化)。 - 参数为
selinux_setup:进入 SELinux 设置阶段(SELinux 是 Android 的安全策略系统)。 - 参数为
second_stage:进入第二阶段初始化(后续详述)。 - 无参数:直接进入 第一阶段初始化(FirstStageMain) 。
关键点:内核启动 init 时不带参数,因此默认执行FirstStageMain。
三、Init 第一阶段:FirstStageMain 的核心任务
第一阶段的目标是搭建最小系统环境,为后续服务启动做准备,主要分为以下步骤:
1. 设置崩溃重启机制(InstallRebootSignalHandlers)
- 作用:监听致命信号(如 SIGABRT、SIGSEGV),一旦 init 崩溃,直接重启到 Bootloader(开发模式下),避免系统卡死。
- 原理:通过
sigaction注册信号处理函数,子进程崩溃时直接退出,父进程(init)崩溃时触发系统重启。
2. 挂载虚拟文件系统(核心操作)
Init 会挂载多个内存型文件系统,这些系统不占用磁盘空间,用于临时存储系统运行时数据:
-
tmpfs挂载:/dev:存储硬件设备节点(如键盘、屏幕驱动)。/mnt、/apex:临时挂载点,用于存放厂商分区或动态库。
-
devpts挂载:/dev/pts:管理虚拟终端(如 SSH 连接时的终端设备)。
-
proc挂载:/proc:暴露内核进程信息(如proc/cmdline存储启动参数)。
-
sysfs挂载:/sys:提供硬件设备的属性接口(如读取电池状态)。
-
selinuxfs挂载:-
/sys/fs/selinux:存储 SELinux 策略文件。
-
类比:这些挂载相当于在内存中搭建了一个「临时仓库」,存放系统运行必需的「工具和清单」。
3. 重定向标准输入输出(SetStdioToDevNull)
- 操作:将
stdin(输入)、stdout(输出)、stderr(错误)重定向到/dev/null(黑洞设备)。 - 原因:Init 作为后台进程,不需要用户交互,避免无关输出干扰系统日志。
4. 初始化内核日志(InitKernelLogging)
-
问题:Init 启动时,Android 日志系统(Logcat)尚未就绪,如何记录日志?
-
解决方案:
- 通过
KernelLogger将日志写入/dev/kmsg(内核消息缓冲区)。 - 后续可通过
logcat -b kernel查看这些早期日志。
- 通过
-
实现:
- 格式化日志内容(如
<级别>标签: 消息),通过writev系统调用写入内核缓冲区。
- 格式化日志内容(如
5. 挂载关键分区(DoFirstStageMount)
-
目标:挂载
/system(系统分区)、/vendor(厂商分区)等核心分区。 -
流程:
- AVB 校验:通过 Android Verified Boot(AVB)验证分区完整性,防止篡改。
- 设备初始化:创建逻辑分区(如加密分区解密)。
- 实际挂载:将分区挂载到指定路径,供后续服务读取文件(如 SELinux 策略、系统二进制文件)。
6. 进入第二阶段:execv 重新执行 init
第一阶段最后,通过 execv 带参数 selinux_setup 重新执行 init 程序,进入第二阶段初始化:
c
const char* path = "/system/bin/init";
const char* args[] = {path, "selinux_setup", nullptr};
execv(path, const_cast<char**>(args)); // 切换到第二阶段
作用:第一阶段完成底层环境搭建,第二阶段负责启动系统服务、解析 init.rc 脚本等更高层任务。
四、关键知识点总结
-
Init 进程的地位:
- 它是用户空间的「根进程」,所有应用和服务都由它启动。
- 分为两阶段初始化:第一阶段构建最小系统环境,第二阶段启动核心服务。
-
虚拟文件系统的作用:
tmpfs/devpts/proc/sysfs是系统运行的基础设施,分别用于设备管理、进程信息、硬件属性等。
-
日志与安全机制:
- 早期日志通过内核缓冲区记录,确保可追溯。
- AVB 校验和 SELinux 设置是 Android 系统安全的基石,防止恶意篡改和越权访问。
-
阶段切换的本质:
- 通过
execv重新执行 init 程序并传递参数,实现代码逻辑的「分段执行」,避免单阶段过于臃肿。
- 通过
五、类比说明
Init 进程的启动类似「搭建舞台」:
-
第一阶段:先搬来舞台框架(挂载文件系统)、准备基础设备(创建设备节点)、拉上幕布(重定向输入输出),并测试音响(日志系统)。
-
第二阶段:幕布拉开后,开始表演真正的节目 —— 启动演员(系统服务)、执行剧本(init.rc 脚本),最终呈现完整的系统功能。
通过这两个阶段,Init 进程逐步将 Android 系统从「内核控制」过渡到「用户空间主导」,为后续 Zygote、SystemServer 等进程的启动铺平道路。