android 开机启动流程分析(13)Zygote的分裂

    xiaoxiao2022-07-13  134

    该系列文章总纲链接:专题分纲目录 android 开机启动流程分析


    本章关键点总结 & 说明:

    这里因为整体的导图太大,因此截取一部分 ,方便大家看的清楚:

    zygote分裂 这一部分实际上使用的就是前面zygote和SystemServer启动的步骤,在上图中用蓝色部分进行简单表示

    同时,下面的图是开机启动流程分析 持续迭代的效果,可放大观看。

    说明:思维导图是基于之前文章不断迭代的,本章内容我们关注➕"启动SystemServer ->SS"部分即可

    Zygote的分裂解读Zygote分裂出system_server后,就通过runSelectLoopMode等待并处理来自AMS的消息 这里以一个Activity的启动为例,具体分析Zygote是如何分裂和繁殖的。

    1 AMS发送请求

    AMS是由SS创建的。通过startActivit来启动一个新的Activity,最后调用到AMS中的startProcessLocked函数,代码如下所示:

    private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) { long startTime = SystemClock.elapsedRealtime(); if (app.pid > 0 && app.pid != MY_PID) { checkTime(startTime, "startProcess: removing from pids map"); synchronized (mPidsSelfLocked) { mPidsSelfLocked.remove(app.pid); mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); } checkTime(startTime, "startProcess: done removing from pids map"); app.setPid(0); } ... /** 当AMS需要启动一个新进程时,会通过socket将ActivityThread类名等重要信息的参数传递给zygote Process.start {下面的entryPoint的值是"android.app.ActivityThread"} ->startViaZygote -->argsForZygote.add("--runtime-init");//参数初始化,这个参数很重要 -->{add("--setuid=" + uid);add("--setgid=" + gid);一些其他参数处理} -->return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote) --->openZygoteSocketIfNeeded ---->ZygoteState.connect(ZYGOTE_SOCKET);{创建并连接到zygote} ---->ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);{创建并连接到secondary_zygote} --->zygoteSendArgsAndGetResult ---->将args通过socket写入到zygote/secondary_zygote中 ---->从zygote/secondary_zygote中读取数据{int{数据大小+数据}+boolean} */ Process.ProcessStartResult startResult = Process.start(entryPoint, app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet, app.info.dataDir, entryPointArgs); ...//异常处理 }

    最后的调用zygoteSendArgsAndGetResult,使得AMS向Zygote发送请求。 注意:由于AMS驻留于SystemServer进程中,所以正是SS向Zygote发送了消息。

    2 Zygote响应请求

    回到ZygoteInit中,处理代码在 runSelectLoop()中,代码如下:

    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller { ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>(); ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); FileDescriptor[] fdArray = new FileDescriptor[4]; //sServerSocket是我们先前在registerZygoteSocket建立的Socket fds.add(sServerSocket.getFileDescriptor()); peers.add(null); int loopCount = GC_LOOP_COUNT; while (true) { int index; ... fdArray = fds.toArray(fdArray); //selectReadable内部调用select,使用多路复用I/O模型。当有客户端连接或有数据时,则selectReadable就会返回。 index = selectReadable(fdArray);//返回-1:错误,返回0:fd不在监听的集合fd_set内,返回>0:fd在fd_set中 if (index == 0) { //如有监听到一个客户端连接上,其客户端在Zygote的代表是ZygoteConnection //acceptCommandPeer->return ZygoteConnection(sServerSocket.accept(), abiList); ZygoteConnection newPeer = acceptCommandPeer(abiList); peers.add(newPeer); //添加peer对象 fds.add(newPeer.getFileDescriptor());//将newPeer的fd添加fds的描述符集合中 } else { boolean done; //客户端发送了请求,peers.get返回的是ZygoteConnection //后续处理将交给ZygoteConnection的runOnce函数完成。 done = peers.get(index).runOnce(); //后面根据AMS发来的数据来创建对象时会调用该方法 if (done) {//处理完请求从fd_set中移除fd peers.remove(index); fds.remove(index); } } } }

    当有请求数据发来时,Zygote都会调用ZygoteConnection的runOnce函数。runOnce的实现如下所示:

    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { ... /** readArgumentList ->mSocketReader.readLine();读取参数个数字符串转换为argc ->循环读取参数,总大小为argc,读完放到mSocketReader中 */ args = readArgumentList();//读取AMS即SS发送过来的参数 descriptors = mSocket.getAncillaryFileDescriptors();//获取可操作客户端文件描述符 ...//异常处理 ... checkTime(startTime, "zygoteConnection.runOnce: preForkAndSpecialize"); //Zygote根据AMS传递的参数创建一个子进程。 pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,parsedArgs.appDataDir); checkTime(startTime, "zygoteConnection.runOnce: postForkAndSpecialize"); ... try { if (pid == 0) { //子进程处理,这个子进程是我们要创建的ActivityThread进程 IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; /** handleChildProc ->closeSocket(); ->ZygoteInit.closeServerSocket(); ->RuntimeInit.zygoteInit -->nativeZygoteInit();//最终会调用AppRuntime的onZygoteInit,在那个函数中建立了和Binder的关系 -->applicationInit(targetSdkVersion, argv, classLoader); --->invokeStaticMain方法{抛出MethodAndArgsCaller异常,携带类名为ActivityThread} ---->mMethod.invoke(null, new Object[] { mArgs });//启动对应的ActivityThread进程 */ handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); return true; } else { //zygote进程接下来的处理 IoUtils.closeQuietly(childPipeFd); childPipeFd = null; /** handleParentProc,父进程的收尾工作 ->获取当前子进程的pid,通过pid和pipeFd来确认usingWrapper ->mSocketOutStream.writeInt(pid); ->mSocketOutStream.writeBoolean(usingWrapper); */ return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); } } finally { IoUtils.closeQuietly(childPipeFd); IoUtils.closeQuietly(serverPipeFd); } }

    说明:所有app的父进程都是zygote

    3 Zygote分裂总结

     Zygote的分裂由SS控制,SS创建AMS,之后AMS请求创建新的应用进程。 AMS通过socket通讯模型与zygote进行通讯,发送对应应用程序的相关信息。 Zygote接收到AMS发来的相关应用程序信息,创建对应的APP进程。
    最新回复(0)