本文首发于微信公众号「后厂技术官」 
 
前言 作为“Android框架层”这个大系列中的第一个系列,我们首先要了解的是Android系统启动流程,在这个流程中会涉及到很多重要的知识点,这个系列我们就来一一讲解它们,这一篇我们就来学习init进程。
1.init简介 init进程是Android系统中用户空间的第一个进程,作为第一个进程,它被赋予了很多极其重要的工作职责,比如创建zygote(孵化器)和属性服务等。init进程是由多个源文件共同组成的,这些文件位于源码目录system/core/init。本文将基于Android7.0源码来分析Init进程。
2.引入init进程 说到init进程,首先要提到Android系统启动流程的前几步:1.启动电源以及系统启动 2.引导程序Bootloader 3.linux内核启动 4.init进程启动 
讲到第四步就发现我们这一节要讲的init进程了。关于Android系统启动流程的所有步骤会在本系列的最后一篇做讲解。
3.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(0 );     add_environment("PATH" , _PATH_DEFPATH);     bool  is_first_stage = (argc == 1 ) || (strcmp (argv[1 ], "--second-stage" ) != 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 );         #define  MAKE_STR(x) __STRING(x)          mount("proc" , "/proc" , "proc" , 0 , "hidepid=2,gid="  MAKE_STR(AID_READPROC));         mount("sysfs" , "/sys" , "sysfs" , 0 , NULL );     }     open_devnull_stdio();     klog_init();     klog_set_level(KLOG_NOTICE_LEVEL);     NOTICE("init %s started!\n" , is_first_stage ? "first stage"  : "second stage" );     if  (!is_first_stage) {                  close(open("/dev/.booting" , O_WRONLY | O_CREAT | O_CLOEXEC, 0000 ));                  property_init();         process_kernel_dt();         process_kernel_cmdline();         export_kernel_boot_props();     }  ...          start_property_service();     const  BuiltinFunctionMap function_map;     Action::set_function_map(&function_map);     Parser& parser = Parser::GetInstance();     parser.AddSectionParser("service" ,std ::make_unique<ServiceParser>());     parser.AddSectionParser("on" , std ::make_unique<ActionParser>());     parser.AddSectionParser("import" , std ::make_unique<ImportParser>());          parser.ParseConfig("/init.rc" );    ...           while  (true ) {         if  (!waiting_for_exec) {             am.ExecuteOneCommand();             restart_processes();         }         int  timeout = -1 ;         if  (process_needs_restart) {             timeout = (process_needs_restart - gettime()) * 1000 ;             if  (timeout < 0 )                 timeout = 0 ;         }         if  (am.HasMoreCommands()) {             timeout = 0 ;         }         bootchart_sample(&timeout);         epoll_event ev;         int  nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1 , timeout));         if  (nr == -1 ) {             ERROR("epoll_wait failed: %s\n" , strerror(errno));         } else  if  (nr == 1 ) {             ((void  (*)()) ev.data.ptr)();         }     }     return  0 ; } 
init的main方法做了很多事情,我们只需要关注主要的几点,在注释1处调用 property_init来对属性进行初始化并在注释2处的 调用start_property_service启动属性服务,关于属性服务,后面会讲到。注释3处 parser.ParseConfig(“/init.rc”)用来解析init.rc。解析init.rc的文件为system/core/init/init_parse.cpp文件,接下来我们查看init.rc里做了什么。
4.init.rc init.rc是一个配置文件,内部由Android初始化语言编写(Android Init Language)编写的脚本,它主要包含五种类型语句:system/core/rootdir/init.rc 
on init     sysclktz 0      # Mix device-specific information into the entropy pool     copy /proc/cmdline /dev/urandom     copy /default .prop /dev/urandom ... on boot     # basic network init      ifup lo     hostname localhost     domainname localdomain     # set RLIMIT_NICE to allow priorities from 19 to -20      setrlimit 13  40  40  ...     
这里只截取了一部分代码,其中#是注释符号。on init和on boot是Action类型语句,它的格式为:
on <trigger> [&& <trigger>]*         <command>      <command>       
为了分析如何创建zygote,我们主要查看Services类型语句,它的格式如下所示:
service <name> <pathname> [ <argument> ]*       <option>           <option>      ...   
需要注意的是在Android 7.0中对init.rc文件进行了拆分,每个服务一个rc文件。我们要分析的zygote服务的启动脚本则在init.zygoteXX.rc中定义,这里拿64位处理器为例,init.zygote64.rc的代码如下所示。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  audioserver      onrestart  restart  cameraserver      onrestart  restart  media      onrestart  restart  netd      writepid  /dev /cpuset /foreground /tasks  /dev /stune /foreground /tasks  
其中service用于通知init进程创建名zygote的进程,这个zygote进程执行程序的路径为/system/bin/app_process64,后面的则是要传给app_process64的参数。class main指的是zygote的class name为main,后文会用到它。
5.解析service 接下来我们来解析service,会用到两个函数,一个是ParseSection,它会解析service的rc文件,比如上文讲到的init.zygote64.rc,ParseSection函数主要用来搭建service的架子。另一个是ParseLineSection,用于解析子项。代码如下所示。system/core/init/service.cpp 
bool  ServiceParser::ParseSection (const  std ::vector <std ::string >& args,                                  std ::string * err)      if  (args.size() < 3 ) {         *err = "services must have a name and a program" ;         return  false ;     }     const  std ::string & name = args[1 ];     if  (!IsValidName(name)) {         *err = StringPrintf("invalid service name '%s'" , name.c_str());         return  false ;     }     std ::vector <std ::string > str_args (args.begin() + 2 , args.end())      service_ = std ::make_unique<Service>(name, "default" , str_args);     return  true ; } bool  ServiceParser::ParseLineSection (const  std ::vector <std ::string >& args,                                      const  std ::string & filename, int  line,                                      std ::string * err)  const      return  service_ ? service_->HandleLine(args, err) : false ; } 
注释1处,根据参数,构造出一个service对象,它的classname为”default”。当解析完毕时会调用EndSection:
void  ServiceParser::EndSection ()      if  (service_) {         ServiceManager::GetInstance().AddService(std ::move(service_));     } } 
接着查看AddService做了什么:
void  ServiceManager::AddService (std ::unique_ptr <Service> service)      Service* old_service = FindServiceByName(service->name());     if  (old_service) {         ERROR("ignored duplicate definition of service '%s'" ,               service->name().c_str());         return ;     }     services_.emplace_back(std ::move(service)); } 
注释1处的代码将service对象加入到services链表中。上面的解析过程总体来讲就是根据参数创建出service对象,然后根据选项域的内容填充service对象,最后将service对象加入到vector类型的services链表中。,
6.init启动zygote 讲完了解析service,接下来该讲init是如何启动service,在这里我们主要讲解启动zygote这个service。在zygote的启动脚本中我们得知zygote的class name为main。在init.rc有如下配置代码:system/core/rootdir/init.rc 
... on nonencrypted         # A/B update verifier that marks a successful boot.       exec - root -- /system/bin/update_verifier nonencrypted       class_start main              class_start late_start  ...     
其中class_start是一个COMMAND,对应的函数为do_class_start。我们知道main指的就是zygote,因此class_start main用来启动zygote。do_class_start函数在builtins.cpp中定义,如下所示。
system/core/init/builtins.cpp 
static  int  do_class_start (const  std ::vector <std ::string >& args)               ServiceManager::GetInstance().         ForEachServiceInClass(args[1 ], [] (Service* s) { s->StartIfNotDisabled(); });     return  0 ; } 
来查看StartIfNotDisabled做了什么:system/core/init/service.cpp 
bool  Service::StartIfNotDisabled ()      if  (!(flags_ & SVC_DISABLED)) {         return  Start();     } else  {         flags_ |= SVC_DISABLED_START;     }     return  true ; } 
接着查看Start方法,如下所示。
bool  Service::Start ()      flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));     time_started_ = 0 ;     if  (flags_ & SVC_RUNNING) {         return  false ;     }     bool  needs_console = (flags_ & SVC_CONSOLE);     if  (needs_console && !have_console) {         ERROR("service '%s' requires console\n" , name_.c_str());         flags_ |= SVC_DISABLED;         return  false ;     }        struct  stat  sb ;     if  (stat(args_[0 ].c_str(), &sb) == -1 ) {         ERROR("cannot find '%s' (%s), disabling '%s'\n" ,               args_[0 ].c_str(), strerror(errno), name_.c_str());         flags_ |= SVC_DISABLED;         return  false ;     } ...     pid_t  pid = fork();     if  (pid == 0 ) {         umask(077 );         for  (const  auto & ei : envvars_) {             add_environment(ei.name.c_str(), ei.value.c_str());         }         for  (const  auto & si : sockets_) {             int  socket_type = ((si.type == "stream"  ? SOCK_STREAM :                                 (si.type == "dgram"  ? SOCK_DGRAM :                                  SOCK_SEQPACKET)));             const  char * socketcon =                 !si.socketcon.empty() ? si.socketcon.c_str() : scon.c_str();             int  s = create_socket(si.name.c_str(), socket_type, si.perm,                                   si.uid, si.gid, socketcon);             if  (s >= 0 ) {                 PublishSocket(si.name, s);             }         } ...                  if  (execve(args_[0 ].c_str(), (char **) &strs[0 ], (char **) ENV) < 0 ) {             ERROR("cannot execve('%s'): %s\n" , args_[0 ].c_str(), strerror(errno));         }         _exit(127 );     } ...     return  true ; } 
通过注释1和2的代码,我们得知在Start方法中调用fork函数来创建子进程,并在子进程中调用execve执行system/bin/app_process,这样就会进入framework/cmds/app_process/app_main.cpp的main函数,如下所示。frameworks/base/cmds/app_process/app_main.cpp 
int  main (int  argc, char * const  argv[])     ...     if  (zygote) {         runtime.start("com.android.internal.os.ZygoteInit" , args, zygote);     } else  if  (className) {         runtime.start("com.android.internal.os.RuntimeInit" , args, zygote);     } else  {         fprintf (stderr , "Error: no class name or --zygote supplied.\n" );         app_usage();         LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied." );         return  10 ;     } } 
从注释1处的代码可以得知调用runtime(AppRuntime)的start来启动zygote。
7.属性服务 Windows平台上有一个注册表管理器,注册表的内容采用键值对的形式来记录用户、软件的一些使用信息。即使系统或者软件重启,它还是能够根据之前在注册表中的记录,进行相应的初始化工作。Android也提供了一个类似的机制,叫做属性服务。system/core/init/init.cpp 
property_init(); start_property_service(); 
这两句代码用来初始化属性服务配置并启动属性服务。首先我们来学习服务配置的初始化和启动。
属性服务初始化与启动 property_init函数具体实现的代码如下所示。system/core/init/property_service.cpp 
void  property_init ()      if  (__system_property_area_init()) {         ERROR("Failed to initialize property area\n" );         exit (1 );     } } 
__system_property_area_init函数用来初始化属性内存区域。接下来查看start_property_service函数的具体代码:
void  start_property_service ()      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 );     register_epoll_handler(property_set_fd, handle_property_set_fd); } 
注释1处用来创建非阻塞的socket。注释2处调用listen函数对property_set_fd进行监听,这样创建的socket就成为了server,也就是属性服务;listen函数的第二个参数设置8意味着属性服务最多可以同时为8个试图设置属性的用户提供服务。注释3处的代码将property_set_fd放入了epoll句柄中,用epoll来监听property_set_fd:当property_set_fd中有数据到来时,init进程将用handle_property_set_fd函数进行处理。
** 属性服务处理请求**system/core/init/property_service.cpp 
static  void  handle_property_set_fd () ...         if (memcmp (msg.name,"ctl." ,4 ) == 0 ) {             close(s);             if  (check_control_mac_perms(msg.value, source_ctx, &cr)) {                 handle_control_message((char *) msg.name + 4 , (char *) msg.value);             } else  {                 ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n" ,                         msg.name + 4 , msg.value, cr.uid, cr.gid, cr.pid);             }         } else  {                          if  (check_mac_perms(msg.name, source_ctx, &cr)) {                 property_set((char *) msg.name, (char *) msg.value);             } else  {                 ERROR("sys_prop: permission denied uid:%d  name:%s\n" ,                       cr.uid, msg.name);             }             close(s);         }         freecon(source_ctx);         break ;     default :         close(s);         break ;     } } 
注释1处的代码用来检查客户端进程权限,在注释2处则调用property_set函数对属性进行修改,代码如下所示。
int  property_set (const  char * name, const  char * value)      int  rc = property_set_impl(name, value);     if  (rc == -1 ) {         ERROR("property_set(\"%s\", \"%s\") failed\n" , name, value);     }     return  rc; } 
property_set函数主要调用了property_set_impl函数:
static  int  property_set_impl (const  char * name, const  char * value)      size_t  namelen = strlen (name);     size_t  valuelen = strlen (value);     if  (!is_legal_property_name(name, namelen)) return  -1 ;     if  (valuelen >= PROP_VALUE_MAX) return  -1 ;     if  (strcmp ("selinux.reload_policy" , name) == 0  && strcmp ("1" , value) == 0 ) {         if  (selinux_reload_policy() != 0 ) {             ERROR("Failed to reload policy\n" );         }     } else  if  (strcmp ("selinux.restorecon_recursive" , name) == 0  && valuelen > 0 ) {         if  (restorecon_recursive(value) != 0 ) {             ERROR("Failed to restorecon_recursive %s\n" , value);         }     }          prop_info* pi = (prop_info*) __system_property_find(name);          if (pi != 0 ) {                 if (!strncmp (name, "ro." , 3 )) return  -1 ;                 __system_property_update(pi, value, valuelen);     } else  {                 int  rc = __system_property_add(name, namelen, value, valuelen);         if  (rc < 0 ) {             return  rc;         }     }          if  (strncmp ("net." , name, strlen ("net." )) == 0 )  {         if  (strcmp ("net.change" , name) == 0 ) {             return  0 ;         }                property_set("net.change" , name);     } else  if  (persistent_properties_loaded &&             strncmp ("persist." , name, strlen ("persist." )) == 0 ) {                  write_persistent_property(name, value);     }     property_changed(name, value);     return  0 ; } 
property_set_impl函数主要用来对属性进行修改,并对以ro、net和persist开头的属性进行相应的处理。到这里,属性服务处理请求的源码就讲到这。
8.init进程总结 讲到这,总结起来init进程主要做了三件事:
参考资料:Android的init过程详解(一) Android启动过程深入解析 Android7.0解析Init.rc文件 Android 7.0 init.rc的一点改变 Android7.0 init进程源码分析 Android情景分析之属性服务