Android 8.1 zygote創建新應用進程

Android 8.1 zygote創建新應用進程

涉及到的文件以及路徑:

frameworks/base/core/java/com/android/internal/os/Zygote.java
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

分析過Android系統啓動流程的同學都知道,zygote啓動之後,會調用ZygoteInit.java中的main函數。

ZygoteInit.java的路徑: frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

這個main函數如下:

 public static void main(String argv[]) {
		// 創建一個ZygoteServer 對象,這個是8.0 之後纔有的 
		// 這個就是zygote最後等待ActivityManager 連接來 fork新進程的地方
        ZygoteServer zygoteServer = new ZygoteServer();

        // Mark zygote start. This ensures that thread creation will throw
        // an error.
        // 調用native函數,確保當前沒有其它線程在運行
        // 主要還是處於安全的考慮
		// 啓動無多線程模式 .當在zygoteInit中新建線程系統掛掉
		// 主要是由於擔心用戶新建線程提高預加載速度
		// 但是可能沒做好同步工作, 當有的應用需要預加載的資源,但是多線程情況下還沒有加載,發生問題
        ZygoteHooks.startZygoteNoThreadCreation();

        // Zygote goes into its own process group.
		// 指定當前進程的id(第一個參數是目標進程id,第二個參數是進程組id,把第二個參數設置成第一個的值)
        try {
            Os.setpgid(0, 0);
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to setpgid(0,0)", ex);
        }

        final Runnable caller;
        try { // 解析上面傳遞過來的參數
            // Report Zygote start time to tron unless it is a runtime restart
            if (!"1".equals(SystemProperties.get("sys.boot_completed"))) { // 如果是重啓sys.boot_completed值是1
                //上報Zygote進程啓動的時間
                MetricsLogger.histogram(null, "boot_zygote_init",(int) SystemClock.elapsedRealtime());
            }

            String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
            TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,Trace.TRACE_TAG_DALVIK);
            bootTimingsTraceLog.traceBegin("ZygoteInit");
            RuntimeInit.enableDdms();

            boolean startSystemServer = false; // 是否啓動 SystemServer
            String socketName = "zygote";      // 創建的socket的名稱
            String abiList = null;             // 支持的so庫的類型
            boolean enableLazyPreload = false; // 這個尚不清楚,不過傳遞過來的參數中沒有這個
            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.");
            }

            zygoteServer.registerServerSocket(socketName); // 註冊server socket
            // 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());
                preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                    SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            } else {
                Zygote.resetNicePriority();
            }

            // Do an initial gc to clean up after startup
            bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
            gcAndFinalize();
            bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC

            bootTimingsTraceLog.traceEnd(); // ZygoteInit
            // Disable tracing so that forked processes do not inherit stale tracing tags from
            // Zygote.
            Trace.setTracingEnabled(false, 0);

            // Zygote process unmounts root storage spaces.
			// // 卸載root的存儲空間
            Zygote.nativeUnmountStorageOnInit();

            // Set seccomp policy
            // Set seccomp policy
            // 加載seccomp的過濾規則
            // 所有 Android 軟件都使用系統調用(簡稱爲 syscall)與 Linux 內核進行通信
            // 內核提供許多特定於設備和SOC的系統調用,讓用戶空間進程(包括應用)可以直接與內核進行交互
            // 不過,其中許多系統調用Android未予使用或未予正式支持
            // 通過seccomp,Android可使應用軟件無法訪問未使用的內核系統調用
            // 由於應用無法訪問這些系統調用,因此,它們不會被潛在的有害應用利用
            // 該過濾器安裝到zygote進程中,由於所有Android應用均衍生自該進程
            // 因而會影響到所有應用
            Seccomp.setPolicy();

            ZygoteHooks.stopZygoteNoThreadCreation(); // 允許有其他線程了

            if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, socketName, zygoteServer); // 啓動SystemServer

                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                if (r != null) {
                    r.run(); // 這裏會調用到 RuntimeInit.java 中的 MethodAndArgsCaller 的 run方法,來正式進入 SystemServer的main函數
                    return;
                }
            }

            Log.i(TAG, "Accepting command socket connections");

            // The select loop returns early in the child process after a fork and
            // loops forever in the zygote.
            caller = zygoteServer.runSelectLoop(abiList); // zygote進程進入無限循環,處理請求
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
		    Log.i(TAG, "zygoteServer.closeServerSocket finally finally");
			// 這個地方有兩個調用的流程
			// 1: zygote 進程退出的時候會調用這個函數,用來關閉zygote自己創建的用來接收ActivityManager的鏈接請求的socket
			// 2:當每個子線程fork完畢,準備好之後,會走到這裏,這個時候會在子進程中執行的,這裏會調用closeServerSocket函數,確保從zygote集成過來的socket關閉。
			//    其實這個時候,因爲子進程剛剛fock出來的時候就已經掉用過closeServerSocket函數了,因此再次調用,是沒有效果的
            zygoteServer.closeServerSocket();
        }

        // We're in the child process and have exited the select loop. Proceed to execute the
        // command.
        if (caller != null) {
            caller.run(); // 這裏纔是重點,上面會返回一個Runnable的對象,這個地方調用他的 run函數會進入到子進程的真正的main函數裏面
        }
    }

這個main函數中,首選會創建一個ZygoteServer對象,這個就是用來處理後續zygote socket連接的地方。然後會解析前面傳遞進來的參數。根據參數決定是否啓動SystemServer,啓動SystemServer的部分,網上比較多,這裏就不做詳細介紹了。

  根據代碼流程我們會發現,在main函數的最後會調用 caller = zygoteServer.runSelectLoop(abiList);進入到ZygoteServer類的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.
     */
    Runnable runSelectLoop(String abiList) {
		// 記錄需要監聽的句柄
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
		// 記錄上面監聽的句柄所對應的處理類的實例對象
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

        fds.add(mServerSocket.getFileDescriptor());
        peers.add(null); // 這裏add null 是爲了使得它的index 和 fds 的index想對應。

        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);
            }
            for (int i = pollFds.length - 1; i >= 0; --i) { // 根據監聽到的消息長度,循環處理監聽到的所有消息
                if ((pollFds[i].revents & POLLIN) == 0) { // 無效消息,跳過
                    continue;
                }
                Slog.e(TAG, "runSelectLoop i = "+i+" mIsForkChild = "+mIsForkChild);
                if (i == 0) { // 如果 i是0,就說明監聽到了連接請求,
				    // 此時調用 acceptCommandPeer 函數,這個函數會調用 mServerSocket.accept() 接受連接,並返回句柄
					// 然後用此句柄爲參數創建了 ZygoteConnection 對象,然後由 ZygoteConnection 對象負責這一個連接的後續數據處理
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer); // 添加到 peers 這個
                    fds.add(newPeer.getFileDesciptor());  // 添加到 fds,然後在下次循環的時候,將剛剛接受的鏈接請求也一同添加到監聽
                } else { // 如果不是0.那就是上面 i=0的時候接受到的連接發來數據了。
                    try {
                        ZygoteConnection connection = peers.get(i); // 從剛剛記錄的peers中獲取處理對應數據的 ZygoteConnection 類
                        final Runnable command = connection.processOneCommand(this);
                        // 因爲上面的 processOneCommand 函數調用中,如果創建了新的進程,上面的函數就會有兩個返回,
						// 第一個是父進程的正常返回 此時的返回值是 null,還是在zygote進程中運行,並且mIsForkChild的值是沒有變的,這個時候會進入到else中
						// 第二個返回時子進程的返回 此時的返回時不是空,此時是在子進程中運行,並且在子進程剛剛創建的時候,就將自己的mIsForkChild設置爲 true了。
						
                        if (mIsForkChild) {
                            // We're in the child. We should always have a command to run at this
                            // stage if processOneCommand hasn't called "exec".
							// 這裏是在子進程
                            if (command == null) {
                                throw new IllegalStateException("command == null");
                            }

                            return command;
                        } else {
                            // We're in the server - we should never have any commands to run.
							// 這裏是在父進程中
                            if (command != null) {
                                throw new IllegalStateException("command != null");
                            }

                            // We don't know whether the remote side of the socket was closed or
                            // not until we attempt to read from it from processOneCommand. This shows up as
                            // a regular POLLIN event in our regular processing loop.
                            if (connection.isClosedByPeer()) {
                                connection.closeSocket();
                                peers.remove(i);
                                fds.remove(i);
                            }
                        }
                    } catch (Exception e) {
                        if (!mIsForkChild) {
                            // We're in the server so any exception here is one that has taken place
                            // pre-fork while processing commands or reading / writing from the
                            // control socket. Make a loud noise about any such exceptions so that
                            // we know exactly what failed and why.

                            Slog.e(TAG, "Exception executing zygote command: ", e);

                            // Make sure the socket is closed so that the other end knows immediately
                            // that something has gone wrong and doesn't time out waiting for a
                            // response.
                            ZygoteConnection conn = peers.remove(i);
                            conn.closeSocket();

                            fds.remove(i);
                        } else {
                            // We're in the child so any exception caught here has happened post
                            // fork and before we execute ActivityThread.main (or any other main()
                            // method). Log the details of the exception and bring down the process.
                            Log.e(TAG, "Caught post-fork exception in child process.", e);
                            throw e;
                        }
                    }
                }
            }
        }
    }


ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
這個函數首先創建兩個鏈表,第一個鏈表 fds 是用來保存要監聽的socket文件描述符。
第二個鏈表peers用來保存對應的socket文件上的事件處理函數
另外 fds 和 peers 中元素是有對應關鍵的,即:fds中的第i個元素所對應的處理類就是peers中的第i個元素。這個後面的代碼中可以看出來
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
這裏將mServerSocket.getFileDescriptor()添加到fds裏面,就是將zygote自己創建的用來監聽ActivityManager連接的socket添加到fds鏈表裏面。因爲這個socket上沒有對應的事件處理類,因此其對應的peers中的處理類對象設置爲null

 

StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {// 填充pollFds
    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);
}

  上面這個部分代碼就是每次循環都會 根據 fds 的大小重新建立pollFds,然後開始監聽。

// 上面的函數一旦監聽到動作就會返回,然後執行下面的代碼
for (int i = pollFds.length - 1; i >= 0; --i) {
 if ((pollFds[i].revents & POLLIN) == 0) {
     continue;
 }
 // 上面根據監聽的pollFds的長度,循環從後到前,依次判斷是哪個句柄上存在數據,獲取存在數據的句柄
 
 if (i == 0) { // 如果i等於0,就說明是zygote的socket上監聽到了連接請求。
    // 對於新的鏈接請求,這裏會調用 acceptCommandPeer 函數,這個函數會調用 mServerSocket.accept() 接受連接,並返回句柄
    // 然後用此句柄爲參數創建了 ZygoteConnection 對象,然後由 ZygoteConnection 對象負責這一個連接的後續數據處理
    ZygoteConnection newPeer = acceptCommandPeer(abiList);
    peers.add(newPeer); // 將新創建的ZygoteConnection添加到 peers 這個列表中
    fds.add(newPeer.getFileDesciptor());  // 添加到 fds,然後在下次循環的時候,將剛剛接受的鏈接請求也一同添加到監聽。
 } else { // 如果i不是0.就說明是已將連接的socket上有數據發送過來了
   ZygoteConnection connection = peers.get(i); // 從剛剛記錄的peers中獲取處理對應數據的 ZygoteConnection 類
   final Runnable command = connection.processOneCommand(this); // 調用processOneCommand 函數處理socket發送過來的數據。
   if (mIsForkChild) { // 由於前面processOneCommand函數很可能會創建新的進程,因此當再次返回這裏的時候,有可能會有兩個進程這裏就需要判斷是在那個進程中
   	// 這裏是在子進程。表示在processOneCommand中fork了新的進程,此時返回來的時候,新的進程會設置 mIsForkChild 標誌位
       if (command == null) {
           throw new IllegalStateException("command == null");
       }
       return command;
   } else {
   	   // 這裏是在父進程中。表示的時候 zygote 進程,
       // 下面會關閉socket,並且將此socket的文件句柄,以及對應的處理類從鏈表中移除。
       if (connection.isClosedByPeer()) {
           connection.closeSocket();
           peers.remove(i);
           fds.remove(i);
       }
   }
 }
}

下面我們看下acceptCommandPeer函數的具體實現:

    /**
     * Waits for and accepts a single command connection. Throws
     * RuntimeException on failure.
     // socket編程中,accept()調用主要用在基於連接的套接字類型,比如SOCK_STREAM和SOCK_SEQPACKET
     // 它提取出所監聽套接字的等待連接隊列中第一個連接請求,創建一個新的套接字,並返回指向該套接字的文件描述符
     // 新建立的套接字不在監聽狀態,原來所監聽的套接字的狀態也不受accept()調用的影響
	 // 從代碼,可以看出 acceptCommandPeer 調用了server socket的accpet函數。於是當新的連接建立時,
	 // zygote將會創建出一個新的socket與其通信,並將該socket加入到fds中。因此,一旦通信連接建立後,fds中將會包含有多個socket
     */
    private ZygoteConnection acceptCommandPeer(String abiList) {
        try {
			// 注意這裏的參數中調用了 mServerSocket.accept()
            return createNewConnection(mServerSocket.accept(), abiList);
        } catch (IOException ex) {
            throw new RuntimeException(
                    "IOException during accept()", ex);
        }
    }

    protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
            throws IOException {
		 // 這裏根據參數,直接創建ZygoteConnection類對象
        return new ZygoteConnection(socket, abiList);
    }


下面是ZygoteConnection的構造函數
    /**
     * Constructs instance from connected socket.
     *
     * @param socket non-null; connected socket
     * @param abiList non-null; a list of ABIs this zygote supports.
     * @throws IOException
     */
    ZygoteConnection(LocalSocket socket, String abiList) throws IOException {
        mSocket = socket;
        this.abiList = abiList;
        mSocketOutStream= new DataOutputStream(socket.getOutputStream());
        mSocketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()), 256);
        mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
        try {
            peer = mSocket.getPeerCredentials();
        } catch (IOException ex) {
            Log.e(TAG, "Cannot read peer credentials", ex);
            throw ex;
        }
        isEof = false;
    }

上面的代碼流程很清晰,就是創建了一個ZygoteConnection對象。這個對象是用來處理這個socket具體發送過來的數據的。

下面我們在看下processOneCommand函數的具體實現。看看ZygoteConnection類中的processOneCommand函數都幹了什麼。

/**
 * Reads one start command from the command socket. If successful, a child is forked and a
 * {@code Runnable} that calls the childs main method (or equivalent) is returned in the child
 * process. {@code null} is always returned in the parent process (the zygote).
 *
 * If the client closes the socket, an {@code EOF} condition is set, which callers can test
 * for by calling {@code ZygoteConnection.isClosedByPeer}.
 */
Runnable processOneCommand(ZygoteServer zygoteServer) {
    String args[];
    Arguments parsedArgs = null;
    FileDescriptor[] descriptors;
    try {
        args = readArgumentList(); // 從socket 中讀取傳遞過來的各種參數
        descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {
        throw new IllegalStateException("IOException on command socket", ex);
    }

    // readArgumentList returns null only when it has reached EOF with no available
    // data to read. This will only happen when the remote socket has disconnected.
    if (args == null) {
        isEof = true;
        return null;
    }
    int pid = -1;
    FileDescriptor childPipeFd = null;
    FileDescriptor serverPipeFd = null;

	// parsedArgs 這個類是個工具類,主要是保存 並解析上面傳遞的參數,並保存解析的結果
	// 這裏根據讀取到的數據,來構建Arguments類,這個類會解析傳遞過來的數據,並保存解析的結果
    parsedArgs = new Arguments(args);
    if (parsedArgs.abiListQuery) { // 查詢 AbiList
        handleAbiListQuery();
        return null;
    }
    if (parsedArgs.preloadDefault) { // 加載,並返回結果
        handlePreload();
        return null;
    }
    if (parsedArgs.preloadPackage != null) { // 預加載,
        handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs,
                parsedArgs.preloadPackageCacheKey);
        return null;
    }

    if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
        throw new ZygoteSecurityException("Client may not specify capabilities: " +
                "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
                ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
    }

	// 安全檢查
    applyUidSecurityPolicy(parsedArgs, peer);
    applyInvokeWithSecurityPolicy(parsedArgs, peer);
    applyDebuggerSystemProperty(parsedArgs);
    applyInvokeWithSystemProperty(parsedArgs);

    int[] fdsToIgnore = null;

	Log.e(TAG, " processOneCommand  parsedArgs.invokeWith = "+parsedArgs.invokeWith);
    if (parsedArgs.invokeWith != null) { // 這裏好像一直都是空的,因此這裏進不去
        try {
            FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC); // 獲取管道通訊的兩端
            childPipeFd = pipeFds[1];  // 寫入端
            serverPipeFd = pipeFds[0]; // 讀取端
            Os.fcntlInt(childPipeFd, F_SETFD, 0);
            fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
        } catch (ErrnoException errnoEx) {
            throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
        }
    }

    /**
     * In order to avoid leaking descriptors to the Zygote child,
     * the native code must close the two Zygote socket descriptors
     * in the child process before it switches from Zygote-root to
     * the UID and privileges of the application being launched.
     *
     * In order to avoid "bad file descriptor" errors when the
     * two LocalSocket objects are closed, the Posix file
     * descriptors are released via a dup2() call which closes
     * the socket and substitutes an open descriptor to /dev/null.
     */

    int [] fdsToClose = { -1, -1 };
    FileDescriptor fd = mSocket.getFileDescriptor();
    if (fd != null) {
        fdsToClose[0] = fd.getInt$();
    }
    fd = zygoteServer.getServerSocketFileDescriptor();
    if (fd != null) {
        fdsToClose[1] = fd.getInt$();
    }
    fd = null;
	// 創建子進程
    pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
            parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
            parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
            parsedArgs.appDataDir);

    try {
        if (pid == 0) {
            // in child 
			// 因爲子進程是複製於父進程,因此在子進程中 他的 mIsForkChild 值依然是父進程的原始值,false
			// 此時調用 setForkChild 只會設置子進程中的 mIsForkChild 變量的值,
            zygoteServer.setForkChild(); //設置標誌.這樣在這個地方返回的時候,zygoteServer 就會走到子進程的處理函數中了

            zygoteServer.closeServerSocket(); // 關閉子線程中的 socket,這個socket是從zygote集成過來的,因此這裏需要首選關閉掉。
            IoUtils.closeQuietly(serverPipeFd); // 關閉流
            serverPipeFd = null;

            return handleChildProc(parsedArgs, descriptors, childPipeFd);
        } else {
            // In the parent. A pid < 0 indicates a failure and will be handled in
            // handleParentProc. 這裏是在父進程中
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            handleParentProc(pid, descriptors, serverPipeFd);
            return null;
        }
    } finally {
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

這個函數的流程比較簡單,首先讀取對端發送過來的數據,然後根據發送過來的數據構建Arguments這個類,這類會解析傳遞過來的參數,並保存解析的結果。然後根據解析情況進行各種判斷。然後調用Zygote.forkAndSpecialize創建新的進程,這個函數會有兩次返回,第一次是在原來的父進程中返回,第二次是在新創建的子進程中返回。從這個函數返回起,子進程和父進程就分道揚鑣了,這個時候,我們需要注意下自己看的這部分代碼是在子線程中還是在父進程中。
 

下面我們在貼下forkAndSpecialize函數的代碼
 public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
       int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
       int[] fdsToIgnore, String instructionSet, String appDataDir) {
     VM_HOOKS.preFork(); // 這裏會等待zygote的所有子線程都退出即:停止Zyote的4個Daemon子線程的運行,初始化gc堆
     // Resets nice priority for zygote process.
     resetNicePriority(); // 設置zygote進程的優先級爲 normal
     int pid = nativeForkAndSpecialize(
               uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
               fdsToIgnore, instructionSet, appDataDir);
     // Enable tracing as soon as possible for the child process.
     if (pid == 0) {
		// 子進程中
         Trace.setTracingEnabled(true, debugFlags);

         // Note that this event ends at the end of handleChildProc,
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
     }
     VM_HOOKS.postForkCommon(); // 啓動4個Deamon子線程
     return pid;
 }

下面我們看下handleChildProc函數的大體流程

    private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
            FileDescriptor pipeFd) {

        closeSocket(); // 關閉socket。這個socket 根前面剛剛關閉的socket不是同一個

        if (parsedArgs.niceName != null) { // 設置子進程的名稱
            Process.setArgV0(parsedArgs.niceName);
        }

        // End of the postFork event.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        if (parsedArgs.invokeWith != null) { // 這裏好像一直都是空的
            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(),
                    pipeFd, parsedArgs.remainingArgs);

            // Should not get here.
            throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
        } else { // 這裏調用 ZygoteInit.zygoteInit 進一步初始化
            return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                    null /* classLoader */);
        }
    }

下面我們看下ZygoteInit.zygoteInit的實現

	// 這個函數是一個公共的函數,啓動 systemServer 以及啓動 應用都會調用到這裏
    public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams(); // 將system.out 以及System.err 的輸出重定向到 Android  log中

        RuntimeInit.commonInit();
        ZygoteInit.nativeZygoteInit(); // 初始化native層
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

    下面是applicationInit函數的實現
    protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
		// 如果應用調用System.exit()直接終結一個進程,但是沒有調用 shutdown hooks,這個對於一個Android應用了來說確實可以
		// 但是shutdown hooks是用來關閉Binder的,如果沒有調用,會導致一些線程遺留,造成crash
        nativeSetExitWithoutCleanup(true);

        // We want to be fairly aggressive about heap utilization, to avoid
        // holding on to a lot of memory that isn't needed.
        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);  // 與內存佔用相關
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); // 設置sdk版本

        final Arguments args = new Arguments(argv);

        // The end of of the RuntimeInit event (see #zygoteInit).
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        // Remaining arguments are passed to the start class's static main
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }

 這個findStaticMain函數會根據傳遞的參數,找到對應的java類的靜態main函數,然後 通過return new MethodAndArgsCaller(m, argv);來返回一個MethodAndArgsCaller類,下面我們看下MethodAndArgsCaller類的實現。

  static class MethodAndArgsCaller implements Runnable {
    /** method to call */
    private final Method mMethod;
    /** argument array */
    private final String[] mArgs;
    public MethodAndArgsCaller(Method method, String[] args) {
        mMethod = method;
        mArgs = args;
    }

    public void run() {
        try {
            mMethod.invoke(null, new Object[] { mArgs }); //這個會調用相應的方法並將mArgs作爲參數傳遞過去
        } catch (IllegalAccessException ex) {
            throw new RuntimeException(ex);
        } catch (InvocationTargetException ex) {
            Throwable cause = ex.getCause();
            if (cause instanceof RuntimeException) {
                throw (RuntimeException) cause;
            } else if (cause instanceof Error) {
                throw (Error) cause;
            }
            throw new RuntimeException(ex);
        }
    }
}

這個類的實現很簡單,就是保存要啓動的函數對象,已經要傳遞的參數,然後提供一個 run函數來執行對應的函數並傳遞參數給這個函數。如果這裏調用的是 SystemServer,那麼這裏就會調用SystemServer.java的main函數,如果是啓動的應用,那就會調用ActivityThread.java 的main函數。

但是上面的findStaticMain並沒有調用這個run函數,而是僅僅創建了一個類對象,然後就將這個對象返回了。那麼這個函數是在哪裏調用的呢,這裏就一層一層的返回了,首先這裏會返回到ZygoteConnection.java的processOneCommand 函數,然後這個函數接着返回,會返回到ZygoteServer.java中的runSelectLoop函數中,在這個函數有下面的代碼:

if (mIsForkChild) {
    // We're in the child. We should always have a command to run at this
    // stage if processOneCommand hasn't called "exec".
    // 這裏是在子進程
    if (command == null) {
        throw new IllegalStateException("command == null");
    }
    return command; // 這裏再次返回
}

上面的代碼會繼續返回到ZygoteInit.java中的main函數中;下面這部分代碼就會main函數的處理函數。


            // The select loop returns early in the child process after a fork and
            // loops forever in the zygote.
            caller = zygoteServer.runSelectLoop(abiList); // zygote進程進入無限循環,處理請求
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
		    Log.i(TAG, "zygoteServer.closeServerSocket finally finally");
			// 這個地方有兩個調用的流程
			// 1: zygote 進程退出的時候會調用這個函數,用來關閉zygote自己創建的用來接收ActivityManager的鏈接請求的socket
			// 2:當每個子線程fork完畢,準備好之後,會走到這裏,這個時候會在子進程中執行的,這裏會調用closeServerSocket函數,確保從zygote集成過來的socket關閉。
			//    其實這個時候,因爲子進程剛剛fock出來的時候就已經掉用過closeServerSocket函數了,因此再次調用,是沒有效果的
            zygoteServer.closeServerSocket();
        }

        // We're in the child process and have exited the select loop. Proceed to execute the
        // command.
        if (caller != null) {
            caller.run(); // 這裏纔是重點,上面會返回一個Runnable的對象,這個地方調用他的 run函數會進入到子進程的真正的main函數裏面
        }

上面的這段代碼,當zygoteServer.runSelectLoop返回的時候,就已經是在子進程中了,此時會在後面調用caller.run();來執行對應的java文件的main函數。至此zygote中啓動新進程的流程就梳理完成了。

 

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