1. 概述
在 Android 系统中,所有的应用程序以及系统服务进程 SystemService 都是由 zygote 进程孕育 (fork)出来的。zygote 进程的作用可以概括为以下三点:
- 创建 java 虚拟机,加载系统资源
- 应用程序启动过程中负责 fork 出子进程
在 Android 应用程序启动时,ActivityManagerService 会通过 socket 与 zygote 进程进行通信,请求它 fork 一个子进程出来作为这个即将要启动的应用程序的进程。 - 系统重要服务进程 SystemService 的孕育者
Android 系统中非常重要的系统服务进程 SystemServer 也是 zygote 在启动过程中 fork 出来的。
2. zygote 分析
2.1 启动过程分析
我们知道 Android 系统是基于 Linux 内核的,而在 Linux 系统中,所有的进程都是 init 进程的子进程,zygote 进程也不例外,它是由 init 进程创建的。
File:system/core/rootdir/init.rc
import /init.${ro.zygote}.rc
File:system/core/rootdir/init.zygote32.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
- 关键字 service 为:创建一个名为 zygote 的进程,这个 zygote 进程要执行的程序是 /system/bin/app_process,后面是传给 app_process 的参数。
- socket 关键字表示这个 zygote 进程需要一个名称为 zygote 的 socket 资源,这样系统在我们就可以在 /dev/socket 目录下看到一个名为 zygote 的文件,这里的 socket 主要用于本地进程间通信。ActivityManagerService 就是通这个 socket 来和 zygote 进程通信请求 fork 一个应用程序进程。
- 后面的 onrestart 表示这个 zygote 进程重启时需要执行的命令。
而进程 app_process 的源码位置在:platform/frameworks/base/cmds/app_process/app_main.cpp
这个函数由两种启动模式:
- 一种是 zygote 模式,也就是初始化 zygote 进程,传递的参数有 --start-system-server、 --socket-name=zygote,前者表示启动SystemServer,后者指定socket的名称
- 一种是 application 模式,也就是启动普通应用程序,传递的参数有 class 名字以及 class 带的参数
两者最终都是调用 AppRuntime 对象的 start 函数,加载 ZygoteInit 或 RuntimeInit 两个Java类,并将之前整理的参数传入进去。
由于本篇讲的是zygote进程启动流程,因此接下来我只讲解ZygoteInit的加载.
int main(int argc, char* const argv[])
{
...
// 构建 AppRuntime 对象,并将参数 (-Xzygote) 传递进去
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// Process command line arguments
// ignore argv[0]
argc--;
argv++;
// 所有在"--"后面或者非"-"开头的参数都会被传入vm
// 所谓一个特例,在 spaced_commands 变量中定义的参数会被传入vm
const char* spaced_commands[] = { "-cp", "-classpath" };
// Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
bool known_command = false;
...
省略代码
通过 runtime.addOption 初始化参数集合
这边直接跳过
...
// Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
// 跳过一个参数,之前跳过了 -Xzygote,这里继续跳过 /system/bin,就是所谓的 parent dir
++i; // Skip unused "parent dir" argument.
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) { // 表示是 zygote 启动模式
zygote = true;
niceName = ZYGOTE_NICE_NAME; // 根据平台可能是 zygote64 或 zygote
} else if (strcmp(arg, "--start-system-server") == 0) { // 是否开启 SystemService
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) { // application 启动模式
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) { // 进程别名
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) { // application启动的class
className.setTo(arg);
break;
} else {
--i;
break;
}
}
Vector<String8> args;
if (!className.isEmpty()) {
// className 不为空表示是 application 启动模式
// 这里不做分析
...
} else {
// 表示处在 zygote 启动模式
// 新建Dalvik的缓存目录.
maybeCreateDalvikCache();
if (startSystemServer) {
args.add(String8("start-system-server"));
}
//加入--abi-list=参数
char prop[PROP_VALUE_MAX];
if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
ABI_LIST_PROPERTY);
return 11;
}
String8 abiFlag("--abi-list=");
abiFlag.append(prop);
args.add(abiFlag);
// In zygote mode, pass all remaining arguments to the zygote
// main() method.
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}
// 设置进程别名
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
if (zygote) {
//如果是zygote启动模式,则加载ZygoteInit
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} 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.");
}
我们看到,在最后调用的是 runtime.start 函数,这个就是要启动虚拟机了,接下来我们分析 start 函数
2.2 AppRuntime 分析
AppRuntime 类的声明和实现均在 app_main.cpp 中,它是由 AndroidRuntime 类派生出来的,AppRuntime 重载了 onStart、onZygoteInit、onExit 等一些重要的方法。
前面调用的 start 方法实现在基类 AndroidRuntime 中,前半部分主要是初始化JNI,然后创建虚拟机,注册一些JNI函数
File:platform/frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
... // 日志打印,获取ANDROID_ROOT环境变量
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
// ① 创建虚拟机
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env); //表示虚拟创建完成时回调的方法
/*
* Register android functions.
*/
// ② 注册 JNI 函数
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
... //③ JNI 方式调用 ZygoteInit 类的 main 函数
}
上面的分析中,关键点①、②、③共同组成了 Android 系统中 Java 世界的三部曲。
1. 创建虚拟机 startVm
这个函数没有特别之处,就是调用JNI的虚拟机创建函数,但是创建虚拟机时的一些参数是在 startVm 中确定的,其实就是从各种系统属性中读取一些参数,然后通过 addOption 设置到 AndroidRuntime 的 mOptions 数组中存起来,代码如下:
File:platform/frameworks/base/core/jni/AndroidRuntime.cpp
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
// 调用 JNI_CreateJavaVM 创建虚拟机,pEnv 返回当前线程的 JniEnv 变量
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
return -1;
}
return 0;
}
2. 注册 JNI 函数 startReg
前面是如何创建虚拟机,下一步需要给虚拟机注册一些 JNI 函数,正式因为后续 Java 世界用到的一些函数时采用 native 方法实现的,所以才必须提前注册这些函数
File:platform/frameworks/base/core/jni/AndroidRuntime.cpp
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
ATRACE_NAME("RegisterAndroidNatives");
// 设置 Thread 类的线程创建函数为 javaCreateThreadEtc
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
ALOGV("--- registering native functions ---\n");
// 创建一个 200 容量的局部引用作用域
env->PushLocalFrame(200);
// 注册 Jni 函数
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL); //释放局部引用作用域
//createJavaThread("fubar", quickTest, (void*) "hello");
return 0;
}
register_jni_procs是主要的 JNI 注册函数
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
for (size_t i = 0; i < count; i++) {
if (array[i].mProc(env) < 0) {
#ifndef NDEBUG
ALOGD("----------!!! %s failed to load\n", array[i].mName);
#endif
return -1;
}
}
return 0;
}
mProc 就是为 Java 类注册了 JNI 函数
3. 反射调用 ZygoteInit 类的 main 函数
虚拟机已创建好,JNI函数也已注册,下一步就是通过CallStaticVoidMethod了,通过这个函数真正进入 Java 世界。
这个 Java 世界的入口就是 CallStaticVoidMethod 最终调用的 com.android.internal.os.ZygoteInit 的 main 函数。
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
...
// ① 创建 Socket,通过这个 Socket 与 ActivityManagerService 通信
zygoteServer.registerServerSocket(socketName);
...
// ② 预加载资源
preload(bootTimingsTraceLog);
...
if (startSystemServer) {
// ③ fork 出 SystemService
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
r.run();
return;
}
}
......
zygoteServer.runSelectLoop(abiList);
......
}
建立 IPC 通信服务端 - registerServerSocket
先分析主体的框架,首先创建了一个 ZygoteServer 类,并 registerServerSocket 创建一个 Socket,这个Socket 将 listen 并 accept Client
它将作为服务端来和客户端的 ActivityManagerService 进行通信来 fork 出子进程。
预加载类和资源 - preload
首先看 preloadClass
File:ZygoteInit.java
private static void preloadClasses() {
final VMRuntime runtime = VMRuntime.getRuntime();
InputStream is;
try {
// 预加载类的信息存储在 PRELOADED_CLASSED 中(/system/etc/preloaded-classes)
is = new FileInputStream(PRELOADED_CLASSES);
} catch (FileNotFoundException e) {
Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
return;
}
... // 统计工作
try {
BufferedReader br
= new BufferedReader(new InputStreamReader(is), 256);
int count = 0;
String line;
while ((line = br.readLine()) != null) {
// Skip comments and blank lines.
line = line.trim();
if (line.startsWith("#") || line.equals("")) {
continue;
}
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, line);
try {
if (false) {
Log.v(TAG, "Preloading " + line + "...");
}
// Load and explicitly initialize the given class. Use
// Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups
// (to derive the caller's class-loader). Use true to force initialization, and
// null for the boot classpath class-loader (could as well cache the
// 通过 JAVA 反射来加载类
// class-loader of this class in a variable).
Class.forName(line, true, null);
count++;
} catch (ClassNotFoundException e) {
}
}
Log.i(TAG, "...preloaded " + count + " classes in "
+ (SystemClock.uptimeMillis()-startTime) + "ms.");
} catch (IOException e) {
Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
} finally {
... // 扫尾工作
}
}
preload_class 文件由 framework/base/tools/preload 工具生成,它判断每个类加载的时间是否大于1250微秒,超过就写入 preload_class 文件,最后由 zygote 进行预加载。
preloadClass 执行的时间比较长,这也是andorid启动慢的原因,可以在此进行开机速度优化
preloadResource 预加载的原理很简单,就是在 zygote 进程启动后将资源读取出来,保存到 Resources 一个全局静态变量中,下次读取系统资源的时候优先从静态变量中查找
启动 SystemService —— forkSystemServer
第三个关键点是 startSystemService,这个函数会创建 Java 世界中传统 Service 所驻留的进程 system_service,该进程是 framework 的核心。
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
...
// 设置参数
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
/* Request to fork the system server process */
// fork 出一个子进程,这个子进程就是 systemSevice
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) {
// fork 成功,开启一些预备工作
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
return handleSystemServerProcess(parsedArgs);
}
return null;
}
Zygote.forkSystemServer() 创建一个系统服务进程,进程创建成功后返回 pid 为 0,由于此处生成的新进程和 Zygote 进程一模一样,也就是说这个新进程中同样包含了刚才创建的 Socket,但是该 Socket 在此处无效,因此要将其关闭。接下来调用 handleSystemServerProcess() 处理刚才新建的进程即 SystemServer 进程,需要注意此时已经工作在 SystemServe r进程中
有求必应之等待请求 —— runSelectLoop
前面一个关键点是 registZygotSocket 注册了一个用于 IPC 的 Socket,它的用途在这个函数中能体现出来,这个函数监听客户端的请求
/**
* Runs the zygote process's select loop. Accepts new connections as
* they happen, and reads commands from connections one spawn-request's
* worth at a time.
*/
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
// 新客户端连接请求,充当服务端 Socket
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
try {
ZygoteConnection connection = peers.get(i);
final Runnable command = connection.processOneCommand(this);
if (mIsForkChild) {
// We're in the child. We should always have a command to run at this
// stage if processOneCommand hasn't called "exec".
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
} else {
// We're in the server - we should never have any commands to run.
if (command != null) {
throw new IllegalStateException("command != null");
}
// We don't know whether the remote side of the socket was closed or
// not until we attempt to read from it from processOneCommand. This shows up as
// a regular POLLIN event in our regular processing loop.
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(i);
fds.remove(i);
}
}
} catch (Exception e) {
...
}
}
}
}
}
- 处理客户端连接和客户请求,其中客户在 zygote 中用 ZygoteConnection 对象来表示
- 客户的请求在函数 processOneCommand 中处理
3. 总结
zygote 是 Android系统中创建 Java 世界的盘古,它创建第一个 Java 虚拟机,同时它又是女娲,繁殖了 framework 的核心 system_server 进程
- 第一天,创建 AppRuntime 对象,并调用他的 start,此后的活动由 AppRuntime 控制
- 第二天,调用 startVm 创建 Java 虚拟机,然后调用 startReg 来注册 JNI 函数
- 第三天,通过 JNI 调用 com.android.internal.os.ZygoteInit 类的 main 函数,进入 Java 世界,但这个世界刚开始啥也没有
- 第四天,调用 registerZygoteSocket,通过这个函数,它可以响应子孙后代的请求,同时 zygote 调用 preloadClasses 和 preloadResources,为Java世界添砖加瓦
- 第五天,zygote 觉得自己的工作压力大了,便通过调用 startSystemServer 分裂一个子进程 system_server 来为 java 世界服务
- 第六天,zygote 调用 runSelectLoop – 等待并处理来自客户的消息,后便睡去
以后的日子里,zygote 随时守护在我们周围,当接收子孙后代的请求后,它会随时醒来为它们工作。