Android 世界中,誰喊醒了 Zygote?

本文基於 Android 9.0 , 代碼倉庫地址 : https://github.com/lulululbj/android_9.0.0_r45

文中源碼鏈接:

https://github.com/lulululbj/android_9.0.0_r45/blob/master/frameworks/base/services/java/com/android/server/SystemServer.java

https://github.com/lulululbj/android_9.0.0_r45/blob/master/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

https://github.com/lulululbj/android_9.0.0_r45/blob/master/frameworks/base/core/java/android/os/Process.java

https://github.com/lulululbj/android_9.0.0_r45/blob/master/frameworks/base/core/java/android/os/ZygoteProcess.java

對 Zygote 和 SystemServer 啟動流程還不熟悉的建議閱讀下面兩篇文章:

https://juejin.im/post/5d8f73bf51882555b149dc64

https://juejin.im/post/5da341f451882561ba64b9da

Zygote 作為 Android 世界的受精卵,在成功繁殖出 system_server 進程之後並沒有完全功成身退,仍然承擔著受精卵的責任。Zygote 通過調用其持有的 ZygoteServer 對象的 runSelectLoop() 方法開始等待客戶端的呼喚,有求必應。客戶端的請求無非是創建應用進程,以 startActivity() 為例,假如開啟的是一個尚未創建進程的應用,那麼就會向 Zygote 請求創建進程。下面將從 客戶端發送請求服務端處理請求 兩方面來進行解析。

客戶端發送請求

startActivity() 的具體流程這裡就不分析了,系列後續文章會寫到。我們直接看到創建進程的 startProcess() 方法,該方法在 ActivityManagerService 中,後面簡稱 AMS。

Process.startProcess()

> ActivityManagerService.java
private ProcessStartResult startProcess(String hostingType, String entryPoint,
 ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
 String seInfo, String requiredAbi, String instructionSet, String invokeWith,
 long startTime) {
 try {
 checkTime(startTime, "startProcess: asking zygote to start proc");
 final ProcessStartResult startResult;
 if (hostingType.equals("webview_service")) {
 startResult = startWebView(entryPoint,
 app.processName, uid, uid, gids, runtimeFlags, mountExternal,
 app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
 app.info.dataDir, null,
 new String[] {PROC_START_SEQ_IDENT + app.startSeq});
 } else {
 // 新建進程
 startResult = Process.start(entryPoint,
 app.processName, uid, uid, gids, runtimeFlags, mountExternal,
 app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
 app.info.dataDir, invokeWith,
 new String[] {PROC_START_SEQ_IDENT + app.startSeq});
 }
 checkTime(startTime, "startProcess: returned from zygote!");
 return startResult;
 } finally {
 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 }
}

調用 Process.start() 方法新建進程,繼續追進去:

> Process.java
public static final ProcessStartResult start(
 // android.app.ActivityThread,創建進程後會調用其 main() 方法
 final String processClass,
 final String niceName, // 進程名
 int uid, int gid, int[] gids,
 int runtimeFlags, int mountExternal,
 int targetSdkVersion,
 String seInfo,
 String abi,
 String instructionSet,
 String appDataDir,
 String invokeWith, // 一般新建應用進程時,此參數不為 null
 String[] zygoteArgs) {
 return zygoteProcess.start(processClass, niceName, uid, gid, gids,
 runtimeFlags, mountExternal, targetSdkVersion, seInfo,
 abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
 }

繼續調用 zygoteProcess.start() :

> ZygoteProess.java
public final Process.ProcessStartResult start(final String processClass,
 final String niceName,
 int uid, int gid, int[] gids,
 int runtimeFlags, int mountExternal,
 int targetSdkVersion,
 String seInfo,
 String abi,
 String instructionSet,
 String appDataDir,
 String invokeWith,
 String[] zygoteArgs) {
 try {
 return startViaZygote(processClass, niceName, uid, gid, gids,
 runtimeFlags, mountExternal, targetSdkVersion, seInfo,
 abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
 zygoteArgs);
 } catch (ZygoteStartFailedEx ex) {
 Log.e(LOG_TAG,
 "Starting VM process through Zygote failed");
 throw new RuntimeException(
 "Starting VM process through Zygote failed", ex);
 }
}

調用 startViaZygote() 方法。終於看到 Zygote 的身影了。

startViaZygote()

> ZygoteProcess.java
private Process.ProcessStartResult startViaZygote(final String processClass,
 final String niceName,
 final int uid, final int gid,
 final int[] gids,
 int runtimeFlags, int mountExternal,
 int targetSdkVersion,
 String seInfo,
 String abi,
 String instructionSet,
 String appDataDir,
 String invokeWith,
 boolean startChildZygote, // 是否克隆 zygote 進程的所有狀態
 String[] extraArgs)
 throws ZygoteStartFailedEx {
 ArrayList argsForZygote = new ArrayList();
 // --runtime-args, --setuid=, --setgid=,
 // and --setgroups= must go first
 // 處理參數
 argsForZygote.add("--runtime-args");
 argsForZygote.add("--setuid=" + uid);
 argsForZygote.add("--setgid=" + gid);
 argsForZygote.add("--runtime-flags=" + runtimeFlags);
 if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
 argsForZygote.add("--mount-external-default");
 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
 argsForZygote.add("--mount-external-read");
 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
 argsForZygote.add("--mount-external-write");
 }
 argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
 // --setgroups is a comma-separated list
 if (gids != null && gids.length > 0) {
 StringBuilder sb = new StringBuilder();
 sb.append("--setgroups=");
 int sz = gids.length;
 for (int i = 0; i < sz; i++) {
 if (i != 0) {
 sb.append(',');
 }
 sb.append(gids[i]);
 }
 argsForZygote.add(sb.toString());
 }
 if (niceName != null) {
 argsForZygote.add("--nice-name=" + niceName);
 }
 if (seInfo != null) {
 argsForZygote.add("--seinfo=" + seInfo);
 }
 if (instructionSet != null) {
 argsForZygote.add("--instruction-set=" + instructionSet);
 }
 if (appDataDir != null) {
 argsForZygote.add("--app-data-dir=" + appDataDir);
 }
 if (invokeWith != null) {
 argsForZygote.add("--invoke-with");
 argsForZygote.add(invokeWith);
 }
 if (startChildZygote) {
 argsForZygote.add("--start-child-zygote");
 }
 argsForZygote.add(processClass);
 if (extraArgs != null) {
 for (String arg : extraArgs) {
 argsForZygote.add(arg);
 }
 }
 synchronized(mLock) {
 // 和 Zygote 進程進行 socket 通信
 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
 }
}

前面一大串代碼都是在處理參數,大致瀏覽即可。核心在於最後的 openZygoteSocketIfNeeded() 和 zygoteSendArgsAndGetResult() 這兩個方法。從方法命名就可以看出來,這裡要和 Zygote 進行 socket 通信了。還記得 ZygoteInit.main() 方法中調用的 registerServerSocketFromEnv() 方法嗎?它在 Zygote 進程中創建了服務端 socket。

openZygoteSocketIfNeeded()

先來看看 openZygoteSocketIfNeeded() 方法。

> ZygoteProcess.java
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
 Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
 
 // 未連接或者連接已關閉
 if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
 try {
 // 開啟 socket 連接
 primaryZygoteState = ZygoteState.connect(mSocket);
 } catch (IOException ioe) {
 throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
 }
 maybeSetApiBlacklistExemptions(primaryZygoteState, false);
 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
 }
 if (primaryZygoteState.matches(abi)) {
 return primaryZygoteState;
 }
 // 當主 zygote 沒有匹配成功,嘗試 connect 第二個 zygote
 if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
 try {
 secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
 } catch (IOException ioe) {
 throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
 }
 maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
 }
 if (secondaryZygoteState.matches(abi)) {
 return secondaryZygoteState;
 }
 throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}

如果與 Zygote 進程的 socket 連接未開啟,則嘗試開啟,可能會產生阻塞和重試。連接調用的是 ZygoteState.connect() 方法,ZygoteState 是 ZygoteProcess 的內部類。

 > ZygoteProcess.java
 
 public static class ZygoteState {
 final LocalSocket socket;
 final DataInputStream inputStream;
 final BufferedWriter writer;
 final List abiList;
 boolean mClosed;
 private ZygoteState(LocalSocket socket, DataInputStream inputStream,
 BufferedWriter writer, List abiList) {
 this.socket = socket;
 this.inputStream = inputStream;
 this.writer = writer;
 this.abiList = abiList;
 }
 public static ZygoteState connect(LocalSocketAddress address) throws IOException {
 DataInputStream zygoteInputStream = null;
 BufferedWriter zygoteWriter = null;
 final LocalSocket zygoteSocket = new LocalSocket();
 try {
 zygoteSocket.connect(address);
 zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
 zygoteWriter = new BufferedWriter(new OutputStreamWriter(
 zygoteSocket.getOutputStream()), 256);
 } catch (IOException ex) {
 try {
 zygoteSocket.close();
 } catch (IOException ignore) {
 }
 throw ex;
 }
 String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
 Log.i("Zygote", "Process: zygote socket " + address.getNamespace() + "/"
 + address.getName() + " opened, supported ABIS: " + abiListString);
 return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
 Arrays.asList(abiListString.split(",")));
 }
 ...
}

通過 socket 連接 Zygote 遠程服務端。

再回頭看之前的 zygoteSendArgsAndGetResult() 方法。

zygoteSendArgsAndGetResult()

 > ZygoteProcess.java
 
 private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
 ZygoteState zygoteState, ArrayList args)
 throws ZygoteStartFailedEx {
 try {
 ...
 final BufferedWriter writer = zygoteState.writer;
 final DataInputStream inputStream = zygoteState.inputStream;
 writer.write(Integer.toString(args.size()));
 writer.newLine();
 // 向 zygote 進程發送參數
 for (int i = 0; i < sz; i++) {
 String arg = args.get(i);
 writer.write(arg);
 writer.newLine();
 }
 writer.flush();
 // 是不是應該有一個超時時間?
 Process.ProcessStartResult result = new Process.ProcessStartResult();
 // Always read the entire result from the input stream to avoid leaving
 // bytes in the stream for future process starts to accidentally stumble
 // upon.
 // 讀取 zygote 進程返回的子進程 pid
 result.pid = inputStream.readInt();
 result.usingWrapper = inputStream.readBoolean();
 if (result.pid < 0) { // pid 小於 0 ,fork 失敗
 throw new ZygoteStartFailedEx("fork() failed");
 }
 return result;
 } catch (IOException ex) {
 zygoteState.close();
 throw new ZygoteStartFailedEx(ex);
 }
}

通過 socket 發送請求參數,然後等待 Zygote 進程返回子進程 pid 。客戶端的工作到這裡就暫時完成了,我們再追蹤到服務端,看看服務端是如何處理客戶端請求的。

Zygote 處理客戶端請求

Zygote 處理客戶端請求的代碼在 ZygoteServer.runSelectLoop() 方法中。

 > ZygoteServer.java
 
 Runnable runSelectLoop(String abiList) {
 ...
 while (true) {
 ...
 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;
 }
 if (i == 0) { // 有新客戶端連接
 ZygoteConnection newPeer = acceptCommandPeer(abiList);
 peers.add(newPeer);
 fds.add(newPeer.getFileDesciptor());
 } else { // 處理客戶端請求
 try {
 ZygoteConnection connection = peers.get(i);
 // fork 子進程,並返回包含子進程 main() 函數的 Runnable 對象
 final Runnable command = connection.processOneCommand(this);
 if (mIsForkChild) {
 // 位於子進程
 if (command == null) {
 throw new IllegalStateException("command == null");
 }
 return command;
 } else {
 // 位於父進程
 if (command != null) {
 throw new IllegalStateException("command != null");
 }
 if (connection.isClosedByPeer()) {
 connection.closeSocket();
 peers.remove(i);
 fds.remove(i);
 }
 }
 } catch (Exception e) {
 ...
 } finally {
 mIsForkChild = false;
 }
 }
 }
 }
}

acceptCommandPeer() 方法用來響應新客戶端的 socket 連接請求。processOneCommand() 方法用來處理客戶端的一般請求。

processOneCommand()

> ZygoteConnection.java
Runnable processOneCommand(ZygoteServer zygoteServer) {
 String args[];
 Arguments parsedArgs = null;
 FileDescriptor[] descriptors;
 try {
 // 1. 讀取 socket 客戶端發送過來的參數列表
 args = readArgumentList();
 descriptors = mSocket.getAncillaryFileDescriptors();
 } catch (IOException ex) {
 throw new IllegalStateException("IOException on command socket", ex);
 }
 ...
 // 2. fork 子進程
 pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
 parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
 parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
 parsedArgs.instructionSet, parsedArgs.appDataDir);
 try {
 if (pid == 0) {
 // 處於進子進程
 zygoteServer.setForkChild();
 // 關閉服務端 socket
 zygoteServer.closeServerSocket();
 IoUtils.closeQuietly(serverPipeFd);
 serverPipeFd = null;
 // 3. 處理子進程事務
 return handleChildProc(parsedArgs, descriptors, childPipeFd,
 parsedArgs.startChildZygote);
 } else {
 // 處於 Zygote 進程
 IoUtils.closeQuietly(childPipeFd);
 childPipeFd = null;
 // 4. 處理父進程事務
 handleParentProc(pid, descriptors, serverPipeFd);
 return null;
 }
 } finally {
 IoUtils.closeQuietly(childPipeFd);
 IoUtils.closeQuietly(serverPipeFd);
 }
}
 

processOneCommand() 方法大致可以分為五步,下面逐步分析。

readArgumentList()

> ZygoteConnection.java
private String[] readArgumentList()
 throws IOException {
 int argc;
 try {
 // 逐行讀取參數
 String s = mSocketReader.readLine();
 if (s == null) {
 // EOF reached.
 return null;
 }
 argc = Integer.parseInt(s);
 } catch (NumberFormatException ex) {
 throw new IOException("invalid wire format");
 }
 // See bug 1092107: large argc can be used for a DOS attack
 if (argc > MAX_ZYGOTE_ARGC) {
 throw new IOException("max arg count exceeded");
 }
 String[] result = new String[argc];
 for (int i = 0; i < argc; i++) {
 result[i] = mSocketReader.readLine();
 if (result[i] == null) {
 // We got an unexpected EOF.
 throw new IOException("truncated request");
 }
 }
 return result;
}

讀取客戶端發送過來的請求參數。

forkAndSpecialize()

> Zygote.java
public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
 int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
 int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) {
 VM_HOOKS.preFork();
 // Resets nice priority for zygote process.
 resetNicePriority();
 int pid = nativeForkAndSpecialize(
 uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
 fdsToIgnore, startChildZygote, instructionSet, appDataDir);
 // Enable tracing as soon as possible for the child process.
 if (pid == 0) {
 Trace.setTracingEnabled(true, runtimeFlags);
 // Note that this event ends at the end of handleChildProc,
 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
 }
 VM_HOOKS.postForkCommon();
 return pid;
}

nativeForkAndSpecialize() 是一個 native 方法,在底層 fork 了一個新進程,並返回其 pid。不要忘記了這裡的 一次fork,兩次返回 。pid > 0 說明還是父進程。pid = 0 說明進入了子進程。子進程中會調用 handleChildProc,而父進程中會調用 handleParentProc()。

handleChildProc()

> ZygoteConnection.java
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
 FileDescriptor pipeFd, boolean isZygote) {
 closeSocket(); // 關閉 socket 連接
 ...
 if (parsedArgs.niceName != null) {
 // 設置進程名
 Process.setArgV0(parsedArgs.niceName);
 }
 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 {
 if (!isZygote) { // 新建應用進程時 isZygote 參數為 false
 return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
 null /* classLoader */);
 } else {
 return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
 parsedArgs.remainingArgs, null /* classLoader */);
 }
 }
}

當看到 ZygoteInit.zygoteInit() 時你應該感覺很熟悉了,接下來的流程就是:

ZygoteInit.zygoteInit() -> RuntimeInit.applicationInit() -> findStaticMain()

和 SystemServer 進程的創建流程一致。這裡要找的 main 方法就是 ActivityThrad.main() 。ActivityThread 雖然並不是一個線程,但你可以把它理解為應用的主線程。

handleParentProc()

> ZygoteConnection.java
private void handleParentProc(int pid, FileDescriptor[] descriptors, FileDescriptor pipeFd) {
 if (pid > 0) {
 setChildPgid(pid);
 }
 if (descriptors != null) {
 for (FileDescriptor fd: descriptors) {
 IoUtils.closeQuietly(fd);
 }
 }
 boolean usingWrapper = false;
 if (pipeFd != null && pid > 0) {
 int innerPid = -1;
 try {
 // Do a busy loop here. We can't guarantee that a failure (and thus an exception
 // bail) happens in a timely manner.
 final int BYTES_REQUIRED = 4; // Bytes in an int.
 StructPollfd fds[] = new StructPollfd[] {
 new StructPollfd()
 };
 byte data[] = new byte[BYTES_REQUIRED];
 int remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS;
 int dataIndex = 0;
 long startTime = System.nanoTime();
 while (dataIndex  
< data.length && remainingSleepTime > 0) { fds[0].fd = pipeFd; fds[0].events = (short) POLLIN; fds[0].revents = 0; fds[0].userData = null; int res = android.system.Os.poll(fds, remainingSleepTime); long endTime = System.nanoTime(); int elapsedTimeMs = (int)((endTime - startTime) / 1000000l); remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS - elapsedTimeMs; if (res > 0) { if ((fds[0].revents & POLLIN) != 0) { // Only read one byte, so as not to block. int readBytes = android.system.Os.read(pipeFd, data, dataIndex, 1); if (readBytes < 0) { throw new RuntimeException("Some error"); } dataIndex += readBytes; } else { // Error case. revents should contain one of the error bits. break; } } else if (res == 0) { Log.w(TAG, "Timed out waiting for child."); } } if (dataIndex == data.length) { DataInputStream is = new DataInputStream(new ByteArrayInputStream(data)); innerPid = is.readInt(); } if (innerPid == -1) { Log.w(TAG, "Error reading pid from wrapped process, child may have died"); } } catch (Exception ex) { Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex); } // Ensure that the pid reported by the wrapped process is either the // child process that we forked, or a descendant of it. if (innerPid > 0) { int parentPid = innerPid; while (parentPid > 0 && parentPid != pid) { parentPid = Process.getParentPid(parentPid); } if (parentPid > 0) { Log.i(TAG, "Wrapped process has pid " + innerPid); pid = innerPid; usingWrapper = true; } else { Log.w(TAG, "Wrapped process reported a pid that is not a child of " + "the process that we forked: childPid=" + pid + " innerPid=" + innerPid); } } } try { mSocketOutStream.writeInt(pid); mSocketOutStream.writeBoolean(usingWrapper); } catch (IOException ex) { throw new IllegalStateException("Error writing to command socket", ex); } }

主要進行一些資源清理的工作。到這裡,子進程就創建完成了。

總結

Android 世界中,誰喊醒了 Zygote?

  1. 調用 Process.start() 創建應用進程
  2. ZygoteProcess 負責和 Zygote 進程建立 socket 連接,並將創建進程需要的參數發送給 Zygote 的 socket 服務端
  3. Zygote 服務端接收到參數之後調用 ZygoteConnection.processOneCommand() 處理參數,並 fork 進程
  4. 最後通過 findStaticMain() 找到 ActivityThread 類的 main() 方法並執行,子進程就啟動了

預告

到現在為止已經解析了 Zygote 進程 ,SystemServer 進程,以及應用進程的創建。下一篇的內容是和應用最密切相關的系統服務 ActivityManagerService , 來看看它在 SystemServer 中是如何被創建和啟動的,敬請期待!

本文由博客一文多發平臺 https://openwrite.cn?from=article_bottom 發佈!


分享到:


相關文章: