Zygote进程基础介绍
Zygote中文翻译为“受精卵”,正如其名,它主要用于孵化子进程。在Android系统中有以下两种程序:
- java应用程序,主要基于ART虚拟机,所有的应用程序apk都属于这类
- native程序,也就是利用C或C++语言开发的程序,如bootanimation。
所有的Java应用程序进程及系统服务SystemServer进程都由Zygote进程通过Linux的fork()函数孵化出来的,这也就是为什么把它称为Zygote的原因,因为他就像一个受精卵,孵化出无数子进程,而native程序则由Init程序创建启动。Zygote进程最初的名字不是“zygote”而是“app_process”,这个名字是在Android.mk文件中定义的。
如图所示为Zygote孵化框架:
Zygote是一个C/S模型,Zygote进程作为服务端,其他进程作为客户端向它发出“孵化”请求,而Zygote接收到这个请求后就“孵化”出一个新的进程。如图所示,当点击Launcher里的应用程序图标去启动一个新的应用程序进程时,这个请求会到达框架层的核心服务ActivityManagerService中,当AMS收到这个请求后,它通过调用Process类发出一个“孵化”子进程的Socket请求,而Zygote监听到这个请求后就立刻fork一个新的进程出来。
Zygote进程的启动
Zygote进程对应的主文件为app_main.cpp,当他被Init进程启动起来之后,就会进入主文件app_main.cpp的main()函数。接下来它的main函数开始分析Zygote进程的启动:
main()函数最后调用runtime的start()函数,runtime是一个AppRuntime对象,看看AppRuntime类:
AppRuntime类继承AndroidRuntime类,因此前面调用的runtime的start()函数就会进入AndroidRuntime的start()函数,下面看看该函数:
AndroidRuntime的start()函数主要做了以下三件事情:
- 调用startVM()函数启动虚拟机
- 调用startReg()函数注册JNI方法
- 调用com.android.internal.os.ZygoteInit类的main()函数(若是子进程,则调用com.android.internal.os.RuntimeInit的main()函数,从而基本结束初始化。而Zygote进程的main函数则还有以下的会讲到的5项工作)
下面一一介绍三个函数的具体工作:
启动虚拟机
通过调用startVM()函数启动虚拟机:
注册JNI方法
在Android中,Java世界要调用native世界的函数就要用JNI机制,并且在Android系统中也大量使用JNI机制,Android系统通过如下的startReg()函数去注册:
startReg()函数通过调用register_jni_procs()函数去进一步注册,传递的值是gRegJNI数组,原生Android6.0版本该数组超过130个,具体如下:
上面所列的JNI都通过register_jni_procs()函数来注册:
通过循环对所有的JNI函数进行注册。。。
调用ZygoteInit类的main()
ZygoteInit是一个Java类,我们终于走到了Java世界,看看该main()方法:
ZygoteInit类的main()方法主要做了以下5项工作:
- 调用ZygoteServer类的registerServerSocket()方法创建一个Zygote的Socket接口,用来和AMS通信
- 调用preload()预加载类和资源
- 调用forkSystemServer()函数来启动SystemServer进程,r.run()启动其main()方法
- 调用ZygoteServer类的runSelectLoop()函数在前面创建的Socket接口上进入一个无限循环,等待核心服务AMS请求创建新的应用程序进程。
- 调用caller.run()方法,启动子进程直接进入子进程的main()方法(非system_server进程,该进程由r.run()启动main()方法)
下面一一讲解着五项工作的内容:
registerServerSocket()
通过调用ZygoteServer类的registerServerSocket()方法来创建一个Java层的LocalServerSocket对象,目的是等待创建新的应用程序进程请求:
preload()预加载类与资源
|
|
既然加载这些类和资源这么耗时间,为什么还要预加载:
应用程序都从Zygote孵化出来,应用程序都会继承Zygote的所有内容,如果在Zygote启动的时候加载这些类和资源,这些孵化的应用程序就继承Zygote的类和资源,这样启动引用程序的时候就不需要加载类和资源了,启动的速度就会快很多。开机的次数不多,但是启动应用程序的次数非常多。
启动SystemServer进程
后续我们将分析启动SystemServer进程,主要是比较启动SystemServer进程与启动普通应用程序进程的区别。
runSelectLoop()函数进入无限循环
|
|
在无限循环中,如果变量i==0,表示Zygote Socket服务还没有准备好;当i!=0时,表示正在等待客户端来连接“Zygote”这个Socket。当有孵化子进程的请求时,就会调用ZygoteConnection类的processOneCommand()函数来创建子进程。
caller.run()函数
我们将在启动应用程序进程的时候分析caller.run()函数。
SystemServer进程
启动syetem_server进程
从上面的学习可知,启动系统服务system_server进程从ZygoteInit.java的main()方法调用forkSystemServer()方法开始,先看看该方法:
首先设置了system_server进程的uid。gid和groups,然后设置进程的名字为”–nice-name=system_server”。接着调用forkSystemServer()函数来fork一个新的进程,他有两个返回值,一个在当前进程中返回,另一个在新创建的进程中返回,在当前进程中返回值是新创建的pid值,而新创建进程中的返回值是0。
如果pid==0,表示已经进入SystemServer子进程,于是先调用zygoteServer.closeServerSocket()关闭“Zygote”socket,由于Zygote启动过程中创建一个“Zygote”Socket。而系统服务进程system_server也继承了Socket,不用所以close它。接着调用了handleSystemServerProcess()方法:
主要调用了ZygoteInit.zygoteInit()方法:
zygoteInit()方法主要调用了ZygoteInit.nativeZygoteInit()和RuntimeInit.applicationInit()这两个方法:
- nativeZygoteInit()主要执行Binder驱动程序初始化的相关工作,它调用之后system_server进程就可以进行Binder进程通信(),是个native方法。
- 调用applicationInit()方法主要是为了进入SystemServer.java的main()方法
接下来看看RuntimeInit.applicationInit()方法:
|
|
可以看出applicationInit()方法调用findStaticMain()方法,而该方法通过反射获取system-server的main()方法后返回一个MethodAndArgsCaller,这是一个Runnable:
可见通过反射调用main()方法,但返回到哪呢?其实在上面的ZygoteInit类的main()方法中,在创建完system_server后直接调用,如下ZygoteInit类的main()方法代码所示,Runnable类型的r调用r.run()方法:
SystemServer fork新进程
Init进程、Zygote进程和SystemServer进程都非常重要,因为任何一个死机否会出现重启。从上面的讲解中可知,SystemServer系统服务的启动从ZygoteInit类的forkSystemServer()方法开始:
主要调用了两个方法,Zygote.forkSystemServer()和handleSystemServerProcess(),上面讲解了handleSystemServerProcess(),现在主要分析Zygote.forkSystemServer():
主要调用了nativeForkSystemServer(),这是一个native方法,对应的实现如下:
主要调用了ForkAndSpecializeCommon()函数:
主要调用了两个函数,fork()函数来创建一个新的子进程,接下来看看UnsetSigChldHandler():
SetSigChldHandler()设置了信号处理函数SigChldHandler,意思是子进程死亡之后,就会产生一个信号,Zygote进程受到该信号之后就会调用SigChldHandler()处理异常:
变量gSystemServerPid表示SystemServer进程的pid,若SystemServer进程停止工作,那么首先通过getpid()来获取Zygote进程的pid,然后调用kill函数杀死它,即SystemServer停止工作之后,Zygote进程自杀,已达到Zygote与SystemServer生死与共的目的。
在Init进程的main()函数中有一个死循环,如果它的子进程Zygote停止工作,就会去重启子进程,代码如下:
从这个过程可知,Init进程、Zygote进程、SystemServer进程紧密相连,任何一个都不能出问题。
SystemServer创建框架核心服务
当SystemServer启动之后,就会进入main()方法,又在它的main()方法中调用run()方法。Android系统的核心服务AMS、WMS、PMS等就是在run()方法里进行创建和初始化的,当它们创建之后,会通过ServiceManager的add_server()方法把它们加入到ServiceManager中统一管理。
run()方法主要调用了三个重要的方法,在这三个方法中创建和初始化了重要的系统服务,如AMS、WMS、PMS等等。
APP应用程序进程
前面分析了Zygote如何启动SystemServer子进程,接下来再分析Zygote如何启动其他子进程,也就是创建应用程序进程的过程,这个过程和创建SystemServer进程基本一样。当点击Launcher主界面的一个应用程序图标时,如果这个应用程序还未曾启动,就会启动它。而判断应用程序有没有启动和去启动应用程序都由核心服务AMS来做,它的startProcessLocked()方法会真正地启动应用程序子进程。
下面为AMS的startProcessLocked()方法:
AMS的startProcessLocked()方法调用Process类的start()方法为应用程序创建新的进程,这里的参数entryPoint为“android.app.ActivityThread”,它是传进去的第一个参数,也就是程序初始化进程时要加载的主文件Java类。当应用进程启动之后,会把这个类加载到进程,调用它的main()方法作为应用程序进程的入口。
Process类的start()直接调用了ZygoteProcess类的start()方法,该start()方法有直接调用了ZygoteProcess类的startViaZygote()方法,下面看看该方法实现:
首先给它设置值,包括uid、gid等。这些值是应用程序在安装时系统分配好的。接着调用openZygoteSocketIfNeeded()方法来链接“zygote”Socket,链接Socket成功之后,就会调用zygoteSendArgsAndGetResult()方法来进一步处理。
先来看看openZygoteSocketIfNeeded()方法:
方法中的mSocket的值是“zygote”,通过connect()方法去链接“zygote”Socket。
接着看看zygoteSendArgsAndGetResult()方法:
通过Socket写入流writer把前面传过来的那些参数写进去,Socket即ZygoteServer类的runSelectLoop()方法监听。写入这些数据之后,ZygoteServer类的runSelectLoop()方法就能被监听到。
看一下runSelectLoop()方法的关键实现代码:
进入ZygoteConnection类的processOneCommand()方法后:
之前启动SystemServer进程的代码有点相似。此处是通过Zygote.forkAndSpecialize()来fork新的应用进程,而启动systemserver进程是通过Zygote.forkSystemServer()来fork SystemServer进程。这里通过handleChildProc()方法处理,而之前是嗲偶用handleSystemServerProcess()来处理。通过fork新的应用程序进程之后,返回pid等于0就表示进入子进程,于是调用handleChildProc()方法进一步处理:
到此处,后面便和上面一样的了,唯一不同的是,SystemServer进程启动之后进入的是主类SystemServer.java的main()函数,而这里应用程序启动起来后进入的是主类是ActivityThread.java的main()函数。
至此,Zygote进程以及Zygote进程启动SystemServer进程和启动应用程序进程就分析完毕了,Zygote进程为了启动SystemServer和启动应用程序进程主要做了两件事,一是初始化Binder驱动用来进行进程间通信,二是通过反射进入main()方法。