Android四大组件之Activity(六)——Zygote:针对新启动的Activity创建一个新的进程

1、使用的是Android 7.1.2的源代码:

https://pan.baidu.com/s/1XcVD68cC_2wKtm8jJkdNQA
przv

2、感谢IT先森的系列博客:

Android应用进程创建流程大揭秘
Android四大组件之bindService源码实现详解
Android四大组件之Activity启动流程源码实现详解概要
Activity启动流程(一)发起端进程请求启动目标Activity
Activity启动流程(二)system_server进程处理启动Activity请求
Activity启动流程(三)-Activity Task调度算法复盘分析
Activity启动流程(四)-Pause前台显示Activity,Resume目标Activity
Activity启动流程(五)请求并创建目标Activity进程
Activity启动流程(六)注册目标Activity进程到system_server进程以及创建目标Activity进程Application
Activity启动流程(七)初始化目标Activity并执行相关生命周期流程

3、理解Android进程创建流程:http://gityuan.com/2016/03/26/app-process-create/

继续上一篇:Android四大组件之Activity(五)——AMS:针对新启动的Activity创建一个新的进程

一、Zygote

     Zygote含义为受精卵,是人的第一个细胞,其他细胞都是由其分裂出来的。对于Android来说,它是Android Java世界的第一个进程,其他所有Java进程都是由其fork出来的。

     Android会利用Zygote进程然后通过fork机制克隆出一个和原来Zygote进程几乎完全相同的进程(此进程包括继承Zygote进程相关的资源和财产),新进程不用再进行初始化操作,只需要修改一些关键参数就可以了,如上的逻辑极大地加快了新建进程的速度和资源的调度。总之一句话Zygote进程会孵化新的进程,新进程会继承自己的资源和财产,然后新进程根据自己的需要定制化地差异成长!

在这里插入图片描述

二、代码分析

1、ZygoteInit.main
//[ZygoteInit.java]
    public static void main(String argv[]) {
   
    	...
        try {
   
			...
			//创建zygote通信服务端
			 //开启LocalSocket通信通道,通道客户端fork进程的请求,而这里的客户端通常是system_server进程
            registerZygoteSocket(socketName);
			...
            //此处zygote进程开始进入runSelectLoop无限死循环,等待客户端的请求
            runSelectLoop(abiList);//

            closeServerSocket();//关闭通信socket通信通道
        } catch (MethodAndArgsCaller caller) {
   
            caller.run();//在异常捕获方法中子进程中调用MethodAndArgsCaller的run方法
        } catch (Throwable ex) {
   
            closeServerSocket();
            throw ex;
        }            
    }

注意:

  • 在Android O(8)及其之前版本 runSelectLoop() 方法会抛出异常MethodAndArgsCaller,从而进入caller.run()方法;但是Android P(9)及之后都不是通过抛异常的方式来运行caller.run了,而是直接在子进程中返回执行。
  • zygote 进程在 runSelectLoop 中已经无限循环了,后续又执行caller.run,是因为此时执行caller.run不是zygote进程了,而是创建的子进程。
2、ZygoteInit.registerZygoteSocket

     Zygote进程需要通过Socket通道接收客户端进程的请求,而 registerZygoteSocket用来创建LocalServerSocket实例对象,sServerSocket,作为Zygote进程的socket通信的服务端,用来接收system_server进程向Zygote进程发来的请求 ,其核心代码如下:

//[ZygoteInit.java]
	private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
    private static void registerZygoteSocket(String socketName) {
   
        if (sServerSocket == null) {
   
            int fileDesc;
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {
   
            //System.getenv 获取指定的环境变量的值
            	//从环境变量获取socket端的服务名
                String env = System.getenv(fullSocketName);
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
   
                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
            }

            try {
   
                FileDescriptor fd = new FileDescriptor();
                fd.setInt$(fileDesc);
                //LocalServerSocket,本地socket这个是谷歌改良版本的socket通信方式不同于传统的socket
                sServerSocket = new LocalServerSocket(fd);
            } catch (IOException ex) {
   
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }

上述代码作用:

  • 先从环境变量中获取socket端的服务名
  • 然后通过获取的服务名,创建LocalServerSocket,这里有一点需要注意的是这里的LocalServerSocket和通常的socket是有区别的,LocalSocket比Java本身的socket效率要高,没有经过协议栈,是Android自己实现的类似共享内存一样的东西,在传输大量数据的时候就需要用到。
3、ZygoteInit.runSelectLoop

    在上述的 socket 通信通道建立之后,Zygote 进程就进入 runSelectLoop 无限循环之中了。

    当客户端有新消息到来时,创建一个新的连接去执行客户端发来的请求。例如,system_server 进程的 AMS 发过来请求,Zygote 进程进行处理:

  • 新建一个peers列表,用于存储每个客户端的连接。将 fd 数据转存到 pollFds 中,遍历。
  • 当i=0时表示有客户端与服务端连接成功,此时执行acceptCommandPeer()方法拿到新的连接,并将其存入到peers集合中。
  • 当i>0时,表示客户端在向服务器传输数据,从peers中拿出与客户端的连接,执行ZygoteConnection.runOnce去创建进程
//[ZygoteInit.java]
    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
   
    	//注意此处的fds虽然是方法内的list,但是由于while无限循环可以认为fds是一个全局变量
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        
		//sServerSocket是socket通信中的服务端,即zygote进程。保存到fds[0]
        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);

        while (true) {
   
        	//每次循环,都重新创建需要监听的pollFds
            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 {
   
            	//处理轮询状态,当pollFds有事件到来则往下执行,否则阻塞在这里。即:阻塞等待fd的变化
                Os.poll(pollFds, -1);  //欧s
            } catch (ErrnoException ex) {
   
                throw new RuntimeException("poll failed", ex);
            }
			/*
				注意这里是倒序处理的,网上有的博客说是优先处理已建立连接的信息,后处理新建连接的请求
				我觉得这个表述不是很正确,我觉得采用倒序是为了先处理已经建立连接的请求,但是这个优先反而是后面建立连接的请求有数据到来是优先处理了
				然后接着最后处理sServerSocket,此时即有新的客户端要求建立连接
			*/      
			//当fd有变化时(客户端有连接时),会进入该for循环      
            for (int i = pollFds.length - 1; i >= 0; --i) {
   
                 //采用I/O多路复用机制,当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行;
                // 否则进入continue,跳出本次循环。
                
                // revents 指返回的事件
				// POLLIN 表示有数据可读
                if ((pollFds[i].revents & POLLIN) == 0) {
    
                    continue;
                }

                if (i == 0) {
   
                    // 即fds[0],代表的是sServerSocket
                    // 创建新连接并处理请求
               		// 则创建ZygoteConnection对象,并添加到fds。
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);  //-->1、进入这里
                    //加入到peers和fds,下一次也开始监听
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                }
                /*
                	我想这个方法的难点,小伙们应该是想怎么进入这个分支执行的吗
                	注意i == 0的时候会fds.add, 从而使fds长度发生改变再次循环时会进入i > 0的分支
                */ 
                else {
   
                	//i>0,则代表通过socket接收来自对端的数据,并执行相应操作
         
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值