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_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文件分析(四)
- android启动代码init.c文件分析(一)
- android启动代码init.c文件分析(二)
- android启动代码init.c文件分析(三)
- Android 启动分析 --- init.c (system/core/init/init.c)
- android启动过程中init.c文件分析
- android启动过程中init.c文件分析
- Android启动之init.c文件main函数分析
- android init.c 文件分析
- ARM启动代码分析(2440init.c)
- Android启动过程分析——init.c(一)
- Android启动过程分析——init.c(二)
- Android启动流程分析(四) init进程分析
- android init(system/core/init/init.c)分析
- android init(system/core/init/init.c)分析
- android init(system/core/init/init.c)分析
- Android系统启动流程分析init.c和init.rc文件
- Android启动init.c
- 不做不明真相的开发者 之驱动与中断
- 对象的比较,排序,重写equals(),compareTo(),hashCode()方法
- vim的使用
- 趣味算式
- Cuda C++ Thrust API与 Cuda Runtime API程序比较
- android启动代码init.c文件分析(四)
- C语言中,局部变量、全局变量、静态变量、堆、栈的内存地址
- 泊松分酒
- Java Vs. C♯
- Django调试模式下Sql执行的差异
- “UC第一”惹了谁?
- The window manager
- Asp.Net底层解析(二)——视图状态ViewState与控件状态ControlState详解
- POJ2185(最小覆盖子矩阵) #by nobody