AndroidInitProcess分析心得(2)

print?//\system\core\init\init_parser.c  
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, "lass_reset")) return K_class_reset; 
        //……  
    } 
    return K_UNKNOWN; 

//\system\core\init\init_parser.c
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, "lass_reset")) return K_class_reset;
        //……
    }
    return K_UNKNOWN;
}
由此段程序代碼可以發現此函數會根據存入的字符串先由字符串的第一個字符做分類, 再去比較之後的字符去回傳相對應的K_xxx.之後再將keyword傳入kw_is作判斷,Google在這裡的判斷設計kw_is會利用macro而不是用一般的函數去實作, 一是因為這個判斷動作隻有單純的做比對,另外一點就是會少一次functioncall stack的效能以加快執行速度.

[cpp]
//system\core\init\init_parser.c  
#define kw_is(kw, type) (keyword_info[kw].flags & (type)) 

//system\core\init\init_parser.c
#define kw_is(kw, type) (keyword_info[kw].flags & (type))

這裡會發現是用keyword_info數組中的元素所帶出來的flags跟type作&比較.

[cpp]
//system\core\init\init_parser.c  
#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"  
}; 
 
//system\core\init\keywords.h  
//…  
    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) 
//…. 

//system\core\init\init_parser.c
#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"
};

//system\core\init\keywords.h
//…
    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_info是一個Mappingtable. 每一個lookup_keyword 函數所回傳的keyword K_xxx對應一個函數do_xxx.

        因此便可以再從parse_config函數中的呼叫lookup_keyword繼續分析下去.

[cpp]
// system\core\init\init_parser.c  
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); 

// system\core\init\init_parser.c
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);
}
由之前針對lookup_keyword和kw_is的分析就可以知道, 這裡是要從init.rc中撈出keyword再利用kw_is的判斷來做不同parser方式. 由上面的程序代碼可以知道, 隻有在keyword_infomapping table中有SECTION flag, 才會有新的list. 而在(android4.2)目前的版本中從keywords.h所有的KEYWORD可知道, 有SECTIONflag對應到的字符隻有import, on, service. 撇開import字符是用來作類似include的動作之外,on跟service就是用來建立之前所提的actionlist和service list. 接下來分析parse_new_section函數

[cpp]
//system\core\init\init_parser.c  
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: 
        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: 
        parse_import(state, nargs, args); 
        break; 
    } 
    state->parse_line = parse_line_no_op; 

//system\core\init\init_parser.c
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:
        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:
        parse_import(state, nargs, args);
        break;
    }
    state->parse_line = parse_line_no_op;
}

 

由於在執行流程分析中, execute_one_command函數就隻有用來執行action list上面的command,所以就從parse_action函數來分析.

[cpp]
//system\core\init\init_parser.c  
static void *parse_action(struct parse_state *state, int nargs, char **args) 

    struct action *act; 
    if (nargs < 2) { 
        parse_error(state, "actions must have a trigger\n"); 
        return 0; 
    } 
    if (nargs > 2) { 
        parse_error(state, "actions may not have extra parameters\n"); 
        return 0; 
    } 
    act = calloc(1, sizeof(*act)); 
    act->name = args[1]; 
    list_init(&act->commands); 
    list_add_tail(&action_list, &act->alist); 
        /* XXX add to hash */ 
    return act; 

//system\core\init\init_parser.c
static void *parse_action(struct parse_state *state, int nargs, char **args)
{
    struct action *act;
    if (nargs < 2) {
        parse_error(state, "actions must have a trigger\n");
        return 0;
    }
    if (nargs > 2) {
        parse_error(state, "actions may not have extra parameters\n");
        return 0;
    }
    act = calloc(1, sizeof(*act));
    act->name = args[1];
    list_init(&act->commands);
    list_add_tail(&action_list, &act->alist);
        /* XXX add to hash */
    return act;
}

由上面的程序代碼可以知道, action list就是由一串act 元素所建立起來的linkedlist. 一旦action list有瞭新的act 元素, 接下來就執行parse_line_action函數

[cpp]
//system\core\init\init_parser.c  
static void parse_line_action(struct parse_state* state, int nargs, char **args) 

    struct command *cmd; 
    struct action *act = state->context; 
    int (*func)(int nargs, char **args); 
    int kw, n; 
 
    if (nargs == 0) { 
        return; 
    } 
 
    kw = lookup_keyword(args[0]); 
    if (!kw_is(kw, COMMAND)) { 
        parse_error(state, "invalid command '%s'\n", args[0]); 
        return; 
    } 
 
    n = kw_nargs(kw); 
    if (nargs < n) { 
        parse_error(state, "%s requires %d %s\n", args[0], n – 1, 
            n > 2 ? "arguments" : "argument"); 
        return; 
    } 
    cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs); 
    cmd->func = kw_func(kw); 
    cmd->nargs = nargs; 
    memcpy(cmd->args, args, sizeof(char*) * nargs); 
    list_add_tail(&act->commands, &cmd->clist); 

//system\core\init\init_parser.c
static void parse_line_action(struct parse_state* state, int nargs, char **args)
{
    struct command *cmd;
    struct action *act = state->context;
    int (*func)(int nargs, char **args);
    int kw, n;

    if (nargs == 0) {
        return;
    }

    kw = lookup_keyword(args[0]);
    if (!kw_is(kw, COMMAND)) {
        parse_error(state, "invalid command '%s'\n", args[0]);
        return;
    }

    n = kw_nargs(kw);
    if (nargs < n) {
        parse_error(state, "%s requires %d %s\n", args[0], n – 1,
            n > 2 ? "arguments" : "argument");
        return;
    }
    cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
    cmd->func = kw_func(kw);
    cmd->nargs = nargs;
    memcpy(cmd->args, args, sizeof(char*) * nargs);
    list_add_tail(&act->commands, &cmd->clist);
}

 

You May Also Like