Init 进程启动分析四

706 阅读5分钟

Android 系统中 init.rc 文件的结构、语法及在系统启动中的关键作用,帮助你理解这个控制 Init 进程启动服务的核心配置文件:

一、init.rc 是什么?为什么重要?

init.rc 是 Android 系统启动时由 Init 进程解析的核心配置脚本,用于定义系统服务的启动规则初始化操作

  • 作用

    • 告诉 Init 进程「启动哪些服务」「何时启动」「如何启动」。
    • 配置服务的用户权限、安全上下文、重启策略等关键参数。
  • 位置:通常位于 /system/core/rootdir/init.rc,可通过 init 进程动态加载其他 .rc 文件(如 init.usb.rcinit.zygote.rc)。

二、init.rc 的基本结构:块(Section)的分类

init.rc 由多个「块」组成,每个块以关键字开头,分为两大类:

1. 动作块(Action Section)

  • 关键字on

  • 作用:定义「当某个事件发生时,执行一系列命令」。

  • 格式

    ini

    on <触发条件>  # 触发动作的事件
        <命令1>     # 事件触发时执行的操作
        <命令2>     # 可包含多个命令
    
    • 触发条件(Trigger)

      • 系统事件

        • on init:Init 进程初始化完成时触发(最早的事件)。
        • on boot:系统启动完成时触发(所有核心服务已启动)。
        • on charger:设备插入充电器时触发。
      • 属性变化

        • on property:name=value:当系统属性 name 的值变为 value 时触发。

          • 示例:on property:sys.boot_completed=1 表示系统启动完成后触发。
    • 常见命令

      • exec <路径>:运行指定程序(如 exec /sbin/adbd 启动 ADB 服务)。
      • setprop <名称> <值>:设置系统属性(如 setprop sys.language zh 设置语言)。
      • symlink <源路径> <目标路径>:创建符号链接(如 symlink /system/etc /etc 映射目录)。

2. 服务块(Service Section)

  • 关键字service

  • 作用:定义「需要长期运行的后台服务」及其启动参数。

  • 格式

    ini

    service <名称> <可执行路径> [参数...]  # 服务名称和启动命令
        <选项1>  # 服务配置选项(如用户权限、重启策略等)
        <选项2>
    
    • 关键选项

      • class <类别>:将服务分组(如 class core),可通过 class_start core 批量启动同一类别服务。
      • user <用户> / group <组>:指定服务运行的用户和组(如 user system 表示以系统用户运行)。
      • disabled:默认不随类别启动,需手动通过 start <服务名> 启动。
      • oneshot:服务退出后不自动重启(适用于一次性任务,如系统初始化脚本)。
      • critical:服务崩溃超过一定次数(如 4 次)时,系统重启到 Bootloader(用于关键服务,如 Zygote)。
      • socket <名称> <类型> <权限>:创建 Unix 套接字供服务通信(如 socket logd stream 0666 logd logd 为日志服务创建套接字)。

三、经典示例解析

1. 动作块示例:系统初始化

ini

on init
    sysclktz 0              # 设置系统时区为 GMT+0
    symlink /system/etc /etc # 创建符号链接,兼容旧路径
    mkdir /dev/socket 0755   # 创建套接字目录,权限 0755
  • 触发条件:Init 进程完成第一阶段初始化后触发。
  • 作用:设置基础系统环境,创建必要目录和链接。

2. 服务块示例:ADB 服务

ini

service adbd /sbin/adbd
    user adb                # 以 adb 用户运行
    group adb               # 属于 adb 组
    disabled                # 默认不启动,需手动触发
    socket adbd stream 660   # 创建名为 adbd 的套接字,权限 660
  • 启动方式:通过 start adbd 命令手动启动。
  • 权限说明:套接字权限 660 表示用户和组可读可写,其他用户无权限。

3. 服务块示例:系统启动动画

ini

service bootanim /system/bin/bootanimation
    class core              # 属于 core 类别,随核心服务启动
    user graphics           # 以 graphics 用户运行(拥有图形资源权限)
    group graphics audio    # 属于 graphics 和 audio 组
    disabled                # 默认不启动(由 Launcher 触发)
    oneshot                 # 动画播放完成后自动退出,不重启
  • 特点:一次性任务,播放完启动动画后自动终止,无需持续运行。

四、核心功能与应用场景

1. 权限与安全上下文配置

  • 通过 user/group 限制服务权限,避免以 root 运行非必要服务(如 logd 服务以 logd 用户运行,避免越权访问)。
  • 通过 seclabel 选项为服务设置 SELinux 安全标签(如 seclabel u:r:logd:s0 限制日志服务的访问范围)。

2. 服务管理与重启策略

  • 自动重启:未设置 oneshot 时,服务崩溃后 Init 会自动重启(如 Zygote 服务)。
  • 严格模式(critical) :关键服务(如 surfaceflinger)若频繁崩溃,系统会重启到 Bootloader,防止系统卡死。

3. 进程间通信(IPC)配置

  • 通过 socket 选项创建套接字,实现服务与其他进程的通信(如 servicemanager 通过套接字管理系统服务)。
  • 示例:socket system_server stream 660 system system 创建名为 system_server 的套接字,供 SystemServer 进程监听客户端请求。

五、如何阅读和调试 init.rc?

  1. 官方文档:查看 AOSP 源码中的 system/core/init/README.md,了解完整语法和选项说明。

  2. 日志定位:通过 logcat -b kernel 查看 Init 进程解析 init.rc 时的日志(如 init: Starting service 'adbd')。

  3. 动态调试

    • 使用 stop <服务名>/start <服务名> 命令手动控制服务启停。
    • 修改 init.rc 后,通过 adb remount 重新挂载系统分区并重启设备生效。

六、总结:init.rc 与系统启动的关系

init.rc 是 Android 系统启动的「服务配置蓝图」,通过定义动作和服务,实现了:

  1. 分层初始化:通过 on early-init/on init/on boot 等触发条件,确保服务按顺序启动(如先挂载分区,再启动应用框架)。

  2. 最小权限原则:通过用户、组、SELinux 标签限制服务权限,提升系统安全性。

  3. 弹性管理:自动重启崩溃服务、严格模式防止系统崩溃,保障稳定性。

理解 init.rc 的结构和语法,是深入分析 Android 系统启动流程、定制系统服务的基础。