Init 进程启动分析三

270 阅读5分钟

Android 系统启动中 Init 进程第二阶段(second_stage)的核心逻辑,解析从安全初始化到系统服务启动的关键步骤:

一、第二阶段入口:SecondStageMain 函数的初始化

在完成 SELinux 初始化后,Init 进程通过 execv 带参数 second_stage 进入第二阶段,核心逻辑在 SecondStageMain 函数中执行。这一阶段的目标是:

  • 完成系统属性初始化
  • 启动进程监控机制
  • 加载系统服务配置文件
  • 为启动 Zygote、SystemServer 等核心服务做最终准备

二、关键步骤详解

1. 进程安全与优先级设置

  • 注册崩溃重启信号
    与第一阶段类似,通过 InstallRebootSignalHandlers 监听致命信号(如 SIGABRT),开发模式下崩溃时直接重启到 Bootloader。

  • 设置最高进程优先级

    c

    WriteFile("/proc/1/oom_score_adj", "-1000");
    
    • oom_score_adj 是 Android 的进程优先级值,范围从 -1000(最高优先级)到 +1000(最低)。
    • Init 作为根进程,设置为 -1000 确保系统运行时始终保留,不会被内存管理机制杀死。
  • 启用系统调用过滤(Seccomp)
    通过 GlobalSeccomp() 限制 Init 进程可用的系统调用,减少潜在安全风险(如禁止危险的内核操作)。

2. 系统标记与密钥管理

  • 创建引导进行中标记

    c

    close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
    
    • 在 /dev 下创建 .booting 文件,作为系统启动中的临时标记,供其他进程(如固件加载器)检测启动状态。
  • 内核密钥服务初始化

    c

    keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);
    
    • 调用内核密钥管理接口,为后续加密操作(如文件加密 FBE)准备密钥缓存,确保安全上下文的密钥可用。

3. 属性系统:Android 的「全局配置中心」

属性系统是 Android 中存储全局配置的核心机制(如设备型号、语言设置),第二阶段的初始化步骤包括:

  1. 解析内核启动参数

    • process_kernel_dt() :从设备树(Device Tree)读取硬件相关配置(如分区挂载点),设置 ro.boot 开头的属性(如 ro.boot.vendor_id)。

    • process_kernel_cmdline() :解析内核命令行参数(如 androidboot.hardware=ranchu),转换为系统属性。

      • 示例:命令行参数 androidboot.storagemedia=emmc 会生成 ro.boot.storagemedia=emmc
  2. 导出内核属性

    c

    export_kernel_boot_props();
    
    • 将内核相关属性(如序列号)同步到用户空间可访问的属性(如 ro.serialno 来自 ro.boot.serialno)。
  3. 加载默认属性文件

    c

    property_load_boot_defaults(load_debug_prop);
    
    • 读取 /system/etc/prop.default/system/build.prop 等文件,设置系统默认属性(如 ro.product.model)。

4. SELinux 二次配置:确保安全上下文生效

  • 日志重定向:再次调用 SelinuxSetupKernelLogging(),确保第二阶段的 SELinux 日志仍写入内核缓冲区。

  • 安全上下文校验

    c

    SelinuxRestoreContext();
    
    • 遍历关键文件(如 /system/bin 下的可执行文件),通过 restorecon 命令应用默认安全标签,确保文件访问权限符合 SELinux 策略。

5. 进程监控与服务启动

  • 初始化 epoll 事件监听

    c

    Epoll epoll;
    InstallSignalFdHandler(&epoll);
    
    • 使用 Linux 的 epoll 机制监控子进程退出信号(SIGCHLD),当子进程(如 Zygote)崩溃时,Init 可及时回收资源并重启服务。
  • 启动属性服务(Property Service)

    c

    StartPropertyService(&epoll);
    
    • 属性服务是 Android 系统的「全局配置中心」,允许进程通过 property_get/property_set 接口读写系统属性,支持跨进程通信。
  • 处理分区挂载与清理

    • 卸载临时挂载点 /debug_ramdisk
    • 挂载厂商覆盖分区(/system/vendor_overlay),确保不同设备的定制化配置生效。

三、关键知识点总结

  1. 属性系统的核心作用

    • 系统属性是 Android 的「全局变量」,贯穿启动流程(如 ro.boot 系列属性决定设备型号、分区布局)。
    • 示例:ro.boot.selinux=enforcing 控制 SELinux 运行模式,ro.product.name 决定系统显示名称。
  2. 进程优先级与监控

    • Init 通过 oom_score_adj 确保自身不被杀死,通过 epoll 监听子进程状态,实现「守护进程」的职责(如重启崩溃的 Zygote)。
  3. 安全机制的分层实现

    • 第一阶段完成 SELinux 策略加载,第二阶段校验文件安全上下文,确保用户空间服务在严格的安全域中运行。
  4. 阶段切换的设计思想

    • 第一阶段:「最小化环境搭建」(挂载文件系统、基础安全)。
    • 第二阶段:「功能完善与服务启动」(属性初始化、进程监控、服务配置)。
    • 通过分阶段解耦,降低启动流程的复杂度,便于问题定位(如属性错误可直接追溯到第二阶段)。

四、类比说明

Init 进程的第二阶段类似「操作系统的初始化向导」:

  • 设置优先级:如同给向导最高权限,确保其能完成所有配置步骤。

  • 属性系统:类似向导中的「配置表单」,填写设备型号、语言等信息,供后续应用读取。

  • SELinux 校验:类似向导中的「安全检查」,确保所有配置符合安全规范(如禁止应用访问敏感目录)。

  • 启动属性服务:如同启动「全局配置数据库」,允许所有应用查询和修改系统参数。

通过这一阶段,Android 系统从「内核控制的裸机环境」过渡到「用户空间主导的可配置环境」,为最终启动桌面(Launcher)和应用程序奠定基础。