3.4.5 解析Action
1.parse_action
解析Action首先从parse_action函数开始,代码如下:
static void parse_action(struct parse_state state, int nargs, charargs)
{
struct action act;
……//省略错误处理内容
act = calloc(1, sizeof(act));
act->name = args[1];
list_init(&act->commands);
/将Action的指针节点放入action_list中/
list_add_tail(&action_list, &act->alist);
return act;
}
从parse_action函数的代码可以看出,解析Action的过程与解析Service的过程十分相似。首先给新创建的Action分配存储空间,然后将Action的指针节点放入一个action_list列表中。这里又涉及两个重要的数据类型:action结构体和action_list链表。
action_list与service_list都是由list_declare宏声明,即static list_declare(action_list)。
action结构体定义在/system/core/init/init.h中,代码如下:
struct action {
/这个指针节点所在的链表存储了所有Action的指针节点 /
struct listnode alist;
/这个指针节点所在的链表存储了所有即将执行的Action的指针节点/
struct listnode qlist;
/这个指针节点所在的链表存储了所有要触发的Action的指针节点/
struct listnode tlist;
unsigned hash;
const charname;
/Action对应的Command/
struct listnode commands;
struct command current;
};
2.parse_line_action
熟悉了Action的存储形式,接着分析Action的解析过程。定位到parse_line_action函数,该函数位于init_parser.c中,代码如下:
static void parse_line_action(struct parse_state state, int nargs, charargs)
{
struct command cmd;
/通过state结构体得到当前Action的引用/
struct action *act = state->context;
int (func)(int nargs, charargs);
int kw, n;
/依然是根据关键字匹配,不过这次匹配的是Command /
kw = lookup_keyword(args[0]);
n = kw_nargs(kw);
……//省略错误处理内容
cmd = malloc(sizeof(cmd) + sizeof(char) nargs);
cmd->func = kw_func(kw);//获取Command对应的指令函数
cmd->nargs = nargs;
memcpy(cmd->args, args, sizeof(char)nargs);
/将Command加入Action的Command列表/
list_add_tail(&act->commands, &cmd->clist);
parse_line_action函数的执行过程很清晰,要比parse_line_service简单很多。
这里涉及一个重要的数据类型struct command。command结构体定义在/system/core/init/init.h中,代码如下:
struct command
{
/ list of commands in an action /
struct listnode clist;
/ command对应的执行函数/
int (func)(int nargs, charargs);
int nargs;
char args[1];
};
至此,init.rc的解析过程便告一段落。接下来开始分析Action和Service的执行阶段。