继续上一节的分析步骤
(二)、init.rc配置文件解析(system/core/rootdir/init.rc)
1、Android Init Language(Android初始化语言)
这里参照初始化语言的语法说明文档system/core/init/Readme.txt,介绍下Android初始化语言的语法知识。
(1)、基本约定
- init由四类基本语句组成:Actions、Commands、Services、Options。
- 所有类型的语句都是基于行的,每行都有若干个tokens组成,token之间以空格分开。如果一个token之间需要使用空格,则使用转义字符反斜线(‘\’)来转义,或者是使用双引号把整个token括起来。如果反斜线出现在行尾,表示下一行仍然是当前行。
- 以“#”开始的行是注释行。
- 动作(Actions)和服务(Services)表示一个新的段落(section)的开始,所有的指令(commands)和选项(options)归属于上方最近的一个段落。第一个段落之前的commands或options没有任何意义。
- 动作(Actions)和服务(Services)拥有唯一的名字,如果出现重名,后面出现的将被作为错误忽略掉。
(2)、基本语法
Android初始化语言定义了六个基本概念:Section、Action、Service、Trigger、Command、Option;两个基本关键字:on、service、import;一些指令关键字。
- Command:是最小的功能单元,表示一条Linux命令或一个函数的调用。
- Trigger:表示一个触发条件,用来触发Action的执行,也可以表示一个Action的名称。
- Option:是Service的修饰符,用来指定何时、如何启动Service程序。
- on:关键字on用来声明一个Action。
- service:关键字service用来声明一个Service。关键字的定义在system/core/init/Keywords.h中声明。
- Action:一个Action由关键字on声明、由Trigger触发的一组Command序列。
- Service:每一个Service都是init进程的子进程,由关键字service、服务名、服务对应的命令的路径、命令的参数、Option组成,代表一些在初始化阶段启动的程序。
- section:init.rc文件的基本组成单位就是section;每个Action或Service隐含表示一个section,每个section表示一个完整的功能。
- import:代表一个section,表示引入另外一个.rc文件。
Action格式如下,其中on是声明Action的关键字,trigger是Action的触发条件,command是Action要执行的命令。
on <trigger>
<command>
<command>
<command>
举例说明:
on early-init
# Set init and its forked children's oom_adj.
write /proc/1/oom_score_adj -1000
# Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
write /sys/fs/selinux/checkreqprot 0
# Set the security context for the init process.
# This should occur before anything else (e.g. ueventd) is started.
setcon u:r:init:s0
# Set the security context of /adb_keys if present.
restorecon /adb_keys
start ueventd
# create mountpoints
mkdir /mnt 0775 root system
由这个Action表示的section是一个整体,因此组成Action的command是一起执行的。那么在什么时候执行呢?是有init.c的main函数决定的,main函数会在某个时刻调用action_for_each_trigger("early-init", action_add_queue_tail)函数,这样就会把这个Action里的所有命令加入到一个执行队列中,在某个时候会顺序执行队列了的命令。
Service格式如下,其中service是声明Service的关键字,name是Service的名字,pathname是Service所要执行的命令的路径,option是服务的启动配置参数。
service <name> <pathname> [ <argument> ]*
<option>
<option>
举例说明:
service bootanim /system/bin/bootanimation
user graphics
group graphics
disabled
oneshot # oneshot表示一个option
这里是一个Service表示的section,bootanim是服务名,/system/bin.bootanimation是bootanim服务执行的命令路径,oneshot表示这个服务只执行一次,如果没有该option,表示这个服务会一直存在,如果这个服务被杀死,则会重新启动。
import也表示一个section,import表示引入另外一个.rc文件。相当于包含另外一些section,在解析完init.rc后继续调用init_parse_config_file函数来解析引入的.rc文件。例如:
import /init.${ro.hardware}.rc
import /init.${ro.zygote}.rc
2、init.rc内容
(1)、init启动ServiceManager进程,这个进程主要负责系统服务的注册管理,包括“java系统服务”,“本地系统服务”。
serviceservicemanager/system/bin/servicemanager
class core #class关键字声明的Option,该Service属于core类别
user system # user关键字声明的Option,该Service属于system用户
group system
critical #critical关键字声明的Option,该Service在4分钟内重启4次,将导致系统重启进入recovery模式
onrestart restart healthd #onrestart关键字声明的Option,指定该Service重启后要执行的Command,restart zygote 是一个Command,restart对应的处理函数是do_restart
onrestart restart zygote
onrestart restart media
onrestart restart surfaceflinger
onrestart restart drm
(2)、init启动Media Server进程,这个进程负责启动C/C++的“本地系统服务”。
service media /system/bin/mediaserver
class main
user media
group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
ioprio rt 4 #设置io优先级
(3)、init启动Zygote进程,这个进程启动SystemServer进程,从而启动“java系统服务”,包括PowerManagerService,SensorService等。
自从Android5.0开始创建zygote进程脚本是在Init.zygote**.rc里的(import /init.${ro.zygote}.rc),这是因为Android L支持64为的app,所以又起了一个Zygote64来专门负责64为APK的孵化。
init.rc对Zygote服务的section声明是在Init.zygote32.rc或Init.zygote64.rc或Init.zygote32_64.rc或Init.zygote64_32.rc中进行的(system/core/rootdir/),64位的芯片通常会使用system/core/rootdir/init.zygote64_32.rc。
servicezygote/system/bin/app_process64-Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
servicezygote_secondary/system/bin/app_process32-Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
socket zygote_secondary stream 660 root system
onrestart restart zygote
启动zygote进程时,传递参数-Xzygote /system/bin --zygote --start-system-server --socket-name=zygote。
3、init解析过程
在init.c的main函数中调用 init_parse_config_file("/init.rc"),表示开始解析init.rc配置文件,该函数位于system/core/init/Init_parser.c中。
int init_parse_config_file(const char *fn)
{
char *data;
/* 调用open、read、malloc读取配置文件init.rc的内容到buffer,并配合struct stat记录文件状态,主要记录的是文件大小,保存到read_file的第二个参数,这里传入0,表示不带回文件大小。 */
data = read_file(fn, 0);
if (!data) return -1;
parse_config(fn, data); /* 开始解析 init.rc */
DUMP(); /* DUMP()位于/system/core/init/parser.c中,用于输出service_list和action_list中存储的Service和Action。调试的时候很大,默认是关闭的。 */
return 0;
}
读取完配置文件的内容后,将调用parse_config进行解析。