前言
俗话说的好,好记忆不如烂笔头;从业Android开发已多年,东西是越学越多,越学越忘,此系列文章是对过去的所学总结。
Zygote的理解
1).Zygote的作用
1.启动SystemServer
2.孵化应用进程
关于第二点孵化应用进程可能是大家比较熟悉的点,其实SystemServer也是通过Zygote启动的,因为SystemServer需要用到Zygote里面准备的一些系统资源:比如常用的一些类,注册的JNI函数,主题资源,共享库等等,具体看之后的源码介绍
2).Zygote的启动流程
进程启动.pngAndroid里面进程常用套路:进程启动->准备工作->Loop循环
Loop循环
就是不停的接收消息处理消息,这个消息是从哪来的呢?他可能是通过这个Socket发过来的,也可能是Message,也可能呢,是Binder驱动发过来的消息
Zygote进程如何启动
Zygote进程它是如何被启动的呢?这个我们得感谢init进程,它是Linux启动之后用户空间的第一个进程,Init进程启动之后首先会去加载一个启用配置文件(init.rc)。里面定义了哪些系统服务需要这时候启动的。Zygote就是要启动的服务之一(我们很熟悉的ServiceManager进程也在其中)。那这个进程是怎么启动的呢?就是通过fork加execve系统调用。
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
writepid /dev/cpuset/foreground/tasks
init.rc语法就不扩展了,其中有service名称(zygote),有fork加execve系统调用所需的可执行程序路径(/system/bin/app_process64)以及后面所需的参数
Zygote进程启动之后做了什么
1.Native世界
Zygote通过fork+ execve系统调用启动进程,它执行的是一个二进制的可执行程序,用C++写的里面有main函数作为入口。所以Zygote天生就是native的。做了如下三件事
Zygote的native世界.png简单的逻辑代码可参考如下:
int main(int argc, char *argv[]) {
JavaVM *jvm;
JNIEnv *env;
JNI_CreateJavaVM(&jvm, (void **) &env, &vm_args);
jclass clazz = env->FindClass("ZygoteInit");
jmethodID method = env->GetStaticMethodID(clazz, "Main", "([Ljava/lang/String;)V");
env->CallStaticVoidMethod(clazz, method, args);
jvm->DestroyJavaVM();
}
1.里边首先通过 JNI_CreateJavaVM去创建一个虚拟机。然后 再去找到一个叫ZygoteInit的Java类, 再去这个类里面找一个叫Main的静态函数,再通过这个CallStaticVoidMethod去调用这个函数,最后呢,再去destroy这个java虚拟机 。
2.JNI_CreateJavaVM去创建虚拟机。我们回想一下我们自己的应用,里边好像直接就可以JNI调用了啊。没有这么一句得先创建Java虚拟机的,那是为什么呢?因为这个Java虚拟机其实在Zygote进程里面就已经创建好了。咱们应用进程的是Zygote孵化出来的,就继承了他的这个虚拟机,我们就不用再创建一遍了,我们唯一要做的就是这个在进程启动的时候重置一下这个虚拟机的状态 ,再重启一下这个虚拟机,里面的一些守护线程就可以了
2.Java世界
终于到了java世界了,在java世界中做了哪些事情呢?主要有三件事
- 预加载资源:为了将来继承给子进程,包括主题资源,常用类等
// 代码来自Android23中:ZygoteInit.java
static void preload() {
Log.d(TAG, "begin preload");
preloadClasses();
preloadResources();
preloadOpenGL();
preloadSharedLibraries();
preloadTextResources();
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes.
WebViewFactory.prepareWebViewInZygote();
Log.d(TAG, "end preload");
- 启动SystemServer:SystemServer单独跑在一个进程
// 代码来自Android23中:ZygoteInit.java
private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException {
......
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
......
}
- 进入Loop循环:等待的是socket消息
// 代码来自Android23中:ZygoteInit.java
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
...
while (true) {
for (int i = pollFds.length - 1; i >= 0; --i) {
boolean done = peers.get(i).runOnce();
}
}
}
到这进入Loop循环后,等待Socket消息,拿到消息后执行的是runOnce()
runOnce()
// 代码来自Android23中:ZygoteInit.java
boolean runOnce() {
String[] args = readArgumentList();
int pid = Zygote.forkAndSpecialize();
if (pid == 0) {
// in child
handleChildProc(args, ...);
return true;
}
}
runOnce先会创建一个进程,然后在子进程中最终会调用handleChildProc,这个方法其实就是执行了一个java类的main函数,类名通过AMS跨进程传过来,其实就是
这就通过Zygote孵化了一个进程,进程的入口函数就是我们熟悉的ActivityThread的main方法。
总结
Zygote启动流程如下:
- init进程fork出zygote进程
- 启动虚拟机,注册jni函数
- 预加载系统资源
- 启动SystemServer
- 进入Socket Loop循环
思考点
1.Zygote的跨进程通信采用了Linux的Socket,而不是Binder,为什么不采用Binder呢?(后面文章会解释,不过理解了本篇文章的同学应该也能猜到的吧)
网友评论