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又回来了!