Zygote 作为 Android 世界的受精卵,在成功繁殖出 system_server 进程之后并没有完全功成身退,仍然承担着受精卵的责任。Zygote 通过调用其持有的 ZygoteServer 对象的 runSelectLoop() 方法开始等待客户端的呼唤,有求必应。客户端的请求无非是创建应用进程,以 startActivity() 为例,假如开启的是一个尚未创建进程的应用,那么就会向 Zygote 请求创建进程。下面将从 客户端发送请求 和 服务端处理请求 两方面来进行解析。
客户端发送请求
startActivity() 的具体流程这里就不分析了,系列后续文章会写到。我们直接看到创建进程的 startProcess() 方法,该方法在 ActivityManagerService 中,后面简称 AMS。
Process.startProcess()
1> ActivityManagerService.java 2 3private ProcessStartResult startProcess(String hostingType, String entryPoint, 4 ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal, 5 String seInfo, String requiredAbi, String instructionSet, String invokeWith, 6 long startTime) { 7 try { 8 checkTime(startTime, "startProcess: asking zygote to start proc"); 9 final ProcessStartResult startResult; 10 if (hostingType.equals("webview_service")) { 11 startResult = startWebView(entryPoint, 12 app.processName, uid, uid, gids, runtimeFlags, mountExternal, 13 app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, 14 app.info.dataDir, null, 15 new String[] {PROC_START_SEQ_IDENT + app.startSeq}); 16 } else { 17 // 新建进程 18 startResult = Process.start(entryPoint, 19 app.processName, uid, uid, gids, runtimeFlags, mountExternal, 20 app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, 21 app.info.dataDir, invokeWith, 22 new String[] {PROC_START_SEQ_IDENT + app.startSeq}); 23 } 24 checkTime(startTime, "startProcess: returned from zygote!"); 25 return startResult; 26 } finally { 27 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 28 } 29}
调用 Process.start() 方法新建进程,继续追进去:
1> Process.java 2 3public static final ProcessStartResult start( 4 // android.app.ActivityThread,创建进程后会调用其 main() 方法 5 final String processClass, 6 final String niceName, // 进程名 7 int uid, int gid, int[] gids, 8 int runtimeFlags, int mountExternal, 9 int targetSdkVersion, 10 String seInfo, 11 String abi, 12 String instructionSet, 13 String appDataDir, 14 String invokeWith, // 一般新建应用进程时,此参数不为 null 15 String[] zygoteArgs) { 16 return zygoteProcess.start(processClass, niceName, uid, gid, gids, 17 runtimeFlags, mountExternal, targetSdkVersion, seInfo, 18 abi, instructionSet, appDataDir, invokeWith, zygoteArgs); 19 }
继续调用 zygoteProcess.start() :
1> ZygoteProess.java 2 3public final Process.ProcessStartResult start(final String processClass, 4 final String niceName, 5 int uid, int gid, int[] gids, 6 int runtimeFlags, int mountExternal, 7 int targetSdkVersion, 8 String seInfo, 9 String abi, 10 String instructionSet, 11 String appDataDir, 12 String invokeWith, 13 String[] zygoteArgs) { 14 try { 15 return startViaZygote(processClass, niceName, uid, gid, gids, 16 runtimeFlags, mountExternal, targetSdkVersion, seInfo, 17 abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */, 18 zygoteArgs); 19 } catch (ZygoteStartFailedEx ex) { 20 Log.e(LOG_TAG, 21 "Starting VM process through Zygote failed"); 22 throw new RuntimeException( 23 "Starting VM process through Zygote failed", ex); 24 } 25}
调用 startViaZygote() 方法。终于看到 Zygote 的身影了。
startViaZygote()
1> ZygoteProcess.java 2 3private Process.ProcessStartResult startViaZygote(final String processClass, 4 final String niceName, 5 final int uid, final int gid, 6 final int[] gids, 7 int runtimeFlags, int mountExternal, 8 int targetSdkVersion, 9 String seInfo, 10 String abi, 11 String instructionSet, 12 String appDataDir, 13 String invokeWith, 14 boolean startChildZygote, // 是否克隆 zygote 进程的所有状态 15 String[] extraArgs) 16 throws ZygoteStartFailedEx { 17 ArrayList<String> argsForZygote = new ArrayList<String>(); 18 19 // --runtime-args, --setuid=, --setgid=, 20 // and --setgroups= must go first 21 // 处理参数 22 argsForZygote.add("--runtime-args"); 23 argsForZygote.add("--setuid=" + uid); 24 argsForZygote.add("--setgid=" + gid); 25 argsForZygote.add("--runtime-flags=" + runtimeFlags); 26 if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) { 27 argsForZygote.add("--mount-external-default"); 28 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) { 29 argsForZygote.add("--mount-external-read"); 30 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) { 31 argsForZygote.add("--mount-external-write"); 32 } 33 argsForZygote.add("--target-sdk-version=" + targetSdkVersion); 34 35 // --setgroups is a comma-separated list 36 if (gids != null && gids.length > 0) { 37 StringBuilder sb = new StringBuilder(); 38 sb.append("--setgroups="); 39 40 int sz = gids.length; 41 for (int i = 0; i < sz; i++) { 42 if (i != 0) { 43 sb.append(','); 44 } 45 sb.append(gids[i]); 46 } 47 48 argsForZygote.add(sb.toString()); 49 } 50 51 if (niceName != null) { 52 argsForZygote.add("--nice-name=" + niceName); 53 } 54 55 if (seInfo != null) { 56 argsForZygote.add("--seinfo=" + seInfo); 57 } 58 59 if (instructionSet != null) { 60 argsForZygote.add("--instruction-set=" + instructionSet); 61 } 62 63 if (appDataDir != null) { 64 argsForZygote.add("--app-data-dir=" + appDataDir); 65 } 66 67 if (invokeWith != null) { 68 argsForZygote.add("--invoke-with"); 69 argsForZygote.add(invokeWith); 70 } 71 72 if (startChildZygote) { 73 argsForZygote.add("--start-child-zygote"); 74 } 75 76 argsForZygote.add(processClass); 77 78 if (extraArgs != null) { 79 for (String arg : extraArgs) { 80 argsForZygote.add(arg); 81 } 82 } 83 84 synchronized(mLock) { 85 // 和 Zygote 进程进行 socket 通信 86 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote); 87 } 88}
前面一大串代码都是在处理参数,大致浏览即可。核心在于最后的 openZygoteSocketIfNeeded() 和 zygoteSendArgsAndGetResult() 这两个方法。从方法命名就可以看出来,这里要和 Zygote 进行 socket 通信了。还记得 ZygoteInit.main() 方法中调用的 registerServerSocketFromEnv() 方法吗?它在 Zygote 进程中创建了服务端 socket。
openZygoteSocketIfNeeded()
先来看看 openZygoteSocketIfNeeded() 方法。
1> ZygoteProcess.java 2 3private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx { 4 Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held"); 5 6 // 未连接或者连接已关闭 7 if (primaryZygoteState == null || primaryZygoteState.isClosed()) { 8 try { 9 // 开启 socket 连接 10 primaryZygoteState = ZygoteState.connect(mSocket); 11 } catch (IOException ioe) { 12 throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe); 13 } 14 maybeSetApiBlacklistExemptions(primaryZygoteState, false); 15 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState); 16 } 17 if (primaryZygoteState.matches(abi)) { 18 return primaryZygoteState; 19 } 20 21 // 当主 zygote 没有匹配成功,尝试 connect 第二个 zygote 22 if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) { 23 try { 24 secondaryZygoteState = ZygoteState.connect(mSecondarySocket); 25 } catch (IOException ioe) { 26 throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe); 27 } 28 maybeSetApiBlacklistExemptions(secondaryZygoteState, false); 29 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState); 30 } 31 32 if (secondaryZygoteState.matches(abi)) { 33 return secondaryZygoteState; 34 } 35 36 throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi); 37}
如果与 Zygote 进程的 socket 连接未开启,则尝试开启,可能会产生阻塞和重试。连接调用的是 ZygoteState.connect() 方法,ZygoteState 是 ZygoteProcess 的内部类。
1> ZygoteProcess.java 2 3public static class ZygoteState { 4 final LocalSocket socket; 5 final DataInputStream inputStream; 6 final BufferedWriter writer; 7 final List<String> abiList; 8 9 boolean mClosed; 10 11 private ZygoteState(LocalSocket socket, DataInputStream inputStream, 12 BufferedWriter writer, List<String> abiList) { 13 this.socket = socket; 14 this.inputStream = inputStream; 15 this.writer = writer; 16 this.abiList = abiList; 17 } 18 19 public static ZygoteState connect(LocalSocketAddress address) throws IOException { 20 DataInputStream zygoteInputStream = null; 21 BufferedWriter zygoteWriter = null; 22 final LocalSocket zygoteSocket = new LocalSocket(); 23 24 try { 25 zygoteSocket.connect(address); 26 27 zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream()); 28 29 zygoteWriter = new BufferedWriter(new OutputStreamWriter( 30 zygoteSocket.getOutputStream()), 256); 31 } catch (IOException ex) { 32 try { 33 zygoteSocket.close(); 34 } catch (IOException ignore) { 35 } 36 37 throw ex; 38 } 39 40 String abiListString = getAbiList(zygoteWriter, zygoteInputStream); 41 Log.i("Zygote", "Process: zygote socket " + address.getNamespace() + "/" 42 + address.getName() + " opened, supported ABIS: " + abiListString); 43 44 return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter, 45 Arrays.asList(abiListString.split(","))); 46 } 47 ... 48}
通过 socket 连接 Zygote 远程服务端。
再回头看之前的 zygoteSendArgsAndGetResult() 方法。
zygoteSendArgsAndGetResult()
1 > ZygoteProcess.java 2 3private static Process.ProcessStartResult zygoteSendArgsAndGetResult( 4 ZygoteState zygoteState, ArrayList<String> args) 5 throws ZygoteStartFailedEx { 6 try { 7 ... 8 final BufferedWriter writer = zygoteState.writer; 9 final DataInputStream inputStream = zygoteState.inputStream; 10 11 writer.write(Integer.toString(args.size())); 12 writer.newLine(); 13 14 // 向 zygote 进程发送参数 15 for (int i = 0; i < sz; i++) { 16 String arg = args.get(i); 17 writer.write(arg); 18 writer.newLine(); 19 } 20 21 writer.flush(); 22 23 // 是不是应该有一个超时时间? 24 Process.ProcessStartResult result = new Process.ProcessStartResult(); 25 26 // Always read the entire result from the input stream to avoid leaving 27 // bytes in the stream for future process starts to accidentally stumble 28 // upon. 29 // 读取 zygote 进程返回的子进程 pid 30 result.pid = inputStream.readInt(); 31 result.usingWrapper = inputStream.readBoolean(); 32 33 if (result.pid < 0) { // pid 小于 0 ,fork 失败 34 throw new ZygoteStartFailedEx("fork() failed"); 35 } 36 return result; 37 } catch (IOException ex) { 38 zygoteState.close(); 39 throw new ZygoteStartFailedEx(ex); 40 } 41}
通过 socket 发送请求参数,然后等待 Zygote 进程返回子进程 pid 。客户端的工作到这里就暂时完成了,我们再追踪到服务端,看看服务端是如何处理客户端请求的。
Zygote 处理客户端请求
Zygote 处理客户端请求的代码在 ZygoteServer.runSelectLoop() 方法中。
1> ZygoteServer.java 2 3Runnable runSelectLoop(String abiList) { 4 ... 5 6 while (true) { 7 ... 8 try { 9 // 有事件来时往下执行,没有时就阻塞 10 Os.poll(pollFds, -1); 11 } catch (ErrnoException ex) { 12 throw new RuntimeException("poll failed", ex); 13 } 14 for (int i = pollFds.length - 1; i >= 0; --i) { 15 if ((pollFds[i].revents & POLLIN) == 0) { 16 continue; 17 } 18 19 if (i == 0) { // 有新客户端连接 20 ZygoteConnection newPeer = acceptCommandPeer(abiList); 21 peers.add(newPeer); 22 fds.add(newPeer.getFileDesciptor()); 23 } else { // 处理客户端请求 24 try { 25 ZygoteConnection connection = peers.get(i); 26 // fork 子进程,并返回包含子进程 main() 函数的 Runnable 对象 27 final Runnable command = connection.processOneCommand(this); 28 29 if (mIsForkChild) { 30 // 位于子进程 31 if (command == null) { 32 throw new IllegalStateException("command == null"); 33 } 34 35 return command; 36 } else { 37 // 位于父进程 38 if (command != null) { 39 throw new IllegalStateException("command != null"); 40 } 41 42 if (connection.isClosedByPeer()) { 43 connection.closeSocket(); 44 peers.remove(i); 45 fds.remove(i); 46 } 47 } 48 } catch (Exception e) { 49 ... 50 } finally { 51 mIsForkChild = false; 52 } 53 } 54 } 55 } 56}
acceptCommandPeer() 方法用来响应新客户端的 socket 连接请求。processOneCommand() 方法用来处理客户端的一般请求。
processOneCommand()
1> ZygoteConnection.java 2 3Runnable processOneCommand(ZygoteServer zygoteServer) { 4 String args[]; 5 Arguments parsedArgs = null; 6 FileDescriptor[] descriptors; 7 8 try { 9 // 1\. 读取 socket 客户端发送过来的参数列表 10 args = readArgumentList(); 11 descriptors = mSocket.getAncillaryFileDescriptors(); 12 } catch (IOException ex) { 13 throw new IllegalStateException("IOException on command socket", ex); 14 } 15 16 ... 17 18 // 2\. fork 子进程 19 pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, 20 parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, 21 parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote, 22 parsedArgs.instructionSet, parsedArgs.appDataDir); 23 24 try { 25 if (pid == 0) { 26 // 处于进子进程 27 zygoteServer.setForkChild(); 28 // 关闭服务端 socket 29 zygoteServer.closeServerSocket(); 30 IoUtils.closeQuietly(serverPipeFd); 31 serverPipeFd = null; 32 // 3\. 处理子进程事务 33 return handleChildProc(parsedArgs, descriptors, childPipeFd, 34 parsedArgs.startChildZygote); 35 } else { 36 // 处于 Zygote 进程 37 IoUtils.closeQuietly(childPipeFd); 38 childPipeFd = null; 39 // 4\. 处理父进程事务 40 handleParentProc(pid, descriptors, serverPipeFd); 41 return null; 42 } 43 } finally { 44 IoUtils.closeQuietly(childPipeFd); 45 IoUtils.closeQuietly(serverPipeFd); 46 } 47}
processOneCommand() 方法大致可以分为五步,下面逐步分析。
readArgumentList()
1> ZygoteConnection.java 2 3private String[] readArgumentList() 4 throws IOException { 5 6 int argc; 7 8 try { 9 // 逐行读取参数 10 String s = mSocketReader.readLine(); 11 12 if (s == null) { 13 // EOF reached. 14 return null; 15 } 16 argc = Integer.parseInt(s); 17 } catch (NumberFormatException ex) { 18 throw new IOException("invalid wire format"); 19 } 20 21 // See bug 1092107: large argc can be used for a DOS attack 22 if (argc > MAX_ZYGOTE_ARGC) { 23 throw new IOException("max arg count exceeded"); 24 } 25 26 String[] result = new String[argc]; 27 for (int i = 0; i < argc; i++) { 28 result[i] = mSocketReader.readLine(); 29 if (result[i] == null) { 30 // We got an unexpected EOF. 31 throw new IOException("truncated request"); 32 } 33 } 34 35 return result; 36}
读取客户端发送过来的请求参数。
forkAndSpecialize()
1> Zygote.java 2 3public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, 4 int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, 5 int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) { 6 VM_HOOKS.preFork(); 7 // Resets nice priority for zygote process. 8 resetNicePriority(); 9 int pid = nativeForkAndSpecialize( 10 uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, 11 fdsToIgnore, startChildZygote, instructionSet, appDataDir); 12 // Enable tracing as soon as possible for the child process. 13 if (pid == 0) { 14 Trace.setTracingEnabled(true, runtimeFlags); 15 16 // Note that this event ends at the end of handleChildProc, 17 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); 18 } 19 VM_HOOKS.postForkCommon(); 20 return pid; 21}
nativeForkAndSpecialize() 是一个 native 方法,在底层 fork 了一个新进程,并返回其 pid。不要忘记了这里的 一次fork,两次返回 。pid > 0 说明还是父进程。pid = 0 说明进入了子进程。子进程中会调用 handleChildProc,而父进程中会调用 handleParentProc()。
handleChildProc()
1> ZygoteConnection.java 2 3private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, 4 FileDescriptor pipeFd, boolean isZygote) { 5 closeSocket(); // 关闭 socket 连接 6 ... 7 8 if (parsedArgs.niceName != null) { 9 // 设置进程名 10 Process.setArgV0(parsedArgs.niceName); 11 } 12 13 if (parsedArgs.invokeWith != null) { 14 WrapperInit.execApplication(parsedArgs.invokeWith, 15 parsedArgs.niceName, parsedArgs.targetSdkVersion, 16 VMRuntime.getCurrentInstructionSet(), 17 pipeFd, parsedArgs.remainingArgs); 18 19 // Should not get here. 20 throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned"); 21 } else { 22 if (!isZygote) { // 新建应用进程时 isZygote 参数为 false 23 return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, 24 null /* classLoader */); 25 } else { 26 return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion, 27 parsedArgs.remainingArgs, null /* classLoader */); 28 } 29 } 30}
当看到 ZygoteInit.zygoteInit() 时你应该感觉很熟悉了,接下来的流程就是:
ZygoteInit.zygoteInit()->RuntimeInit.applicationInit()->findStaticMain()
和 SystemServer 进程的创建流程一致。这里要找的 main 方法就是 ActivityThrad.main() 。ActivityThread虽然并不是一个线程,但你可以把它理解为应用的主线程。
handleParentProc()
1> ZygoteConnection.java 2 3private void handleParentProc(int pid, FileDescriptor[] descriptors, FileDescriptor pipeFd) { 4 if (pid > 0) { 5 setChildPgid(pid); 6 } 7 8 if (descriptors != null) { 9 for (FileDescriptor fd: descriptors) { 10 IoUtils.closeQuietly(fd); 11 } 12 } 13 14 boolean usingWrapper = false; 15 if (pipeFd != null && pid > 0) { 16 int innerPid = -1; 17 try { 18 // Do a busy loop here. We can't guarantee that a failure (and thus an exception 19 // bail) happens in a timely manner. 20 final int BYTES_REQUIRED = 4; // Bytes in an int. 21 22 StructPollfd fds[] = new StructPollfd[] { 23 new StructPollfd() 24 }; 25 26 byte data[] = new byte[BYTES_REQUIRED]; 27 28 int remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS; 29 int dataIndex = 0; 30 long startTime = System.nanoTime(); 31 32 while (dataIndex < data.length && remainingSleepTime > 0) { 33 fds[0].fd = pipeFd; 34 fds[0].events = (short) POLLIN; 35 fds[0].revents = 0; 36 fds[0].userData = null; 37 38 int res = android.system.Os.poll(fds, remainingSleepTime); 39 long endTime = System.nanoTime(); 40 int elapsedTimeMs = (int)((endTime - startTime) / 1000000l); 41 remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS - elapsedTimeMs; 42 43 if (res > 0) { 44 if ((fds[0].revents & POLLIN) != 0) { 45 // Only read one byte, so as not to block. 46 int readBytes = android.system.Os.read(pipeFd, data, dataIndex, 1); 47 if (readBytes < 0) { 48 throw new RuntimeException("Some error"); 49 } 50 dataIndex += readBytes; 51 } else { 52 // Error case. revents should contain one of the error bits. 53 break; 54 } 55 } else if (res == 0) { 56 Log.w(TAG, "Timed out waiting for child."); 57 } 58 } 59 60 if (dataIndex == data.length) { 61 DataInputStream is = new DataInputStream(new ByteArrayInputStream(data)); 62 innerPid = is.readInt(); 63 } 64 65 if (innerPid == -1) { 66 Log.w(TAG, "Error reading pid from wrapped process, child may have died"); 67 } 68 } catch (Exception ex) { 69 Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex); 70 } 71 72 // Ensure that the pid reported by the wrapped process is either the 73 // child process that we forked, or a descendant of it. 74 if (innerPid > 0) { 75 int parentPid = innerPid; 76 while (parentPid > 0 && parentPid != pid) { 77 parentPid = Process.getParentPid(parentPid); 78 } 79 if (parentPid > 0) { 80 Log.i(TAG, "Wrapped process has pid " + innerPid); 81 pid = innerPid; 82 usingWrapper = true; 83 } else { 84 Log.w(TAG, "Wrapped process reported a pid that is not a child of " 85 + "the process that we forked: childPid=" + pid 86 + " innerPid=" + innerPid); 87 } 88 } 89 } 90 91 try { 92 mSocketOutStream.writeInt(pid); 93 mSocketOutStream.writeBoolean(usingWrapper); 94 } catch (IOException ex) { 95 throw new IllegalStateException("Error writing to command socket", ex); 96 } 97 }
主要进行一些资源清理的工作。到这里,子进程就创建完成了。
总结

- 调用
Process.start()创建应用进程 ZygoteProcess负责和Zygote进程建立 socket 连接,并将创建进程需要的参数发送给 Zygote 的 socket 服务端Zygote服务端接收到参数之后调用ZygoteConnection.processOneCommand()处理参数,并 fork 进程- 最后通过
findStaticMain()找到ActivityThread类的 main() 方法并执行,子进程就启动了
