1. 引言
在 Android 系统中,.rc 文件是 init 进程的启动配置文件,它定义了系统启动过程中需要创建的服务、执行的动作、设置的系统属性等。理解 .rc 语法是阅读 Android 源码、定制系统启动流程的基础。本文将系统梳理 .rc 文件的语法规则,并结合源码实例进行讲解。
2. .rc 文件概述
.rc 文件是 Android init 进程解析的脚本文件,采用类似 C 语言的行式语法。它由若干语句组成,每条语句以关键字开头,后跟参数,语句之间以换行分隔。
2.1 文件位置
- 系统核心服务:
/system/core/rootdir/init.rc - 硬件相关:
/device/<厂商>/<设备>/init.<设备>.rc - 分区相关:
/system/etc/init/目录下的.rc文件
2.2 基本结构
text
# 注释以 # 开头
on <触发器>
命令1
命令2
service <服务名> <可执行文件路径>
<选项>
3. 基础语法元素
3.1 注释
以 # 开头,支持行尾注释:
text
# 这是注释
service zygote /system/bin/app_process # 行尾注释
3.2 续行
使用反斜杠 \ 进行续行:
text
on boot
setprop ro.boot.hardware \
qcom
3.3 关键字
.rc 文件的核心关键字分为三类:
| 类别 | 关键字 |
|---|---|
| 动作 | on、service |
| 命令 | start、stop、setprop、mkdir、chmod、chown、mount、write、exec、symlink、insmod 等 |
| 选项 | class、user、group、oneshot、disabled、socket、seclabel、critical 等 |
4. on 触发器与动作
on 语句定义了一组在特定触发条件下执行的命令:
text
on <触发器>
命令
4.1 常见触发器
| 触发器 | 触发时机 |
|---|---|
early-init |
init 进程早期初始化 |
init |
init 进程主初始化阶段 |
boot |
系统属性 ro.boot.bootreason 设置后 |
property:<属性名>=<值> |
指定属性被设置时 |
post-fs |
文件系统挂载完成后 |
post-fs-data |
data 分区挂载完成后 |
zygote-start |
zygote 启动前 |
4.2 示例
text
on boot
setprop sys.usb.config none
start servicemanager
text
on property:sys.boot_completed=1
start bootanim
5. service 服务定义
service 语句定义一个由 init 管理的守护进程:
text
service <服务名> <可执行文件> [参数...]
<选项>
5.1 示例
text
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
user root
group root readproc
socket zygote stream 660 root system
seclabel u:r:zygote:s0
5.2 常用选项
| 选项 | 说明 |
|---|---|
class <名称> |
服务所属类别,可用 class_start 批量启动 |
user <用户名> |
运行服务的用户 |
group <组名> |
运行服务的组 |
oneshot |
服务退出后不自动重启 |
disabled |
服务默认不启动,需手动 start |
socket <名称> <类型> <权限> <用户> <组> |
创建 socket |
seclabel <标签> |
设置 SELinux 标签 |
critical |
服务崩溃导致系统重启 |
onrestart <命令> |
服务重启时执行的命令 |
6. 常用命令详解
6.1 属性操作
text
setprop <属性名> <值>
getprop <属性名>
6.2 文件系统操作
text
mkdir /data/local 0755
chmod 0755 /system/bin/foo
chown root system /dev/foo
mount ext4 /dev/block/mmcblk0p1 /data
symlink /system/etc/foo /etc/foo
6.3 服务控制
text
start <服务名>
stop <服务名>
class_start <类别名>
class_stop <类别名>
6.4 执行命令
text
exec /system/bin/foo --arg
exec_start <服务名>
6.5 写入文件
text
write /sys/class/leds/lcd/brightness 100
7. 完整实例分析
以下是一个典型的自定义服务 .rc 文件:
text
# 自定义守护进程
on property:persist.demo.enable=1
start demo_service
service demo_service /system/bin/demo_daemon
class main
user system
group system
oneshot
seclabel u:r:demo_daemon:s0
socket demo stream 0660 system system
7.1 解析
- 当属性
persist.demo.enable被设置为1时,触发start demo_service。 demo_service以system用户身份运行,属于main类别。- 服务退出后不自动重启(
oneshot)。 - 创建名为
demo的流式 socket,权限0660。
8. 源码中的实际应用
在 Android 源码中,init.rc 位于 system/core/rootdir/ 目录。以 zygote 服务为例:
text
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
user root
group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
这段配置表明:zygote 属于 main 类别,以 root 身份运行,创建 zygote socket,并在重启时联动重启多个媒体相关服务。
9. 调试与验证
9.1 查看服务状态
bash
adb shell ps -A | grep <服务名>
9.2 手动启动服务
bash
adb shell start <服务名>
9.3 查看 init 日志
bash
adb logcat -s init
9.4 检查语法错误
bash
adb shell init --help
10. 总结
.rc 文件是 Android 启动流程的核心配置,掌握其语法有助于:
- 理解系统启动顺序
- 定制开机服务
- 调试启动问题
- 阅读和修改 AOSP 源码
建议读者结合 system/core/init/ 目录下的解析器源码(parser.cpp、service.cpp)深入理解 .rc 的解析逻辑,从而更全面地掌握 Android 启动机制。