zygote 进程启动分析二

136 阅读4分钟

Android 系统中 Zygote 进程启动的核心技术细节,解析从 C++ 运行时到 Java 层的关键过渡流程:

一、Zygote 启动的「桥梁」:AppRuntime 与 AndroidRuntime

Zygote 进程的启动涉及 C++ 层与 Java 层的协同,核心由 AppRuntime 类(继承自 AndroidRuntime)负责创建 Java 运行环境。

1. AppRuntime 的使命

  • 作用:作为 Java 虚拟机(ART)的「启动器」,负责:

    • 初始化虚拟机实例。
    • 注册 Java 层所需的本地(Native)方法。
    • 调用 Java 层的入口函数(如 ZygoteInit.main())。
  • 关键成员

    • mJavaVM:指向 Java 虚拟机的指针。
    • mClass:存储待启动的 Java 类(如 ZygoteInit)。

2. 构造函数:初始化全局环境

c++

AppRuntime::AppRuntime(char* argBlockStart, const size_t argBlockLength)
    : AndroidRuntime(argBlockStart, argBlockLength) {
    SkGraphics::Init(); // 初始化 Skia 图形系统(Android 绘图基础)
    assert(gCurRuntime == NULL); // 确保全局唯一实例
    gCurRuntime = this; // 保存到全局变量,方便其他模块调用
}
  • 关键点

    • 通过 gCurRuntime 确保每个进程仅有一个 AndroidRuntime 实例。
    • 初始化 Skia,为后续图形渲染奠定基础。

二、启动虚拟机:从 C++ 到 Java 的「大门」

1. startVm 函数:唤醒 ART 虚拟机

c++

if (startVm(&mJavaVM, &env, zygote) != 0) {
    return; // 启动失败则退出
}
  • 核心逻辑

    • 调用 JNIInvocation::Init() 初始化 JNI 环境。
    • 通过 AndroidRuntime::startVm() 创建 ART 虚拟机实例,获取 JNIEnv 指针(用于 C++ 与 Java 交互)。
  • 参数意义

    • zygote 标志:告知虚拟机以「Zygote 模式」启动,启用预加载优化。

2. onVmCreated:准备 Java 类加载

c++

virtual void onVmCreated(JNIEnv* env) {
    if (mClassName.isEmpty()) return; // Zygote 模式下 mClassName 为空,直接返回
    // 查找并缓存 Java 类(非 Zygote 场景用于启动普通 Java 类)
    jclass clazz = env->FindClass(toSlashClassName(mClassName));
    mClass = env->NewGlobalRef(clazz);
}
  • Zygote 特化

    • Zygote 启动时无需指定具体类名(mClassName 为空),直接跳过类加载,专注于虚拟机初始化。

三、注册 Native 方法:Java 与 C++ 的「翻译官」

1. startReg 函数:建立跨语言通信桥梁

c++

if (startReg(env) < 0) {
    ALOGE("Unable to register all android natives\n");
    return;
}
  • 核心流程

    1. 注册 JNI 方法:通过 register_jni_procs 函数将 gRegJNI 数组中的本地方法注册到虚拟机。

    2. 关键方法示例

      • register_com_android_internal_os_ZygoteInit_nativeZygoteInit:Zygote 初始化的本地实现。
      • register_android_os_Binder:Binder 跨进程通信的本地支持。
      • register_android_util_Log:日志系统的本地接口。
  • 作用:使 Java 层能调用 C++ 实现的底层功能(如进程管理、图形渲染)。

四、调用 Java 入口:触发 ZygoteInit 的 main 函数

1. 构造参数数组

c++

jobjectArray strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr); // 第一个参数为类名
for (size_t i = 0; i < options.size(); ++i) {
    env->SetObjectArrayElement(strArray, i + 1, env->NewStringUTF(options[i].string()));
}
  • 参数构成

    • 第 0 个元素:类名(如 com.android.internal.os.ZygoteInit)。
    • 后续元素:启动参数(如 --start-system-server--socket-name=zygote)。

2. 调用 main 函数

c++

jclass startClass = env->FindClass(slashClassName); // 查找 ZygoteInit 类
jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V");
env->CallStaticVoidMethod(startClass, startMeth, strArray); // 触发 Java 层主函数
  • 执行逻辑

    • 通过 JNI 调用 ZygoteInit.main(String[] args),正式进入 Java 层初始化流程。
    • 至此,C++ 层任务完成,Zygote 进程的核心逻辑(预加载资源、启动 SystemServer、监听套接字)在 Java 层展开。

五、关键流程总结

  1. C++ 层初始化

    • AppRuntime 构造函数初始化全局环境,启动虚拟机并注册本地方法。
  2. Java 层接管

    • 通过 CallStaticVoidMethod 调用 ZygoteInit.main(),开始预加载类、启动 SystemServer 等操作。
  3. 跨层协作核心

    • JNI 是连接 C++ 与 Java 的桥梁,register_jni_procs 确保 Java 层能访问底层功能。
    • ZygoteInit 作为 Java 入口,负责后续的应用孵化和系统服务启动。

六、类比说明

Zygote 启动过程类似「搭建跨国公司的翻译部门」:

  • AppRuntime:相当于部门负责人,负责搭建翻译团队(初始化虚拟机)、招聘翻译(注册 Native 方法)。

  • JNI 注册:翻译团队的「语言手册」,记录 Java 与 C++ 的对应接口(如 Java 的 Log.d() 对应 C++ 的日志实现)。

  • ZygoteInit.main() :部门的「首席翻译」,接到任务后(参数数组)开始处理具体业务(预加载资源、启动服务)。

通过这一流程,Android 系统完成了从底层硬件到上层应用框架的过渡,为后续应用启动和系统服务运行奠定了基础。