Android6.0 init 深入分析

之前写过一篇关于android5.0 init的介绍,这篇博客是介绍android6.0init,之前有的代码介绍不详细。而且分析 解析init.rc那块代码也没有结合init.rc介绍。

一、 main函数的一些准备工作

下面我们分析下源码:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. int main(int argc, char** argv) {  
  2.     if (!strcmp(basename(argv[0]), "ueventd")) {  
  3.         return ueventd_main(argc, argv);  
  4.     }  
  5.   
  6.     if (!strcmp(basename(argv[0]), "watchdogd")) {  
  7.         return watchdogd_main(argc, argv);  
  8.     }  

由于ueventd watchdogd是公用代码,所以启动的时候根据文件名来判断是哪个进程,继续分析:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // Clear the umask.  
  2. umask(0);  
  3.   
  4. add_environment("PATH", _PATH_DEFPATH);//添加环境变量  
  5.   
  6. bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);  
  7.   
  8. // Get the basic filesystem setup we need put together in the initramdisk  
  9. // on / and then we'll let the rc file figure out the rest.  
  10. if (is_first_stage) {  
  11.     mount("tmpfs""/dev""tmpfs", MS_NOSUID, "mode=0755");  
  12.     mkdir("/dev/pts", 0755);  
  13.     mkdir("/dev/socket", 0755);  
  14.     mount("devpts""/dev/pts""devpts", 0, NULL);  
  15.     mount("proc""/proc""proc", 0, NULL);  
  16.     mount("sysfs""/sys""sysfs", 0, NULL);  
  17. }  

这块代码主要添加环境变量,以及挂载各种文件系统。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. open_devnull_stdio();  
  2. klog_init();  
  3. klog_set_level(KLOG_NOTICE_LEVEL);//log的初始化  
  4.   
  5. NOTICE("init%s started!\n", is_first_stage ? "" : " second stage");  
  6.   
  7. if (!is_first_stage) {  
  8.     // Indicate that booting is in progress to background fw loaders, etc.  
  9.     close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));//启动的时候创建一个.booting文件  
  10.   
  11.     property_init();//属性初始化  
  12.   
  13.     // If arguments are passed both on the command line and in DT,  
  14.     // properties set in DT always have priority over the command-line ones.  
  15.     process_kernel_dt();  
  16.     process_kernel_cmdline();  
  17.   
  18.     // Propogate the kernel variables to internal variables  
  19.     // used by init as well as the current required properties.  
  20.     export_kernel_boot_props();//设置一些属性  
  21. }  

这里我们有没有注意到is_first_stage这个变量,我们再来往下看。如果是is_first_stage会再执行execv函数,重新启动init。这个时候参数是"--second-stage"

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. if (is_first_stage) {  
  2.     if (restorecon("/init") == -1) {  
  3.         ERROR("restorecon failed: %s\n", strerror(errno));  
  4.         security_failure();  
  5.     }  
  6.     char* path = argv[0];  
  7.     char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };  
  8.     if (execv(path, args) == -1) {  
  9.         ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));  
  10.         security_failure();  
  11.     }  
  12. }  

这个时候再启动,也就是if_first_stage为false。这个时候参数有"--second-stage"了

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);  


我们再看上面函数先是open_devnull_stdio函数,这个函数就是把标准输入,输出,错误输出重定义到空设备上。然后创建一个 .booting文件代表系统在启动,做了一些属性的初始化,以及一些boot相关的系统属性设置获取等。我们先看下open_devnull_stdio代码:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void open_devnull_stdio(void)  
  2. {  
  3.     // Try to avoid the mknod() call if we can. Since SELinux makes  
  4.     // a /dev/null replacement available for free, let's use it.  
  5.     int fd = open("/sys/fs/selinux/null", O_RDWR);  
  6.     if (fd == -1) {  
  7.         // OOPS, /sys/fs/selinux/null isn't available, likely because  
  8.         // /sys/fs/selinux isn't mounted. Fall back to mknod.  
  9.         static const char *name = "/dev/__null__";  
  10.         if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {  
  11.             fd = open(name, O_RDWR);  
  12.             unlink(name);  
  13.         }  
  14.         if (fd == -1) {  
  15.             exit(1);  
  16.         }  
  17.     }  
  18.   
  19.     dup2(fd, 0);  
  20.     dup2(fd, 1);  
  21.     dup2(fd, 2);  
  22.     if (fd > 2) {  
  23.         close(fd);  
  24.     }  
  25. }  
property_init()函数主要是属性的初始化,这个我们在之前分析属性系统的那篇博客分析过了。
我们再来看process_kernel_dt函数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void process_kernel_dt(void)  
  2. {  
  3.     static const char android_dir[] = "/proc/device-tree/firmware/android";  
  4.   
  5.     std::string file_name = android::base::StringPrintf("%s/compatible", android_dir);  
  6.   
  7.     std::string dt_file;  
  8.     android::base::ReadFileToString(file_name, &dt_file);  
  9.     if (!dt_file.compare("android,firmware")) {//compatible文件内容是否是android,firmware  
  10.         ERROR("firmware/android is not compatible with 'android,firmware'\n");  
  11.         return;  
  12.     }  
  13.   
  14.     std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dir), closedir);  
  15.     if (!dir)  
  16.         return;  
  17.   
  18.     struct dirent *dp;  
  19.     while ((dp = readdir(dir.get())) != NULL) {//读取目录的每个文件  
  20.         if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible"))  
  21.             continue;  
  22.   
  23.         file_name = android::base::StringPrintf("%s/%s", android_dir, dp->d_name);  
  24.   
  25.         android::base::ReadFileToString(file_name, &dt_file);  
  26.         std::replace(dt_file.begin(), dt_file.end(), ',''.');  
  27.   
  28.         std::string property_name = android::base::StringPrintf("ro.boot.%s", dp->d_name);//每个文件名作为属性名,里面的内容作为属性值  
  29.         property_set(property_name.c_str(), dt_file.c_str());  
  30.     }  
  31. }  

上面这个函数主要是在/proc/device-tree/firmware/Android 这个目录下,先看compatible文件内容是否是android,firmware。然后这个目录下每个文件名作为属性,文件里面的内容作为属性值。这里话就是ro.boot.hareware ro.boot.name这两个属性值。

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. root@lte26007:/proc/device-tree/firmware/android # ls  
  2. compatible  
  3. hardware  
  4. name  
继续看process_kernel_cmdline函数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void process_kernel_cmdline(void)  
  2. {  
  3.     /* don't expose the raw commandline to nonpriv processes */  
  4.     chmod("/proc/cmdline", 0440);  
  5.   
  6.     /* first pass does the common stuff, and finds if we are in qemu. 
  7.      * second pass is only necessary for qemu to export all kernel params 
  8.      * as props. 
  9.      */  
  10.     import_kernel_cmdline(false, import_kernel_nv);  
  11.     if (qemu[0])  
  12.         import_kernel_cmdline(true, import_kernel_nv);  
  13. }  

import_kernel_cmdline函数就是读取proc/cmdline中的内容,然后调用import_kernel_nv函数设置系统属性

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void import_kernel_cmdline(bool in_qemu, std::function<void(char*,bool)> import_kernel_nv)  
  2. {  
  3.     char cmdline[2048];  
  4.     char *ptr;  
  5.     int fd;  
  6.   
  7.     fd = open("/proc/cmdline", O_RDONLY | O_CLOEXEC);  
  8.     if (fd >= 0) {  
  9.         int n = read(fd, cmdline, sizeof(cmdline) - 1);  
  10.         if (n < 0) n = 0;  
  11.   
  12.         /* get rid of trailing newline, it happens */  
  13.         if (n > 0 && cmdline[n-1] == '\n') n--;  
  14.   
  15.         cmdline[n] = 0;  
  16.         close(fd);  
  17.     } else {  
  18.         cmdline[0] = 0;  
  19.     }  
  20.   
  21.     ptr = cmdline;  
  22.     while (ptr && *ptr) {  
  23.         char *x = strchr(ptr, ' ');  
  24.         if (x != 0) *x++ = 0;  
  25.         import_kernel_nv(ptr, in_qemu);  
  26.         ptr = x;  
  27.     }  
  28. }  

在import_kernel_nv函数中设置系统属性,但是一定要有androidboot这样的关键字眼才会设置ro.boot这样的属性。这块在我们的设备cmdline中没有这样的字眼,也就不会设置这些属性。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void import_kernel_nv(char *name, bool for_emulator)  
  2. {  
  3.     char *value = strchr(name, '=');  
  4.     int name_len = strlen(name);  
  5.   
  6.     if (value == 0) return;  
  7.     *value++ = 0;  
  8.     if (name_len == 0) return;  
  9.   
  10.     if (for_emulator) {  
  11.         /* in the emulator, export any kernel option with the 
  12.          * ro.kernel. prefix */  
  13.         char buff[PROP_NAME_MAX];  
  14.         int len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name );  
  15.   
  16.         if (len < (int)sizeof(buff))  
  17.             property_set( buff, value );  
  18.         return;  
  19.     }  
  20.   
  21.     if (!strcmp(name,"qemu")) {  
  22.         strlcpy(qemu, value, sizeof(qemu));  
  23.     } else if (!strncmp(name, "androidboot.", 12) && name_len > 12) {  
  24.         const char *boot_prop_name = name + 12;  
  25.         char prop[PROP_NAME_MAX];  
  26.         int cnt;  
  27.   
  28.         cnt = snprintf(prop, sizeof(prop), "ro.boot.%s", boot_prop_name);  
  29.         if (cnt < PROP_NAME_MAX)  
  30.             property_set(prop, value);  
  31.     }  
  32. }  

再来看export_kernel_boot_props这个函数,它也就是设置一些属性,设置ro属性根据之前ro.boot这类的属性值,如果没有设置成unknown,像之前我们有ro.boot.hardware, 那我们就可以设置root.hardware这样的属性。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void export_kernel_boot_props() {  
  2.     struct {  
  3.         const char *src_prop;  
  4.         const char *dst_prop;  
  5.         const char *default_value;  
  6.     } prop_map[] = {  
  7.         //{ "ro.boot.serialno",   "ro.serialno",   "", },  
  8.         { "ro.boot.mode",       "ro.bootmode",   "unknown", },  
  9.         { "ro.boot.baseband",   "ro.baseband",   "unknown", },  
  10.         { "ro.boot.bootloader""ro.bootloader""unknown", },  
  11.         { "ro.boot.hardware",   "ro.hardware",   "unknown", },  
  12.         { "ro.boot.revision",   "ro.revision",   "0", },  
  13.     };  
  14.     for (size_t i = 0; i < ARRAY_SIZE(prop_map); i++) {  
  15.         char value[PROP_VALUE_MAX];  
  16.         int rc = property_get(prop_map[i].src_prop, value);  
  17.         property_set(prop_map[i].dst_prop, (rc > 0) ? value : prop_map[i].default_value);  
  18.     }  
  19. }  

下面这块都是selinux相关的,我们就不分析了。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.  
  2. selinux_initialize(is_first_stage);  
  3.   
  4. // If we're in the kernel domain, re-exec init to transition to the init domain now  
  5. // that the SELinux policy has been loaded.  
  6. if (is_first_stage) {  
  7.     if (restorecon("/init") == -1) {  
  8.         ERROR("restorecon failed: %s\n", strerror(errno));  
  9.         security_failure();  
  10.     }  
  11.     char* path = argv[0];  
  12.     char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };  
  13.     if (execv(path, args) == -1) {  
  14.         ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));  
  15.         security_failure();  
  16.     }  
  17. }  
  18.   
  19. // These directories were necessarily created before initial policy load  
  20. // and therefore need their security context restored to the proper value.  
  21. // This must happen before /dev is populated by ueventd.  
  22. INFO("Running restorecon...\n");  
  23. restorecon("/dev");  
  24. restorecon("/dev/socket");  
  25. restorecon("/dev/__properties__");  
  26. restorecon_recursive("/sys");  

然后创建了一个epoll的fd

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. epoll_fd = epoll_create1(EPOLL_CLOEXEC);  
  2. if (epoll_fd == -1) {  
  3.     ERROR("epoll_create1 failed: %s\n", strerror(errno));  
  4.     exit(1);  
  5. }  

继续分析,signal_handler_init函数主要是当子进程被kill之后,会在父进程接受一个信号。处理这个信号的时候往sockpair一端写数据,而另一端的fd是加入的epoll中。这块我们后面会专门其一节讲解。而property_load_boot_defaults就是解析根目录的default.prop中的属性,然后设置到属性中去。start_prperty_service就是把接受属性的socket的fd加入epoll中,也定义了处理函数,属性之前博客专门分析过了。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. signal_handler_init();  
  2.   
  3. property_load_boot_defaults();  
  4. start_property_service();  

看看signal_handler_init函数就是处理子进程kill时的情况。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void SIGCHLD_handler(int) {  
  2.     if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {  
  3.         ERROR("write(signal_write_fd) failed: %s\n", strerror(errno));  
  4.     }  
  5. }  
  6.   
  7. void signal_handler_init() {  
  8.     // Create a signalling mechanism for SIGCHLD.  
  9.     int s[2];  
  10.     if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {  
  11.         ERROR("socketpair failed: %s\n", strerror(errno));  
  12.         exit(1);  
  13.     }  
  14.   
  15.     signal_write_fd = s[0];  
  16.     signal_read_fd = s[1];  
  17.   
  18.     // Write to signal_write_fd if we catch SIGCHLD.  
  19.     struct sigaction act;  
  20.     memset(&act, 0, sizeof(act));  
  21.     act.sa_handler = SIGCHLD_handler;  
  22.     act.sa_flags = SA_NOCLDSTOP;  
  23.     sigaction(SIGCHLD, &act, 0);  
  24.   
  25.     reap_any_outstanding_children();  
  26.   
  27.     register_epoll_handler(signal_read_fd, handle_signal);  
  28. }  


二、解析init.rc

下面我们开始分析解析init.rc并且结合init.rc一起看

init.rc的语言我们可以看这篇博客,主要是init.rc主要有Actions和Service两种,具体看这篇博客http://blog.csdn.net/kc58236582/article/details/52042331

我们通过init_parse_config_file函数来解析init.rc,先把文件数据读取到data中,然后调用parse_config来解析数据。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. int init_parse_config_file(const char* path) {  
  2.     INFO("Parsing %s...\n", path);  
  3.     Timer t;  
  4.     std::string data;  
  5.     if (!read_file(path, &data)) {  
  6.         return -1;  
  7.     }  
  8.   
  9.     data.push_back('\n'); // TODO: fix parse_config.  
  10.     parse_config(path, data);  
  11.     dump_parser_state();  
  12.   
  13.     NOTICE("(Parsing %s took %.2fs.)\n", path, t.duration());  
  14.     return 0;  
  15. }  

我们先来看看dump_parser_state函数,当解析完之后我们可以在这个函数中打印所有的service和action。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void dump_parser_state() {  
  2.     if (false) {  
  3.         struct listnode* node;  
  4.         list_for_each(node, &service_list) {  
  5.             service* svc = node_to_item(node, struct service, slist);  
  6.             INFO("service %s\n", svc->name);  
  7.             INFO("  class '%s'\n", svc->classname);  
  8.             INFO("  exec");  
  9.             for (int n = 0; n < svc->nargs; n++) {  
  10.                 INFO(" '%s'", svc->args[n]);  
  11.             }  
  12.             INFO("\n");  
  13.             for (socketinfo* si = svc->sockets; si; si = si->next) {  
  14.                 INFO("  socket %s %s 0%o\n", si->name, si->type, si->perm);  
  15.             }  
  16.         }  
  17.   
  18.         list_for_each(node, &action_list) {  
  19.             action* act = node_to_item(node, struct action, alist);  
  20.             INFO("on ");  
  21.             char name_str[256] = "";  
  22.             build_triggers_string(name_str, sizeof(name_str), act);  
  23.             INFO("%s", name_str);  
  24.             INFO("\n");  
  25.   
  26.             struct listnode* node2;  
  27.             list_for_each(node2, &act->commands) {  
  28.                 command* cmd = node_to_item(node2, struct command, clist);  
  29.                 INFO("  %p", cmd->func);  
  30.                 for (int n = 0; n < cmd->nargs; n++) {  
  31.                     INFO(" %s", cmd->args[n]);  
  32.                 }  
  33.                 INFO("\n");  
  34.             }  
  35.             INFO("\n");  
  36.         }  
  37.     }  
  38. }  

好回到正题看parse_config函数,来解析从init.rc文件中获取的数据。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void parse_config(const char *fn, const std::string& data)  
  2. {  
  3.     struct listnode import_list;  
  4.     struct listnode *node;  
  5.     char *args[INIT_PARSER_MAXARGS];  
  6.   
  7.     int nargs = 0;  
  8.   
  9.     parse_state state;  
  10.     state.filename = fn;  
  11.     state.line = 0;  
  12.     state.ptr = strdup(data.c_str());  // TODO: fix this code!  
  13.     state.nexttoken = 0;  
  14.     state.parse_line = parse_line_no_op;//这里的函数是空实现  
  15.   
  16.     list_init(&import_list);  
  17.     state.priv = &import_list;  
  18.   
  19.     for (;;) {  
  20.         switch (next_token(&state)) {  
  21.         case T_EOF:  
  22.             state.parse_line(&state, 0, 0);  
  23.             goto parser_done;  
  24.         case T_NEWLINE:  
  25.             state.line++;  
  26.             if (nargs) {  
  27.                 int kw = lookup_keyword(args[0]);  
  28.                 if (kw_is(kw, SECTION)) {  
  29.                     state.parse_line(&state, 0, 0);  
  30.                     parse_new_section(&state, kw, nargs, args);  
  31.                 } else {  
  32.                     state.parse_line(&state, nargs, args);  
  33.                 }  
  34.                 nargs = 0;  
  35.             }  
  36.             break;  
  37.         case T_TEXT:  
  38.             if (nargs < INIT_PARSER_MAXARGS) {  
  39.                 args[nargs++] = state.text;  
  40.             }  
  41.             break;  
  42.         }  
  43.     }  
  44.   
  45. parser_done:  
  46.     list_for_each(node, &import_list) {  
  47.          struct import *import = node_to_item(node, struct import, list);  
  48.          int ret;  
  49.   
  50.          ret = init_parse_config_file(import->filename);  
  51.          if (ret)  
  52.              ERROR("could not import file '%s' from '%s'\n",  
  53.                    import->filename, fn);  
  54.     }  
  55. }  

我们先来看看next_token函数,我们来看下这个函数,

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. int next_token(struct parse_state *state)  
  2. {  
  3.     char *x = state->ptr;  
  4.     char *s;  
  5.   
  6.     if (state->nexttoken) {//刚进来为空  
  7.         int t = state->nexttoken;  
  8.         state->nexttoken = 0;  
  9.         return t;  
  10.     }  
  11.   
  12.     for (;;) {  
  13.         switch (*x) {  
  14.         case 0:  
  15.             state->ptr = x;  
  16.             return T_EOF;  
  17.         case '\n':  
  18.             x++;  
  19.             state->ptr = x;  
  20.             return T_NEWLINE;  
  21.         case ' ':  
  22.         case '\t':  
  23.         case '\r':  
  24.             x++;  
  25.             continue;  
  26.         case '#':  
  27.             while (*x && (*x != '\n')) x++;  
  28.             if (*x == '\n') {  
  29.                 state->ptr = x+1;  
  30.                 return T_NEWLINE;  
  31.             } else {  
  32.                 state->ptr = x;  
  33.                 return T_EOF;  
  34.             }  
  35.         default://刚进来肯定直接是这个  
  36.             goto text;  
  37.         }  
  38.     }  
  39.   
  40. textdone:  
  41.     state->ptr = x;  
  42.     *s = 0;  
  43.     return T_TEXT;  
  44. text:  
  45.     state->text = s = x;//赋值state->text  
  46. textresume:  
  47.     for (;;) {  
  48.         switch (*x) {  
  49.         case 0:  
  50.             goto textdone;  
  51.         case ' ':  
  52.         case '\t':  
  53.         case '\r'://碰到空什么的,直接返回T_TEXT  
  54.             x++;  
  55.             goto textdone;  
  56.         case '\n':  
  57.             state->nexttoken = T_NEWLINE;//碰到回车换行直接nexttoken是newline  
  58.             x++;  
  59.             goto textdone;  
  60.         case '"':  
  61.             x++;  
  62.             for (;;) {  
  63.                 switch (*x) {  
  64.                 case 0:  
  65.                         /* unterminated quoted thing */  
  66.                     state->ptr = x;  
  67.                     return T_EOF;  
  68.                 case '"':  
  69.                     x++;  
  70.                     goto textresume;  
  71.                 default:  
  72.                     *s++ = *x++;  
  73.                 }  
  74.             }  
  75.             break;  
  76.         case '\\':  
  77.             x++;  
  78.             switch (*x) {  
  79.             case 0:  
  80.                 goto textdone;  
  81.             case 'n':  
  82.                 *s++ = '\n';  
  83.                 break;  
  84.             case 'r':  
  85.                 *s++ = '\r';  
  86.                 break;  
  87.             case 't':  
  88.                 *s++ = '\t';  
  89.                 break;  
  90.             case '\\':  
  91.                 *s++ = '\\';  
  92.                 break;  
  93.             case '\r':  
  94.                     /* \ <cr> <lf> -> line continuation */  
  95.                 if (x[1] != '\n') {  
  96.                     x++;  
  97.                     continue;  
  98.                 }  
  99.             case '\n':  
  100.                     /* \ <lf> -> line continuation */  
  101.                 state->line++;  
  102.                 x++;  
  103.                     /* eat any extra whitespace */  
  104.                 while((*x == ' ') || (*x == '\t')) x++;  
  105.                 continue;  
  106.             default:  
  107.                     /* unknown escape -- just copy */  
  108.                 *s++ = *x++;  
  109.             }  
  110.             continue;  
  111.         default:  
  112.             *s++ = *x++;//一般的值继续往前走  
  113.         }  
  114.     }  
  115.     return T_EOF;  
  116. }  

看这个函数的代码,我们只需要知道。当我们普通的进来,没有碰到换行,只有碰到空格的话,返回T_TEXT,并且nextoken为null。

我们再来看T_TEXT的时候只是在数组里面保存了state.text的内容,然后继续下一次。当我们直到碰到/n,回车换行。这个时候返回T_TEXT,但是nexttoken是T_NEWLINE

这样下次,就直接返回T_NEWLINE了,当返回T_NEWLINE直接调用lookup_keyword函数。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. for (;;) {  
  2.     switch (next_token(&state)) {  
  3.     case T_EOF:  
  4.         state.parse_line(&state, 0, 0);  
  5.         goto parser_done;  
  6.     case T_NEWLINE:  
  7.         state.line++;  
  8.         if (nargs) {  
  9.             int kw = lookup_keyword(args[0]);  
  10.             if (kw_is(kw, SECTION)) {  
  11.                 state.parse_line(&state, 0, 0);  
  12.                 parse_new_section(&state, kw, nargs, args);  
  13.             } else {  
  14.                 state.parse_line(&state, nargs, args);  
  15.             }  
  16.             nargs = 0;  
  17.         }  
  18.         break;  
  19.     case T_TEXT:  
  20.         if (nargs < INIT_PARSER_MAXARGS) {  
  21.             args[nargs++] = state.text;  
  22.         }  
  23.         break;  
  24.     }  
  25. }  

lookup_keyword函数就是看第一个单词返回一个K_**的值而已。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static int lookup_keyword(const char *s)  
  2. {  
  3.     switch (*s++) {  
  4.     case 'b':  
  5.         if (!strcmp(s, "ootchart_init")) return K_bootchart_init;  
  6.         break;  
  7.     case 'c':  
  8.         if (!strcmp(s, "opy")) return K_copy;  
  9.         if (!strcmp(s, "lass")) return K_class;  
  10.         if (!strcmp(s, "lass_start")) return K_class_start;  
  11.         if (!strcmp(s, "lass_stop")) return K_class_stop;  
  12.         if (!strcmp(s, "lass_reset")) return K_class_reset;  
  13.         if (!strcmp(s, "onsole")) return K_console;  
  14.         if (!strcmp(s, "hown")) return K_chown;  
  15.         if (!strcmp(s, "hmod")) return K_chmod;  
  16.         if (!strcmp(s, "ritical")) return K_critical;  
  17.         break;  
  18.     case 'd':  
  19.         if (!strcmp(s, "isabled")) return K_disabled;  
  20.         if (!strcmp(s, "omainname")) return K_domainname;  
  21.         break;  
  22.     case 'e':  
  23.         if (!strcmp(s, "nable")) return K_enable;  
  24.         if (!strcmp(s, "xec")) return K_exec;  
  25.         if (!strcmp(s, "xport")) return K_export;  
  26.         break;  
  27.     case 'g':  
  28.         if (!strcmp(s, "roup")) return K_group;  
  29.         break;  
  30.     case 'h':  
  31.         if (!strcmp(s, "ostname")) return K_hostname;  
  32.         break;  
  33.     case 'i':  
  34.         if (!strcmp(s, "oprio")) return K_ioprio;  
  35.         if (!strcmp(s, "fup")) return K_ifup;  
  36.         if (!strcmp(s, "nsmod")) return K_insmod;  
  37.         if (!strcmp(s, "mport")) return K_import;  
  38.         if (!strcmp(s, "nstallkey")) return K_installkey;  
  39.         break;  
  40.     case 'k':  
  41.         if (!strcmp(s, "eycodes")) return K_keycodes;  
  42.         break;  
  43.     case 'l':  
  44.         if (!strcmp(s, "oglevel")) return K_loglevel;  
  45.         if (!strcmp(s, "oad_persist_props")) return K_load_persist_props;  
  46.         if (!strcmp(s, "oad_system_props")) return K_load_system_props;  
  47.         break;  
  48.     case 'm':  
  49.         if (!strcmp(s, "kdir")) return K_mkdir;  
  50.         if (!strcmp(s, "ount_all")) return K_mount_all;  
  51.         if (!strcmp(s, "ount")) return K_mount;  
  52.         break;  

再来看这个宏

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #define kw_is(kw, type) (keyword_info[kw].flags & (type))  

来看看它的定义,首先先说下宏定义##代表后面是连接起来的,#代表就是后面这个变量

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #define KEYWORD(symbol, flags, nargs, func) \  
  2.     [ K_##symbol ] = { #symbol, func, nargs + 1, flags, },  
  3.   
  4. static struct {  
  5.     const char *name;  
  6.     int (*func)(int nargs, char **args);  
  7.     unsigned char nargs;  
  8.     unsigned char flags;  
  9. } keyword_info[KEYWORD_COUNT] = {  
  10.     [ K_UNKNOWN ] = { "unknown", 0, 0, 0 },  
  11. #include "keywords.h"  
  12. };  

这样我们再来看下keywords.h这个头文件,这里就比较明白是它是解析各个关键词是属于SECTION,COMMAND,OPTION的

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #ifndef KEYWORD//因为前面定义了KEYWORD  
  2. int do_bootchart_init(int nargs, char **args);  
  3. ......  
  4. #endif  
  5.     KEYWORD(bootchart_init,        COMMAND, 0, do_bootchart_init)  
  6.     KEYWORD(chmod,       COMMAND, 2, do_chmod)  
  7.     KEYWORD(chown,       COMMAND, 2, do_chown)  
  8.     KEYWORD(class,       OPTION,  0, 0)  
  9. ......  
  10.     KEYWORD(import,      SECTION, 1, 0)  
  11. .....  
  12. .....  
  13.     KEYWORD(service,     SECTION, 0, 0)  
  14.     KEYWORD(writepid,    OPTION,  0, 0)  
  15. #ifdef __MAKE_KEYWORD_ENUM__  
  16.     KEYWORD_COUNT,  
  17. };  
  18. #undef __MAKE_KEYWORD_ENUM__  
  19. #undef KEYWORD  
  20. #endif  

这样我们就可以通过kw_is(kw, SECTION)来判断是否属于SECTION

我们来看下函数,如果是SECTION,刚开始调用state.parse_line也是空实现

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. if (kw_is(kw, SECTION)) {  
  2.     state.parse_line(&state, 0, 0);  
  3.     parse_new_section(&state, kw, nargs, args);  
  4. else {  
  5.     state.parse_line(&state, nargs, args);  
  6. }  

再来看看parse_new_section函数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void parse_new_section(struct parse_state *state, int kw,  
  2.                        int nargs, char **args)  
  3. {  
  4.     printf("[ %s %s ]\n", args[0],  
  5.            nargs > 1 ? args[1] : "");  
  6.     switch(kw) {  
  7.     case K_service://如果是service  
  8.         state->context = parse_service(state, nargs, args);  
  9.         if (state->context) {  
  10.             state->parse_line = parse_line_service;  
  11.             return;  
  12.         }  
  13.         break;  
  14.     case K_on://是on  
  15.         state->context = parse_action(state, nargs, args);  
  16.         if (state->context) {  
  17.             state->parse_line = parse_line_action;  
  18.             return;  
  19.         }  
  20.         break;  
  21.     case K_import://是import  
  22.         parse_import(state, nargs, args);  
  23.         break;  
  24.     }  
  25.     state->parse_line = parse_line_no_op;  
  26. }  


2.1 解析service

我们先来看下如果是service,先调用parse_service函数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void *parse_service(struct parse_state *state, int nargs, char **args)  
  2. {  
  3.     if (nargs < 3) {  
  4.         parse_error(state, "services must have a name and a program\n");  
  5.         return 0;  
  6.     }  
  7.     if (!valid_name(args[1])) {  
  8.         parse_error(state, "invalid service name '%s'\n", args[1]);  
  9.         return 0;  
  10.     }  
  11.   
  12.     service* svc = (service*) service_find_by_name(args[1]);//找service  
  13.     if (svc) {//如果找到该service,说明重复了  
  14.         parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);  
  15.         return 0;  
  16.     }  
  17.   
  18.     nargs -= 2;  
  19.     svc = (service*) calloc(1, sizeof(*svc) + sizeof(char*) * nargs);//new一个service  
  20.     if (!svc) {  
  21.         parse_error(state, "out of memory\n");  
  22.         return 0;  
  23.     }  
  24.     svc->name = strdup(args[1]);//各种初始化  
  25.     svc->classname = "default";  
  26.     memcpy(svc->args, args + 2, sizeof(char*) * nargs);  
  27.     trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));  
  28.     svc->args[nargs] = 0;  
  29.     svc->nargs = nargs;  
  30.     list_init(&svc->onrestart.triggers);  
  31.     cur_trigger->name = "onrestart";  
  32.     list_add_tail(&svc->onrestart.triggers, &cur_trigger->nlist);  
  33.     list_init(&svc->onrestart.commands);  
  34.     list_add_tail(&service_list, &svc->slist);//把service放进service_list  
  35.     return svc;  
  36. }  

state->parse_line赋值了parse_line_service函数了。然后我们再出这个函数看看,当你再来一行新的,这个时候不是SECTION,就要调用parse_line_service函数来解析了。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. case T_NEWLINE:  
  2.     state.line++;  
  3.     if (nargs) {  
  4.         int kw = lookup_keyword(args[0]);  
  5.         if (kw_is(kw, SECTION)) {  
  6.             state.parse_line(&state, 0, 0);  
  7.             parse_new_section(&state, kw, nargs, args);  
  8.         } else {  
  9.             state.parse_line(&state, nargs, args);  
  10.         }  
  11.         nargs = 0;  
  12.     }  
  13.     break;  

我们来看下parse_line_service函数:下面就是解析各种参数,然后填充service变量而已。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void parse_line_service(struct parse_state *state, int nargs, char **args)  
  2. {  
  3.     struct service *svc = (service*) 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_class:  
  16.         if (nargs != 2) {  
  17.             parse_error(state, "class option requires a classname\n");  
  18.         } else {  
  19.             svc->classname = args[1];  
  20.         }  
  21.         break;  
  22.     case K_console:  
  23.         svc->flags |= SVC_CONSOLE;  
  24.         break;  
  25.     case K_disabled:  


2.2 解析on关键字

下面我们来看下解析on关键字的

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. case K_on:  
  2.     state->context = parse_action(state, nargs, args);  
  3.     if (state->context) {  
  4.         state->parse_line = parse_line_action;  
  5.         return;  
  6.     }  
  7.     break;  
先看下parse_action函数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void *parse_action(struct parse_state *state, int nargs, char **args)  
  2. {  
  3.     struct trigger *cur_trigger;  
  4.     int i;  
  5.     if (nargs < 2) {  
  6.         parse_error(state, "actions must have a trigger\n");  
  7.         return 0;  
  8.     }  
  9.   
  10.     action* act = (action*) calloc(1, sizeof(*act));//新建aciton  
  11.     list_init(&act->triggers);  
  12.   
  13.     for (i = 1; i < nargs; i++) {  
  14.         if (!(i % 2)) {  
  15.             if (strcmp(args[i], "&&")) {//有的触发器有几个条件,比如可以两个属性同事满足  
  16.                 struct listnode *node;  
  17.                 struct listnode *node2;  
  18.                 parse_error(state, "& is the only symbol allowed to concatenate actions\n");  
  19.                 list_for_each_safe(node, node2, &act->triggers) {  
  20.                     struct trigger *trigger = node_to_item(node, struct trigger, nlist);  
  21.                     free(trigger);  
  22.                 }  
  23.                 free(act);  
  24.                 return 0;  
  25.             } else  
  26.                 continue;  
  27.         }  
  28.         cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));  
  29.         cur_trigger->name = args[i];  
  30.         list_add_tail(&act->triggers, &cur_trigger->nlist);  
  31.     }  
  32.   
  33.     list_init(&act->commands);  
  34.     list_init(&act->qlist);  
  35.     list_add_tail(&action_list, &act->alist);//把aciton加入action_list中  
  36.         /* XXX add to hash */  
  37.     return act;  
  38. }  

这里新建一个action,然后加入action_list中。主要触发器可以有几个条件。比如满足两个属性要求,然后保存在action的的triggers中。

同样我们再来看看parse_line_action函数,这个函数就是各种命令了。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void parse_line_action(struct parse_state* state, int nargs, char **args)  
  2. {  
  3.     struct action *act = (action*) state->context;  
  4.     int kw, n;  
  5.   
  6.     if (nargs == 0) {  
  7.         return;  
  8.     }  
  9.   
  10.     kw = lookup_keyword(args[0]);  
  11.     if (!kw_is(kw, COMMAND)) {  
  12.         parse_error(state, "invalid command '%s'\n", args[0]);  
  13.         return;  
  14.     }  
  15.   
  16.     n = kw_nargs(kw);  
  17.     if (nargs < n) {  
  18.         parse_error(state, "%s requires %d %s\n", args[0], n - 1,  
  19.             n > 2 ? "arguments" : "argument");  
  20.         return;  
  21.     }  
  22.     command* cmd = (command*) malloc(sizeof(*cmd) + sizeof(char*) * nargs);  
  23.     cmd->func = kw_func(kw);  
  24.     cmd->line = state->line;  
  25.     cmd->filename = state->filename;  
  26.     cmd->nargs = nargs;  
  27.     memcpy(cmd->args, args, sizeof(char*) * nargs);  
  28.     list_add_tail(&act->commands, &cmd->clist);// 加入到act->commands  
  29. }  

这里注意是kw_func宏,就是和之前那个宏一样,这里是选择每个命令的处理函数。


2.3 处理import

处理import我们来看下parse_import函数,这个函数很简单就把import的文件名保存在import_list中。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void parse_import(struct parse_state *state, int nargs, char **args)  
  2. {  
  3.     struct listnode *import_list = (listnode*) state->priv;  
  4.     char conf_file[PATH_MAX];  
  5.     int ret;  
  6.   
  7.     if (nargs != 2) {  
  8.         ERROR("single argument needed for import\n");  
  9.         return;  
  10.     }  
  11.   
  12.     ret = expand_props(conf_file, args[1], sizeof(conf_file));  
  13.     if (ret) {  
  14.         ERROR("error while handling import on line '%d' in '%s'\n",  
  15.               state->line, state->filename);  
  16.         return;  
  17.     }  
  18.   
  19.     struct import* import = (struct import*) calloc(1, sizeof(struct import));  
  20.     import->filename = strdup(conf_file);  
  21.     list_add_tail(import_list, &import->list);  
  22.     INFO("Added '%s' to import list\n", import->filename);  
  23. }  

最后我们来看下当所有init.rc中的关键字解析完之后,就会遍历import_list,然后调用init_parse_config_file函数再来解析该文件。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. parser_done:  
  2.     list_for_each(node, &import_list) {  
  3.          struct import *import = node_to_item(node, struct import, list);  
  4.          int ret;  
  5.   
  6.          ret = init_parse_config_file(import->filename);  
  7.          if (ret)  
  8.              ERROR("could not import file '%s' from '%s'\n",  
  9.                    import->filename, fn);  
  10.     }  

所以一般在init.rc中import的文件,放入action service列表中,会比直接在init.rc中的service和aciton靠后。


三、加入执行队列

在解析init.rc文件后,这节将介绍把Action加入执行队列中。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. action_for_each_trigger("early-init", action_add_queue_tail);  
  2.   
  3. // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...  
  4. queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");  
  5. // ... so that we can start queuing up actions that require stuff from /dev.  
  6. queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");  
  7. queue_builtin_action(keychord_init_action, "keychord_init");  
  8. queue_builtin_action(console_init_action, "console_init");  
  9.   
  10. // Trigger all the boot actions to get us started.  
  11. action_for_each_trigger("init", action_add_queue_tail);  
  12.   
  13. // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random  
  14. // wasn't ready immediately after wait_for_coldboot_done  
  15. queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");  
  16.   
  17. // Don't mount filesystems or start core system services in charger mode.  
  18. char bootmode[PROP_VALUE_MAX];  
  19. if (property_get("ro.bootmode", bootmode) > 0 && strcmp(bootmode, "charger") == 0) {  
  20.     action_for_each_trigger("charger", action_add_queue_tail);  
  21. else {  
  22.     action_for_each_trigger("late-init", action_add_queue_tail);  
  23. }  
  24.   
  25. // Run all property triggers based on current state of the properties.  
  26. queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");  

我们先来看action_for_each_trigger函数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void action_for_each_trigger(const char *trigger,  
  2.                              void (*func)(struct action *act))  
  3. {  
  4.     struct listnode *node, *node2;  
  5.     struct action *act;  
  6.     struct trigger *cur_trigger;  
  7.   
  8.     list_for_each(node, &action_list) {//遍历每个action  
  9.         act = node_to_item(node, struct action, alist);  
  10.         list_for_each(node2, &act->triggers) {//遍历每个action的triggers  
  11.             cur_trigger = node_to_item(node2, struct trigger, nlist);  
  12.             if (!strcmp(cur_trigger->name, trigger)) {//是否与传入的trigger名字匹配  
  13.                 func(act);//调用回调函数  
  14.             }  
  15.         }  
  16.     }  
  17. }  

我们再来看下传入的回调函数action_add_queue_tail,这个函数就是把aciton加入执行列表中。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void action_add_queue_tail(struct action *act)  
  2. {  
  3.     if (list_empty(&act->qlist)) {  
  4.         list_add_tail(&action_queue, &act->qlist);  
  5.     }  
  6. }  

1. 这样的话像第一句,就是在所有的aciton中是否有early-init这样的trigger,有的话加入执行列表。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. action_for_each_trigger("early-init", action_add_queue_tail);  

我们看下init.rc中early-init中的内容,设置了init进程的adj,开启ueventd进程等。

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. on early-init  
  2.     # Set init and its forked children's oom_adj.  
  3.     write /proc/1/oom_score_adj -1000  
  4.   
  5.     # Set the security context of /adb_keys if present.  
  6.     restorecon /adb_keys  
  7.   
  8.     start ueventd  
  9.   
  10.     #add for amt  
  11.     mkdir /amt 0775 root system  

下面我们再来看下queue_builtin_action函数,这个函数的话就是直接创建一个action,然后新建command,关键是func会调函数设置好。最后把action加入执行队列中。

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void queue_builtin_action(int (*func)(int nargs, char **args), const char *name)  
  2. {  
  3.     action* act = (action*) calloc(1, sizeof(*act));  
  4.     trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));  
  5.     cur_trigger->name = name;  
  6.     list_init(&act->triggers);  
  7.     list_add_tail(&act->triggers, &cur_trigger->nlist);  
  8.     list_init(&act->commands);  
  9.     list_init(&act->qlist);  
  10.   
  11.     command* cmd = (command*) calloc(1, sizeof(*cmd));  
  12.     cmd->func = func;  
  13.     cmd->args[0] = const_cast<char*>(name);  
  14.     cmd->nargs = 1;  
  15.     list_add_tail(&act->commands, &cmd->clist);  
  16.   
  17.     list_add_tail(&action_list, &act->alist);  
  18.     action_add_queue_tail(act);  
  19. }  

2. 因此这里我们看下wait_for_coldboot_done_action函数,这函数就是等待/dev/.coldboot_done文件

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static int wait_for_coldboot_done_action(int nargs, char **args) {  
  2.     Timer t;  
  3.   
  4.     NOTICE("Waiting for %s...\n", COLDBOOT_DONE);  
  5.     // Any longer than 1s is an unreasonable length of time to delay booting.  
  6.     // If you're hitting this timeout, check that you didn't make your  
  7.     // sepolicy regular expressions too expensive (http://b/19899875).  
  8.     if (wait_for_file(COLDBOOT_DONE, 1)) {  
  9.         ERROR("Timed out waiting for %s\n", COLDBOOT_DONE);  
  10.     }  
  11.   
  12.     NOTICE("Waiting for %s took %.2fs.\n", COLDBOOT_DONE, t.duration());  
  13.     

wait_for_file等待/dev/.coldboot_done文件,超时时间设置的是1秒。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. int wait_for_file(const char *filename, int timeout)  
  2. {  
  3.     struct stat info;  
  4.     uint64_t timeout_time_ns = gettime_ns() + timeout * UINT64_C(1000000000);  
  5.     int ret = -1;  
  6.   
  7.     while (gettime_ns() < timeout_time_ns && ((ret = stat(filename, &info)) < 0))  
  8.         usleep(10000);  
  9.   
  10.     return ret;  
  11. }  

3. mix_hwrng_into_linux_rng_action函数从硬件PNG的设备文件/dev/hw_random读取512字节并写到LinuxRNG设备文件dev/urandom中。

4. keychord_init_action初始化组合键监听模块,这个函数调用了keychord_init函数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static int keychord_init_action(int nargs, char **args)  
  2. {  
  3.     keychord_init();  
  4.     return 0;  
  5. }  
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void keychord_init() {  
  2.     service_for_each(add_service_keycodes);  
  3.   
  4.     // Nothing to do if no services require keychords.  
  5.     if (!keychords) {  
  6.         return;  
  7.     }  
  8.   
  9.     keychord_fd = TEMP_FAILURE_RETRY(open("/dev/keychord", O_RDWR | O_CLOEXEC));  
  10.     if (keychord_fd == -1) {  
  11.         ERROR("could not open /dev/keychord: %s\n", strerror(errno));  
  12.         return;  
  13.     }  
  14.   
  15.     int ret = write(keychord_fd, keychords, keychords_length);  
  16.     if (ret != keychords_length) {  
  17.         ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno));  
  18.         close(keychord_fd);  
  19.     }  
  20.   
  21.     free(keychords);  
  22.     keychords = nullptr;  
  23.   
  24.     register_epoll_handler(keychord_fd, handle_keychord);  
  25. }  
keychord_init函数先是遍历各个service,然后调用add_service_keycodes函数,在add_service_keycodes函数中,主要看service有没有keycodes这个变量,有的话将新建一个keychord,然后将service的keycodes保存在这个变量中。最后还有一个全局的keychords,所以的数据最后都是可以通过这个全局指针找到。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void add_service_keycodes(struct service *svc)  
  2. {  
  3.     struct input_keychord *keychord;  
  4.     int i, size;  
  5.   
  6.     if (svc->keycodes) {  
  7.         /* add a new keychord to the list */  
  8.         size = sizeof(*keychord) + svc->nkeycodes * sizeof(keychord->keycodes[0]);  
  9.         keychords = (input_keychord*) realloc(keychords, keychords_length + size);  
  10.         if (!keychords) {  
  11.             ERROR("could not allocate keychords\n");  
  12.             keychords_length = 0;  
  13.             keychords_count = 0;  
  14.             return;  
  15.         }  
  16.   
  17.         keychord = (struct input_keychord *)((char *)keychords + keychords_length);  
  18.         keychord->version = KEYCHORD_VERSION;  
  19.         keychord->id = keychords_count + 1;  
  20.         keychord->count = svc->nkeycodes;  
  21.         svc->keychord_id = keychord->id;  
  22.   
  23.         for (i = 0; i < svc->nkeycodes; i++) {  
  24.             keychord->keycodes[i] = svc->keycodes[i];  
  25.         }  
  26.         keychords_count++;  
  27.         keychords_length += size;  
  28.     }  
  29. }  

然后我们把keychords这个全局变量数据写入/dev/keychord文件中,最后调用register_epoll_handler函数把这个fd注册到epoll中。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. int ret = write(keychord_fd, keychords, keychords_length);  
  2. if (ret != keychords_length) {  
  3.     ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno));  
  4.     close(keychord_fd);  
  5. }  
  6.   
  7. free(keychords);  
  8. keychords = nullptr;  
  9.   
  10. register_epoll_handler(keychord_fd, handle_keychord);  

最后在这个fd有数据来的时候,我们读取出来,通过service_find_by_keychord看与哪个service的的keychord匹配,匹配的话就把service启动。但是前提是and_enabled是running。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void handle_keychord() {  
  2.     struct service *svc;  
  3.     char adb_enabled[PROP_VALUE_MAX];  
  4.     int ret;  
  5.     __u16 id;  
  6.   
  7.     // Only handle keychords if adb is enabled.  
  8.     property_get("init.svc.adbd", adb_enabled);  
  9.     ret = read(keychord_fd, &id, sizeof(id));  
  10.     if (ret != sizeof(id)) {  
  11.         ERROR("could not read keychord id\n");  
  12.         return;  
  13.     }  
  14.   
  15.     if (!strcmp(adb_enabled, "running")) {  
  16.         svc = service_find_by_keychord(id);  
  17.         if (svc) {  
  18.             INFO("Starting service %s from keychord\n", svc->name);  
  19.             service_start(svc, NULL);  
  20.         } else {  
  21.             ERROR("service for keychord %d not found\n", id);  
  22.         }  
  23.     }  
  24. }  

5. console_init_action是显示A N D R O I D 字样的logo。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static int console_init_action(int nargs, char **args)  
  2. {  
  3.     char console[PROP_VALUE_MAX];  
  4.     if (property_get("ro.boot.console", console) > 0) {  
  5.         snprintf(console_name, sizeof(console_name), "/dev/%s", console);  
  6.     }  
  7.   
  8.     int fd = open(console_name, O_RDWR | O_CLOEXEC);  
  9.     if (fd >= 0)  
  10.         have_console = 1;//是否有控制台  
  11.     close(fd);  
  12.   
  13.     fd = open("/dev/tty0", O_WRONLY | O_CLOEXEC);  
  14.     if (fd >= 0) {  
  15.         const char *msg;  
  16.             msg = "\n"  
  17.         "\n"  
  18.         "\n"  
  19.         "\n"  
  20.         "\n"  
  21.         "\n"  
  22.         "\n"  // console is 40 cols x 30 lines  
  23.         "\n"  
  24.         "\n"  
  25.         "\n"  
  26.         "\n"  
  27.         "\n"  
  28.         "\n"  
  29.         "\n"  
  30.         "             A N D R O I D ";  
  31.         write(fd, msg, strlen(msg));//显示android字样  
  32.         close(fd);  
  33.     }  
  34.   
  35.     return 0;  
  36. }  

6. action_for_each_trigger("init", action_add_queue_tail); 触发init触发器, 主要是mount一些设备,还有创建一些目录。

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. on init  
  2.     sysclktz 0  
  3.   
  4.     # Backward compatibility.  
  5.     symlink /system/etc /etc  
  6.     symlink /sys/kernel/debug /d  
  7.   
  8.     # Link /vendor to /system/vendor for devices without a vendor partition.  
  9.     symlink /system/vendor /vendor  
  10.   
  11.     # Create cgroup mount point for cpu accounting  
  12.     mkdir /acct  
  13.     mount cgroup none /acct cpuacct  
  14.     mkdir /acct/uid  
  15.   
  16.     # Create cgroup mount point for memory  
  17.     mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000  
  18. ......  

7. mix_hwrng_into_linux_rng_action也是和RNG相关
8. charger和late-init,根据ro.bootmode来触发charger还是late-init触发器

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. char bootmode[PROP_VALUE_MAX];  
  2. if (property_get("ro.bootmode", bootmode) > 0 && strcmp(bootmode, "charger") == 0) {  
  3.     action_for_each_trigger("charger", action_add_queue_tail);  
  4. else {  
  5.     action_for_each_trigger("late-init", action_add_queue_tail);  
  6. }  

late-init内容如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. on late-init  
  2.     trigger early-fs  
  3.     trigger fs  
  4.     trigger post-fs  
  5.   
  6.     # Load properties from /system/ + /factory after fs mount. Place  
  7.     # this in another action so that the load will be scheduled after the prior  
  8.     # issued fs triggers have completed.  
  9.     trigger load_system_props_action//加载系统属性  
  10.   
  11.     # Now we can mount /data. File encryption requires keymaster to decrypt  
  12.     # /data, which in turn can only be loaded when system properties are present  
  13.     trigger post-fs-data  
  14.     trigger load_persist_props_action//加载persist属性  
  15.   
  16.     # Remove a file to wake up anything waiting for firmware.  
  17.     trigger firmware_mounts_complete  
  18.   
  19.     trigger early-boot  
  20.     trigger boot//这里面启动main core服务  

而on charger就会启动一个charger进程

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. on charger  
  2.     class_start charger  

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. service charger /charger  
  2.     seclabel u:r:healthd:s0  
  3.     oneshot  

9. queue_property_triggers_action就是看现在那些aciton满足条件,把它加入执行列中。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static int queue_property_triggers_action(int nargs, char **args)  
  2. {  
  3.     queue_all_property_triggers();  
  4.     /* enable property triggers */  
  5.     property_triggers_enabled = 1;  
  6.     return 0;  
  7. }  


[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void queue_all_property_triggers()  
  2. {  
  3.     queue_property_triggers(NULL, NULL);  
  4. }  

最后调用queue_property_triggers,遍历所有的aciton是属性的那种,只要满足条件加入执行队列。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void queue_property_triggers(const char *name, const char *value)  
  2. {  
  3.     struct listnode *node, *node2;  
  4.     struct action *act;  
  5.     struct trigger *cur_trigger;  
  6.     bool match;  
  7.     int name_length;  
  8.   
  9.     list_for_each(node, &action_list) {  
  10.         act = node_to_item(node, struct action, alist);  
  11.         match = !name;  
  12.         list_for_each(node2, &act->triggers) {  
  13.             cur_trigger = node_to_item(node2, struct trigger, nlist);  
  14.             if (!strncmp(cur_trigger->name, "property:", strlen("property:"))) {  
  15.                 const char *test = cur_trigger->name + strlen("property:");  
  16.                 if (!match) {  
  17.                     name_length = strlen(name);  
  18.                     if (!strncmp(name, test, name_length) &&  
  19.                         test[name_length] == '=' &&  
  20.                         (!strcmp(test + name_length + 1, value) ||  
  21.                         !strcmp(test + name_length + 1, "*"))) {  
  22.                         match = true;  
  23.                         continue;  
  24.                     }  
  25.                 }  
  26.                 const char* equals = strchr(test, '=');  
  27.                 if (equals) {  
  28.                     char prop_name[PROP_NAME_MAX + 1];  
  29.                     char value[PROP_VALUE_MAX];  
  30.                     int length = equals - test;  
  31.                     if (length <= PROP_NAME_MAX) {  
  32.                         int ret;  
  33.                         memcpy(prop_name, test, length);  
  34.                         prop_name[length] = 0;  
  35.   
  36.                         /* does the property exist, and match the trigger value? */  
  37.                         ret = property_get(prop_name, value);  
  38.                         if (ret > 0 && (!strcmp(equals + 1, value) ||  
  39.                                         !strcmp(equals + 1, "*"))) {  
  40.                             continue;  
  41.                         }  
  42.                     }  
  43.                 }  
  44.             }  
  45.             match = false;  
  46.             break;  
  47.         }  
  48.         if (match) {  
  49.             action_add_queue_tail(act);  
  50.         }  
  51.     }  
  52. }  


四、属性系统

属性会在start_property_service函数中,把属性的socket 的fd加入到了epoll中,init主要是检测属性发生改变时,有哪些action满足条件需要触发。以及一些persist属性保存。ctl属性开启 关闭service等。

具体的我们在之前的博客http://blog.csdn.net/kc58236582/article/details/51939322,已经分析的比较详细了,这里就不说了。


五、执行执行队列中的Action

执行命令主要是在main函数中的while循环中调用execute_one_command,因为执行队列会不断变化,所以需要在while循环中不断调用这个函数。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. while (true) {  
  2.     if (!waiting_for_exec) {  
  3.         execute_one_command();  
  4.         restart_processes();  
  5.     }  
  6.   
  7.     int timeout = -1;  
  8.     if (process_needs_restart) {  
  9.         timeout = (process_needs_restart - gettime()) * 1000;  
  10.         if (timeout < 0)  
  11.             timeout = 0;  
  12.     }  
  13.   
  14.     if (!action_queue_empty() || cur_action) {  
  15.         timeout = 0;  
  16.     }  
  17.   
  18.     bootchart_sample(&timeout);  
  19.   
  20.     epoll_event ev;  
  21.     int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));  
  22.     if (nr == -1) {  
  23.         ERROR("epoll_wait failed: %s\n", strerror(errno));  
  24.     } else if (nr == 1) {  
  25.         ((void (*)()) ev.data.ptr)();  
  26.     }  
  27. }  

我们来看下这个函数,比较简单先调用action_remove_queue_head函数,然后获取command,最后调用command的func回调函数。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void execute_one_command() {  
  2.     Timer t;  
  3.   
  4.     char cmd_str[256] = "";  
  5.     char name_str[256] = "";  
  6.   
  7.     if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {  
  8.         cur_action = action_remove_queue_head();  
  9.         cur_command = NULL;  
  10.         if (!cur_action) {  
  11.             return;  
  12.         }  
  13.   
  14.         build_triggers_string(name_str, sizeof(name_str), cur_action);  
  15.   
  16.         INFO("processing action %p (%s)\n", cur_action, name_str);  
  17.         cur_command = get_first_command(cur_action);  
  18.     } else {  
  19.         cur_command = get_next_command(cur_action, cur_command);  
  20.     }  
  21.   
  22.     if (!cur_command) {  
  23.         return;  
  24.     }  
  25.   
  26.     int result = cur_command->func(cur_command->nargs, cur_command->args);  
  27.     if (klog_get_level() >= KLOG_INFO_LEVEL) {  
  28.         for (int i = 0; i < cur_command->nargs; i++) {  
  29.             strlcat(cmd_str, cur_command->args[i], sizeof(cmd_str));  
  30.             if (i < cur_command->nargs - 1) {  
  31.                 strlcat(cmd_str, " "sizeof(cmd_str));  
  32.             }  
  33.         }  
  34.         char source[256];  
  35.         if (cur_command->filename) {  
  36.             snprintf(source, sizeof(source), " (%s:%d)", cur_command->filename, cur_command->line);  
  37.         } else {  
  38.             *source = '\0';  
  39.         }  
  40.         INFO("Command '%s' action=%s%s returned %d took %.2fs\n",  
  41.              cmd_str, cur_action ? name_str : "", source, result, t.duration());  
  42.     }  
  43. }  


六、kill 进程处理以及再次开启service进程

之前我们在分析signal_handler_init函数的时候没有详细说,现在说下这个函数。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void signal_handler_init() {  
  2.     // Create a signalling mechanism for SIGCHLD.  
  3.     int s[2];  
  4.     if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {  
  5.         ERROR("socketpair failed: %s\n", strerror(errno));  
  6.         exit(1);  
  7.     }  
  8.   
  9.     signal_write_fd = s[0];  
  10.     signal_read_fd = s[1];  
  11.   
  12.     // Write to signal_write_fd if we catch SIGCHLD.  
  13.     struct sigaction act;  
  14.     memset(&act, 0, sizeof(act));  
  15.     act.sa_handler = SIGCHLD_handler;  
  16.     act.sa_flags = SA_NOCLDSTOP;  
  17.     sigaction(SIGCHLD, &act, 0);//子进程终结发给父进程的信号  
  18.   
  19.     reap_any_outstanding_children();  
  20.   
  21.     register_epoll_handler(signal_read_fd, handle_signal);  
  22. }  
我们先来看下信号的处理函数,SIGCHLD_handler就是往socketpair的一端写入数据

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void SIGCHLD_handler(int) {  
  2.     if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {  
  3.         ERROR("write(signal_write_fd) failed: %s\n", strerror(errno));  
  4.     }  
  5. }  
然后sockpair的另一端,注册到epoll中去,我们也来看下处理函数handle_signal,读取了sockpair中的内容后,调用了reap_any_outstanding_children函数,这个函数在signal_handler_init函数里面也调用了。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void handle_signal() {  
  2.     // Clear outstanding requests.  
  3.     char buf[32];  
  4.     read(signal_read_fd, buf, sizeof(buf));  
  5.   
  6.     reap_any_outstanding_children();  
  7. }  
我们来看下reap_any_outstanding_children函数,直接while循环调用了wait_for_one_process函数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void reap_any_outstanding_children() {  
  2.     while (wait_for_one_process()) {  
  3.     }  
  4. }  

我们再来看wait_for_one_process函数,先调用了waitpid方法,pid为-1,代表监听所有的子进程。WNOHANG代表不阻塞。当pid值返回0和-1时return false,直接while循环退出了,否则一直处理一个接着一个进程挂掉的信号。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static bool wait_for_one_process() {  
  2.     int status;  
  3.     pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));//WNOHANG代表不阻塞  
  4.     if (pid == 0) {  
  5.         return false;  
  6.     } else if (pid == -1) {  
  7.         ERROR("waitpid failed: %s\n", strerror(errno));  
  8.         return false;  
  9.     }  
  10.   
  11.     service* svc = service_find_by_pid(pid);//找到service  
  12.   
  13.     std::string name;  
  14.     if (svc) {  
  15.         name = android::base::StringPrintf("Service '%s' (pid %d)", svc->name, pid);  
  16.     } else {  
  17.         name = android::base::StringPrintf("Untracked pid %d", pid);  
  18.     }  
  19.   
  20.     NOTICE("%s %s\n", name.c_str(), DescribeStatus(status).c_str());  
  21.   
  22.     if (!svc) {  
  23.         return true;//没找到service 直接结束处理下个进程信号  
  24.     }  
  25.   
  26.     // TODO: all the code from here down should be a member function on service.  
  27.   
  28.     if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {//如果不是oneshot 或者是restart的这种flag  
  29.         NOTICE("Service '%s' (pid %d) killing any children in process group\n", svc->name, pid);  
  30.         kill(-pid, SIGKILL);//kill该进程群组所有的进程  
  31.     }  
  32.   
  33.     // Remove any sockets we may have created.去除socket  
  34.     for (socketinfo* si = svc->sockets; si; si = si->next) {  
  35.         char tmp[128];  
  36.         snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);  
  37.         unlink(tmp);  
  38.     }  
  39.   
  40.     if (svc->flags & SVC_EXEC) {  
  41.         INFO("SVC_EXEC pid %d finished...\n", svc->pid);  
  42.         waiting_for_exec = false;  
  43.         list_remove(&svc->slist);  
  44.         free(svc->name);  
  45.         free(svc);  
  46.         return true;  
  47.     }  
  48.   
  49.     svc->pid = 0;  
  50.     svc->flags &= (~SVC_RUNNING);//去除running的flag  
  51.   
  52.     // Oneshot processes go into the disabled state on exit,  
  53.     // except when manually restarted.  
  54.     if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {  
  55.         svc->flags |= SVC_DISABLED;//oneshot而且没有restart的flag,附上disabled的flag  
  56.     }  
  57.   
  58.     // Disabled and reset processes do not get restarted automatically.  
  59.     if (svc->flags & (SVC_DISABLED | SVC_RESET))  {//已经reset或者disabled直接结束  
  60.         svc->NotifyStateChange("stopped");  
  61.         return true;  
  62.     }  
  63.   
  64.     time_t now = gettime();  
  65.     if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) {  
  66.         if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {  
  67.             if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {  
  68.                 ERROR("critical process '%s' exited %d times in %d minutes; "  
  69.                       "rebooting into recovery mode\n", svc->name,  
  70.                       CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);  
  71.                 android_reboot(ANDROID_RB_RESTART2, 0, "recovery");  
  72.                 return true;  
  73.             }  
  74.         } else {  
  75.             svc->time_crashed = now;  
  76.             svc->nr_crashed = 1;  
  77.         }  
  78.     }  
  79.   
  80.     svc->flags &= (~SVC_RESTART);  
  81.     svc->flags |= SVC_RESTARTING;// restarting代表重启中  
  82.   
  83.     // Execute all onrestart commands for this service.  
  84.     struct listnode* node;  
  85.     list_for_each(node, &svc->onrestart.commands) {//有onrestart的command命令的,重启的时候要先调用命令  
  86.         command* cmd = node_to_item(node, struct command, clist);  
  87.         cmd->func(cmd->nargs, cmd->args);  
  88.     }  
  89.     svc->NotifyStateChange("restarting");  
  90.     return true;  
  91. }  

这个函数主要将service的flags赋值,一般的进程被kill 之后最后会被附上SVC_RESTARTING这个flag,而且又onrestart的,先执行其command。对于已经是disabled和reset的service直接结束,对于是oneshot而且没有restart flag的service,直接附上disabled这个flag。

我们先来看看下面servicemanager这个service,当servicemanager重启的时候,会restart healthd等。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. service servicemanager /system/bin/servicemanager  
  2.     class core  
  3.     user system  
  4.     group system  
  5.     critical  
  6.     onrestart restart healthd  
  7.     onrestart restart zygote  
  8.     onrestart restart media  
  9.     onrestart restart surfaceflinger  
  10.     onrestart restart drm  

restart这个命令对应的是do_restart函数,最后调用service_restart函数重启service

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. int do_restart(int nargs, char **args)  
  2. {  
  3.     struct service *svc;  
  4.     svc = service_find_by_name(args[1]);  
  5.     if (svc) {  
  6.         service_restart(svc);  
  7.     }  
  8.     return 0;  
  9. }  

我们再来看看service的NotifyStateChange函数,主要是设置init.svc.(service的name)这个属性为这个service最新的状态。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void service::NotifyStateChange(const char* new_state) {  
  2.     if (!properties_initialized()) {  
  3.         // If properties aren't available yet, we can't set them.  
  4.         return;  
  5.     }  
  6.   
  7.     if ((flags & SVC_EXEC) != 0) {  
  8.         // 'exec' commands don't have properties tracking their state.  
  9.         return;  
  10.     }  
  11.   
  12.     char prop_name[PROP_NAME_MAX];  
  13.     if (snprintf(prop_name, sizeof(prop_name), "init.svc.%s", name) >= PROP_NAME_MAX) {  
  14.         // If the property name would be too long, we can't set it.  
  15.         ERROR("Property name \"init.svc.%s\" too long; not setting to %s\n", name, new_state);  
  16.         return;  
  17.     }  
  18.   
  19.     property_set(prop_name, new_state);  
  20. }  

下面我们需要再结合main函数中在while循环中调用的restart_processes函数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void restart_processes()  
  2. {  
  3.     process_needs_restart = 0;  
  4.     service_for_each_flags(SVC_RESTARTING,  
  5.                            restart_service_if_needed);  
  6. }  

结合service_for_each_flags,遍历所有的service,只要service的flags有SVC_RESTARTING的就调用restart_service_if_needed函数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void service_for_each_flags(unsigned matchflags,  
  2.                             void (*func)(struct service *svc))  
  3. {  
  4.     struct listnode *node;  
  5.     struct service *svc;  
  6.     list_for_each(node, &service_list) {  
  7.         svc = node_to_item(node, struct service, slist);  
  8.         if (svc->flags & matchflags) {  
  9.             func(svc);  
  10.         }  
  11.     }  
  12. }  

在restart_service_if_needed函数中,会去除SVC_RESTARTING的flag,然后调用service_start启动进程。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void restart_service_if_needed(struct service *svc)  
  2. {  
  3.     time_t next_start_time = svc->time_started + 5;  
  4.   
  5.     if (next_start_time <= gettime()) {  
  6.         svc->flags &= (~SVC_RESTARTING);  
  7.         service_start(svc, NULL);  
  8.         return;  
  9.     }  
  10.   
  11.     if ((next_start_time < process_needs_restart) ||  
  12.         (process_needs_restart == 0)) {  
  13.         process_needs_restart = next_start_time;  
  14.     }  
  15. }  

所以普通的进程,使用kill的话,哪怕进程被kill了之后,还会被init进程启动的。我们再来看看service_start函数,先把一些flag清除

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void service_start(struct service *svc, const char *dynamic_args)  
  2. {  
  3.     // Starting a service removes it from the disabled or reset state and  
  4.     // immediately takes it out of the restarting state if it was in there.  
  5.     svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));//清除flag  
  6.     svc->time_started = 0;  
  7.   
  8.     // Running processes require no additional work --- if they're in the  
  9.     // process of exiting, we've ensured that they will immediately restart  
  10.     // on exit, unless they are ONESHOT.  
  11.     if (svc->flags & SVC_RUNNING) {//已经启动的service直接退出  
  12.         return;  
  13.     }  
  14.   
  15.     bool needs_console = (svc->flags & SVC_CONSOLE);//需要控制台的service  
  16.     if (needs_console && !have_console) {//是否有控制台,没有直接退出  
  17.         ERROR("service '%s' requires console\n", svc->name);  
  18.         svc->flags |= SVC_DISABLED;  
  19.         return;  
  20.     }  
  21.   
  22.     struct stat s;  
  23.     if (stat(svc->args[0], &s) != 0) {  
  24.         ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);  
  25.         svc->flags |= SVC_DISABLED;  
  26.         return;  
  27.     }  
  28.   
  29.     if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {  
  30.         ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",  
  31.                svc->args[0]);  
  32.         svc->flags |= SVC_DISABLED;  
  33.         return;  
  34.     }  

后面是selinux的相关,后面就直接fork进程,处理一些子进程的环境等。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. char* scon = NULL;  
  2. if (is_selinux_enabled() > 0) {  
  3. ......  
  4. }  
  5.   
  6. NOTICE("Starting service '%s'...\n", svc->name);  
  7.   
  8. pid_t pid = fork();  
  9. if (pid == 0) {  
  10.     ......  
  11.     _exit(127);  
  12. }  

最后设置下service的时间,pid,以及flags状态改成running,最后通知(设置属性)改成running了。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. if (pid < 0) {  
  2.     ERROR("failed to start '%s'\n", svc->name);  
  3.     svc->pid = 0;  
  4.     return;  
  5. }  
  6.   
  7. svc->time_started = gettime();  
  8. svc->pid = pid;  
  9. svc->flags |= SVC_RUNNING;  
  10.   
  11. if ((svc->flags & SVC_EXEC) != 0) {  
  12.     INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n",  
  13.          svc->pid, svc->uid, svc->gid, svc->nr_supp_gids,  
  14.          svc->seclabel ? : "default");  
  15.     waiting_for_exec = true;  
  16. }  
  17.   
  18. svc->NotifyStateChange("running");  

像普通的进程我们通过kill进程会被init再次启动,那怎样才能kill 这个进程,又不会被init进程启动呢,可以使用stop命令,我们看下do_stop函数。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. int do_stop(int nargs, char **args)  
  2. {  
  3.     struct service *svc;  
  4.     svc = service_find_by_name(args[1]);  
  5.     if (svc) {  
  6.         service_stop(svc);  
  7.     }  
  8.     return 0;  
  9. }  

调用了service_stop_or_reset只是flag为disabled

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void service_stop(struct service *svc)  
  2. {  
  3.     service_stop_or_reset(svc, SVC_DISABLED);  
  4. }  

service_stop_or_reset函数中,最后会kill整个进程组,而且因为把flag改成了disabled,在init中也不会启动进程了。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void service_stop_or_reset(struct service *svc, int how)  
  2. {  
  3.     /* The service is still SVC_RUNNING until its process exits, but if it has 
  4.      * already exited it shoudn't attempt a restart yet. */  
  5.     svc->flags &= ~(SVC_RESTARTING | SVC_DISABLED_START);//清相关flag  
  6.   
  7.     if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) {  
  8.         /* Hrm, an illegal flag.  Default to SVC_DISABLED */  
  9.         how = SVC_DISABLED;  
  10.     }  
  11.         /* if the service has not yet started, prevent 
  12.          * it from auto-starting with its class 
  13.          */  
  14.     if (how == SVC_RESET) {  
  15.         svc->flags |= (svc->flags & SVC_RC_DISABLED) ? SVC_DISABLED : SVC_RESET;// 看之前是否有disabled这个flag  
  16.     } else {  
  17.         svc->flags |= how;  
  18.     }  
  19.   
  20.     if (svc->pid) {  
  21.         NOTICE("Service '%s' is being killed...\n", svc->name);  
  22.         kill(-svc->pid, SIGKILL);//kill 整个进程组  
  23.         svc->NotifyStateChange("stopping");  
  24.     } else {  
  25.         svc->NotifyStateChange("stopped");  
  26.     }  
  27. }  

也可以自己调用start命令,最后通过do_start函数启动这个service。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. int do_start(int nargs, char **args)  
  2. {  
  3.     struct service *svc;  
  4.     svc = service_find_by_name(args[1]);  
  5.     if (svc) {  
  6.         service_start(svc, NULL);  
  7.     }  
  8.     return 0;  
  9. }  

再看下do_restart

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. int do_restart(int nargs, char **args)  
  2. {  
  3.     struct service *svc;  
  4.     svc = service_find_by_name(args[1]);  
  5.     if (svc) {  
  6.         service_restart(svc);  
  7.     }  
  8.     return 0;  
  9. }  

在service_restart函数中,当是running状态,直接把它kill了,然后在init处理进程信号时,会把它的flag变成restarting,之后init进程会重启这个进程。其他的状态就直接启动service了。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void service_restart(struct service *svc)  
  2. {  
  3.     if (svc->flags & SVC_RUNNING) {  
  4.         /* Stop, wait, then start the service. */  
  5.         service_stop_or_reset(svc, SVC_RESTART);  
  6.     } else if (!(svc->flags & SVC_RESTARTING)) {  
  7.         /* Just start the service since it's not running. */  
  8.         service_start(svc, NULL);  
  9.     } /* else: Service is restarting anyways. */  
  10. }  
至于stop start命令只能在init.rc中使用,但是我们可以通过ctl.start ctl.stop ctl.restart来达到这个目的。处理的话,之前在属性系统中已经分析过了。



普通对一个service命令处理只有stop start restart没有reset,而在class_reset class_stop class_start中有,我们来看看这些命令处理。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. int do_class_stop(int nargs, char **args)  
  2. {  
  3.     service_for_each_class(args[1], service_stop);  
  4.     return 0;  
  5. }  
  6.   
  7. int do_class_reset(int nargs, char **args)  
  8. {  
  9.     service_for_each_class(args[1], service_reset);  
  10.     return 0;  
  11. }  

再结合service_for_each_class函数,我们知道class_reset class_stop 只是遍历所有的service,看看其class是否满足,满足就调用service_stop 和 service_reset函数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void service_for_each_class(const char *classname,  
  2.                             void (*func)(struct service *svc))  
  3. {  
  4.     struct listnode *node;  
  5.     struct service *svc;  
  6.     list_for_each(node, &service_list) {  
  7.         svc = node_to_item(node, struct service, slist);  
  8.         if (!strcmp(svc->classname, classname)) {  
  9.             func(svc);  
  10.         }  
  11.     }  
  12. }  
而我们再看看do_class_start有点不一样,遍历所有的service看看其class是否满足然后调用service_start_if_not_disabled函数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  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. }  

看看service_start_if_not_disabled函数只有在flags不等于SVC_DISABLED的时候才会调用service_start函数。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. static void service_start_if_not_disabled(struct service *svc)  
  2. {  
  3.     if (!(svc->flags & SVC_DISABLED)) {  
  4.         service_start(svc, NULL);  
  5.     } else {  
  6.         svc->flags |= SVC_DISABLED_START;  
  7.     }  
  8. }  

这样如果调用class_stop再调用class_start也不能再次启动这些class的service了,只有启动那些之前调用的是reset的service。

class_stop了之后,就只能一个一个service调用start命令了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值