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 过程中的跨层调用开销。

相关推荐
城东米粉儿2 小时前
android 耗电优化 笔记
android
毕设源码-钟学长2 小时前
【开题答辩全过程】以 基于安卓的医疗健康查询系统为例,包含答辩的问题和答案
android
归真仙人2 小时前
【UE】UMG安卓相关问题
android·ue5·游戏引擎·ue4·虚幻·unreal engine
sugarzhangnotes2 小时前
MySQL 8.0升级中的字符集陷阱与解决方案
android·数据库·mysql
3***g2052 小时前
C盘清理技巧分享了解C盘空间占用情况
android
摘星编程2 小时前
Flutter for OpenHarmony 实战:CustomScrollView 自定义滚动视图详解
android·javascript·flutter
lynn8570_blog3 小时前
关于compose的remember
android·kotlin
毕设源码-邱学长3 小时前
【开题答辩全过程】以 基于安卓的外卖点餐APP的设计与实现为例,包含答辩的问题和答案
android