在Android系统中,Dalvik虚拟机或者是ART,应用程序进程,还有运行系统的关键服务(比如SystemServer等)进程都是由zygote来创建的,zygote通过fork来创建子进程。因为zygote进程在启动时,会创建Dalvik虚拟机或者是ART,所以通过fork出的子进程中也会带有Dalvik虚拟机或者ART。
通过简单易懂(二)之解析init.rc文件,我们能知道zygote进程是由init进程启动时创建而成的。
这里有个小知识点:起初zygote进程的名称并不是叫“zygote”,在源码中能看到它修改进程名为zygote的地方,代码(frameworks/base/cmds/app_process/app_main.cpp)如下:
zygote启动过程源码分析
先来一张时序图,根据时序图来分析源码:
根据简单易懂(二)之解析init.rc文件,我们知道init主要是调用了app_main.cpp中main函数里的runtime.start(“com.android.internal.os.ZygoteInit”, args, zygote)来启动zygote进程的,这里的runtime其实就是AndroidRuntime的实例。
app_main.cpp
我们先从app_main.cpp里的main函数开始分析:
//代码文件位置:frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[]){
*****省略部分代码*****
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
//如果当前运行在zygote进程中,则将zygote设置为true
zygote = true;
niceName = ZYGOTE_NICE_NAME;
}
*****省略部分代码*****
if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", args, zygote); }
*****省略部分代码*****
}
因为zygote进程都是通过fork自身来创建子进程的,所以zygote的子进程也都可以进入到app_main.cpp的main函数,所以main函数中为了区分当前是运行在哪个进程里,会通过参数arg来判断。上面代码中,通过判断是否包含“–zygote”,如果有,说明是在zygote进程中。(这个“–zygote”在init.rc文件里传过来的,具体可以看上篇文章)。
AndroidRuntime
接下来就是如果zygote等于true的话,就会调用到AndroidRuntime的start函数:
//代码文件位置:frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
*****省略部分代码*****
//在这里启动Java虚拟机
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
//为Java虚拟机注册JNI方法
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
*****省略部分代码*****
//这个className就是app_main传过来的"com.android.internal.os.ZygoteInit"
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
*****省略部分代码*****
//将"com.android.internal.os.ZygoteInit"里的 “.” 替换为 “/”
char* slashClassName = toSlashClassName(className);
//找到ZygoteInit类
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
//在这里找到ZygoteInit的main方法
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
//通过JNI调用ZygoteInit的main方法
env->CallStaticVoidMethod(startClass, startMeth, strArray);
*****省略部分代码*****
上述代码里加了注释了,整体下来的流程是:先调用startVm函数创建了Java虚拟机,接着调用startReg函数给Java虚拟机注册JNI方法,再找到ZygoteInit后,通过JNI调到到ZygoteInit的main方法。
这里需要通过JNI调用的原因是:因为ZygoteInit是一个java语言编写的类,然而当前是在zygote进程下还处于Native环境下,如果要调用到java层的代码,就需要通过JNI调用。
ZygoteInit
也就是说到这里时,zygote进程就从Native层进入到java层了。继续看java层ZygoteInit的main方法:
//代码文件位置:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
*****省略部分代码*****
//创建一个Server端的Socket,socketName的值为"zygote"
zygoteServer.registerServerSocket(socketName);
*****省略部分代码*****
//预加载类和资源
preload(bootTimingsTraceLog);
*****省略部分代码*****
if (startSystemServer) {
//注意,在这里启动了SystemServer进程
startSystemServer(abiList, socketName, zygoteServer);
}
Log.i(TAG, "Accepting command socket connections");
//一直循环,等待AMS的请求,去fork子进程
zygoteServer.runSelectLoop(abiList);
}
通过上述代码,我们能知道ZygoteInit的main方法主要做4件事:
- 创建一个Server端的Socket。
- 预加载类和资源。
- 启动SystemServer进程。
- 一直等待AMS请求,去创建新的应用程序进程。
小知识点:从这里我们知道了zygote进程是通过socket来跟其他进程通信的。
这里能看到SystemServer进程是这里被启动的,也就证明了前面讲的zygote进程负责启动systemserver进程,具体的启动过程,我们留下一篇文章讲。