Android深水区:Android系统启动

Android深水区:Android系统启动

开篇

对于Android系统,有一张大家都见过的系统架构图

Android系统.png

我们平时接触的Android应用开发及开源代码都位于最上层(Application层),对Android FrameWork层接触不多,但Android系统很多的精妙设计都处于FrameWork层及以下,要想理解Android系统则必须学习FrameWork层。本系列我将和大家一起开始FrameWork层的学习,我们将依次学习Android启动、Android跨进程Binder机制,Android四大组件启动过程。在学习过程中不仅会接触大量的Java层源码,由于Android系统底层是linux,因此学习过程中还会涉及一些linux知识及C++代码,为了不让大家陷入代码、纠于细节,本系列主要会从架构层面解释具体原理,对应节点会列出对应源码位置,有兴趣的同学可以去进一步阅读源码。要想学好Android,只有那句程序猿至理名言RTFSC(Read The Fucking Source Code)。
关于Android源码阅读,推荐一个非常好的在线阅读源码阅读网址:Android源码

Android系统启动流程

本文主要介绍Android系统的启动过程,主要目的一是让大家大致了解Android手机启动后都在做什么,二是介绍几个核心的系统服务及进程,为后续文章做一个铺垫。本文以Android 9.0.0_r8系统源码为例,Android系统启动大致可以分为四步:

  • 系统环境准备
  • 启动init进程
  • 启动Zygote进程
  • 启动SystemServer进程
Android系统启动.png

下面我们依次来分析每一步都在做什么

系统环境准备

该步骤主要是用户按下开机键后的一些硬件初始化、系统加载过程,简单介绍不作过多说明

BootLoader

Bootloader是嵌入式系统在加电后执行的第一段代码,进行硬件初始化,获取内存大小信息等,调整手机到适配状态。在它完成CPU和相关硬件的初始化之后,再将操作系统映像或固化的嵌入式应用程序加载到内存中然后跳转到操作系统所在的空间,最终目标是拉起操作系统。当用户按下开机键后,芯片就会开始将BootLoader加载到内存中。

系统加载

BootLoader加载成功后,手机会通过BootLoader加载系统,启动系统内核(Kernel)并做相应的环境初始化设置,开始init进程启动

init进程

init进程简介

  • 我们知道,Android系统也有很多自己的系统级的服务进程,Android系统可以正常运行都依赖于这些进程,而init进程是这些所有的进程的根进程,这些进程都是由init进程孵化而来。
  • init进程是Android系统的第一个进程,我们可以通过adb shell -p命令 看到,init进程的pid为1。

init启动流程分析

init是处于linux系统的用户空间,在第一步系统环境准备后,linux内核启动成功便会调用/system/core/init/Init.cpp 中的main()开始init进程的启动。init.cpp中main()函数较长,做相应截取说明

int main(int argc, char** argv) {
     ...
    // 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("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
    mkdir("/dev/pts", 0755);
     ...
    // 2.初始化log服务、属性服务
    InitKernelLogging(argv);
    ....
    property_init();
    ...
    // 3、解析init.rc
    LoadBootScripts(am, sm);
    ...
    // 相关逻辑执行完后,会进入一个while true循环等待任务执行
}

代码很长,我们关心的主要包含3步

第一步 创建、挂载相应文件

  • 创建并挂载系统运行时所需的目录,主要包括tmpfs、devpts、proc、sysfs和selinuxfs五种文件系统。

第二步 初始化log服务、属性服务

  • 调用InitKernelLogging(argv)初始化日志系统,之后会执行LOG(INFO) << "init first stage started!",出内核中第一句log。
  • 在Android系统中,所有的进程共享系统初始值,这些值存在于系统的共享内存区域,通过调用property_init()对相关值进行初始化。

第三步 解析init.rc配置文件

  • LoadBootScripts函数主要工作就是解析init.rc文件,关键代码parser.ParseConfig("/init.rc")
  • init.rc文件是一个非常重要的配置文件,它由AIL语言(Android Init Language)编写,源码位于/system/core/rootdir/init.rc,核心代码如下。
    # Now we can start zygote for devices with file based encryption
    trigger zygote-start
  • trigger zygote-start从源码注释可以看出,这步开始初始化Zygote进程。

Zygote进程

Zygote进程简介

Zygote是受精卵的意思,它是Android中的一个非常重要的守护进程服务(Daem Service),所有的其他Dalvik虚拟机(进程)都是通过zygote孵化(fork)出来的。Android应用程序是由Java语言编写的,运行在各自独立的Dalvik虚拟机(进程)中。如果每个应用程序在启动之时都需要单独运行和初始化一个虚拟机(进程),会大大降低系统性能,因此Android首先创建一个zygote虚拟机(进程),然后通过它孵化出其他的虚拟机(进程),进而共享虚拟机内存和框架层资源,这样大幅度提高应用程序的启动和运行速度。
Zygote是Android中最重要的一个进程,和Init进程,SystemServer进程是支撑Android世界的三极。Android8.0后对zygote.rc文件进行了拆分,存在以下四种:

  • init.zygote32.rc
  • init.zygote32_64.rc
  • init.zygote64.rc
  • init.zygote64_32.rc

我们以init.zygote32.rc为例来简单分析下

service zygote /system/bin/app_process -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

代码不多,共15行,也是Android Init Language语法,执行逻辑就是启动进程,名称为zygote,执行程序为/system/bin/app_process,类名为main,当Zygote进程重启时,重启audioserver、cameraserver、media等进程。下面我们通过frameworks/base/cmds/app_process/app_main.cpp具体分析Zygote进程初始化流程。

Zygote启动流程分析

Zygote进程初始化过程会进入Java层,因此我们分为C++层跟Java层分别分析。

C++层

同样,我们看下app_main.cpp中的main方法,代码较长,我们截取分析。

int main(int argc, char* const argv[])
{
    ...
   // 1、创建AppRuntime变量
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));     // 1
    // Process command line arguments
    // ignore argv[0]
    argc--;
    argv++;

    ...
    // 2、创建Zygote进程
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            // Zygote进程自己
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {     
            // SystemServer进程
            startSystemServer = true; 
        } else if (strcmp(arg, "--application") == 0) {
           // 普通应用进程
            application = true;
        } 
        
        ...
    }

    ...

    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.");
    }
}
第一步 创建AppRuntime变量
  • 定义了一个名为runtime的变量,其类型是AppRuntime,该类继承自AndroidRuntime,也定义在app_main.cpp中
第二步 创建Zygote进程,进入Java层
  • 定义了一个名为runtime的变量,其类型是AppRuntime,该类继承自AndroidRuntime,也定义在app_main.cpp中
  • Zygote进程都是通过fork自身来创建子进程的,这样Zygote进程以及它的子进程都可以进入app_main.cpp的main()函数,因此main()函数中为了区分当前运行在哪个进程,会判断参数argv中是否包含--zygote,若包含则说明main()函数是运行在Zygote进程中的并将变量zygote设置为true;判断参数argv是否包含--start-system-server,若包含则说明main()函数是运行在SystemServer进程中的并在将变量startSystemServer设置为true;判断参数argv是否包含--application,若包含则说明main()函数是运行在普通进程。
  • 若zygote属性为true,则通过AppRuntime的start()函数,通过jni调用,执行com.android.internal.os.ZygoteInit中的main()方法,经过此步,Android初始化首次进入Java层。下面我们开始研究ZygoteInit,该类位于/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

Java层

我们截取看下ZygoteInit中的main方法

         // 1、创建Socket
          ...
          String socketName = "zygote";
          ...
          zygoteServer.registerServerSocketFromEnv(socketName);
          ...
         // 2、预加载类、资源
         preload(bootTimingsTraceLog);
         ...
         // 3、fork SystemServer进程
         if (startSystemServer) {
             Runnable r = forkSystemServer(abiList, socketName, zygoteServer); 
             ...
             if (r != null) {
                 r.run();
                 return;
              }
         }
          ...
            
         // 4、等待AMS消息
         // The select loop returns early in the child process after a fork and
         // loops forever in the zygote.
          caller = zygoteServer.runSelectLoop(abiList); 

第一步 创建Socket
  • 调用registerServerSocketFromEnv()方法创建一个Server端名为“zygote”的Socket,这个Socket用于与AMS(ActivityManagerService)通信,后续程序运行时若要创建普通进程,则由AMS通过该Socket通知Zygote进程孵化。这里稍微了解Android跨进程通信的可能会问,此处为什么不使用Binder进行跨进程通信,原因在于Binder机制依赖于ServiceManger,而此时ServiceManger还未创建。
第二步 预加载类、资源
  • 调用preload(bootTimingsTraceLog)方法,预加载类和资源,应用程序中以com.android.internal.R.xxx头的资源,便是此时由Zygote加载到内存的。
第三步 fork SystemServer进程
  • 在C++层第二步中判断逻辑一致,当若传入的参数中包含--start-system-server,则startSystemServer为true
  • 调用forkSystemServer()方法fork出SystemServer进程,调用run()方法启动。
第四步
  • 调用ZygoteServer的runSelectLoop()方法,等待AMS请求创建新的应用程序进程。

SystemServer进程

SystemServer进程简介

  • SystemServer进程是Zygote创建的第一个Java进程,主要用于创建系统服务,ActivityMangerService、PackageManagerService和WindowManagerService等这些重要的服务都是通过SystemServer进程启动的。

SystemServer启动流程分析

上文谈到forkSystemServer()方法,该方法进行一系列调用后,最终启动SystemServer进程会进入com.android.server.SystemServer.java,该类的main方法直接调用SystemServer的run()方法,我们直接看run方法。

private void run() {
     ...
     // 创建主线程
     Looper.prepareMainLooper();
     ...
     // 1、加载动态库
     System.loadLibrary("android_servers");
     ...
     // 创建system Context
     createSystemContext();
     ...
     // 2、创建ServiceManager
     mSystemServiceManager = new SystemServiceManager(mSystemContext);
     ...
     // 3、启动引导服务、启动核心服务、启动其他服务
     startBootstrapServices();    
     startCoreServices();         
     startOtherServices();
     ...
}

第一步 加载动态库

  • 加载动态库libandroid_servers.so,初始化native服务。

第二步 创建ServiceManager

  • 创建SystemServiceManager对象,Binder机制启用。

第三步 启动引导服务、启动核心服务、启动其他服务

  • 官方把系统服务分为了三种类型,分别是引导服务、核心服务和其他服务。
  • 引导服务主要包括ActivityManagerService、PowerManagerService、PackageManagerService。
  • 核心服务有DropBoxManagerService、BatteryService等。
  • 其他服务是一些不紧要和不需要立即启动的服务,不一一举例。

总结

至此,Android系统启动核心部分已经分析结束。我们分析了Android系统启动后硬件环境准备,init进程如何启动Zygote进程,Zygote进程如何孵化SystemServer进程。本文分析主要是流程分析,源码分析只是指出关键方法,很多代码细节一笔带过,有兴趣的同学可以自己去源码内研究。

你可能感兴趣的:(Android深水区:Android系统启动)