安卓init.rc解析

Android init.rc 超详细解析

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


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

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

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

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


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

init.rc 的语法由四大核心元素 构成:Actions、Services、Commands、Triggers,同时支持 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 命令 (如 ls、echo),必须用内置命令或 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 次则系统重启 servicemanager、zygote 等核心服务必须标记
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 阶段 :挂载 tmpfs、devpts 等基础文件系统,初始化 SELinux,设置基础权限
  2. init 阶段 :挂载 /system、/vendor 等分区,启动 core 类服务(servicemanager、hwservicemanager)
  3. late-init 阶段 :启动 main 类服务(surfaceflinger、media_server 等),初始化硬件服务
  4. boot 阶段 :所有核心服务启动完成,触发 boot 触发器,执行桌面启动前的初始化
  5. 后续阶段:响应系统属性变化、电源事件等触发器,动态执行对应 Action

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


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

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

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 服务(如 surfaceflinger、media_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 ServiceManager 或 adb shell dmesg
  • 关键错误日志:/proc/kmsg(内核日志,包含 init 阶段的错误)

3. oneshot 和 disabled 选项的区别

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

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

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

  1. 废弃了 /init.rc 中的大量硬编码逻辑,改为模块化的 .rc 文件,每个服务对应独立的配置文件(如 servicemanager.rc)
  2. 引入 init 阶段的依赖管理,支持服务间依赖(如 servicemanager 启动后,再启动 surfaceflinger)
  3. 强化 SELinux 安全控制,所有服务的 seclabel 必须在配置中明确指定,禁止隐式权限
相关推荐
事圆则缓28 分钟前
HTTP 请求是怎么走的:从 Android 页面到服务端响应
android·网络协议·http
美狐美颜SDK开放平台2 小时前
直播APP平台搭建需要哪些技术?视频美颜SDK只是其中一环
android·ios·音视频·直播美颜sdk·视频美颜sdk
AIsoft_86893 小时前
传统记录方式为什么越来越难满足需求?
android·iphone
小π军3 小时前
安卓、iOS、鸿蒙三端的理解
android·ios·harmonyos
BD_Marathon4 小时前
ChatPromptTemplate的高级特性
android·java·javascript
夜晚回家4 小时前
Python 变量入门详解 | 用 BMI 案例串起赋值、乘方与取整
android·python
程序猿追4 小时前
立方体转到九十度:用 kotlin-math 核对鸿蒙上的两种旋转
android·开发语言·kotlin
半调子的社畜4 小时前
记账 App 我装了删、删了装,最后自己写了一个:本地语音识别 + R8 踩坑复盘
android·ai编程
hunterandroid5 小时前
Android 运行时权限实战:从声明权限到拒绝后的可用降级
android
a5986525 小时前
docker-android 6080 端口访问失败?
android·docker·容器·云手机