Android系统启动(三)-Zygote篇
在Android系统中,Zygote是java进程的鼻祖。它在启动时会创建虚拟机,并通过fork(复制进程)的形式来创建应用程序进程和SystemServer进程。
一、Zygote启动流程
从上篇文章得知init启动Zygote时主要是调用app_main.cpp的main函数中的AppRuntime的start来启动zygote进程的,我们就从app_main.cpp的main函数开始分析。
1.1 AndroidRuntime.cpp
AppRuntime声明在app_main.cpp中,它继承AndroidRuntime,也就是我们调用start其实是调用AndroidRuntime的start函数。
frameworks/base/core/jni/AndroidRuntime.cpp start( )方法中主要工作:
- 调用startVm函数来创建JavaVm(DVM),并通过调用startReg函数用来为DVM注册JNI
startVm(&mJavaVM, &env, zygote)
startReg(env)
- 找到ZygoteInit的main函数,并通过JNI调用,自此Zygote便进入了Java框架层。
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V”);
env->CallStaticVoidMethod(startClass, startMeth, strArray);
1.2 ZygoteInit.java
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java main( )方法中主要工作:
-
注册Zygote用的Socket,当Zygote进程将SystemServer进程启动后,就会在这个服务端的Socket上来等待ActivityManagerService请求Zygote进程来创建新的应用程序进程。
registerZygoteSocket(socketName);
-
预加载的资源、类、虚拟机实例等。
preload();
-
启动SystemServer进程,该进程承载着framework的核心服务。
startSystemServer(abiList, socketName);
-
循环等待并处理AMS发送来的创建新应用进程请求。如果收到创建应用程序的请求,则调用ZygoteConnection的runOnce函数来创建一个新的应用程序进程。
runSelectLoop(abiList);
整体流程时序图如下:
from gityuan
Zygote进程启动总结:
- 解析init.zygote.rc中的参数,创建AppRuntime并调用AppRuntime.start()方法,实际调用AndroidRuntime.start(), 通过startVM()方法创建虚拟机,再调用startReg()注册JNI函数;
- 通过JNI方式调用ZygoteInit.main(),第一次进入Java世界;
- registerZygoteSocket()建立socket通道,zygote作为通信的服务端,用于响应客户端请求;
- preload()预加载通用类、drawable和color资源、openGL以及共享库以及WebView,用于提高app启动效率;
- zygote完毕大部分工作,接下来再通过startSystemServer(),fork得力帮手system_server进程,也是上层framework的运行载体。
- zygote功成身退,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。
- 同时会因为surfaceflinger、servicemanager、system_server进程被杀而被动触发Zygote重启。
- 对于Android 5.0以上系统,有两个zygote进程,分别是zygote、zygote64两个进程,从名字可以看出分别对应32位和64位,但是确实是都创建了。
mido:/ # ps | grep zygote root 714 1 2176388 47548 poll_sched 7faf1bd660 S zygote64 root 715 1 1613320 35496 poll_sched 00f292e3f4 S zygote
二、copy-on-write fork了解一下
linux为了提高 fork 的效率,采用了 copy-on-write 技术,从父进程fork一个子进程,刚fork之后,这两个虚拟地址实际上指向的是相同的物理地址(内存页),且把父子共享的页面标记为“只读”,但如果其中任何一个进程要对共享的页面“写操作”,这时内核会复制一个物理页面给这个进程使用,同时修改页表,把原来的只读页面标记为“可写”,留给另外一个进程使用。此时两个虚拟地址指向不同的物理地址(新的物理地址的内容从原物理地址中复制得到)。
以Zygote进程fork应用程序进程为例:
from gityuanZygote进程地址空间中包含有预加载资源、预加载类、虚拟机实例等。当Zygote fork一个应用程序进程时,父子进程先是共享相同物理地址资源,但是仅仅只能读不能写,如果此时应用进程开始写操作,那么会从Zygote原物理地址中复制内容到一块新的物理地址上,供应用程序进程使用。这样子进程可以高效而完整地继承父进程内存地址中的数据。