Android FrameWork - Zygote 启动流程分析

基于 Android 12 源码

涉及文件:

system/core/rootdir/init.rc

system/core/rootdir/init.zygote64.rc

system/core/rootdir/init.zygote32.rc

frameworks/base/cmds/app_process/app_main.cpp

frameworks/base/core/jni/AndroidRuntime.cpp

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

Zygote 进程是由 init 进程通过解析 init.rc 文件而创建的。在 init.rc 中,有以下关键代码段,负责触发 Zygote 进程的启动:

rc 复制代码
on late-init
    # ... 其他 late-init 动作 ...
    # Now we can start zygote for devices with file based encryption
    trigger zygote-start

这个 trigger zygote-start 语句是一个事件触发器,当 late-init 事件发生时,它会触发 zygote-start 事件。

zygote-start 事件被触发后,init 会开始寻找定义了该事件的 service(服务)

在 Android 12 中,Zygote 服务的定义位于特定的 .rc 文件中,以支持不同的架构:

  • init.zygote64.rc: 针对 64 位设备,定义了 64 位 Zygote 服务。
  • init.zygote32.rc: 针对 32 位设备,定义了 32 位 Zygote 服务。
  • init.zygote64_32.rc: 针对 64 位设备但需要兼容 32 位应用程序的情况,定义了 64 位和 32 位 Zygote 服务。

init.zygote64.rc 为例:

rc 复制代码
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

zygote-start 事件发生时,这些代码就会被执行,-Xzygote: 告诉 app_process 这个进程是 Zygote。--start-system-server: 告诉 Zygote 进程在自身启动完成后,立即启动 System Server 进程。

这里 /system/bin/app_process64是由源码编译生成的二进制,不要纠结为什么找不到该文件,而frameworks/base/cmds/app_process/app_main.cpp才是 Zygote 的原生入口,无论 app_process32 还是 app_process64,它们的 C++ 主函数入口都是 app_main.cpp 中的 main() 函数

main 函数源码:

c++ 复制代码
int main(int argc, char* const argv[])
{
    // ...

    // AppRuntime 是 AndroidRuntime 的子类(定义在 app_main.cpp 中)。
    // 初始化 JNI 环境 > 启动 ART/Dalvik 虚拟机 > 注册 JNI 方法 > 最终调用 Java 类的 main() 方法
    // argv[0] 是可执行文件路径(如/system/bin/app_process64)
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // Process command line arguments
    // ignore argv[0]
    argc--;
    argv++;

    const char* spaced_commands[] = { "-cp", "-classpath" };
    // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
    bool known_command = false;


    // 下面代码是把以 - 开头的参数(如 -Xzygote、-Dxxx)作为 虚拟机参数,添加到 runtime 中。
    // 这些参数会传递给 ART 虚拟机(类似 JVM 的 -Xmx, -XX: ..)
    int i;
    for (i = 0; i < argc; i++) {
        if (known_command == true) {
          runtime.addOption(strdup(argv[i]));
          // The static analyzer gets upset that we don't ever free the above
          // string. Since the allocation is from main, leaking it doesn't seem
          // problematic. NOLINTNEXTLINE
          ALOGV("app_process main add known option '%s'", argv[i]);
          known_command = false;
          continue;
        }

        for (int j = 0;
             j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
             ++j) {
          if (strcmp(argv[i], spaced_commands[j]) == 0) {
            known_command = true;
            ALOGV("app_process main found known command '%s'", argv[i]);
          }
        }

        if (argv[i][0] != '-') {
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            ++i; // Skip --.
            break;
        }

        runtime.addOption(strdup(argv[i]));
        // The static analyzer gets upset that we don't ever free the above
        // string. Since the allocation is from main, leaking it doesn't seem
        // problematic. NOLINTNEXTLINE
        ALOGV("app_process main add option '%s'", argv[i]);
    }

    // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    // 解析参数
    // 最关键的分支,通过设置 zygote 变量决定进程是 Zygote 还是普通应用!
    ++i;  // Skip unused "parent dir" argument.
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }

    Vector<String8> args;
    if (!className.isEmpty()) {
        // 非 Zygote 模式:启动普通应用
        
        // We're not in zygote mode, the only argument we need to pass
        // to RuntimeInit is the application argument.
        //
        // The Remainder of args get passed to startup class main(). Make
        // copies of them before we overwrite them with the process name.
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);

        if (!LOG_NDEBUG) {
          String8 restOfArgs;
          char* const* argv_new = argv + i;
          int argc_new = argc - i;
          for (int k = 0; k < argc_new; ++k) {
            restOfArgs.append(""");
            restOfArgs.append(argv_new[k]);
            restOfArgs.append("" ");
          }
          ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
        }
    } else {
         // Zygote 模式
        
        // We're in zygote mode.
        maybeCreateDalvikCache();

        if (startSystemServer) {
            args.add(String8("start-system-server"));
        }

        char prop[PROP_VALUE_MAX];
        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
            LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
                ABI_LIST_PROPERTY);
            return 11;
        }

        String8 abiFlag("--abi-list=");
        abiFlag.append(prop);
        args.add(abiFlag);

        // In zygote mode, pass all remaining arguments to the zygote
        // main() method.
        for (; i < argc; ++i) {
            args.add(String8(argv[i]));
        }
    }

    // 设置进程名,默认 static const char ZYGOTE_NICE_NAME[] = "zygote";
    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }

    // 启动 Java 层,准备起飞~
    // Java层入口为 ZygoteInit.main()
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

runtime 源码位置位于 frameworks/base/core/jni/AndroidRuntime.cpp这是 Android 原生(C++)代码的一部分,属于 JNI 框架层。

runtime.start 源码:

c++ 复制代码
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    // ...

    // ========================================================================
    // STEP 1: 初始化 JNI 调用环境(JniInvocation)
    // ========================================================================
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);  // 初始化 JNI 层调用框架(加载 libart.so 等)

    JNIEnv* env;
    // 调用 startVm() 实际启动 ART 虚拟机
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        ALOGE("startVm failed");
        return;
    }

    // 虚拟机创建成功后的回调
    onVmCreated(env);

    // ========================================================================
    // STEP 2: 注册所有系统级 JNI 方法
    // 如:android.os, android.app, android.content 等包下的 native 函数
    // ========================================================================
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
    // 示例:注册后,Java 层调用 android.os.SystemClock.uptimeMillis()
    //      才能正确跳转到 native 对应的 C++ 函数

    // ========================================================================
    // STEP 3: 构造 Java 层 main(String[] args) 所需的参数数组
    // ========================================================================
    jclass stringClass;
    jobjectArray strArray;  // 对应 String[]
    jstring classNameStr;   // 对应 className 参数

    // 查找 java.lang.String 类
    stringClass = env->FindClass("java/lang/String");
    assert(stringClass != NULL);

    // 创建 String 数组,长度 = 参数个数 + 1(+1 是主类名)
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    assert(strArray != NULL);

    // 第一个元素:主类名(如 com.android.internal.os.ZygoteInit)
    classNameStr = env->NewStringUTF(className);
    assert(classNameStr != NULL);
    env->SetObjectArrayElement(strArray, 0, classNameStr);

    // 后续元素:传入的 options 参数(如 start-system-server, --abi-list=...)
    for (size_t i = 0; i < options.size(); ++i) {
        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
        assert(optionsStr != NULL);
        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
    }

    // ========================================================================
    // STEP 4: 查找并调用 Java 主类的 main() 方法
    //           实现从 Native 到 Java 的"点火"
    // ========================================================================
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    // 将点号分隔类名转为斜杠分隔,如 com.example.App → com/example/App

    // 查找 Java 类
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
    } else {
        // 获取 main 方法的 Method ID
        // 签名:([Ljava/lang/String;)V → 接收 String[],返回 void
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
        } else {
            // 正式调用 Java 层 main 方法!
            // 控制权从此转移到 Java 层 🛫
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
            // !!!无限循环开始,后续代码不会被执行!!!
            // 程序"进入" Java 层,永不返回

            // 可选:检查是否有未捕获异常
#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }
    free(slashClassName);  // 释放转换后的类名字符串

    // ========================================================================
    // STEP 5: 收尾工作(正常情况下不会执行到这里)
    //           因为 main() 是无限循环,不会返回
    // ========================================================================
    ALOGD("Shutting down VM\n");

    // 尝试分离当前线程(主线程)
    if (mJavaVM->DetachCurrentThread() != JNI_OK)
        ALOGW("Warning: unable to detach main thread\n");

    // 销毁虚拟机(通常不会执行)
    if (mJavaVM->DestroyJavaVM() != 0)
        ALOGW("Warning: VM did not shut down cleanly\n");
}

虚拟机已经被启动,通过 JNI 调用 Java 代码,Java 代码就可以在虚拟机跑起来了,接下来完全进入 Java 代码内容,呜呜呜~,终于到能看懂的代码了

接下来就来到了 ZygoteInit.java,源码位置:

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

在线查看:android.googlesource.com/platform/fr...

入口函数 main() 源码分析:

c++ 复制代码
    @UnsupportedAppUsage
    public static void main(String[] argv) {
        ZygoteServer zygoteServer = null;

        // Mark zygote start. This ensures that thread creation will throw
        // an error.
        // 🔹 防止在 Zygote 初始化过程中创建线程
        //    因为 fork() 前不能有多余线程(否则会导致 fork 安全问题)
        //    调用此方法后,任何尝试创建线程的操作都会抛出异常
        ZygoteHooks.startZygoteNoThreadCreation();

        // Zygote goes into its own process group.
        try {
            Os.setpgid(0, 0);  // setpgid(pid, pgid): pid=0 表示当前进程
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to setpgid(0,0)", ex);
        }

        Runnable caller;
        try {
            // Store now for StatsLogging later.
            // 判断是否是"运行时重启"(如 system_server 崩溃后重启)
            // sys.boot_completed=1 表示系统已启动完成
            final long startTime = SystemClock.elapsedRealtime();
            final boolean isRuntimeRestarted = "1".equals(
                    SystemProperties.get("sys.boot_completed"));

            // 根据是 32 位还是 64 位 Zygote 选择不同的 trace tag
            String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
            TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
                    Trace.TRACE_TAG_DALVIK);
            bootTimingsTraceLog.traceBegin("ZygoteInit");
            RuntimeInit.preForkInit();

            // 解析启动参数
            boolean startSystemServer = false; // 是否启动 system_server
            String zygoteSocketName = "zygote"; // Zygote socket 名称
            String abiList = null; // 支持的 ABI 列表(如 arm,x86,arm64)
            boolean enableLazyPreload = false; // 是否延迟预加载

            // 🔹 解析命令行参数(来自 app_process 的启动参数)
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true; // 标记:需要 fork system_server
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = true;  // 延迟预加载(节省启动时间)
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }
            
            // 判断是否为主 Zygote(即 zygote 或 zygote64)
            final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
            if (!isRuntimeRestarted) {
                if (isPrimaryZygote) {
                    FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                            BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START,
                            startTime);
                } else if (zygoteSocketName.equals(Zygote.SECONDARY_SOCKET_NAME)) {
                    FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                            BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START,
                            startTime);
                }
            }

            // 必须提供 ABI 列表,否则无法知道支持哪些指令集
            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }

            // In some configurations, we avoid preloading resources and classes eagerly.
            // In such cases, we will preload things prior to our first fork.
            // 🔹 预加载核心资源(类、资源、共享库)
            //    如果未启用"延迟预加载",则在此处立即执行
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                        SystemClock.uptimeMillis());

                 // 执行预加载(核心优化:让所有应用共享这些已加载的类)
                preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                        SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            }

            // Do an initial gc to clean up after startup
            // 🔹 执行一次 GC,清理启动期间产生的垃圾对象
            //    因为 preload() 加载了大量类,可能产生临时对象
            bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
            gcAndFinalize();// 显式触发 GC 和 finalize
            bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC

            bootTimingsTraceLog.traceEnd(); // ZygoteInit

            // 🔹 初始化 native 层状态(如注册 fork hook、设置信号处理等)
            Zygote.initNativeState(isPrimaryZygote);

            // 🔹 允许线程创建(Zygote 初始化阶段结束)
            //    之前调用 startZygoteNoThreadCreation() 禁止了线程创建
            ZygoteHooks.stopZygoteNoThreadCreation();

            // 🔹 创建 ZygoteServer,用于监听 socket 连接
            //    它会监听来自 ActivityManagerService 的启动请求
            zygoteServer = new ZygoteServer(isPrimaryZygote);

            // 🔹 尝试 fork 出 system_server 进程(系统服务宿主)
            if (startSystemServer) {
                // forkSystemServer() 在父进程(Zygote)中返回 null
                // 在子进程(system_server)中返回一个 Runnable 任务
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                if (r != null) {
                    r.run();
                    return;// 子进程执行完后退出,不再继续下面的 select loop
                }
                 // 注意:父进程(Zygote)继续向下执行
            }

            Log.i(TAG, "Accepting command socket connections");

            // The select loop returns early in the child process after a fork and
            // loops forever in the zygote.
            // 🔹 进入无限循环,监听 socket
            //    - 在 Zygote 父进程中:永远循环,等待 fork 请求
            //    - 在 fork 出的子进程中:立即返回一个 Runnable 任务
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with fatal exception", ex);
            throw ex;
        } finally {
            // 异常清理:关闭 socket(正常流程不会执行到这里)
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket();
            }
        }

        // We're in the child process and have exited the select loop. Proceed to execute the
        // command.
        
        // 🔹 只有在子进程中才会执行到这里(caller != null)
        //    caller 是从 runSelectLoop() 返回的 Runnable 任务
        //    通常是启动某个应用进程的初始化逻辑
        if (caller != null) {
            caller.run();
        }
    }

ZygoteInit.main() 是 Android 的"生命之源"------它预加载万物,孵化系统,静候召唤,永不停歇。

这里有一点反直觉的代码,ZygoteInit.main() ****只被执行一次,而 这段代码却有两个分支,一个是子进程一个是父进程的:

scss 复制代码
            // 🔹 尝试 fork 出 system_server 进程(系统服务宿主)
            if (startSystemServer) {
                // forkSystemServer() 在父进程(Zygote)中返回 null
                // 在子进程(system_server)中返回一个 Runnable 任务
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                if (r != null) {
                    r.run();
                    return;// 子进程执行完后退出,不再继续下面的 select loop
                }
                 // 注意:父进程(Zygote)继续向下执行
            }

相当于 forkSystemServer 返回了两个值!一个为 null 一个不为 null,神不神奇,其实 forkSystemServer 仍只会返回一个值,开机的时候 系统服务一定会被创建,Zygote 更会被创建,代表着 forkSystemServer 之上的代码仍会被执行一次,forkSystemServer 及以下的代码会被执行两次。

why?神奇之处就在与 多进程,fork() 之后,这个方法的后续代码会被两个进程执行,举个例子,把 fork 当成克隆,想象科学家有一个"启动程序":

markdown 复制代码
1. 准备实验材料
2. 克隆一个自己(fork)
3. 如果我是克隆人(r != null):
     执行任务:去火星
     完成后死亡
4. 如果我是原版(r == null):
     继续在地球等待,准备下一次克隆

这就是Linux 的 fork() 行为,神奇所在:

在 C 语言里你可能见过这样的写法:

c 复制代码
pid_t pid = fork();
if (pid == 0) {
    // 子进程逻辑
} else if (pid > 0) {
    // 父进程逻辑
}

一次调用,两次返回!

这里最神奇的就是:

  • 只有 一次调用 fork() ,但它会在 父进程返回子进程 PID ,在 子进程返回 0
  • 所以,父子进程都会"继续执行 fork() 之后的代码",但执行路径不同。

zygote进程内加载了preload()方法中的所有资源,当需要fork新进程时,采用copy on write技术,如下:


完整流程图:

  1. 解析init.zygote.rc中的参数,创建AppRuntime并调用AppRuntime.start()方法;
  2. 调用AndroidRuntime的startVM()方法创建虚拟机,再调用startReg()注册JNI函数;
  3. 通过JNI方式调用ZygoteInit.main(),第一次进入Java世界;
  4. registerZygoteSocket()建立socket通道,zygote作为通信的服务端,用于响应客户端请求;
  5. preload()预加载通用类、drawable和color资源、openGL以及共享库以及WebView,用于提高ap启动效率;
  6. zygote完毕大部分工作,接下来再通过startSystemServer(),fork得力帮手system_server进程,也是上层framework的运行载体。
  7. zygote功成身退,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。
相关推荐
雨白29 分钟前
Android 自定义 View:精通文字的测量与高级排版
android
Jasonakeke1 小时前
【重学MySQL】八十八、8.0版本核心新特性全解析
android·数据库·mysql
一条上岸小咸鱼3 小时前
Kotlin 类型检查与转换
android·kotlin
闲暇部落3 小时前
android studio配置 build
android·android studio·build
龙之叶6 小时前
Android系统模块编译调试与Ninja使用指南
android
源码哥_博纳软云7 小时前
JAVA国际版多商户运营版商城系统源码多商户社交电商系统源码支持Android+IOS+H5
android·java·ios·微信·微信小程序·小程序·uni-app
用户2018792831677 小时前
bindService是如何完成binder传递的?
android
洞见不一样的自己7 小时前
Android 小知识点
android
tangweiguo030519879 小时前
Flutter性能优化完全指南:构建流畅应用的实用策略
android·flutter