/*****************************************************************
*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_action,cur_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函数的参数中unsignedmatchflags是SVC_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这里是1,get_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_action和keychord_init_action函数的时候,我们会让下面的那两个if判断通过,最终这三个都会设置完毕。我们仔细看一下这里对events成员赋值都是POLLIN,这样当后期有read events可操作时就会返回。
在main函数中紧跟着这三个if后面仍然是两个if结构,这两个是关于timout的设置就不看了。最后调用poll函数。如果poll能检测到socket变化,就利用一个for循环去判断发生变化的是哪一个socket。并最终调用对应的函数去处理这些变化。
本文深入分析Android启动过程中init.c的for循环,讲解execute_one_command函数如何处理action和command结构体,实现命令的执行。同时,介绍了restart_processes函数在服务重启中的作用,以及poll函数在检测socket变化中的应用。

被折叠的 条评论
为什么被折叠?



