android启动代码init.c文件分析(四)

来源:互联网 发布:梨园淘宝城 还营业吗 编辑:程序博客网 时间:2024/05/14 04:05

/*****************************************************************

*version:android4.2

*author:冷雨

*嵌入式开发群:122879839

*****************************************************************/

 

  终于来到最后了,这是一个长长的for循环。

    for(;;) {        int nr, i, timeout = -1;        execute_one_command();        restart_processes();        if (!property_set_fd_init && get_property_set_fd() > 0) {            ufds[fd_count].fd = get_property_set_fd();            ufds[fd_count].events = POLLIN;            ufds[fd_count].revents = 0;            fd_count++;            property_set_fd_init = 1;        }        if (!signal_fd_init && get_signal_fd() > 0) {            ufds[fd_count].fd = get_signal_fd();            ufds[fd_count].events = POLLIN;            ufds[fd_count].revents = 0;            fd_count++;            signal_fd_init = 1;        }        if (!keychord_fd_init && get_keychord_fd() > 0) {            ufds[fd_count].fd = get_keychord_fd();            ufds[fd_count].events = POLLIN;            ufds[fd_count].revents = 0;            fd_count++;            keychord_fd_init = 1;        }        if (process_needs_restart) {            timeout = (process_needs_restart - gettime()) * 1000;            if (timeout < 0)                timeout = 0;        }        if (!action_queue_empty() || cur_action)            timeout = 0;#if BOOTCHART        if (bootchart_count > 0) {            if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)                timeout = BOOTCHART_POLLING_MS;            if (bootchart_step() < 0 || --bootchart_count == 0) {                bootchart_finish();                bootchart_count = 0;            }        }#endif        nr = poll(ufds, fd_count, timeout);        if (nr <= 0)            continue;        for (i = 0; i < fd_count; i++) {            if (ufds[i].revents == POLLIN) {                if (ufds[i].fd == get_property_set_fd())                    handle_property_set_fd();                else if (ufds[i].fd == get_keychord_fd())                    handle_keychord();                else if (ufds[i].fd == get_signal_fd())                    handle_signal();            }        }    }    return 0;}


 

  首先调用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);}


 

  这里涉及到两个变量,我们先贴出代码。

static struct action *cur_action = NULL;static struct command *cur_command = NULL;


 

  由于是第一次调用这个函数,这里的cur_actioncur_command现在仍未NULL,所以第一个if里面的代码可以执行。里面首先调用了action_remove_queue_head函数。

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);        return act;    }}


 

  在这个函数中首先获得第一个action结构体,然后将这个结构体对应的节点从action_queue里面删除,最后返回这个action结构体。

  回到execute_one_command函数中,调用get_first_command去获得一个command结构体指针。看一下他的实现函数。

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);}


 

  这个函数首先获得head节点,然后利用node_to_item将这个节点转化成command结构体指针。

  再次回到execute_one_command函数中,如果能够正确的获得command结构体指针,便会执行cur_command->func函数。

  这样我们知道main函数中调用execute_one_command函数的作用了。首先从action_queue链表中获得头部的action结构体,并将这个头部的action结构体从action_queue移除。如果我们是第一次使用这个action结构体的话,我们会调用get_first_command函数去获得链接在它上面的第一个command结构体,并执行这个结构体对应的函数;如果我们不是第一次使用这个action结构体的话,我们会调用get_next_command函数去获得链接在这个action结构体的下一个command结构体,并执行对应的函数。

main函数中,我们现在是处于一个for循环中。所以,每当我们在for循环中调用execute_one_command的时候,便会获得一个command结构体,并执行其对应的函数。当我们获得action结构体的最后一个command结构体后,再次调用execute_one_command函数的时候,我们就会从action_queue中去获得新的action结构体,并重复获得command结构体,执行函数的步骤,直到最终我们把action_queue链表中的所有的action结构体上的所有的command都调用一遍。

 

  我们把思维拉回到main函数中,接下来有一个restart_processes函数。这个函数是做什么的?如果我们启动的service有死掉的话,这个函数便会检测到,并且调用相应的函数去重新打开service,即实现restart功能。

static void restart_processes(){    process_needs_restart = 0;    service_for_each_flags(SVC_RESTARTING,                           restart_service_if_needed);}void service_for_each_flags(unsigned matchflags,                            void (*func)(struct service *svc)){    struct listnode *node;    struct service *svc;    list_for_each(node, &service_list) {        svc = node_to_item(node, struct service, slist);        if (svc->flags & matchflags) {            func(svc);        }    }}


 

  注意到我们传给service_for_each_flags函数的参数中unsignedmatchflagsSVC_RESTARTING,在service_for_each_flags函数中,我们首先获得一个service结构体,然后让这个结构体的flags匹配我们传递过来的SVC_RESTARTING,如果我们这个结构体的flags恰好是SVC_RESTARTING的话,就执行我们作为参数传递过来的那个函数即restart_service_if_needed

 

  我们回到main函数中。下面是关于poll函数的使用,poll在这里用于检测socket变化的函数。看代码,如果条件满足的话便会初始化struct pollfd ufds[4]中各个成员变量。其实这里我们仅仅操作了ufds数组中的三个成员。我们先看第一个成员,如果(!property_set_fd_init && get_property_set_fd() > 0)这个条件满足的话就会进行下面的初始化。

intproperty_set_fd_init = 0;

所以!property_set_fd_init这里是1get_property_set_fd()函数是定义在system/core/init/property_service.c文件中的函数。

int get_property_set_fd(){    return property_set_fd;}


 

  他返回的是property_set_fd变量,这个变量是多少?

static int property_set_fd = -1;

  这里的property_set_fd = -1是初始值,那么在什么时候这个值能够满足我们的判断条件呢。还记得前面前面执行过下面一行代码吗?

queue_builtin_action(property_service_init_action,"property_service_init");

  这段代码的作用是创建一个action结构体和一个command结构体,将这个command结构体链入了action结构体,并将property_service_init_action赋值给了command结构体的func变量。这样在main函数的for循环下找到这个action结构体后,会依次找到action结构体下面的command结构体,并调用对应的func成员函数。最终会调用到我们的这个property_service_init_action函数。我们看看这个函数的实现代码。

static int property_service_init_action(int nargs, char **args){    /* read any property files on system or data and     * fire up the property service.  This must happen     * after the ro.foo properties are set above so     * that /data/local.prop cannot interfere with them.     */    start_property_service();    return 0;}void start_property_service(void){    int fd;    load_properties_from_file(PROP_PATH_SYSTEM_BUILD);    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);    load_override_properties();    /* Read persistent properties after all default values have been loaded. */    load_persistent_properties();    fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);    if(fd < 0) return;    fcntl(fd, F_SETFD, FD_CLOEXEC);    fcntl(fd, F_SETFL, O_NONBLOCK);    listen(fd, 8);    property_set_fd = fd;}

  看到start_property_service函数的最后一行没?这里改变了property_set_fd的值!这样我们main函数下的if判断就能够通过了也就可以去初始化对应的成员变量。

  同理,当我们调用signal_init_actionkeychord_init_action函数的时候,我们会让下面的那两个if判断通过,最终这三个都会设置完毕。我们仔细看一下这里对events成员赋值都是POLLIN,这样当后期有read events可操作时就会返回。

 

  在main函数中紧跟着这三个if后面仍然是两个if结构,这两个是关于timout的设置就不看了。最后调用poll函数。如果poll能检测到socket变化,就利用一个for循环去判断发生变化的是哪一个socket。并最终调用对应的函数去处理这些变化。


 

原创粉丝点击