主要是通过该函数实现解析:在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; }
static void parse_config(const char *fn, char *s) { struct parse_state state; struct listnode import_list; struct listnode *node; char *args[INIT_PARSER_MAXARGS]; int nargs; nargs = 0; state.filename = fn; state.line = 0; state.ptr = s; state.nexttoken = 0; state.parse_line = parse_line_no_op; list_init(&import_list); state.priv = &import_list; for (;;) { switch (next_token(&state)) { case T_EOF: 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)) { state.parse_line(&state, 0, 0); parse_new_section(&state, kw, nargs, args); } else { 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; INFO("importing '%s'", import->filename); ret = init_parse_config_file(import->filename); if (ret) ERROR("could not import file '%s' from '%s'\n", import->filename, fn); } }
#include "keywords.h" #define KEYWORD(symbol, flags, nargs, func) \ [ K_##symbol ] = { #symbol, func, nargs + 1, flags, }, static struct { const char *name; int (*func)(int nargs, char **args); unsigned char nargs; unsigned char flags; } keyword_info[KEYWORD_COUNT] = { [ K_UNKNOWN ] = { "unknown", 0, 0, 0 }, #include "keywords.h" }; #undef KEYWORD
在keywords.h中,将关键字分成了三类,分别是:Section、Command、Option.以init.rc中的一段来看parser_config函数是如何解析的。其中三个关键字被分类为Section:import,on,service
service servicemanager /system/bin/servicemanager class core user system group system critical onrestart restart healthd onrestart restart zygote onrestart restart media onrestart restart surfaceflinger onrestart restart drm
第一次执行next_token()出来,case t_text,此时,nargs = 1, args[0] = service
第二次执行next_token()出来,case t_text,此时, nargs =2, args[0] = service, args[1] = servicemanager,
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: state->context = parse_service(state, nargs, args); if (state->context) { state->parse_line = parse_line_service; return; } break; case K_on: state->context = parse_action(state, nargs, args); if (state->context) { state->parse_line = parse_line_action; return; } break; case K_import: parse_import(state, nargs, args); break; } state->parse_line = parse_line_no_op; }
对于service和action,其实就是实例化一个service和action的结构体,添加到service的list和action的list里面去,并且将parse_line函数转换成对应的prase_line_action/service函数;对于import,则是将import的路径,以及import的文件名保存到import的list里面去。
对于service,parse_new_section的主要做了两件事:1、实例化一个service添加到service的list中;2、将prase_line函数赋值成prase_line_service.
对于class这种属于Option分类的,是用来补充service的信息的。
case K_class: if (nargs != 2) { parse_error(state, "class option requires a classname\n"); } else { svc->classname = args[1]; } break;
对于onrestart是属于Option分类,后面接的是Command,用来表示重启要做什么动作。
case K_onrestart: nargs--; args++; //kw是restart kw = lookup_keyword(args[0]); if (!kw_is(kw, COMMAND)) { parse_error(state, "invalid command '%s'\n", args[0]); break; } kw_nargs = kw_nargs(kw); if (nargs < kw_nargs) { parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1, kw_nargs > 2 ? "arguments" : "argument"); break; } cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs); cmd->func = kw_func(kw); cmd->nargs = nargs; memcpy(cmd->args, args, sizeof(char*) * nargs); list_add_tail(&svc->onrestart.commands, &cmd->clist); break;
service有一个Command的list,专门用来保存onrestart要做的操作。
对于Action和Service类型的Section,其解析的流程都是类似的,解析的过程就是讲init.rc中的配置,映射到c++中的对象。
对于import类型的Section,其解析的流程就是将import文件的路径和文件名,保存到import_list
static void parse_import(struct parse_state *state, int nargs, char **args) { struct listnode *import_list = state->priv; struct import *import; char conf_file[PATH_MAX]; int ret; if (nargs != 2) { ERROR("single argument needed for import\n"); return; } //展开属性,对于变量(即通过$引用的,找到它实际的值,替换进去,保存对应的路径) ret = expand_props(conf_file, args[1], sizeof(conf_file)); if (ret) { ERROR("error while handling import on line '%d' in '%s'\n", state->line, state->filename); return; } import = calloc(1, sizeof(struct import)); import->filename = strdup(conf_file); list_add_tail(import_list, &import->list); INFO("found import '%s', adding to import list", import->filename); }
本文件解析完成之后,再对import的文件进行同样的解析。
parser_done: list_for_each(node, &import_list) { struct import *import = node_to_item(node, struct import, list); int ret; INFO("importing '%s'", import->filename); ret = init_parse_config_file(import->filename); if (ret) ERROR("could not import file '%s' from '%s'\n", import->filename, fn); } }