3.4.5 解析Action

1.parse_action

解析Action首先从parse_action函数开始,代码如下:


static voidparse_action(struct parse_statestate, int nargs, char**args)

{

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 char*name;

/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_statestate, int nargs, char*args)

{

struct command*cmd;

/通过state结构体得到当前Action的引用/

struct action*act=state->context;

int(func)(int nargs, char*args);

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(charnargs);

/将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, char*args);

int nargs;

char*args[1];

};


至此,init.rc的解析过程便告一段落。接下来开始分析Action和Service的执行阶段。