1 概述
在 Android
系统中,DVM
(Dalvik
虚拟机)和 ART
,系统服务进程 system_server
以及应用程序进程都是由 Zygote
进程来创建的(而 Native
程序,也就是 C/C++
开发的程序则是由 init
进程创建启动的)。Zygote
进程也称孵化器,通过 fork(复制进程)
的形式来创建应用程序进程和 system_server
进程,由于 Zygote
进程在启动时会创建 DVM
或者 ART
,因此通过 fork
而创建的应用程序进程和 system_server
进程可以在内部获取一个 DVM
或者 ART
的实例副本。
Zygote
进程是在 init
进程启动时创建的,起初,Zygote
进程的名称并不是 Zygote
,而是 app_process
,这个名称是在 /frameworks/base/cmds/app_process/Android.mk
中定义的。Zygote
进程启动后,Linux
系统下的 pctrl
系统会调用 app_process
,将其名称换成了 Zygote
。
Zygote
是一个 C/S
模型。Zygote
进程作为服务端,通过 Socket
的方式和其他进程进行通信,这里的“其他进程”主要指的是系统服务进程 system_server
。
在 Linux
系统中,调用 fork
函数创建子进程的时候,不会复制父进程的内存,而是父子进程共享一个内存空间,只有当子进程或者父进程对内存数据进行修改时才会进行内存复制,从而,父进程和子进程才有各自的内存空间。在此之前,只会以只读的方式共享。
写时拷贝(copy-on-write
):等到修改数据的时候才真正的分配内存空间,是一种可以推迟甚至避免拷贝数据的技术。这是对程序性能的优化,这样做的目的是为了避免不必要的拷贝。
Zygote
作为孵化器,可以提前加载一些资源,这样 fork
出的子进程就可以直接使用这些资源,而不用重新加载。比如,system_server
进程就可以直接使用 Zygote
进程中的 JNI
函数、共享库、常用类以及主题资源。
Zygote
进程启动工作了以下几件事:
- 调用
AppRuntime/AndroidRuntime.start
方法,创建Java
虚拟机并为其注册JNI
方法; - 通过
JNI
调用ZygoteInit.main
方法,从Native
层进入Java
框架层; - 启动
system_server
进程; - 通过
ZygoteServer
创建服务器端的Socket
,并通过ZygoteServer.runSelectLoop
方法等待AMS
的请求来创建新的应用程序进程;
以下是 Zygote
启动的时序图:
2 Zygote
启动脚本
在 init进程启动过程 中讲到,init
进程会解析 init.rc
文件,然后创建和加载 service
字段指定的进程,Zygote
进程就是以这种方式被 init
进程加载的。在 init.rc
文件中采用 Import
类型语句来引入 Zygote
启动脚本,这些启动脚本都是由 Android
初始化语言(Android Init Language
)来编写的:
// /system/core/rootdir/init.rc
import /init.environ.rc
import /init.usb.rc
import /init.${
ro.hardware}.rc
import /vendor/etc/init/hw/init.${
ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${
ro.zygote}.rc // ${ro.zygote} 由厂商定义,与平台无关
可以看出,init.rc
不会直接引入一个固定的文件,而是根据 ro.zygote
的内容来引入不同的文件。
从 Android 5.0
开始,开始支持 64
位程序,Zygote
也就有了 32
位和 64
位的区别,所以用 ro.zygote
属性来控制使用不同的 Zygote
启动脚本,从而也就启动了不同版本的 Zygote
进程,从而也就启动了不同版本的 Zygote
进程,ro.zygote
属性的取值有以下 4
种:
init.zygote32.rc
:Zygote
进程对应的执行程序是app_process
(纯32 bit
模式);init.zygote32_64.rc
:启动两个Zygote
进程(zygote
和zygote_secondary
),对应的执行程序分别是app_process32
(主模式)、app_process64
;init.zygote64.rc
:Zygote
进程对应的执行程序是app_process64
(纯64 bit
模式);init.zygote64_32.rc
:启动两个Zygote
进程(zygote
和zygote_secondary
),对应的执行程序分别是app_process64
(主模式)、app_process32
;
这些 Zygote
启动脚本都放在 system/core/rootdir
目录中,如下所示:
以 64
位处理器为例,init.zygote64_32.rc
的代码如下所示:
脚本中有两个 Service
类型语句,说明会启动两个 Zygote
进程,一个名称为 zygote
,执行程序为 app_process64
,作为主模式;另一个名称为 zygote_secondary
,执行程序为 app_process32
,作为辅模式。其他的脚本文件与此类似。
以init.zygote64_32.rc
为例,其启动文件地址为 /system/bin/app_process64
(上图),app_process64
对应的代码在 /frameworks/base/cmds/app_process
的目录下。
首先,看一下 Android.mk
:
// /frameworks/base/cmds/app_process/Android.mk
LOCAL_PATH:= $(call my-dir)
....
app_process_src_files := \
app_main.cpp \
...
LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64
...
由上面的代码可知,不管是 app_prcess
、app_prcess32
还是 app_prcess64
,对应的源文件都是 app_main.cpp
。
3 Zygote
进程启动过程
init
启动 Zygote
进程时主要是通过调用 app_main.cpp
文件中的 main
函数,其中是通过调用 AppRuntime
的 start
方法来启动 Zygote
进程的:
// /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) {
// 1
// 如果当前运行在Zygote进程中,则将zygote设置为true
zygote = true; // 2
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
// 3
// 如果当前运行在system_server进程中,则将startSystemServer设置为true
startSystemServer = true; // 4
}
...
}
...
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
// 如果运行在zygote进程中
if (zygote) {
// 5
runtime.start("com.android.internal.os.ZygoteInit", args, zygote); // 6
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
}
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
Zygote
进程都是通过 fork
自身来创建子进程的,这样,Zygote
进程以及它的子进程都可以进入 app_main.cpp
的 main
函数,因此,main
函数中为了区分当前运行在哪个进程, 会在注释 1
处判断参数 arg
中是否包含了 --zygote
,如果包含了则说明 main
函数是运行在 Zygote
进程中的,并在注释 2
处将 zygote
设置为 true
。同理在注释 3
处判断参数 arg
中是否包含 --start-system-server
,如果包含了则说明 main
函数试运行在 system_server
进程中的,并在注释 4
处将 startSystemServer
设置为 true
。
注释 5
处,如果 zygote
为 true
,就说明当前运行在 zygote
进程中,就会调用注释 6
处的 AppRuntime
的 start
函数。AppRuntime
继承自 AndroidRuntime
,且没有重写 start
方法,因此,Zygote
的流程进入了 AndroidRutime
中,代码如下所示:
// /frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...
/* start the virtual machine 启动Java虚拟机 */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {
// 1
return;
}
onVmCreated(env);
/*
* Register android functions. 为Java虚拟机注册JNI方法
*/
if (startReg(env) < 0) {
// 2
ALOGE("Unable to register all android natives\n");
return;
}
...
// 从app_main的main函数得知className为com.android.internal.os.ZygoteInit
classNameStr = env->NewStringUTF(className); // 3
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
for (size_t i = 0; i < options.size(); ++i) {
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
assert(optionsStr != NULL);
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
* 将className的"."替换为"/"
*/
char* slashClassName = toSlashClassName(className != NULL ? className : ""); // 4
// 找到 zygoteInit
jclass startClass = env->FindClass(slashClassName); // 5
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"); // 6
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
// 通过JNI调用ZygoteInit的main方法
env->CallStaticVoidMethod(startClass, startMeth, strArray); // 7
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly\n");
}
在注释 1
出调用 startVm
函数来创建 Java
虚拟机,在注释 2
处调用 startReg
函数为 Java
虚拟机注册 JNI
方法。在注释 3
处的 className
的值是传进来的参数,它的值为 com.android.internal.os.ZygoteInit
。在注释 4
处通过 toSlashClassName
函数,将 className
的 .
替换成 /
,替换后的值为 com/android/internal/os/ZygoteInit
,并赋值给 slashClassName
,接着在注释 5
处根据 slashClassName
找到 ZygoteInit
,找到 ZygoteInit
后,在注释 6
处调用 ZygoteInit.main
方法。最终会在注释 7
处通过 JNI
调用 ZygoteInit.main
方法。这里为什么要用 JNI
呢?因为 ZygoteInit.main
方法是由 Java
语言编写的,当前的运行逻辑在 Native
中,这就需要通过 JNI
来调用 Java
。这样,Zygote
就从 Native
层进入了 Java
框架层。
通过 JNI
调用 ZygoteInit.main
方法后,Zygote
就进入了 Java
框架层,此前是没有任何代码进入 Java
框架层的,换句话说是 Zygote
开创了 Java
框架层,ZygoteInit.main
方法代码如下:
// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
// ZygoteServer是Zygote进程的Socket通讯服务端的管理类
ZygoteServer zygoteServer = null;
...
Runnable caller;
try {
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload(bootTimingsTraceLog); // 1
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}
...
zygoteServer = new ZygoteServer(isPrimaryZygote); // 2
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); // 3
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
r.run();
return;
}
}
Log.i(TAG, "Accepting command socket connections");
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
caller = zygoteServer.runSelectLoop(abiList); // 4
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
if (zygoteServer != null) {
zygoteServer.closeServerSocket();
}
}
...
}
注释 1
处预加载类和资源。注释 2
处创建一个 Server
端的 Socket
通道,用于响应ActivityManagerService
请求 Zygote
来创建新的应用程序进程的请求。注释 3
处启动 system_server
进程,这样系统的服务也会由 system_server
进程启动起来。注释 4
处调用 ZygoteServer.runSelectLoop
方法来等待 AMS
创建新进程的请求。
由以上可知,ZygoteInit.main
方法中主要做了 4
件事情:
- 预加载类和资源;
- 创建
Server
端的Socket
,用于响应ActivityManagerService
创建新的应用进程的请求; - 启动
system_server
进程,这样系统服务也就会由system_server
启动起来; - 等待
ActivityManagerService
创建新的应用程序进程的请求;