Android启动流程分析(九) 解析init.rc的service

#############################################

本文为极度寒冰原创,转载请注明出处

#############################################

在分析完解析init.rc的action之后,剩下的一部分就是解析service了。

而解析service还是需要回到parse_config里面来。根据前面的知识,我们也可以很容易的知道在关键字为section的时候,会进入到parse_new_section。

这里会先执行parse_service,然后将service以及后面跟的option设置为执行parse_line:parse_line_service。

要理解service的解析流程的话,首先要关注的就是service的结构体。

struct service {/* list of all services */struct listnode slist; // listnode slistconst char *name;// nameconst char *classname; // 默认值为defultunsigned flags;// 选项pid_t pid;// Service所在进程的PIDtime_t time_started; /* time of last start */time_t time_crashed; /* first crash within inspection window */int nr_crashed;/* number of times crashed within window */uid_t uid;// effective user IDgid_t gid;// effective group IDgid_t supp_gids[NR_SVC_SUPP_GIDS]; // supplementary idssize_t nr_supp_gids;// supp_gids的大小char *seclabel;struct socketinfo *sockets; // 为service创建的Socketsstruct svcenvinfo *envvars; // 为service设置的环境变量struct action onrestart; /* Actions to execute on restart. *//* keycodes for triggering this service via /dev/keychord */int *keycodes;int nkeycodes;int keychord_id;int ioprio_class;int ioprio_pri;int nargs;/* "MUST BE AT THE END OF THE STRUCT" */char *args[1];}; /*^——-'args' MUST be at the end of this struct! */

这个结构体相比较而言就比较简单了,除了service的本身属性以外,对于数据结构方面就只有一个listnode。

struct listnode slist; 这也就是说,在service的结构体中,,这个结构体只会被加入一条链表而不是像action的两条链表。

另外需要注意的是,在service的结构体中,也维护了一个action的结构体,这就是说,在service中,也存在着一个action的commands的链表?

然后我们就来看看parse_service的函数

static void *parse_service(struct parse_state *state, int nargs, char **args){struct service *svc; // 声明结构体if (nargs < 3) { // 如果service的参数小于三个的话,我们会认为service是个不正常的service。service最少的nargs也是3,分别为service关键字,service的名字,service启动的时候要执行的命令parse_error(state, "services must have a name and a program\n");return 0;}if (!valid_name(args[1])) { //如果service的name为不标准的名字的话,含有其它的符号的话,我们会认为这个service是不规范的service。parse_error(state, "invalid service name '%s'\n", args[1]);return 0;}svc = service_find_by_name(args[1]); 。。// 会从已经存在的service_list里面去查找,是否已经有同名的service存在if (svc) { // 如果发现有同名的service存在的话,则会返回errorparse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);return 0;}nargs -= 2; // 去除service关键字与service的namesvc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs); // malloc这个结构体if (!svc) { // 如果malloc失败的话,提示out of memoryparse_error(state, "out of memory\n");return 0;}svc->name = args[1]; // 设置service的name为service关键字后的第一个参数svc->classname = "default"; // 默认的classname为defaultmemcpy(svc->args, args + 2, sizeof(char*) * nargs); // 将args剩余的参数复制到svc的args里面svc->args[nargs] = 0; // 给args的最后一项设置为0svc->nargs = nargs; // 参数的数目等于传进来的参数的数目svc->onrestart.name = "onrestart"; // 设置onrestart.name为onrestartlist_init(&svc->onrestart.commands); // 初始化onrestart的链表list_add_tail(&service_list, &svc->slist); // 将当前的service结构体加入到了service_list的链表里面return svc;}从上面我们知道,在执行完parse_service之后,会初始化service的一些属性,将service servicename之后的做为args进行保存。

另外,将这个解析出来的service加入到service_list的链表里面。

然后接下来,去执行的就是

state->parse_line = parse_line_service;那我们像action,再来看看parse_line_service的操作static void parse_line_service(struct parse_state *state, int nargs, char **args){struct service *svc = state->context;struct command *cmd;int i, kw, kw_nargs;if (nargs == 0) {return;}svc->ioprio_class = IoSchedClass_NONE;kw = lookup_keyword(args[0]);switch (kw) {case K_capability:break;case K_class:if (nargs != 2) {parse_error(state, "class option requires a classname\n");} else {svc->classname = args[1];}break;case K_console:svc->flags |= SVC_CONSOLE;break;case K_disabled:svc->flags |= SVC_DISABLED;svc->flags |= SVC_RC_DISABLED;break;case K_ioprio:if (nargs != 3) {parse_error(state, "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n");} else {    。。。。……..case K_onrestart:        nargs–;        args++;        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;……………}

可以看到,parse_line_service的这个函数,主要就是将解析service的每一行,将其对应进不同的case里面,进行service结构体的填充。

可能这样讲,理解起来会有困难。

一直觉得人应该去旅行,在年轻的时候,趁着有脾气装潇洒,

Android启动流程分析(九) 解析init.rc的service

相关文章:

你感兴趣的文章:

标签云: