当前位置: 代码迷 >> Android >> 【android】依据init.rc启动action和service
  详细解决方案

【android】依据init.rc启动action和service

热度:19   发布时间:2016-05-01 10:55:16.0
【android】根据init.rc启动action和service

一、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选项

criticaldisabledsetenv <name> <value>socket <name> <type> <perm> [ <user> [ <group> ] ]user <username>group <groupname> [ <groupname> ]*oneshotclass <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 KEYWORDint 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_startKEYWORD(start,       COMMAND, 1, do_start)do_start->service_startKEYWORD(restart,     COMMAND, 1, do_restart)do_restart->service_startmain[for(;;)]->restart_processes->service_for_each_flags->restart_service_if_needed->service_startmain[for(;;)]->handle_property_set_fd->handle_control_message->msg_start->service_startmain[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,...........)











 

 

  相关解决方案