init进程
init是一个由内核启动的用户级进程
init是Linux系统中用户空间的第一个进程。由于Android是基于Linux内核的,所以init也是Android系统中用户空间的第一个进程。
adb shell ps中init的PID为1,PPID为0
- init进程主要作用:
1.解析脚本init.rc 2.根据init.rc配置信息,触发Action及启动Service 3.解析系统property文件并初始化property信息 4.提供系统property服务管理及完成对应的触发事件 5.维护系统级Service
解析脚本init.rc
- init解析init.rc过程
init进程从system/core/init/init.c中的int main(int argc, char **argv)方法开始执行 解析init.rc是在main函数中的init_parse_config_file("/init.rc");中进行的,依次会执行如下操作: 1.扫描init.rc中的token,找到其中的文件结束EOF/文本TEXT/新行NEWLINE, 其中的空格‘ ’、‘\t’、‘\r’会被忽略,#开头的行也被忽略掉; 而对于TEXT,空格‘ ’、‘\t’、‘\r’、‘\n’都是TEXT的结束标志。 2.对每一个TEXT token,都加入到args[]数组中 3.当遇到新一行(‘\n’)的时候,用lookup_keyword(args[0]);检索匹配关键字 1) 对Section(on和service),调用parse_new_section() 解析; - 对on section,调用parse_action(),并设置解析函数parse_line为parse_line_action() - 对service section,调用parse_service(),并设置解析函数parse_line为parse_line_service() 2) 对其他关键字的行(非on或service开头的地方,也就是没有切换section)调用parse_line() 4.将解析出的action command添加到action_list中,将service添加到service_list 5.执行action_for_each_trigger时,会把队列action_list里所匹配的action,追加到action_queue的队尾;
- 解析init.rc涉及到的三个关键链表:
static list_declare(service_list); static list_declare(action_list); static list_declare(action_queue);
- init动作的四个阶段:
init动作四个阶段包括early-init,init,early-boot,boot; //action_for_each_trigger方法会根据这四个阶段来将action_list里所匹配的action,添加到action_queue中;例如:action_for_each_trigger("early-init", action_add_queue_tail); 1.early-init wait_for_coldboot_done keychord_init console_init 2.init early-fs fs post-fs post-fs-data property_service_init signal_init check_startup 3.early-boot 4.boot
根据init.rc配置信息,触发Action及启动Service
init.c(system/core/init/init.c)中的int main(int argc, char **argv)
- 在解析init.rc后,会调用action_for_each_trigger,queue_builtin_action会将action和一些初始化操作加到action_list中
- 调用以下无限for循环,就开始触发action及启动service
for(;;) { ...... execute_one_command();//触发action & 启动service restart_processes();//处理重启的函数 ...... }
- execute_one_command方法关键逻辑:
1.action_remove_queue_head函数获取action_queue链表中的第一个action节点 2.通过action节点调用get_next_command函数获取它的下一个Command 3.执行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(); //获取action_queue链表中的第一个action节点 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); //通过action节点调用get_next_command函数获取它的下一个Command } if (!cur_command) return; ret = cur_command->func(cur_command->nargs, cur_command->args); //执行Command INFO("command '%s' r=%d\n", cur_command->args[0], ret); }
- restart_processes中关键逻辑:
1.循环获取service_list中的Service节点 2.调用service_for_each_flags函数,通过Service节点中的flags、 time_started判断是否启动该Service 3.调用service_start函数,fork子进程,创建Socket、执行启动Service等操作 service_start函数来解释init.rc文件中的service命令 static void restart_processes() { process_needs_restart = 0; service_for_each_flags(SVC_RESTARTING,restart_service_if_needed); //调用service_for_each_flags函数,通过Service节点中的flags、 time_started判断是否启动该Service }
解析系统property文件并初始化property信息
- 安卓中的属性服务类似于windows上的注册表机制;
- 通过adb shell getprop获取系统当前属性
- 属性服务是怎么启动的?
1.首先,属性服务也会有对于的action:property_service_init,queue_builtin_action会根据action去调用相应的处理方法:property_service_init_action 2.初始化调用过程:property_service_init_action-> start_property_service-> load_properties_from_file(如build prop,system prop文件)& create_socket & listen & set property_set_fd(等待应用发送请求 3.多路切换监听过程 for(;;) { ...... 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; } ...... nr = poll(ufds, fd_count, timeout); }
提供系统property服务管理及完成对应的触发事件
- setprop怎么工作的?
当执行setprop时就会执行Toolbox中的main函数 toolbox是一个工具
- 你是不是在想,setprop与init进程有什么关系呢?
init进程将属性服务启动后,属性服务运行在init进程里,并管理属性服务,当setprop时,toolbox就会与init进程进行交互;(个人理解)
维护系统级Service
- init进程是如何维护系统级Service的?
1.在init.c的main函数中,会调用handle_signal方法,用于等待接收子进程退出时发送的signal信号; 2.当子进程退出时,会调用sigchld_handler方法,发送一个signal信号(往socket中写数据) 3.handle_signal中的wait_for_one_process方法接收到该信号后,会根据传过来的pid找到相应的service,并根据该service的flags执行相应操作(如,重启等),完成进程的维护。