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

相关推荐
CedarQR1 小时前
云卓 G20 遥控器 Android 开发实录:从 USB 设备到读取摇杆/按键通道值
android·linux·无人机
pengyu2 小时前
【Kotlin 协程修仙录 · 炼虚境 · 初阶】 | 虚空造物:Channel 基础与协程间通信的管道艺术
android·前端·kotlin
小强闯江湖2 小时前
ViewCompose:让原生 Android View 进入声明式时代
android·开源·kotlin
摇滚侠4 小时前
《SpringBoot 3:入门与应用实战》第 6 章 Spring Boot 最佳实践 阅读笔记 12
android·spring boot·笔记
mmsx4 小时前
Android 宠物健康服务平台实战:从架构设计到主题换肤完整解析(源码和文档)
android·架构·sqlite·app·源码·宠物
、如果4 小时前
ima Skills 自进化实战:三层结构、反馈与版本验证
android·人工智能·ai编程
hunterandroid5 小时前
自定义 View 绘制与触摸冲突:从滑动卡顿到事件分发闭环
android·前端
weixin_403810135 小时前
安卓自动化脚本 HID 硬件选购指南:蓝牙HID与OTG HID区别、成本与搭建教程
android·运维·自动化·hid·安卓自动化脚本·安卓中控
qq_316837755 小时前
uniapp 安卓/H5 使用 contentEditable 属性 富文本编辑器
android·javascript·uni-app
二流小码农6 小时前
鸿蒙开发:了解Context
android·ios·harmonyos