//\system\core\init\init_parser.c
int lookup_keyword(const char *s)
{
switch (*s++) {
case 'c':
if (!strcmp(s, "opy")) return K_copy;
if (!strcmp(s, "apability")) return K_capability;
if (!strcmp(s, "hdir")) return K_chdir;
if (!strcmp(s, "hroot")) return K_chroot;
if (!strcmp(s, "lass")) return K_class;
if (!strcmp(s, "lass_start")) return K_class_start;
if (!strcmp(s, "lass_stop")) return K_class_stop;
if (!strcmp(s, "lass_reset")) return K_class_reset;
//......
}
return K_UNKNOWN;
}
由此段程序代码可以发现此函数会根据存入的字符串先由字符串的第一个字符做分类, 再去比较之后的字符去回传相对应的K_xxx.之后再将keyword传入kw_is作判断,Google在这里的判断设计kw_is会利用macro而不是用一般的函数去实作, 一是因为这个判断动作只有单纯的做比对,另外一点就是会少一次functioncall stack的效能以加快执行速度.
//system\core\init\init_parser.c
#define kw_is(kw, type) (keyword_info[kw].flags & (type))
这里会发现是用keyword_info数组中的元素所带出来的flags跟type作&比较.
//system\core\init\init_parser.c
#define KEYWORD(symbol, flags, nargs, func) \
[ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
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"
};
//system\core\init\keywords.h
//...
KEYWORD(capability, OPTION, 0, 0)
KEYWORD(chdir, COMMAND, 1, do_chdir)
KEYWORD(chroot, COMMAND, 1, do_chroot)
KEYWORD(class, OPTION, 0, 0)
KEYWORD(class_start, COMMAND, 1, do_class_start)
KEYWORD(class_stop, COMMAND, 1, do_class_stop)
KEYWORD(class_reset, COMMAND, 1, do_class_reset)
KEYWORD(console, OPTION, 0, 0)
//....
由上面便可以知道keyword_info是一个Mappingtable. 每一个lookup_keyword 函数所回传的keyword K_xxx对应一个函数do_xxx.
因此便可以再从parse_config函数中的呼叫lookup_keyword继续分析下去.
// system\core\init\init_parser.c
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);
}
由之前针对lookup_keyword和kw_is的分析就可以知道, 这里是要从init.rc中捞出keyword再利用kw_is的判断来做不同parser方式. 由上面的程序代码可以知道, 只有在keyword_infomapping table中有SECTION flag, 才会有新的list. 而在(android4.2)目前的版本中从keywords.h所有的KEYWORD可知道, 有SECTIONflag对应到的字符只有import, on, service. 撇开import字符是用来作类似include的动作之外,on跟service就是用来建立之前所提的actionlist和service list. 接下来分析parse_new_section函数
//system\core\init\init_parser.c
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;
}
由于在执行流程分析中, execute_one_command函数就只有用来执行action list上面的command,所以就从parse_action函数来分析.
//system\core\init\init_parser.c
static void *parse_action(struct parse_state *state, int nargs, char **args)
{
struct action *act;
if (nargs < 2) {
parse_error(state, "actions must have a trigger\n");
return 0;
}
if (nargs > 2) {
parse_error(state, "actions may not have extra parameters\n");
return 0;
}
act = calloc(1, sizeof(*act));
act->name = args[1];
list_init(&act->commands);
list_add_tail(&action_list, &act->alist);
/* XXX add to hash */
return act;
}
由上面的程序代码可以知道, action list就是由一串act 元素所建立起来的linkedlist. 一旦action list有了新的act 元素, 接下来就执行parse_line_action函数
//system\core\init\init_parser.c
static void parse_line_action(struct parse_state* state, int nargs, char **args)
{
struct command *cmd;
struct action *act = state->context;
int (*func)(int nargs, char **args);
int kw, n;
if (nargs == 0) {
return;
}
kw = lookup_keyword(args[0]);
if (!kw_is(kw, COMMAND)) {
parse_error(state, "invalid command '%s'\n", args[0]);
return;
}
n = kw_nargs(kw);
if (nargs < n) {
parse_error(state, "%s requires %d %s\n", args[0], n - 1,
n > 2 ? "arguments" : "argument");
return;
}
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(&act->commands, &cmd->clist);
}