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.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执行相应操作(如,重启等),完成进程的维护。