Zygote进程启动详解

我们都知道Android系统是架构在linux内核之上移动操作系统。在unix系统中所有的进程都是在init进程的子进程,有init进程负责fork创建。所以zygote进程肯定也是init进程fork出来的子进程。关于init进程的启动暂时不谈。
那么Zygote进程作为android 应用程序进程和系统服务进程SystemServer的主进程,那我主要做了哪些工作呢?我们通过源码分析一下。

这片文章我们只要分析Zygote进程的启动流程来加深一下了解。init进程在启动Zygote进程时一般都会调用ZygoteInit类的main方法,那么我们看一下main方法的具体实现(android23源码)。

  1. main()方法内容:

    public class ZygoteInit {
         public static void main(String argv[]) {
        try {
        //1.在此主要完成了ddms的启动,
            RuntimeInit.enableDdms();
            // Start profiling the zygote initialization.
            //2.开始分析zygote进程的初始化
            SamplingProfilerIntegration.start();
    
            boolean startSystemServer = false;
            String socketName = "zygote";
            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.");
            }
    //3.zygote进程注册socket
            registerZygoteSocket(socketName);
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());
            //4.资源预加载
            preload();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());
    
            // Finish profiling the zygote initialization.
    //5.结束对zygote进程初始化的分析        SamplingProfilerIntegration.writeZygoteSnapshot();
    
            // Do an initial gc to clean up after startup
            gcAndFinalize();
    
            // Disable tracing so that forked processes do not inherit stale tracing tags from
            // Zygote.
            Trace.setTracingEnabled(false);
    
            if (startSystemServer) {
                //6.启动systemserver
                startSystemServer(abiList, socketName);
            }
    
            Log.i(TAG, "Accepting command socket connections");
            //7.接受进程请求
            runSelectLoop(abiList);
            //8.关闭socket
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }
    }

    我们总结一下真个main方法都完成了哪些事情:

    • 启动android DDMS.
    • 开始分析zygote进程的初始化,本方法主要是结合VM相关机制.
    • zygote进程注册于系统通信的socket。
    • 资源的预加载 主要加载了:通用class,资源,opengl,共享库, 字符资源,以及webview的初始化准备。
    • 启动systemserver. systemserver负责很多android重要服务的管理,如:packageManagerService ,ActivityManagerService等。具体SystemServer都做了哪些工作以后在好好看看。
    • 处理客户端的连接和请求。
    • 关闭socket连接。

    registerZygoteSocket()源码如下:


    /**
     * Registers a server socket for zygote command connections
     * 注册一个zygote进程的连接socket
     *
     * @throws RuntimeException when open fails
     */
    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);
            }
        }
    }

从环境变量中获得名为“ANDROID_SOCKET_zygote”的值作为socket的fd。zygote进程的文件就是/dev/socket/zygote文件。
ANDROID_SOCKET_zygote就是进程文件的fd。其中注册zygote的socket就是调用了native层的相关方法在此暂时不谈。

preload()方法的内容下:

 static void preload() {
        Log.d(TAG, "begin preload");
        preloadClasses();    
        preloadResources();
        preloadOpenGL();
        preloadSharedLibraries();
        preloadTextResources();
            // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
        WebViewFactory.prepareWebViewInZygote();
        Log.d(TAG, "end preload");
    }

类和资源的预先加载都比较简单就不多说了。注意到webview在zygote进程中准备了一些初始化的工作,主要是为native层的库配置内存地址空间。

启动systemserver:

/** 
     * Prepare the arguments and fork for the system server process. 
     */  
    private static boolean startSystemServer()  
            throws MethodAndArgsCaller, RuntimeException {  
        long capabilities = posixCapabilitiesAsBits(  
            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  
        );  
        /* Hardcoded command line to start the system server */  
        String args[] = {  
            "--setuid=1000",    // #define AID_SYSTEM  1000  
            "--setgid=1000",    // 1000 是系统属性  
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",  
            "--capabilities=" + capabilities + "," + capabilities,  
            "--runtime-init",  
            "--nice-name=system_server",    // 进程名为system_server  
            "com.android.server.SystemServer",  // 类名  
        };  
        ZygoteConnection.Arguments parsedArgs = null;  

        int pid;  

        try {  
            parsedArgs = new ZygoteConnection.Arguments(args);  
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);  
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);  

            /*  
                进程启动参数都已经在上面硬编码了 
                最后调用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 */  
        if (pid == 0) {  
            // 子进程处理消息  
            handleSystemServerProcess(parsedArgs);  
        }  

        return true;  
}  

runSelectLoop()方法等待请求:

private static void runSelectLoop() throws MethodAndArgsCaller {  
        ArrayList fds = new ArrayList();  
        ArrayList peers = new ArrayList();  
        FileDescriptor[] fdArray = new FileDescriptor[4];  

        //记录sServerSocket的fd信息 
        fds.add(sServerSocket.getFileDescriptor());  
        peers.add(null);  

        int loopCount = GC_LOOP_COUNT;  
        while (true) {  
            int index;  

            /* 
             * Call gc() before we block in select(). 
             * It's work that has to be done anyway, and it's better 
             * to avoid making every child do it.  It will also 
             * madvise() any free memory as a side-effect. 
             * 
             * Don't call it every time, because walking the entire 
             * heap is a lot of overhead to free a few hundred bytes. 
             */  
            if (loopCount <= 0) {  
                gc();  
                loopCount = GC_LOOP_COUNT;  
            } else {  
                loopCount--;  
            }  

            try {  
                fdArray = fds.toArray(fdArray);  

                //selectReadable是一个native函数
                index = selectReadable(fdArray);  
            } catch (IOException ex) {  
                throw new RuntimeException("Error in select()", ex);  
            }  

            if (index < 0) {  
                throw new RuntimeException("Error in select()");  
            } else if (index == 0) {  

                ZygoteConnection newPeer = acceptCommandPeer();  
                peers.add(newPeer);  
                fds.add(newPeer.getFileDesciptor());  
            } else {  
                boolean done;   
                done = peers.get(index).runOnce();  
                // 请求处理完成之后,移除与该客户端的连接  
                if (done) {  
                    peers.remove(index);  
                    fds.remove(index);  
                }  
            }  
        }  
}  

selectReadable()方法是个native方法,内部是调用了unix的select()来建立socket连接。当外部请求socket连接时会返回一个值。

返回值代表的意思如下:
小于0: 内部发生错误
等于0: 该客户端第一次连接到服务端
大于0: 客户端与服务端已经建立连接,并开始发送数据

于是就有了下面判断的各种处理。

你可能感兴趣的:(移动开发)