Zygote进程启动分析

作者: 飞飞飞_Android | 来源:发表于2017-06-09 23:03 被阅读0次

    最近在追溯Activity启动的流程,顺手温习下Android上层的启动流程,就从Zygote进程启动开始。

    Zygote进程是由linux的init进程启动的,是所有android进程的父进程,包括systemserver和所有的应用进程都是由Zygote fork出来。

    Init进程在启动Zygote进程时,会调用ZygoteInit.main方法(MTK平台项目代码,其中残留了一些mtk修改的痕迹)

        public static void main(String argv[]) {
            /// M: GMO Zygote64 on demand @{
            DEBUG_ZYGOTE_ON_DEMAND =
                SystemProperties.get(PROP_ZYGOTE_ON_DEMAND_DEBUG).equals("1");
            if (DEBUG_ZYGOTE_ON_DEMAND) {
                Log.d(TAG, "ZygoteOnDemand: Zygote ready = " + sZygoteReady);
            }
            String socketName = "zygote";
            /// M: GMO Zygote64 on demand @}
    
            // Mark zygote start. This ensures that thread creation will throw
            // an error.
            ZygoteHooks.startZygoteNoThreadCreation();
    
            try {
                Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit");
                RuntimeInit.enableDdms();
                /// M: Added for BOOTPROF
                //MTPROF_DISABLE = "1".equals(SystemProperties.get("ro.mtprof.disable"));
                // Start profiling the zygote initialization.
                SamplingProfilerIntegration.start();
    
                boolean startSystemServer = false;
                String abiList = null;
                for (int i = 1; i < argv.length; i++) {
                    if ("start-system-server".equals(argv[i])) {
                        startSystemServer = 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.");
                }
    
                registerZygoteSocket(socketName);
                Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                    SystemClock.uptimeMillis());
                /// M: Added for BOOTPROF
                addBootEvent("Zygote:Preload Start");
    
                /// M: GMO Zygote64 on demand @{
                /// M: Added for Zygote preload control @{
                preloadByName(socketName);
                /// @}
                /// M: GMO Zygote64 on demand @}
    
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                    SystemClock.uptimeMillis());
                Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
    
                // Finish profiling the zygote initialization.
                SamplingProfilerIntegration.writeZygoteSnapshot();
    
                // Do an initial gc to clean up after startup
                Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC");
                gcAndFinalize();
                Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
    
                Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
    
                // Disable tracing so that forked processes do not inherit stale tracing tags from
                // Zygote.
                Trace.setTracingEnabled(false);
    
                // Zygote process unmounts root storage spaces.
                Zygote.nativeUnmountStorageOnInit();
    
                /// M: Added for BOOTPROF
                addBootEvent("Zygote:Preload End");
    
                ZygoteHooks.stopZygoteNoThreadCreation();
    
                /// N: Move MPlugin init after preloading due to "Zygote: No Thread Creation Issues". @{
                boolean preloadMPlugin = false;
                if (!sZygoteOnDemandEnabled) {
                    preloadMPlugin = true;
                } else {
                    if ("zygote".equals(socketName)) {
                        preloadMPlugin = true;
                    }
                }
                if (preloadMPlugin) {
                    Log.i(TAG1, "preloadMappingTable() -- start ");
                    PluginLoader.preloadPluginInfo();
                    Log.i(TAG1, "preloadMappingTable() -- end ");
                }
                /// @}
    
                if (startSystemServer) {
                    startSystemServer(abiList, socketName);
                }
    
                /// M: GMO Zygote64 on demand @{
                sZygoteReady = true;
                if (DEBUG_ZYGOTE_ON_DEMAND) {
                    Log.d(TAG, "ZygoteOnDemand: Zygote ready = " + sZygoteReady +
                        ", socket name: " + socketName);
                }
                /// M: GMO Zygote64 on demand @}
    
                Log.i(TAG, "Accepting command socket connections");
                runSelectLoop(abiList);
    
                /// M: GMO Zygote64 on demand @{
                zygoteStopping("ZygoteOnDemand: End of runSelectLoop", socketName);
                /// M: GMO Zygote64 on demand @}
    
                closeServerSocket();
            } catch (MethodAndArgsCaller caller) {
                caller.run();
            } catch (RuntimeException ex) {
                Log.e(TAG, "Zygote died with exception", ex);
                closeServerSocket();
                throw ex;
            }
    
            /// M: GMO Zygote64 on demand @{
            zygoteStopping("ZygoteOnDemand: End of main function", socketName);
            /// M: GMO Zygote64 on demand @}
        }
    

    1. Mark zygote start.

     // Mark zygote start. This ensures that thread creation will throw
     // an error.
    ZygoteHooks.startZygoteNoThreadCreation();    
    

    标记zygote启动开始,调用ZygoteHooks的Jni方法,原因不是特别理解,贴出该方法google给的说明:
    /**
    * Called by the zygote when starting up. It marks the point when any thread
    * start should be an error, as only internal daemon threads are allowed there.
    */
    public static native void startZygoteNoThreadCreation();
    zygote启动时调用,在这里启动任意其他线程都是错误的,只有内部的守护线程被允许。

    2. ddms服务

    RuntimeInit.enableDdms();
    

    3.启动系能统计

    SamplingProfilerIntegration.start();
    

    4.解析参数列表

                boolean startSystemServer = false;
                String abiList = null;
                for (int i = 1; i < argv.length; i++) {
                    if ("start-system-server".equals(argv[i])) {
                        startSystemServer = 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]);
                    }
                }
    

    判断systemserver是否启动,获取socketname等等

    5.注册Socket

    registerZygoteSocket(socketName);

        private static void registerZygoteSocket(String socketName) {
            if (sServerSocket == null) {
                int fileDesc;
                final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
                try {
                    String env = System.getenv(fullSocketName);
                    fileDesc = Integer.parseInt(env);
                } catch (RuntimeException ex) {
                    throw new RuntimeException(fullSocketName + " unset or invalid", ex);
                }
    
                try {
                    FileDescriptor fd = new FileDescriptor();
                    fd.setInt$(fileDesc);
                    sServerSocket = new LocalServerSocket(fd);
                } catch (IOException ex) {
                    throw new RuntimeException(
                            "Error binding to local socket '" + fileDesc + "'", ex);
                }
            }
        }
    

    初始化Server端(也就是Zygote)的socket。值得一提的是,这里用到的socket类型是LocalSocket, 它是Android对Linux 的 Local Socket的一个封装。Local Socket 是Linux提供的一种基于Socket的进程间通信方式,对Server端来讲,唯一的区别就是bind到一个本地的文件描述符(fd)而不是某个IP地址和端口号。

    6.预加载资源

    static void preload() {
        Log.d(TAG, "begin preload");
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "BeginIcuCachePinning");
        beginIcuCachePinning();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadClasses");
        preloadClasses();         //预加载位于/system/etc/preloaded-classes文件中的类
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadResources");
        preloadResources();    //预加载资源,包含drawable和color资源
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
        preloadOpenGL();    //预加载OpenGL
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        preloadSharedLibraries();     //通过System.loadLibrary()方法,
                                    //预加载"android","compiler_rt","jnigraphics"这3个共享库
        preloadTextResources();      //预加载  文本连接符资源
        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
        WebViewFactory.prepareWebViewInZygote();   //仅用于zygote进程,用于内存共享的进程
        endIcuCachePinning();
        warmUpJcaProviders();
        Log.d(TAG, "end preload");
    }
    

    对于类加载,采用反射机制Class.forName()方法来加载。对于资源加载,主要是 com.android.internal.R.array.preloaded_drawables和com.android.internal.R.array.preloaded_color_state_lists,在应用程序中以com.android.internal.R.xxx开头的资源,便是此时由Zygote加载到内存的。

    zygote进程内加载了preload()方法中的所有资源,当需要fork新进程时,采用copy on write技术,如下:

    7.gc操作

        /**
         * Runs several special GCs to try to clean up a few generations of
         * softly- and final-reachable objects, along with any other garbage.
         * This is only useful just before a fork().
         */
        /*package*/ static void gcAndFinalize() {
            final VMRuntime runtime = VMRuntime.getRuntime();
    
            /* runFinalizationSync() lets finalizers be called in Zygote,
             * which doesn't have a HeapWorker thread.
             */
            System.gc();
            runtime.runFinalizationSync();
            System.gc();
        }
    

    Runs多次gc,保证清理?

    8.startSystemServer

        private static boolean startSystemServer(String abiList, String socketName)
                throws MethodAndArgsCaller, RuntimeException {
            long capabilities = posixCapabilitiesAsBits(
                OsConstants.CAP_IPC_LOCK,
                OsConstants.CAP_KILL,
                OsConstants.CAP_NET_ADMIN,
                OsConstants.CAP_NET_BIND_SERVICE,
                OsConstants.CAP_NET_BROADCAST,
                OsConstants.CAP_NET_RAW,
                OsConstants.CAP_SYS_MODULE,
                OsConstants.CAP_SYS_NICE,
                OsConstants.CAP_SYS_RESOURCE,
                OsConstants.CAP_SYS_TIME,
                OsConstants.CAP_SYS_TTY_CONFIG
            );
            /* Containers run without this capability, so avoid setting it in that case */
            if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER, false)) {
                capabilities |= posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND);
            }
            /* Hardcoded command line to start the system server */
            String args[] = {
                "--setuid=1000",
                "--setgid=1000",
                /// M: ANR mechanism for system_server add shell(2000) group to access
                ///    /sys/kernel/debug/tracing/tracing_on
                "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,2000," +
                    "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 */
    // fork子进程,用于运行system_server
                pid = Zygote.forkSystemServer(
                        parsedArgs.uid, parsedArgs.gid,
                        parsedArgs.gids,
                        parsedArgs.debugFlags,
                        null,
                        parsedArgs.permittedCapabilities,
                        parsedArgs.effectiveCapabilities);
            } catch (IllegalArgumentException ex) {
                throw new RuntimeException(ex);
            }
    
            /* For child process */
        //进入子进程system_server
            if (pid == 0) {
                if (hasSecondZygote(abiList)) {
                    waitForSecondaryZygote(socketName);
                }
            // 完成system_server进程剩余的工作
                handleSystemServerProcess(parsedArgs);
            }
    
            return true;
        }
    

    9.runSelectLoop

        /**
         * Runs the zygote process's select loop. Accepts new connections as
         * they happen, and reads commands from connections one spawn-request's
         * worth at a time.
         *
         * @throws MethodAndArgsCaller in a child process when a main() should
         * be executed.
         */
        private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
            ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
            ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        //sServerSocket是socket通信中的服务端,即zygote进程
            fds.add(sServerSocket.getFileDescriptor());
            peers.add(null);
    
            while (true) {
                StructPollfd[] pollFds = new StructPollfd[fds.size()];
                for (int i = 0; i < pollFds.length; ++i) {
                    pollFds[i] = new StructPollfd();
                    pollFds[i].fd = fds.get(i);
                    pollFds[i].events = (short) POLLIN;
                }
                try {
                    Os.poll(pollFds, -1);
                } catch (ErrnoException ex) {
                    throw new RuntimeException("poll failed", ex);
                }
    //采用I/O多路复用机制,当客户端发出连接请求或者数据处理请求时,跳过continue,执行后面的代码
                for (int i = pollFds.length - 1; i >= 0; --i) {
                    if ((pollFds[i].revents & POLLIN) == 0) {
                        continue;
                    }
                    if (i == 0) {
                    //创建客户端连接
                        ZygoteConnection newPeer = acceptCommandPeer(abiList);
                        peers.add(newPeer);
                        fds.add(newPeer.getFileDesciptor());
                    } else {
                    //处理客户端数据事务
                        boolean done = peers.get(i).runOnce();
                        if (done) {
                            peers.remove(i);
                            fds.remove(i);
                        }
                    }
                }
            }
        }
    

    Zygote采用高效的I/O多路复用机制,保证在没有客户端连接请求或数据处理时休眠,否则响应客户端的请求。

    10.简单小结

    ZygoteInit.main方法是android java代码开始的地方,

    • registerZygoteSocket()建立socket通道,zygote作为通信的服务端,用于响应客户端请求;
    • preload()预加载通用类、drawable和color资源、openGL以及共享库以及WebView,用于提高ap启动效率;
    • zygote完毕大部分工作,接下来再通过startSystemServer(),fork得力帮手system_server进程,也是上层framework的运行载体。
    • zygote功成身退,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。

    参考链接:
    http://www.cnblogs.com/samchen2009/p/3294713.html
    http://gityuan.com/2016/02/14/android-system-server/
    http://blog.csdn.net/omnispace/article/details/51773292

    相关文章

      网友评论

        本文标题:Zygote进程启动分析

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