深入理解init_3 --------- 解析Zygote 的service(基于源码2.2,代码源自Google)
2017-03-02 15:56
591 查看
深入理解init_3 ——— 解析Zygote 的service
1、解析service
zygote对应的service section 内容是:解析zygo service 的主要函数
1.1文件位置 init.rc
/system/core/rootdir/init.rc1.2、关键代码分析
service zygote /system/bin/app_process -Xzygote /system/bin -zygote \ ---start -system-server socket zygote stream 666 #socket 是OPTION #下面的onreatart 是OPTION ,而write和restart是COMMAND onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart media
解析section的入口函数是parse_new_section,它的代码如下:
2、跳入parser.c文件解析section
2.1、文件位置
/system/core/init/parser.c2.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解析service state->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.h3.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.c4.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 = 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[na 4000 rgs]=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》,邓凡平著。
相关文章推荐
- 深入理解init_4``````````init控制service(基于Android2.2,代码源自Google)
- 深入理解init_5-----属性服务(基于Android 2.2,代码源自Google)
- 深入理解init_2-----解析配置文件init.rc(基于Android 2.2,代码源于Google)
- 深入理解init_1----init分析(基于Android 2.2,源码来自Google)
- 深入理解zygote——1(代码源于GooGle)
- 深入理解zygote——2(代码源于GooGle)
- caffe源码深入学习5:超级详细的caffe卷积层代码解析
- 从源码出发深入理解 Android Service
- 利用maven整合SSH步骤以及源码解析可以更好的深入理解
- Android EventBus源码解析 带你深入理解EventBus
- Android EventBus源码解析 带你深入理解EventBus
- 从源码深入理解java集合(基于jdk1.7)
- Android EventBus源码解析 带你深入理解EventBus
- 深入理解 GNU GRUB - 02 boot.S 2.2 MBR结构 2.3 boot.S代码结构
- Android EventBus源码解析 带你深入理解EventBus
- 深入理解Zuul之源码解析(转载)
- Android EventBus源码解析 带你深入理解EventBus(二)
- Android EventBus源码解析 带你深入理解EventBus
- Android EventBus源码解析 带你深入理解EventBus
- 深入理解Zuul之源码解析