Android啟動流程分析(九) 解析init.rc的service

來源:互聯網
上載者:User

標籤:init.rc   android 啟動流程   android service啟動   init.rc service   init.rc解析   

#############################################

本文為極度寒冰原創,轉載請註明出處

#############################################

在分析完解析init.rc的action之後,剩下的一部分就是解析service了。

而解析service還是需要回到parse_config裡面來。根據前面的知識,我們也可以很容易的知道在關鍵字為section的時候,會進入到parse_new_section。

這裡會先執行parse_service,然後將service以及後面跟的option設定為執行parse_line:parse_line_service。

要理解service的解析流程的話,首先要關注的就是service的結構體。

struct service {    /* list of all services */    struct listnode slist;   // listnode slist    const char *name;        // name    const char *classname;   // 預設值為defult    unsigned flags;          // 選項    pid_t pid;               // Service所在進程的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;               // effective user ID    gid_t gid;               // effective group ID    gid_t supp_gids[NR_SVC_SUPP_GIDS];  // supplementary ids    size_t nr_supp_gids;     // supp_gids的大小    char *seclabel;    struct socketinfo *sockets;  // 為service建立的Sockets    struct svcenvinfo *envvars;  // 為service設定的環境變數    struct action onrestart;  /* Actions to execute on restart. */    /* keycodes for triggering this service via /dev/keychord */    int *keycodes;    int nkeycodes;    int keychord_id;    int ioprio_class;    int ioprio_pri;    int nargs;    /* "MUST BE AT THE END OF THE STRUCT" */    char *args[1];}; /*     ^-------'args' MUST be at the end of this struct! */

這個結構體相比較而言就比較簡單了,除了service的本身屬性以外,對於資料結構方面就只有一個listnode。

struct listnode slist; 
這也就是說,在service的結構體中,這個結構體只會被加入一條鏈表而不是像action的兩條鏈表。

另外需要注意的是,在service的結構體中,也維護了一個action的結構體,這就是說,在service中,也存在著一個action的commands的鏈表?

然後我們就來看看parse_service的函數

static void *parse_service(struct parse_state *state, int nargs, char **args){    struct service *svc;  // 聲明結構體    if (nargs < 3) { // 如果service的參數小於三個的話,我們會認為service是個不正常的service。service最少的nargs也是3,分別為service關鍵字,service的名字,service啟動的時候要執行的命令        parse_error(state, "services must have a name and a program\n");        return 0;    }    if (!valid_name(args[1])) {  //如果service的name為不標準的名字的話,含有其它的符號的話,我們會認為這個service是不規範的service。        parse_error(state, "invalid service name '%s'\n", args[1]);        return 0;    }    svc = service_find_by_name(args[1]); 。。// 會從已經存在的service_list裡面去尋找,是否已經有同名的service存在    if (svc) {  // 如果發現有同名的service存在的話,則會返回error        parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);        return 0;    }    nargs -= 2;  // 去除service關鍵字與service的name    svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs); // malloc這個結構體    if (!svc) { // 如果malloc失敗的話,提示out of memory        parse_error(state, "out of memory\n");        return 0;    }    svc->name = args[1];  // 設定service的name為service關鍵字後的第一個參數    svc->classname = "default";  // 預設的classname為default    memcpy(svc->args, args + 2, sizeof(char*) * nargs); // 將args剩餘的參數複製到svc的args裡面    svc->args[nargs] = 0;  // 給args的最後一項設定為0    svc->nargs = nargs;  // 參數的數目等於傳進來的參數的數目    svc->onrestart.name = "onrestart"; // 設定onrestart.name為onrestart    list_init(&svc->onrestart.commands); // 初始化onrestart的鏈表    list_add_tail(&service_list, &svc->slist);  // 將當前的service結構體加入到了service_list的鏈表裡面    return svc;}
從上面我們知道,在執行完parse_service之後,會初始化service的一些屬性,將service servicename之後的做為args進行儲存。

另外,將這個解析出來的service加入到service_list的鏈表裡面。

然後接下來,去執行的就是

state->parse_line = parse_line_service;
那我們像action,再來看看parse_line_service的操作

static void parse_line_service(struct parse_state *state, int nargs, char **args){    struct service *svc = state->context;    struct command *cmd;    int i, kw, kw_nargs;    if (nargs == 0) {        return;    }    svc->ioprio_class = IoSchedClass_NONE;    kw = lookup_keyword(args[0]);    switch (kw) {    case K_capability:        break;    case K_class:        if (nargs != 2) {            parse_error(state, "class option requires a classname\n");        } else {            svc->classname = args[1];        }        break;    case K_console:        svc->flags |= SVC_CONSOLE;        break;    case K_disabled:        svc->flags |= SVC_DISABLED;        svc->flags |= SVC_RC_DISABLED;        break;    case K_ioprio:        if (nargs != 3) {            parse_error(state, "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n");        } else {    。。。。                                                                                                                                                                                                                                     ........                                                                                                                                                                                                                                                          case K_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;                                                                                                                                                                                                                                                                                              ...............                                                                                                                                                                                                                                                                                 }

可以看到,parse_line_service的這個函數,主要就是將解析service的每一行,將其對應進不同的case裡面,進行service結構體的填充。

可能這樣講,理解起來會有困難。

但是為了方便理解,我們從init.rc裡面找個例子出來分析:

service servicemanager /system/bin/servicemanager    class core    user system    group system    critical    onrestart restart healthd    onrestart restart zygote    onrestart restart media    onrestart restart surfaceflinger    onrestart restart drm
在parse_line_service的時候,會在

class的關鍵字的時候,執行到

    case K_class:        if (nargs != 2) { // 判斷是否是兩個token,如果不是的話,格式錯誤            parse_error(state, "class option requires a classname\n");        } else {            svc->classname = args[1];        }        break;
也就是將service的classname從"default"修改為“args[1]”
在user system的的option的時候,

會去執行

    case K_user:        if (nargs != 2) {            parse_error(state, "user option requires a user id\n");        } else {            svc->uid = decode_uid(args[1]);        }        break;
會將uid設定為system對應的uid

另外需要注意的是,在解析的過程中,會有一個比較重要的option是restart,來看一下當執行到這個關鍵字的時候的時候,會運行什麼。

    case K_onrestart:        nargs--;        args++;         kw = lookup_keyword(args[0]);          if (!kw_is(kw, COMMAND)) {  // 判斷是否是command,如果restart之後跟的不是command的話,就會返回error            parse_error(state, "invalid command '%s'\n", args[0]);            break;        }        kw_nargs = kw_nargs(kw);  // 獲得當前command所需的參數        if (nargs < kw_nargs) { // 如果傳遞的參數小於我們需要的參數的話,會返回error            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); // 初始化command        cmd->func = kw_func(kw);   // 將kw所包含的func賦值給cmd->func        cmd->nargs = nargs;  // 將參數的個數儲存為nargs        memcpy(cmd->args, args, sizeof(char*) * nargs); // 將這些參數複製到cmd的args中        list_add_tail(&svc->onrestart.commands, &cmd->clist); // 將這些command加入到service結構體的內部鏈表中        break;

至此,我們分析了所有關於init.rc的解析問題。

在service的解析後,會產生一條鏈表儲存service的結構體,然後service的結構體裡面自己運行維護一個action。

這個action會包含所有的restatt包含的內容,也就是restart的option關鍵字後會包含要執行的command

這個的結構應該比action的要簡單和明了的多。

分析完瞭解析,我們應該去看一下android是如何在啟動的過程中去執行這些action和service的。






Android啟動流程分析(九) 解析init.rc的service

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.