一、init.rc语法规则
1.init.rc文件的内容主要分类
动作(Action)
命令(Commands)
服务(Services)
选项(Options)
触发(trigger)
2.动作和命令一起使用
- on <trigger>
- <command>
- <command>
- <command>
2.1.trigger是触发条件,为真执行命令
trigger有以下几种类型
- boot
- /init.conf加载完毕时触发
- <name>=<value>
- 当<name>被设置为<value>时触发
- device-added-<path>
- device-removed-<path>
- 设备<path>被添加移除时触发
- service-exited-<name>
- 当服务<name>退出时触发
3.服务和选项一起使用
- service <name> <pathname> [ <argument> ]*
- <option>
- <option>
3.1.option选项
- critical
- disabled
- setenv <name> <value>
- socket <name> <type> <perm> [ <user> [ <group> ] ]
- user <username>
- group <groupname> [ <groupname> ]*
- oneshot
- class <name>
- onrestart
二、init.rc文件的解析
1.init_parse_config_file
在system/core/init/init.c文件的main函数中调用
- init_parse_config_file("/init.rc");
函数将init.rc作为参数读取进来
- int init_parse_config_file(const char *fn)
- {
- char *data;
- data = read_file(fn, 0); //读取init.rc文件到data中
- if (!data) return -1;
- parse_config(fn, data); //解析配置
- DUMP();
- return 0;
- }
2.解析配置parse_config
- static void parse_config(const char *fn, char *s)
- {
- struct parse_state state;
- char *args[INIT_PARSER_MAXARGS];
- int nargs;
- nargs = 0;
- state.filename = fn;
- state.line = 1;
- state.ptr = s; //指向init.rc的数据
- state.nexttoken = 0;
- state.parse_line = parse_line_no_op; //空操作
- for (;;) {
- switch (next_token(&state)) { //-->3.next_token跳过注释等,筛选需要解析的行
- case T_EOF: //文件末尾
- state.parse_line(&state, 0, 0); //后面参数为 0, 0所以直接返回
- return;
- case T_NEWLINE: //新行解析
- if (nargs) { //有文本参数
- int kw = lookup_keyword(args[0]); //解析关键词-->4.lookup_keyword
- if (kw_is(kw, SECTION)) { //判断是否section类-->5.kw_is
- state.parse_line(&state, 0, 0); //后面参数为 0, 0所以直接返回
- parse_new_section(&state, kw, nargs, args); //6.parse_new_section
- }
- else {
- state.parse_line(&state, nargs, args); //解析前一行parse_line_service或parse_line_action
- }
- nargs = 0; //nargs参数个数清0
- }
- break;
- case T_TEXT: //文本
- if (nargs < INIT_PARSER_MAXARGS) {
- args[nargs++] = state.text; //保存文本参数,nargs++
- }
- break;
- }
- }
- }
T_TEXT分支记录参数信息 例如
on early-init
symlink /initlogo.rle.bak /initlogo.rle
则会记录成
args[0]=on, args[1]=early-init -->换行
args[0]=symlink, args[1]=/initlogo.rle.bak, args[2]=/initlogo.rle -->换行
记录完后换新行会进入T_NEWLINE分支,分支会解析上一行的args[0],提取关键字,判断关键字类型做处理
如果是on和service关键词会调用parse_new_section处理,如果不是则调用state.parse_line函数处理,
parse_line函数可以是parse_line_service【service】或parse_line_action【on】
该parse_line函数主要是解析on/service后面带的command/options
正如例子中,on early-init 调用parse_new_section设置parse_line函数为parse_line_action
接着处理【on的command】symlink /initlogo.rle.bak /initlogo.rle的时候则调用parse_line函数parse_line_action
等到所有都处理完了则进入T_EOF分支,T_EOF分支return,跳出循环体
3.next_token
- int next_token(struct parse_state *state)
- {
- char *x = state->ptr;
- char *s;
- if (state->nexttoken) {
- int t = state->nexttoken;
- state->nexttoken = 0;
- return t;
- }
- for (;;) {
- switch (*x) {
- case 0: //文件结尾
- state->ptr = x;
- return T_EOF;
- case '\n': //换行
- state->line++; //行数++
- x++;
- state->ptr = x;
- return T_NEWLINE;
- case ' ': //空格
- case '\t': //tab制表
- case '\r': //回车
- x++;
- continue;
- case '#': //注释
- while (*x && (*x != '\n')) //跳过注释直到换行
- x++;
- state->line++; //行数++
- state->ptr = x;
- return T_NEWLINE;
- default: //文本
- goto text;
- }
- }
- textdone:
- state->ptr = x;
- *s = 0;
- return T_TEXT;
- text:
- state->text = s = x;
- textresume:
- for (;;) {
- switch (*x) {
- case 0: //文本结束
- goto textdone;
- case ' ': //空格
- case '\t': //tab制表
- case '\r': //回车
- x++;
- goto textdone;
- case '\n': //换行
- state->nexttoken = T_NEWLINE;
- x++;
- goto textdone;
- case '"': //引号括起
- x++;
- for (;;) {
- switch (*x) {
- case 0:
- state->ptr = x;
- return T_EOF;
- case '"': //引号结束
- x++;
- goto textresume;
- default: //引号括起的内容
- *s++ = *x++;
- }
- }
- break;
- case '\\': //转义字符
- x++;
- switch (*x) {
- case 0:
- goto textdone;
- case 'n':
- *s++ = '\n';
- break;
- case 'r':
- *s++ = '\r';
- break;
- case 't':
- *s++ = '\t';
- break;
- case '\\':
- *s++ = '\\';
- break;
- case '\r':
- /* \ <cr> <lf> -> line continuation */
- if (x[1] != '\n') {
- x++;
- continue;
- }
- case '\n':
- /* \ <lf> -> line continuation */
- state->line++;
- x++;
- /* eat any extra whitespace */
- while((*x == ' ') || (*x == '\t')) x++;
- continue;
- default:
- /* unknown escape -- just copy */
- *s++ = *x++;
- }
- continue;
- default: //复制文本到s
- *s++ = *x++;
- }
- }
- return T_EOF;
- }
4.lookup_keyword
- 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;
- if (!strcmp(s, "lass_stop")) return K_class_stop;
- 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;
- break;
- case 'e':
- if (!strcmp(s, "xec")) return K_exec;
- if (!strcmp(s, "xport")) return K_export;
- break;
- case 'g':
- if (!strcmp(s, "roup")) return K_group;
- break;
- case 'h':
- if (!strcmp(s, "ostname")) return K_hostname;
- break;
- case 'i':
- if (!strcmp(s, "oprio")) return K_ioprio;
- if (!strcmp(s, "fup")) return K_ifup;
- if (!strcmp(s, "nsmod")) return K_insmod;
- if (!strcmp(s, "mport")) return K_import;
- break;
- case 'k':
- if (!strcmp(s, "eycodes")) return K_keycodes;
- break;
- case 'l':
- if (!strcmp(s, "oglevel")) return K_loglevel;
- break;
- case 'm':
- if (!strcmp(s, "kdir")) return K_mkdir;
- if (!strcmp(s, "ount")) return K_mount;
- break;
- case 'o':
- if (!strcmp(s, "n")) return K_on;
- if (!strcmp(s, "neshot")) return K_oneshot;
- if (!strcmp(s, "nrestart")) return K_onrestart;
- break;
- case 'r':
- if (!strcmp(s, "estart")) return K_restart;
- break;
- case 's':
- if (!strcmp(s, "ervice")) return K_service;
- if (!strcmp(s, "etenv")) return K_setenv;
- if (!strcmp(s, "etkey")) return K_setkey;
- if (!strcmp(s, "etprop")) return K_setprop;
- if (!strcmp(s, "etrlimit")) return K_setrlimit;
- if (!strcmp(s, "ocket")) return K_socket;
- if (!strcmp(s, "tart")) return K_start;
- if (!strcmp(s, "top")) return K_stop;
- if (!strcmp(s, "ymlink")) return K_symlink;
- if (!strcmp(s, "ysclktz")) return K_sysclktz;
- break;
- case 't':
- if (!strcmp(s, "rigger")) return K_trigger;
- break;
- case 'u':
- if (!strcmp(s, "ser")) return K_user;
- break;
- case 'w':
- if (!strcmp(s, "rite")) return K_write;
- if (!strcmp(s, "ait")) return K_wait;
- break;
- }
- return K_UNKNOWN;
- }
5.kw_is
5.1.kw_is宏定义
- #define kw_is(kw, type) (keyword_info[kw].flags & (type))
5.2.keyword_info全局数组的定义
- 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文件
5.3.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_domainname(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_import(int nargs, char **args);
- int do_mkdir(int nargs, char **args);
- int do_mount(int nargs, char **args);
- int do_restart(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_start(int nargs, char **args);
- int do_stop(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_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(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(console, OPTION, 0, 0)
- KEYWORD(critical, OPTION, 0, 0)
- KEYWORD(disabled, OPTION, 0, 0)
- KEYWORD(domainname, COMMAND, 1, do_domainname)
- KEYWORD(exec, COMMAND, 1, do_exec)
- KEYWORD(export, COMMAND, 2, do_export)
- KEYWORD(group, OPTION, 0, 0)
- KEYWORD(hostname, COMMAND, 1, do_hostname)
- KEYWORD(ifup, COMMAND, 1, do_ifup)
- KEYWORD(insmod, COMMAND, 1, do_insmod)
- KEYWORD(import, COMMAND, 1, do_import)
- KEYWORD(keycodes, OPTION, 0, 0)
- KEYWORD(mkdir, COMMAND, 1, do_mkdir)
- KEYWORD(mount, COMMAND, 3, do_mount)
- KEYWORD(on, SECTION, 0, 0)
- KEYWORD(oneshot, OPTION, 0, 0)
- KEYWORD(onrestart, OPTION, 0, 0)
- KEYWORD(restart, COMMAND, 1, do_restart)
- KEYWORD(service, SECTION, 0, 0)
- KEYWORD(setenv, OPTION, 2, 0)
- KEYWORD(setkey, COMMAND, 0, do_setkey)
- KEYWORD(setprop, COMMAND, 2, do_setprop)
- KEYWORD(setrlimit, COMMAND, 3, do_setrlimit)
- KEYWORD(socket, OPTION, 0, 0)
- KEYWORD(start, COMMAND, 1, do_start)
- KEYWORD(stop, COMMAND, 1, do_stop)
- KEYWORD(trigger, COMMAND, 1, do_trigger)
- KEYWORD(symlink, COMMAND, 1, do_symlink)
- KEYWORD(sysclktz, COMMAND, 1, do_sysclktz)
- KEYWORD(user, OPTION, 0, 0)
- KEYWORD(wait, COMMAND, 1, do_wait)
- KEYWORD(write, COMMAND, 2, do_write)
- KEYWORD(copy, COMMAND, 2, do_copy)
- KEYWORD(chown, COMMAND, 2, do_chown)
- KEYWORD(chmod, COMMAND, 2, do_chmod)
- KEYWORD(loglevel, COMMAND, 1, do_loglevel)
- KEYWORD(ioprio, OPTION, 0, 0)
- #ifdef __MAKE_KEYWORD_ENUM__
- KEYWORD_COUNT,
- };
- #undef __MAKE_KEYWORD_ENUM__
- #undef KEYWORD
- #endif
5.4.结合KEYWORD宏拆开全局keyword_info数组可得
- 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 },
- [ K_capability ] = { "capability", 0, 0, OPTION },
- [ K_chdir ] = { "chdir", do_chdir, 1, COMMAND },
- [ K_chroot ] = { "chroot", do_chroot, 1, COMMAND },
- [ K_class ] = { "class", 0, 0, OPTION, },
- [ K_class_start ] = { "class_start", do_class_start, 1, COMMAND },
- [ K_class_stop ] = { "class_stop", do_class_stop, 1, COMMAND },
- [ K_console ] = { "console", 0, 0, OPTION },
- [ K_critical ] = { "critical", 0, 0, OPTION },
- [ K_disabled ] = { "disabled", 0, 0, OPTION },
- [ K_domainname ] = { "domainname", do_domainname, 1, COMMAND },
- [ K_exec ] = { "exec", do_exec, 1, COMMAND },
- [ K_export ] = { "export", do_export, 2, COMMAND },
- [ K_group ] = { "group", 0, 0, OPTION },
- [ K_hostname ] = { "hostname", do_hostname, 1, COMMAND },
- [ K_ifup ] = { "ifup", do_ifup, 1 COMMAND },
- [ K_insmod ] = { "insmod", do_insmod, 1, COMMAND },
- [ K_import ] = { "import", do_import, 1, COMMAND },
- [ K_keycodes ] = { "keycodes", 0, 0, OPTION },
- [ K_mkdir ] = { "mkdir", do_mkdir, 1, COMMAND },
- [ K_mount ] = { "mount", do_mount, 3, COMMAND },
- [ K_on ] = { "on", 0, 0, SECTION },///
- [ K_oneshot ] = { "oneshot", 0, 0, OPTION },
- [ K_onrestart ] = { "onrestart", 0, 0, OPTION },
- [ K_restart ] = { "restart", do_restart, 1, COMMAND },
- [ K_service ] = { "service", 0, 0, SECTION },///
- [ K_setenv ] = { "setenv", 0, 2, OPTION },
- [ K_setkey ] = { "setkey", do_setkey, 0, COMMAND },
- [ K_setprop ] = { "setprop", do_setprop, 2, COMMAND },
- [ K_setrlimit ] = { "setrlimit", do_setrlimit , 3, COMMAND },
- [ K_socket ] = { "socket", 0, 0, OPTION },
- [ K_start ] = { "start", do_start, 1, COMMAND },
- [ K_stop ] = { "stop", do_stop, 1, COMMAND },
- [ K_trigger ] = { "trigger", do_trigger, 1, COMMAND },
- [ K_symlink ] = { "symlink", do_symlink, 1, COMMAND },
- [ K_sysclktz ] = { "sysclktz", do_sysclktz, 1, COMMAND },
- [ K_user ] = { "user", 0, 0, OPTION },
- [ K_wait ] = { "wait", do_wait, 1, COMMAND },
- [ K_write ] = { "write", do_write, 2, COMMAND },
- [ K_copy ] = { "copy", do_copy, 2, COMMAND },
- [ K_chown ] = { "chown", do_chown, 2, COMMAND },
- [ K_chmod ] = { "chmod", do_chmod, 2, COMMAND },,
- [ K_loglevel ] = { "loglevel", do_loglevel, 1, COMMAND },
- [ K_ioprio ] = { "ioprio", 0, 0 OPTION },
- }
5.5.同理可以理解
- #define kw_name(kw) (keyword_info[kw].name) //根据关键词获取名字
- #define kw_func(kw) (keyword_info[kw].func) //根据关键词获取处理函数指针
- #define kw_nargs(kw) (keyword_info[kw].nargs) //根据关键词获取参数个数
6.parse_new_section
- 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类型-->三、service的处理
- state->context = parse_service(state, nargs, args); //解析service
- if (state->context) {
- state->parse_line = parse_line_service; //设置parse_line函数,处理options
- return;
- }
- break;
- case K_on: //on类型 -->四、action的处理
- state->context = parse_action(state, nargs, args); //解析action
- if (state->context) {
- state->parse_line = parse_line_action; //设置parse_line函数,处理command
- return;
- }
- break;
- }
- state->parse_line = parse_line_no_op;
- }
三、service的处理
1.相关结构体
- struct service {
- struct listnode slist;
- const char *name;
- const char *classname;
- unsigned flags;
- pid_t pid;
- time_t time_started;
- time_t time_crashed;
- int nr_crashed;
- uid_t uid;
- gid_t gid;
- gid_t supp_gids[NR_SVC_SUPP_GIDS];
- size_t nr_supp_gids;
- struct socketinfo *sockets;
- struct svcenvinfo *envvars;
- struct action onrestart;
- int *keycodes;
- int nkeycodes;
- int keychord_id;
- int ioprio_class;
- int ioprio_pri;
- int nargs;
- char *args[1];
- }
2.parse_service解析service
- static void *parse_service(struct parse_state *state, int nargs, char **args)
- {
- struct service *svc;
- if (nargs < 3) { //至少要三个service 服务名 应用程序路径
- 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
- 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); //分配service和参数内存
- if (!svc) {
- parse_error(state, "out of memory\n");
- return 0;
- }
- svc->name = args[1]; //服务名
- svc->classname = "default"; //默认设置service->classname为"default",在init.rc有一句class_start default
- memcpy(svc->args, args + 2, sizeof(char*) * nargs); //复制参数,参数中移除argc[0]和argc[1],从argc[2]复制起
- svc->args[nargs] = 0; //最后一个参数值为0表示参数结束
- svc->nargs = nargs; //设置服务的参数个数为更新后的参数个数
- svc->onrestart.name = "onrestart";
- list_init(&svc->onrestart.commands); //初始化命令链表
- list_add_tail(&service_list, &svc->slist); //添加到全局service_list链表中
- return svc;
- }
3.parse_line_service解析service的选项
- static void parse_line_service(struct parse_state *state, int nargs, char **args) //解析service的选项options
- {
- struct service *svc = state->context;
- struct command *cmd;
- int i, kw, kw_nargs;
- if (nargs == 0) { //参数个数为0直接返回
- return;
- }
- svc->ioprio_class = IoSchedClass_NONE;
- kw = lookup_keyword(args[0]); //根据参数0获取关键词(选项Options)
- switch (kw) {
- case K_capability: //capability
- break;
- case K_class: //class
- if (nargs != 2) {
- parse_error(state, "class option requires a classname\n");
- } else {
- svc->classname = args[1];
- }
- break;
- case K_console: //console
- svc->flags |= SVC_CONSOLE;
- break;
- case K_disabled: //disabled
- svc->flags |= SVC_DISABLED;
- break;
- case K_ioprio: //ioprio
- if (nargs != 3) {
- parse_error(state, "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n");
- } else {
- svc->ioprio_pri = strtoul(args[2], 0, 8);
- if (svc->ioprio_pri < 0 || svc->ioprio_pri > 7) {
- parse_error(state, "priority value must be range 0 - 7\n");
- break;
- }
- if (!strcmp(args[1], "rt")) {
- svc->ioprio_class = IoSchedClass_RT;
- } else if (!strcmp(args[1], "be")) {
- svc->ioprio_class = IoSchedClass_BE;
- } else if (!strcmp(args[1], "idle")) {
- svc->ioprio_class = IoSchedClass_IDLE;
- } else {
- parse_error(state, "ioprio option usage: ioprio <rt|be|idle> <0-7>\n");
- }
- }
- break;
- case K_group: //group
- if (nargs < 2) {
- parse_error(state, "group option requires a group id\n");
- } else if (nargs > NR_SVC_SUPP_GIDS + 2) {
- parse_error(state, "group option accepts at most %d supp. groups\n",
- NR_SVC_SUPP_GIDS);
- } else {
- int n;
- svc->gid = decode_uid(args[1]);
- for (n = 2; n < nargs; n++) {
- svc->supp_gids[n-2] = decode_uid(args[n]);
- }
- svc->nr_supp_gids = n - 2;
- }
- break;
- case K_keycodes: //keycodes
- if (nargs < 2) {
- parse_error(state, "keycodes option requires atleast one keycode\n");
- }
- else {
- svc->keycodes = malloc((nargs - 1) * sizeof(svc->keycodes[0]));
- if (!svc->keycodes) {
- parse_error(state, "could not allocate keycodes\n");
- }
- else {
- svc->nkeycodes = nargs - 1;
- for (i = 1; i < nargs; i++) {
- svc->keycodes[i - 1] = atoi(args[i]);
- }
- }
- }
- break;
- case K_oneshot: //oneshot
- svc->flags |= SVC_ONESHOT;
- break;
- case K_onrestart: //onrestart
- nargs--;
- args++;
- kw = lookup_keyword(args[0]);
- if (!kw_is(kw, COMMAND)) {
- parse_error(state, "invalid command '%s'\n", args[0]);
- break;
- }
- kw_nargs = kw_nargs(kw);
- if (nargs < kw_nargs) {
- parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,kw_nargs > 2 ? "arguments" : "argument");
- break;
- }
- cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
- cmd->func = kw_func(kw);
- cmd->nargs = nargs;
- memcpy(cmd->args, args, sizeof(char*) * nargs);
- list_add_tail(&svc->onrestart.commands, &cmd->clist);
- break;
- case K_critical: //critical
- svc->flags |= SVC_CRITICAL;
- break;
- case K_setenv: //setenv
- { /* name value */
- struct svcenvinfo *ei;
- if (nargs < 2) {
- parse_error(state, "setenv option requires name and value arguments\n");
- break;
- }
- ei = calloc(1, sizeof(*ei));
- if (!ei) {
- parse_error(state, "out of memory\n");
- break;
- }
- ei->name = args[1];
- ei->value = args[2];
- ei->next = svc->envvars;
- svc->envvars = ei;
- break;
- }
- case K_socket: //socket
- {/* name type perm [ uid gid ] */
- struct socketinfo *si;
- if (nargs < 4) {
- parse_error(state, "socket option requires name, type, perm arguments\n");
- break;
- }
- if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")&& strcmp(args[2],"seqpacket")) {
- parse_error(state, "socket type must be 'dgram', 'stream' or 'seqpacket'\n");
- break;
- }
- si = calloc(1, sizeof(*si));
- if (!si) {
- parse_error(state, "out of memory\n");
- break;
- }
- si->name = args[1];
- si->type = args[2];
- si->perm = strtoul(args[3], 0, 8);
- if (nargs > 4)
- si->uid = decode_uid(args[4]);
- if (nargs > 5)
- si->gid = decode_uid(args[5]);
- si->next = svc->sockets;
- svc->sockets = si;
- break;
- }
- case K_user: //user
- if (nargs != 2) {
- parse_error(state, "user option requires a user id\n");
- }
- else {
- svc->uid = decode_uid(args[1]);
- }
- break;
- default:
- parse_error(state, "invalid option '%s'\n", args[0]);
- }
- }
四、action的处理
1.相关结构体
- struct action {
- struct listnode alist;
- struct listnode qlist;
- struct listnode tlist;
- unsigned hash;
- const char *name;
- struct listnode commands;
- struct command *current;
- };
- struct command
- {
- struct listnode clist;
- int (*func)(int nargs, char **args);
- int nargs;
- char *args[1];
- };
2.parse_action解析action
- static void *parse_action(struct parse_state *state, int nargs, char **args)
- {
- struct action *act;
- if (nargs < 2) { //on类型的参数必须为2个 args[0]=on,args[1]=触发条件[trigger]
- 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)); //分配action结构体内存
- act->name = args[1];
- list_init(&act->commands) //初始化命令链表;
- list_add_tail(&action_list, &act->alist); //添加到全局action_list链表中
- return act;
- }
3.parse_line_action解析command
- static void parse_line_action(struct parse_state* state, int nargs, char **args) //解析command
- {
- struct command *cmd;
- struct action *act = state->context;
- int (*func)(int nargs, char **args);
- int kw, n;
- if (nargs == 0) { //参数个数为0直接返回
- return;
- }
- kw = lookup_keyword(args[0]); //根据参数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->nargs = nargs; //设置参数个数
- memcpy(cmd->args, args, sizeof(char*) * nargs); //复制参数
- list_add_tail(&act->commands, &cmd->clist); //添加到state->context链表
- }
五、service和action的执行
前面分析了:init解析init.rc文件并筛选出service和action,分别设置其结构体成员并添加进各自的全局链表service_list和action_list中
接着分析下service和action的执行
在init的main函数中除了解析init.rc(init_parse_config_file("/init.rc");)
还解析了跟硬件相关的
get_hardware_name(hardware, &revision);
snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
init_parse_config_file(tmp);
解析的结果都同样保存在全局链表service_list和action_list中
接着会有以下几行函数
- 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(property_init_action, "property_init");
- queue_builtin_action(keychord_init_action, "keychord_init");
- queue_builtin_action(console_init_action, "console_init");
- queue_builtin_action(set_init_properties_action, "set_init_properties");
- action_for_each_trigger("init", action_add_queue_tail);
- action_for_each_trigger("early-fs", action_add_queue_tail);
- action_for_each_trigger("fs", action_add_queue_tail);
- action_for_each_trigger("post-fs", action_add_queue_tail);
- queue_builtin_action(property_service_init_action, "property_service_init");
- queue_builtin_action(signal_init_action, "signal_init");
- queue_builtin_action(check_startup_action, "check_startup");
- action_for_each_trigger("early-boot", action_add_queue_tail);
- action_for_each_trigger("boot", action_add_queue_tail);
- queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");
1.action_for_each_trigger
- 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) { //遍历全局action_list
- act = node_to_item(node, struct action, alist);
- if (!strcmp(act->name, trigger)) { //比较名字和trigger触发条件
- func(act); //符合触发条件,则执行action_add_queue_tail函数
- }
- }
- }
1.1 action_add_queue_tail
- void action_add_queue_tail(struct action *act)
- {
- list_add_tail(&action_queue, &act->qlist);
- }
综合上面的action_for_each_trigger函数集,可知main函数
依次处理脚本中on标志以 early-init init early-fs fs post-fs early-boot boot的trigger的action
执行action_add_queue_tail函数将action添加到全局action_queue队列链表
2.queue_builtin_action
- void queue_builtin_action(int (*func)(int nargs, char **args), char *name)
- {
- struct action *act;
- struct command *cmd;
- act = calloc(1, sizeof(*act)); //分配action内存
- act->name = name; //设置名字
- list_init(&act->commands); //初始化command链表
- cmd = calloc(1, sizeof(*cmd)); //分配command
- cmd->func = func; //设置执行函数为传递的第一个参数
- cmd->args[0] = name; //设置command的参数0
- list_add_tail(&act->commands, &cmd->clist); //添加command到action的commands链表中
- list_add_tail(&action_list, &act->alist); //添加action到全局action_list链表中
- action_add_queue_tail(act); //添加action到全局action_queue队列链表
- }
创建以name标记的action,并添加进全局action_list中,同时添加进action_queue队列链表
所以全局action_queue队列链表中的顺序调整为
early-init [wait_for_coldboot_done] [property_init] [keychord_init] [console_init] [set_init_properties]
init early-fs fs post-fs [property_service_init] [signal_init] [check_startup] early-boot boot [queue_propety_triggers]
接着进入main的for(;;)循环体
3.execute_one_command执行一个command
- void execute_one_command(void)
- {
- int ret;
- //第一次执行cur_action为0,执行完某个action下的所有command后cur_command为0,条件为真
- if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
- cur_action = action_remove_queue_head(); //获取下一个action
- cur_command = NULL;
- if (!cur_action)
- return;
- INFO("processing action %p (%s)\n", cur_action, cur_action->name);
- cur_command = get_first_command(cur_action); //获取action的第一个command
- }
- else { //循环执行某个action下的所有command
- cur_command = get_next_command(cur_action, cur_command); //获取action的下一个command
- }
- if (!cur_command) //没有command可取了,则cur_command=0
- return; //返回
- ret = cur_command->func(cur_command->nargs, cur_command->args); //执行command的处理函数
- INFO("command '%s' r=%d\n", cur_command->args[0], ret);
- }
因为execute_one_command套在for(;;)中所以会循环执行action_queue队列链表下的action的command
4.service_list下的服务的执行
4.1service由service_start启动
搜索代码遍历调用service_start的分支:
- KEYWORD(class_start, COMMAND, 1, do_class_start)
- do_class_start->service_for_each_class->service_start_if_not_disabled->service_start
- KEYWORD(start, COMMAND, 1, do_start)
- do_start->service_start
- KEYWORD(restart, COMMAND, 1, do_restart)
- do_restart->service_start
- main[for(;;)]->restart_processes->service_for_each_flags->restart_service_if_needed->service_start
- main[for(;;)]->handle_property_set_fd->handle_control_message->msg_start->service_start
- main[for(;;)]->handle_keychord->service_start
前三个分支是由处理command是调用的处理函数do_XXX调用的,也就是execute_one_command函数的处理过程会调用到
后三个分支是在init的main函数的循环体中调用
在init.rc中有一句class_start default
作为class_start命令在处理时会调用到do_class_start
- int do_class_start(int nargs, char **args) //argc[1]=default
- {
- service_for_each_class(args[1], service_start_if_not_disabled);
- return 0;
- }
service_for_each_class根据class类名查找service
- 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) { //遍历全局service_list
- svc = node_to_item(node, struct service, slist);
- if (!strcmp(svc->classname, classname)) { //在前面parse_service函数中,将svc->classname = "default",所以为真
- func(svc); //调用service_start_if_not_disabled
- }
- }
- }
service_start_if_not_disabled启动没有禁止启动的service
- static void service_start_if_not_disabled(struct service *svc)
- {
- if (!(svc->flags & SVC_DISABLED)) { //若没设置SVC_DISABLED标志,也就是init.rc中对应的service的options没有disabled
- service_start(svc, NULL); //则会启动服务
- }
- }
到这里重要的正规的service就已经启动了
5.service_start的简单解析
- void service_start(struct service *svc, const char *dynamic_args)
- {
- struct stat s;
- pid_t pid;
- int needs_console;
- int n;
- svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING)); //去掉禁用和重启标志
- svc->time_started = 0;
- if (svc->flags & SVC_RUNNING) { //若已经运行了,则直接返回
- return;
- }
- needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0; //需要console
- if (needs_console && (!have_console)) { //需要但没有console
- ERROR("service '%s' requires console\n", svc->name);
- svc->flags |= SVC_DISABLED;
- return;
- }
- if (stat(svc->args[0], &s) != 0) {
- ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);
- svc->flags |= SVC_DISABLED;
- return;
- }
- if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) { //没one-shot标志但使用了动态参数
- ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",svc->args[0]);
- svc->flags |= SVC_DISABLED;
- return;
- }
- NOTICE("starting '%s'\n", svc->name); //打印信息
- pid = fork(); //创建进程
- if (pid == 0) { //子进程
- struct socketinfo *si;
- struct svcenvinfo *ei;
- char tmp[32];
- int fd, sz;
- if (properties_inited()) {
- get_property_workspace(&fd, &sz);
- sprintf(tmp, "%d,%d", dup(fd), sz);
- add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
- }
- for (ei = svc->envvars; ei; ei = ei->next)
- add_environment(ei->name, ei->value);
- for (si = svc->sockets; si; si = si->next) {
- int socket_type = (!strcmp(si->type, "stream") ? SOCK_STREAM :(!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
- int s = create_socket(si->name, socket_type,si->perm, si->uid, si->gid);
- if (s >= 0) {
- publish_socket(si->name, s);
- }
- }
- if (svc->ioprio_class != IoSchedClass_NONE) {
- if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
- ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",getpid(), svc->ioprio_class, svc->ioprio_pri, strerror(errno));
- }
- }
- if (needs_console) { //需要控制台
- setsid();
- open_console(); //打开控制台
- } else {
- zap_stdio();
- }
- setpgid(0, getpid());
- if (svc->gid) {
- setgid(svc->gid);
- }
- if (svc->nr_supp_gids) {
- setgroups(svc->nr_supp_gids, svc->supp_gids);
- }
- if (svc->uid) {
- setuid(svc->uid);
- }
- if (!dynamic_args) {
- if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {//service 路径参数对应的应用程序
- ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
- }
- }
- else {
- char *arg_ptrs[INIT_PARSER_MAXARGS+1];
- int arg_idx = svc->nargs;
- char *tmp = strdup(dynamic_args);
- char *next = tmp;
- char *bword;
- /* Copy the static arguments */
- memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));
- while((bword = strsep(&next, " "))) {
- arg_ptrs[arg_idx++] = bword;
- if (arg_idx == INIT_PARSER_MAXARGS)
- break;
- }
- arg_ptrs[arg_idx] = '\0';
- execve(svc->args[0], (char**) arg_ptrs, (char**) ENV); //service 路径参数对应的应用程序
- }
- _exit(127);
- }
- if (pid < 0) {
- ERROR("failed to start '%s'\n", svc->name);
- svc->pid = 0;
- return;
- }
- svc->time_started = gettime(); //记录service启动时间
- svc->pid = pid; //记录service的pid号
- svc->flags |= SVC_RUNNING; //添加已运行标志SVC_RUNNING
- if (properties_inited())
- notify_service_state(svc->name, "running");
- }
这里execve(svc->args[0], (char**) arg_ptrs, (char**) ENV)中args[0]是init.rc中service <name> <pathname> [ <argument> ]*的<pathname>,
arg_ptrs指向[ <argument> ]*
例如:service servicemanager /system/bin/servicemanager就会执行execve(/system/bin/servicemanager,...........)