android系统启动流程启动画面学习之init和init.rc分析


这段时间,断断续续的忙了一阵,因为父亲的去世也不情愿的休息了20来天,一点也没有办法。回来后重新开始学习android的启动流程。对android系统级别的学习,阅读代码成为了唯一的办法,不像应用程序开发来得那么明了快捷。之前花了好多时间才对android的binder驱动做了一定的了解,最近几天从android的启动画面,分析到了init这个内核最先启动的一个进程。参考内容包括老罗的android之旅和邓平凡老师的深入理解android卷,本人只是对学习做一定的总结,帮助自己进一步理解。

一 . init.c中的main函数(路径:system/core/init/init.c)

先给出main的源码,然后对个别关键函数进行分析

[cpp]  view plain copy
  1. int main(int argc, char **argv)  
  2. {  
  3.     int fd_count = 0;  
  4.     struct pollfd ufds[4];  
  5.     char *tmpdev;  
  6.     char* debuggable;  
  7.     char tmp[32];  
  8.     int property_set_fd_init = 0;  
  9.     int signal_fd_init = 0;  
  10.     int keychord_fd_init = 0;  
  11.   
  12.     if (!strcmp(basename(argv[0]), "ueventd"))  
  13.         return ueventd_main(argc, argv);  
  14.   
  15.     /* clear the umask */  
  16.     umask(0);  
  17.   
  18.         /* Get the basic filesystem setup we need put 
  19.          * together in the initramdisk on / and then we'll 
  20.          * let the rc file figure out the rest. 
  21.          */  
  22.     mkdir("/dev", 0755);  
  23.     mkdir("/proc", 0755);  
  24.     mkdir("/sys", 0755);  
  25.   
  26.     mount("tmpfs""/dev""tmpfs", 0, "mode=0755");  
  27.     mkdir("/dev/pts", 0755);  
  28.     mkdir("/dev/socket", 0755);  
  29.     mount("devpts""/dev/pts""devpts", 0, NULL);  
  30.     mount("proc""/proc""proc", 0, NULL);  
  31.     mount("sysfs""/sys""sysfs", 0, NULL);  
  32.   
  33.         /* We must have some place other than / to create the 
  34.          * device nodes for kmsg and null, otherwise we won't 
  35.          * be able to remount / read-only later on. 
  36.          * Now that tmpfs is mounted on /dev, we can actually 
  37.          * talk to the outside world. 
  38.          */  
  39.     open_devnull_stdio();  
  40.     log_init();  
  41.       
  42.     INFO("reading config file\n");  
  43.     init_parse_config_file("/init.rc");  
  44.   
  45.     /* pull the kernel commandline and ramdisk properties file in */  
  46.     import_kernel_cmdline(0);  
  47.   
  48.     get_hardware_name(hardware, &revision);  
  49.     snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);//和平台硬件hardware有关系  
  50.     init_parse_config_file(tmp);  
  51.   
  52.     action_for_each_trigger("early-init", action_add_queue_tail);  
  53.   
  54.     queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");  
  55.     queue_builtin_action(property_init_action, "property_init");  
  56.     queue_builtin_action(keychord_init_action, "keychord_init");  
  57.     queue_builtin_action(console_init_action, "console_init");//第二个开机画面显示函数  
  58.     queue_builtin_action(set_init_properties_action, "set_init_properties");  
  59.   
  60.         /* execute all the boot actions to get us started */  
  61.     action_for_each_trigger("init", action_add_queue_tail);  
  62.     action_for_each_trigger("early-fs", action_add_queue_tail);  
  63.     action_for_each_trigger("fs", action_add_queue_tail);  
  64.     action_for_each_trigger("post-fs", action_add_queue_tail);  
  65.   
  66.     queue_builtin_action(property_service_init_action, "property_service_init");  
  67.     queue_builtin_action(signal_init_action, "signal_init");  
  68.     queue_builtin_action(check_startup_action, "check_startup");  
  69.   
  70.     /* execute all the boot actions to get us started */  
  71.     action_for_each_trigger("early-boot", action_add_queue_tail);  
  72.     action_for_each_trigger("boot", action_add_queue_tail);//把boot这个action添加到action_queue链表中  
  73.   
  74.         /* run all property triggers based on current state of the properties */  
  75.     queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");  
  76.   
  77.   
  78. #if BOOTCHART  
  79.     queue_builtin_action(bootchart_init_action, "bootchart_init");  
  80. #endif  
  81.   
  82.     for(;;) {  
  83.         int nr, i, timeout = -1;  
  84.   
  85.         execute_one_command(); //检查action_queue列表是否为空,执行action  
  86.         restart_processes();//检查是否有进程需要重启  
  87.   
  88.         if (!property_set_fd_init && get_property_set_fd() > 0) {  
  89.             ufds[fd_count].fd = get_property_set_fd();  
  90.             ufds[fd_count].events = POLLIN;  
  91.             ufds[fd_count].revents = 0;  
  92.             fd_count++;  
  93.             property_set_fd_init = 1;  
  94.         }  
  95.         if (!signal_fd_init && get_signal_fd() > 0) {  
  96.             ufds[fd_count].fd = get_signal_fd();  
  97.             ufds[fd_count].events = POLLIN;  
  98.             ufds[fd_count].revents = 0;  
  99.             fd_count++;  
  100.             signal_fd_init = 1;  
  101.         }  
  102.         if (!keychord_fd_init && get_keychord_fd() > 0) {  
  103.             ufds[fd_count].fd = get_keychord_fd();  
  104.             ufds[fd_count].events = POLLIN;  
  105.             ufds[fd_count].revents = 0;  
  106.             fd_count++;  
  107.             keychord_fd_init = 1;  
  108.         }  
  109.   
  110.         if (process_needs_restart) {  
  111.             timeout = (process_needs_restart - gettime()) * 1000;  
  112.             if (timeout < 0)  
  113.                 timeout = 0;  
  114.         }  
  115.   
  116.         if (!action_queue_empty() || cur_action)  
  117.             timeout = 0;  
  118.   
  119. #if BOOTCHART  
  120.         if (bootchart_count > 0) {  
  121.             if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)  
  122.                 timeout = BOOTCHART_POLLING_MS;  
  123.             if (bootchart_step() < 0 || --bootchart_count == 0) {  
  124.                 bootchart_finish();  
  125.                 bootchart_count = 0;  
  126.             }  
  127.         }  
  128. #endif  
  129.   
  130.         nr = poll(ufds, fd_count, timeout);  
  131.         if (nr <= 0)  
  132.             continue;  
  133.   
  134.         for (i = 0; i < fd_count; i++) {  
  135.             if (ufds[i].revents == POLLIN) {  
  136.                 if (ufds[i].fd == get_property_set_fd())  
  137.                     handle_property_set_fd();  
  138.                 else if (ufds[i].fd == get_keychord_fd())  
  139.                     handle_keychord();  
  140.                 else if (ufds[i].fd == get_signal_fd())  
  141.                     handle_signal();  
  142.             }  
  143.         }  
  144.     }  
  145.   
  146.     return 0;  
  147. }  

init作为用户空间第一个启动的进程,需要完成很多的任务。分以下部分内容来分析

1.  uevent进程

  if (!strcmp(basename(argv[0]), "ueventd"))
        return ueventd_main(argc, argv);

这个函数是取出argv中的第一个参数,比如/sbin/ueventd,则basename为ueventd。android系统第一次启动的进程名init,所以该函数ueventd_main不执行,该函数的真正执行在init启动service ueventd /sbin/ueventd后,fork出一个子进程,execve启动/sbin/ueventd后,实际上该函数是对init的符合链接,也就是ueventd进程执行起来后执行的代码还是init.c中的main,因此不同的进程名执行相同的main函数。ueventd_main函数的主要功能:在Linux系统中现在都使用uevent机制来管理设备的热插拔事件,给用户空间权利来完成一些设备文件节点的创建。这种机制是建立在socket的通信机制上,用户空间和内核驱动进行交互,详细的机制没有去了解过。是linux2.6的版本中常用的机制。比如驱动出现device_create等时,会向用户空间报告一个uevent事件,用户空间由uevent进程解析后去创建设备节点。

2.init.rc的解析

INFO("reading config file\n");
init_parse_config_file("/init.rc");

init.rc是一个配置文件,内部有许多的语言规则,所有语言会在init_parse_config_file中进行解析。调用流程如下:init_parse_config_file—>read_file—>parse_config.

parse_config源码如下:

[html]  view plain copy
  1. static void parse_config(const char *fn, char *s)//s为init.rc中字符串的内容  
  2. {  
  3.     struct parse_state state;  
  4.     char *args[INIT_PARSER_MAXARGS];  
  5.     int nargs;  
  6.   
  7.     nargs = 0;  
  8.     state.filename = fn;  
  9.     state.line = 1;  
  10.     state.ptr = s;  
  11.     state.nexttoken = 0;  
  12.     state.parse_line = parse_line_no_op;  
  13.     for (;;) {  
  14.         switch (next_token(&state)) {  
  15.         case T_EOF:       //文件的结尾  
  16.             state.parse_line(&state, 0, 0);  
  17.             return;  
  18.         case T_NEWLINE://新的一行  
  19.             if (nargs) {  
  20.                 int kw = lookup_keyword(args[0]);          //读取init.rc返回关键字例如service,返回K_service  
  21.                 if (kw_is(kw, SECTION)) {                        //查看关键字是否为SECTION,只有service和on满足  
  22.                     state.parse_line(&state, 0, 0);  
  23.                     parse_new_section(&state, kw, nargs, args);  
  24.                 } else {  
  25.                     state.parse_line(&state, nargs, args);//on 和service两个段下面的内容  
  26.                 }  
  27.                 nargs = 0;  
  28.             }  
  29.             break;  
  30.         case T_TEXT://文本内容  
  31.             if (nargs < INIT_PARSER_MAXARGS) {  
  32.                 args[nargs++] = state.text;  
  33.             }  
  34.             break;  
  35.         }  
  36.     }  
  37. }  
  38.   
  39. int init_parse_config_file(const char *fn)  
  40. {  
  41.     char *data;  
  42.     data = read_file(fn, 0);  
  43.     if (!data) return -1;  
  44.   
  45.     parse_config(fn, data);  
  46.     DUMP();  
  47.     return 0;  
  48. }  

这个函数中可以看到在for的无邪循环中,主要对init.rc的内容进行解析,以一行一行进行读取,每读取完一行内容换行时到下一行时,使用lookup_keyword分析已经读取的一行的第一个参数,部分代码如下:

[html]  view plain copy
  1. case 's':  
  2.         if (!strcmp(s, "ervice")) return K_service;  
  3.         if (!strcmp(s, "etenv")) return K_setenv;  
  4.         if (!strcmp(s, "etkey")) return K_setkey;  
  5.         if (!strcmp(s, "etprop")) return K_setprop;  
  6.         if (!strcmp(s, "etrlimit")) return K_setrlimit;  
  7.         if (!strcmp(s, "ocket")) return K_socket;  
  8.         if (!strcmp(s, "tart")) return K_start;  
  9.         if (!strcmp(s, "top")) return K_stop;  
  10.         if (!strcmp(s, "ymlink")) return K_symlink;  
  11.         if (!strcmp(s, "ysclktz")) return K_sysclktz;  

该函数主要对每一行的第一个字符做case,然后在strcmp第一个命令,这些命令都是按init.rc的格式要求来进行的。比如常用的service和on等经过lookup_keyword后返回K_servcie和K_on。随后使用kw_is(kw, SECTION)判断返回的kw是不是属于SECTION类型,在init.rc中只有service和on满足该类型,这样就会对on和service所在的段进行解析,我们这里首先分析service,以init.rc中的service zygote为例

[plain]  view plain copy
  1. service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server  
  2.     class main  
  3.     socket zygote stream 666  
  4.     onrestart write /sys/android_power/request_state wake  
  5.     onrestart write /sys/power/state on  
  6.     onrestart restart media  
  7.     onrestart restart netd  

当解析到这段代码时,执行parse_service

[plain]  view plain copy
  1. static void *parse_service(struct parse_state *state, int nargs, char **args)  
  2. {  
  3.     struct service *svc;  
  4.     if (nargs < 3) {  
  5.         parse_error(state, "services must have a name and a program\n");  
  6.         return 0;  
  7.     }  
  8.     if (!valid_name(args[1])) {  
  9.         parse_error(state, "invalid service name '%s'\n", args[1]);  
  10.         return 0;  
  11.     }  
  12.   
  13.     svc = service_find_by_name(args[1]);//查找服务是否已经存在  
  14.     if (svc) {  
  15.         parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);  
  16.         return 0;  
  17.     }  
  18.   
  19.     nargs -= 2;  
  20.     svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);  
  21.     if (!svc) {  
  22.         parse_error(state, "out of memory\n");  
  23.         return 0;  
  24.     }  
  25.     svc->name = args[1];          //sevice的名字  
  26.     svc->classname = "default"; //svc的类名默认是default  
  27.     memcpy(svc->args, args + 2, sizeof(char*) * nargs);//首个参数放的是可执行文件  
  28.     svc->args[nargs] = 0;  
  29.     svc->nargs = nargs;//参数个数  
  30.     svc->onrestart.name = "onrestart";  
  31.     list_init(&svc->onrestart.commands);  
  32.     list_add_tail(&service_list, &svc->slist);  
  33.     return svc;  
  34. }  

在这里agrs[1]就是zygote,系统会先查找是否已经存在该服务,然后构建一个service svc,进行相关的填充,包括服务名,服务所属的类别名字,已经服务启动带入的参数个数(要减去service和服务名zygote),最后将这个svc加入到service_list全局链表中。随后所做的是对Service的下面几行Option进行解析,比如class,socket,onrestart等等。使用的是parse_line_service函数,如下:

[plain]  view plain copy
  1. static void parse_line_service(struct parse_state *state, int nargs, char **args)  
  2. {  
  3.     struct service *svc = state->context;  
  4.     struct command *cmd;  
  5.     int i, kw, kw_nargs;  
  6.   
  7.     if (nargs == 0) {  
  8.         return;  
  9.     }  
  10.   
  11.     svc->ioprio_class = IoSchedClass_NONE;  
  12.   
  13.     kw = lookup_keyword(args[0]);  
  14.     switch (kw) {  
  15.     case K_capability:  
  16.         break;  
  17.     case K_class:  
  18.         if (nargs != 2) {  
  19.             parse_error(state, "class option requires a classname\n");  
  20.         } else {  
  21.             svc->classname = args[1];//比如main,core类  
  22.         }  
  23.         break;  
  24.    case K_console:  
  25.         svc->flags |= SVC_CONSOLE;  
  26.         break;  
  27.     case K_disabled:  
  28.         svc->flags |= SVC_DISABLED;  
  29. ......  
  30.  case K_onrestart:  
  31.         nargs--;  
  32.         args++;  
  33.         kw = lookup_keyword(args[0]);  
  34.         if (!kw_is(kw, COMMAND)) {  
  35.             parse_error(state, "invalid command '%s'\n", args[0]);  
  36.             break;  
  37.         }  
  38.         kw_nargs = kw_nargs(kw);  
  39.         if (nargs < kw_nargs) {  
  40.             parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,  
  41.                 kw_nargs > 2 ? "arguments" : "argument");  
  42.             break;  
  43.         }  
  44.   
  45.         cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);  
  46.         cmd->func = kw_func(kw);  
  47.         cmd->nargs = nargs;  
  48.         memcpy(cmd->args, args, sizeof(char*) * nargs);  
  49.         list_add_tail(&svc->onrestart.commands, &cmd->clist);  
  50.         break;  
  51. .......  
  52. }  

这里以class这个keyword为例,会将当前class所属的svc进行类名的变革,变为main类别,类似的socket和onrestart类似。

到此为止整个service都解析完成 ,开始下一个section的内容。但是zygote这个服务进程的启动还没有开始,将在下面分析。

下面分析on字段的内容,以on boot这个section作为列子进行分析

[plain]  view plain copy
  1. on boot  
  2.   ifup lo  
  3.     hostname localhost  
  4.     domainname localdomain  
  5. ....  
  6. # Set this property so surfaceflinger is not started by system_init  
  7.     setprop system_init.startsurfaceflinger 0  
  8.   
  9.     class_start core  
  10.     class_start main  

和前面分析像类似,case中进入K_on选项执行函数parse_action

[plain]  view plain copy
  1. static void *parse_action(struct parse_state *state, int nargs, char **args)  
  2. {  
  3.     struct action *act;  
  4.     if (nargs < 2) {  
  5.         parse_error(state, "actions must have a trigger\n");  
  6.         return 0;  
  7.     }  
  8.     if (nargs > 2) {  
  9.         parse_error(state, "actions may not have extra parameters\n");  
  10.         return 0;  
  11.     }  
  12.     act = calloc(1, sizeof(*act));  
  13.     act->name = args[1];  //action的名字如boot,init等  
  14.     list_init(&act->commands);  
  15.     list_add_tail(&action_list, &act->alist);  
  16.         /* XXX add to hash */  
  17.     return act;  
  18. }  

在这里可以看到一个action结构体类似于service,这个action的名字为boot,最后会将这个action加入到全局链表action_list中。

随后执行parse_line_action函数,对on字段所在的option进行解析,代码如下:

[plain]  view plain copy
  1. static void parse_line_action(struct parse_state* state, int nargs, char **args) //action所在的行  
  2. {  
  3.     struct command *cmd;  
  4.     struct action *act = state->context;//on boot启动  
  5.     int (*func)(int nargs, char **args);  
  6.     int kw, n;  
  7.   
  8.     if (nargs == 0) {  
  9.         return;  
  10.     }  
  11.   
  12.     kw = lookup_keyword(args[0]);//命令的参数个数  
  13.     if (!kw_is(kw, COMMAND)) {  
  14.         parse_error(state, "invalid command '%s'\n", args[0]);  
  15.         return;  
  16.     }  
  17.   
  18.     n = kw_nargs(kw);  
  19.     if (nargs < n) {  
  20.         parse_error(state, "%s requires %d %s\n", args[0], n - 1,  
  21.             n > 2 ? "arguments" : "argument");  
  22.         return;  
  23.     }  
  24.     cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);  
  25.     cmd->func = kw_func(kw);  
  26.     cmd->nargs = nargs;  
  27.     memcpy(cmd->args, args, sizeof(char*) * nargs);  
  28.     list_add_tail(&act->commands, &cmd->clist);   //  

这里以class_start main为例该关键字为 KEYWORD(class_start, COMMAND, 1, do_class_start),填充一个command结构体,包括这个cmd的执行函数如class_start对应的func为do_class_start,函数的参数个数nargs=1。同时将这个cmd添加到action的commands所在的全局列表中。本文中将会出现2个cmd。

至此,on和service两个section已经举列子分析完成。

3 下面继续分析main函数中的queue_builtin_action和action_for_each_trigger。

queue_builtin_action(console_init_action, "console_init");//第二个开机画面显示函数
该函数实现将console_init这个action添加到action_queue全局链表中看。

action_for_each_trigger("boot", action_add_queue_tail);//把boot这个action添加到action_queue链表中

[plain]  view plain copy
  1. void action_for_each_trigger(const char *trigger,  
  2.                              void (*func)(struct action *act))  
  3. {  
  4.     struct listnode *node;  
  5.     struct action *act;  
  6.     list_for_each(node, &action_list) {  
  7.         act = node_to_item(node, struct action, alist);  
  8.         if (!strcmp(act->name, trigger)) {  
  9.             func(act);  
  10.         }  
  11.     }  
  12. }  

在该函数中,首先遍历action_list链表,找到action,看是否有名字叫boot的trigger存在,我们知道刚才在解析init.rc中的on boot时,将boot这个作为action的name加入到了action_list中去,所以可以找到这个boot的action。成功匹配后调用action_add_queue_tail,家这个action再次加入到action_queue中,等待着执行。

4 for(;;)循环中执行execute_one_command

[plain]  view plain copy
  1. void execute_one_command(void)  
  2. {  
  3.     int ret;  
  4.   
  5.     if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {  
  6.         cur_action = action_remove_queue_head();  
  7.         cur_command = NULL;  
  8.         if (!cur_action)  
  9.             return;  
  10.         INFO("processing action %p (%s)\n", cur_action, cur_action->name);  
  11.         cur_command = get_first_command(cur_action);  
  12.     } else {  
  13.         cur_command = get_next_command(cur_action, cur_command);  
  14.     }  
  15.   
  16.     if (!cur_command)  
  17.         return;  
  18.   
  19.     ret = cur_command->func(cur_command->nargs, cur_command->args);//执行class_start等  
  20.     INFO("command '%s' r=%d\n", cur_command->args[0], ret);  
  21. }  

使用action_remove_queue_head获取action_queue链表中的action后,移除该节点,使用get_first_command获得在action中的命令,比如这里出现的boot和console_init这两个action。针对console_init启动console_init_action这个函数。如果是boot则会对boot这个action所具有的commands链表进行cmd的获取,class_start的func指针函数为do_class_start:

[plain]  view plain copy
  1. int do_class_start(int nargs, char **args)  
  2. {  
  3.         /* Starting a class does not start services  
  4.          * which are explicitly disabled.  They must  
  5.          * be started individually.  
  6.          */  
  7.     service_for_each_class(args[1], service_start_if_not_disabled);//查找要启动的舒服所属类是否是当前要启动的类  
  8.     return 0;  
  9. }  

可以看到提取了命令行的第二个参数入main,core等。在service_for_each_class中遍历service_list查找属于该类的service,如我们前面提到的zygote,查找到后执行service_start_if_not_disabled——>service_start至此我们进入了启动service的代码

[plain]  view plain copy
  1. void service_start(struct service *svc, const char *dynamic_args)  
  2. {  
  3.     struct stat s;  
  4.     pid_t pid;  
  5.     int needs_console;  
  6.     int n;  
  7.   
  8.         /* starting a service removes it from the disabled  
  9.          * state and immediately takes it out of the restarting  
  10.          * state if it was in there  
  11.          */  
  12.     svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING));  
  13.     svc->time_started = 0;//服务的启动时间设为0   
  14.       
  15.         /* running processes require no additional work -- if  
  16.          * they're in the process of exiting, we've ensured  
  17.          * that they will immediately restart on exit, unless  
  18.          * they are ONESHOT  
  19.          */  
  20.     if (svc->flags & SVC_RUNNING) {  
  21.         return;  
  22.     }  
  23.   
  24.     needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;  
  25.     if (needs_console && (!have_console)) {  
  26.         ERROR("service '%s' requires console\n", svc->name);  
  27.         svc->flags |= SVC_DISABLED;  
  28.         return;  
  29.     }  
  30.   
  31.     if (stat(svc->args[0], &s) != 0) {   //通过文件名获取文件信息保存到s的buf中  
  32.         ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);  
  33.         svc->flags |= SVC_DISABLED;  
  34.         return;  
  35.     }  
  36.   
  37.     if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {  
  38.         ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",  
  39.                svc->args[0]);  
  40.         svc->flags |= SVC_DISABLED;  
  41.         return;  
  42.     }  
  43.   
  44.     NOTICE("starting '%s'\n", svc->name);  
  45.   
  46.     pid = fork();//创建子进程  
  47.   
  48.     if (pid == 0) {   //子进程  
  49.         struct socketinfo *si;  
  50.         struct svcenvinfo *ei;  
  51.         char tmp[32];  
  52.         int fd, sz;  
  53.   
  54.         if (properties_inited()) {  
  55.             get_property_workspace(&fd, &sz);  
  56.             sprintf(tmp, "%d,%d", dup(fd), sz);  
  57.             add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);  
  58.         }  
  59.   
  60.         for (ei = svc->envvars; ei; ei = ei->next)  
  61.             add_environment(ei->name, ei->value);  
  62.   
  63.         for (si = svc->sockets; si; si = si->next) {  
  64.             int socket_type = (  
  65.                     !strcmp(si->type, "stream") ? SOCK_STREAM :  
  66.                         (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));  
  67.             int s = create_socket(si->name, socket_type,  
  68.                                   si->perm, si->uid, si->gid);//创建套接字  
  69.             if (s >= 0) {  
  70.                 publish_socket(si->name, s);  
  71.             }  
  72.         }  
  73.   
  74.         if (svc->ioprio_class != IoSchedClass_NONE) {  
  75.             if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {  
  76.                 ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",  
  77.                       getpid(), svc->ioprio_class, svc->ioprio_pri, strerror(errno));  
  78.             }  
  79.         }  
  80.   
  81.         if (needs_console) {  
  82.             setsid();  
  83.             open_console();  
  84.         } else {  
  85.             zap_stdio();  
  86.         }  
  87.   
  88. #if 0  
  89.         for (n = 0; svc->args[n]; n++) {  
  90.             INFO("args[%d] = '%s'\n", n, svc->args[n]);  
  91.         }  
  92.         for (n = 0; ENV[n]; n++) {  
  93.             INFO("env[%d] = '%s'\n", n, ENV[n]);  
  94.         }  
  95. #endif  
  96.   
  97.         setpgid(0, getpid());  
  98.   
  99.     /* as requested, set our gid, supplemental gids, and uid */  
  100.         if (svc->gid) {  
  101.             setgid(svc->gid);  
  102.         }  
  103.         if (svc->nr_supp_gids) {  
  104.             setgroups(svc->nr_supp_gids, svc->supp_gids);  
  105.         }  
  106.         if (svc->uid) {  
  107.             setuid(svc->uid);  
  108.         }  
  109.   
  110.         if (!dynamic_args) {  
  111.             if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {  
  112.                 ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));//执行服务的可执行文件  
  113.             }  
  114.         } else {  
  115.             char *arg_ptrs[INIT_PARSER_MAXARGS+1];  
  116.             int arg_idx = svc->nargs;  
  117.             char *tmp = strdup(dynamic_args);  
  118.             char *next = tmp;  
  119.             char *bword;  
  120.   
  121.             /* Copy the static arguments */  
  122.             memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));  
  123.   
  124.             while((bword = strsep(&next, " "))) {  
  125.                 arg_ptrs[arg_idx++] = bword;  
  126.                 if (arg_idx == INIT_PARSER_MAXARGS)  
  127.                     break;  
  128.             }  
  129.             arg_ptrs[arg_idx] = '\0';  
  130.             execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);  
  131.         }  
  132.         _exit(127);  
  133.     }  
  134.   
  135.     if (pid < 0) {  
  136.         ERROR("failed to start '%s'\n", svc->name);  
  137.         svc->pid = 0;  
  138.         return;  
  139.     }  
  140.   
  141.     svc->time_started = gettime();  
  142.     svc->pid = pid;  
  143.     svc->flags |= SVC_RUNNING;  
  144.   
  145.     if (properties_inited())  
  146.         notify_service_state(svc->name, "running");  
  147. }  

分析这段代码,主要内容:

a.检查当前service如zygote的flag即SVC_RUNNING(服务运行中),SVC_DISABLE等

b.fork一个子进程,子进程中会建立一个socket用于通信,同时使用if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0)执行zygote对应的可执行文件,至此service zygote真正的启动。

到这里为止,对android系统的init启动有了清晰的了解,对init如何启动adbd,zygote等service有了一定的了解,以及对init.rc有了清晰的认识。init中还有部分内容等着后续几天做一定的学习。

补充:service进程的重启在restart_processes中进行,他会重启flag为SVC_RESTARTING的服务。这部分进程的重启其实在init由handle_signal来管理,一旦出现service崩溃,poll函数会接受到相关文件变化的信息,执行handle_signal中的wait_for_one_process

[plain]  view plain copy
  1. static int wait_for_one_process(int block)  
  2. {  
  3.     pid_t pid;  
  4.     int status;  
  5.     struct service *svc;  
  6.     struct socketinfo *si;  
  7.     time_t now;  
  8.     struct listnode *node;  
  9.     struct command *cmd;  
  10.   
  11.     while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );  
  12.     if (pid <= 0) return -1;  
  13.     INFO("waitpid returned pid %d, status = %08x\n", pid, status);  
  14.   
  15.     svc = service_find_by_pid(pid);  
  16.     if (!svc) {  
  17.         ERROR("untracked pid %d exited\n", pid);  
  18.         return 0;  
  19.     }  
  20. .....  
  21.  svc->flags |= SVC_RESTARTING;  
  22.   
  23.     /* Execute all onrestart commands for this service. */  
  24.     list_for_each(node, &svc->onrestart.commands) {  
  25.         cmd = node_to_item(node, struct command, clist);  
  26.         cmd->func(cmd->nargs, cmd->args);  
  27.     }  
  28.     notify_service_state(svc->name, "restarting");  
  29.     return 0;  
  30. }  

该函数使用waitpid,找到子进程退出的进程号pid,然后查找到该service,对service中的onrestart这个commands进行操作,入restart media等。同时将service的flag设置为SVC_RESTARTING,这样就结合前面讲到的restart_processes重新启动该服务进程。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值