Android 世界中,谁喊醒了 Zygote ?
本文基于 android 9.0 , 代码仓库地址 :
文中源码链接:
对 zygote
和 systemserver
启动流程还不熟悉的建议阅读下面两篇文章:
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<string> argsforzygote = new arraylist<string>(); // --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<string> abilist; boolean mclosed; private zygotestate(localsocket socket, datainputstream inputstream, bufferedwriter writer, list<string> 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<string> 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); } }
主要进行一些资源清理的工作。到这里,子进程就创建完成了。
总结
- 调用
process.start()
创建应用进程 -
zygoteprocess
负责和zygote
进程建立 socket 连接,并将创建进程需要的参数发送给 zygote 的 socket 服务端 -
zygote
服务端接收到参数之后调用zygoteconnection.processonecommand()
处理参数,并 fork 进程 - 最后通过
findstaticmain()
找到activitythread
类的 main() 方法并执行,子进程就启动了
预告
到现在为止已经解析了 zygote
进程 ,systemserver
进程,以及应用进程的创建。下一篇的内容是和应用最密切相关的系统服务 activitymanagerservice , 来看看它在 systemserver
中是如何被创建和启动的,敬请期待!
文章首发微信公众号:
秉心说
, 专注 java 、 android 原创知识分享,leetcode 题解。更多最新原创文章,扫码关注我吧!