AOSP15的Zygote启动流程源码分析

Zygote(受精卵进程)是 Android 系统中所有 Java 应用程序进程及 SystemServer 的父进程。扮演"孵化器"角色,负责孵化系统中所有应用程序进程,通过 fork 机制和写时复制(Copy-on-Write)技术,加速进程创建并减少内存占用。

一、整体流程概览

Zygote 的启动经历了从 Linux 内核空间 到 Native C++ 空间,最后进入 Java 空间 的过程。

  1. init 进程:解析 .rc 脚本,启动 app_process 二进制文件。
  2. Native 阶段:初始化 AndroidRuntime,启动 ART 虚拟机并注册 JNI。
  3. Java 阶段:ZygoteInit 预加载资源,启动 SystemServer。
  4. 循环阶段:进入 ZygoteServer 循环,等待 Socket 消息孵化应用。

二、第一阶段:Native 层启动 (app_process)

1. 入口:app_main.cpp

源码路径frameworks/base/cmds/app_process/app_main.cpp

init进程根据 init.zygote64.rc 中的配置启动。main 函数是起点:

  • 识别身份:通过判断参数中是否有 --zygote 来确定自己作为 Zygote 启动。
  • 准备参数:指定主类名为 com.android.internal.os.ZygoteInit。
  • 调用 Runtime:
c++ 复制代码
// 启动 AndroidRuntime
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);

2. 核心桥梁:AndroidRuntime.cpp

源码路径frameworks/base/core/jni/AndroidRuntime.cpp

runtime.start 函数完成了 Native 到 Java 的惊险一跃:

  • startVm() :启动 ART (Android Runtime)。配置堆大小、JIT 编译模式、GC 策略等。
  • startReg():注册系统核心 JNI 方法。这使得 Java 代码可以调用 Native 的驱动接口和底层
  • JNI 调用
c++ 复制代码
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ......

    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        // 找到 Java 层的 ZygoteInit 类及其 main 方法
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            // 正式进入 Java 世界
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
        }
    }
  }

    ......

三、 第二阶段:Java 层初始化 (ZygoteInit)

源码路径frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

进入 ZygoteInit.main() 后,Zygote 开始构建"受精卵"的基因:

1. 预加载资源 (Preload)

这是 Android 启动优化的核心,通过 preload() 方法:

  • preloadClasses():从 /system/etc/preloaded-classes 加载数千个核心 Java 类。
  • preloadResources():加载系统 Framework 的资源文件(图标、布局)。
  • preloadSharedLibraries():加载常用的动态链接库。
  • 优势 :子进程在 fork 时直接共享这些内存,只有在修改时才会物理复制(COW 机制

2. 创建 ZygoteServer (Socket)

Zygote 会创建一个名为 zygoteLocalServerSocket ,用于接收来自 ActivityManagerService (AMS) 的进程启动请求。

四、 第三阶段:孵化 SystemServer

Zygote 初始化完成后,第一个任务就是启动 SystemServer,它是 Android 大脑的载体。

  1. Fork 进程:调用 Zygote.forkSystemServer()。

  2. 身份分化:

  • 父进程 (Zygote):继续执行 runSelectLoop 监听 Socket。
  • 子进程 (SystemServer):
    • 调用 handleSystemServerProcess。
    • 关闭继承自 Zygote 的不需要的 Socket 和资源。
    • 最终通过反射调用 com.android.server.SystemServer.main()。

五、 第四阶段:运行循环 (ZygoteServer、ZygoteInit)

Zygote 最后会通过 runSelectLoop() 进入阻塞等待状态: 源码路径frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

java 复制代码
Runnable runSelectLoop(String abiList) {
    while (true) {
        // 使用 poll/select 监听 Socket 消息
        StructPollfd[] pollFds = ...;
        Os.poll(pollFds, -1);
        
        while(-pollIndex >= 0){
            if (pollIndex == 0) {
                // 当收到 AMS 发来的命令时
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                socketFDs.add(newPeer.getFileDescriptor());
            } else if (pollIndex < usapPoolEventFDIndex) {

                ZygoteConnection connection = peers.get(pollIndex);
                boolean multipleForksOK = !isUsapPoolEnabled()
                                    && ZygoteHooks.isIndefiniteThreadSuspensionSafe();
                // 执行 fork 逻辑
                final Runnable command = connection.processCommand(this, multipleForksOK);

                if (mIsForkChild) {
                    if (command == null) {
                        throw new IllegalStateException("command == null");
                    }
                    return command;
                 } else {
                    if (command != null) {
                        throw new IllegalStateException("command != null");
                    }
                    if (connection.isClosedByPeer()) {
                        connection.closeSocket();
                        peers.remove(pollIndex);
                        socketFDs.remove(pollIndex);
                        }
                    }
                 }
                        
        }

    }
}

run子进程执行应用入口 源码路径frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

java 复制代码
public static void main(String[] argv) {
        ......
        if (caller != null) {
            caller.run();
        }
    }

六、 总结

Zygote 的启动是 "由厚变薄" 的过程:

  1. 由厚:它在启动时加载了大量的类和资源,导致自身占用了较大的内存。
  2. 变薄:由于 Linux 的 fork 机制,后续启动的所有 App 进程都共享 Zygote 的这一份内存空间(Copy-on-Write机制,COW)。

在 AOSP 15 中,这种设计依然是系统响应速度和内存效率的基础。同时 AOSP 15 进一步优化了 ZygoteCommandBuffer 机制,减少了 fork 过程中的跨层调用开销。

相关推荐
阿巴斯甜5 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker5 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95276 小时前
Andorid Google 登录接入文档
android
黄林晴8 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab20 小时前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android