AndroidRuntime.start
SS002 解释了 app_process 如何选择 ZygoteInit 或 RuntimeInit。本篇继续向下追踪 AndroidRuntime::start():它如何确定系统根目录,创建 ART VM,调用 AppRuntime 回调注册 Android native 方法,再把 class name 和 options 组装成 Java String[],最后通过 JNI 找到静态 main(String[])。
这条链的关键不是“native 调 Java”这一句,而是每一步都有明确 owner:环境变量由进程启动环境提供,VM 参数由 startVm() 组合,JNI 表由 startReg() 维护,启动类由 FindClass() 解析,VM 主线程直到 CallStaticVoidMethod() 返回才继续清理。失败发生在哪一步,决定了该查 app_process、ART、JNI 注册还是 Java 入口。
1. start的入口契约
源码文件:frameworks/base/core/jni/AndroidRuntime.cpp
相关函数:AndroidRuntime::start()
void AndroidRuntime::start(const char* className,
const Vector<String8>& options,
bool zygote)
{
ALOGD(">>>>>> START %s uid %d <<<<<<\\n",
className != NULL ? className : "(unknown)", getuid());
static const String8 startSystemServer("start-system-server");
bool primary_zygote = false;
for (size_t i = 0; i < options.size(); ++i) {
if (options[i] == startSystemServer) {
primary_zygote = true;
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
}className 是 Java 启动类,options 是 SS002 组装的参数,zygote 只影响 VM 创建配置。start-system-server 并不是传给 main() 的业务参数而已:这里先把它识别为 primary zygote,影响启动日志和 startVm() 的 primary_zygote 参数。也就是说,同一个 ZygoteInit 类名在 primary/secondary zygote 上可能拥有不同的 VM 配置上下文。
2. 环境目录与VM准备
源码文件:frameworks/base/core/jni/AndroidRuntime.cpp
相关函数:AndroidRuntime::start()、AndroidRuntime::startVm()
const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
if (!hasDir("/system")) {
LOG_FATAL("No root directory specified, and /system does not exist.");
return;
}
setenv("ANDROID_ROOT", rootDir, 1);
}
const char* artRootDir = getenv("ANDROID_ART_ROOT");
if (artRootDir == NULL) {
LOG_FATAL("No ART directory specified with ANDROID_ART_ROOT environment variable.");
return;
}
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
return;
}这里至少有四个环境目录:ANDROID_ROOT、ANDROID_ART_ROOT、ANDROID_I18N_ROOT 和 ANDROID_TZDATA_ROOT。startVm() 之前的检查确保 ART、国际化数据和时区数据路径已经能被后续 VM 初始化使用;JniInvocation::Init() 再选择实际 JNI 实现。startVm() 返回非零时,VM 尚未交给 onVmCreated(),因此不能继续假设 JNI native 已注册。
startVm() 内部把属性、命令行和 zygote/primary 标志转换成 JavaVMInitArgs,最后调用 JNI_CreateJavaVM()。它是 VM 配置 owner,不负责查找 ZygoteInit.main()。
3. JNI注册的时机
源码文件:frameworks/base/core/jni/AndroidRuntime.cpp
相关函数:AndroidRuntime::startReg()
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
ATRACE_NAME("RegisterAndroidNatives");
androidSetCreateThreadFunc(
(android_create_thread_fn) javaCreateThreadEtc);
env->PushLocalFrame(200);
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
return 0;
}JNI 注册发生在 VM 创建之后、调用 Java main() 之前。gRegJNI 是静态注册表,每个 REG_JNI(...) 项负责一个 Android native 模块;PushLocalFrame(200)/PopLocalFrame() 限制注册阶段产生的 local reference,失败时返回 -1 让 start() 停止继续启动。
这里的线程 owner 也很重要:androidSetCreateThreadFunc() 让后续 native 创建线程使用能够附着到 JavaVM 的创建函数。它不是 Binder 线程池启动;Binder 线程池由 AppRuntime::onStarted() 或 onZygoteInit() 负责。
4. Java入口的组装
源码文件:frameworks/base/core/jni/AndroidRuntime.cpp
jclass stringClass = env->FindClass("java/lang/String");
jobjectArray strArray = env->NewObjectArray(
options.size() + 1, stringClass, NULL);
jstring 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).c_str());
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}Java main() 收到的数组第 0 项是 class name,后续才是 options。对 Zygote 来说,ZygoteInit.main() 会读取 start-system-server、--abi-list 等参数;对 RuntimeInit 来说,RuntimeInit.main() 会把第 0 项当作目标启动类并继续解析剩余参数。这个数组不是 app_process 的原始 argv,也不包含 VM 选项。
5. Java入口反射
源码文件:frameworks/base/core/jni/AndroidRuntime.cpp
char* slashClassName = toSlashClassName(
className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\\n", slashClassName);
} else {
jmethodID startMeth = env->GetStaticMethodID(
startClass, "main", "([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\\n", className);
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
}
free(slashClassName);toSlashClassName() 把 Java 常见的点号类名转换成 JNI 所需的斜杠形式。FindClass() 成功只证明类能被当前 JNI 上下文找到;还要通过精确签名 ([Ljava/lang/String;)V 找到静态 main。任何一步失败都只记录错误并继续到 VM 清理段,不能把“日志打印后仍执行清理”误认为 Java main 已经运行。
CallStaticVoidMethod() 是控制权转移点:从这里开始,ZygoteInit 或 RuntimeInit 的 Java 代码成为主线程消费者。该调用返回后,AndroidRuntime 不再执行第二个 Java 入口,而是进入 detach/destroy。
6. VM结束与回调边界
源码文件:frameworks/base/core/jni/AndroidRuntime.cpp、frameworks/base/cmds/app_process/app_main.cpp
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");AndroidRuntime::start() 负责 detach 和 destroy;AppRuntime::onStarted() 在应用/工具 main 返回前后还会停止 kernel Binder 与 hwbinder 的进程状态;onExit() 在 Zygote 模式下同样停止这两类 Binder 状态。三者不是重复清理:VM 生命周期、Binder 进程状态和 app_process 的退出回调分别由不同 owner 管理。
7. 失败定位
# VM/环境:输入环境变量和 AndroidRuntime.cpp,输出环境检查与 startVm 分支。
rg -n "ANDROID_ROOT|ANDROID_ART_ROOT|ANDROID_I18N_ROOT|ANDROID_TZDATA_ROOT|startVm\(" \
frameworks/base/core/jni/AndroidRuntime.cpp
# JNI 注册:输入静态注册表和注册函数,输出模块注册入口及失败返回。
rg -n "gRegJNI|startReg|register_jni_procs|androidSetCreateThreadFunc" \
frameworks/base/core/jni/AndroidRuntime.cpp
# Java 入口:输入 FindClass/main 调用和 Java 入口,输出 class、签名与参数消费者。
rg -n "FindClass|GetStaticMethodID|CallStaticVoidMethod" \
frameworks/base/core/jni/AndroidRuntime.cpp
rg -n "public static void main|RuntimeInit\.main|ZygoteInit\.main" \
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java \
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java排查时按顺序区分:环境/VM 错误、JNI 注册错误、class 或 main 签名错误、Java main 内部异常。不要只看 START 日志判断启动成功;真正进入 Java 世界的边界是 CallStaticVoidMethod(),真正完成 Zygote/SystemServer 启动还要继续读对应 Java 主线。
下一篇将展开 ZygoteInit.main() 的参数解析和预加载入口;不会重复本文的 VM 创建、JNI 注册和静态 main 反射。
