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

本文为极度寒冰原创,转载请注明出处

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

在分析完解析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的。






更多相关文章

  1. android 自动化压力测试-monkey 3 命令参数
  2. android上下文之间参数的传递与接…
  3. android binder机制及其源码解析之第二节 重要函数讲解之常用数
  4. Android调用系统相机onActivityResult返回参数data为null
  5. 查看android目录结构
  6. 剖析Android程序结构-----Android新手入门
  7. android intent activity参数传递

随机推荐

  1. Android(安卓)studio RelativeLayout相对
  2. TecentUtil 腾讯微博 android
  3. android获取屏幕相关信息
  4. android Digital Clock
  5. android的Timer方法
  6. Android(安卓)判断程序前后台状态
  7. android首页Splash页面简单实现
  8. android ion 内存泄漏排查
  9. Android调用WebView
  10. Android传感器(一)-列出手机所具有的传感器