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是如何启动的?这些问题将在下一篇文章进行介绍。












0 0
原创粉丝点击