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进程进行交互;(个人理解)


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


Android 应用进程uid不变 android init进程_Android 应用进程uid不变_02