美文网首页Android开发
谈谈对Android中Zygote的理解

谈谈对Android中Zygote的理解

作者: Android进阶架构 | 来源:发表于2020-09-29 15:08 被阅读0次

    Zygote是什么?

    在Android中,负责孵化新进程的这个进程叫做Zygote,安卓上其他的应用进程都是由它孵化的。众所周知,安卓是Linux内核,安卓系统上运行的一切程序都是放在Dalvik虚拟机上的,Zygote也不例外,事实上,它是安卓运行的第一个Dalvik虚拟机进程。既然Zygote负责孵化其他的安卓进程,那么它自己是由谁孵化的呢?既然Android是基于Linux内核,那么Zygote当然就是Linux内核启动的用户级进程Init创建的了。

    Zygote的作用是什么?

    对于Zygote的作用实际上可以概括为以下两点:

    • 创建SystemServer
    • 孵化应用进程

    Zygote的启动过程

    • Zygote进程在Init进程启动过程中被以service服务的形式启动:

      service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
      class main
      socket zygote stream 660 root system 
      
    • 调用app_main.cpp的main函数中的AppRuntime的start方法来启动Zygote进程

    • 调用startVm函数来创建虚拟机,调用startReg函数为java虚拟机注册JNI方法

    • 通过toSlashClassName找到ZygoteInit,通过GetStaticMethedID函数找到main方法然后调用,ZygoteInit的main方法是由Java语言编写的,当前的运行逻辑在Native中,这就需要JNI来调用Java,这样Zygote就从Native层进入了Java框架层。

    • ZygoteInit的main方法的源码如下:

        frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
        public static void main(String argv[]) {
           //1、创建ZygoteServer
            ZygoteServer zygoteServer = new ZygoteServer();
          .......
            try {
                 .......
                boolean startSystemServer = false;
                String socketName = "zygote";
                String abiList = null;
                boolean enableLazyPreload = false;
               // 2、解析app_main.cpp传来的参数
                for (int i = 1; i < argv.length; i++) {
                    if ("start-system-server".equals(argv[i])) {
                        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]);
                    }
                }
    
                if (abiList == null) {
                    throw new RuntimeException("No ABI list supplied.");
                }
                //3、创建一个Server端的Socket
                zygoteServer.registerServerSocket(socketName);
                // In some configurations, we avoid preloading resources and classes eagerly.
                // In such cases, we will preload things prior to our first fork.
                if (!enableLazyPreload) {
                    bootTimingsTraceLog.traceBegin("ZygotePreload");
                    EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                        SystemClock.uptimeMillis());
                   //4、加载进程的资源和类
                    preload(bootTimingsTraceLog);
                    EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                        SystemClock.uptimeMillis());
                    bootTimingsTraceLog.traceEnd(); // ZygotePreload
                } else {
                    Zygote.resetNicePriority();
                }
                  ........
                if (startSystemServer) {
                    //5、开启SystemServer进程,这是受精卵进程的第一次分裂
                    startSystemServer(abiList, socketName, zygoteServer);
                }
    
                Log.i(TAG, "Accepting command socket connections");
               //6、启动一个死循环监听来自Client端的消息
                zygoteServer.runSelectLoop(abiList);
               //7、关闭SystemServer的Socket
                zygoteServer.closeServerSocket();
            } catch (Zygote.MethodAndArgsCaller caller) {
               //8、这里捕获这个异常调用MethodAndArgsCaller的run方法。
                caller.run();
            } catch (Throwable ex) {
                Log.e(TAG, "System zygote died with exception", ex);
                zygoteServer.closeServerSocket();
                throw ex;
            }
        }
    

    总结下来的流程:

    【1】通过registerServerSocket方法来创建一个Server端的socket,这个name为zygote的socket用于等待ActivityManagerService请求Zygote来创建新的应用程序进程

    【2】预加载,预加载项如下:

    preloadClasses();
    preloadResources();
    preloadOpenGL();
    preloadSharedLibraries();
    preloadTextResources();
    WebViewFactory.prepareWebViewInZygote();
    ...
    

    以下是Android应用进程共享内存图:

    通过上图可以很容易理解在Zygote进程预加载系统资源后,然后通过它孵化出其他的虚拟机进程,进而共享虚拟机内存和框架层资源,这样大幅度提高应用程序的启动和运行速度。

    【3】启动SystemServer进程

    【4】执行runSelectLoop()方法等待消息去创建应用进程

    Zygote注意细节

    • Zygote进行fork的时候要是单线程,为了避免造成死锁或者状态不一致等问题
    • Zygote的跨进程通信没有采用Binder机制,而是采用本地socket

    关于Zygote的疑问

    • 孵化应用进程这种事为什么不交给SystemServer来做,而专门设计一个Zygote?

      我们知道,应用在启动的时候需要做很多准备工作,包括启动虚拟机,加载各类系统资源等等,这些都是非常耗时的,如果能在zygote里就给这些必要的初始化工作做好,子进程在fork的时候就能直接共享,那么这样的话效率就会非常高。这个就是zygote存在的价值,这一点呢SystemServer是替代不了的,主要是因为SystemServer里跑了一堆系统服务,这些是不能继承到应用进程的。而且我们应用进程在启动的时候,内存空间除了必要的资源外,最好是干干净净的,不要继承一堆乱七八糟的东西。所以呢,不如给SystemServer和应用进程里都要用到的资源抽出来单独放在一个进程里,也就是这的zygote进程,然后zygote进程再分别孵化出SystemServer进程和应用进程。孵化出来之后,SystemServer进程和应用进程就可以各干各的事了。

    • Zygote的IPC通信机制为什么不采用binder?如果采用binder的话会有什么问题么?

      第一个原因,我们可以设想一下采用binder调用的话该怎么做,首先zygote要启用binder机制,需要打开binder驱动,获得一个描述符,再通过mmap进行内存映射,还要注册binder线程,这还不够,还要创建一个binder对象注册到serviceManager,另外AMS要向zygote发起创建应用进程请求的话,要先从serviceManager查询zygote的binder对象,然后再发起binder调用,这来来回回好几趟非常繁琐,相比之下,zygote和SystemServer进程本来就是父子关系,对于简单的消息通信,用管道或者socket非常方便省事。第二个原因,如果zygote启用binder机制,再fork出SystemServer,那么SystemServer就会继承了zygote的描述符以及映射的内存,这两个进程在binder驱动层就会共用一套数据结构,这显然是不行的,所以还得先给原来的旧的描述符关掉,再重新启用一遍binder机制,这个就是自找麻烦了。

    在网上看到一个Zygote工作流程图,感觉描述的非常清晰,可以参考一下:


    好了,关于Zygote的理解就到这里了,有什么不对的地方希望大家指正!共同进步!

    喜欢本文的话,不妨顺手给我点个小赞、评论区留言或者转发支持一下呗😜😜😜~
    点击【GitHub】还有彩蛋哦!!!

    相关文章

      网友评论

        本文标题:谈谈对Android中Zygote的理解

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