二、Android情景分析之详解init进程(以启动zygote为例)

来源:互联网 发布:网络电视怎么看直播啊 编辑:程序博客网 时间:2024/05/21 20:29

概述

init是linux系统中用户空间的第一个进程。由于Android是基于linux内核的,所以init也是Android系统中用户空间的第一个进程,它的进程号为1。

作为系统中的第一个用户空间进程,init进程被赋予了很多及其重要的工作职责。

1.      init进程创建系统中几个关键进程,例如zygote等。

2.      Android系统有很多属性,于是init就提供了一个property service(属性服务)来管理它们。(这篇文章讲过 http://blog.csdn.net/hu3167343/article/details/38230271)

今天我们主要以第1点来详细说明下init进程的工作。


init进程的main函数

init进程的主要代码如下:

[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.     bool is_charger = false;  
  12.       
  13.     ...  
  14.     mkdir("/dev", 0755);  
  15.     mkdir("/proc", 0755);  
  16.     mkdir("/sys", 0755);  
  17.   
  18.     mount("tmpfs""/dev""tmpfs", MS_NOSUID, "mode=0755");  
  19.     mkdir("/dev/pts", 0755);  
  20.     mkdir("/dev/socket", 0755);  
  21.     mount("devpts""/dev/pts""devpts", 0, NULL);  
  22.     mount("proc""/proc""proc", 0, NULL);  
  23.     mount("sysfs""/sys""sysfs", 0, NULL);  
  24.   
  25.     ...  
  26.   
  27.     // 属性服务初始化  
  28.     property_init();  
  29.   
  30.     get_hardware_name(hardware, &revision);  
  31.   
  32.     process_kernel_cmdline();  
  33.   
  34.     // selinux安全机制初始化  
  35.     union selinux_callback cb;  
  36.     cb.func_log = klog_write;  
  37.     selinux_set_callback(SELINUX_CB_LOG, cb);  
  38.   
  39.     cb.func_audit = audit_callback;  
  40.     selinux_set_callback(SELINUX_CB_AUDIT, cb);  
  41.   
  42.     selinux_initialize();  
  43.     /* These directories were necessarily created before initial policy load 
  44.      * and therefore need their security context restored to the proper value. 
  45.      * This must happen before /dev is populated by ueventd. 
  46.      */  
  47.     restorecon("/dev");  
  48.     restorecon("/dev/socket");  
  49.     restorecon("/dev/__properties__");  
  50.     restorecon_recursive("/sys");  
  51.   
  52.     is_charger = !strcmp(bootmode, "charger");  
  53.   
  54.     INFO("property init\n");  
  55.     if (!is_charger)  
  56.         property_load_boot_defaults();  
  57.   
  58.     // 解析init.rc配置文件  
  59.     INFO("reading config file\n");  
  60.     init_parse_config_file("/init.rc");  
  61.       
  62.     /* 
  63.     解析完init.rc配置文件后,会得到一系列的Action,action_for_each_trigger函数用来执行early-init阶段的Action。 
  64.     init将动作执行的时间划分为4个阶段:early-init、init、early-boot、boot。由于有些动作必须要在其他动作完成后才能执行,所以就有了先后之分。哪些动作属于哪个阶段由配置文件决定。 
  65.     */  
  66.     action_for_each_trigger("early-init", action_add_queue_tail);  
  67.   
  68.     queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");  
  69.     queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");  
  70.     queue_builtin_action(keychord_init_action, "keychord_init");  
  71.     queue_builtin_action(console_init_action, "console_init");  
  72.   
  73.     /* execute all the boot actions to get us started */  
  74.     // 执行init阶段的动作  
  75.     action_for_each_trigger("init", action_add_queue_tail);  
  76.   
  77.     /* skip mounting filesystems in charger mode */  
  78.     if (!is_charger) {  
  79.         action_for_each_trigger("early-fs", action_add_queue_tail);  
  80.         action_for_each_trigger("fs", action_add_queue_tail);  
  81.         action_for_each_trigger("post-fs", action_add_queue_tail);  
  82.         action_for_each_trigger("post-fs-data", action_add_queue_tail);  
  83.     }  
  84.   
  85.     /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random 
  86.      * wasn't ready immediately after wait_for_coldboot_done 
  87.      */  
  88.     queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");  
  89.   
  90.     queue_builtin_action(property_service_init_action, "property_service_init");  
  91.     queue_builtin_action(signal_init_action, "signal_init");  
  92.     queue_builtin_action(check_startup_action, "check_startup");  
  93.   
  94.     // 执行early-boot和boot阶段的动作  
  95.     if (is_charger) {  
  96.         action_for_each_trigger("charger", action_add_queue_tail);  
  97.     } else {  
  98.         action_for_each_trigger("early-boot", action_add_queue_tail);  
  99.         action_for_each_trigger("boot", action_add_queue_tail);  
  100.     }  
  101.   
  102.         /* run all property triggers based on current state of the properties */  
  103.     queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");  
  104.   
  105.   
  106. #if BOOTCHART  
  107.     queue_builtin_action(bootchart_init_action, "bootchart_init");  
  108. #endif  
  109.   
  110.     // 无限循环,用来处理各种消息  
  111.     for(;;) {  
  112.         int nr, i, timeout = -1;  
  113.   
  114.         execute_one_command();  
  115.         restart_processes();    // 重启那些已经死去的进程  
  116.       
  117.     // 用来监听属性设置服务的事件  
  118.         if (!property_set_fd_init && get_property_set_fd() > 0) {  
  119.             ufds[fd_count].fd = get_property_set_fd();  
  120.             ufds[fd_count].events = POLLIN;  
  121.             ufds[fd_count].revents = 0;  
  122.             fd_count++;  
  123.             property_set_fd_init = 1;  
  124.         }  
  125.         if (!signal_fd_init && get_signal_fd() > 0) {  
  126.             ufds[fd_count].fd = get_signal_fd();  
  127.             ufds[fd_count].events = POLLIN;  
  128.             ufds[fd_count].revents = 0;  
  129.             fd_count++;  
  130.             signal_fd_init = 1;  
  131.         }  
  132.         if (!keychord_fd_init && get_keychord_fd() > 0) {  
  133.             ufds[fd_count].fd = get_keychord_fd();  
  134.             ufds[fd_count].events = POLLIN;  
  135.             ufds[fd_count].revents = 0;  
  136.             fd_count++;  
  137.             keychord_fd_init = 1;  
  138.         }  
  139.   
  140.         if (process_needs_restart) {  
  141.             timeout = (process_needs_restart - gettime()) * 1000;  
  142.             if (timeout < 0)  
  143.                 timeout = 0;  
  144.         }  
  145.   
  146.         if (!action_queue_empty() || cur_action)  
  147.             timeout = 0;  
  148.   
  149. #if BOOTCHART  
  150.         if (bootchart_count > 0) {  
  151.             if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)  
  152.                 timeout = BOOTCHART_POLLING_MS;  
  153.             if (bootchart_step() < 0 || --bootchart_count == 0) {  
  154.                 bootchart_finish();  
  155.                 bootchart_count = 0;  
  156.             }  
  157.         }  
  158. #endif  
  159.   
  160.         nr = poll(ufds, fd_count, timeout);  
  161.         if (nr <= 0)  
  162.             continue;  
  163.       
  164.     // 处理具体的消息  
  165.         for (i = 0; i < fd_count; i++) {  
  166.             if (ufds[i].revents == POLLIN) {  
  167.                 if (ufds[i].fd == get_property_set_fd())  
  168.                     handle_property_set_fd();  
  169.                 else if (ufds[i].fd == get_keychord_fd())  
  170.                     handle_keychord();  
  171.                 else if (ufds[i].fd == get_signal_fd())  
  172.                     handle_signal();  
  173.             }  
  174.         }  
  175.     }  
  176.   
  177.     return 0;  
  178. }  

从以上代码来看,init进程的工作量还是很大的,主要集中在如下几个事情:

1.      解析init.rc配置文件。

2.      执行各个阶段的动作,创建zygote的工作就是在其中的某个阶段完成的。

3.      初始化property service(属性服务)。

4.      init进入一个无限循环,并且等到一些事情的发生。


解析init.rc

init的main函数主要是解析了init.rc文件,然后执行相应的初始化操作。我们先来看看init_parse_config_file函数的实现:

[cpp] view plain copy
  1. int init_parse_config_file(const char *fn)  
  2. {  
  3.     char *data;  
  4.     data = read_file(fn, 0); // 读取inic.rc文件的内容  
  5.     if (!data) return -1;  
  6.       
  7. // 开始解析  
  8.     parse_config(fn, data);  
  9.     DUMP();  
  10.     return 0;  
  11. }  
  12.   
  13. static void parse_config(const char *fn, char *s)  
  14. {  
  15.     struct parse_state state;  
  16.     struct listnode import_list;  
  17.     struct listnode *node;  
  18.     char *args[INIT_PARSER_MAXARGS];  
  19.     int nargs;  
  20.   
  21.     nargs = 0;  
  22.     state.filename = fn;  
  23.     state.line = 0;  
  24.     state.ptr = s;  
  25.     state.nexttoken = 0;  
  26.     state.parse_line = parse_line_no_op; // 设置解析函数,在android4.1上此函数为空  
  27.   
  28.     list_init(&import_list);  
  29.     state.priv = &import_list;  
  30.   
  31.     // 开始解析init.rc文件内容,以行为单位  
  32.     for (;;) {  
  33.         switch (next_token(&state)) {  
  34.         case T_EOF: // 文件末尾  
  35.             state.parse_line(&state, 0, 0);  
  36.             goto parser_done;  
  37.         case T_NEWLINE: // 新的行  
  38.             state.line++;  
  39.             if (nargs) {  
  40.                 int kw = lookup_keyword(args[0]);  
  41.                 if (kw_is(kw, SECTION)) {  
  42.                     state.parse_line(&state, 0, 0);  
  43.                     parse_new_section(&state, kw, nargs, args);  
  44.                 } else {  
  45.                     state.parse_line(&state, nargs, args);  
  46.                 }  
  47.                 nargs = 0;  
  48.             }  
  49.             break;  
  50.         case T_TEXT:    // 文本内容,设置为args参数  
  51.             if (nargs < INIT_PARSER_MAXARGS) {  
  52.                 args[nargs++] = state.text;  
  53.             }  
  54.             break;  
  55.         }  
  56.     }  
  57.   
  58. parser_done:  
  59.     list_for_each(node, &import_list) {  
  60.          struct import *import = node_to_item(node, struct import, list);  
  61.          int ret;  
  62.   
  63.          INFO("importing '%s'", import->filename);  
  64.          ret = init_parse_config_file(import->filename);  
  65.          if (ret)  
  66.              ERROR("could not import file '%s' from '%s'\n",  
  67.                    import->filename, fn);  
  68.     }  
  69. }  

再来看看keywords.h对init.rc文件中关键字的定义

[cpp] view plain copy
  1. KEYWORD(capability,  OPTION,  0, 0)  
  2. KEYWORD(chdir,       COMMAND, 1, do_chdir)  
  3. KEYWORD(chroot,      COMMAND, 1, do_chroot)  
  4. KEYWORD(class,       OPTION,  0, 0)  
  5. KEYWORD(class_start, COMMAND, 1, do_class_start)  
  6. KEYWORD(class_stop,  COMMAND, 1, do_class_stop)  
  7. KEYWORD(class_reset, COMMAND, 1, do_class_reset)  
  8. KEYWORD(console,     OPTION,  0, 0)  
  9. KEYWORD(critical,    OPTION,  0, 0)  
  10. KEYWORD(disabled,    OPTION,  0, 0)  
  11. KEYWORD(domainname,  COMMAND, 1, do_domainname)  
  12. KEYWORD(exec,        COMMAND, 1, do_exec)  
  13. KEYWORD(export,      COMMAND, 2, do_export)  
  14. KEYWORD(group,       OPTION,  0, 0)  
  15. KEYWORD(hostname,    COMMAND, 1, do_hostname)  
  16. KEYWORD(ifup,        COMMAND, 1, do_ifup)  
  17. KEYWORD(insmod,      COMMAND, 1, do_insmod)  
  18. KEYWORD(import,      SECTION, 1, 0)  
  19. KEYWORD(keycodes,    OPTION,  0, 0)  
  20. KEYWORD(mkdir,       COMMAND, 1, do_mkdir)  
  21. KEYWORD(mount_all,   COMMAND, 1, do_mount_all)  
  22. KEYWORD(mount,       COMMAND, 3, do_mount)  
  23. KEYWORD(on,          SECTION, 0, 0)  
  24. KEYWORD(oneshot,     OPTION,  0, 0)  
  25. KEYWORD(onrestart,   OPTION,  0, 0)  
  26. KEYWORD(powerctl,    COMMAND, 1, do_powerctl)  
  27. KEYWORD(restart,     COMMAND, 1, do_restart)  
  28. KEYWORD(restorecon,  COMMAND, 1, do_restorecon)  
  29. KEYWORD(rm,          COMMAND, 1, do_rm)  
  30. KEYWORD(rmdir,       COMMAND, 1, do_rmdir)  
  31. KEYWORD(seclabel,    OPTION,  0, 0)  
  32. KEYWORD(service,     SECTION, 0, 0)  
  33. KEYWORD(setcon,      COMMAND, 1, do_setcon)  
  34. KEYWORD(setenforce,  COMMAND, 1, do_setenforce)  
  35. KEYWORD(setenv,      OPTION,  2, 0)  
  36. KEYWORD(setkey,      COMMAND, 0, do_setkey)  
  37. KEYWORD(setprop,     COMMAND, 2, do_setprop)  
  38. KEYWORD(setrlimit,   COMMAND, 3, do_setrlimit)  
  39. KEYWORD(setsebool,   COMMAND, 2, do_setsebool)  
  40. KEYWORD(socket,      OPTION,  0, 0)  
  41. KEYWORD(start,       COMMAND, 1, do_start)  
  42. KEYWORD(stop,        COMMAND, 1, do_stop)  
  43. KEYWORD(swapon_all,  COMMAND, 1, do_swapon_all)  
  44. KEYWORD(trigger,     COMMAND, 1, do_trigger)  
  45. KEYWORD(symlink,     COMMAND, 1, do_symlink)  
  46. KEYWORD(sysclktz,    COMMAND, 1, do_sysclktz)  
  47. KEYWORD(user,        OPTION,  0, 0)  
  48. KEYWORD(wait,        COMMAND, 1, do_wait)  
  49. KEYWORD(write,       COMMAND, 2, do_write)  
  50. KEYWORD(copy,        COMMAND, 2, do_copy)  
  51. KEYWORD(chown,       COMMAND, 2, do_chown)  
  52. KEYWORD(chmod,       COMMAND, 2, do_chmod)  
  53. KEYWORD(loglevel,    COMMAND, 1, do_loglevel)  
  54. KEYWORD(load_persist_props,    COMMAND, 0, do_load_persist_props)  
  55. KEYWORD(ioprio,      OPTION,  0, 0)  

Init.rc文件的主要内容如下(system\core\rootdir\init.rc):

[cpp] view plain copy
  1. # Copyright (C) 2012 The Android Open Source Project  
  2. #  
  3. # IMPORTANT: Do not create world writable files or directories.  
  4. # This is a common source of Android security bugs.  
  5. #  
  6.   
  7. import /init.environ.rc  
  8. import /init.usb.rc  
  9. import /init.${ro.hardware}.rc  
  10. import /init.trace.rc  
  11.   
  12. # 根据上面的分析可知,on关键字标示一个section,对应的名字为early-init  
  13. on early-init   
  14.     # Set init and its forked children's oom_adj.  
  15.     write /proc/1/oom_adj -16  
  16.   
  17.     # Set the security context for the init process.  
  18.     # This should occur before anything else (e.g. ueventd) is started.  
  19.     setcon u:r:init:s0  
  20.   
  21.     start ueventd  
  22.   
  23. # create mountpoints  
  24.     mkdir /mnt 0775 root system  
  25. …  
  26. # 又一个新的section,名为boot  
  27. on boot  
  28. ...  
  29.     # class_start是一个COMMAND,对应处理函数是do_class_start  
  30.     class_start core  
  31.     class_start main  
  32. …  
  33.   
  34. # system server cannot write to /proc/sys files, so proxy it through init  
  35. on property:sys.sysctl.extra_free_kbytes=*  
  36.     write /proc/sys/vm/extra_free_kbytes ${sys.sysctl.extra_free_kbytes}  
  37.   
  38. ## Daemon processes to be run by init.  
  39. ##  
  40. service ueventd /sbin/ueventd  
  41.     class core  
  42.     critical  
  43.     seclabel u:r:ueventd:s0  
  44.   
  45. …  
  46. # 下面这个section的意思是,如果属性ro.kernel.qemu为1,那么执行相应的COMMAND ,# 即start adbd  
  47. on property:ro.kernel.qemu=1  
  48.     start adbd  
  49.   
  50. ...  
  51. #  service关键字也是一个SECTION,对应的SECTION名为zygote。  
  52. service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server  
  53.     class main  
  54.     socket zygote stream 660 root system  
  55.     onrestart write /sys/android_power/request_state wake  
  56.     onrestart write /sys/power/state on  
  57.     onrestart restart media  
  58.     onrestart restart netd  
  59.   
  60. service drm /system/bin/drmserver  
  61.     class main  
  62.     user drm  
  63.     group drm system inet drmrpc  
  64. ...  

从上面对init.rc文件大致分析可知

1、  一个section的内容从这个标识section的关键字开始,到下一个标识section的地方结束。

2、  Init.rc中出现了名为early-init和boot的section,这里的early-init和boot就是前面介绍的4个动作执行阶段中的early-init和boot。也就是说在boot阶段执行的动作都是由boot这个section定义的。

另外,zygote被放在了一个service section中,下面以zygote这个section为例,具体介绍下service是如何解析的。


解析zygote 服务

Zygote对应的service section内容如下:

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

解析section的入口函数是parse_new_section:

[cpp] view plain copy
  1. 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:  
  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:  
  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:  
  22.         parse_import(state, nargs, args);  
  23.         break;  
  24.     }  
  25.     state->parse_line = parse_line_no_op;  
  26. }  

其中,解析service时,用到了parse_service和parse_line_service这两个函数,在介绍这两个函数之前,我们首先看看init是如何组织这个service的。

service结构体

[cpp] view plain copy
  1. struct service {  
  2.     /* 
  3.         用来连接所有的services。Init中有一个全局的service_list变量,专门用来保存解析配置文件后得到的service。  
  4.     */  
  5.     struct listnode slist;  
  6.   
  7.     const char *name;           // service的名字,在我们的例子中为zygote  
  8.     const char *classname;      // service所属的class名字,默认为default  
  9.   
  10.     unsigned flags;         // service的属性  
  11.     pid_t pid;                  // 进程号  
  12.     time_t time_started;    /* 上一次启动时间 */  
  13.     time_t time_crashed;    /* 上一次死亡时间*/  
  14.     int nr_crashed;         /* 死亡次数 */  
  15.       
  16.     uid_t uid;  
  17.     gid_t gid;  
  18.     gid_t supp_gids[NR_SVC_SUPP_GIDS];  
  19.     size_t nr_supp_gids;  
  20.   
  21.     char *seclabel;  
  22.     /* 
  23.         有些service需要使用socket来通信,下面这个socketinfo用来描述socket的相关信息。 
  24.         我们的zygote也使用了socket,配置文件中的内容是socket zygote stream 660 root system。 
  25.         它表示将创建一个AF_STREAM类型的socket(其实就是TCP socket),该socket的名为zygote,读写权限是660。 
  26.     */  
  27.     struct socketinfo *sockets;  
  28.     // service一般运行在一个单独的进程中,envvars用来描述创建这个进程时所需的环境  
  29.     // 变量信息。  
  30.     struct svcenvinfo *envvars;  
  31.     /* 
  32.         虽然onrestart关键字是一个OPTION,可是这个OPTION后面一般都跟着一个COMMAND,action结构体就是用来存储command信息的。 
  33.     */  
  34.     struct action onrestart;  /* Actions to execute on restart. */  
  35.       
  36.     /* keycodes for triggering this service via /dev/keychord */  
  37.     int *keycodes;  
  38.     int nkeycodes;  
  39.     int keychord_id;  
  40.   
  41.     // io优先级  
  42.     int ioprio_class;  
  43.     int ioprio_pri;  
  44.   
  45.     int nargs;  // 参数个数  
  46.     /* "MUST BE AT THE END OF THE STRUCT" */  
  47.     char *args[1];  // 用于存储参数内容  
  48. };  

了解了service结构,那么其中的action是怎么保存的呢,我们再来看看action结构体。

[cpp] view plain copy
  1. struct action {  
  2.     /* 
  3.         一个action结构可以被链入三个不同的双向链表中,其中alist用来存储所有的action, 
  4.         qlist用来链接那些等待执行的action,tlist用来链接那些待某些条件满足后就需要执行的action。 
  5.     */      
  6.     /* node in list of all actions */  
  7.         struct listnode alist;  
  8.   
  9.         /* node in the queue of pending actions */  
  10.         struct listnode qlist;  
  11.   
  12.         /* node in list of actions for a trigger */  
  13.         struct listnode tlist;  
  14.   
  15.         unsigned hash;  
  16.         const char *name;   // 名字一般为"onrestart"  
  17.       
  18.     /* 
  19.         一个command的结构列表,command结构如下: 
  20.         struct command 
  21.         { 
  22.                 /* list of commands in an action */  
  23.                 struct listnode clist;  
  24.                 int (*func)(int nargs, char **args);  
  25.                 int nargs;  
  26.                 char *args[1];  
  27.         };  
  28.     */  
  29.         struct listnode commands;  
  30.         struct command *current;  
  31. };  


解析parse_service

了解了关键的结构体之后,我们接下来看看parse_service函数的具体思路:

[cpp] view plain copy
  1. static void *parse_service(struct parse_state *state, int nargs, char **args)  
  2. {  
  3.     struct service *svc;  
  4. // ….省略参数检测  
  5.   
  6. // 根据服务名在全局服务链表service_list里面查找,如果已经有了,则返回  
  7.     svc = service_find_by_name(args[1]);  
  8.     if (svc) {  
  9.         parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);  
  10.         return 0;  
  11.     }  
  12.   
  13.     // 分配service结构内存  
  14.     nargs -= 2;  
  15.     svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);  
  16.     if (!svc) {  
  17.         parse_error(state, "out of memory\n");  
  18.         return 0;  
  19.     }  
  20.     svc->name = args[1]; // 服务名,此处为zygote  
  21.     svc->classname = "default"// 设置classname为default,此处很关键  
  22.     memcpy(svc->args, args + 2, sizeof(char*) * nargs); // 拷贝参数,此处拷贝的是字符指针  
  23.     svc->args[nargs] = 0;  
  24.     svc->nargs = nargs;  // 保存参数个数  
  25.     svc->onrestart.name = "onrestart";   
  26.     list_init(&svc->onrestart.commands); // 初始化action结构的commands链表  
  27.     list_add_tail(&service_list, &svc->slist); // 将当前服务添加到service_list链表中  
  28.     return svc;  
  29. }  

由上面分析可知,parse_service函数只是搭建了一个svc的框架,并最后把它链入了service_list链表。我们再来看看parse_line_service函数吧。


解析parse_line_service

[cpp] 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:   // 用来修改classname  
  18.         if (nargs != 2) {  
  19.             parse_error(state, "class option requires a classname\n");  
  20.         } else {  
  21.             svc->classname = args[1];  
  22.         }  
  23.         break;  
  24.     …  
  25.     case K_oneshot:  
  26.         svc->flags |= SVC_ONESHOT;  
  27.         break;  
  28.     case K_onrestart: // 开始解析onrestart后面的COMMAND  
  29.         nargs--;  
  30.         args++;  
  31.         kw = lookup_keyword(args[0]);  
  32.         if (!kw_is(kw, COMMAND)) {  
  33.             parse_error(state, "invalid command '%s'\n", args[0]);  
  34.             break;  
  35.         }  
  36.         kw_nargs = kw_nargs(kw);  
  37.         if (nargs < kw_nargs) {  
  38.             parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,  
  39.                 kw_nargs > 2 ? "arguments" : "argument");  
  40.             break;  
  41.         }  
  42.         // 分配command结构的内存,拷贝参数等  
  43.         cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);  
  44.         cmd->func = kw_func(kw);  
  45.         cmd->nargs = nargs;  
  46.         memcpy(cmd->args, args, sizeof(char*) * nargs);  
  47.         // 添加到commands链表中  
  48.         list_add_tail(&svc->onrestart.commands, &cmd->clist);  
  49.         break;  
  50.     …  
  51.     case K_socket: {/* name type perm [ uid gid ] */  
  52.         struct socketinfo *si;  
  53.         if (nargs < 4) {  
  54.             parse_error(state, "socket option requires name, type, perm arguments\n");  
  55.             break;  
  56.         }  
  57.         if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")  
  58.                 && strcmp(args[2],"seqpacket")) {  
  59.             parse_error(state, "socket type must be 'dgram', 'stream' or 'seqpacket'\n");  
  60.             break;  
  61.         }  
  62.         si = calloc(1, sizeof(*si));  
  63.         if (!si) {  
  64.             parse_error(state, "out of memory\n");  
  65.             break;  
  66.         }  
  67.         si->name = args[1]; // socket名字  
  68.         si->type = args[2]; // socket类型  
  69.         si->perm = strtoul(args[3], 0, 8); // socket读写权限  
  70.         if (nargs > 4)  
  71.             si->uid = decode_uid(args[4]);  
  72.         if (nargs > 5)  
  73.             si->gid = decode_uid(args[5]);  
  74.         si->next = svc->sockets;  
  75.         svc->sockets = si;  
  76.         break;  
  77.     }  
  78.     …  
  79.     default:  
  80.         parse_error(state, "invalid option '%s'\n", args[0]);  
  81.     }  
  82. }  

parse_line_service函数将根据配置文件的内容填充service结构体,zygote service解析完之后的结果如下图所示:

解析完之后:

1.      全局的service_list链表将解析后的service全部链接到了一起。

2.      socketinfo也是一个双向链表,这里链接了service用到的socket信息,zygote进程只有一个socket。

3.      onrestart通过commands指向一个commands链表,zygote共有4个commands。


init控制service

启动zygote

init.rc的zygote服务中有这样一句话:

service zygote /system/bin/app_process-Xzygote /system/bin --zygote --start-system-server

class main

服务默认创建的时候classname为“default”,这里通过“class main”来修改classname为“main”。之后,我们再回过头去看init.rc中有这个一句话:


在init进程启动的boot阶段,有一句“class_start main”。而class_start是一个COMMAND,其对应的处理函数是do_class_start。接着来看看do_class_start函数吧:

[cpp] view plain copy
  1. int do_class_start(int nargs, char **args)  
  2. {  
  3.     /* 
  4.         Args为do_class_start的参数,init.rc中只有一个参数,就是“main“、“core”等。 
  5.         service_for_each_class函数就是从service_list链表中找到classname和参数一致的service, 
  6.         然后调用service_start_if_not_disabled函数。 
  7.     */  
  8.         service_for_each_class(args[1], service_start_if_not_disabled);  
  9.         return 0;  
  10. }  
  11.   
  12. void service_for_each_class(const char *classname,  
  13.                             void (*func)(struct service *svc))  
  14. {  
  15.     struct listnode *node;  
  16.     struct service *svc;  
  17.     list_for_each(node, &service_list) {  
  18.         svc = node_to_item(node, struct service, slist);  
  19.         if (!strcmp(svc->classname, classname)) {  
  20.             func(svc);  
  21.         }  
  22.     }  
  23. }  

service_start_if_not_disabled函数具体做了什么呢?接着看:

[cpp] view plain copy
  1. static void service_start_if_not_disabled(struct service *svc)  
  2. {  
  3.     // 如果flags不为SVC_DISABLED,那么开始启动服务  
  4.     if (!(svc->flags & SVC_DISABLED)) {  
  5.         service_start(svc, NULL);  
  6.     }  
  7. }  

具体来看看服务的启动过程:

[cpp] 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.     char *scon = NULL;  
  8.     int rc;  
  9.   
  10.     svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART));  
  11.     svc->time_started = 0;  
  12.   
  13.     if (svc->flags & SVC_RUNNING) {  
  14.         return;  
  15.     }  
  16.   
  17.     needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;  
  18.     if (needs_console && (!have_console)) {  
  19.         ERROR("service '%s' requires console\n", svc->name);  
  20.         svc->flags |= SVC_DISABLED;  
  21.         return;  
  22.     }  
  23.   
  24.     /* 
  25.         Service一般运行于另外一个进程中,这个进程也是init的子进程,所以启动service前需要判断对应的可执行文件是否存在,zygote服务对应的可执行文件为/system/bin/app_process 
  26.     */  
  27.     if (stat(svc->args[0], &s) != 0) {  
  28.         ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);  
  29.         svc->flags |= SVC_DISABLED;  
  30.         return;  
  31.     }  
  32.   
  33.     if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {  
  34.         ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",  
  35.                svc->args[0]);  
  36.         svc->flags |= SVC_DISABLED;  
  37.         return;  
  38.     }  
  39.   
  40.     // … 省略selinux相关的内容  
  41.       
  42.     // 通过fork创建一个子进程  
  43.     pid = fork();  
  44.       
  45.     if (pid == 0) { // 在子进程中  
  46.         struct socketinfo *si;  
  47.         struct svcenvinfo *ei;  
  48.         char tmp[32];  
  49.         int fd, sz;  
  50.   
  51.         umask(077);  
  52.         // 设置属性服务信息到环境变量  
  53.     if (properties_inited()) {  
  54.             get_property_workspace(&fd, &sz);  
  55.             sprintf(tmp, "%d,%d", dup(fd), sz);  
  56.             add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);  
  57.         }  
  58.         // 设置属性进程的环境变量  
  59.         for (ei = svc->envvars; ei; ei = ei->next)  
  60.             add_environment(ei->name, ei->value);  
  61.   
  62.         setsockcreatecon(scon);  
  63.           
  64.     // 根据socketinfo创建socket,用于通信  
  65.         for (si = svc->sockets; si; si = si->next) {  
  66.             int socket_type = (  
  67.                     !strcmp(si->type, "stream") ? SOCK_STREAM :  
  68.                         (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));  
  69.             int s = create_socket(si->name, socket_type,  
  70.                                   si->perm, si->uid, si->gid);  
  71.             if (s >= 0) {  
  72.                 publish_socket(si->name, s);  
  73.             }  
  74.         }  
  75.   
  76.         ….  
  77.           
  78.         if (!dynamic_args) {  
  79.     /* 
  80.         调用execve函数来执行/system/bin/app_process,这样就进入了app_process的main函数中了。 
  81.     */  
  82.             if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {  
  83.                 ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));  
  84.             }  
  85.         } else {  
  86.             …  
  87.         }  
  88.         _exit(127);  
  89.     }  
  90.   
  91.     …  
  92.     // 父进程中设置子服务进程的信息,启动时间、pid等。  
  93.     svc->time_started = gettime();  
  94.     svc->pid = pid;  
  95.     svc->flags |= SVC_RUNNING;  
  96.       
  97.     // 如果属性服务已经初始化完毕了,那么就设置相应服务为running状态  
  98.     if (properties_inited())  
  99.         notify_service_state(svc->name, "running");  
  100. }  

原来,zygote是通过fork和execv共同创建的,但是service结构中的onrestart字段好像没有派上用场,原因何在?我们接着往下看。


重启zygote

init进程在初始化的时候会调用signal_init函数来初始化一个socket对,主要用来父子进程间通信。

[cpp] view plain copy
  1. void signal_init(void)  
  2. {  
  3.         int s[2];  
  4.   
  5.         struct sigaction act;  
  6.     memset(&act, 0, sizeof(act));  
  7.     /* 
  8.         父进程设置sa_flags为SA_NOCLDSTOP,表明只有子进程在退出时父进程才能收到SIGCHLD的信号,处理函数为sigchld_handler 
  9.     */  
  10.         act.sa_handler = sigchld_handler;  
  11.         act.sa_flags = SA_NOCLDSTOP;  
  12.         sigaction(SIGCHLD, &act, 0);  
  13.   
  14.         /* create a signalling mechanism for the sigchld handler */  
  15.         if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {  
  16.             signal_fd = s[0];  
  17.             signal_recv_fd = s[1];  
  18.             fcntl(s[0], F_SETFD, FD_CLOEXEC);  
  19.             fcntl(s[0], F_SETFL, O_NONBLOCK);  
  20.             fcntl(s[1], F_SETFD, FD_CLOEXEC);  
  21.             fcntl(s[1], F_SETFL, O_NONBLOCK);  
  22.         }  
  23.   
  24.         handle_signal();  
  25. }  

因此,子进程在退出时,父进程收到SIGCHLD消息,此时,信号处理函数为sigchld_handler。

[cpp] view plain copy
  1. static void sigchld_handler(int s)  
  2. {  
  3.     write(signal_fd, &s, 1);  
  4. }  

signal_fd被写入值之后,那么对应的signal_recv_fd便能收到消息了。处理逻辑在init进程main函数的最后面的for循环中进行处理:

[cpp] view plain copy
  1. int get_signal_fd()  
  2. {  
  3.     return signal_recv_fd;  
  4. }  
  5.   
  6. for (i = 0; i < fd_count; i++) {  
  7.     …  
  8.         else if (ufds[i].fd == get_signal_fd())  
  9.             handle_signal();  
  10.     }  
  11. }  
  12.   
  13. void handle_signal(void)  
  14. {  
  15.     char tmp[32];  
  16.   
  17.     /* we got a SIGCHLD - reap and restart as needed */  
  18.     read(signal_recv_fd, tmp, sizeof(tmp));  
  19.     while (!wait_for_one_process(0))  
  20.         ;  
  21. }  
  22.   
  23. static int wait_for_one_process(int block)  
  24. {  
  25.     pid_t pid;  
  26.     int status;  
  27.     struct service *svc;  
  28.     struct socketinfo *si;  
  29.     time_t now;  
  30.     struct listnode *node;  
  31.     struct command *cmd;  
  32.   
  33.     // 获得退出进程的pid  
  34.     while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );  
  35.     if (pid <= 0) return -1;  
  36.     INFO("waitpid returned pid %d, status = %08x\n", pid, status);  
  37.       
  38.     // 遍历service_list链表,找到退出的那个服务  
  39.     svc = service_find_by_pid(pid);  
  40.     if (!svc) {  
  41.         ERROR("untracked pid %d exited\n", pid);  
  42.         return 0;  
  43.     }  
  44.   
  45.     NOTICE("process '%s', pid %d exited\n", svc->name, pid);  
  46.   
  47.     /* 
  48.         如果不是SVC_ONESHOT即一次性启动的服务,那么就杀死该进程的所有子进程,这也是为什么zygote死后,java世界崩溃的原因。 
  49.     */  
  50.     if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {  
  51.         kill(-pid, SIGKILL);  
  52.         NOTICE("process '%s' killing any children in process group\n", svc->name);  
  53.     }  
  54.   
  55.     /* 删除服务创建的socket信息*/  
  56.     for (si = svc->sockets; si; si = si->next) {  
  57.         char tmp[128];  
  58.         snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);  
  59.         unlink(tmp);  
  60.     }  
  61.   
  62.     svc->pid = 0;  
  63.     svc->flags &= (~SVC_RUNNING);  
  64.   
  65.     /*  
  66.         如果服务进程的标志SVC_ONESHOT置位了,则表明此服务为一次性服务,死了之后就不需要重启,除非设置SVC_RESTART标志来手动重启该服务。 
  67.         此类服务死了之后,就置为SVC_DISABLED 
  68.     */  
  69.     if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {  
  70.         svc->flags |= SVC_DISABLED;  
  71.     }  
  72.   
  73.     /* 通知属性服务器,将该服务属性设置为stopped */  
  74.     if (svc->flags & (SVC_DISABLED | SVC_RESET) )  {  
  75.         notify_service_state(svc->name, "stopped");  
  76.         return 0;  
  77.     }  
  78.   
  79.     now = gettime();  
  80.     /* 
  81.         如果进程带有SVC_CRITICA标志,那么此时如果进程在4分钟内,死了>4次,则重启进入到recovery模式。根据init.rc的配置可知,ueventd、healthd、servicemanager等服务享有此种特殊待遇。 
  82.     */  
  83.     if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) {  
  84.         if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {  
  85.             if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {  
  86.                 ERROR("critical process '%s' exited %d times in %d minutes; "  
  87.                       "rebooting into recovery mode\n", svc->name,  
  88.                       CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);  
  89.                 android_reboot(ANDROID_RB_RESTART2, 0, "recovery");  
  90.                 return 0;  
  91.             }  
  92.         } else {  
  93.             svc->time_crashed = now;  
  94.             svc->nr_crashed = 1;  
  95.         }  
  96.     }  
  97.   
  98.     svc->flags &= (~SVC_RESTART);  
  99.     svc->flags |= SVC_RESTARTING;  
  100.   
  101.     /*  
  102.         Execute all onrestart commands for this service.  
  103.  
  104.         Zygote将执行如下操作: 
  105.         write /sys/android_power/request_state wake 
  106.         write /sys/power/state on 
  107.         restart media 
  108.         restart netd 
  109.     */  
  110.     list_for_each(node, &svc->onrestart.commands) {  
  111.         cmd = node_to_item(node, struct command, clist);  
  112.         cmd->func(cmd->nargs, cmd->args);  
  113.     }  
  114.   
  115.     /* 重新通知属性服务器,将该服务属性设置为restarting */  
  116.     notify_service_state(svc->name, "restarting");  
  117.     return 0;  
  118. }  

通过上面的代码可以知道onrestart的作用了,但是上述代码只是设置了相应svc的一些状态,flag、time_crashed、nr_crashed等等。那么真正的svc启动是在哪里呢?在init进程的main函数中,有一个大的无限循环,代码如下: 

[cpp] view plain copy
  1. for(;;) {  
  2.     int nr, i, timeout = -1;  
  3.   
  4.     execute_one_command();  
  5.   
  6.     // 此处就是调用service_start函数来重启那些flag带有SVC_RESTARTING的服务进程  
  7.     restart_processes();  
  8.     ….  
  9. }  

至此,死去的服务又开始重新启动了。

0 0
原创粉丝点击