安卓init.rc解析

Android init.rc 超详细解析

init.rc 是 Android 系统启动流程中,由 init 进程解析和执行的核心配置文件,定义了系统服务、启动脚本、权限控制、挂载规则等关键行为,是理解 Android 启动机制的核心。下面从语法规则、核心组件、执行流程、实战案例、常见问题五个维度拆解。


一、基础定位:它在启动流程里的角色

结合你之前看的启动流程图,init 进程是内核启动后的第一个用户态进程,它的核心工作就是:

  1. 解析 init.rc 及所有引入的 .rc 配置文件
  2. 按照配置创建 / 挂载文件系统、设置权限
  3. 启动关键进程(如 service_managerZygotesurfaceflinger
  4. 管理系统服务的生命周期(重启、崩溃处理)

init.rc 本质是一种Android Init Language(AIL) 编写的脚本,不是通用 Shell 脚本,语法有严格规范。


二、核心语法规则(必懂基础)

init.rc 的语法由四大核心元素 构成:ActionsServicesCommandsTriggers,同时支持 Options 控制行为。

1. 基本格式

  • 注释:以 # 开头,到行尾结束
  • 关键字:区分大小写,必须小写
  • 缩进:用空格 / 制表符,同层级语句缩进一致(影响解析)
  • 跨多行:用 \ 换行

2. 四大核心元素详解

(1)Triggers(触发器)

定义触发条件,当条件满足时,会执行绑定的 Action。常见触发器:

表格

触发器 触发时机
early-init init 进程刚启动,挂载基础文件系统前
init 挂载基础文件系统后,关键服务启动前
late-init 核心系统服务启动完成后
boot 系统启动完成,进入用户态前
property:ro.bootmode=charger 当系统属性 ro.bootmode 变为 charger 时触发
sys.powerctl=* 电源控制事件触发(关机、重启)

(2)Actions(动作块)

格式:on <trigger> [&& <trigger>]*,定义触发器满足时要执行的 Commands 序列。示例:

rc

复制代码
# 当 boot 触发器触发时,执行这些命令
on boot
    # 挂载 /data 分区(示例)
    mount_all /vendor/etc/fstab.${ro.boot.hardware.platform}
    # 设置系统属性
    setprop ro.boottime.init.boot_complete 1
    # 创建目录并设置权限
    mkdir /data/misc 0771 system system

(3)Services(服务块)

格式:service <name> <path> [arguments]*,定义由 init 进程管理的系统服务(常驻进程)。核心属性:

  • name:服务名称,唯一标识
  • path:服务可执行文件路径
  • arguments:启动参数
  • 后续可跟 Options 控制服务行为

示例:

rc

复制代码
# 定义 servicemanager 服务
service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    socket servicemanager stream 0660 root system

(4)Commands(命令)

Action 块中可执行的内置命令,是 init 进程直接实现的逻辑,不是 Shell 命令。常见命令:

表格

命令 作用 示例
exec 执行外部程序(阻塞式) exec /system/bin/mount_ext4 /dev/block/by-name/userdata /data
mkdir 创建目录 mkdir /data/system 0700 system system
mount 挂载文件系统 mount ext4 /dev/block/sda1 /system ro
setprop 设置系统属性 setprop ro.build.version.sdk 33
chmod/chown 修改文件权限 / 所有者 chmod 0644 /sys/class/leds/lcd-backlight/brightness
write 向文件写入内容 write /sys/power/state mem
symlink 创建软链接 symlink /system/bin/toolbox /system/bin/ls

注意:init.rc不能直接写 Shell 命令 (如 lsecho),必须用内置命令或 exec 调用外部可执行文件。

3. 服务块的关键 Options(控制服务行为)

这些选项直接影响服务的启动方式、权限和生命周期,是系统服务定义的核心:

表格

Option 作用 示例场景
class <name> 指定服务所属类别,可通过 start <class> 批量启动 class core(核心服务,boot 阶段必须启动)、class main(普通服务)
user <username> 服务运行的用户(默认 root) user system(以 system 用户运行,避免 root 权限过大)
group <groupname> [groupname]* 服务运行的用户组 group system radio(同时加入 system 和 radio 组,获取权限)
critical 标记为关键服务,崩溃 4 次则系统重启 servicemanagerzygote 等核心服务必须标记
oneshot 服务退出后不自动重启(一次性任务) 分区格式化、初始化脚本
disabled 不随类别自动启动,需手动 start <name> 调试用服务、可选组件
socket <name> <type> <perm> [user] [group] [seclabel] 创建 Binder/UNIX 域套接字,供进程间通信 socket servicemanager stream 0660 root system
priority <priority> 设置进程优先级(-20 到 19,默认 0) priority -10(提高关键服务优先级)
seclabel <label> 设置 SELinux 安全上下文 seclabel u:r:init:s0

三、init.rc 的执行流程(从解析到运行)

结合你之前的启动流程图,init.rc 的完整执行路径如下:

1. 解析阶段

  1. init 进程启动后,首先解析 /init.rc(根目录的主配置文件)
  2. 递归解析所有引入的配置文件:
    • init.rc 会引入 /system/etc/init//vendor/etc/init//odm/etc/init/ 下的所有 .rc 文件
    • 厂商定制的服务、硬件相关配置,通常放在 /vendor/etc/init/ 下(如 vendor.rc
  3. 解析完成后,将所有 Action 按触发器分组,Service 存入服务列表

2. 执行阶段(按触发器顺序)

  1. early-init 阶段 :挂载 tmpfsdevpts 等基础文件系统,初始化 SELinux,设置基础权限
  2. init 阶段 :挂载 /system/vendor 等分区,启动 core 类服务(servicemanagerhwservicemanager
  3. late-init 阶段 :启动 main 类服务(surfaceflingermedia_server 等),初始化硬件服务
  4. boot 阶段 :所有核心服务启动完成,触发 boot 触发器,执行桌面启动前的初始化
  5. 后续阶段:响应系统属性变化、电源事件等触发器,动态执行对应 Action

关键细节:init 进程是单线程事件循环Action 中的命令按顺序执行,前一个命令完成后才会执行下一个,阻塞式命令(如 exec)会卡住后续流程。


四、实战解析:典型系统服务的 init.rc 配置

以你流程图中的 servicemanagerZygote 为例,拆解真实配置的含义:

1. servicemanager 配置(核心 Binder 服务管理器)

rc

复制代码
service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    socket servicemanager stream 0660 root system
  • class core:属于核心服务,init 会在 init 阶段强制启动,崩溃后自动重启
  • critical:崩溃 4 次会触发系统重启,是 Android 的 "心脏服务"
  • socket:创建一个 UNIX 域套接字,供其他进程注册 / 查询 Binder 服务(如 surfaceflingermedia_server

2. Zygote 配置(Java 进程孵化器)

rc

复制代码
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd
  • app_process64:Zygote 的可执行文件,负责孵化所有 Java 进程(包括 system_server 和普通应用)
  • --start-system-server:启动时同时创建 system_server 进程(你流程图中的关键节点)
  • onrestart:当 Zygote 重启时,触发这些命令(唤醒系统、重启依赖服务)

五、厂商定制与常见修改场景

1. 厂商配置的存放位置

Android 分区化设计中,不同层级的配置文件存放位置不同:

表格

分区 路径 用途
/system /system/etc/init/ 原生 Android 系统服务配置
/vendor /vendor/etc/init/ 芯片厂商 / 设备厂商定制的硬件服务配置
/odm /odm/etc/init/ 设备厂商的机型定制配置
/product /product/etc/init/ 系统应用 / 服务的定制配置

2. 常见修改场景(开发 / 调试)

场景 1:添加自定义后台服务

rc

复制代码
# 定义一个自定义服务,开机启动,崩溃自动重启
service my_custom_service /vendor/bin/my_service
    class main
    user system
    group system
    disabled  # 先禁用,调试时再启用
    oneshot   # 一次性服务,退出不重启(可选)

# 在 boot 阶段启动该服务
on boot
    start my_custom_service

场景 2:修改分区挂载参数

rc

复制代码
# 调整 /data 分区的挂载权限,开启 discard(TRIM)优化
on init
    mount_all --early /vendor/etc/fstab.${ro.boot.hardware.platform}
    # 重新挂载 /data,添加 discard 选项
    mount ext4 /dev/block/by-name/userdata /data ro,discard

场景 3:添加调试命令

rc

复制代码
# 在 boot 阶段执行调试脚本,输出启动日志
on boot
    exec /system/bin/log -t init_debug "Boot completed, running custom debug script"
    exec /vendor/bin/debug_init.sh

六、常见问题与避坑指南

1. 为什么 init.rc 里的命令不执行?

  • 检查触发器:确认命令所在的 Action 触发器是否触发(如 boot 阶段的命令,必须等所有核心服务启动后才会执行)
  • 权限问题:init 进程运行在 root 权限,但 SELinux 会限制操作,可通过 dmesg | grep avc 查看 SELinux 拒绝日志
  • 缩进错误:init.rc 解析器对缩进敏感,同层级语句缩进不一致会导致解析失败
  • 命令错误:不能直接写 Shell 命令,必须用内置命令或 exec 调用外部可执行文件

2. 服务启动失败,日志在哪里看?

  • init 进程日志:adb logcat -s init
  • 服务崩溃日志:adb logcat -s ServiceManageradb shell dmesg
  • 关键错误日志:/proc/kmsg(内核日志,包含 init 阶段的错误)

3. oneshotdisabled 选项的区别

  • oneshot:服务退出后不自动重启,适合一次性任务(如初始化脚本)
  • disabled:服务默认不启动,必须通过 start <service_name> 手动触发,适合调试 / 可选服务

七、进阶:Android 10+ 的 init 架构变化

从 Android 10 开始,init 引入了分区化配置服务管理优化

  1. 废弃了 /init.rc 中的大量硬编码逻辑,改为模块化的 .rc 文件,每个服务对应独立的配置文件(如 servicemanager.rc
  2. 引入 init 阶段的依赖管理,支持服务间依赖(如 servicemanager 启动后,再启动 surfaceflinger
  3. 强化 SELinux 安全控制,所有服务的 seclabel 必须在配置中明确指定,禁止隐式权限
相关推荐
徒手猫11 小时前
myslq 中json 格式的数据如何获取某个属性
android·json
2401_8275602011 小时前
【电脑和手机系统】解锁bl后刷LineageOS与Magisk各模块的安装(七)
android·linux·智能手机
超人也会哭️呀12 小时前
ES 混合检索(文本+向量)中的条件处理陷阱——当权限过滤遇到关键词查询
android·大数据·elasticsearch
zuowei288912 小时前
Laravel10.x重磅升级:8大新特性解析
android
imuliuliang12 小时前
Laravel4.x核心特性全解析
android
草莓熊Lotso15 小时前
【Linux系统加餐】从原理到封装:基于建造者模式实现System V信号量工业级C++封装
android·linux·运维·服务器·网络·c++·建造者模式
程序员煊子20 小时前
用 Cursor 从零搭一个 Compose 本地记账 App:实战记录与源码解析
android·kotlin·compose·cursor
alexhilton1 天前
面向Android开发者的Google I/O 2026
android·kotlin·android jetpack
私人珍藏库1 天前
【Android】豆图助手-永久HY-模拟微X~zfb各种截图
android·app·工具·软件·多功能