ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
zygote对应的service section内容是: **init.rc::zygote** ~~~ service zygote /system/bin/app_process -Xzygote/system/bin –zygote \ --start-system-server socketzygote stream 666 #socket是OPTION #下面的onrestart是OPTION,而write和restart是COMMAND onrestartwrite /sys/android_power/request_state wake onrestart write /sys/power/state on onrestartrestart media ~~~ 解析section的入口函数是parse_new_section,它的代码如下所示: **parser.c** ~~~ void parse_new_section(struct parse_state*state, int kw, int nargs, char **args) { switch(kw) { caseK_service: //解析service,用parse_service和parse_line_service state->context = parse_service(state, nargs, args); if(state->context) { state->parse_line = parse_line_service; return; } break; caseK_on: //解析on section ......//读者可以自己研究 break; } state->parse_line = parse_line_no_op; } ~~~ 其中,service解析时,用到了parse_service和parse_line_service两个函数,在分别介绍它们之前,先看init是如何组织这个service的。 1. service结构体 init中使用了一个叫service的结构体来保存和service section相关的信息,不妨来看这个结构体,代码如下所示: **init.h::service结构体定义** ~~~ struct service { //listnode是一个特殊的结构体,在内核代码中用得非常多,主要用来将结构体链接成一个 //双向链表。init中有一个全局的service_list,专门用来保存解析配置文件后得到的service。 struct listnode slist; constchar *name; //service的名字,对应我们这个例子就是”zygote”。 constchar *classname; //service所属class的名字,默认是”defult” unsigned flags;//service的属性 pid_tpid; //进程号 time_ttime_started; //上一次启动的时间 time_ttime_crashed; //上一次死亡的时间 intnr_crashed; //死亡次数 uid_tuid; //uid,gid相关 gid_tgid; gid_tsupp_gids[NR_SVC_SUPP_GIDS]; size_tnr_supp_gids; /* 有些service需要使用socket,下面这个socketinfo用来描述socket的相关信息。 我们的zygote也使用了socket,配置文件中的内容是socket zygote stream 666。 它表示将创建一个AF_STREAM类型的socket(其实就是TCP socket),该socket的名为“zygote”, 读写权限是666。 */ structsocketinfo *sockets; //service一般运行在单独的一个进程中,envvars用来描述创建这个进程时所需的环境变量信息。 structsvcenvinfo *envvars; /* 虽然关键字onrestart标示一个OPTION,可是这个OPTION后面一般跟着COMMAND, 下面这个action结构体可用来存储command信息,马上就会分析到它。 */ structaction onrestart; //和keychord相关的内容 int*keycodes; intnkeycodes; intkeychord_id; //io优先级设置 intioprio_class; intioprio_pri; //参数个数 intnargs; //用于存储参数 char*args[1]; }; ~~~ 我们现在已了解的service的结构体,相对来说还算是清晰易懂的。而zygote中的那三个onrestart该怎么表示呢?请看service中使用的这个action结构体: **init.h::action结构体定义** ~~~ struct action { /* 一个action结构体可存放在三个双向链表中,其中alist用于存储所有action, qlist用于链接那些等待执行的action,tlist用于链接那些待某些条件满足后 就需要执行的action。 */ structlistnode alist; structlistnode qlist; structlistnode tlist; unsigned hash; constchar *name; //这个OPTION对应的COMMAND链表,以zygote为例,它有三个onrestart option,所以 //它对应会创建三个command结构体。 structlistnode commands; structcommand *current; }; ~~~ 了解了上面的知识后,你是否能猜到parse_service和parse_line_service的作用了呢?马上就来看它们。 2. parse_service parse_service的代码如下所示: **parser.c** ~~~ static void *parse_service(struct parse_state*state, int nargs, char **args) { structservice *svc; //声明一个service结构体 ...... //init维护了一个全局的service链表,先判断是否已经有同名的service了。 svc =service_find_by_name(args[1]); if(svc) { ...... //如果有同名的service,则不能继续后面的操作。 return 0; } nargs-= 2; svc =calloc(1, sizeof(*svc) + sizeof(char*) * nargs); ...... svc->name = args[1]; svc->classname= "default";//设置classname为”default”,这个很关键! memcpy(svc->args, args + 2, sizeof(char*) * nargs); svc->args[nargs] = 0; svc->nargs = nargs; svc->onrestart.name= "onrestart"; list_init(&svc->onrestart.commands); //把zygote这个service加到全局链表service_list中。 list_add_tail(&service_list, &svc->slist); returnsvc; } ~~~ parse_service函数只是搭建了一个service的架子,具体的内容尚需由后面的解析函数来填充。来看service的另外一个解析函数parse_line_service。 3. parse_line_service parse_line_service的代码如下所示: **parser.c** ~~~ static void parse_line_service(structparse_state *state, int nargs, char **args) { structservice *svc = state->context; structcommand *cmd; int i,kw, kw_nargs; ...... svc->ioprio_class = IoSchedClass_NONE; //其实还是根据关键字来做各种处理。 kw =lookup_keyword(args[0]); switch(kw) { caseK_capability: break; caseK_class: if(nargs != 2) { ...... }else { svc->classname = args[1]; } break; ...... caseK_oneshot: /* 这是service的属性,它一共有五个属性,分别为: SVC_DISABLED:不随class自动启动。下面将会看到class的作用。 SVC_ONESHOT:退出后不需要重启,也就是这个service只启动一次就可以了。 SVC_RUNNING:正在运行,这是service的状态。 SVC_RESTARTING:等待重启,这也是service的状态。 SVC_CONSOLE:该service需要使用控制台 。 SVC_CRITICAL:如果在规定时间内该service不断重启,则系统会重启并进入恢复模式。 zygote没有使用任何属性,这表明它:会随着class的处理自动启动; 退出后会由init重启;不使用控制台;即使不断重启也不会导致系统进入恢复模式。 */ svc->flags |= SVC_ONESHOT; break; caseK_onrestart: //根据onrestart的内容,填充action结构体的内容 nargs--; args++; kw= lookup_keyword(args[0]); ...... //创建command结构体 cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs); cmd->func = kw_func(kw); cmd->nargs = nargs; memcpy(cmd->args, args, sizeof(char*) * nargs); //把新建的command加入到双向链表中。 list_add_tail(&svc->onrestart.commands, &cmd->clist); break; ...... caseK_socket: { //创建socket相关信息 struct socketinfo *si; ...... si= calloc(1, sizeof(*si)); if(!si) { parse_error(state, "out of memory\n"); break; } si->name = args[1]; //socket的名字 si->type = args[2]; //socket的类型 si->perm = strtoul(args[3], 0, 8); //socket的读写权限 if(nargs > 4) si->uid = decode_uid(args[4]); if(nargs > 5) si->gid = decode_uid(args[5]); si->next = svc->sockets; svc->sockets = si; break; } ...... default: parse_error(state, "invalid option '%s'\n", args[0]); } } ~~~ parse_line_service将根据配置文件的内容填充service结构体,那么,zygote解析完后会得到什么呢?图3-1表示了zygote解析后的结果: :-: ![](http://img.blog.csdn.net/20150802095010545?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图3-1 zygote解析结果示意图 从上图中可知: - service_list链表将解析后的service全部链接到了一起,并且是一个双向链表,前向节点用prev表示,后向节点用next表示。 - socketinfo也是一个双向链表,因为zygote只有一个socket,所以画了一个虚框socket做为链表的示范。 - onrestart通过commands指向一个commands链表,zygote有三个commands。 zygote这个service解析完了,现在就是“万事俱备,只欠东风”了。接下来要了解的是,init是如何控制service的。