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

198 篇文章 98 订阅

该系列文章总纲链接:专题总纲目录 Android Framework 总纲


本章关键点总结 & 说明:

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

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分裂总结

  1.  Zygote的分裂由SS控制,SS创建AMS,之后AMS请求创建新的应用进程。
  2.  AMS通过socket通讯模型与zygote进行通讯,发送对应应用程序的相关信息。
  3.  Zygote接收到AMS发来的相关应用程序信息,创建对应的APP进程。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图王大胜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值