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进程分析五 :进程的终止与再启动
***************************************************************************
1 前言
上一篇文章中,我们简单分析了 init 进程是如何去解析init.rc文件的,最终解析得到两个链表:
- 动作列表:action_list
- 服务列表: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 }
可以看到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 }
这个函数比较简单,接收两个参数:
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 }
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 }
通过上面的分析,我们大概可以理清楚基本的流程:
- 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
这个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)
比如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 }
首先是调用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 }
注意: 在这个函数中 调用 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
在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 }
该函数中调用了 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 }
这个函数也比较简单:在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 }
可以清楚的看到当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
比如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
比如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 }
这段代码的大体处理流程:
执行“当前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是如何执行启动的了。
*******
===
********
*