前言
计划写一个系列文章,从 Zygote 开始,说到 Activity,再到 View 的显示及事件分发等,意在把 Android 开发中最核心的一些的知识点串成线,看看 Android 是怎么把它们组织到一起的,希望能写好。
本文是第一篇,以“Zygote 的启动流程及运行机制”为题, 将打通“虚拟机-Zygote-应用进程-ActivityThread”这一条线。
Zygote 的中文意思是受精卵、合子,可以理解为孵化器——Android 中大多数应用进程和系统进程都是通过 Zygote 来生成的。
PS:源码基于 Android API 27。
Zygote 是怎么启动的?
init
Android 的第一个进程为 init,init 通过解析 init.rc 来陆续启动其它关键的系统服务进程——其中最重要的是 ServiceManager、Zygote 和 SystemServer。下面以 init.zygote64.rc 为例开始分析:
## 服务名、路径、参数
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
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
writepid /dev/cpuset/foreground/tasks
通过指定 --zygote 参数,app_process 可以识别出是否需要启动 zygote。
虚拟机的启动
下面开始分析路径 app_process 中的文件 app_main.cpp :
// app_process/app_main.cpp
int main(int argc, char* const argv[])
{
// 创建 Android 虚拟机对象
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
...
// Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
++i; // Skip unused "parent dir" argument.
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) { // // init.rc 指定了参数--zygote,因此这里为 true
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) { // init.rc 指定了参数--start-system-server,因此这里也为 true
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
...
} else {
...
}
}
Vector<String8> args;
if (!className.isEmpty()) {
...
} else {
if (startSystemServer) {
args.add(String8("start-system-server")); // 添加 SystemServer 参数
}
...
}
...
if (zygote) {
// 启动虚拟机及 Zygote,注意包名
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.");
}
}
根据以上代码,可以知道 Zygote 运行于 Android 虚拟机上,因为 AppRuntime 继承于 AndroidRuntime:
class AppRuntime : public AndroidRuntime
{
public:
AppRuntime(char* argBlockStart, const size_t argBlockLength)
: AndroidRuntime(argBlockStart, argBlockLength)
, mClass(NULL)
{
}
...
}
AppRuntime 更多是处理一些事件完成后的回调,主要的实现依然在 AndroidRuntime 中。因此下面直接看 AndroidRumtime::start 的实现:
/*
* Start the Android runtime. This involves starting the virtual machine
* and calling the "static void main(String[] args)" method in the class
* named by "className".
*
* Passes the main function two arguments, the class name and the specified
* options string.
*
* 该方法用于启动 Android 虚拟机,并调用 className 对应的类的 main 方法
*/
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...
/* 启动虚拟机 */
JniInvocation jni_invocation;
jni_invocation.Init(NULL); // 初始化虚拟机环境
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) { // 启动
return;
}
onVmCreated(env); // 回调,通知虚拟机已成功启动
/*
* 注册 Android 的 native 函数
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
/*
* We want to call main() with a String array with arguments in it.
* At present we have two arguments, the class name and an option string.
* Create an array to hold them.
*
* 调用 className 对应的类的 main 方法,并传入相应的参数
*/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
stringClass = env->FindClass("java/lang/String");
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
classNameStr = env->NewStringUTF(className);
env->SetObjectArrayElement(strArray, 0, classNameStr);
// 设置参数
for (size_t i = 0; i < options.size(); ++i) {
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
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.
*
* 当前线程会成为虚拟机的主线程,除非虚拟