Android init启动分析(2)init.rc解析处理
1. 前言
基于上一篇继续说明
https://www.ebaina.com/articles/140000012378
2. init.rc目录结构
system/core/rootdir/
├── Android.mk
├── etc
│ ├── hosts
│ ├── init.testmenu
│ └── mountd.conf
├── init.environ.rc.in
├── init.rc
├── init.trace.rc
├── init.usb.rc
├── init.zygote32_64.rc
├── init.zygote32.rc
├── init.zygote64_32.rc
├── init.zygote64.rc
└── ueventd.rc
Android 在system/core/init/readme.txt 文件中对rc脚本语言规则进行了说明.rc脚本主要包括了
Actions, Commands, Services, 和Options 4种类型声明.
Init.rc文件基本组成单位是section.,有Actions和Services、Import三种类型。
3. init.rc脚本格式
(1)Actions
Android rc脚本文件中Action,以关键字on开始,在关键字on和下一个关键字on之间为一个section;Action中关键字on后面的字符串是trigger,用于决定Action执行的时机.Action被执行时,其中的Command也会被逐一运行. Actions格式如下:
on <trigger>
<command>
<command>
<command>
struct action {
struct listnode alist; /* actions链表节点 */
struct listnode qlist; /*等待执行的actions链表节点 */
struct listnode tlist; /* trigger 链表*/
unsigned hash;
const char *name;
struct listnode commands; /* commands链表,用于挂载Action中所有的命令 */
struct command *current; /*当前正在被执行的command命令*/
};
(2)Service
Android rc脚本文件中Service是一个后台程序,Options是Service的一个参数项,用于决定Service运行时机以及如何运行,Service格式如下
service <name> <pathname> [ <argument> ]*
<option>
<option>
...
Inir进程中解析init.rc脚本中service section内容保存在struct service结构体实例中,结构体如下:
truct service {
struct listnode slist; //插入全局链表service_list的节点list
const char *name; //服务名称
const char *classname; //服务类名称,默认是“default“
unsigned flags; //服务keyword关键字类型
pid_t pid;
time_t time_started; /* time of last start */
time_t time_crashed; /* first crash within inspection window */
int nr_crashed; /* number of times crashed within window */
uid_t uid;
gid_t gid;
gid_t supp_gids[NR_SVC_SUPP_GIDS];
size_t nr_supp_gids;
char *seclabel;
struct socketinfo *sockets;
struct svcenvinfo *envvars; //服务env环境变量
struct action onrestart; // 服务重启时需要执行的命令
int *keycodes;
int nkeycodes;
int keychord_id;
int ioprio_class;
int ioprio_pri;
int nargs; //参数个数
char *args[1]; //服务值args[0]为脚本内容中第三个参数;args[1] = 0
};
(3)import 关键字
在一个.rc文件中引入其他的都rc文件.
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.${ro.zygote}.rc
import /init.trace.rc
实际在根目录下存在的*.rc文件如下
init.common.rc
init.debug.rc
init.environ.rc
init.rc
init.recovery.sun50iw1p1.rc
init.sun50iw1p1.rc
init.sun50iw1p1.usb.rc
init.trace.rc
init.usb.rc
init.zygote32.rc
ueventd.rc
ueventd.sun50iw1p1.rc
init.rc import section
init.rc import section的解析主要在system/core/init/init_parser.c文件的parse_config()函数尾部,import解析内容会通过import结构体添加到import_list中,再次执行解析流程
static void parse_config(const char *fn, char *s)
{
... .... .... .....
parser_done:
list_for_each(node, &import_list) {
struct import *import = node_to_item(node, struct import, list);
... .... .... .....
ret = init_parse_config_file(import->filename);
if (ret)
ERROR("could not import file '%s' from '%s'\n",
import->filename, fn);
}
}
4. init.rc 解析
init.rc解析流程,解析的主函数在system/core/init/init_parser.c文件中:
static void parse_config(const char *fn, char *s)
{
struct parse_state state;
struct listnode import_list;
... ... ...
list_init(&import_list);
state.priv = &import_list;
for (;;) {
switch (next_token(&state)) {
... ... ...
case T_NEWLINE:
state.line++;
if (nargs) {
int kw = lookup_keyword(args[0]);
if (kw_is(kw, SECTION)) {
state.parse_line(&state, 0, 0);
parse_new_section(&state, kw, nargs, args);
} else {
state.parse_line(&state, nargs, args);
}
... ... ...
parser_done:
list_for_each(node, &import_list) {
struct import *import = node_to_item(node, struct import, list);
ret = init_parse_config_file(import->filename);
... ... ...
}
}
parse_config主要完成以下步骤:
a.初始化state,将*.rc文件名称和文件内容分别保存在state. filename和state.ptr变量中。初始化import_list链表,链表指针保存在state.priv变量中;
b.通过next_token()函数检查每一行内容,分别返回T_EOF、T_NEWLINE和T_TEXT三种状态,分别为文件内容结束、文件内容换行和被空格隔开的参数三种类型;
c.针对T_NEWLINE类型,解析上一行脚本内容args[0]第一次参数,判断命令类型,如果是K_service、K_on和K_import类型,则调用parse_new_section进入新的section解析流程;
d.如果是K_service,调用parse_service( )动态创建struct service 类型内存区svc。初始化svc成员onrestart.name默认为"onrestart",初始化svc->onrestart.commands链表,用于挂载服务重启时执行的命令。将服务插入service_list全局链表中。最后将svc指针返回给state->context,state->parse_line指向parse_line_service( )函数,用于后面解析service section中的options参数。
e.如果是K_on,调用parse_action()动态初始化struct action 类型内存区act,初始化commands链表和qlist链表,将act插入到action_list全局链表中。最后将act指针返回给state->context,state->parse_line指向parse_line_action() 函数,用于解析Action section中的command命令,并插入act->commands链表中;
f.如果是K_import,调用parse_import(),动态创建struct import 类型内存区import,初始化filename,将import插入到import_list全局链表中。
5. init.rc 执行
- 分享
- 举报
-
浏览量:4620次2021-04-15 14:56:16
-
浏览量:5675次2020-12-23 09:56:49
-
浏览量:833次2023-08-30 10:00:35
-
浏览量:3452次2019-12-05 18:03:06
-
浏览量:6516次2021-01-08 15:16:17
-
浏览量:578次2024-01-25 13:00:44
-
浏览量:2435次2020-09-30 18:11:55
-
浏览量:6944次2021-01-22 15:28:47
-
浏览量:994次2023-12-01 12:14:35
-
浏览量:8584次2020-12-12 15:02:16
-
浏览量:1082次2023-11-29 12:31:57
-
浏览量:4879次2022-10-14 08:34:42
-
浏览量:5490次2020-10-15 16:38:57
-
浏览量:1463次2024-01-25 16:21:59
-
浏览量:1188次2024-03-15 09:51:11
-
浏览量:4843次2021-03-26 16:03:04
-
浏览量:3788次2020-08-19 16:34:45
-
浏览量:1295次2023-12-04 13:11:50
-
浏览量:7140次2021-01-16 14:52:44
-
广告/SPAM
-
恶意灌水
-
违规内容
-
文不对题
-
重复发帖
free-jdx
感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明