注册

认识Zygote

Zygote的父进程是init进程,他孵化了SystemServer进程,以及我们的应用进程。


一、Zygote作用


功能主要是


:启动安卓虚拟机DVM


:启动SystemServer(Android系统进程)


:孵化应用进程


:加载 常用类 JNI函数 主题资源 共享库 等 


Zygote进程和系统其他进程的关系如图所示:



二、Zygote进程启动和应用进程启动


如图所示:



1.Zygote进程启动流程


Zygote是由init进程启动的,init进程是Linux系统启动后用户空间的第一个进程, 首先会去加载init.rc配置文件,然后启动其中定义的系统服务(Zygote,ServiceManager等), Init进程创建Zygote时,会调用app_main.cpp的main() 方法, 启动Zygote后,启动安卓虚拟机,接着在native层中通过jni调用java层的ZygoteInit的main()。


<!--app_main.cpp
int main(int argc, char* const argv[])
{
// 创建Android运行时对象
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// 代码省略...

// 调用AppRuntime.start方法,
// 而AppRuntime是AndroidRuntime的子类,并且没有重写start方法
// 因此调用的是AndroidRuntime的start方法
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
}
-->

这里一共就做了两件事,第一件创建AppRuntime,第二件调用start方法,详细看一下start方法:


<!--
/*
* AndroidRuntime.cpp
* Start the Android runtime.
*/
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
/* start the virtual machine */
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
return;
}

/*
* Register android functions.
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
jmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
-->

startVM -- 启动Java虚拟机 


startReg -- 注册JNI 通过JNI调用Java方法,执行com.android.internal.os.ZygoteInit 的 main 方法。


ZygoteInit .main主要干了4个事情,如下:


<!--
/*frameworks/base/core/java/com/android/internal/os/ZygoteInit.java*/
public static void main(String[] argv) {
ZygoteServer zygoteServer = null;
...
try {
...
// 1.preload提前加载框架通用类和系统资源到进程,加速进程启动
preload(bootTimingsTraceLog);
...
// 2.创建zygote进程的socket server服务端对象
zygoteServer = new ZygoteServer(isPrimaryZygote);
...
// 3.启动SystemServer(Android系统进程)
forkSystemServer
...
// 4.进入死循环,等待AMS发请求过来
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
...
} finally {
...
}
...
caller.run();//执行MethodAndArgsCaller包装后的runnable
}
-->

1.创建了ZygoteServer:这是一个Socket相关的服务,目的是进行跨进程通信。 


2.预加载preload:预加载相关的资源。 


3.创建SystemServer进程: 通过forkSystemServer分裂出了两个进程,一个Zygote进程,一个SystemServer进程。而且由于是分裂的, 所以新分裂出来的进程也拥有虚拟机,也能调用JNI,也拥有预加载的资源,也会执行后续的代码。 


4.执行runSelectLoop():内部是一个while(true)循环,等待AMS创建新的进程的請求消息。(想想Looper.loop()) 


2.Zygote启动应用进程流程


zygote进程通过Socket监听接收AMS的请求,fork创建子应用进程,然后pid为0时进入子进程空间,然后在ZygoteInit#zygoteInit中完成进程的初始化动作。


先看一下ZygoteServer.runSelectLoop


<!--
/*frameworks/base/core/java/com/android/internal/os/ZygoteServer.java*/
Runnable runSelectLoop(String abiList) {
// 进入死循环监听
while (true) {
while (--pollIndex >= 0) {
if (pollIndex == 0) {
...
} else if (pollIndex < usapPoolEventFDIndex) {
// Session socket accepted from the Zygote server socket
// 得到一个请求连接封装对象ZygoteConnection
ZygoteConnection connection = peers.get(pollIndex);
// processCommand函数中处理AMS客户端请求
final Runnable command = connection.processCommand(this, multipleForksOK);
...
}
}
}
}
-->

再通過ZygoteConnection中处理AMS创建新应用进程的请求。


 <!--
//ZygoteConnection.java
Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
...
// 1.fork创建应用子进程
pid = Zygote.forkAndSpecialize(...);
try {
if (pid == 0) {
...
// 2.pid为0,当前处于新创建的子应用进程中,处理请求参数
return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
} else {
...
handleParentProc(pid, serverPipeFd);
}
} finally {
...
}
}

private Runnable handleChildProc(ZygoteArguments parsedArgs,
FileDescriptor pipeFd, boolean isZygote) {
...
// 关闭从父进程zygote继承过来的ZygoteServer服务端地址
closeSocket();
...
if (parsedArgs.mInvokeWith != null) {
...
} else {
if (!isZygote) {
// 继续进入ZygoteInit#zygoteInit继续完成子应用进程的相关初始化工作
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mDisabledCompatChanges,
parsedArgs.mRemainingArgs, null /* classLoader */);
} else {
...
}
}
}
-->

通过调用 Zygote.forkAndSpecialize()函数来创建子进程,会有一个返回值pid,分别在子进程和父进程各返回一次, 子进程返回 0 ,父进程返回1,通过判断pid为0还是1来判断当前是是父进程还是子进程;默认子进程继承父进程是继承了父进程的一切资源 分叉后的进程会将socket停掉并重新初始化一些数据,但preload的资源和类保和VM留了下来,应用进程继承了Zygote进程所创建的虚拟机, 应用进程的在使用的时候就不需要再去创建,自此新的进程和zygote进程分道扬镳。  


注意:其中包括应用进程的主线程也是在这里从zygote进程继承而来的,应用进程的主线程并不是自己主动创建的新线程。


Zygote启动应用进程的时候不管父进程中有多少个线程,子进程在创建的时候都只有一个线程,对于子进程来说,多出现的线程在子进程中都不复存在, 因为如果其他线程也被复制到子进程,这时在子进程中就会存在一些问题,有时程序在执行的过程中可能会形成死锁,状态不一致等,所以比较安全的做法是在创建子进程的时候,只保留父进程的 主线程,其他都在暂停(此时线程资源是释放的所以不会继承到子进程),子进程启动完后再重启这些线程。


ZygoteInit.zygoteInit 方法完成应用进程初始化:


<!--
/*frameworks/base/core/java/com/android/internal/os/ZygoteInit.java*/
public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader) {
...
// 原生添加名为“ZygoteInit ”的systrace tag以标识进程初始化流程
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();
// 1.RuntimeInit#commonInit中设置应用进程默认的java异常处理机制
RuntimeInit.commonInit();
// 2.ZygoteInit#nativeZygoteInit函数中JNI调用启动进程的binder线程池
ZygoteInit.nativeZygoteInit();
// 3.RuntimeInit#applicationInit中反射创建ActivityThread对象并调用其“main”入口方法
return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
classLoader);
}
-->

1.设置应用进程默认的java异常处理机制(可以实现监听、拦截应用进程所有的Java crash的逻辑);


2.JNI调用启动进程的binder线程池(注意应用进程的binder线程池资源是自己创建的并非从zygote父进程继承的);


3.通过反射创建ActivityThread对象并调用其“main”入口方法。


最后再看看RuntimeInit.applicationInit做了啥:


<!--
/*frameworks/base/core/java/com/android/internal/os/RuntimeInit.java*/
protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader) {
...
// 结束“ZygoteInit ”的systrace tag
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// Remaining arguments are passed to the start class's static main
return findStaticMain(args.startClass, args.startArgs, classLoader);
}

protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class<?> cl;
try {
// 1.反射加载创建ActivityThread类对象
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
...
}
Method m;
try {
// 2.反射调用其main方法
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
...
} catch (SecurityException ex) {
...
}
...
// 3.触发执行以上逻辑
return new MethodAndArgsCaller(m, argv);
}
-->

主要就是调用ActivityThread.main方法,从此进入ActivityThread中。


三、参考资料


【Zygote进程的启动 --学习笔记】 blog.csdn.net/qq\_4223721…


【说说你对zygote的理解?】http://www.cnblogs.com/rxh1050/p/1…


【Zygote Fork机制与资源预加载】http://www.jianshu.com/p/be384613c…


作者:zzy的学习笔记
链接:https://juejin.cn/post/7220995317633302584
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册