美文网首页
Android系统启动-Init进程

Android系统启动-Init进程

作者: isLJli | 来源:发表于2021-12-05 15:55 被阅读0次

    Android开机启动流程

    如图1所示,是Android开机启动大致流程,其中流程大致为加载BootLoader -> 启动Linux系统内核-> 创建Init进程(native层-> framework -> app)

    图1 来自Gityuan.com

    本文章将重点讲解Init进程的启动流程,其中Init进程的终点则是创建解析文件的子进程,并且守护这个子进程(进行重启)。先从整体在布局分析

    图2 开机启动流程

    Android开机启动Linux内核

    如上面的图1所思,在Android开机时,先ROM加载程序预定的程序BootLoader,然后BootLoader会去检查RAM、初始化硬件参数等就会启动Linux内核。
    当Linux Kernel内核启动后,就会初始化各种硬件环境、加载驱动程序等。当Linux内核加载完成后,就会启动用户空间的第一个进程Init进程。这里的Linux内核层称为内核空间,native层以上则称为用户空间。所以Init进程是所有用户进程的父进程

    Init进程的启动过程

    本篇代码基于Android6.0源码分析(只要会一个版本,其他版本的基本也能看懂),线上源码阅读地址:http://androidxref.com/, Init进程代码目录主要在:

    /system/core/init/Init.cpp
    /system/core/rootdir/init.rc
    /system/core/init/init_parser.cpp
    /system/core/init/builtins.cpp
    /system/core/init/signal_handler.cpp
    

    Init进程是用户进程的第一个进程,其pid = 1,其主要用来初始化和启动属性服务,创建子进程如Zygote进程等。在Linux内核加载完成后,第一件事就是创建Init进程,我们先看Init进程的创建后执行的第一个main()函数
    /system/core/init/init.cpp

    int main(int argc, char**argv) {
      if (!strcmp(basename(argv[0]), "ueventd")) {
          return ueventd_main(argc, argv);
      }
      if (!strcmp(basename(argv[0]), "watchdogd")) {
          return watchdogd_main(argc, argv);
      }
      //清理umask
      umask(0);
      if (is_first_stage) {
           // 创建和挂载启动所需的文件目录
          mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
          mkdir("/dev/pts", 0755);
          mkdir("/dev/socket", 0755);
          mount("devpts", "/dev/pts", "devpts", 0, NULL);
          mount("proc", "/proc", "proc", 0, NULL);
          mount("sysfs", "/sys", "sysfs", 0, NULL);
      }
      // 初始化Kernel的Log,可以获取Kernel的Log
      klog_init();
      if (!is_first_stage) {
          // 1.对属性服务进行初始化,分配空间
          property_init();
      }
      // 2. 处理异常退出的子进程,会把子进程的信号全部清除,并重启该子进程定义的重启服务
      signal_handler_init();
      // 3. 启动属性服务
      start_property_service();
      // 4. 解析init.rc配置文件
      init_parse_config_file("/init.rc");
    
      while (true) {
          if (!waiting_for_exec) {
              execute_one_command();
              // 5. 重启死去的子进程
              restart_processes();
          }
      }
      return 0;
    }
    
    

    在main()函数通过精简代码中,首先创建和挂载所需要的文件目录,这些都是系统运行时的目录。然后则是我们重点分析的场景:

    1. 注释1中调用property_init进行属性服务的初始化,在注释3中调用start_property_service来启动属性服务
    2. 在注释2中通过signal_handler_init进行子进程的信号处理
    3. 在注释4中解析init.rc的配置脚本文件,在这个脚本文件中说明了要创建启动什么进程;
    4. 在注释5中,restart_processes则循环查看重启守护子进程

    1. 子进程异常处理

    调用signal_handler_init进行子进程信号量的处理,子进程在暂停或退出时会发出一个终止的SIGCHLD信号,而signal_handler_init函数则对这个信号进行监听,并对这个子进程的信息进行删除重置,并执行子进程在脚本文件的配置的onrestart的服务。
    signal_handler_init函数的实现主要在:/system/core/init/signal_handler.cpp

    void signal_handler_init() {
      int s[ 2];
      // 创建 socket pair
      if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -
          ERROR("socketpair failed: %s\n", strerror(errno));
          exit(1);
      }
      signal_write_fd = s[0];
      signal_read_fd = s[1];
      //如果捕获到SIGCHLD信号则写入signal_write_fd
      struct sigaction act;
      memset( & act, 0, sizeof(act));
      act.sa_handler = SIGCHLD_handler;
      // SA_NOCLDSTOP事Init进程在子进程终止时才捕获SIGCHLD
      act.sa_flags = SA_NOCLDSTOP;
      sigaction(SIGCHLD, & act, 0);
       // 判断并对终止的进程做处理
      reap_any_outstanding_children();
      // 注册signal_read_fd状态进行回调执行handle_signal函数,handle_signal本质还是执行上面的reap_any_outstanding_children()方法
      register_epoll_handler(signal_read_fd, handle_signal);
    }
    
    /system/core/init/init.cpp
    void register_epoll_handler(int fd, void (*fn)())
      {
          epoll_event ev;
          ev.events = EPOLLIN;
          ev.data.ptr = reinterpret_cast < void*>(fn);
           // 将fd的可读事件加入到epoll_fd的监听队列中,并回调相应函数
          if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, & ev) ==-1){
          ERROR("epoll_ctl failed: %s\n", strerror(errno));
      }
      }
    
    

    接下来,我们看看handle_signal回调函数,对于发出终止信号的子进程怎么处理?

    static void handle_signal() {
      // Clear outstanding requests.
      // 把signal_read_fd写入buf
      char buf[ 32];
      read(signal_read_fd, buf, sizeof(buf));
      // 重点执行此函数
      reap_any_outstanding_children();
    }
    
    static void reap_any_outstanding_children() {
     // 通过wait_for_one_process()函数,遍历寻找终止的子进程
      while (wait_for_one_process()) {
      }
    }
    
    // 查看是否为退出进程,如果是则移除属性,并启动配置文件的onrestart的服务。
    static bool wait_for_one_process() {
      int status;
       // 根据pid判断是否为退出进程,没退出则pid=0
      pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, & status, WNOHANG));
      if (pid == 0) {
          return false;
      } else if (pid == -1) {
          ERROR("waitpid failed: %s\n", strerror(errno));
          return false;
      }
       // 执行到这里说明是退出进程
      // 根据pid找到相应的service配置脚本文件
      service * svc = service_find_by_pid(pid);
      std::string name;
      // 如果没有配置文件则直接退出
      if (!svc) {
          return true;
      }
     
      //当flags为RESTART,且不是ONESHOT时,先kill进程组内所有的子进程或子线程
      if (!(svc -> flags & SVC_ONESHOT) || (svc -> flags & SVC_RESTART)) {
          NOTICE("Service '%s' (pid %d) killing any children in process group\n", svc -> name, pi
          kill(-pid, SIGKILL);
      }
    
       //移除当前服务svc中的所有创建过的socket
      for (socketinfo * si = svc -> sockets; si; si = si -> next) {
          char tmp[ 128];
          snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si -> name);
          unlink(tmp);
      }
       //当flags为EXEC时,释放相应的服务
      if (svc -> flags & SVC_EXEC) {
          INFO("SVC_EXEC pid %d finished...\n", svc -> pid);
          waiting_for_exec = false;
          list_remove( & svc -> slist);
          free(svc -> name);
          free(svc);
          return true;
      }
      
      //执行serive配置文件的onrestart启动相应的服务
      struct listnode*node;
      list_for_each(node, & svc -> onrestart.commands){
          command * cmd = node_to_item(node, struct command, clist);
          cmd -> func(cmd -> nargs, cmd -> args);
      }
      svc -> NotifyStateChange("restarting");
      return true;
    }
    
    

    signal_handler_init对子进程的信号处理就完成了,可以就是对终止子进程的进行注册回调,并移除相关的属性,并启动revice文件的onrestart的配置服务。

    2. 解析Init.rc

    init.rc是非常重要的配置文件,位于/system/core/rootdir/目录中。它是由Android初始化语言编写的脚本,Android初始化语言的学习可以参考这篇文章,Android的初始化语言大致分为:: Action、Command、Service、Option、Import五种类型,但Init.rc主要分为import的导入、service启动服务、on命令。

    // import导入
    import /init.environ.rc
    import /init.usb.rc
    ...
    
    on early-init
      write /proc/1/oom_score_adj -1000
      restorecon /adb_keys
      start ueventd
    ...
    on nonencrypted
      class_start main // 启动classname为mian的服务
      class_start late_start
    
    ...
    
    service servicemanager /system/bin/servicemanager
      class core
      user system
      group system
      critical
      onrestart restart healthd
      onrestart restart zygote
      onrestart restart media
      onrestart restart surfaceflinger
      onrestart restart drm
    
    service surfaceflinger /system/bin/surfaceflinger
    service media /system/bin/mediaserver
    service installd /system/bin/installd
    
    

    on中有class_start main其意思是启动classname为mian的服务,在Init进程中会启动一个很重要的Zygote子进程,接下来分析一些Zygote服务脚本的定义,Zygote的service服务脚本并不在Init.rc中,而是自己定义了独自的Zygote服务脚本文件,位于/system/core/rootdir/init.zygote64.rc

    service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
      class main
      socket zygote stream 660 root system
      onrestart write /sys/android_power/request_state wake
      onrestart write /sys/power/state on
      onrestart restart media
      onrestart restart netd
      writepid /dev/cpuset/foreground/tasks
    

    这里的脚本是启动一个名叫zygote的进程,并且执行的路径是/system/bin/app_process64,后面则是参数。class main:是这个进程的classname叫做main,onrestart是在上面的子进程信号处理时会进行重启的进程。所以在Init.rc文件中会启动zygote进程。

    在Init.rc文件中,除了启动zygote进程之外,还会启动一些如servicemanager、surfaceflinger 、media、installd等重要的进程。

    那么这些进程创建的过程又是如何的呢?,请看下一节的启动解析的服务。

    3. 启动解析的服务

    在配置的脚本文件中通过class_start main去启动一个ClassName为main的服务,其中class_start中对应的启动函数为do_class_start,位于/system/core/init/builtins.cpp目录中。

      int do_class_start(int nargs, char **args)
      {
          service_for_each_class(args[1], service_start_if_not_disabled);
          return 0;
      }
    
       // 遍历寻找相同名字的classname,然后执行参数函数,也就是执行上面的service_start_if_not_disabled
      void service_for_each_class(const char *classname,
      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 (!strcmp(svc->classname, classname)) {
          func(svc);
      }
      }
      }
    
    
      static void service_start_if_not_disabled(struct service *svc)
      {
          if (!(svc->flags & SVC_DISABLED)) {
          // 只要没有设置 disabled 选项 就执行此函数创建进程
          service_start(svc, NULL);
      } else { svc ->
          flags | = SVC_DISABLED_START;
      }
      }
    
    void service_start(struct service *svc, const char *dynamic_args)
    {
      ...
      // fork 创建了一个子进程
      pid_t pid = fork();
      if (pid == 0) {
          // 代表子进程,子进程会继承父进程的所有资源,可简单理解为读时共享写事复制
          ...
          // 启动子进程
          execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
      }
    }
    

    所以通过配置的service的文件,通过fork()去创建一个子进程,并且子进程的pid=0,如果不是则是父进程。并调用execve()函数启动子进程。

    4. 初始化和启动属性服务

    属性服务类似一个注册表,填入到这个注册表的属性,在系统或软件重启时,还会对这个注册表的属性进行初始化的加载。
    在init.cpp文件中main()函数,就通过这两个函数分别进行初始化和启动

    property_init()
    start_property_service()

    property_init

      void property_init()
      {
          if (property_area_initialized) {
              return;
          }
    
          property_area_initialized = true;
    
          if (__system_property_area_init()) {
              return;
          }
    
          pa_workspace.size = 0;
          pa_workspace.fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
          if (pa_workspace.fd == -1) {
              ERROR("Failed to open %s: %s\n", PROP_FILENAME, strerror(errno));
              return;
          }
      }
    

    property_init()函数主要做的事情就是通过__system_property_area_init方法进行内存的创建。

    start_property_service

      void start_property_service()
      {
          // 创建socket
          property_set_fd =
              create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
          0666, 0, 0, NULL);
          if (property_set_fd == -1) {
              ERROR("start_property_service socket creation failed: %s\n", strerror(errno));
              exit(1);
          }
    
          listen(property_set_fd, 8);
           // 对property_set_fd进行监听,并调用handle_property_set_fd回调函数
          register_epoll_handler(property_set_fd, handle_property_set_fd);
      }
    

    5. 守护解析的服务

    最后,通过while循环,当有子进程终止时,让让可以重新启动的子进程重新启动

      while (true)
      {
          if (!waiting_for_exec) {
              execute_one_command();
              restart_processes();
    
          }
      }
    
      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);
      }
      }
      }
    
    
      static void restart_service_if_needed(struct service *svc)
      {
          time_t next_start_time = svc->time_started+5;
    
          if (next_start_time <= gettime()) { svc ->
              flags & = (~SVC_RESTARTING);
              // 重新启动进程
              service_start(svc, NULL);
              return;
          }
    
          if ((next_start_time < process_needs_restart) ||
              (process_needs_restart == 0)
          ) {
              process_needs_restart = next_start_time;
          }
      }
    
    

    总结

    Init进程的创建过程,主要就是通过解析Init.rc文件去创建一些重要的子进程比如Zagote、surfaceflinger进程,它的启动是用fork、exec去启动子进程,然后就是对子进程的终止进行监听回调,对于一些可以重启的服务进行重启和创建进程。

    相关文章

      网友评论

          本文标题:Android系统启动-Init进程

          本文链接:https://www.haomeiwen.com/subject/tfxgtrtx.html