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(我这里表述有点问题,这里实际上是同一个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中启动新进程的流程就梳理完成了。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值