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

相关推荐
Godikov1 小时前
硬件异步事件下的业务一致性:智能柜领取/归还流程的竞态设计
android
Godikov1 小时前
不用 Netty:Android 手写 TCP 客户端实战——自定义协议帧、粘包处理与可靠重连
android
事圆则缓1 小时前
Java 面向对象如何落到 Android View 体系
android
iPad协议个微协议3 小时前
# 微信自动营销系统如何基于 WechatApi 做事件驱动设计
android·微信·企业微信·个人开发·wechatapi·微信个人号开发
AirDroid_cn3 小时前
隐私沙盒:第三方应用读取剪切板内容如何拦截?
android·gitee
2501_915918415 小时前
怎么把 Python 写的 Flet 应用打包成 iOS App 并上架 App Store?
android·ios·小程序·https·uni-app·iphone·webview
邪修king6 小时前
Re:Linux系统篇(二十六):文件系统(二):Ext 文件系统底层详解:从 inode、块组到软硬链接,结合 Windows 讲透文件管理本质
android·java·linux
又见情义7 小时前
RK3568 Android 13 版本号管理实战:基于 ROCKCHIP_BUILD_NUMBER 的定制化方案
android
终端安全笔记7 小时前
iOS 27 强制 TLS 1.2:租赁设备的注册链路会在哪一环断
android·网络·安全·ios·智能手机
mmsx7 小时前
MapLibre 实战 11|用户说"我的地块丢了":一个 sealed class 图层模型,和四个让我重构三版的坑
android·前端·开源