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

相关推荐
ANYOUZHEN2 小时前
bugku shell
android
南宫码农5 小时前
我的电视 - Android原生电视直播软件 完整使用教程
android·开发语言·windows·电视盒子
道亦无名5 小时前
音频数据特征值提取 方法和步骤
android·音视频
Lancker5 小时前
定制侠 一个国产纯血鸿蒙APP的诞生过程
android·华为·智能手机·鸿蒙·国产操作系统·纯血鸿蒙·华为鸿蒙
2601_949809597 小时前
flutter_for_openharmony家庭相册app实战+通知设置实现
android·javascript·flutter
液态不合群7 小时前
【面试题】MySQL 中 count(*)、count(1) 和 count(字段名) 有什么区别?
android·数据库·mysql
雪球Snowball9 小时前
【Android关键流程】资源加载
android
2501_915918419 小时前
常见 iOS 抓包工具的使用,从代理抓包、设备抓包到数据流抓包
android·ios·小程序·https·uni-app·iphone·webview
墨月白10 小时前
[QT]QProcess的相关使用
android·开发语言·qt
enbug11 小时前
编译安卓内核:以坚果R1、魔趣MK100(Android 10)系统为例
android·linux