Blog icon indicating copy to clipboard operation
Blog copied to clipboard

Android 系统启动流程

Open RWebRTC opened this issue 8 years ago • 2 comments

转载自

枫寒 - 简书,略作修改。本文包含三个部分:综述 Android 系统启动Android 的 init 进程启动过程Zygote 的启动过程

正文

Android 系统启动

对于Android系统整个启动过程来说,基本可以划分成三个阶段:Bootloader 引导、Linux kernel 启动、Android 启动。如下的流程图可以看出三个阶段的执行顺序和联系(一张图看不懂就看三张图)。

112356615

112356709

2848265-3

原图 naotu baidu com_file_215b19ae3f2187344a484be8a67a4e82 token e5be85bce42717c0

Bootloader 引导

BootLoader是在操作系统运行之前运行的一段程序,它可以将系统的软硬件环境带到一个合适状态,为运行操作系统做好准备。它的任务就是把 OS 拉起来运行,启动 Linux 内核,我们对这一块的内容并不太注意。

Linux kernel启动

Linex kernel启动后会初始化环境/驱动等,接着会启动 init的进程。

1.Init进程的启动

init进程,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序 init 的方式,启动 init 进程。

启动过程是代码system\core\init\init.cpp的 main 函数的执行过程。在函数中执行了:文件夹建立,挂载,rc文件解析,属性设置,启动服务,执行动作,socket 监听等。在rc文件解析中会启动 ServiceManager 服务和 Zygote 进程。

2. ServiceManager 服务

ServiceManager 用来管理系统中所有的 binder service,不管是本地的c++实现的还是java语言实现的都需要这个进程来统一管理,最主要的管理就是,注册添加服务,获取服务。所有的 Service 使用前都必须先在 ServiceManager 中进行注册。

3. Zygote 进程的启动

Zygote 进程启动才算建立起真正的 Android 的运行空间。不过 Init 进程不会直接启动 Zygote 进程,而是使用 app_process 命令来通过 Android Runtime 来启动,Android Runtime 会启动第一个 Davlik 虚拟机,并调用 Zygote 的 main 方法,启动服务。dir/system/core/rootdir/init.zygote32.rc:

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

Android启动

1. Zygote 启动

Zygote 从 frameworks/base/cmds/app_process/app_main.cpp 中的 main 开始,并建立 Android Run Time。

//建立 Android runtime
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
// 然后调用 Java 的 ZygoteInit
// dir/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
// 随后
//登记Listen端口
registerZygoteSocket();
//启动SystemServer服务
startSystemServer();

2. SystemServer启动

在上一步中调用了 startSystemServer, Zygote 上 fork 了一个进程:com.android.server.SystemServer。于是 Java 中的 SystemServer 就建立起来了,SystemServer 的 main 函数中会启动一些服务:

startBootstrapServices();
startCoreServices();
startOtherServices();

在startBootstrapServices()中看到

mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();

ActivityManagerService.Lifecycle 是 ActivityManagerService 的静态内部类, 持有 ActivityManagerService 实例。所以 ActivityManagerService 是在这里被启动起来的。

当然还有很多的其他服务(PackageManagerService、PowerManagerService、DisplayManagerService、BatteryService等)也都会被启动起来。

在所有的服务启动完成后,会调用Service.systemReady()来通知各对应的服务,系统已经就绪。

3.ActivityManagerService启动

在 ActivityManagerService 的 systemReady() 方法中有:

startHomeActivityLocked();
mStackSupervisor.startHomeActivity()

这样Home程序被启动起来,整个android的启动过程就完成了,进入用户界面。


霸 气 的 分 割 线

Android 的 init 进程启动过程

0. 前言

Android 中的内核启动后,kernel 会启动第一个用户级别的进程:init,它是一个由内核启动的第一个用户级进程。我们可以通过adb shell ps | grep init来查看到他的 pid 为 1。接下来从源码的角度看看init进程启动的时候做了什么?

init 进程的源码在 android 源码的: dir/system/core/init 目录中。我们看到该目录下有一个 Android.mk 文件,至少看到如下内容,告诉我们会生成一个 init 的的可执行文件。

LOCAL_MODULE:= init
include $(BUILD_EXECUTABLE)

而 init 的入口 main 函数是在 init.cpp 文件中定义的。

1. 入口

1. 命令行解析

if (!strcmp(basename(argv[0]), "ueventd")) {    
      return ueventd_main(argc, argv);
}
if (!strcmp(basename(argv[0]), "watchdogd")) {    
      return watchdogd_main(argc, argv);
}

watchdog 和 uevent 命令已经集成到了 init, 它们在 /sbin 目录,是一个链接文件,直接链接到 /init,所以当执行 /sbin/eventd 或 /sbin/watchdogd 时,将会进入对应的 ueventd_main 或 watchdogd_main 入口点。ueventd 守护进程负责解析 /ueventd.rc 文件,并创建相应的设备结点等。watchdogd 守护进程负责定时向 "/dev/watchdog" 执行写操作,以判断系统是否正常运行。这两个进程不是本文讨论的重点,所以先忽略。

2. 挂载根文件系统的目录

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, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
mount("sysfs", "/sys", "sysfs", 0, NULL);
mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));

分别挂载 proc 和和 sysfs 文件系统到 /proc 和 /sys 目录 close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000)); 在/dev目录创建一个空文件 .booting 来表示正在执行初始化 InitKernelLogging(argv); 重定向标准输入,标准输出,标准错误输出到 /dev/null selinux_initialize(is_first_stage) 加载SELinux策略, 后面有一些初始化文件上下文的操作等

3. 解析 init.rc 文件

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");
  • 3.1 init.rc 文件是以块(section)为单位组织的,一个 section 包含多行。section 分为两大类:分别为“服务(service)”和“行为(action)”。

  • 3.2 “服务”块以关键字“service”开始,表示启动某个进程的方式和参数,“行为”块以关键字“on”开始,表示一堆命令的集合。每个块以关键字“service”或“on”开始,直到下一个“on”或“service”结束,中间所有行都属于这个“块”。

  • 3.3 上面在解析 init.rc 文件时使用了 Parser 类(在init目录下的init_parser.h中定义), 初始化 ServiceParser 用来解析 “service”块,ActionParser 用来解析"on"块,ImportParser 用来解析“import”块,“import”是用来引入一个 init 配置文件,来扩展当前配置的。

  • 3.4 parser 解析 init.rc 文件,/init.rc 文件是 dir/system/core/rootdir/init.rc。

  • 3.5 dir/system/core/init/readme.txt 中对 init 文件中的所有关键字做了介绍,主要包含了 Actions, Commands, Services, Options, and Imports 等

  • 3.6 在 ParseConfig 解析完 init 脚本后,init会依次执行几个重要的阶段:

    3.6.1 on early-init阶段

      am.QueueEventTrigger("early-init"); 执行 on early-init 内容,主要包括 start ueventd 等
    

    3.6.2. on init 阶段

      am.QueueEventTrigger("init"); 执行 on init 内容,主要包括 创建/挂载一些目录,以及 symlink 等
    

    3.6.3. on charger/late-init阶段

      ```
       // Don't mount filesystems or start core system services in charger mode.
       std::string bootmode = property_get("ro.bootmode");
       if (bootmode == "charger") {
           am.QueueEventTrigger("charger");
       } else {
           am.QueueEventTrigger("late-init");
       }
      ```
    

    如果是充电模式下启动 就会执行 on charger 内容, 否则执行 on late-init 内容,在 init.rc 的 on late-init 中看到很多 trigger(触发器),用于执行对应的 Action。

      ```
      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
    
      # 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
      ```
    

    从最后两行可以看出,late-init 触发了on early-boot 和 on boot 两个 Action。

    3.6.4. on boot 阶段在 on boot 的最后 class_start core 会启动 class 为核心的服务,这些服务包括 ueventd、logd、healthd、adbd(disabled)、lmkd(LowMemoryKiller)、servicemanager、vold、debuggerd、surfaceflinger、bootanim(disabled)等

    3.6.5. main 服务的启动

    在 main 函数后面的 while 循环中,调用 execute_one_command 依次执行操作队列中的命令

      ```
      while (true) {
          if (!waiting_for_exec) {
              am.ExecuteOneCommand();
              restart_processes();
          }
      }
      ```
    

    在 /init.rc 的开头部分

      ```
      import /init.environ.rc
      import /init.usb.rc
      import /init.${ro.hardware}.rc
      import /init.usb.configfs.rc
      import /init.${ro.zygote}.rc
      ```
    

    通过 ro.zygote 的属性 import 对应的 zygote 的 rc 文件,通过 adb shell getprop ro.zygote 查看得到 zygote64_32, 所以 import 的是 /init.zygote64_32.rc 文件,该文件中定义的 zygote 如下:

      ```
      service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
      class main
      priority -20
      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
      ```
    

    可以看到 zygote 的 class 是 main, 它是在 on nonencrypted 时被启动的

      ```
      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
      ```
    

    注:但在 Android 7.0 中,对该机制做了一些改变 。 单一的init*.rc,被拆分,服务根据其二进制文件的位置(/system,/vendor,/odm)定义到对应分区的etc/init目录中,每个服务一个 rc 文件。与该服务相关的触发器、操作等也定义在同一 rc 文件中。

      /system/etc/init,包含系统核心服务的定义,如 SurfaceFlinger、MediaServer、Logcatd 等。
      /vendor/etc/init, SOC 厂商针对 SOC 核心功能定义的一些服务。比如高通、MTK 某一款 SOC 的相关的服务。
      /odm/etc/init,OEM/ODM 厂商如小米、华为、OPP 其产品所使用的外设以及差异化功能相关的服务。
    

    查看 Android 7.0 虚拟机的 /system/etc/init 如下

    2848265-c235da5cec4a1208

    上面的 ServiceManager 这个服务也从 init.rc 中拆分出来了。

4. 启动完成

至此,init 进程已经启动完成,一些重要的服务如 core 服务和 main 服务也都启动起来,并启动了zygote(/system/bin/app_process64)进程,zygote 初始化时会创建虚拟机,启动 SystemServer 等,它的启动过程也是非常复杂。


霸 气 的 分 割 线

Zygote 的启动过程

0. 前言

上节文章的最后说到了 init 以 service 的方式启动了 Zygote 进程。这节文章主要讲 Zygote 进程的启动流程。

对于 Zygote 进程的描述如下:

在 Android 中,zygote 是整个系统创建新进程的核心。Zygote 进程在内部会先启动 Dalvik 虚拟机,继而加载一些必要的系统资源和系统类,最后进入一种监听状态。在后续的运作中,当其他系统模块(比如AMS)希望创建新进程时,只需向 Zygote 进程发出请求,Zygote 进程监听到该请求后,会相应地“分裂”出新的进程,于是这个新进程在初生之时,就先天具有了自己的 Dalvik 虚拟机以及系统资源。

1. 启动流程

/init.zygote64_32.rc 文件中启动 Zygote 的内容如下:

    service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    priority -20
    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

在 dir/system/core/rootdir/ 目录下可以看到 init.zygote32.rc、init.zygote32_64.rc、init.zygote64.rc、init.zygote64_32.rc 等文件,这是因为 Android5.0 开始支持 64 位的编译,所以 Zygote 进程本身也有 32 位和 64 位版本。

从上面定义看到Zygote进程的可执行文件是 frameworks/base/cmds/app_process/app_main.cpp。

接下来分析 main 函数的流程。

1.1. 创建 AppRuntime 对象 AppRuntime 是在 app_process 中定义的类,继承了系统的 AndroidRuntime 类,AndroidRuntime 类的主要作用是创建和初始化虚拟机。

1.2. 解析启动参数

  while (i < argc) {
    const char* arg = argv[i++];
    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;
    } else if (strncmp(arg, "--nice-name=", 12) == 0) {
        niceName.setTo(arg + 12);
    } else if (strncmp(arg, "--", 2) != 0) {
        className.setTo(arg);
        break;
    } else {
        --i;
        break;
    }
}

从 init.rc 文件中传入的参数是 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote,解析后:

zygote = true;
niceName = zygoe;
startSystemServer = true;

1.3. 执行 ZygoteInit 类

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;
}

Zygote 经过解析参数后为 true, 所以会执行 runtime.start("com.android.internal.os.ZygoteInit", args, zygote); AndroidRuntime 的 start 方法实现在 dir/frameworks/base/core/jni/AndroidRuntime.cpp 中,

/*

 * Start the Android runtime.  This involves starting the virtual machine
 * and calling the "static void main(String[] args)" method in the class
 * named by "className".
 *
 * Passes the main function two arguments, the class name and the specified
 * options string.
 */
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    // 启动虚拟机,注册jni等
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
    ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
    /* keep going */
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

#if 0
        if (env->ExceptionCheck())
            threadExitUncaughtException(env);
#endif
        }
    }
      ...
}

这个方法会启动 Android 运行环境,意味着它会启动 Android 虚拟机,并调用参数中 className 中的 main 方法。 从传入的 com.android.internal.os.ZygoteInit 类中找到 main 函数,即调用 ZygoteInit.java 类中的 main 方法。AndroidRuntime 及之前的方法都是 native 的方法,而此刻调用的 ZygoteInit.main 方法是 java 的方法,到这里我们就进入了 java 的世界。

调用示意图如下:

2848265-da92b5d71fba5c28

1.4. ZygoteInit 的 main 方法

ZygoteInit 定义在 dir/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java 中。

public static void main(String argv[]) {
    try {
        ...
        registerZygoteSocket(socketName);
        preload();
        if (startSystemServer) {
            startSystemServer(abiList, socketName);
        }
        runSelectLoop(abiList);
        ...
    } catch (MethodAndArgsCaller caller) {
        caller.run();
    } catch (RuntimeException ex) {
        Log.e(TAG, "Zygote died with exception", ex);
        closeServerSocket();
        throw ex;
    }
}

主要工作:

  • 注册Zygote的socket监听端口,应用接收启动应用程序的消息
  • 调用preload()方法加载系统资源,包括预加载类,Framework资源等
  • 调用startSystemServer()方法启动SystemServer进程
  • 调用runSelectLoop()方法进入监听和接收消息循环

可见SystemServer是Zygote启动的第一个进程。

以上学习了 Android 系统的启动流程。

RWebRTC avatar Nov 24 '16 07:11 RWebRTC

Great!

tingshuonitiao avatar Sep 15 '17 06:09 tingshuonitiao

cool

sbbqq avatar Apr 10 '19 08:04 sbbqq