android源码系列:init分析1
来源:互联网 发布:maxwell 3d软件 编辑:程序博客网 时间:2024/04/29 22:00
android4.0_src\system\core\init\init.c
android4.0_src\system\core\rootdir\init.rc
android4.0_src\system\core\init\init_parser.c
在分析init进程前,先看下在init_parser.c文件中有如下一段代码:
-----------------------
#include "keywords.h"
#define KEYWORD(symbol, flags, nargs, func) \
[ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
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"
};
#undef KEYWORD
------------------------
在这段代码中,两次包含头文件keywords.h,在keywords.h头文件中将根据是否定义宏KEYWORD来包含不同部分。这里有个地方需要注意,#和##在宏定义中的使用,
#:在宏展开的时候会将#后面的参数替换成字符串;##:将前后两个的单词拼接在一起,作为一个符号使用,这个符号必须先声明过。在第一次包含keywords.h头文件
时没有定义宏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_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(int nargs, char **args);
int do_restart(int nargs, char **args);
int do_rm(int nargs, char **args);
int do_rmdir(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_load_persist_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,
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(class_reset, COMMAND, 1, do_class_reset)
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, SECTION, 1, 0)
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(rm, COMMAND, 1, do_rm)
KEYWORD(rmdir, COMMAND, 1, do_rmdir)
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(load_persist_props, COMMAND, 0, do_load_persist_props)
KEYWORD(ioprio, OPTION, 0, 0)
KEYWORD_COUNT,
};
#undef __MAKE_KEYWORD_ENUM__
#undef KEYWORD
#define KEYWORD(symbol, flags, nargs, func) \
[ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
而在第二次包含keyword.h头文件时,已经定义了宏KEYWORD,所以包含的部分如下:
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 },
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(class_reset, COMMAND, 1, do_class_reset)
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, SECTION, 1, 0)
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(rm, COMMAND, 1, do_rm)
KEYWORD(rmdir, COMMAND, 1, do_rmdir)
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(load_persist_props, COMMAND, 0, do_load_persist_props)
KEYWORD(ioprio, OPTION, 0, 0)
};
#undef KEYWORD
从上面可以看出宏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_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(int nargs, char **args);
int do_restart(int nargs, char **args);
int do_rm(int nargs, char **args);
int do_rmdir(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_load_persist_props(int nargs, char **args);
int do_wait(int nargs, char **args);
enum {
K_UNKNOWN,
K_capability,
K_chdir,
K_chroot,
K_class,
K_class_start,
K_class_stop,
K_class_reset,
K_console,
K_critical,
K_disabled,
K_domainname,
K_exec,
K_export,
K_group,
K_hostname,
K_ifup,
K_insmod,
K_import,
K_keycodes,
K_mkdir,
K_mount,
K_on,
K_oneshot,
K_onrestart,
K_restart,
K_rm,
K_rmdir,
K_service,
K_setenv,
K_setkey,
K_setprop,
K_setrlimit,
K_socket,
K_start,
K_stop,
K_trigger,
K_symlink,
K_sysclktz,
K_user,
K_wait,
K_write,
K_copy,
K_chown,
K_chmod,
K_loglevel,
K_load_persist_props,
K_ioprio,
KEYWORD_COUNT,
};
#define KEYWORD(symbol, flags, nargs, func) \
[ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
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, 1, OPTION, },
[ K_chdir ] = { "chdir", do_chdir, 2, COMMAND, },
[ K_chroot ] = { "chroot", do_chroot, 2, COMMAND, },
[ K_class ] = { "class", 0, 1, OPTION, },
[ K_class_start ] = { "class_start", do_class_start, 2, COMMAND, },
[ K_class_stop ] = { "class_stop", do_class_stop, 2, COMMAND, },
[ K_class_reset ] = { "class_reset", do_class_reset, 2, COMMAND, },
[ K_console ] = { "console", 0, 1, OPTION, },
[ K_critical ] = { "critical", 0, 1, OPTION, },
[ K_disabled ] = { "disabled", 0, 1, OPTION, },
[ K_domainname ] = { "domainname", do_domainname, 2, COMMAND, },
[ K_exec ] = { "exec", do_exec, 2, COMMAND, },
[ K_export ] = { "export", do_export, 3, COMMAND, },
[ K_group ] = { "group", 0, 1, OPTION, },
[ K_hostname ] = { "hostname", do_hostname, 2, COMMAND, },
[ K_ifup ] = { "ifup", do_ifup, 2, COMMAND, },
[ K_insmod ] = { "insmod", do_insmod, 2, COMMAND, },
[ K_import ] = { "import", 0, 2, SECTION, },
[ K_keycodes ] = { "keycodes", 0, 1, OPTION, },
[ K_mkdir ] = { "mkdir", do_mkdir, 2, COMMAND, },
[ K_insmod ] = { "insmod", do_insmod, 2, COMMAND, },
[ K_mount ] = { "mount", do_mount, 4, COMMAND, },
[ K_on ] = { "on", 0, 1, SECTION, },
[ K_oneshot ] = { "oneshot", 0, 1, OPTION, },
[ K_onrestart ] = { "onrestart", 0, 1, OPTION, },
[ K_restart ] = { "restart", do_restart, 2, COMMAND, },
[ K_rm ] = { "rm", do_rm, 2, COMMAND, },
[ K_rmdir ] = { "rmdir", do_rmdir, 2, COMMAND, },
[ K_service ] = { "service", 0, 1, SECTION, },
[ K_setenv ] = { "setenv", 0, 3, OPTION, },
[ K_setkey ] = { "setkey", do_setkey, 1, COMMAND, },
[ K_setprop ] = { "setprop", do_setprop, 3, COMMAND, },
[ K_setrlimit ] = { "setrlimit", do_setrlimit, 4, COMMAND, },
[ K_socket ] = { "socket", 0, 1, OPTION, },
[ K_start ] = { "start", do_start, 2, COMMAND, },
[ K_stop ] = { "stop", do_stop, 2, COMMAND, },
[ K_trigger ] = { "trigger", do_trigger, 2, COMMAND, },
[ K_symlink ] = { "symlink", do_symlink, 2, COMMAND, },
[ K_sysclktz ] = { "sysclktz", do_sysclktz, 2, COMMAND, },
[ K_user ] = { "user", 0, 1, OPTION, },
[ K_wait ] = { "wait", do_wait, 2, COMMAND, },
[ K_write ] = { "write", do_write, 3, COMMAND, },
[ K_copy ] = { "copy", do_copy, 3, COMMAND, },
[ K_chown ] = { "chown", do_chown, 3, COMMAND, },
[ K_chmod ] = { "chmod", do_chmod, 3, COMMAND, },
[ K_loglevel ] = { "loglevel", do_loglevel, 2, COMMAND, },
[ K_load_persist_props ] = { "load_persist_props", do_load_persist_props, 1, COMMAND, },
[ K_ioprio ] = { "ioprio", 0, 1, OPTION, },
};
这个结构体会在解析配置文件时会用到,后面分析代码会看到。
下面开始分析init进程的代码:
首先,分析解析配置文件函数init_parse_config_file(),在讲解之前先看几个结构体:
struct action {
struct listnode alist; /* node in list of all actions *///list_add_tail(&action_list, &act->alist);
struct listnode qlist; /* node in the queue of pending actions */
struct listnode tlist; /* node in list of actions for a trigger */
unsigned hash;
const char *name; //act->name = args[1];
struct listnode commands; //list_init(&act->commands);
struct command *current;
};
struct service {
struct listnode slist; //list_add_tail(&service_list, &svc->slist);
const char *name; //svc->name = args[1];
const char *classname; //svc->classname = "default";
unsigned flags;
pid_t pid;
time_t time_started; /* time of last start */
time_t time_crashed; /* first crash within inspection window */
int nr_crashed; /* number of times crashed within window */
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; //svc->onrestart.name = "onrestart";
/* keycodes for triggering this service via /dev/keychord */
int *keycodes;
int nkeycodes;
int keychord_id;
int ioprio_class;
int ioprio_pri;
int nargs;
char *args[1]; //nargs -= 2;memcpy(svc->args, args + 2, sizeof(char*) * nargs); svc->args[nargs] = 0; svc->nargs = nargs;
};
struct command
{
struct listnode clist; //list_add_tail(&act->commands, &cmd->clist);
int (*func)(int nargs, char **args); //cmd->func = kw_func(kw);#define kw_func(kw) (keyword_info[kw].func)
int nargs; //cmd->nargs = nargs;
char *args[1]; //memcpy(cmd->args, args, sizeof(char*) * nargs);
};
这几个数据结构就是用来存储解析配置文件时的信息,从keyword_info数组中可以看出,配置文件主要包含SECTION、COMMAND和OPTION三类信息,而SECTION又分为
import、service和on三种类型,其中on使用action结构体表示,service使用service结构体表示,而import则是导入其他的文件,而COMMAND和OPTION又是依附在
service和on类型上的。配置文件中存在多个on和service,因此就对应有多个action结构体和service结构体,而这些结构体分别保存在action_list和service_list
两个双向链表中,在init_parser.c文件中,定义了三个双向链表:
static list_declare(service_list);
static list_declare(action_list);
static list_declare(action_queue);
下面看具体的解析函数:
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 = 0;
state.ptr = s;
state.nexttoken = 0;
state.parse_line = parse_line_no_op;
for (;;) {
switch (next_token(&state)) {
case T_EOF:
state.parse_line(&state, 0, 0);
return;
case T_NEWLINE:
state.line++;
if (nargs) {
int kw = lookup_keyword(args[0]);
if (kw_is(kw, 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;
}
}
}
next_token()函数主要每遇到分隔符就返回T_TEXT,这样就把前面解析的字符保存在args数组中,当遇到换行符时就返回T_NEWLINE,这时才分析第一个参数,
看是属于哪种类型,这里就用到了前面提到的keyword_info数组,首先通过lookup_keyword获取参数对应的索引值,再用这个索引值在keyword_info数组获取
相应元素,再判断是否是SECTION类型,如果是就调用parse_new_section函数:
void parse_new_section(struct parse_state *state, int kw, int nargs, char **args)
{
switch(kw) {
case K_service:
state->context = parse_service(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_service;
return;
}
break;
case K_on:
state->context = parse_action(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_action;
return;
}
break;
case K_import:
.......
}
state->parse_line = parse_line_no_op;
}
这个函数很简单,如果是service就调用parse_service,如果是on就调用parse_action,这里要注意的是对state->parse_line的赋值,因为上面parse_config函数中
当不是SECTION类型时就会调用state->parse_line函数,所以如果是on就会调用parse_line_action函数,如果是service就会调用parse_line_service。从这里可以
看出,解析配置文件主要是围绕on和service进行的,当遇到on时就会通过parse_action函数构建一个action结构体,并把相应的信息填充到这个结构体中,而on所在行
下面的行就通过parse_line_action函数每行相应构建一个command结构体,并把相应信息填充到这个结构体中,而且这个command结构体会被添加到前面那个action结构体
的commands链表中去list_add_tail(&act->commands, &cmd->clist);这样直到遇到on或service。当遇到service时就会通过parse_service函数构建一个service结构体,
service下面的行就通过parse_line_service函数进行解析,parse_line_service函数比parse_line_action稍微复杂点,会根据类型的不同做相应的处理,主要是填充
service结构体的信息或者像parse_line_action构建command,具体情况请分析parse_line_service函数。这样配置文件中信息就以action和servcie结构体分别保存在
action_list和service_list链表中。为了更形象的说明解析过程,下面举例说明:
service ueventd /sbin/ueventd //service{name:ueventd, classname:default, nargs:1, args:[/sbin/ueventd], onrestart.name:onrestart}
class core //service->classname = core;
critical //service->flags |= SVC_CRITICAL;
console //service->flags |= SVC_CONSOLE;
disabled //service->flags |= SVC_DISABLED;service->flags |= SVC_RC_DISABLED;
user shell //service->uid = decode_uid(args[1]);
group log /service->gid = decode_uid(args[1]);
socket vold stream 0660 root mount //socketinfo{name:vold, type:stream, perm:0660, uid:root, gid:mount}
ioprio be 2 //service->ioprio_class = IoSchedClass_BE;
oneshot //service->flags |= SVC_ONESHOT;
onrestart restart zygote //command{func:do_restart,nargs:2,args:[restart,zygote]}
onrestart restart media //command{func:do_restart,nargs:2,args:[restart,media]}
parse_config函数遇到这个service时,就会解析出下面信息:
int nargs = 3;
char **args = {{"service"}, {"ueventd"}, {"/sbin/ueventd"}};
接着就会调用parse_new_section函数,而最终调用parse_service函数,从而解析出如上右边service结构体,此时state->parse_line赋值为parse_line_service,因此
从class core开始每行都使用parse_line_service进行解析,具体的解析行为可参考右边的注释。
从上面可以看出,action里面有个commands链表,这个链表保存了属于该action的所有命令,这些命令肯定是要被执行的,而在init进程中action是要在action_queue中才会被
执行的,所有接下来就看action是怎样被添加到action_queue中的?以及service是如何启动的?这些问题将在下一篇文章进行介绍。
android4.0_src\system\core\rootdir\init.rc
android4.0_src\system\core\init\init_parser.c
在分析init进程前,先看下在init_parser.c文件中有如下一段代码:
-----------------------
#include "keywords.h"
#define KEYWORD(symbol, flags, nargs, func) \
[ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
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"
};
#undef KEYWORD
------------------------
在这段代码中,两次包含头文件keywords.h,在keywords.h头文件中将根据是否定义宏KEYWORD来包含不同部分。这里有个地方需要注意,#和##在宏定义中的使用,
#:在宏展开的时候会将#后面的参数替换成字符串;##:将前后两个的单词拼接在一起,作为一个符号使用,这个符号必须先声明过。在第一次包含keywords.h头文件
时没有定义宏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_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(int nargs, char **args);
int do_restart(int nargs, char **args);
int do_rm(int nargs, char **args);
int do_rmdir(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_load_persist_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,
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(class_reset, COMMAND, 1, do_class_reset)
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, SECTION, 1, 0)
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(rm, COMMAND, 1, do_rm)
KEYWORD(rmdir, COMMAND, 1, do_rmdir)
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(load_persist_props, COMMAND, 0, do_load_persist_props)
KEYWORD(ioprio, OPTION, 0, 0)
KEYWORD_COUNT,
};
#undef __MAKE_KEYWORD_ENUM__
#undef KEYWORD
#define KEYWORD(symbol, flags, nargs, func) \
[ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
而在第二次包含keyword.h头文件时,已经定义了宏KEYWORD,所以包含的部分如下:
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 },
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(class_reset, COMMAND, 1, do_class_reset)
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, SECTION, 1, 0)
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(rm, COMMAND, 1, do_rm)
KEYWORD(rmdir, COMMAND, 1, do_rmdir)
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(load_persist_props, COMMAND, 0, do_load_persist_props)
KEYWORD(ioprio, OPTION, 0, 0)
};
#undef KEYWORD
从上面可以看出宏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_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(int nargs, char **args);
int do_restart(int nargs, char **args);
int do_rm(int nargs, char **args);
int do_rmdir(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_load_persist_props(int nargs, char **args);
int do_wait(int nargs, char **args);
enum {
K_UNKNOWN,
K_capability,
K_chdir,
K_chroot,
K_class,
K_class_start,
K_class_stop,
K_class_reset,
K_console,
K_critical,
K_disabled,
K_domainname,
K_exec,
K_export,
K_group,
K_hostname,
K_ifup,
K_insmod,
K_import,
K_keycodes,
K_mkdir,
K_mount,
K_on,
K_oneshot,
K_onrestart,
K_restart,
K_rm,
K_rmdir,
K_service,
K_setenv,
K_setkey,
K_setprop,
K_setrlimit,
K_socket,
K_start,
K_stop,
K_trigger,
K_symlink,
K_sysclktz,
K_user,
K_wait,
K_write,
K_copy,
K_chown,
K_chmod,
K_loglevel,
K_load_persist_props,
K_ioprio,
KEYWORD_COUNT,
};
#define KEYWORD(symbol, flags, nargs, func) \
[ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
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, 1, OPTION, },
[ K_chdir ] = { "chdir", do_chdir, 2, COMMAND, },
[ K_chroot ] = { "chroot", do_chroot, 2, COMMAND, },
[ K_class ] = { "class", 0, 1, OPTION, },
[ K_class_start ] = { "class_start", do_class_start, 2, COMMAND, },
[ K_class_stop ] = { "class_stop", do_class_stop, 2, COMMAND, },
[ K_class_reset ] = { "class_reset", do_class_reset, 2, COMMAND, },
[ K_console ] = { "console", 0, 1, OPTION, },
[ K_critical ] = { "critical", 0, 1, OPTION, },
[ K_disabled ] = { "disabled", 0, 1, OPTION, },
[ K_domainname ] = { "domainname", do_domainname, 2, COMMAND, },
[ K_exec ] = { "exec", do_exec, 2, COMMAND, },
[ K_export ] = { "export", do_export, 3, COMMAND, },
[ K_group ] = { "group", 0, 1, OPTION, },
[ K_hostname ] = { "hostname", do_hostname, 2, COMMAND, },
[ K_ifup ] = { "ifup", do_ifup, 2, COMMAND, },
[ K_insmod ] = { "insmod", do_insmod, 2, COMMAND, },
[ K_import ] = { "import", 0, 2, SECTION, },
[ K_keycodes ] = { "keycodes", 0, 1, OPTION, },
[ K_mkdir ] = { "mkdir", do_mkdir, 2, COMMAND, },
[ K_insmod ] = { "insmod", do_insmod, 2, COMMAND, },
[ K_mount ] = { "mount", do_mount, 4, COMMAND, },
[ K_on ] = { "on", 0, 1, SECTION, },
[ K_oneshot ] = { "oneshot", 0, 1, OPTION, },
[ K_onrestart ] = { "onrestart", 0, 1, OPTION, },
[ K_restart ] = { "restart", do_restart, 2, COMMAND, },
[ K_rm ] = { "rm", do_rm, 2, COMMAND, },
[ K_rmdir ] = { "rmdir", do_rmdir, 2, COMMAND, },
[ K_service ] = { "service", 0, 1, SECTION, },
[ K_setenv ] = { "setenv", 0, 3, OPTION, },
[ K_setkey ] = { "setkey", do_setkey, 1, COMMAND, },
[ K_setprop ] = { "setprop", do_setprop, 3, COMMAND, },
[ K_setrlimit ] = { "setrlimit", do_setrlimit, 4, COMMAND, },
[ K_socket ] = { "socket", 0, 1, OPTION, },
[ K_start ] = { "start", do_start, 2, COMMAND, },
[ K_stop ] = { "stop", do_stop, 2, COMMAND, },
[ K_trigger ] = { "trigger", do_trigger, 2, COMMAND, },
[ K_symlink ] = { "symlink", do_symlink, 2, COMMAND, },
[ K_sysclktz ] = { "sysclktz", do_sysclktz, 2, COMMAND, },
[ K_user ] = { "user", 0, 1, OPTION, },
[ K_wait ] = { "wait", do_wait, 2, COMMAND, },
[ K_write ] = { "write", do_write, 3, COMMAND, },
[ K_copy ] = { "copy", do_copy, 3, COMMAND, },
[ K_chown ] = { "chown", do_chown, 3, COMMAND, },
[ K_chmod ] = { "chmod", do_chmod, 3, COMMAND, },
[ K_loglevel ] = { "loglevel", do_loglevel, 2, COMMAND, },
[ K_load_persist_props ] = { "load_persist_props", do_load_persist_props, 1, COMMAND, },
[ K_ioprio ] = { "ioprio", 0, 1, OPTION, },
};
这个结构体会在解析配置文件时会用到,后面分析代码会看到。
下面开始分析init进程的代码:
首先,分析解析配置文件函数init_parse_config_file(),在讲解之前先看几个结构体:
struct action {
struct listnode alist; /* node in list of all actions *///list_add_tail(&action_list, &act->alist);
struct listnode qlist; /* node in the queue of pending actions */
struct listnode tlist; /* node in list of actions for a trigger */
unsigned hash;
const char *name; //act->name = args[1];
struct listnode commands; //list_init(&act->commands);
struct command *current;
};
struct service {
struct listnode slist; //list_add_tail(&service_list, &svc->slist);
const char *name; //svc->name = args[1];
const char *classname; //svc->classname = "default";
unsigned flags;
pid_t pid;
time_t time_started; /* time of last start */
time_t time_crashed; /* first crash within inspection window */
int nr_crashed; /* number of times crashed within window */
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; //svc->onrestart.name = "onrestart";
/* keycodes for triggering this service via /dev/keychord */
int *keycodes;
int nkeycodes;
int keychord_id;
int ioprio_class;
int ioprio_pri;
int nargs;
char *args[1]; //nargs -= 2;memcpy(svc->args, args + 2, sizeof(char*) * nargs); svc->args[nargs] = 0; svc->nargs = nargs;
};
struct command
{
struct listnode clist; //list_add_tail(&act->commands, &cmd->clist);
int (*func)(int nargs, char **args); //cmd->func = kw_func(kw);#define kw_func(kw) (keyword_info[kw].func)
int nargs; //cmd->nargs = nargs;
char *args[1]; //memcpy(cmd->args, args, sizeof(char*) * nargs);
};
这几个数据结构就是用来存储解析配置文件时的信息,从keyword_info数组中可以看出,配置文件主要包含SECTION、COMMAND和OPTION三类信息,而SECTION又分为
import、service和on三种类型,其中on使用action结构体表示,service使用service结构体表示,而import则是导入其他的文件,而COMMAND和OPTION又是依附在
service和on类型上的。配置文件中存在多个on和service,因此就对应有多个action结构体和service结构体,而这些结构体分别保存在action_list和service_list
两个双向链表中,在init_parser.c文件中,定义了三个双向链表:
static list_declare(service_list);
static list_declare(action_list);
static list_declare(action_queue);
下面看具体的解析函数:
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 = 0;
state.ptr = s;
state.nexttoken = 0;
state.parse_line = parse_line_no_op;
for (;;) {
switch (next_token(&state)) {
case T_EOF:
state.parse_line(&state, 0, 0);
return;
case T_NEWLINE:
state.line++;
if (nargs) {
int kw = lookup_keyword(args[0]);
if (kw_is(kw, 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;
}
}
}
next_token()函数主要每遇到分隔符就返回T_TEXT,这样就把前面解析的字符保存在args数组中,当遇到换行符时就返回T_NEWLINE,这时才分析第一个参数,
看是属于哪种类型,这里就用到了前面提到的keyword_info数组,首先通过lookup_keyword获取参数对应的索引值,再用这个索引值在keyword_info数组获取
相应元素,再判断是否是SECTION类型,如果是就调用parse_new_section函数:
void parse_new_section(struct parse_state *state, int kw, int nargs, char **args)
{
switch(kw) {
case K_service:
state->context = parse_service(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_service;
return;
}
break;
case K_on:
state->context = parse_action(state, nargs, args);
if (state->context) {
state->parse_line = parse_line_action;
return;
}
break;
case K_import:
.......
}
state->parse_line = parse_line_no_op;
}
这个函数很简单,如果是service就调用parse_service,如果是on就调用parse_action,这里要注意的是对state->parse_line的赋值,因为上面parse_config函数中
当不是SECTION类型时就会调用state->parse_line函数,所以如果是on就会调用parse_line_action函数,如果是service就会调用parse_line_service。从这里可以
看出,解析配置文件主要是围绕on和service进行的,当遇到on时就会通过parse_action函数构建一个action结构体,并把相应的信息填充到这个结构体中,而on所在行
下面的行就通过parse_line_action函数每行相应构建一个command结构体,并把相应信息填充到这个结构体中,而且这个command结构体会被添加到前面那个action结构体
的commands链表中去list_add_tail(&act->commands, &cmd->clist);这样直到遇到on或service。当遇到service时就会通过parse_service函数构建一个service结构体,
service下面的行就通过parse_line_service函数进行解析,parse_line_service函数比parse_line_action稍微复杂点,会根据类型的不同做相应的处理,主要是填充
service结构体的信息或者像parse_line_action构建command,具体情况请分析parse_line_service函数。这样配置文件中信息就以action和servcie结构体分别保存在
action_list和service_list链表中。为了更形象的说明解析过程,下面举例说明:
service ueventd /sbin/ueventd //service{name:ueventd, classname:default, nargs:1, args:[/sbin/ueventd], onrestart.name:onrestart}
class core //service->classname = core;
critical //service->flags |= SVC_CRITICAL;
console //service->flags |= SVC_CONSOLE;
disabled //service->flags |= SVC_DISABLED;service->flags |= SVC_RC_DISABLED;
user shell //service->uid = decode_uid(args[1]);
group log /service->gid = decode_uid(args[1]);
socket vold stream 0660 root mount //socketinfo{name:vold, type:stream, perm:0660, uid:root, gid:mount}
ioprio be 2 //service->ioprio_class = IoSchedClass_BE;
oneshot //service->flags |= SVC_ONESHOT;
onrestart restart zygote //command{func:do_restart,nargs:2,args:[restart,zygote]}
onrestart restart media //command{func:do_restart,nargs:2,args:[restart,media]}
parse_config函数遇到这个service时,就会解析出下面信息:
int nargs = 3;
char **args = {{"service"}, {"ueventd"}, {"/sbin/ueventd"}};
接着就会调用parse_new_section函数,而最终调用parse_service函数,从而解析出如上右边service结构体,此时state->parse_line赋值为parse_line_service,因此
从class core开始每行都使用parse_line_service进行解析,具体的解析行为可参考右边的注释。
从上面可以看出,action里面有个commands链表,这个链表保存了属于该action的所有命令,这些命令肯定是要被执行的,而在init进程中action是要在action_queue中才会被
执行的,所有接下来就看action是怎样被添加到action_queue中的?以及service是如何启动的?这些问题将在下一篇文章进行介绍。
0 0
- android源码系列:init分析1
- android源码系列:init分析2
- android源码系列:init分析3
- Android Init进程源码分析
- Android Init进程源码分析
- Android Init进程源码分析
- Android Init进程源码分析
- Android Init进程源码分析
- Android Init进程源码分析
- Android Init进程源码分析
- Android init 进程源码分析
- Android 源码分析之 init 分析
- 【Android7.1.2源码解析系列】android init目录下的Android.mk编译文件分析
- Android init进程——源码分析
- Android源码系列分析
- 【Android7.1.2源码解析系列】实战分析init.rc文件
- Android3.1 init进程启动源码分析
- jquery 源码分析-核心(1)初始化init
- JavaScript 之 图片滚动实例分析
- 博客
- poj1088
- Struts2使用之值栈与OGNL-概述
- jquery的html,text,val
- android源码系列:init分析1
- 实现复数类中的运算符重载(找朋友)
- 数据库启动/关闭原理
- 字节流与字符流
- objcopy转换elf文件为bin文件
- poj 1004 Financial Management
- 通过协议分析理解端口扫描原理
- POJ 2185 Milking Grid
- poj1111