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接收来自对端的数据,并执行相应操作
boolean done