Android 世界中,谁喊醒了 Zygote ?

前端之家收集整理的这篇文章主要介绍了Android 世界中,谁喊醒了 Zygote ?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

本文基于 Android 9.0,代码仓库地址 : android_9.0.0_r45

文中源码链接

SystemServer.java

ActivityManagerService.java

Process.java

ZygoteProcess.java

ZygoteSystemServer 启动流程还不熟悉的建议阅读下面两篇文章

Java 世界的盘古和女娲 —— Zygote

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,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,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 targetSdkVersion,String abi,String appDataDir,// 一般新建应用进程时,此参数不为 null
                String[] zygoteArgs) {
        return zygoteProcess.start(processClass,niceName,gid,targetSdkVersion,abi,appDataDir,zygoteArgs);
    }

继续调用 zygoteProcess.start()

> ZygoteProess.java

public final Process.ProcessStartResult start(final String processClass,String[] zygoteArgs) {
    try {
        return startViaZygote(processClass,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 int uid,final int gid,final int[] gids,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() 方法ZygoteStateZygoteProcess 的内部类。

> 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,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[][] rlimits,String niceName,int[] fdsToClose,int[] fdsToIgnore,String appDataDir) {
    VM_HOOKS.preFork();
    // Resets nice priority for zygote process.
    resetNicePriority();
    int pid = nativeForkAndSpecialize(
              uid,startChildZygote,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.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,null /* classLoader */);
        }
    }
}

当看到 ZygoteInit.zygoteInit() 时你应该感觉很熟悉了,接下来的流程就是:

ZygoteInit.zygoteInit() -> RuntimeInit.applicationInit() -> findStaticMain()

SystemServer 进程的创建流程一致。这里要找的 main 方法就是 ActivityThrad.main()ActivityThread 虽然并不是一个线程,但你可以把它理解为应用的主线程。

handleParentProc()

> ZygoteConnection.java

private void handleParentProc(int pid,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,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);
        }
    }

主要进行一些资源清理的工作。到这里,子进程就创建完成了。

总结

分享图片

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

预告

到现在为止已经解析了 Zygote 进程 ,SystemServer 进程,以及应用进程的创建。下一篇内容是和应用最密切相关的系统服务 ActivityManagerService,来看看它在 SystemServer 中是如何被创建和启动的,敬请期待!

文章首发微信公众号: 秉心说 , 专注 Java 、 Android 原创知识分享,LeetCode 题解。

更多最新原创文章,扫码关注我吧!

分享图片

猜你在找的Android相关文章