Android init 语法包括了5类声明:Actions,Services,Commands,Options,和Imports。
所有这些语法都是以行为解析单位,中间需要以空格为语法间隔,行首有#的将被认为是注释而不会被解析.
section是init.rc中的基本组成单位,section分为两种类型:Actions和Services,所有的commands或者options都属于section的内容。在第一个section之前的所有commands或者options都将被忽略。
Actions和Sevices都有唯一的命名,如果有第二个Action名字和前面的相同,那么这两个Actions的所有commands都将合并在一起。如果有第二个Sevice和前面的相同,那么它将被忽略并且会记录下来一个出错log。
所有init语法都是用.rc文件来配置的,一个系统中会在不同的目录中存在很多个.rc文件。/init.rc是主rc文件并且被init执行文件第一个解析,平台相关的主入口是/init.${ro.hardware}.rc。它负责整个system的initial setup。
当执行mount_all命令时,init进程会加载所有/{system,vendor,odm}/etc/init/目录中的所有.rc文件。我们可以通过在mount_all命令中来修改或者扩展我们需要加载的.rc文件所在的目录。
不同etc/init目录一般包含不同内容:
(1)/system/etc/init/ 是包含core系统项目,比如surfaceflinger,mediaservice,logcatd相关的.rc配置
(2)/vendor/etc/init/是包含了SOC级别的.rc配置的
(3)/odm/etc/init/是包含了终端OEM厂商的项目配置
所有的services要根据自己bin文件所在的位置防止.rc配置文件到对应的etc/init/目录中。有一个编译宏命令可以用来帮助开发者做这件事情,那就是LOCAL_INIT_RC.
举个例子:
logcated.rc和Android.mk存在于/system/core/logcat目录中,在编译过程中,Android.mk中的LOCAL_INIT_RC命令会把logcated.rc移动到/system/etc/init目录中。
这种做法把不同服务需要的init命令给区分开了,放置于不同文件和目录中,这样更加方便维护和merge代码。
使用在mount_all命令中,有两个options “early”和“late”,如果设置了“–early”,init会跳过对“latemount”修饰的目录的挂载。如果设置了“–late”,init会只挂载被“latemount”修饰的目录,但除了import的.rc文件。默认情况下,没有设置以上两种option的话,mount_all会挂载fstab中所有的目录。
Actions
格式如下:
on <trigger> [&& <trigger>] *
<command>
<command>
<command>
Services
服务是一种程序,它由init来启动的并且当它退出时init也会restart。
格式如下:
service <name> <pathname> [ <argument> ]*
<option>
<option>
<option>
Options
选项是service的一些配置,他们应决定什么时间以什么方式来启动service。下面将介绍一些比较常见和关键的options。
class <name>
为服务指定一个class名字,同一个class中的所有的services将被同时启动或者同时停止。如果service没有制定这个option,那么它会被默认属于“default” 类型。
user <username>
执行service之前设置它的username,当前默认是root用户
group <groupname> [ <groupname> ]*
在启动service之前改变它的groupname,当前默认是root组。
setenv <name> <value>
在启动service的进程环境中设置环境变量
disabled
加入此option的service将不会由class的调用而自动启动,它需要被指名来启动。
critical
这个选项意味着这是一个设备相关的service,如果这种service在4分钟时间内反复退出了4次,那么设备将会重启并且进入recovery模式。
oneshot
当服务退出时不要重新restart它。
onrestart
当服务restart重启时,执行一个command。
Triggers
触发器是指一种事件来触发actions的执行。一般可以分成两种类型:event trigger和property trigger
Event trigger可以由“trigger”命令来产生,也可以有init程序中的“QueueEventTrigger()”函数来产生。一般需要一个简单的字符串作为参数,比如“boot”后者“late-init”。
Property trigger是在property改变时产生的一类事件。格式如下:“propety:=”或者“propety:=*”。
一个action可以有多个property trigger但是它只能有一个event trigger。
举例说明:
'on boot && property:a=b'
代表这这个action只能在boot 事件发生并且此时a=b的情况下才会执行。
'on property:a=b && property:c=d'
这个代表这action可以在三种情况下执行,
1)在boot阶段,a=b并且c=d
2)任何时间当a=b时,c的值被设置为和d相等
3)任何时间当c=d时,a的值被设置为和b相等
Commands
class_start <serviceclass>
启动一个class的services
class_stop <serviceclass>
停止一个class的services
class_reset <serviceclass>
停止一个class的services但是并不disable他们。
mount_all <fstab> [ <path> ]* [--<option>]
调用 fs_mgr_mount_all 挂载fstab并且imports对应目录下的 .rc files
exec [ <seclabel> [ <user> [ <group> ]* ] ] -- <command> [ <argument> ]*
执行命令
mount <type> <device> <dir> [ <flag> ]* [<options>]、
mount一个分区到一个目录中
umount <path>
unmount一个分区
trigger <event>
触发一个event事件
start <service>
开始一个service
stop <service>
停止一个service
restart <service>
重启一个service
setprop <name> <value>
设置一个系统prop
wait <path> [ <timeout> ]
等待一个path的生成,超时时间可以设定
write <path> <content>
写入path文件一个string
bootchart_init
如果配置了bootchart,那就开始bootcharting。这条命令是包含在default init.rc中的。
Imports
import并不是一个命令,它是导入.rc配置文件的关键字。当包含.rc的文件被解析完后init才会开始去解析被包含的.rc文件。
格式如下:
import <path>
如果path是一个文件,那么就按照文件来解析,如果是一个目录,就会把该目录中的所有.rc都进行解析一下。只在两个时间点会执行import操作:
1)当boot阶段加载ini.rc时
2)当mount_all后加载.rc时
debug
默认情况下,被init执行的程序会把stdout和stderr重定向到/dev/null。为了帮助debug,可以通过Android程序logwrapper。
example:
servcie akmd /system/bin/logwrapper /sbin/akmd
为了快速编译,可以使用如下命令:
mm -j
m ramdisk-nodeps
m bootimage-nodeps
adb reboot bootloader
fastboot boot $ANDROID_PRODUCT_OUT/boot.img