Android 4.4 Init进程分析四 :init.rc脚本文件的执行

****************************************************************************

Android 4.4 init进程分析文章链接

  Android 4.4 Init进程分析一 :Android init进程概述

  Android 4.4 Init进程分析二 :Android初始化语言

  Android 4.4 Init进程分析三:init.rc脚本文件的解析

  Android 4.4 Init进程分析四 :init.rc脚本文件的执行

  Android 4.4 Init进程分析五 :进程的终止与再启动

  Android 4.4 Init进程分析六 :属性服务

***************************************************************************

 

1 前言

上一篇文章中,我们简单分析了 init 进程是如何去解析init.rc文件的,最终解析得到两个链表:

  1. 动作列表:action_list
  2. 服务列表:service_list

那么得到这两个列表后,init进程又是怎么去执行这些动作及服务的呢?这篇文章中我们继续分析。

2 action动作的执行

在init进程的main函数中,调用init_parse_config_file("/init.rc")函数后得到action_list,接下来就是分析这些action怎样执行。

2.1 init进程main()函数的后续处理

我们先看看main()函数的代码片段:

http://androidxref.com/4.4_r1/xref/system/core/init/init.c#1038

 1 int main(int argc, char **argv)
 2 {
 3     ...
 4     INFO("reading config file\n");
 5     init_parse_config_file("/init.rc"); //解析init.rc文件,得到action_list and serice_list
 6 
 7     action_for_each_trigger("early-init", action_add_queue_tail); // 把和trigger name相匹配的action放入action_queue
 8 
 9     queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done"); // 内建action处理
10     queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng"); // 内建action处理
11     queue_builtin_action(keychord_init_action, "keychord_init"); // 内建action处理
12     queue_builtin_action(console_init_action, "console_init"); // 内建action处理
13 
14     /* execute all the boot actions to get us started */
15     action_for_each_trigger("init", action_add_queue_tail);
16 
17     /* skip mounting filesystems in charger mode */
18     if (!is_charger) {
19         action_for_each_trigger("early-fs", action_add_queue_tail);
20         action_for_each_trigger("fs", action_add_queue_tail);
21         action_for_each_trigger("post-fs", action_add_queue_tail);
22         action_for_each_trigger("post-fs-data", action_add_queue_tail);
23     }
24 
25     /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
26      * wasn't ready immediately after wait_for_coldboot_done
27      */
28     queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng"); // 内建action处理
29 
30     queue_builtin_action(property_service_init_action, "property_service_init"); // 内建action处理
31     queue_builtin_action(signal_init_action, "signal_init"); // 内建action处理
32     queue_builtin_action(check_startup_action, "check_startup"); // 内建action处理
33 
34     if (is_charger) {
35         action_for_each_trigger("charger", action_add_queue_tail);
36     } else {
37         action_for_each_trigger("early-boot", action_add_queue_tail);
38         action_for_each_trigger("boot", action_add_queue_tail);
39     }
40 
41         /* run all property triggers based on current state of the properties */
42     queue_builtin_action(queue_property_triggers_action, "queue_property_triggers"); // 内建action处理
43 
44 
45 #if BOOTCHART
46     queue_builtin_action(bootchart_init_action, "bootchart_init"); // 内建action处理
47 #endif
48 
49     ...
50 }
View Code

可以看到main函数中在parse完.rc文件后,会调用action_for_each_trigger()函数做一些筛选的处理,把与trigger name相匹配的action放入action_queue。

2.2 action_for_each_trigger()函数

函数定义如下:

http://androidxref.com/4.4_r1/xref/system/core/init/init_parser.c#504

 1 void action_for_each_trigger(const char *trigger,
 2                              void (*func)(struct action *act))
 3 {
 4     struct listnode *node;
 5     struct action *act;
 6     list_for_each(node, &action_list) { // 遍历action_list
 7         act = node_to_item(node, struct action, alist);
 8         if (!strcmp(act->name, trigger)) { // 匹配trigger name
 9             func(act); // 处理函数,比如action_add_queue_tail,把action加入到action_queue
10         }
11     }
12 }
View Code

这个函数比较简单,接收两个参数:

const char *trigger: trigger name的字符指针,比如“early-init”、“init” ....

void (*func)(struct action *act) : 函数指针,也就是筛选出与指定的trigger name相匹配的action后调用这个函数来处理action。

比如:action_for_each_trigger("early-init", action_add_queue_tail)

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 }
View Code

action_add_queue_tail()函数把action加入到action_queue队列中。

2.3 queue_builtin_action()函数

代码中还可以看到调用了queue_builtin_action()函数,这个函数的作用是对‘内建action’进行处理,先看一下函数定义:

http://androidxref.com/4.4_r1/xref/system/core/init/init_parser.c#569

 1 void queue_builtin_action(int (*func)(int nargs, char **args), char *name)
 2 {
 3     struct action *act;
 4     struct command *cmd;
 5 
 6     act = calloc(1, sizeof(*act));
 7     act->name = name;
 8     list_init(&act->commands);
 9     list_init(&act->qlist);
10 
11     cmd = calloc(1, sizeof(*cmd));
12     cmd->func = func;
13     cmd->args[0] = name;
14     list_add_tail(&act->commands, &cmd->clist);
15 
16     list_add_tail(&action_list, &act->alist);
17     action_add_queue_tail(act);
18 }
View Code

通过上面的分析,我们大概可以理清楚基本的流程:

  • init进程通过调用init_parse_config_file("/init.rc")函数解析得到action_list,这个action_list可以被理解成一个来自init.rc的“草稿列表”,列表中的节点顺序基本上和init.rc脚本里编写section时的顺序一致,包括import进来的其它rc文件的解析结果也会放到这个action_list中。

 

  • action_list中各个结点的顺序不一定就是合适的“运行顺序”,所以我们需要另一个按我们的要求依次串接的队列,这个队列中各个结点的顺序也就是我们期望的“运行顺序”,那就是action_queue队列。

 

  • 另外,有些新的action并没有体现在init.rc脚本里,而是写在具体代码里的,这些action可以被称为“内建action”,我们可以通过调用queue_builtin_action()将“内建action”添加进action_list列表和action_queue队列中。

 2.4 init进程里主要分割的“子阶段”

如下图所示:

 

 

 

  •  绿色框内的action是 "内建action",透过queue_builtin_action来处理;
  •  early-init/init/boot是比较重要的子阶段;

2.4.1 early-init子阶段

我们先看early-init子阶段,这部分在init.rc里是这样表达的:

http://androidxref.com/4.4_r1/xref/system/core/rootdir/init.rc

1 on early-init
2     # Set init and its forked children's oom_adj.
3     write /proc/1/oom_adj -16
4 
5     # Set the security context for the init process.
6     # This should occur before anything else (e.g. ueventd) is started.
7     setcon u:r:init:s0
8 
9     start ueventd
View Code

这个action的触发器是 early-init,一旦触发就会执行4条command,分别是write、setcon、start和mkdir。

不同command对应的func回调函数也是不同的,具体对应什么,在上一篇文章有分析,可以查看Keywords.h

http://androidxref.com/4.4_r1/xref/system/core/init/keywords.h

 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)
View Code

比如start命令对应的回调函数是 do_start(), 代码如下:

http://androidxref.com/4.4_r1/xref/system/core/init/builtins.c#584

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 }
View Code

首先是调用service_find_by_name()函数,根据service name去service_list中找到对应的service节点

然后调用service_start()函数按照这个service 的选项要求启动它。

 http://androidxref.com/4.4_r1/xref/system/core/init/init.c#154

  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         /* starting a service removes it from the disabled or reset
 11          * state and immediately takes it out of the restarting
 12          * state if it was in there
 13          */
 14     svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART));
 15     svc->time_started = 0;
 16 
 17         /* running processes require no additional work -- if
 18          * they're in the process of exiting, we've ensured
 19          * that they will immediately restart on exit, unless
 20          * they are ONESHOT
 21          */
 22     if (svc->flags & SVC_RUNNING) {
 23         return;
 24     }
 25 
 26     needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;
 27     if (needs_console && (!have_console)) {
 28         ERROR("service '%s' requires console\n", svc->name);
 29         svc->flags |= SVC_DISABLED;
 30         return;
 31     }
 32 
 33     if (stat(svc->args[0], &s) != 0) {
 34         ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);
 35         svc->flags |= SVC_DISABLED;
 36         return;
 37     }
 38 
 39     if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {
 40         ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
 41                svc->args[0]);
 42         svc->flags |= SVC_DISABLED;
 43         return;
 44     }
 45 
 46     if (is_selinux_enabled() > 0) {
 47         if (svc->seclabel) {
 48             scon = strdup(svc->seclabel);
 49             if (!scon) {
 50                 ERROR("Out of memory while starting '%s'\n", svc->name);
 51                 return;
 52             }
 53         } else {
 54             char *mycon = NULL, *fcon = NULL;
 55 
 56             INFO("computing context for service '%s'\n", svc->args[0]);
 57             rc = getcon(&mycon);
 58             if (rc < 0) {
 59                 ERROR("could not get context while starting '%s'\n", svc->name);
 60                 return;
 61             }
 62 
 63             rc = getfilecon(svc->args[0], &fcon);
 64             if (rc < 0) {
 65                 ERROR("could not get context while starting '%s'\n", svc->name);
 66                 freecon(mycon);
 67                 return;
 68             }
 69 
 70             rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon);
 71             freecon(mycon);
 72             freecon(fcon);
 73             if (rc < 0) {
 74                 ERROR("could not get context while starting '%s'\n", svc->name);
 75                 return;
 76             }
 77         }
 78     }
 79 
 80     NOTICE("starting '%s'\n", svc->name);
 81 
 82     pid = fork();
 83 
 84     if (pid == 0) {
 85         struct socketinfo *si;
 86         struct svcenvinfo *ei;
 87         char tmp[32];
 88         int fd, sz;
 89 
 90         umask(077);
 91         if (properties_inited()) {
 92             get_property_workspace(&fd, &sz);
 93             sprintf(tmp, "%d,%d", dup(fd), sz);
 94             add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
 95         }
 96 
 97         for (ei = svc->envvars; ei; ei = ei->next)
 98             add_environment(ei->name, ei->value);
 99 
100         setsockcreatecon(scon);
101 
102         for (si = svc->sockets; si; si = si->next) {
103             int socket_type = (
104                     !strcmp(si->type, "stream") ? SOCK_STREAM :
105                         (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
106             int s = create_socket(si->name, socket_type,
107                                   si->perm, si->uid, si->gid);
108             if (s >= 0) {
109                 publish_socket(si->name, s);
110             }
111         }
112 
113         freecon(scon);
114         scon = NULL;
115         setsockcreatecon(NULL);
116 
117         if (svc->ioprio_class != IoSchedClass_NONE) {
118             if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
119                 ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
120                       getpid(), svc->ioprio_class, svc->ioprio_pri, strerror(errno));
121             }
122         }
123 
124         if (needs_console) {
125             setsid();
126             open_console();
127         } else {
128             zap_stdio();
129         }
130 
131 #if 0
132         for (n = 0; svc->args[n]; n++) {
133             INFO("args[%d] = '%s'\n", n, svc->args[n]);
134         }
135         for (n = 0; ENV[n]; n++) {
136             INFO("env[%d] = '%s'\n", n, ENV[n]);
137         }
138 #endif
139 
140         setpgid(0, getpid());
141 
142     /* as requested, set our gid, supplemental gids, and uid */
143         if (svc->gid) {
144             if (setgid(svc->gid) != 0) {
145                 ERROR("setgid failed: %s\n", strerror(errno));
146                 _exit(127);
147             }
148         }
149         if (svc->nr_supp_gids) {
150             if (setgroups(svc->nr_supp_gids, svc->supp_gids) != 0) {
151                 ERROR("setgroups failed: %s\n", strerror(errno));
152                 _exit(127);
153             }
154         }
155         if (svc->uid) {
156             if (setuid(svc->uid) != 0) {
157                 ERROR("setuid failed: %s\n", strerror(errno));
158                 _exit(127);
159             }
160         }
161         if (svc->seclabel) {
162             if (is_selinux_enabled() > 0 && setexeccon(svc->seclabel) < 0) {
163                 ERROR("cannot setexeccon('%s'): %s\n", svc->seclabel, strerror(errno));
164                 _exit(127);
165             }
166         }
167 
168         if (!dynamic_args) {
169             if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {
170                 ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
171             }
172         } else {
173             char *arg_ptrs[INIT_PARSER_MAXARGS+1];
174             int arg_idx = svc->nargs;
175             char *tmp = strdup(dynamic_args);
176             char *next = tmp;
177             char *bword;
178 
179             /* Copy the static arguments */
180             memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));
181 
182             while((bword = strsep(&next, " "))) {
183                 arg_ptrs[arg_idx++] = bword;
184                 if (arg_idx == INIT_PARSER_MAXARGS)
185                     break;
186             }
187             arg_ptrs[arg_idx] = '\0';
188             execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
189         }
190         _exit(127);
191     }
192 
193     freecon(scon);
194 
195     if (pid < 0) {
196         ERROR("failed to start '%s'\n", svc->name);
197         svc->pid = 0;
198         return;
199     }
200 
201     svc->time_started = gettime();
202     svc->pid = pid;
203     svc->flags |= SVC_RUNNING;
204 
205     if (properties_inited())
206         notify_service_state(svc->name, "running");
207 }
View Code

注意: 在这个函数中 调用 pid = fork(); 函数创建一个子进程来运行服务。

2.4.2 boot子阶段

boot部分在init.rc里是这样表达的:

http://androidxref.com/4.4_r1/xref/system/core/rootdir/init.rc

  1 on boot
  2 # basic network init
  3     ifup lo
  4     hostname localhost
  5     domainname localdomain
  6 
  7 # set RLIMIT_NICE to allow priorities from 19 to -20
  8     setrlimit 13 40 40
  9 
 10 # Memory management.  Basic kernel parameters, and allow the high
 11 # level system server to be able to adjust the kernel OOM driver
 12 # parameters to match how it is managing things.
 13     write /proc/sys/vm/overcommit_memory 1
 14     write /proc/sys/vm/min_free_order_shift 4
 15     chown root system /sys/module/lowmemorykiller/parameters/adj
 16     chmod 0664 /sys/module/lowmemorykiller/parameters/adj
 17     chown root system /sys/module/lowmemorykiller/parameters/minfree
 18     chmod 0664 /sys/module/lowmemorykiller/parameters/minfree
 19 
 20     # Tweak background writeout
 21     write /proc/sys/vm/dirty_expire_centisecs 200
 22     write /proc/sys/vm/dirty_background_ratio  5
 23 
 24     # Permissions for System Server and daemons.
 25     chown radio system /sys/android_power/state
 26     chown radio system /sys/android_power/request_state
 27     chown radio system /sys/android_power/acquire_full_wake_lock
 28     chown radio system /sys/android_power/acquire_partial_wake_lock
 29     chown radio system /sys/android_power/release_wake_lock
 30     chown system system /sys/power/autosleep
 31     chown system system /sys/power/state
 32     chown system system /sys/power/wakeup_count
 33     chown radio system /sys/power/wake_lock
 34     chown radio system /sys/power/wake_unlock
 35     chmod 0660 /sys/power/state
 36     chmod 0660 /sys/power/wake_lock
 37     chmod 0660 /sys/power/wake_unlock
 38 
 39     chown system system /sys/devices/system/cpu/cpufreq/interactive/timer_rate
 40     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/timer_rate
 41     chown system system /sys/devices/system/cpu/cpufreq/interactive/timer_slack
 42     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/timer_slack
 43     chown system system /sys/devices/system/cpu/cpufreq/interactive/min_sample_time
 44     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/min_sample_time
 45     chown system system /sys/devices/system/cpu/cpufreq/interactive/hispeed_freq
 46     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/hispeed_freq
 47     chown system system /sys/devices/system/cpu/cpufreq/interactive/target_loads
 48     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/target_loads
 49     chown system system /sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load
 50     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load
 51     chown system system /sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay
 52     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay
 53     chown system system /sys/devices/system/cpu/cpufreq/interactive/boost
 54     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/boost
 55     chown system system /sys/devices/system/cpu/cpufreq/interactive/boostpulse
 56     chown system system /sys/devices/system/cpu/cpufreq/interactive/input_boost
 57     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/input_boost
 58     chown system system /sys/devices/system/cpu/cpufreq/interactive/boostpulse_duration
 59     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/boostpulse_duration
 60     chown system system /sys/devices/system/cpu/cpufreq/interactive/io_is_busy
 61     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/io_is_busy
 62 
 63     # Assume SMP uses shared cpufreq policy for all CPUs
 64     chown system system /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
 65     chmod 0660 /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
 66 
 67     chown system system /sys/class/timed_output/vibrator/enable
 68     chown system system /sys/class/leds/keyboard-backlight/brightness
 69     chown system system /sys/class/leds/lcd-backlight/brightness
 70     chown system system /sys/class/leds/button-backlight/brightness
 71     chown system system /sys/class/leds/jogball-backlight/brightness
 72     chown system system /sys/class/leds/red/brightness
 73     chown system system /sys/class/leds/green/brightness
 74     chown system system /sys/class/leds/blue/brightness
 75     chown system system /sys/class/leds/red/device/grpfreq
 76     chown system system /sys/class/leds/red/device/grppwm
 77     chown system system /sys/class/leds/red/device/blink
 78     chown system system /sys/class/timed_output/vibrator/enable
 79     chown system system /sys/module/sco/parameters/disable_esco
 80     chown system system /sys/kernel/ipv4/tcp_wmem_min
 81     chown system system /sys/kernel/ipv4/tcp_wmem_def
 82     chown system system /sys/kernel/ipv4/tcp_wmem_max
 83     chown system system /sys/kernel/ipv4/tcp_rmem_min
 84     chown system system /sys/kernel/ipv4/tcp_rmem_def
 85     chown system system /sys/kernel/ipv4/tcp_rmem_max
 86     chown root radio /proc/cmdline
 87 
 88 # Set these so we can remotely update SELinux policy
 89     chown system system /sys/fs/selinux/load
 90     chown system system /sys/fs/selinux/enforce
 91 
 92 # Define TCP buffer sizes for various networks
 93 #   ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
 94     setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208
 95     setprop net.tcp.buffersize.wifi    524288,1048576,2097152,262144,524288,1048576
 96     setprop net.tcp.buffersize.lte     524288,1048576,2097152,262144,524288,1048576
 97     setprop net.tcp.buffersize.umts    4094,87380,110208,4096,16384,110208
 98     setprop net.tcp.buffersize.hspa    4094,87380,262144,4096,16384,262144
 99     setprop net.tcp.buffersize.hsupa   4094,87380,262144,4096,16384,262144
100     setprop net.tcp.buffersize.hsdpa   4094,87380,262144,4096,16384,262144
101     setprop net.tcp.buffersize.hspap   4094,87380,1220608,4096,16384,1220608
102     setprop net.tcp.buffersize.edge    4093,26280,35040,4096,16384,35040
103     setprop net.tcp.buffersize.gprs    4092,8760,11680,4096,8760,11680
104     setprop net.tcp.buffersize.evdo    4094,87380,262144,4096,16384,262144
105 
106     class_start core
107     class_start main
View Code

在boot action的最后,出现了两句非常重要的语句:

1     class_start core
2     class_start main

之前我们在讲解Android Init Language时曾提到过service的class选项:服务所属的类,当一个类启动或退出时,其所包含的所有服务可以一同启动或退出。若为指定该option,服务默认属于“default”类

在这里便是利用class选项来启动属于该类的所有service。

class_start命令对应的回调函数是do_class_start(),该函数的代码如下:

http://androidxref.com/4.4_r1/xref/system/core/init/builtins.c#214

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 }
View Code

该函数中调用了 service_for_each_class(args[1], service_start_if_not_disabled) ,来看一下这个函数:

http://androidxref.com/4.4_r1/xref/system/core/init/init_parser.c#478

 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 }
View Code

这个函数也比较简单:在service_list中检索出与指定的class_name匹配的service,然后使用func()函数对这个service进行处理,在这里func函数即为service_start_if_not_disabled()函数:

http://androidxref.com/4.4_r1/xref/system/core/init/builtins.c#195

1 static void service_start_if_not_disabled(struct service *svc)
2 {
3     if (!(svc->flags & SVC_DISABLED)) {
4         service_start(svc, NULL);
5     }
6 }
View Code

可以清楚的看到当service的disabled选项没有开启时,就调用service_start()函数启动这个service.

查看init.rc文件我们可以看到,boot子阶段启动的"core"类型的服务有:

 1 service ueventd /sbin/ueventd
 2     class core
 3     critical
 4     seclabel u:r:ueventd:s0
 5 
 6 service healthd /sbin/healthd
 7     class core
 8     critical
 9     seclabel u:r:healthd:s0
10 
11 service console /system/bin/sh
12     class core
13     console
14     disabled
15     user shell
16     group log
17 
18 # adbd is controlled via property triggers in init.<platform>.usb.rc
19 service adbd /sbin/adbd
20     class core
21     socket adbd stream 660 system system
22     disabled
23     seclabel u:r:adbd:s0
24 
25 service servicemanager /system/bin/servicemanager
26     class core
27     user system
28     group system
29     critical
30     onrestart restart healthd
31     onrestart restart zygote
32     onrestart restart media
33     onrestart restart surfaceflinger
34     onrestart restart drm
35 
36 service vold /system/bin/vold
37     class core
38     socket vold stream 0660 root mount
39     ioprio be 2
View Code

比如Android的核心服务之一:service_manager也是在这一阶段启动的。

 

查看init.rc文件我们可以看到,boot子阶段启动的"main"类型的服务有:

 1 service netd /system/bin/netd
 2     class main
 3     socket netd stream 0660 root system
 4     socket dnsproxyd stream 0660 root inet
 5     socket mdns stream 0660 root system
 6 
 7 service debuggerd /system/bin/debuggerd
 8     class main
 9 
10 service ril-daemon /system/bin/rild
11     class main
12     socket rild stream 660 root radio
13     socket rild-debug stream 660 radio system
14     user root
15     group radio cache inet misc audio log
16 
17 service surfaceflinger /system/bin/surfaceflinger
18     class main
19     user system
20     group graphics drmrpc
21     onrestart restart zygote
22 
23 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
24     class main
25     socket zygote stream 660 root system
26     onrestart write /sys/android_power/request_state wake
27     onrestart write /sys/power/state on
28     onrestart restart media
29     onrestart restart netd
30 
31 service drm /system/bin/drmserver
32     class main
33     user drm
34     group drm system inet drmrpc
35 
36 service media /system/bin/mediaserver
37     class main
38     user media
39     group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
40     ioprio rt 4
41 
42 service bootanim /system/bin/bootanimation
43     class main
44     user graphics
45     group graphics
46     disabled
47     oneshot
48 
49 service installd /system/bin/installd
50     class main
51     socket installd stream 600 system system
52 
53 service flash_recovery /system/etc/install-recovery.sh
54     class main
55     oneshot
56 
57 service racoon /system/bin/racoon
58     class main
59     socket racoon stream 600 system system
60     # IKE uses UDP port 500. Racoon will setuid to vpn after binding the port.
61     group vpn net_admin inet
62     disabled
63     oneshot
64 
65 service mtpd /system/bin/mtpd
66     class main
67     socket mtpd stream 600 system system
68     user vpn
69     group vpn net_admin inet net_raw
70     disabled
71     oneshot
72 
73 service keystore /system/bin/keystore /data/misc/keystore
74     class main
75     user keystore
76     group keystore drmrpc
77 
78 service dumpstate /system/bin/dumpstate -s
79     class main
80     socket dumpstate stream 0660 shell log
81     disabled
82     oneshot
83 
84 service sshd /system/bin/start-ssh
85     class main
86     disabled
87 
88 service mdnsd /system/bin/mdnsd
89     class main
90     user mdnsr
91     group inet net_raw
92     socket mdnsd stream 0660 mdnsr inet
93     disabled
94     oneshot
View Code

比如Android创建内部创建新进程的核心服务zygote 、 图形绘制处理服务surfaceflinger 都是在这一阶段启动的。

 

经过上面的流程,action_list中的action已经按照不同的阶段(init/boot/....)被重新整理并顺序放入action_queue中等待执行。

 

2.5 for循环中执行action_queue

我们继续回到init进程的main()函数中,动作重新整理并加入action_queue队列之后,又是如何执行的呢?

main()函数中可以看到,init进程最终会进入一个for(;;)循环,在这个循环中,每次都会尝试执行一个command:

http://androidxref.com/4.4_r1/xref/system/core/init/init.c#1083

1 int main(int argc, char **argv)
2 {
3     . . . . . .
4     for(;;) {
5         int nr, i, timeout = -1;
6         execute_one_command();
7         restart_processes();
8     . . . . . .
9 }

调用的execute_one_command()的代码如下:

http://androidxref.com/4.4_r1/xref/system/core/init/init.c#531

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

这段代码的大体处理流程:
    执行“当前action”(cur_action)的“当前command”(cur_command)。
    如果执行时没有“当前action”,就尝试从action_queue队列的头部摘取一个节点。
    如果执行时没有“当前command”,就从“当前action”中获取下一个该执行的command。
    而一旦得到了该执行的command,就回调其func函数指针。

3 service服务的启动

通过上面的分析,应该已经可以看出,在action执行阶段已经把开机阶段需要带起的service都启动了,也即是class_start core 类似的命令来启动该类下的所有service.

这里不再赘述。

4 总结

通过这篇文章的分析,我们可以清楚的知道action and service是如何执行启动的了。

 

 

*******

===

********

*

posted on 2020-01-17 17:15  二的次方  阅读(866)  评论(0编辑  收藏  举报