《深入理解Android 卷1》读书笔记 (一)—— Android Init 浅析之从Main开始到service start

本文的大体流程还是按照书本上来,分三段。

(一)从Main开始到service start

(二)zygote restart

(三)属性服务 (property_service)


由于本文内容较长,重新组织了下文章结构,将原文一分为三。


(一)从Main开始到service start.


这里提到的浅析,只是根据自己看代码的经验,在此记录下。

因为自己在网上查找相关信息的时候,发现内容不够详实,

有些还过于老旧(如自己所看的《深入理解Android 卷1》,里面就是基于Android 2.x的)。

最后发现,在Read the Fucking code的过程中,居然自己弄懂了,觉得有必要

在此记录,与大家分享下。


由于我看的代码版本比较新,自己也不知道从哪个版本开始,Android 的Init.c就被改成这样了。

这里姑且认为是Android 4.2及以后版本吧(可能前面的版本已经改成这样了)。


代码路径: system\core\init\init.c


需要理解的点:


int init_parse_config_file(const char *fn)
{
    char *data;
    data = read_file(fn, 0);
    if (!data) return -1;

    parse_config(fn, data);
    DUMP();
    return 0;
}


In parse_config:

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;</span>


In parse_new_section

case K_on:
        state->context = parse_action(state, nargs, args);
        if (state->context) {
            state->parse_line = parse_line_action;
            return;
        }
        break;

init_parse_config_file("/init.rc")

   -----> parse_config
   -----> T_NEWLINE , lookup_keyword , (kw_is(kw, SECTION)) ,
          请参考keywords.h里面的:
          KEYWORD(import,      SECTION, 1, 0)             
          KEYWORD(on,          SECTION, 0, 0)
          KEYWORD(service,     SECTION, 0, 0)
          也就是说此处主要处理的是init.rc里面的import ,  on  , service
   ------> parse_new_section  将on 所对应的action添加到action_list上,
           将service对应的条目添加到service_list链表上。
           还有一个action_queue,那个是在main函数(init.c)中通过action_for_each_trigger
           将成员添加的。
   ------> 当处理每条section条目后,会调用parse_line对其后紧跟的非section行进行处理,直到

              遇到新的section。此处,on对应的是parse_line_action, 而service对应的是parse_line_service
           其实,主要是将那些行添加到双向链表上,以parse_line_service为例,请参考
           case K_onrestart 里面的 list_add_tail(&svc->onrestart.commands, &cmd->clist);
          
    之后通过  execute_one_command();  ( main函数的for循环,位于init.c中)执行各个action_queue

中各个action对应的命令。在main可看到,action_queue中的结点是通过action_for_each_trigger添加进去的。


void action_for_each_trigger(const char *trigger,
                             void (*func)(struct action *act))
{
    struct listnode *node;
    struct action *act;
    list_for_each(node, &action_list) {
        act = node_to_item(node, struct action, alist);
        if (!strcmp(act->name, trigger)) {
            func(act);
        }
    }
}


也就是说,如果action_list里面有此action,则调用func,其实就是action_add_queue_tail
添加到action_queue中。这里是通过strcmp进行字符串比较,而已经添加到action_list里面的
node是通过解析init.rc得到。


    action_for_each_trigger("early-init", action_add_queue_tail);

    queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
    queue_builtin_action(keychord_init_action, "keychord_init");
    queue_builtin_action(console_init_action, "console_init");

    /* execute all the boot actions to get us started */
    action_for_each_trigger("init", action_add_queue_tail);

    /* skip mounting filesystems in charger mode */
    if (!is_charger) {
        action_for_each_trigger("early-fs", action_add_queue_tail);
        action_for_each_trigger("fs", action_add_queue_tail);
        action_for_each_trigger("post-fs", action_add_queue_tail);
        action_for_each_trigger("post-fs-data", action_add_queue_tail);
    }

    queue_builtin_action(property_service_init_action, "property_service_init");
    queue_builtin_action(signal_init_action, "signal_init");
    queue_builtin_action(check_startup_action, "check_startup");

    if (is_charger) {
        action_for_each_trigger("charger", action_add_queue_tail);
    } else {
        action_for_each_trigger("early-boot", action_add_queue_tail);
        action_for_each_trigger("boot", action_add_queue_tail);
    }

        /* run all property triggers based on current state of the properties */
    queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");

这里为啥会跑出来个queue_builtin_action呢? 因为这里面所用的action不在init.rc中,

action_for_each_trigger不能找到action_list中对应的匹配,也就不能通过此函数将

此action添加到action_list中。但是由于这些action又是需要做的,所以单独写了个函数,

生成所需要的结点,然后直接将其加入action_list。


BTW,queue_builtin_action 有使用calloc函数,会看到有直接使用结构体里面的指针

成员,但没有看到此指针的初始化,这里是否会有问题呢??

这里有必要说一下C语言中malloc函数与calloc函数的区别:

calloc在动态分配完内存后,自动初始化该内存空间为零,而malloc不初始化,里边数据是随机的垃圾数据。

看到了么? 那些指针被初始化为0  (NULL) 了。


通过代码,我们知道诸如early-init, init, early-boot, boot,希望加入到action_queue中。查看

init.rc,我们发现有on init, on early-init以及on boot, 所以init, early-init, boot是都有被添加到action-list的。

于是,上面3个也会被加入到action_queue。


我们再来看看execute_one_command到底做了什么。


void execute_one_command(void)
{
    int ret;

    if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
        cur_action = action_remove_queue_head();
        cur_command = NULL;
        if (!cur_action)
            return;
        INFO("processing action %p (%s)\n", cur_action, cur_action->name);
        cur_command = get_first_command(cur_action);
    } else {
        cur_command = get_next_command(cur_action, cur_command);
    }

    if (!cur_command)
        return;

    ret = cur_command->func(cur_command->nargs, cur_command->args);
    INFO("command '%s' r=%d\n", cur_command->args[0], ret);
}


在此简析execute_one_command函数:


(1)循环第一次进入此函数时,cur_action 和cur_command均为NULL,于是会调用

action_remove_queue_head从action_queue中取出第一个action。然后调用get_first_command

获取此action的第一个command,至此,cur_action和cur_command均被赋值,不再为NULL了。


(2)循环第二次进入此函数时,cur_action 和cur_command均不为NULL,于是通过is_last_command

判断cur_command是否为cur_action最后一个command。如果不是,会调用get_next_command

去获取之前那个action的第二个command。否则,cur_action对应的各个command (command list里的)

均被处理了,那么将调用action_remove_queue_head从action_queue中取出第二个action。


(3)依此类推,action_queue里面的各个action所对应的的各个command均会被处理。


(我想这次分析得这么细致,应该所有看到的人都容易理解吧。)


struct action *action_remove_queue_head(void)
{
    if (list_empty(&action_queue)) {
        return 0;
    } else {
        struct listnode *node = list_head(&action_queue);
        struct action *act = node_to_item(node, struct action, qlist);
        list_remove(node);
        list_init(node);
        return act;
    }
}



static struct command *get_first_command(struct action *act)
{
    struct listnode *node;
    node = list_head(&act->commands);
    if (!node || list_empty(&act->commands))
        return NULL;

    return node_to_item(node, struct command, clist);
}

static struct command *get_next_command(struct action *act, struct command *cmd)
{
    struct listnode *node;
    node = cmd->clist.next;
    if (!node)
        return NULL;
    if (node == &act->commands)
        return NULL;

    return node_to_item(node, struct command, clist);
}


初始值cur_action 和cur_command均为NULL。 由于这个是循环,所以,cur_action第一次

得到的是early-init,并依次执行该action下对应的各个command。 当然,boot这个action

下的command也会在处理boot这个action的时候被执行。

on boot那个section下面有   
    class_start core
    class_start main


于是,会执行class_start这个关键字对应的function, 也就是do_class_start 。


int do_class_start(int nargs, char **args)
{
        /* Starting a class does not start services
         * which are explicitly disabled.  They must
         * be started individually.
         */
    service_for_each_class(args[1], service_start_if_not_disabled);
    return 0;
}


void service_for_each_class(const char *classname,
                            void (*func)(struct service *svc))
{
    struct listnode *node;
    struct service *svc;
    <span style="color:#ff6666;">list_for_each</span>(node, &service_list) {
        svc = node_to_item(node, struct service, slist);
        if (!strcmp(svc->classname, classname)) {
            func(svc);
        }
    }
}


static void service_start_if_not_disabled(struct service *svc)
{
    if (!(svc->flags & SVC_DISABLED)) {
        service_start(svc, NULL);
    }
}



而在service_start里面,我们可以看到时通过fork创建了子进程,

execve(svc->args[0], (char**) arg_ptrs, (char**) ENV); 启动子进程。

我们再看看init.rc中的一句:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server<br>

在parse_service里面有填充args成员,是读取到的init.rc内容行的arg+2,其实就是

/system/bin/app_process

就这样,init.rc中的各个service依次启动了。


总结下service start的流程是:

(1)init_parse_config_file("/init.rc")  读取并分析init.rc文件,将里面的

action和service分别添加到action_list 和 service_list


(2)调用action_for_each_trigger,queue_builtin_action,直接或间接调用

action_add_queue_tail 将action_list里面存在的action和单独指定的"builtin action”

添加到action queue。


(3)在for循环里面调用execute_one_command执行action_queue里面添加的

各个action里面的各个command,当然也包括"on" section对应的"boot "action。


(4)"boot "action 里面的class start 这个command的执行,其实对应的就是do_class_start

函数执行,最终service_start被调用来启动各个service。






之前也看了个文章,关于Android Init进程启动的,里面对Init.rc脚本中的各个部分做了概要性的介绍。
网址:http://www.cnblogs.com/mr-raptor/archive/2012/07/12/2588920.html




  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值