3.2.3 init控制service

先看service是如何启动的。

1.启动zygote

init.rc中有这样一句话:


class_start是一个COMMAND,对应的函数为do_class_start,很重要,切记。

class_start default


class_start标识一个COMMAND,对应的处理函数为do_class_start,它位于boot section的范围内。为什么说它很重要呢?

还记得init进程中的四个执行阶段吗?当init进程执行到下面几句话时,do_class_start就会被执行了。


//将boot section节的command加入到执行队列。

action_for_each_trigger("boot",action_add_queue_tail);

//执行队列里的命令,class是一个COMMAND,所以它对应的do_class_start会被执行。

drain_action_queue();


下面来看do_class_start函数:


[—>builtins.c]

int do_class_start(int nargs,char**args)

{

/*

args为do_class_start的参数,init.rc中只有一个参数,就是default。

下面这个函数将从service_list中找到classname为"default"的service,然后调用service_start_if_not_disabled函数。现在读者明白了service结构体中classname的作用了吗?

*/

service_for_each_class(args[1],service_start_if_not_disabled);

return 0;

}


我们已经知道,zygote这个service的classname的值就是“default”,所以会针对这个service调用service_start_if_not_disabled,这个函数的代码是:


[—>parser.c]

static void service_start_if_not_disabled(struct service*svc)

{

if(!(svc->flags&SVC_DISABLED)){

service_start(svc,NULL);//zygote可不设置SVC_DISABLED

}

}


service_start函数的代码如下所示:


[—>init.c]

void service_start(struct servicesvc,const chardynamic_args)

{

struct stat s;

pid_t pid;

int needs_console;

int n;

svc->flags&=(~(SVC_DISABLED|SVC_RESTARTING));

svc->time_started=0;

if(svc->flags&SVC_RUNNING){

return;//如果这个service已经在运行,则不用处理

}

/*

service一般运行于另外一个进程中,这个进程也是init的子进程,所以启动service前需要判断对应的可执行文件是否存在,zygote对应的可执行文件是/system/bin/app_process。

*/

if(stat(svc->args[0],&s)!=0){

svc->flags|=SVC_DISABLED;

return;

}

……

pid=fork();//调用fork创建子进程

if(pid==0){

//pid为零,表示现在运行在子进程中

struct socketinfo*si;

struct svcenvinfo*ei;

char tmp[32];

int fd,sz;

//得到属性存储空间的信息并加到环境变量中,后面在属性服务一节中会碰到使用它的地方。

get_property_workspace(&fd,&sz);

add_environment("ANDROID_PROPERTY_WORKSPACE",tmp);

//添加环境变量信息。

for(ei=svc->envvars;ei;ei=ei->next)

add_environment(ei->name,ei->value);

//根据socketinfo创建socket。

for(si=svc->sockets;si;si=si->next){

int s=create_socket(si->name,

!strcmp(si->type,"dgram")?

SOCK_DGRAM:SOCK_STREAM,

si->perm,si->uid,si->gid);

if(s>=0){

//在环境变量中添加socket信息。

publish_socket(si->name,s);

}

}

……//设置uid,gid等

setpgid(0,getpid());

if(!dynamic_args){

/*

执行/system/bin/app_process,这样就进入到app_process的main函数中了。

fork、execve这两个函数都是Linux系统上常用的系统调用。

*/

if(execve(svc->args[0],(char)svc->args,(char)ENV)<0){

……

}

}else{

……

}

……//父进程init的处理,设置service的信息,如启动时间、进程号,以及状态等。

svc->time_started=gettime();

svc->pid=pid;

svc->flags|=SVC_RUNNING;

//每一个service都有一个属性,zygote的属性为init.svc.zygote,现在设置它的值为running。

notify_service_state(svc->name,"running");

}


原来,zygote是通过fork和execv共同创建的!但service结构中的那个onrestart好像没有派上用场,原因何在?

2.重启zygote

应该根据名字就可猜到onrestart是在zygote重启时用的。下面先看在zygote死后,它的父进程init会有什么动作:


[—>init.c]

static void sigchld_handler(int s)

{//当子进程退出时,init的这个信号处理函数会被调用。

write(signal_fd,&s,1);//往signal_fd中写数据。

}


signal_fd就是在init中通过socketpair创建的两个socket中的一个,既然会往这个signal_fd中发送数据,那么另外一个socket就一定能接收到,这样就会导致init从poll函数中返回,代码如下所示:


[—>init.rc:main函数代码片断]

nr=poll(ufds,fd_count,timeout);

……

if(ufds[2].revents==POLLIN){

read(signal_recv_fd,tmp,sizeof(tmp));

while(!wait_for_one_process(0))//调用wait_for_one_process函数处理。

continue;

}

……

//直接看这个wait_for_one_process函数:

static int wait_for_one_process(int block)

{

pid_t pid;

int status;

struct service*svc;

struct socketinfo*si;

time_t now;

struct listnode*node;

struct command*cmd;

while((pid=waitpid(-1,&status,block?0:WNOHANG))==-1&&

errno==EINTR);

if(pid<=0)return-1;

//找到死掉的那个service,现在应该找到了代表zygote的那个service。

svc=service_find_by_pid(pid);

……

if(!(svc->flags&SVC_ONESHOT)){

//杀掉zygote创建的所有子进程,这就是zygote死后,Java世界崩溃的原因。

kill(-pid,SIGKILL);

}

//清理socket信息,不清楚的读者可以通过命令man 7 AF_UNIX查询一下相关知识。

for(si=svc->sockets;si;si=si->next){

char tmp[128];

snprintf(tmp,sizeof(tmp),ANDROID_SOCKET_DIR"/%s",si->name);

unlink(tmp);

}

svc->pid=0;

svc->flags&=(~SVC_RUNNING);

if(svc->flags&SVC_ONESHOT){

svc->flags|=SVC_DISABLED;

}

……

now=gettime();

/*

如果设置了SVC_CRITICAL标识,则4分钟内该服务重启的次数不能超过4次,否则机器会在重启时进入recovery模式。根据init.rc的配置来看,只有servicemanager进程享有此种待遇。

*/

if(svc->flags&SVC_CRITICAL){

if(svc->time_crashed+CRITICAL_CRASH_WINDOW>=now){

if(++svc->nr_crashed>CRITICAL_CRASH_THRESHOLD){

……

sync();

__reboot(LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,

LINUX_REBOOT_CMD_RESTART2,"recovery");

return 0;

}

}else{

svc->time_crashed=now;

svc->nr_crashed=1;

}

}

svc->flags|=SVC_RESTARTING;

//设置标识为SVC_RESTARTING,然后执行该service onrestart中的COMMAND,这些内容就

//非常简单了,读者可以自行学习。

list_for_each(node,&svc->onrestart.commands){

cmd=node_to_item(node,struct command,clist);

cmd->func(cmd->nargs,cmd->args);

}

//设置init.svc.zygote的值为restarting。

notify_service_state(svc->name,"restarting");

return 0;

}


通过上面的代码可以知道onrestart的作用了,但zygote本身又在哪里重启呢?答案就在下面的代码中:


[—>init.c:main函数代码片断]

for(;){

int nr,i,timeout=-1;

for(i=0;i<fd_count;i++)

ufds[i].revents=0;

drain_action_queue();//poll函数返回后,会进入下一轮的循环

restart_processes();//这里会重启所有flag标志为SVC_RESTARTING的service。

……

}


这样,zygote又回来了!