安卓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 必须在配置中明确指定,禁止隐式权限
相关推荐
千里马学框架2 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台2 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone2 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc2 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo2 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077002 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼2 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone3 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen3 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone3 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui