我们的Android系统是基于Linux系统,所以当我们开机的时候,第一个启动的是Init进程,而后面所有的进程都是Init的子进程,zygote就是Init进程通过解析init.rc文件之后,启动的一个进程
Zygote的进程的主要作用只有两个:
关于孵化:
Zygote进程创建别的进程的时候,用的不是创建,而是孵化这个词,那怎么理解孵化这个意思呢?
关于fork:
fork在zygote进程中是一个很重要的概念,这是Linux内核自带的一个方法,这个方法的作用就是复制一个子进程。那么,怎么理解这个复制的意思,简单来说,就是从成员变量,到内存空间,再到当前所执行的代码指令,都会生成一个副本后放到子进程中。
当进程A调用fork后,进程A和复制的子进程B,都会得到fork方法的return值,并且继续往下执行。
返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1
进程A在开辟一块内存空间之后,持有这个内存空间的引用的话,在fork之后,子进程B也会持有这个内存空间。
由于也不怎么做C语言的开发工作,这部分就快速略过,简单来说就是init进程在读取init.rc文件之后,根据文件里面的指令:
我还是先搬出我的时序图,对这个启动过程先做一个总结。
public class ZygoteInit {
public static void main(String argv[]) {
// 省略了无关代码
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
// 如果返回的值不为空,就代表当前处于子进程,执行子进程找到的main方法
if (r != null) {
r.run();
return;
}
}
}
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
// 省略了无关代码
int pid;
/* fork生成SystemServer进程 */
pid = Zygote.forkSystemServer(
parsedArgs.mUid, parsedArgs.mGid,
parsedArgs.mGids,
parsedArgs.mRuntimeFlags,
null,
parsedArgs.mPermittedCapabilities,
parsedArgs.mEffectiveCapabilities);
// 0表示当前是子进程,也就是SystemServer进程
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
return handleSystemServerProcess(parsedArgs);
}
// 非0表示当前是父进程,也就是Zygote进程
return null;
}
}
public class Zygote {
static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
ZygoteHooks.preFork();
int pid = nativeForkSystemServer(
uid, gid, gids, runtimeFlags, rlimits,
permittedCapabilities, effectiveCapabilities);
// Set the Java Language thread priority to the default value for new apps.
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
ZygoteHooks.postForkCommon();
return pid;
}
/** 最后是调用了内核的fork方法来复制进程 */
private static native int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
}
这里就可以看出来,对于fork方法的基本处理,因为生成的进程和父进程唯一的区别就是return的值不一样,所以就根据这个return值来区分是父进程还是子进程,从而选择接下来要处理的逻辑。
从handleSystemServerProcess开始继续看。
public class ZygoteInit {
private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
// 省略了无关代码
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mDisabledCompatChanges,
parsedArgs.mRemainingArgs, cl);
}
public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader) {
// 省略了无关代码
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
classLoader);
}
}
public class RuntimeInit {
protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader) {
// 省略了无关代码
return findStaticMain(args.startClass, args.startArgs, classLoader);
}
/**
* 找到className中的静态main方法
* 其实就是用反射去找类中的这个方法而已
*/
protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class<?> cl;
try {
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
}
int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
}
/** 这个return的Runnable,最终会在ZygoteInit的main方法中被执行。*/
return new MethodAndArgsCaller(m, argv);
}
/** RuntimeInit中封装的Runnable,run方法就是去跑找到的method而已 */
static class MethodAndArgsCaller implements Runnable {
/** method to call */
private final Method mMethod;
/** argument array */
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException(ex);
}
}
}
}
这段代码不难看出,SystemServer进程做的事,就是通过反射去找到SystemServer.java这个类的静态main方法去执行,同时将ZygoteInit的main方法给return了。
启动APP主要是靠ZygoteServer类,这里还是先搬出时序图
class ZygoteInit {
public static void main(String argv[]) {
// 省略无关代码
ZygoteServer zygoteServer = null;
Runnable caller;
try {
zygoteServer = new ZygoteServer(isPrimaryZygote);
// SelcetLoop方法在fork之后的子进程中会return出一个caller
// SelectLoop方法会在Zygote进程中无限循环不停止。
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
if (zygoteServer != null) {
zygoteServer.closeServerSocket();
}
}
// 执行子进程中return出来的Runnable方法
if (caller != null) {
caller.run();
}
}
}
class ZygoteServer {
Runnable runSelectLoop(String abiList) {
// 省略无关代码
// 将SocketFD添加到列表头
ArrayList<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();
socketFDs.add(mZygoteSocket.getFileDescriptor());
while (true) {
StructPollfd[] pollFDs = null;
pollFDs = new StructPollfd[socketFDs.size()];
int pollIndex = 0;
for (FileDescriptor socketFD : socketFDs) {
pollFDs[pollIndex] = new StructPollfd();
pollFDs[pollIndex].fd = socketFD;
pollFDs[pollIndex].events = (short) POLLIN;
++pollIndex;
}
try {
// 等待文件描述符上的POLLIN事件,代码会阻塞在这里直到响应之后才继续往下执行
Os.poll(pollFDs, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
while (--pollIndex >= 0) {
// 如果没有实际发生的事件并不是可读事件就跳过该文件描述符
if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
continue;
}
if (pollIndex == 0) {
// 创建一个连接
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
socketFDs.add(newPeer.getFileDescriptor());
} else if (pollIndex < usapPoolEventFDIndex) {
try {
// 获取Zygote连接
ZygoteConnection connection = peers.get(pollIndex);
// 获取一个方法,实际上就是获取子进程的静态Main方法
final Runnable command = connection.processOneCommand(this);
// 成员变量,当fork完子进程的时候,子进程会将该变量设置为true
if (mIsForkChild) {
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
else {
//在主进程中关闭掉该连接
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(pollIndex);
socketFDs.remove(pollIndex);
}
}
} catch (Exception e) { }
}
}
}
}
}
这个代码看着其实和Looper.loop非常相似,都是先阻塞在一个地方,等到响应之后才开始继续往下处理。
在runSelectLoop这个方法里面,会出现FileDescriptor或者FD,这个东西是文件描述符,我把百科的话简单提炼介绍一下:
每次在对文件进行打开操作的时候,我们都可以获得该文件在这个文件表的下标。这个下标就叫做文件描述符,我们可以根据这个下标通过LINUX系统的API来操作或者监听那些曾经被打开过的文件。
还想具体了解的话,见百科:
OS.poll,让runSelectLoop阻塞的方法,这个方法的底层调用,就是调用linux系统的poll方法,具体功能为:
等待文件描述符上的某个事件,具体等待什么事件,根据设置决定,看一下StructPollfd 这个对象
public final class StructPollfd {
/** The file descriptor to poll. */
public FileDescriptor fd;
/**
* The events we're interested in. POLLIN corresponds to being in select(2)'s read fd set,
* POLLOUT to the write fd set.
*/
public short events;
/** The events that actually happened. */
public short revents;
}
其中,fd就代表了文件描述符,event代表了关注的事件,revent代表了实际发生的事件。
套入到我们的场景当中,我们等待的就是POLLIN这个事件,也就是可读事件。
在if (pollIndex == 0) 中看一下如何创建一个连接,主要是acceptCommandPeer这个方法,所以就从这里看起
class ZygoteServer {
private ZygoteConnection acceptCommandPeer(String abiList) {
try {
// mZygoteSocket的类型为LocalServerSocket
return createNewConnection(mZygoteSocket.accept(), abiList);
} catch (IOException ex) {
throw new RuntimeException(
"IOException during accept()", ex);
}
}
protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
throws IOException {
return new ZygoteConnection(socket, abiList);
}
}
public class LocalServerSocket implements Closeable {
private final LocalSocketImpl impl;
public LocalSocket accept() throws IOException
{
LocalSocketImpl acceptedImpl = new LocalSocketImpl();
impl.accept(acceptedImpl);
return LocalSocket.createLocalSocketForAccept(acceptedImpl);
}
}
class LocalSocketImpl {
protected void accept(LocalSocketImpl s) throws IOException {
if (fd == null) {
throw new IOException("socket not created");
}
try {
//重点就是这行Os.accept
s.fd = Os.accept(fd, null /* address */);
s.mFdCreatedInternally = true;
} catch (ErrnoException e) {
throw e.rethrowAsIOException();
}
}
}
最后核心的部分是,调用了Os.accept,这个方法的功能简单来说就是,当调用Os.accept后,就会根据参数的fd创建一个新的Socket连接,并返回该连接的FD。
综合一下前面的内容,我们就可以总结出这个死循环总体的功能了
@startuml
participant ZygoteInit as init
participant Zygote as zygote
participant RuntimeInit as rinit
init -> init : main
activate init
init -> init : forkSystemServer
activate init
init -> zygote : forkSystemServer
activate zygote
zygote -> zygote : nativeForkSystemServer\n调用内核的方法复制进程。
activate zygote
zygote --> zygote : return pid\n父进程返回子进程的进程id\n子进程返回0
deactivate zygote
zygote --> init : return pid
deactivate zygote
alt pid != 0
init --> init :return null
else pid == 0
init -> init : handleSystemServerProcess\n处理SystemServer进程
activate init
init -> init : zygoteInit
init -> rinit : applicationInit
activate rinit
rinit -> rinit : findstaticMain\n寻找静态main方法
rinit --> init : return mainMethod\n返回找到的Main方法\n就是SystemServer.Main
deactivate rinit
end
deactivate init
alt return null
init -> init : 代表这是zygote进程,处理后续逻辑。
else return mainMethod
init -> init : run MainMethod\n代表这是SystemServer进程
init -> init : return
end
deactivate init
deactivate init
@enduml
fork(函数)_百度百科
Android源码分析 - Zygote进程 - 掘金
zygote - 简书
Android29源码中贴的文档
https://man7.org/linux/man-pages/man2/accept.2.html
因篇幅问题不能全部显示,请点此查看更多更全内容