一、基本框架
init.rc是一个纯文本文件,我们需要程序去解析init.rc,然后交给程序运行,解析init.rc的过程就是识别一个个section的过程,将各个section的信息保存下来,然后在init.c的main()中去执行一个个命令。
android采用双向链表来存储section的信息,解析完成之后,会得到三个双向链表action_list、service_list、import_list来分别存储三种 的信息。
二、c语言实现
1:init.c中调用init_parse_config_file("/init.rc")
int init_parse_config_file(const char *fn)
{
char *data;
data = read_file(fn, 0);//读文件数据
if (!data) return -1;
parse_config(fn, data);//解析数据
DUMP();
return 0;
}
2:parse_config
static void parse_config(const char *fn, const std::string& data)
{
struct listnode import_list;
struct listnode *node;
char *args[INIT_PARSER_MAXARGS];
int nargs = 0;
parse_state state;
state.filename = fn;
state.line = 0;
state.ptr = strdup(data.c_str()); // TODO: fix this code!
state.nexttoken = 0;
state.parse_line = parse_line_no_op;
list_init(&import_list);
state.priv = &import_list;
for (;;) {
switch (next_token(&state)) { //next_token()根据从state.ptr开始遍历
case T_EOF: //遍历到文件结尾,然后goto解析import的.rc文件
state.parse_line(&state, 0, 0);
goto parser_done;
case T_NEWLINE: //到了一行结束
state.line++;
if (nargs) {
int kw = lookup_keyword(args[0]); // 找到这一行的关键字
if (kw_is(kw, SECTION)) { // 如果这是一个section的第一行
state.parse_line(&state, 0, 0);
parse_new_section(&state, kw, nargs, args);
} else { //如果这不是一个section的第一行
state.parse_line(&state, nargs, args);
}
nargs = 0;
}
break;
case T_TEXT: // 遇到普通字符
if (nargs < INIT_PARSER_MAXARGS) {
args[nargs++] = state.text;
}
break;
}
}
parser_done:
list_for_each(node, &import_list) {
struct import *import = node_to_item(node, struct import, list);
int ret;
ret = init_parse_config_file(import->filename);
if (ret)
ERROR("could not import file '%s' from '%s'\n",
import->filename, fn);
}
}
next_token() 解析完init.rc中一行之后,会返回T_NEWLINE,这时调用lookup_keyword函数来找出这一行的关键字, lookup_keyword返回的是一个整型值(枚举类型),对应keyword_info[]数组的下标,keyword_info[]存放的是keyword_info结构体类型的数据,
struct {
const char *name; //关键字的名称
int (*func)(int nargs, char **args); //对应的处理函数
unsigned char nargs; //参数个数
unsigned char flags; //flag标识关键字的类型,包括COMMAND、OPTION、SECTION
} keyword_info
keyword_info[]中存放的是所有关键字信息,每一项对应一个关键字;
根据每一项的flags就可以判断出关键字的类型,如新的一行是SECTION,就调用parse_new_section()来解析这一行, 如新的一行不是一个SECTION的第一行,那么调用state.parseline()来解析(state.parseline所对应的函数会根据section类型的不同而不同),在parse_new_section()中进行动态设置。
static void parse_new_section(struct parse_state *state, int kw,
int nargs, char **args)
{
printf("[ %s %s ]\n", args[0],
nargs > 1 ? args[1] : "");
switch(kw) {
case K_service: //解析service
state->context = parse_service(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_service; //Service 对应的parse_line
return;
}
break;
case K_on://解析 on 开头的action
state->context = parse_action(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_action; //action 对应的parse_line
return;
}
break;
case K_import: //解析import
parse_import(state, nargs, args);
break;
}
state->parse_line = parse_line_no_op;
}
鉴于篇幅原因,使用文字描述parse_service过程,parse_action,parse_import解析也是类似的:
parse_service函数会去service_list链表查找有没有该命名的service(svc = service_find_by_name(args[1]);),如果没有则会构造service 对象并添加到service_list链表中,返回该service 对象;但是这个service 没有Options,然后通过parse_line_service 解析Options选项填充service 对象;
2.2.3、init.rc中配置的service 启动流程:
/system/core/rootdir/init.rc
class_start core
on nonencrypted
class_start main
class_start late_start
/system/core/init/keywords.h
KEYWORD(class_start, COMMAND, 1, do_class_start)
/system/core/init/builtins.c
int do_class_start(int nargs, char **args)
{
/* Starting a class does not start services
* which are explicitly disabled. They must
* be started individually.
*/
service_for_each_class(args[1], service_start_if_not_disabled);
return 0;
}
/system/core/init/init_parser.cpp
void service_for_each_class(const char *classname,
void (*func)(struct service *svc))
{
struct listnode *node;
struct service *svc;
list_for_each(node, &service_list) {
svc = node_to_item(node, struct service, slist);
if (!strcmp(svc->classname, classname)) {
func(svc);
}
}
}
/system/core/init/builtins.cpp
static void service_start_if_not_disabled(struct service *svc)
{
if (!(svc->flags & SVC_DISABLED)) {
service_start(svc, NULL);
} else {
svc->flags |= SVC_DISABLED_START;
}
}
/system/core/init/init.c
void service_start(struct service *svc, const char *dynamic_args)
{
struct stat s;
pid_t pid;
int needs_console;
int n;
char *scon = NULL;
int rc;
/* starting a service removes it from the disabled or reset
* state and immediately takes it out of the restarting
* state if it was in there
*/
......
pid = fork();//fork 子进程
......
for (si = svc->sockets; si; si = si->next) {
int socket_type = (
!strcmp(si->type, "stream") ? SOCK_STREAM :
(!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));//判断socket 类型
int s = create_socket(si->name, socket_type,
si->perm, si->uid, si->gid, si->socketcon ?: scon);//创建socket对应的fd
if (s >= 0) {
publish_socket(si->name, s);//发布socket的fd,即将create_socket返回的fd添加到
//以"ANDROID_SOCKET_"为前缀的环境变量;
//Zygote的socket的key 为ANDROID_SOCKET_zygote,也是在这创建的;
}
}
......
init.rc 语法与解析 - 简书
Android底层开发_哔哩哔哩_bilibili