深入理解init_3 --------- 解析Zygote 的service(基于源码2.2,代码源自Google)

来源:互联网 发布:淘宝货源 方法步骤 编辑:程序博客网 时间:2024/06/12 19:11

深入理解init_3 ——— 解析Zygote 的service

1、解析service

zygote对应的service section 内容是:

这里写图片描述

      解析zygo service 的主要函数

1.1文件位置 init.rc

/system/core/rootdir/init.rc

1.2、关键代码分析

service zygote  /system/bin/app_process -Xzygote /system/bin -zygote \---start -system-serversocket zygote stream 666  #socket 是OPTION  #下面的onreatart 是OPTION ,而write和restart是COMMAND  onrestart write /sys/android_power/request_state wakeonrestart  write /sys/power/state ononrestart restart media

解析section的入口函数是parse_new_section,它的代码如下:

2、跳入parser.c文件解析section

2.1、文件位置

/system/core/init/parser.c

2.2、主要代码分析

void parse_new_section(struct parser_state *state,int kw,int nargs,char **args){switch (kw){case k_service : //用parse_service 和parse_line_service解析servicestate->context = parse_service(state,narge,args);If (state->context){state->parse_line = parse_line_service;return;}  break;case k_on;  //解析on section(部分代码省略····)break;}state->parse_line =parse_line_no_op;}

在解析service的时候,我们看到用parse_service和parse_line_service这两个函数,在分别介绍他们之前,我们先看一下init是如何组织这个service的。

3、Init中 service的结构体介绍

Init中,使用了一个service的结构体来保存与service section相关信息,下面来看看这个结构体。

3.1、文件位置

/system/core/init/init.h

3.2、关键代码分析

struct service {/*  listnode是一个特殊的结构体,在内核代码中用的最多,主要是用来将结构体链接成一个双向链表。Init 中有一个全局的service_list,专门用于保存解析配置文件后得到的service*/struct listnode slist;const char *name; //server 的名字,与我们对应的就是“zygote”const char *classname; //service 所属class的名字,默认就是defult。unsigned flags; //service的属性pid_t pid; //进程号time_t time_started; //上一次启动的时间time_t time_crashed; //上一次死亡的时间int nr_crashed;  //死亡次数uid_t uid;  //uid,gid相关gid_t gid;gid_t supp_gids[NR_SUOO_GIDS];size_t nr_supp_gids;/*有些service需要使用socket,下面这个socketinfo用来描述socket的相关情况。我们的zygote也使用了socket,配置文件中的内容是socket zygote stream 666 它表示将创建一个AF_STREAM类型的socket(其实就是TCP_SOCKET),该socket的名为“zygote”,读写权限666*/struct socketinfo *sockets;//service 一般运行在单独的进程中,envvars用来描述创建这个进程时所需要的环境变量信息。struct svcenvinfo *envvars;/*虽然关键字onrestart标识一个OPTION,可是这个OPTION 后面一般跟着COMMAND,下面这个action结构体用来存储command信息*/struct action onreatart;//与keychord相关的内容Int *keycodes;Int nkeycodes;Int keychord_id;//io 优先级设置Int iopro_class;Int iopro_pri;//参数个数Int nargs;//用于存储参数char *args[1];};
我们现在了解了service的结构体,相对来说还是比较清晰的。而zygote中的那三个onrestart 该怎么表示呢,下面我们看action这个结构体。
struct action {/*一个action结构体可以存放在三个双向链表中,其中alist用于存储所有的action,qlist用于链接那些等待执行的action,tlist用于链接那些待某些条件满足后才会执行的action*/}struct listnode alist;struct listnode qlist;struct listnode tlist;unsigned hash;const char *name;//这个OPTION对应的};COMMAND  链表,以zygote为例,它有三个 onrestart option,所以它会创建三个command结构体。struct listnode commands;struct command *current;

4、跳转到parser.c文件

4.1、文件位置

/system/core/init/parser.c

4.2、关键代码分析

static void *parse_service(strust parse_state *state,int nargs,char **args){struct service *svc;    //声明一个service结构体(部分代码省略···)//init维护了一个全局的service链表,先判断是否有同名的service 了svc = service_find_by_name(args[1]);if (svc){(部分代码省略···)//如果有同名的service,则不能继续后面操作。return 0;}nargs =2;svc = calloc1,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);return svc;}

parse_service函数只是搭建了一个service的架子,具体的内容尚需由后面的解析函数来填充,下面来看看service的另一解析函数parse_line_service.

static void parse_line_service(strust parse_state *state,int nargs,char **args){struct service *svc = state->context;struct command *cmd;int i,kw,kw_nargs;(部分代码省略······)svc->ioprio_class = IoSchedClass_NONE;//其实还是根据关键字来做各种处理kw = lookup_keyword(args[0]);switch(kw){case k_capability:break;case k_class:if (nargs !=2){(部分代码省略······)}else{svc->classname = args[1];}break;(部分代码省略······)case k_oneshot:/*这是一个service的属性,一共有五个属性,分别为:SVC_DISABLED:不随classs自动启动。下面将看到class作用。SVC_ONESHOT: 退出后不需要重启,也就是说这个service只启动一次就可以了。SVC_RUNNING:正在运行,这是service的状态。SVC_RESTARING:等待在重启,也是service的状态SVC_CONSOLE:该service需要控制台SVC_CRITICAL:如果在规定时间内该service不断重启,则系统会重启并进入恢复模式。zygote没有使用任何属性,这表明它随着class的处理自动启动。退出后会由init重启,不使用控制台,即使不断重启也不会导致系统进入恢复模式。*/svc->flags |= SVC_ONESHOT;break;case k_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;(部分代码省略······)case k_socket:{ //创建socket相关信息struct socketinfo *si;(部分代码省略······)si = calloc(1,sizeof(*si));if (!si){parse_error(sr=state,”out of memory\n”);break;}si->name = args[1]; //socket 的名字si->type =args[2]; //socket的类型si->perm = strtoul(args[3],0,0); //socket的 读写权限if (nargs > 4)si -> gid = 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解析完成后会得到什么呢?下图表明zygote解析后的结果:

这里写图片描述

从上图可知:
1) service_list 链表将解析后的service全部链接到了一起,并且是双向链表,前向节点用prev表示,后向节点用next表示。
2) socketinfo也是一个双向列表,因为zygote只有一个socket,所以用一个圆框socket表示链表的示范 。
3) onrestart通过command指向command链表,zygote有三个commands。
现在zygote这个service解析完了,接下来我们将会了解init 如何控制service。

文档参考:

整理抄录自 — 《深入理解Android卷1》,邓凡平著。

0 0
原创粉丝点击