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<FileDescriptor> fds = new ArrayList<FileDescriptor>();  
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();  
        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: 客戶端與服務端已經建立連接,並開始發送數據

於是就有了下面判斷的各種處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章