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中启动新进程的流程就梳理完成了。