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 fds = new ArrayList();// 记录上面监听的句柄所对应的处理类的实例对象 ArrayList peers = new ArrayList(); 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
ArrayList
这个函数首先创建两个链表,第一个链表 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(我这里表述有点问题,这里实际上是同一个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中启动新进程的流程就梳理完成了。
更多相关文章
- C语言函数以及函数的使用
- android杀进程方法
- Android:WebView与Javascript交互(相互调用参数、传值)
- 利用oom_adj提高Application所在进程的优先级
- Android Hook学习之ptrace函数的使用
- Android SDKVersion 参数列表
- android中线程进程模型
- Android之布局参数
- Android ContentProvider 多进程multiprocess 详解