美文网首页
图解Android系统启动过程(基于Android 8.1系统源

图解Android系统启动过程(基于Android 8.1系统源

作者: Andy周 | 来源:发表于2019-01-14 10:15 被阅读30次

    概述

    Android系统是基于Linux的,启动必须经历3个阶段,即:Boot LoaderLinux KernelAndroid系统服务,笔者今天就基于Android 8.1 系统源代码来分析一下启动过程

    大家本地如果没有源代码的可以在线查看:
    https://www.androidos.net.cn/sourcecode

    启动流程图

    下面是笔者根据一些博客以及系统源代码对比整理出来的一张流程图,由于整个过程涉及到的模块很多,目前只是整理了大致的模块流程,具体的细节后续会逐步整理说明。

    image

    本文设计到的几个关键类路径

    关键类 路径
    init.rc system/core/rootdir/init.rc
    init.cpp system/core/init/init.cpp
    init.zygote64.rc system/core/rootdir/init.zygote64.rc
    app_main.cpp frameworks/base/cmds/app_process/app_main.cpp
    AndroidRuntime.cpp frameworks/base/core/jni/AndroidRuntime.cpp
    ZygoteInit.java frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
    ZygoteServer.java frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

    Android系统启动必经的三个步骤:

    1. 按下电源系统启动

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

    2. 引导程序Bootloader

    引导程序是在Android操作系统开始运行前的一个小程序,它的主要作用是把系统OS拉起来并运行。

    3. linux内核启动

    内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找"init"文件,然后启动root进程或者系统的第一个进程

    第一个进程:init进程

    作为Android系统中第一个被启动的进程,init进程的PID为0,它会通过解析init.rc脚本来构建系统的初始形态。

    一个完整的init.rc脚本通常由4种类型的声明组成,即:

    Action(动作):

    on <trigger> ##触发条件
       <command1> ##执行命令
       <command2> ##执行多个命令
       ...
    

    一个Action实际是响应某一个事件的过程,即当<trigger>所描述的触发事件产生时,依次执行各种command(可以执行多个对应的命令)

    Commands(命令):
    命令会将所属事件被一个一个执行

    Services(服务):

    service <name><pathname> [ <argument> ]*
       <option>
       <option>
       ...
    

    <name>表示service的名称
    <pathname>表示可执行文件的路径
    <argument>启动service所带的参数
    <option>对此service的约束选项

    Options(选项)
    

    约束选项

    Android中的DNS服务器——ServiceManager

    ServiceManager可以理解为Binder机制中DNS服务器,负责某Binder服务在ServiceManager注册时提供的名称底层Binder驱动分配的值的解析。

    servicemanager是在system/core/rootdir/init.rc描述并由init进程启动的。

    on post-fs
        ......
        load_system_props
        # start essential services
        start logd
        //启动servicemanager
        start servicemanager
        start hwservicemanager
        start vndservicemanager
    

    这是frameworks/native/cmds/servicemanager.rc描述脚本

    service servicemanager /system/bin/servicemanager
        class core animation
        user system
        group system readproc
        critical
        onrestart restart healthd
        onrestart restart zygote
        onrestart restart audioserver
        onrestart restart media
        onrestart restart surfaceflinger
        onrestart restart inputflinger
        onrestart restart drm
        onrestart restart cameraserver
        writepid /dev/cpuset/system-background/tasks
        shutdown critical
    

    Zygote进程

    在Android中,Zygote是整个系统创建新进程的核心进程。和ServiceManager类似,它也是由init进程解析init.rc脚本时启动的。

    由于系统不断升级,Android系统也不得不面对32位和64位机器同时存在的情况,所以Zygote的启动也需要根据不同的情况进行区分:

    import /init.environ.rc
    import /init.usb.rc
    import /init.${ro.hardware}.rc
    import /vendor/etc/init/hw/init.${ro.hardware}.rc
    import /init.usb.configfs.rc
    import /init.${ro.zygote}.rc
    ......
    

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

    下面是不同的描述Zygoterc脚本

    脚本 描述
    init.zygote32.rc zygote进程对应的执行程序是app_process(纯32位模式)
    init.zygote64.rc zygote进程对应的执行程序是app_process64(纯64位模式)
    init.zygote32_64.rc 启动两个zygote进程 (名为zygote和zygote_secondary),对应的执行程序分别是 app_process32(主模式)、app_process64
    init.zygote64_32.rc 启动两个zygote进程 (名为zygote和zygote_secondary),对应的执行程序分别是 app_process64(主模式)、app_process32

    这里以64位机器为例:/system/core/rootdir/init.zygote64.rc

    service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
        class main
        priority -20
        user root
        group root readproc
        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
    

    上述脚本内容我们可以看到,启动的是一个名为Zygote的进程,对应的程序名为:app_process64

    frameworks/base/cmds/app_process目录下,我们找到Android.mk文件

    LOCAL_PATH:= $(call my-dir)
    
    app_process_common_shared_libs := \
        libandroid_runtime \
        libbinder \
        libcutils \
        libdl \
        libhwbinder \
        liblog \
        libnativeloader \
        libutils \
    ......
    include $(CLEAR_VARS)
    
    LOCAL_SRC_FILES:= $(app_process_src_files)
    
    LOCAL_LDFLAGS_32 := $(app_process_ldflags_32)
    LOCAL_LDFLAGS_64 := $(app_process_ldflags_64)
    
    LOCAL_SHARED_LIBRARIES := $(app_process_common_shared_libs)
    
    LOCAL_WHOLE_STATIC_LIBRARIES := $(app_process_common_static_libs)
    
    LOCAL_MODULE:= app_process
    LOCAL_MULTILIB := both
    LOCAL_MODULE_STEM_32 := app_process32
    LOCAL_MODULE_STEM_64 := app_process64
    
    LOCAL_CFLAGS += $(app_process_cflags)
    ......
    include $(BUILD_EXECUTABLE)
    

    上述脚本决定了最终编译出来的目标文件

    下面我们来看看frameworks/base/cmds/app_process/app_main.cppmain函数的部分关键代码:

    int main(int argc, char* const argv[])
    {
        .....
    
        AppRuntime runtime(argv[0], computeArgBlockSize(argc, 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.");
        }
    }
    

    上面的函数用来解析启动app_process时传入的参数:

    --zygote:指明以ZygoteInit.java类中的main函数作为虚拟机执行入口
    --start-system-server:告诉Zygote进程启动SystemServer进程
    

    注意上述的AppRuntime本身是继承自AndroidRuntime的,因此最终实际调用的还是AndroidRuntime中的start函数

    虚拟机的启动

    在上面的Zygote启动中也看到了虚拟机的启动代码了

    下面来看看frameworks/base/core/jni/AndroidRuntime.cppmain函数的实现:

    void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
    {
      //初始化JNI环境
      JniInvocation jni_invocation;
      jni_invocation.Init(NULL);
      JNIEnv* env;
      //启动虚拟机
      if (startVm(&mJavaVM, &env, zygote) != 0) {
          return;
      }
      //虚拟机启动后回调
      onVmCreated(env);
      // 注册JNI函数
      if (startReg(env) < 0) {
         ALOGE("Unable to register all android natives\n");
         return;
      }
      ......
      char* slashClassName = toSlashClassName(className != NULL ? className : "");
      jclass startClass = env->FindClass(slashClassName);
      if (startClass == NULL) {
          ......
      } else {
          //通过反射找到ZygoteInit的main函数
          jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
              "([Ljava/lang/String;)V");
          if (startMeth == NULL) {
              ......
          } else {
              env->CallStaticVoidMethod(startClass, startMeth, strArray);
          }
      }
      free(slashClassName);
      ......
    

    上面的过程其实就是启动虚拟机的过程,这里由于篇幅关系,并不大算深究每一个模块,而是先粗看整体的框架结构。虚拟机启动完成之后,会通过反射的形式

    调用frameworks/base/core/java/com/android/internal/os/ZygoteInit.java中的main方法

    ZygoteServer zygoteServer = new ZygoteServer();
    ......
    try {
        ......
        boolean startSystemServer = false;
        String socketName = "zygote";
        String abiList = null;
        boolean enableLazyPreload = false;
        for (int i = 1; i < argv.length; i++) {
            if ("start-system-server".equals(argv[i])) {
                //启动SystemServer
                startSystemServer = true;
            } else if ("--enable-lazy-preload".equals(argv[i])) {
                enableLazyPreload = true;
            } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                abiList = argv[i].substring(ABI_LIST_ARG.length());
            } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                socketName = argv[i].substring(SOCKET_NAME_ARG.length());
            } else {
                throw new RuntimeException("Unknown command line argument: " + argv[i]);
            }
        }
    
        //注册服务端的Socket
        zygoteServer.registerServerSocket(socketName);
        ......
        if (!enableLazyPreload) {
            bootTimingsTraceLog.traceBegin("ZygotePreload");
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());
            //预加载各类资源
            preload(bootTimingsTraceLog);
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());
            bootTimingsTraceLog.traceEnd(); // ZygotePreload
        } else {
            Zygote.resetNicePriority();
        }
        ......
        if (startSystemServer) {
            //正式启动SystemServer
            Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
            ......
            if (r != null) {
                r.run();
                return;
            }
        }
        ......
        caller = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with exception", ex);
        throw ex;
    } finally {
        zygoteServer.closeServerSocket();
    }
    

    因此在ZygoteInit中比较关键的两个操作:

    1.注册一个Socket:如果由新进程需要创建,系统会通过这个Socket来通知它完成进程孵化工作
    2.预加载各类资源:主要用来预加载虚拟机所需要的各类资源。

    紧接着就是下面的代码:

    runSelectLoop(abiList);
    

    这段代码的内部实现其实就是一个while死循环,它用来作为Zygote的守护进程

    启动SystemServer

    前面的ServiceManagerZygote虚拟机等启动过程有了一定的了解了,下面就是关键的SystemServer启动了,之前的脚本也看到了一个叫--start-system-server的参数,这个就是用来启动SystemServer的。

    frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

    private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        ......
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;
    
        int pid;
    
        try {
            parsedArgs = new ZygoteConnection.Arguments(args);
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
    
            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }
    
        //子进程
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
    
            zygoteServer.closeServerSocket();
            //启动各个System Server进程
            return handleSystemServerProcess(parsedArgs);
        }
    
        return null;
    }
    
    

    ZygoteInit中通过forkSystemServer方法创建了一个新进程,这个新进程(pid==0)会在随后的过程中通过handleSystemServerProcess来启动各种支撑系统运行的System Server

    小结

    Android系统中,每个进程都运行在对应的虚拟机上,因此Zygote首先就负责创建出虚拟机
    然后,为了反射调用java代码,必须有对应的JNI函数,于是Zygote进行了JNI函数的注册
    当一切准备妥当后,Zygote进程才进入到了java的世界

    参考:
    《深入理解Android内核设计思想》
    https://blog.csdn.net/freekiteyu/article/details/79175010
    https://www.cnblogs.com/pepsimaxin/p/9443002.html
    https://www.cnblogs.com/pepsimaxin/p/9448874.html
    https://www.cnblogs.com/tiantianbyconan/p/5013863.html

    相关文章

      网友评论

          本文标题:图解Android系统启动过程(基于Android 8.1系统源

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