3、Zygote启动流程(中):app_process主函数入口、AndroidRuntime的start函数、JNI环境初始化
好,我们接着往下走。
上一章我们聊了init进程怎么把Zygote拉起来,说白了就是解析了rc文件,fork了一个子进程,然后执行了/system/bin/app_process这个可执行文件。那今天我们就从这个可执行文件的入口开始,一步步走进Zygote的世界。
3.1 app_process的主函数:一切的起点
你想想看,一个C++程序,入口肯定是main函数。app_process也不例外。它的源码在frameworks/base/cmds/app_process/app_main.cpp里。
我直接贴核心代码,咱们边看边聊:
int main(int argc, char* const argv[])
{
// 创建AppRuntime实例
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// 处理启动参数
// 这里有个细节:Zygote进程启动时,argv[1]是"-Xzygote"
// 而普通应用进程启动时,argv[1]是"--application"
int i;
for (i = 0; i < argc; i++) {
if (argv[i][0] != '-') {
break;
}
if (argv[i][1] == '-' && argv[i][2] == 0) {
++i;
break;
}
runtime.addOption(strdup(argv[i]));
}
// 解析剩余参数
// 这里决定了是启动Zygote还是启动一个普通应用
bool zygote = false;
if (strcmp(argv[i], "--zygote") == 0) {
zygote = true;
}
// 设置进程名
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit",
ZYGOTE_NICE_NAME, zygote);
} else {
runtime.start("com.android.internal.os.ZygoteInit",
"app_process", zygote);
}
return 0;
}
嗯,这里有个关键点:AppRuntime。它是什么?它是AndroidRuntime的子类。说白了,整个Java世界的启动,全靠这个runtime对象来驱动。
核心要点:
- app_process的main函数非常简洁,主要就是创建AppRuntime并调用它的start方法
- 通过命令行参数区分Zygote进程和普通应用进程
- Zygote进程的nice name是"zygote",普通应用是"app_process"
3.2 AndroidRuntime的start函数:Java世界的点火器
好,现在进入重头戏。AppRuntime继承自AndroidRuntime,但start方法是在父类中实现的。我们来看看frameworks/base/core/jni/AndroidRuntime.cpp里的start函数:
void AndroidRuntime::start(const char* className,
const char* niceName,
bool zygote)
{
// 设置进程名
if (niceName) {
set_process_name(niceName);
}
// 设置环境变量
// 这个ANDROID_ROOT很重要,很多资源文件都依赖它
const char* root = getenv("ANDROID_ROOT");
if (root == NULL) {
root = "/system";
setenv("ANDROID_ROOT", root, 1);
}
// 启动Java虚拟机
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
// 创建JavaVM
JavaVM* javaVM;
JavaVMOption options[100];
// ... 各种JNI选项的设置,这里省略
// 关键一步:创建Java虚拟机
if (JNI_CreateJavaVM(&javaVM, &env, &vm_args) != JNI_OK) {
// 创建失败的处理
return;
}
// 注册Android的JNI函数
if (startReg(env) < 0) {
// 注册失败的处理
return;
}
// 调用Java类的main方法
jclass stringClass;
jobjectArray strArray;
// ... 构造参数数组
jmethodID mid = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
env->CallStaticVoidMethod(startClass, mid, strArray);
// 注意:这里不会返回,因为ZygoteInit.main()会进入死循环
}
我个人习惯把start函数分成三个阶段来看:
- 准备阶段:设置进程名、环境变量
- 启动阶段:创建Java虚拟机、注册JNI函数
- 执行阶段:调用Java类的main方法
避坑指南:
我曾经在移植Android系统到新平台时,卡在JNI_CreateJavaVM这一步好几天。后来发现是ANDROID_ROOT环境变量没设置对,导致虚拟机找不到核心库。所以,环境变量的设置顺序很重要,一定要在创建虚拟机之前完成。
3.3 JNI环境初始化:连接C++和Java的桥梁
接下来我们重点看看startReg这个函数。它负责注册Android系统所有的JNI函数。说白了,就是告诉Java虚拟机:这些native方法对应的C++实现在哪里。
int AndroidRuntime::startReg(JNIEnv* env)
{
// 设置线程的JNI环境
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
// 创建JNI环境
env->PushLocalFrame(200);
// 注册JNI函数
if (register_jni_procs(gRegJNI, gRegJNI_SIZE, env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
return 0;
}
这里有个重要的数据结构:gRegJNI。它是一个函数指针数组,每个元素指向一个JNI注册函数。我截取一部分给大家看看:
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_content_AssetManager),
REG_JNI(register_android_content_StringBlock),
// ... 还有上百个注册函数
};
你想想看,Android系统有多少个JNI函数?光这里注册的就有上百个。每个注册函数内部会调用env->RegisterNatives来建立Java方法和C++函数的映射关系。
JNI注册的两种方式:
| 方式 | 说明 | 优点 | 缺点 |
|---|---|---|---|
| 静态注册 | 函数名按JNI规范命名 | 简单直接 | 函数名冗长,不易维护 |
| 动态注册 | 通过RegisterNatives注册 | 灵活,可动态绑定 | 需要额外代码 |
Android系统采用的是动态注册方式。为什么?因为静态注册要求函数名必须按照Java_包名_类名_方法名的格式来命名,你想想看,像com.android.internal.os.RuntimeInit这样的类,对应的C++函数名得有多长?维护起来简直是噩梦。
注意事项:
JNI注册的顺序是有讲究的。我记得有一次调试一个系统服务,发现某个native方法总是调用失败。查了半天,原来是它依赖的另一个JNI函数还没注册。所以,gRegJNI数组的顺序不能随意调整,有依赖关系的必须放在前面。
3.4 小结:从app_process到Java世界的完整链路
好,我们来梳理一下今天的内容。从app_process的main函数开始,到AndroidRuntime的start函数,再到JNI环境的初始化,这条链路其实就做了一件事:把C++的世界和Java的世界连接起来。
我个人觉得,理解这个流程的关键在于把握三个核心点:
- AppRuntime:它是整个过程的驱动器,负责协调各个步骤
- JavaVM:它是Java世界的基石,所有Java代码都运行在它之上
- JNI注册:它是两个世界的桥梁,没有它,Java代码就调不了native方法
下一章,我们会深入ZygoteInit的main方法,看看Zygote进程是如何完成初始化,并进入等待客户端连接的循环的。嗯,那里才是Zygote真正开始干活的地方。