Init是系统的第一个进程,在初始化的时候会启动很多守护进程、装载文件系统、创建系统目录、初始化Android属性系统。
我们就来分析代码吧。
int main(int argc, char **argv) { int fd_count = 0; struct pollfd ufds[4]; char *tmpdev; char* debuggable; char tmp[32]; int property_set_fd_init = 0; int signal_fd_init = 0; int keychord_fd_init = 0; bool is_charger = false; if (!strcmp(basename(argv[0]), "ueventd"))//ueventd和watchdogd与init公用代码,可以在其mk文件中看到,ueventd和watchdogd只是软连接 return ueventd_main(argc, argv); if (!strcmp(basename(argv[0]), "watchdogd")) return watchdogd_main(argc, argv); /* clear the umask */ umask(0); /* Get the basic filesystem setup we need put * together in the initramdisk on / and then we'll * let the rc file figure out the rest. */ mkdir("/dev", 0755); mkdir("/proc", 0755); mkdir("/sys", 0755); mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); mkdir("/dev/pts", 0755); mkdir("/dev/socket", 0755); mount("devpts", "/dev/pts", "devpts", 0, NULL); mount("proc", "/proc", "proc", 0, NULL); mount("sysfs", "/sys", "sysfs", 0, NULL);//创建目录,以及mount
上面是一些创建目录,挂载文件系统
close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));//创建一个空文件booting,表示正在初始化 /* We must have some place other than / to create the * device nodes for kmsg and null, otherwise we won't * be able to remount / read-only later on. * Now that tmpfs is mounted on /dev, we can actually * talk to the outside world. */ open_devnull_stdio(); klog_init(); property_init();//创建共享区域存储属性值 get_hardware_name(hardware, &revision); process_kernel_cmdline();//解析proc/cmdline union selinux_callback cb; cb.func_log = log_callback; selinux_set_callback(SELINUX_CB_LOG, cb); cb.func_audit = audit_callback; selinux_set_callback(SELINUX_CB_AUDIT, cb); selinux_initialize(); /* These directories were necessarily created before initial policy load * and therefore need their security context restored to the proper value. * This must happen before /dev is populated by ueventd. */ restorecon("/dev"); restorecon("/dev/socket"); restorecon("/dev/__properties__"); restorecon_recursive("/sys"); is_charger = !strcmp(bootmode, "charger");//看开机是否是关机充电模式 INFO("property init\n"); property_load_boot_defaults();//解析根目录下的default.prop文件,把文件中定义的属性值读取出来设置到属性系统中
init_parse_config_file函数解析了init.rc文件
int init_parse_config_file(const char *fn) { char *data; data = read_file(fn, 0); if (!data) return -1; parse_config(fn, data); DUMP(); return 0; }
static void parse_config(const char *fn, char *s) { struct parse_state state; struct listnode import_list; struct listnode *node; char *args[INIT_PARSER_MAXARGS]; int nargs; nargs = 0; state.filename = fn; state.line = 0; state.ptr = s; state.nexttoken = 0; state.parse_line = parse_line_no_op; list_init(&import_list); state.priv = &import_list; for (;;) { switch (next_token(&state)) { case T_EOF://文件结束 state.parse_line(&state, 0, 0); goto parser_done; case T_NEWLINE://行结束 state.line++; if (nargs) { int kw = lookup_keyword(args[0]); if (kw_is(kw, SECTION)) {//判断是否有新的section state.parse_line(&state, 0, 0); parse_new_section(&state, kw, nargs, args); } else { state.parse_line(&state, nargs, args); } nargs = 0; } break; case T_TEXT://一个单词结束 if (nargs < INIT_PARSER_MAXARGS) { args[nargs++] = state.text; } break; } } parser_done: list_for_each(node, &import_list) { struct import *import = node_to_item(node, struct import, list); int ret; INFO("importing '%s'", import->filename); ret = init_parse_config_file(import->filename); if (ret) ERROR("could not import file '%s' from '%s'\n", import->filename, fn); } }
parse_config函数调用next_token函数就是寻找单词结束标志或行结束标志。如果是单词结束,就先存在args数组中,如果是行结束,根据第一个单词判断是否是一个section,“section”的标志是关键词on service import。如果是一个新的section,就调用parse_new_section开始一个新的section处理。
static void parse_new_section(struct parse_state *state, int kw, int nargs, char **args) { printf("[ %s %s ]\n", args[0], nargs > 1 ? args[1] : ""); switch(kw) { case K_service://解析service state->context = parse_service(state, nargs, args); if (state->context) { state->parse_line = parse_line_service; return; } break; case K_on:// 解析on state->context = parse_action(state, nargs, args); if (state->context) { state->parse_line = parse_line_action; return; } break; case K_import://解析import的文件 parse_import(state, nargs, args); break; } state->parse_line = parse_line_no_op; }先看parse_service
static void *parse_service(struct parse_state *state, int nargs, char **args) { struct service *svc; if (nargs < 3) { parse_error(state, "services must have a name and a program\n"); return 0; } if (!valid_name(args[1])) { parse_error(state, "invalid service name '%s'\n", args[1]); return 0; } svc = service_find_by_name(args[1]);// 从service_list找,如果有了就退出 if (svc) { parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]); return 0; } nargs -= 2; svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs); if (!svc) { parse_error(state, "out of memory\n"); return 0; } svc->name = args[1]; svc->classname = "default"; memcpy(svc->args, args + 2, sizeof(char*) * nargs); svc->args[nargs] = 0; svc->nargs = nargs; svc->onrestart.name = "onrestart"; list_init(&svc->onrestart.commands); list_add_tail(&service_list, &svc->slist);//将service加到service_list链表 return svc; }
如果成功将parse_line_service赋给state->parse_line 这样在parse_config中就可以解析service了
case T_NEWLINE://行结束 state.line++; if (nargs) { int kw = lookup_keyword(args[0]); if (kw_is(kw, SECTION)) {//判断是否有新的section state.parse_line(&state, 0, 0); parse_new_section(&state, kw, nargs, args); } else { state.parse_line(&state, nargs, args);//利用前面的赋值函数 } nargs = 0; } break;
那就看看parse_line_service函数就是解析各个项
static void parse_line_service(struct parse_state *state, int nargs, char **args) { struct service *svc = state->context; struct command *cmd; int i, kw, kw_nargs; if (nargs == 0) { return; } svc->ioprio_class = IoSchedClass_NONE; kw = lookup_keyword(args[0]); switch (kw) { case K_capability: break; case K_class: if (nargs != 2) { parse_error(state, "class option requires a classname\n"); } else { svc->classname = args[1]; } break; case K_console: svc->flags |= SVC_CONSOLE; break; case K_disabled: svc->flags |= SVC_DISABLED; svc->flags |= SVC_RC_DISABLED; break; case K_ioprio: 。。。。。。。。
而解析action如下,最后将action加到action_list中
static void *parse_action(struct parse_state *state, int nargs, char **args) { struct action *act; if (nargs < 2) { parse_error(state, "actions must have a trigger\n"); return 0; } if (nargs > 2) { parse_error(state, "actions may not have extra parameters\n"); return 0; } act = calloc(1, sizeof(*act)); act->name = args[1]; list_init(&act->commands); list_init(&act->qlist); list_add_tail(&action_list, &act->alist);//加到action_list中 /* XXX add to hash */ return act; }
而和service同样会把parse_line_action赋给state->parse_line ,而在parse_line_action会解析各个命令了
static void parse_line_action(struct parse_state* state, int nargs, char **args) { struct command *cmd; struct action *act = state->context; int (*func)(int nargs, char **args); int kw, n; if (nargs == 0) { return; } kw = lookup_keyword(args[0]); if (!kw_is(kw, COMMAND)) { parse_error(state, "invalid command '%s'\n", args[0]); return; } n = kw_nargs(kw); if (nargs < n) { parse_error(state, "%s requires %d %s\n", args[0], n - 1, n > 2 ? "arguments" : "argument"); return; } cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs); cmd->func = kw_func(kw); cmd->line = state->line; cmd->filename = state->filename; cmd->nargs = nargs; memcpy(cmd->args, args, sizeof(char*) * nargs); list_add_tail(&act->commands, &cmd->clist); }
最后parse_import,将各个import的rc文件加入import_list
static void parse_import(struct parse_state *state, int nargs, char **args) { struct listnode *import_list = state->priv; struct import *import; char conf_file[PATH_MAX]; int ret; if (nargs != 2) { ERROR("single argument needed for import\n"); return; } ret = expand_props(conf_file, args[1], sizeof(conf_file)); if (ret) { ERROR("error while handling import on line '%d' in '%s'\n", state->line, state->filename); return; } import = calloc(1, sizeof(struct import)); import->filename = strdup(conf_file); list_add_tail(import_list, &import->list); INFO("found import '%s', adding to import list", import->filename); }
在parse_config函数最后会对import_list链表中的文件再次解析,这样的话是先解析当前init.rc文件再解析之前import的文件
parser_done: list_for_each(node, &import_list) { struct import *import = node_to_item(node, struct import, list); int ret; INFO("importing '%s'", import->filename); ret = init_parse_config_file(import->filename); if (ret) ERROR("could not import file '%s' from '%s'\n", import->filename, fn); } }
在解析init.rc的时候,只是将普通的on...解析成action加到action_list中,然后只有真正加入action_queue才会真正执行。下面将分析会把哪些aciton加入action_queue
action_for_each_trigger("early-init", action_add_queue_tail); queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done"); queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng"); queue_builtin_action(keychord_init_action, "keychord_init"); queue_builtin_action(console_init_action, "console_init"); /* execute all the boot actions to get us started */ action_for_each_trigger("init", action_add_queue_tail); /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random * wasn't ready immediately after wait_for_coldboot_done */ queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng"); queue_builtin_action(property_service_init_action, "property_service_init"); queue_builtin_action(signal_init_action, "signal_init"); /* Don't mount filesystems or start core system services if in charger mode. */ if (is_charger) {//是否是关机充电模式,如果是这模式,很多都不启动 action_for_each_trigger("charger", action_add_queue_tail); } else { action_for_each_trigger("late-init", action_add_queue_tail); } /* run all property triggers based on current state of the properties */ queue_builtin_action(queue_property_triggers_action, "queue_property_triggers"); #if BOOTCHART queue_builtin_action(bootchart_init_action, "bootchart_init"); #endif
先看action_for_each_trigger,看看action_list有没有当前trigger,有就用函数执行它,而这个函数就是action_add_queue_tail
void action_for_each_trigger(const char *trigger, void (*func)(struct action *act)) { struct listnode *node; struct action *act; list_for_each(node, &action_list) { act = node_to_item(node, struct action, alist); if (!strcmp(act->name, trigger)) { func(act); } } }
而action_add_queue_tail就是将这个action加到action_queue链表中,但是比如"late-init"这个trigger,里面有好多比如"fs",先不加到action_queue链表中,要在execute_one_command的时候解析到这个action,才会根据这个action的cmd,再把"fs"这个action加到action_queue链表中。
void action_add_queue_tail(struct action *act) { if (list_empty(&act->qlist)) { list_add_tail(&action_queue, &act->qlist); } }
而queue_builtin_action也是将新建一个action,加到action_queue,也加到action_list里面。只是这是在init里面加的,而action_for_each_trigger是原先就在init.rc中的,所以action_for_each_trigger的cmd已经解析好了。
void queue_builtin_action(int (*func)(int nargs, char **args), char *name) { struct action *act; struct command *cmd; act = calloc(1, sizeof(*act)); act->name = name; list_init(&act->commands); list_init(&act->qlist); cmd = calloc(1, sizeof(*cmd)); cmd->func = func; cmd->args[0] = name; cmd->nargs = 1; list_add_tail(&act->commands, &cmd->clist); list_add_tail(&action_list, &act->alist); action_add_queue_tail(act); }
aciton一定得通过加入到action_queue才能被init执行,因此一般在init中加入on ......是不会被执行到的,除非放在一个会被触发的on...里面,再显示的调用trigger
for(;;) { int nr, i, timeout = -1; execute_one_command(); restart_processes();
先分析execute_one_command函数
void execute_one_command(void) { int ret, i; char cmd_str[256] = ""; if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {//取每个action,如果是最后一个cmd了,那么下次就要先去action cur_action = action_remove_queue_head(); cur_command = NULL; if (!cur_action) return; INFO("processing action %p (%s)\n", cur_action, cur_action->name); if (!strcmp(cur_action->name, "fs")) { queue_builtin_action(set_usb_serial_action, "set_usb_serial_action"); } cur_command = get_first_command(cur_action); } else {//从每个action中取cmd cur_command = get_next_command(cur_action, cur_command); } if (!cur_command) return; ret = cur_command->func(cur_command->nargs, cur_command->args);//执行每个cmd中的func if (klog_get_level() >= KLOG_INFO_LEVEL) {//打印而已 for (i = 0; i < cur_command->nargs; i++) { strlcat(cmd_str, cur_command->args[i], sizeof(cmd_str)); if (i < cur_command->nargs - 1) { strlcat(cmd_str, " ", sizeof(cmd_str)); } } INFO("command '%s' action=%s status=%d (%s:%d)\n", cmd_str, cur_action ? cur_action->name : "", ret, cur_command->filename, cur_command->line); } }
一开始以为service是在main函数里的restart_processes起的,最后发现不对,restart_processes只对flags是SVC_RESTARTING的service进行重启,而去看解析init.rc的service的时候没有将service的flags初始化为SVC_RESTARTING,也就是说service的启动肯定是别的方式。
于是先去搜service_start这个函数,因为service启动肯定时调这个函数,发现了service_start_if_not_disabled这个函数:
static void service_start_if_not_disabled(struct service *svc) { if (!(svc->flags & SVC_DISABLED)) { service_start(svc, NULL); } else { svc->flags |= SVC_DISABLED_START; } }
只要service的flags不是SVC_DISABLED就启动。
然后又在do_class_start调用这个函数
int do_class_start(int nargs, char **args) { /* Starting a class does not start services * which are explicitly disabled. They must * be started individually. */ service_for_each_class(args[1], service_start_if_not_disabled); return 0; }而do_class_start又在下面这个地方调用,这就是个命令对应的函数,于是去搜init.rc
KEYWORD(class, OPTION, 0, 0) KEYWORD(class_start, COMMAND, 1, do_class_start) KEYWORD(class_stop, COMMAND, 1, do_class_stop) KEYWORD(class_reset, COMMAND, 1, do_class_reset) KEYWORD(console, OPTION, 0, 0)
仔细看了init.rc发现,很多service都有class这个关键词
service ueventd /sbin/ueventd class core critical seclabel u:r:ueventd:s0 service logd /system/bin/logd #class core socket logd stream 0666 logd logd socket logdr seqpacket 0666 logd logd socket logdw dgram 0222 logd logd seclabel u:r:logd:s0 service healthd /sbin/healthd class core critical seclabel u:r:healthd:s0在init.rc确实有class_start main,class_start core这样命令的section,这样就明了,肯定在解析init.rc的section的时候没有仔细分析cmd导致的,我们再分析下好了。
on nonencrypted class_start main class_start late_start on property:sys.chargeonly.mode=0 class_start core start lc-oms-sa #add for boot mode,endparse_line_action分析每行section的命令
static void parse_line_action(struct parse_state* state, int nargs, char **args) { struct command *cmd; struct action *act = state->context; int (*func)(int nargs, char **args); int kw, n; if (nargs == 0) { return; } kw = lookup_keyword(args[0]);//先去分析命令 if (!kw_is(kw, COMMAND)) { parse_error(state, "invalid command '%s'\n", args[0]); return; } n = kw_nargs(kw); if (nargs < n) { parse_error(state, "%s requires %d %s\n", args[0], n - 1, n > 2 ? "arguments" : "argument"); return; } cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs); cmd->func = kw_func(kw); cmd->line = state->line; cmd->filename = state->filename; cmd->nargs = nargs; memcpy(cmd->args, args, sizeof(char*) * nargs); list_add_tail(&act->commands, &cmd->clist); }分析下lookup_keyword函数是解析每个section的cmd的
static int lookup_keyword(const char *s) { switch (*s++) { case 'c'://用首字母分类 if (!strcmp(s, "opy")) return K_copy; if (!strcmp(s, "apability")) return K_capability; if (!strcmp(s, "hdir")) return K_chdir; if (!strcmp(s, "hroot")) return K_chroot; if (!strcmp(s, "lass")) return K_class; if (!strcmp(s, "lass_start")) return K_class_start;//看到class_start了 if (!strcmp(s, "lass_stop")) return K_class_stop; if (!strcmp(s, "lass_reset")) return K_class_reset; if (!strcmp(s, "onsole")) return K_console; if (!strcmp(s, "hown")) return K_chown; if (!strcmp(s, "hmod")) return K_chmod; if (!strcmp(s, "ritical")) return K_critical; break; case 'd': if (!strcmp(s, "isabled")) return K_disabled; if (!strcmp(s, "omainname")) return K_domainname; 。。。。。
再来看看kw_func函数,获取cmd的函数时,这里巧妙运用了宏
我们来看看,kw_func只是一个结构体数组中的一个变量
#define kw_func(kw) (keyword_info[kw].func)
再来看看这个结构体,define中##代表连接在一起,一个#代表将该项变成字符串
#define KEYWORD(symbol, flags, nargs, func) \ [ K_##symbol ] = { #symbol, func, nargs + 1, flags, }, static struct { const char *name; int (*func)(int nargs, char **args); unsigned char nargs; unsigned char flags; } keyword_info[KEYWORD_COUNT] = { [ K_UNKNOWN ] = { "unknown", 0, 0, 0 }, #include "keywords.h" };
有意思的是在这个结构体数组定义的时候,有一个头文件引进
由于在上面已经定义过KEYWORD了,所以这边就跳过了
#ifndef KEYWORD int do_chroot(int nargs, char **args); int do_chdir(int nargs, char **args); int do_class_start(int nargs, char **args); int do_class_stop(int nargs, char **args); int do_class_reset(int nargs, char **args); int do_domainname(int nargs, char **args); int do_enable(int nargs, char **args); int do_exec(int nargs, char **args); int do_export(int nargs, char **args); int do_hostname(int nargs, char **args); int do_ifup(int nargs, char **args); int do_insmod(int nargs, char **args); int do_mkdir(int nargs, char **args); int do_mount_all(int nargs, char **args); int do_mount(int nargs, char **args); int do_powerctl(int nargs, char **args); int do_restart(int nargs, char **args); int do_restorecon(int nargs, char **args); int do_restorecon_recursive(int nargs, char **args); int do_rm(int nargs, char **args); int do_rmdir(int nargs, char **args); int do_setcon(int nargs, char **args); int do_setenforce(int nargs, char **args); int do_setkey(int nargs, char **args); int do_setprop(int nargs, char **args); int do_setrlimit(int nargs, char **args); int do_setsebool(int nargs, char **args); int do_start(int nargs, char **args); int do_stop(int nargs, char **args); int do_swapon_all(int nargs, char **args); int do_trigger(int nargs, char **args); int do_symlink(int nargs, char **args); int do_sysclktz(int nargs, char **args); int do_write(int nargs, char **args); int do_copy(int nargs, char **args); int do_chown(int nargs, char **args); int do_chmod(int nargs, char **args); int do_loglevel(int nargs, char **args); int do_load_persist_props(int nargs, char **args); int do_load_all_props(int nargs, char **args); int do_wait(int nargs, char **args); #define __MAKE_KEYWORD_ENUM__ #define KEYWORD(symbol, flags, nargs, func) K_##symbol, enum { K_UNKNOWN, #endif//直接到这 KEYWORD(capability, OPTION, 0, 0)//再看看上面KEYWORD宏的定义这段就变成 [ K_capablity ] = { "capablity", 0 , 0 + 1, OPTION }, KEYWORD(chdir, COMMAND, 1, do_chdir) KEYWORD(chroot, COMMAND, 1, do_chroot) KEYWORD(class, OPTION, 0, 0) KEYWORD(class_start, COMMAND, 1, do_class_start)// [ K_class_start ] = { "class_start", do_class_start, 1 + 1, COMMAND } , KEYWORD(class_stop, COMMAND, 1, do_class_stop) KEYWORD(class_reset, COMMAND, 1, do_class_reset) KEYWORD(console, OPTION, 0, 0) KEYWORD(critical, OPTION, 0, 0) KEYWORD(disabled, OPTION, 0, 0) 。。。。。。。。。
而我们前面的lookup_keyword返回的是K_class_start,而下面自然也就是do_class_start函数
#define kw_func(kw) (keyword_info[kw].func)
而其实K_class_start 是一个枚举,我们看如何实现的,
#include "keywords.h" #define KEYWORD(symbol, flags, nargs, func) \ [ K_##symbol ] = { #symbol, func, nargs + 1, flags, }, static struct { const char *name; int (*func)(int nargs, char **args); unsigned char nargs; unsigned char flags; } keyword_info[KEYWORD_COUNT] = { [ K_UNKNOWN ] = { "unknown", 0, 0, 0 }, #include "keywords.h" };
看我们在这是先引入"keywords.h"文件,然后再在结构体数组中再引入的
第一次引入的时候"keywords.h"就变成枚举了
#ifndef KEYWORD//进入,下面把函数都定义了 int do_chroot(int nargs, char **args); int do_chdir(int nargs, char **args); int do_class_start(int nargs, char **args); int do_class_stop(int nargs, char **args); int do_class_reset(int nargs, char **args); int do_domainname(int nargs, char **args); int do_enable(int nargs, char **args); int do_exec(int nargs, char **args); int do_export(int nargs, char **args); int do_hostname(int nargs, char **args); int do_ifup(int nargs, char **args); int do_insmod(int nargs, char **args); int do_mkdir(int nargs, char **args); int do_mount_all(int nargs, char **args); int do_mount(int nargs, char **args); int do_powerctl(int nargs, char **args); int do_restart(int nargs, char **args); int do_restorecon(int nargs, char **args); int do_restorecon_recursive(int nargs, char **args); int do_rm(int nargs, char **args); int do_rmdir(int nargs, char **args); int do_setcon(int nargs, char **args); int do_setenforce(int nargs, char **args); int do_setkey(int nargs, char **args); int do_setprop(int nargs, char **args); int do_setrlimit(int nargs, char **args); int do_setsebool(int nargs, char **args); int do_start(int nargs, char **args); int do_stop(int nargs, char **args); int do_swapon_all(int nargs, char **args); int do_trigger(int nargs, char **args); int do_symlink(int nargs, char **args); int do_sysclktz(int nargs, char **args); int do_write(int nargs, char **args); int do_copy(int nargs, char **args); int do_chown(int nargs, char **args); int do_chmod(int nargs, char **args); int do_loglevel(int nargs, char **args); int do_load_persist_props(int nargs, char **args); int do_load_all_props(int nargs, char **args); int do_wait(int nargs, char **args); #define __MAKE_KEYWORD_ENUM__ #define KEYWORD(symbol, flags, nargs, func) K_##symbol, enum { K_UNKNOWN, #endif KEYWORD(capability, OPTION, 0, 0)//就变成K_capability这是枚举的2 KEYWORD(chdir, COMMAND, 1, do_chdir) KEYWORD(chroot, COMMAND, 1, do_chroot) KEYWORD(class, OPTION, 0, 0) KEYWORD(class_start, COMMAND, 1, do_class_start) KEYWORD(class_stop, COMMAND, 1, do_class_stop) KEYWORD(class_reset, COMMAND, 1, do_class_reset) KEYWORD(console, OPTION, 0, 0) 。。。。。
因此在init.rc中有class_start就是去调用do_class_start函数
int do_class_start(int nargs, char **args) { /* Starting a class does not start services * which are explicitly disabled. They must * be started individually. */ service_for_each_class(args[1], service_start_if_not_disabled); return 0; }
service_for_each_class变量service_list中的service看有没有其classname和传入的一样,传入的class有core、main等
void service_for_each_class(const char *classname, void (*func)(struct service *svc)) { struct listnode *node; struct service *svc; list_for_each(node, &service_list) { svc = node_to_item(node, struct service, slist); if (!strcmp(svc->classname, classname)) { func(svc); } } }
而我们在解析service的时候如果有class,会把参数赋给classname
static void parse_line_service(struct parse_state *state, int nargs, char **args) { struct service *svc = state->context; struct command *cmd; int i, kw, kw_nargs; if (nargs == 0) { return; } svc->ioprio_class = IoSchedClass_NONE; kw = lookup_keyword(args[0]); switch (kw) { case K_capability: break; case K_class: if (nargs != 2) { parse_error(state, "class option requires a classname\n"); } else { svc->classname = args[1];//把参数赋给classname } break;
这样当执行到class_start core这个section的时候,就会去遍历service_list中service的class是core的就启动。
这样init.rc的启动service这块分析完了,继续分析。
继续分析restart_processes,restart_processes函数是重启service,也就是之前起过了
static void restart_processes() { process_needs_restart = 0; service_for_each_flags(SVC_RESTARTING, restart_service_if_needed); }它会将service的flags是SVC_RESTARTING的service调用restart_service_if_needed
void service_for_each_flags(unsigned matchflags, void (*func)(struct service *svc)) { struct listnode *node; struct service *svc; list_for_each(node, &service_list) { svc = node_to_item(node, struct service, slist); if (svc->flags & matchflags) { func(svc); } } }
static void restart_service_if_needed(struct service *svc) { time_t next_start_time = svc->time_started + 5; if (next_start_time <= gettime()) { svc->flags &= (~SVC_RESTARTING); service_start(svc, NULL); return; } if ((next_start_time < process_needs_restart) || (process_needs_restart == 0)) { process_needs_restart = next_start_time; } }
service_start就不分析了,在里面会fork一个进程,然后最后将该service的flags改成running。
下面是一个poll的IO复用函数,先加fd,然后监听。
if (!property_set_fd_init && get_property_set_fd() > 0) { ufds[fd_count].fd = get_property_set_fd(); ufds[fd_count].events = POLLIN; ufds[fd_count].revents = 0; fd_count++; property_set_fd_init = 1; } if (!signal_fd_init && get_signal_fd() > 0) { ufds[fd_count].fd = get_signal_fd(); ufds[fd_count].events = POLLIN; ufds[fd_count].revents = 0; fd_count++; signal_fd_init = 1; } if (!keychord_fd_init && get_keychord_fd() > 0) { ufds[fd_count].fd = get_keychord_fd(); ufds[fd_count].events = POLLIN; ufds[fd_count].revents = 0; fd_count++; keychord_fd_init = 1; } if (process_needs_restart) { timeout = (process_needs_restart - gettime()) * 1000; if (timeout < 0) timeout = 0; } if (!action_queue_empty() || cur_action) timeout = 0; #if BOOTCHART if (bootchart_count > 0) { if (timeout < 0 || timeout > BOOTCHART_POLLING_MS) timeout = BOOTCHART_POLLING_MS; if (bootchart_step() < 0 || --bootchart_count == 0) { bootchart_finish(); bootchart_count = 0; } } #endif nr = poll(ufds, fd_count, timeout); if (nr <= 0) continue; for (i = 0; i < fd_count; i++) { if (ufds[i].revents & POLLIN) { if (ufds[i].fd == get_property_set_fd()) handle_property_set_fd(); else if (ufds[i].fd == get_keychord_fd()) handle_keychord(); else if (ufds[i].fd == get_signal_fd()) handle_signal(); } } } return 0;
而各个fd是在之前queue_builtin_action的时候加入命令的,下面就是3个fd
queue_builtin_action(keychord_init_action, "keychord_init");//1 queue_builtin_action(console_init_action, "console_init"); /* execute all the boot actions to get us started */ action_for_each_trigger("init", action_add_queue_tail); /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random * wasn't ready immediately after wait_for_coldboot_done */ queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng"); queue_builtin_action(property_service_init_action, "property_service_init");//2 queue_builtin_action(signal_init_action, "signal_init");//3
先来分析下signal_init_action,
static int signal_init_action(int nargs, char **args) { signal_init(); if (get_signal_fd() < 0) { ERROR("signal_init() failed\n"); exit(1); } return 0; }
signal_init对SIGCHIILD信号处理,处理函数为sigchld_handler,下面建立了一个pipe
void signal_init(void) { int s[2]; struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_handler = sigchld_handler; act.sa_flags = SA_NOCLDSTOP; sigaction(SIGCHLD, &act, 0); /* create a signalling mechanism for the sigchld handler */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) { signal_fd = s[0]; signal_recv_fd = s[1]; fcntl(s[0], F_SETFD, FD_CLOEXEC); fcntl(s[0], F_SETFL, O_NONBLOCK); fcntl(s[1], F_SETFD, FD_CLOEXEC); fcntl(s[1], F_SETFL, O_NONBLOCK); } handle_signal(); }
而处理函数就是往管道的一侧发,那signal_recv_fd 也就有事件了
static void sigchld_handler(int s) { write(signal_fd, &s, 1); }
signal_recv_fd 有事件了会在init的poll函数中,调用handle_signal
void handle_signal(void) { char tmp[32]; /* we got a SIGCHLD - reap and restart as needed */ read(signal_recv_fd, tmp, sizeof(tmp)); while (!wait_for_one_process(0)) ; }
wait_for_one_process具体不分析了,会把service的flags改成SVC_RESTARTING,下次for循环到restart_processes,就会把这个service,restart了。
java层的方法:
getProperty
setProperty
native层方法:
property_get
property_set
属性值成功修改后,init进程会检查init.rc文件中是否定义了和该属性值匹配的触发器。如果有定义,就执行该触发器。
比如:
on property:ro.debuggable=1 start console
当该属性为1,就执行了。
ro:代表只读
persist:写入data/propery开机还有
net:自动设置为最后修改的属性名
和前面的class_start类似,在init.rc中也有load_all_props
on load_all_props_action load_all_props
然后执行该action的cmd的时候会调用do_load_all_props函数
int do_load_all_props(int nargs, char **args) { if (nargs == 1) { load_all_props(); return 0; } return -1; }load_all_props函数从下面几个不同的文件读取属性值,属性值都在这些地方定义
void load_all_props(void) { load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL); load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL); load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL); load_properties_from_file(PROP_PATH_FACTORY, "ro.*"); load_override_properties(); /* Read persistent properties after all default values have been loaded. */ load_persistent_properties(); }在上面这些函数最后都会调到property_set函数
int property_set(const char *name, const char *value) { prop_info *pi; int ret; size_t namelen = strlen(name); size_t valuelen = strlen(value); if (!is_legal_property_name(name, namelen)) return -1; if (valuelen >= PROP_VALUE_MAX) return -1; pi = (prop_info*) __system_property_find(name); if(pi != 0) { /* ro.* properties may NEVER be modified once set */ if(!strncmp(name, "ro.", 3)) return -1; __system_property_update(pi, value, valuelen); } else { ret = __system_property_add(name, namelen, value, valuelen); if (ret < 0) { ERROR("Failed to set '%s'='%s'\n", name, value); return ret; } } /* If name starts with "net." treat as a DNS property. */ if (strncmp("net.", name, strlen("net.")) == 0) { if (strcmp("net.change", name) == 0) { return 0; } /* * The 'net.change' property is a special property used track when any * 'net.*' property name is updated. It is _ONLY_ updated here. Its value * contains the last updated 'net.*' property. */ property_set("net.change", name); } else if (persistent_properties_loaded && strncmp("persist.", name, strlen("persist.")) == 0) { /* * Don't write properties to disk until after we have read all default properties * to prevent them from being overwritten by default values. */ write_persistent_property(name, value); } else if (strcmp("selinux.reload_policy", name) == 0 && strcmp("1", value) == 0) { selinux_reload_policy(); } property_changed(name, value);//最总也会调用property_changed函数 return 0; }
这里有一个property_triggers_enabled变量的判断,这个变量初始为0,在queue_property_triggers_action会把它置为1
void property_changed(const char *name, const char *value) { if (property_triggers_enabled) queue_property_triggers(name, value); }
queue_property_triggers_action函数
static int queue_property_triggers_action(int nargs, char **args) { queue_all_property_triggers(); /* enable property triggers */ property_triggers_enabled = 1; return 0; }
下面是遍历所有的action的所有事待property的,看属性值满足要求就把这个action加入action_queue。这个queue_property_triggers_action只会执行一遍,因为从action_queue拿出来就删了。
void queue_all_property_triggers() { struct listnode *node; struct action *act; list_for_each(node, &action_list) { act = node_to_item(node, struct action, alist); if (!strncmp(act->name, "property:", strlen("property:"))) { /* parse property name and value syntax is property:<name>=<value> */ const char* name = act->name + strlen("property:"); const char* equals = strchr(name, '='); if (equals) { char prop_name[PROP_NAME_MAX + 1]; char value[PROP_VALUE_MAX]; int length = equals - name; if (length > PROP_NAME_MAX) { ERROR("property name too long in trigger %s", act->name); } else { int ret; memcpy(prop_name, name, length); prop_name[length] = 0; /* does the property exist, and match the trigger value? */ ret = property_get(prop_name, value); if (ret > 0 && (!strcmp(equals + 1, value) || !strcmp(equals + 1, "*"))) { action_add_queue_tail(act); } } } } } }
下面继续看property_changed的queue_property_triggers函数,遍历所有的action,哪个属性值是满足,就将其action加入action_queue
void queue_property_triggers(const char *name, const char *value) { struct listnode *node; struct action *act; list_for_each(node, &action_list) { act = node_to_item(node, struct action, alist); if (!strncmp(act->name, "property:", strlen("property:"))) { const char *test = act->name + strlen("property:"); int name_length = strlen(name); if (!strncmp(name, test, name_length) && test[name_length] == '=' && (!strcmp(test + name_length + 1, value) || !strcmp(test + name_length + 1, "*"))) { action_add_queue_tail(act); } } } }
再来看poll监听的系统属性,property_service_init_action函数,先建了一个socket,并获取fd
static int property_service_init_action(int nargs, char **args) { /* read any property files on system or data and * fire up the property service. This must happen * after the ro.foo properties are set above so * that /data/local.prop cannot interfere with them. */ start_property_service(); if (get_property_set_fd() < 0) { ERROR("start_property_service() failed\n"); exit(1); } return 0; }poll监听到这个fd的事件后,也就是上层或者native谁设置了属性,就会往init发socket信息。
nr = poll(ufds, fd_count, timeout); if (nr <= 0) continue; for (i = 0; i < fd_count; i++) { if (ufds[i].revents & POLLIN) { if (ufds[i].fd == get_property_set_fd()) handle_property_set_fd();handle_property_set_fd函数如果发下来的属性是ctl.start ctl.stop ctl.restart,检查属性后启动或者停止指定的service;而如果是其他属性就直接设置了。设置属性最后也会去遍历所有的action,符合要求把这个action加入action_queue
void handle_property_set_fd() { ............. if(memcmp(msg.name,"ctl.",4) == 0) { // Keep the old close-socket-early behavior when handling // ctl.* properties. close(s); if (check_control_mac_perms(msg.value, source_ctx)) { handle_control_message((char*) msg.name + 4, (char*) msg.value);//执行开启service还是暂停 } else { ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n", msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid); } } else { if (check_perms(msg.name, source_ctx)) { property_set((char*) msg.name, (char*) msg.value);//设置属性 } else { ERROR("sys_prop: permission denied uid:%d name:%s\n", cr.uid, msg.name); } // Note: bionic's property client code assumes that the // property server will not close the socket until *AFTER* // the property is written to memory. close(s); } freecon(source_ctx); break; default: close(s); break; } }看看handle_control_message函数根据不同命令执行
void handle_control_message(const char *msg, const char *arg) { if (!strcmp(msg,"start")) { msg_start(arg); } else if (!strcmp(msg,"stop")) { msg_stop(arg); } else if (!strcmp(msg,"restart")) { msg_restart(arg); } else { ERROR("unknown control msg '%s'\n", msg); } }