系统进程启动流程分析(一)

Android启动概览
众所周知,Android是谷歌开发的一款基于Linux的开源操作系统,下图所示为 Android 平台的主要组件

1. Linux 内核
Android 平台的基础是 Linux 内核。例如,Android Runtime (ART) 依靠 Linux 内核来执行底层功

能,例如线程和低层内存管理。
使用 Linux 内核可让 Android 利用主要安全功能,并且允许设备制造商为著名的内核开发硬件驱动程
序。
2. 硬件抽象层 (HAL)
硬件抽象层 (HAL) 提供标准界面,向更高级别的 Java API 框架显示设备硬件功能。HAL 包含多个
库模块,其中每个模块都为特定类型的硬件组件实现一个界面,例如相机或蓝牙模块。当框架 API
要求访问设备硬件时,Android 系统将为该硬件组件加载库模块。
3. Android Runtime
对于运行 Android 5.0(API 级别 21)或更高版本的设备,每个应用都在其自己的进程中运行,并
且有其自己的 Android Runtime (ART) 实例。ART 编写为通过执行 DEX 文件在低内存设备上运行
多个虚拟机,DEX 文件是一种专为 Android 设计的字节码格式,经过优化,使用的内存很少。编
译工具链(例如 Jack)将 Java 源代码编译为 DEX 字节码,使其可在 Android 平台上运行。
ART 的部分主要功能包括:
预先 (AOT) 和即时 (JIT) 编译
优化的垃圾回收 (GC)
在 Android 9(API 级别 28)及更高版本的系统中,支持将应用软件包中的 Dalvik Executable 格
式 (DEX) 文件转换为更紧凑的机器代码。
更好的调试支持,包括专用采样分析器、详细的诊断异常和崩溃报告,并且能够设置观察点以监控
特定字段
在 Android 版本 5.0(API 级别 21)之前,Dalvik 是 Android Runtime。如果您的应用在 ART 上
运行效果很好,那么它应该也可在 Dalvik 上运行,但反过来不一定。
Android 还包含一套核心运行时库,可提供 Java API 框架所使用的 Java 编程语言中的大部分功能,包括
一些 Java 8 语言功能。
4. 原生 C/C++ 库
许多核心 Android 系统组件和服务(例如 ART 和 HAL)构建自原生代码,需要以 C 和 C++ 编写的
原生库。Android 平台提供 Java 框架 API 以向应用显示其中部分原生库的功能。例如,您可以通
过 Android 框架的 Java OpenGL API 访问 OpenGL ES,以支持在应用中绘制和操作 2D 和 3D 图形。
如果开发的是需要 C 或 C++ 代码的应用,可以使用 Android NDK 直接从原生代码访问某些原生平台库。

5. Java API 框架
您可通过以 Java 语言编写的 API 使用 Android OS 的整个功能集。这些 API 形成创建 Android 应
用所需的构建块,它们可简化核心模块化系统组件和服务的重复使用,包括以下组件和服务:
丰富、可扩展的视图系统,可用以构建应用的 UI,包括列表、网格、文本框、按钮甚至可嵌入的网
络浏览器
资源管理器,用于访问非代码资源,例如本地化的字符串、图形和布局文件
通知管理器,可让所有应用在状态栏中显示自定义提醒
Activity 管理器,用于管理应用的生命周期,提供常见的导航返回栈
内容提供程序,可让应用访问其他应用(例如“联系人”应用)中的数据或者共享其自己的数据
开发者可以完全访问 Android 系统应用使用的框架 API。
6. 系统应用
Android 随附一套用于电子邮件、短信、日历、互联网浏览和联系人等的核心应用。平台随附的应
用与用户可以选择安装的应用一样,没有特殊状态。因此第三方应用可成为用户的默认网络浏览
器、短信 Messenger 甚至默认键盘(有一些例外,例如系统的“设置”应用)。
系统应用可用作用户的应用,以及提供开发者可从其自己的应用访问的主要功能。例如,如果您的应用
要发短信,您无需自己构建该功能,可以改为调用已安装的短信应用向您指定的接收者发送消息。

接下来,我们来看下Android系统启动的大概流程,如下图所示:

第一步: 启动电源以及系统启动

当电源按下,引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序到RAM,然后
执行

第二步:引导程序
引导程序是在Android操作系统开始运行前的一个小程序。引导程序是运行的第一个程序,因此它是针
对特定的主板与芯片的。设备制造商要么使用很受欢迎的引导程序比如redboot、uboot、qi
bootloader或者开发自己的引导程序,它不是Android操作系统的一部分。引导程序是OEM厂商或者运
营商加锁和限制的地方。
引导程序分两个阶段执行。
第一个阶段,检测外部的RAM以及加载对第二阶段有用的程序;
第二阶段,引导程序设置网络、内存等等。这些对于运行内核是必要的,为了达到特殊的目标,引导程
序可以根据配置参数或者输入数据设置内核。
Android引导程序可以在\bootable\bootloader\legacy\usbloader找到。传统的加载器包含两个文件,
需要在这里说明:
init.s初始化堆栈,清零BBS段,调用main.c的_main()函数;
main.c初始化硬件(闹钟、主板、键盘、控制台),创建linux标签

第三步:内核

Android内核与桌面linux内核启动的方式差不多。内核启动时,设置缓存、被保护存储器、计划列表,
加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第
一个进程
第四步:init进程
init进程是Linux系统中用户空间的第一个进程,进程号固定为1。Kernel启动后,在用户空间启动init进
程,并调用init中的main()方法执行init进程的职责。
第五步:启动Lancher App

init进程分析
其中init进程是Android系统中及其重要的第一个进程,接下来我们来看下init进程注意做了些什么
1. 创建和挂载启动所需要的文件目录
2. 初始化和启动属性服务
3. 解析init.rc配置文件并启动Zygote进程

// \system\core\init\init.cpp main() L545
/*
* 1.C++中主函数有两个参数,第一个参数argc表示参数个数,第二个参数是参数列表,也就是具体
的参数
* 2.init的main函数有两个其它入口,一是参数中有ueventd,进入ueventd_main,二是参数中
有watchdogd,进入watchdogd_main
*/
int main(int argc, char** argv) {
/*
  * 1.strcmp是String的一个函数,比较字符串,相等返回0
  * 2.C++中0也可以表示false
  * 3.basename是C库中的一个函数,得到特定的路径中的最后一个'/'后面的内容,
  * 比如/sdcard/miui_recovery/backup,得到的结果是backup
  */
  if (!strcmp(basename(argv[0]), "ueventd")) {//当argv[0]的内容为ueventd
时,strcmp的值为0,!strcmp为1
//1表示true,也就执行ueventd_main,ueventd主要是负责设备节点的创建、权限设定等一
些列工作
  return ueventd_main(argc, argv);
 }
  if (!strcmp(basename(argv[0]), "watchdogd")) {//watchdogd俗称看门狗,用于
系统出问题时重启系统
    return watchdogd_main(argc, argv);
 }
  if (argc > 1 && !strcmp(argv[1], "subcontext")) {
    InitKernelLogging(argv);
    const BuiltinFunctionMap function_map;
    return SubcontextMain(argc, argv, &function_map);
 }
  if (REBOOT_BOOTLOADER_ON_PANIC) {
    InstallRebootSignalHandlers();//初始化重启系统的处理信号,内部通过
sigaction 注册信号,当监听到该信号时重启系统
 }
  bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);//查看是
否有环境变量INIT_SECOND_STAGE
  /*
  * 1.init的main方法会执行两次,由is_first_stage控制,first_stage就是第一阶段要
做的事
  */
  if (is_first_stage) {
    boot_clock::time_point start_time = boot_clock::now();
    // Clear the umask.
    umask(0);//清空文件权限
    clearenv();
    setenv("PATH", _PATH_DEFPATH, 1);
    // Get the basic filesystem setup we need put together in the
initramdisk
    // on / and then we'll let the rc file figure out the rest.
//mount是用来挂载文件系统的,mount属于Linux系统调用
    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));
    // Don't expose the raw commandline to unprivileged processes.
    chmod("/proc/cmdline", 0440);//用于修改文件/目录的读写权限
    gid_t groups[] = { AID_READPROC };
    setgroups(arraysize(groups), groups);// 用来将list 数组中所标明的组加入
到目前进程的组设置中
    mount("sysfs", "/sys", "sysfs", 0, NULL);
    mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
//mknod用于创建Linux中的设备文件
    mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
    if constexpr (WORLD_WRITABLE_KMSG) {
      mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11));
   }
    mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
    mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
    // Mount staging areas for devices managed by vold
    // See storage config details at
http://source.android.com/devices/storage/
    mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
       "mode=0755,uid=0,gid=1000");
    // /mnt/vendor is used to mount vendor-specific partitions that can
not be
    // part of the vendor partition, e.g. because they are mounted
read-write.
    mkdir("/mnt/vendor", 0755);
    // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can
actually
    // talk to the outside world...
    InitKernelLogging(argv);//将标准输入输出重定向到"/sys/fs/selinux/null"
    LOG(INFO) << "init first stage started!";
    if (!DoFirstStageMount()) {
      LOG(FATAL) << "Failed to mount required partitions early ...";
   }
    //Avb即Android Verfied boot,功能包括Secure Boot, verfying boot 和 dm-
verity,
    //原理都是对二进制文件进行签名,在系统启动时进行认证,确保系统运行的是合法的二进
制镜像文件。
    //其中认证的范围涵盖:bootloader,boot.img,system.img
    SetInitAvbVersionInRecovery();//在刷机模式下初始化avb的版本,不是刷机模式
直接跳过
    // Enable seccomp if global boot option was passed (otherwise it is
enabled in zygote).
    global_seccomp();
    // Set up SELinux, loading the SELinux policy.
    SelinuxSetupKernelLogging();
    SelinuxInitialize();//加载SELinux policy,也就是安全策略,
    // We're in the kernel domain, so re-exec init to transition to the
init domain now
    // that the SELinux policy has been loaded.
/*
    * 1.这句英文大概意思是,我们执行第一遍时是在kernel domain,所以要重新执行
init文件,切换到init domain,
    * 这样SELinux policy才已经加载进来了
    * 2.后面的security_failure函数会调用panic重启系统
    */
    if (selinux_android_restorecon("/init", 0) == -1) {
      PLOG(FATAL) << "restorecon failed of /init failed";
   }
    setenv("INIT_SECOND_STAGE", "true", 1);
    static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
   uint64_t start_ms = start_time.time_since_epoch().count() /
kNanosecondsPerMillisecond;
    setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
    char* path = argv[0];
    char* args[] = { path, nullptr };
    execv(path, args);//重新执行main方法,进入第二阶段
    // execv() only returns if an error happened, in which case we
    // panic and never fall through this conditional.
    PLOG(FATAL) << "execv(\"" << path << "\") failed";
 }
  // At this point we're in the second stage of init.
  InitKernelLogging(argv);
  LOG(INFO) << "init second stage started!";
  // Set up a session keyring that all processes will have access to. It
  // will hold things like FBE encryption keys. No process should
override
  // its session keyring.
  keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);
  // Indicate that booting is in progress to background fw loaders, etc.
  close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
  property_init();//初始化属性系统,并从指定文件读取属性
  // If arguments are passed both on the command line and in DT,
  // properties set in DT always have priority over the command-line
ones.
//接下来的一系列操作都是从各个文件读取一些属性,然后通过property_set设置系统属性
  // If arguments are passed both on the command line and in DT,
  // properties set in DT always have priority over the command-line
ones.
  /*
  * 1.这句英文的大概意思是,如果参数同时从命令行和DT传过来,DT的优先级总是大于命令行
的
  * 2.DT即device-tree,中文意思是设备树,这里面记录自己的硬件配置和系统运行参数,参
考http://www.wowotech.net/linux_kenrel/why-dt.html
  */
  process_kernel_dt();//处理DT属性
  process_kernel_cmdline();//处理命令行属性
  // Propagate the kernel variables to internal variables
  // used by init as well as the current required properties.
  export_kernel_boot_props();//处理其他的一些属性
  // Make the time that init started available for bootstat to log.
  property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
  property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
  // Set libavb version for Framework-only OTA match in Treble build.
  const char* avb_version = getenv("INIT_AVB_VERSION");
  if (avb_version) property_set("ro.boot.avb_version", avb_version);
  // Clean up our environment.
 unsetenv("INIT_SECOND_STAGE");//清空这些环境变量,因为之前都已经存入到系统属性
中去了
  unsetenv("INIT_STARTED_AT");
  unsetenv("INIT_SELINUX_TOOK");
  unsetenv("INIT_AVB_VERSION");
  // Now set up SELinux for second stage.
  SelinuxSetupKernelLogging();
  SelabelInitialize();
  SelinuxRestoreContext();
  epoll_fd = epoll_create1(EPOLL_CLOEXEC);//创建epoll实例,并返回epoll的文件
描述符
  if (epoll_fd == -1) {
    PLOG(FATAL) << "epoll_create1 failed";
 }
  sigchld_handler_init();//主要是创建handler处理子进程终止信号,创建一个匿名
socket并注册到epoll进行监听
  if (!IsRebootCapable()) {
    // If init does not have the CAP_SYS_BOOT capability, it is running
in a container.
    // In that case, receiving SIGTERM will cause the system to shut
down.
    InstallSigtermHandler();
 }
  property_load_boot_defaults();//从文件中加载一些属性,读取usb配置
  export_oem_lock_status();//设置ro.boot.flash.locked 属性
  start_property_service();//开启一个socket监听系统属性的设置
  set_usb_controller();//设置sys.usb.controller 属性
  const BuiltinFunctionMap function_map;//方法映射 “class_start”->
"do_class_start"
/*
  * 1.C++中::表示静态方法调用,相当于java中static的方法
  */
  Action::set_function_map(&function_map);//将function_map存放到Action中作
为成员属性
  subcontexts = InitializeSubcontexts();
  ActionManager& am = ActionManager::GetInstance();
  ServiceList& sm = ServiceList::GetInstance();
  LoadBootScripts(am, sm);//解析xxx.rc
  // Turning this on and letting the INFO logging be discarded adds 0.2s
to
  // Nexus 9 boot time, so it's disabled by default.
  if (false) DumpState();//打印一些当前Parser的信息,默认是不执行的
  am.QueueEventTrigger("early-init");//QueueEventTrigger用于触发Action,这里
触发 early-init事件
  // Queue an action that waits for coldboot done so we know ueventd has
set up all of /dev...
  am.QueueBuiltinAction(wait_for_coldboot_done_action,
"wait_for_coldboot_done");//QueueBuiltinAction用于添加Action,第一个参数是
Action要执行的Command,第二个是Trigger
  // ... so that we can start queuing up actions that require stuff from
/dev.
  am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction,
"MixHwrngIntoLinuxRng");
  am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
  am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
  am.QueueBuiltinAction(keychord_init_action, "keychord_init");
  am.QueueBuiltinAction(console_init_action, "console_init");
  // Trigger all the boot actions to get us started.
  am.QueueEventTrigger("init");
  // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or
/dev/random
  // wasn't ready immediately after wait_for_coldboot_done
  am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction,
"MixHwrngIntoLinuxRng");
  // Don't mount filesystems or start core system services in charger
mode.
  std::string bootmode = GetProperty("ro.bootmode", "");
  if (bootmode == "charger") {
    am.QueueEventTrigger("charger");
 } else {
    am.QueueEventTrigger("late-init");
 }
  // Run all property triggers based on current state of the properties.
  am.QueueBuiltinAction(queue_property_triggers_action,
"queue_property_triggers");
  while (true) {
    // By default, sleep until something happens.
    int epoll_timeout_ms = -1; //epoll超时时间,相当于阻塞时间
    if (do_shutdown && !shutting_down) {
      do_shutdown = false;
      if (HandlePowerctlMessage(shutdown_command)) {
        shutting_down = true;
     }
   }
    if (!(waiting_for_prop || Service::is_exec_service_running())) {
      am.ExecuteOneCommand();//执行一个command
   }
/*
     * 1.waiting_for_prop和IsWaitingForExec都是判断一个Timer为不为空,相当
于一个标志位
     * 2.waiting_for_prop负责属性设置,IsWaitingForExe负责service运行
     * 3.当有属性设置或Service开始运行时,这两个值就不为空,直到执行完毕才置为空
     * 4.其实这两个判断条件主要作用就是保证属性设置和service启动的完整性,也可以
说是为了同步
     */
    if (!(waiting_for_prop || Service::is_exec_service_running())) {
      if (!shutting_down) {
       auto next_process_restart_time = RestartProcesses();//重启服
务
        // If there's a process that needs restarting, wake up in
time for that.
        if (next_process_restart_time) {
          epoll_timeout_ms =
std::chrono::ceil<std::chrono::milliseconds>(
                     *next_process_restart_time -
boot_clock::now())
                     .count();
          if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
       }
     }
      // If there's more work to do, wake up again immediately.
      if (am.HasMoreCommands()) epoll_timeout_ms = 0;//当还有命令要执行
时,将epoll_timeout_ms设置为0
   }
    epoll_event ev;
/*
    * 1.epoll_wait与epoll_create1、epoll_ctl是一起使用的
    * 2.epoll_create1用于创建epoll的文件描述符,epoll_ctl、epoll_wait都把它
创建的fd作为第一个参数传入
    * 3.epoll_ctl用于操作epoll,EPOLL_CTL_ADD:注册新的fd到epfd中,
EPOLL_CTL_MOD:修改已经注册的fd的监听事件,EPOLL_CTL_DEL:从epfd中删除一个fd;
    * 4.epoll_wait用于等待事件的产生,epoll_ctl调用EPOLL_CTL_ADD时会传入需要
监听什么类型的事件,
    *  比如EPOLLIN表示监听fd可读,当该fd有可读的数据时,调用epoll_wait经过
epoll_timeout_ms时间就会把该事件的信息返回给&ev
    */
    int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1,
epoll_timeout_ms));
    if (nr == -1) {
      PLOG(ERROR) << "epoll_wait failed";
   } else if (nr == 1) {
     ((void (*)()) ev.data.ptr)();//当有event返回时,取出
ev.data.ptr(之前epoll_ctl注册时的回调函数),直接执行
//在signal_handler_init和start_property_service有注册两个fd的监
听,一个用于监听SIGCHLD(子进程结束信号),一个用于监听属性设置
   }
 }
  return 0;
}

init.rc解析
init.rc是一个非常重要的配置文件,它是由Android初始化语言(Android Init Language)编写的脚
本,它主要包含五种类型语句:Action(Action中包含了一系列的Command)、Commands(init语言
中的命令)、Services(由init进程启动的服务)、Options(对服务进行配置的选项)和Import(引入
其他配置文件)。init.rc的配置代码如下所示。

# \system\core\rootdir\init.rc
on init # L41
 sysclktz 0
 # Mix device-specific information into the entropy pool
 copy /proc/cmdline /dev/urandom
 copy /default.prop /dev/urandom
 ...
on <trigger> [&& <trigger>]* //设置触发器
  <command>
  <command> //动作触发之后要执行的命令
 
service <name> <pathname> [ <argument> ]* //<service的名字><执行程序路径><传递参
数>
  <option> //Options是Services的参数配置. 它们影响Service如何运行及运行时机
  group <groupname> [ <groupname>\* ] //在启动Service前将group改为第一个
groupname,第一个groupname是必须有的,
  //默认值为root(或许默认值是无),第二个groupname可以不设置,用于追加组(通过
setgroups)
  priority <priority> //设置进程优先级. 在-20~19之间,默认值是0,能过
setpriority实现
  socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]//创建
一个unix域的socket,名字叫/dev/socket/name , 并将fd返回给Service. type 只能是
"dgram", "stream" or "seqpacket".
   ...  

Action
Action: 通过触发器trigger,即以on开头的语句来决定执行相应的service的时机,具体有如下时机:

  • on early-init; 在初始化早期阶段触发;
  • on init; 在初始化阶段触发;
  • on late-init; 在初始化晚期阶段触发;
  • on boot/charger: 当系统启动/充电时触发,还包含其他情况,此处不一一列举;
  • on property:=: 当属性值满足条件时触发

Service
服务Service,以 service开头,由init进程启动,一般运行在init的一个子进程,所以启动service前需要
判断对应的可执行文件是否存在。init生成的子进程,定义在rc文件,其中每一个service在启动时会通过
fork方式生成子进程。
例如:  service servicemanager /system/bin/servicemanager 代表的是服务名为
servicemanager,服务执行的路径为/system/bin/servicemanager。

Command
下面列举常用的命令

  • class_start <service_class_name>: 启动属于同一个class的所有服务;
  • start <service_name>: 启动指定的服务,若已启动则跳过;
  • stop <service_name>: 停止正在运行的服务
  • setprop :设置属性值
  • mkdir :创建指定目录
  • symlink <sym_link>: 创建连接到的<sym_link>符号链接;
  • write : 向文件path中写入字符串;
  • exec: fork并执行,会阻塞init进程直到程序完毕;
  • exprot :设定环境变量;
  • loglevel :设置log级别

Options
Options是Service的可选项,与service配合使用

  • disabled: 不随class自动启动,只有根据service名才启动;
  • oneshot: service退出后不再重启;
  • user/group: 设置执行服务的用户/用户组,默认都是root;
  • class:设置所属的类名,当所属类启动/退出时,服务也启动/停止,默认为default;
  • onrestart:当服务重启时执行相应命令;
  • socket: 创建名为 /dev/socket/<name> 的socket
  • critical: 在规定时间内该service不断重启,则系统会重启并进入恢复模式

default: 意味着disabled=false,oneshot=false,critical=false。

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --
start-system-server
 class main
 priority -20
 user root
 group root readproc reserved_disk
 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
 onrestart restart wificond
 writepid /dev/cpuset/foreground/tasks

service解析流程

// \system\core\init\init.cpp LoadBootScripts() L110
static void LoadBootScripts(ActionManager& action_manager, ServiceList&
service_list) {
  Parser parser = CreateParser(action_manager, service_list);//创建解析器
  std::string bootscript = GetProperty("ro.boot.init_rc", "");
  if (bootscript.empty()) {
    parser.ParseConfig("/init.rc");
    if (!parser.ParseConfig("/system/etc/init")) {
      late_import_paths.emplace_back("/system/etc/init");
   }
    if (!parser.ParseConfig("/product/etc/init")) {
      late_import_paths.emplace_back("/product/etc/init");
   }
    if (!parser.ParseConfig("/odm/etc/init")) {
      late_import_paths.emplace_back("/odm/etc/init");
   }
    if (!parser.ParseConfig("/vendor/etc/init")) {
      late_import_paths.emplace_back("/vendor/etc/init");
   }
 } else {
    parser.ParseConfig(bootscript);//开始解析
 }
// \system\core\init\init.cpp CreateParser() L100
Parser CreateParser(ActionManager& action_manager, ServiceList&
service_list) {
  Parser parser;
  parser.AddSectionParser("service", std::make_unique<ServiceParser>
(&service_list, subcontexts));//service解析
  parser.AddSectionParser("on", std::make_unique<ActionParser>
(&action_manager, subcontexts));
  parser.AddSectionParser("import", std::make_unique<ImportParser>
(&parser));
  return parser;
}
// \system\core\init\parser.cpp ParseData() L 42
void Parser::ParseData(const std::string& filename, const std::string& data,
size_t* parse_errors) {
 ...
  for (;;) {
    switch (next_token(&state)) {
      case T_EOF:
        end_section();
        return;
      case T_NEWLINE:
       ...
        if (section_parsers_.count(args[0])) {
          end_section();
          section_parser = section_parsers_[args[0]].get();
          section_start_line = state.line;
          if (auto result =
              section_parser->ParseSection(std::move(args),
filename, state.line);// L95
            !result) {
           (*parse_errors)++;
            LOG(ERROR) << filename << ": " << state.line << ": "
<< result.error();
            section_parser = nullptr;
         }
       } else if (section_parser) {
          if (auto result = section_parser-
>ParseLineSection(std::move(args), state.line);// L102
            !result) {
           (*parse_errors)++;
            LOG(ERROR) << filename << ": " << state.line << ": "
<< result.error();
         }
       }
        args.clear();
        break;
      case T_TEXT:
        args.emplace_back(state.text);
        break;
   }
 }
}
// \system\core\init\service.cpp ParseSection() L1180
Result<Success> ServiceParser::ParseSection(std::vector<std::string>&& args,
                      const std::string& filename, int
line) {
  if (args.size() < 3) {
    return Error() << "services must have a name and a program";
 }
  const std::string& name = args[1];
  if (!IsValidName(name)) {
    return Error() << "invalid service name '" << name << "'";
 }
  Subcontext* restart_action_subcontext = nullptr;
  if (subcontexts_) {
    for (auto& subcontext : *subcontexts_) {
      if (StartsWith(filename, subcontext.path_prefix())) {
        restart_action_subcontext = &subcontext;
        break;
     }
   }
 }
  std::vector<std::string> str_args(args.begin() + 2, args.end());
  service_ = std::make_unique<Service>(name, restart_action_subcontext,
str_args);//构建出一个service对象
  return Success();
}
// \system\core\init\service.cpp ParseLineSection() L1206
Result<Success> ServiceParser::ParseLineSection(std::vector<std::string>&&
args, int line) {
  return service_ ? service_->ParseLine(std::move(args)) : Success();
}
// \system\core\init\service.cpp EndSection() L1210
Result<Success> ServiceParser::EndSection() {
  if (service_) {
    Service* old_service = service_list_->FindService(service_->name());
    if (old_service) {
      if (!service_->is_override()) {
        return Error() << "ignored duplicate definition of service
'" << service_->name()
               << "'";
     }
      service_list_->RemoveService(*old_service);
      old_service = nullptr;
   }
    service_list_->AddService(std::move(service_));
}
  return Success();
}
// \system\core\init\service.cpp AddService() L1082
void ServiceList::AddService(std::unique_ptr<Service> service) {
  services_.emplace_back(std::move(service));
}
上面解析完成后,接下来就是启动Service,这里我们以启动Zygote来分析
# \system\core\rootdir\init.rc L680
on nonencrypted
 class_start main //class_start是一个命令,通过do_class_start函数处理
 class_start late_start
// \system\core\init\builtins..cpp do_class_start() L101
static Result<Success> do_class_start(const BuiltinArguments& args) {
  // Starting a class does not start services which are explicitly
disabled.
  // They must be started individually.
  for (const auto& service : ServiceList::GetInstance()) {
    if (service->classnames().count(args[1])) {
      if (auto result = service->StartIfNotDisabled(); !result) {
        LOG(ERROR) << "Could not start service '" << service->name()
             << "' as part of class '" << args[1] << "': " <<
result.error();
     }
   }
 }
  return Success();
}
// \system\core\init\service.cpp StartIfNotDisabled() L977
Result<Success> Service::StartIfNotDisabled() {
  if (!(flags_ & SVC_DISABLED)) {
    return Start();
 } else {
    flags_ |= SVC_DISABLED_START;
 }
  return Success();
}
// \system\core\init\service.cpp Start() L785
Result<Success> Service::Start() {
 //如果service已经运行,则不启动
  if (flags_ & SVC_RUNNING) {
    if ((flags_ & SVC_ONESHOT) && disabled) {
      flags_ |= SVC_RESTART;
   }
    // It is not an error to try to start a service that is already
running.
    return Success();
}
 ...
  //判断需要启动的service的对应的执行文件是否存在,不存在则不启动service
  struct stat sb;
  if (stat(args_[0].c_str(), &sb) == -1) {
    flags_ |= SVC_DISABLED;
    return ErrnoError() << "Cannot find '" << args_[0] << "'";
 }
  std::string scon;
  if (!seclabel_.empty()) {
    scon = seclabel_;
 } else {
    auto result = ComputeContextFromExecutable(args_[0]);
    if (!result) {
      return result.error();
   }
    scon = *result;
 }
  LOG(INFO) << "starting service '" << name_ << "'...";
 //如果子进程没有启动,则调用fork函数创建子进程
  pid_t pid = -1;
  if (namespace_flags_) {
    pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
 } else {
    pid = fork();
 }
  if (pid == 0) {//当期代码逻辑在子进程中运行
    umask(077);
  
 //调用execv函数,启动sevice子进程
    if (!ExpandArgsAndExecv(args_)) {
      PLOG(ERROR) << "cannot execve('" << args_[0] << "')";
   }
    _exit(127);
 }
  return Success();
}

Zygote概叙
Zygote中文翻译为“受精卵”,正如其名,它主要用于孵化子进程。在Android系统中有以下两种程序:
java应用程序,主要基于ART虚拟机,所有的应用程序apk都属于这类native程序,也就是利用C或C++语
言开发的程序,如bootanimation。所有的Java应用程序进程及系统服务SystemServer进程都由Zygote
进程通过Linux的fork()函数孵化出来的,这也就是为什么把它称为Zygote的原因,因为他就像一个受精
卵,孵化出无数子进程,而native程序则由Init程序创建启动。Zygote进程最初的名字不是“zygote”而是
“app_process”,这个名字是在Android.mk文件中定义的
Zgyote是Android中的第一个art虚拟机,他通过socket的方式与其他进程进行通信。这里的“其他进程”
其实主要是系统进程——SystemServer

Zygote是一个C/S模型,Zygote进程作为服务端,它主要负责创建Java虚拟机,加载系统资源,启
动SystemServer进程,以及在后续运行过程中启动普通的应用程序,其他进程作为客户端向它发
出“孵化”请求,而Zygote接收到这个请求后就“孵化”出一个新的进程。比如,当点击Launcher里的
应用程序图标去启动一个新的应用程序进程时,这个请求会到达框架层的核心服务
ActivityManagerService中,当AMS收到这个请求后,它通过调用Process类发出一个“孵化”子进
程的Socket请求,而Zygote监听到这个请求后就立刻fork一个新的进程出来

Zygote触发过程
1. init.zygoteXX.rc

import /init.${ro.zygote}.rc

${ro.zygote} 会被替换成 ro.zyogte 的属性值,这个是由不同的硬件厂商自己定制的,
有四个值,
zygote32: zygote 进程对应的执行程序是 app_process (纯 32bit 模式)
zygote64: zygote 进程对应的执行程序是 app_process64 (纯 64bit 模式)
zygote32_64: 启动两个 zygote 进程 (名为 zygote 和 zygote_secondary),对应的执行程序分别
是 app_process32 (主模式)
zygote64_32: 启动两个 zygote 进程 (名为 zygote 和 zygote_secondary),对应的执行程序分别
是 app_process64 (主模式)、app_process32
2. start zygote
位置:system\core\rootdir\init.rc 560

# It is recommended to put unnecessary data/ initialization from post-fs-
data
# to start-zygote in device's init.rc to unblock zygote start.
on zygote-start && property:ro.crypto.state=unencrypted
 # A/B update verifier that marks a successful boot.
 exec_start update_verifier_nonencrypted
 start netd
 start zygote
 start zygote_secondary
on zygote-start && property:ro.crypto.state=unsupported
 # A/B update verifier that marks a successful boot.
 exec_start update_verifier_nonencrypted
 start netd
 start zygote
 start zygote_secondary
on zygote-start && property:ro.crypto.state=encrypted &&
property:ro.crypto.type=file
 # A/B update verifier that marks a successful boot.
 exec_start update_verifier_nonencrypted
 start netd
 start zygote
 start zygote_secondary

zygote-start 是在 on late-init 中触发的

# Mount filesystems and start core system services. 
on late-init
 trigger early-fs
 # Mount fstab in init.{$device}.rc by mount_all command. Optional
parameter
 # '--early' can be specified to skip entries with 'latemount'.
 # /system and /vendor must be mounted by the end of the fs stage,
 # while /data is optional.
 trigger fs
 trigger post-fs
 # Mount fstab in init.{$device}.rc by mount_all with '--late' parameter
 # to only mount entries with 'latemount'. This is needed if '--early' is
 # specified in the previous mount_all command on the fs stage.
 # With /system mounted and properties form /system + /factory available,
 # some services can be started.
 trigger late-fs
 # Now we can mount /data. File encryption requires keymaster to decrypt
 # /data, which in turn can only be loaded when system properties are
present.
 trigger post-fs-data
 # Now we can start zygote for devices with file based encryption
 trigger zygote-start #
zygote-start 是在 on late-init 中触发的
 # Load persist properties and override properties (if enabled) from
/data.
 trigger load_persist_props_action
 # Remove a file to wake up anything waiting for firmware.
 trigger firmware_mounts_complete
 trigger early-boot
 trigger boot
if (bootmode == "charger") {
    am.QueueEventTrigger("charger");
 } else {
    am.QueueEventTrigger("late-init");
 }

3. app_processXX
位置\frameworks\base\cmds\app_process\

app_process_src_files := \
 app_main.cpp \
LOCAL_SRC_FILES:= $(app_process_src_files)
...
LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64

Zygote启动过程
位置\frameworks\base\cmds\app_process\app_main.cpp
在app_main.cpp的main函数中,主要做的事情就是参数解析. 这个函数有两种启动模式:
1. 一种是zygote模式,也就是初始化zygote进程,传递的参数有--start-system-server --socket-
name=zygote,前者表示启动SystemServer,后者指定socket的名称
2. 一种是application模式,也就是启动普通应用程序,传递的参数有class名字以及class带的参数
两者最终都是调用AppRuntime对象的start函数,加载ZygoteInit或RuntimeInit两个Java类,并将之前
整理的参数传入进去

app_process

// \frameworks\base\cmds\app_process\app_main.cpp main() L280
if (strcmp(arg, "--zygote") == 0) {
      zygote = true;
      niceName = ZYGOTE_NICE_NAME;
   } else if (strcmp(arg, "--start-system-server") == 0) {
      startSystemServer = true;
   } else if (strcmp(arg, "--application") == 0) {
      application = true;
   }
// L349   
if (zygote) {
   //这些Java的应用都是通过 AppRuntime.start(className)开始的
   //其实AppRuntime是AndroidRuntime的子类,它主要实现了几个回调函数,而start()方
法是实现在AndroidRuntime这个方法类里
    runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
 } else if (className) {
    runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
 }

app_process 里面定义了三种应用程序类型:
1. Zygote: com.android.internal.os.ZygoteInit
2. System Server, 不单独启动,而是由Zygote启动
3. 其他指定类名的Java 程序

// \frameworks\base\core\jni\androidRuntime.cpp
class AppRuntime : public AndroidRuntime
{
public:
  AppRuntime(char* argBlockStart, const size_t argBlockLength)
   : AndroidRuntime(argBlockStart, argBlockLength)
   , mClass(NULL)
 {
 }
  void setClassNameAndArgs(const String8& className, int argc, char *
const *argv) {
    mClassName = className;
    for (int i = 0; i < argc; ++i) {
      mArgs.add(String8(argv[i]));
   }
 }
  virtual void onVmCreated(JNIEnv* env)
 {
    if (mClassName.isEmpty()) {
      return; // Zygote. Nothing to do here.
   }
    /*
    * This is a little awkward because the JNI FindClass call uses the
    * class loader associated with the native method we're executing
in.
    * If called in onStarted (from RuntimeInit.finishInit because we're
    * launching "am", for example), FindClass would see that we're
calling
    * from a boot class' native method, and so wouldn't look for the
class
    * we're trying to look up in CLASSPATH. Unfortunately it needs to,
    * because the "am" classes are not boot classes.
    *
    * The easiest fix is to call FindClass here, early on before we
start
    * executing boot class Java code and thereby deny ourselves access
to
    * non-boot classes.
    */
    char* slashClassName = toSlashClassName(mClassName.string());
    mClass = env->FindClass(slashClassName);
    if (mClass == NULL) {
      ALOGE("ERROR: could not find class '%s'\n",
mClassName.string());
   }
    free(slashClassName);
    mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
 }
  virtual void onStarted()
 {
    sp<ProcessState> proc = ProcessState::self();
    ALOGV("App process: starting thread pool.\n");
    proc->startThreadPool();
    AndroidRuntime* ar = AndroidRuntime::getRuntime();
    ar->callMain(mClassName, mClass, mArgs);
    IPCThreadState::self()->stopProcess();
    hardware::IPCThreadState::self()->stopProcess();
 }
  virtual void onZygoteInit()
 {
    sp<ProcessState> proc = ProcessState::self();
    ALOGV("App process: starting thread pool.\n");
    proc->startThreadPool();
 }
  virtual void onExit(int code)
 {
    if (mClassName.isEmpty()) {
      // if zygote
      IPCThreadState::self()->stopProcess();
      hardware::IPCThreadState::self()->stopProcess();
   }
    AndroidRuntime::onExit(code);
 }
  String8 mClassName;
  Vector<String8> mArgs;
  jclass mClass;
};
}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值