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(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。
相关推荐
CYRUS_STUDIO9 分钟前
利用 Linux 信号机制(SIGTRAP)实现 Android 下的反调试
android·安全·逆向
CYRUS_STUDIO28 分钟前
Android 反调试攻防实战:多重检测手段解析与内核级绕过方案
android·操作系统·逆向
黄林晴4 小时前
如何判断手机是否是纯血鸿蒙系统
android
火柴就是我4 小时前
flutter 之真手势冲突处理
android·flutter
法的空间5 小时前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
循环不息优化不止5 小时前
深入解析安卓 Handle 机制
android
恋猫de小郭5 小时前
Android 将强制应用使用主题图标,你怎么看?
android·前端·flutter
jctech5 小时前
这才是2025年的插件化!ComboLite 2.0:为Compose开发者带来极致“爽”感
android·开源
用户2018792831675 小时前
为何Handler的postDelayed不适合精准定时任务?
android
叽哥5 小时前
Kotlin学习第 8 课:Kotlin 进阶特性:简化代码与提升效率
android·java·kotlin