Zygote进程孵化与应用启动机制:从fork到SystemServer的完整旅程

引言

在上一篇文章中,我们见证了init进程如何"开天辟地",创建Android系统的基础环境。现在,让我们把目光投向Zygote ------这个名字在生物学中意为"受精卵",在Android中则是所有应用进程的"母体"

想象这样一个场景:你点击Launcher上的一个应用图标,短短几百毫秒后,应用界面就显示出来了。这背后发生了什么?

css 复制代码
你的点击
    ↓
Launcher通过Binder调用AMS
    ↓
AMS通知Zygote: "给我fork一个新进程!"
    ↓
Zygote执行fork()系统调用
    ↓
新进程诞生,继承Zygote的一切(代码、数据、虚拟机)
    ↓
新进程加载应用代码
    ↓
应用界面显示

这个"秒级启动"的魔法,核心就是Zygote的fork机制

📖 系列前置阅读:建议先阅读第12篇(init进程启动),理解Zygote如何被init启动。


Zygote是什么?

Zygote的三重身份

1. 应用孵化器

  • 所有应用进程都由Zygote fork出来
  • 每个应用进程都是Zygote的"克隆"(Copy-On-Write)

2. 预加载中心

  • 启动时预加载系统类(~6000个类)
  • 预加载系统资源(图标、字符串等)
  • 预加载共享库(WebView、OpenGL等)

3. SystemServer的父进程

  • SystemServer是Zygote fork的第一个子进程
  • SystemServer启动100+系统服务(AMS/WMS/PMS...)

Zygote vs 传统进程创建

传统Linux进程创建:

scss 复制代码
父进程调用fork()
    ↓
创建新进程(复制父进程的代码和数据)
    ↓
新进程调用execve()加载新程序
    ↓
程序从头开始执行

Zygote模式:

scss 复制代码
Zygote预先加载所有常用资源
    ↓
收到fork请求
    ↓
执行fork()(COW机制,不实际复制内存)
    ↓
新进程直接拥有ART虚拟机和预加载的类
    ↓
跳过虚拟机初始化,直接加载应用代码

性能对比:

方式 冷启动时间 内存占用
传统方式(每次初始化虚拟机) ~2000ms 高(每个进程独立)
Zygote fork(共享预加载内容) ~300ms 低(COW共享内存)
提升 85% ~60%

Zygote完整架构图

为了帮助理解Zygote的整体工作流程,下图展示了从Zygote启动到应用进程创建的完整架构:

图:Zygote完整架构,包含启动流程、预加载机制、SystemServer孵化、应用进程创建、COW内存共享和进程优先级管理

这张图涵盖了本文的核心内容:

  • 蓝色区域: Zygote从init启动的完整流程
  • 绿色区域: Zygote内部的预加载机制(~6000类,~430ms)
  • 橙色区域: SystemServer的孵化过程
  • 紫色区域: 应用进程创建的时序流程
  • 黄色区域: COW(Copy-On-Write)内存共享机制
  • 优先级表: OOM Adj从-900到900的进程管理

接下来,我们将逐一深入这些部分的源码实现。


Zygote启动流程

从init.rc到main()

回顾第12篇,init通过init.rc启动Zygote:

bash 复制代码
# /system/etc/init/init.zygote64_32.rc (64位设备)
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 restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    task_profiles ProcessCapacityHigh MaxPerformance
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

关键参数:

  • /system/bin/app_process64: Zygote的启动程序(C++)
  • -Xzygote: 告诉虚拟机以Zygote模式运行
  • --zygote: 启用Zygote功能
  • --start-system-server: 启动后fork SystemServer进程
  • socket zygote stream 660: 创建Socket,接收fork请求

Zygote入口:app_process

cpp 复制代码
// frameworks/base/cmds/app_process/app_main.cpp (Android 15)
int main(int argc, char* const argv[]) {
    // 解析命令行参数
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));

    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    // 解析--zygote和--start-system-server参数
    ++i;
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;  // "zygote" 或 "zygote64"
        } 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);
        }
        // ... 其他参数
    }

    if (zygote) {
        // ========== Zygote模式:启动ZygoteInit ==========
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (!className.isEmpty()) {
        // ========== 应用模式:启动指定类 ==========
        runtime.start(className.string(), args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        return 10;
    }
}

runtime.start()做了什么?

cpp 复制代码
// frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) {
    // ========== 1. 启动ART虚拟机 ==========
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }

    // ========== 2. 注册JNI方法 ==========
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

    // ========== 3. 将命令行参数转换为Java数组 ==========
    jclass stringClass = env->FindClass("java/lang/String");
    jobjectArray strArray = env->NewObjectArray(options.size(), stringClass, NULL);
    for (size_t i = 0; i < options.size(); i++) {
        jstring argStr = env->NewStringUTF(options[i].string());
        env->SetObjectArrayElement(strArray, i, argStr);
    }

    // ========== 4. 调用Java的main方法 ==========
    // className = "com.android.internal.os.ZygoteInit"
    jclass startClass = env->FindClass(slashClassName);
    jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V");

    // 调用 ZygoteInit.main(args)
    env->CallStaticVoidMethod(startClass, startMeth, strArray);

    // 虚拟机退出(正常情况下不会返回)
    if (mJavaVM->DetachCurrentThread() != JNI_OK) {
        ALOGW("Warning: unable to detach main thread\n");
    }
    mJavaVM->DestroyJavaVM();
}

ZygoteInit.main():预加载与Socket循环

Zygote的核心逻辑在ZygoteInit.java中:

java 复制代码
// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java (Android 15)
public static void main(String[] argv) {
    ZygoteServer zygoteServer = null;

    // 标记Zygote启动开始
    Zygote.initNativeState(isPrimaryZygote);
    ZygoteHooks.startZygoteNoThreadCreation();

    try {
        // ========== 1. 解析命令行参数 ==========
        boolean startSystemServer = false;
        String zygoteSocketName = "zygote";
        String abiList = null;
        boolean enableLazyPreload = false;

        for (int i = 1; i < argv.length; i++) {
            if ("start-system-server".equals(argv[i])) {
                startSystemServer = true;
            } 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());
            }
        }

        // ========== 2. 注册Zygote Socket ==========
        // 创建/dev/socket/zygote,监听fork请求
        zygoteServer = new ZygoteServer(isPrimaryZygote);

        if (startSystemServer) {
            // ========== 3. fork SystemServer进程 ==========
            Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
            if (r != null) {
                // 子进程(SystemServer)执行这里
                r.run();
                return;
            }
        }

        // ========== 4. 预加载资源(父进程Zygote继续) ==========
        if (!enableLazyPreload) {
            bootTimingsTraceLog.traceBegin("ZygotePreload");
            preload(bootTimingsTraceLog);  // ← 核心!
            bootTimingsTraceLog.traceEnd();
        } else {
            // Android 15新增:延迟预加载
            lazily​Load​Preload​Classes();
        }

        // ========== 5. GC并压缩堆 ==========
        // 预加载后执行GC,释放临时对象
        gcAndFinalize();
        Zygote.nativeZygoteFinishInit();

        // ========== 6. 进入Socket循环,等待fork请求 ==========
        Log.i(TAG, "Accepting command socket connections");
        zygoteServer.runSelectLoop(abiList);

        // 正常情况下不会执行到这里
        zygoteServer.closeServerSocket();
    } catch (Zygote.MethodAndArgsCaller caller) {
        // 新fork的子进程通过异常返回
        caller.run();
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with fatal exception", ex);
        throw ex;
    } finally {
        if (zygoteServer != null) {
            zygoteServer.closeServerSocket();
        }
    }
}

预加载机制:性能优化的关键

preload()完整流程

java 复制代码
// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
static void preload(TimingsTraceLog bootTimingsTraceLog) {
    // ========== 1. 预加载类(~6000个) ==========
    bootTimingsTraceLog.traceBegin("PreloadClasses");
    preloadClasses();  // 从/system/etc/preloaded-classes读取
    bootTimingsTraceLog.traceEnd();

    // ========== 2. 预加载资源 ==========
    bootTimingsTraceLog.traceBegin("PreloadResources");
    preloadResources();  // 加载framework-res.apk中的资源
    bootTimingsTraceLog.traceEnd();

    // ========== 3. 预加载共享库 ==========
    bootTimingsTraceLog.traceBegin("PreloadAppProcessHALs");
    nativePreloadAppProcessHALs();  // 预加载图形/音频HAL
    bootTimingsTraceLog.traceEnd();

    // ========== 4. 预加载OpenGL ==========
    bootTimingsTraceLog.traceBegin("PreloadOpenGL");
    preloadOpenGL();
    bootTimingsTraceLog.traceEnd();

    // ========== 5. 预加载共享库(libandroid.so等) ==========
    preloadSharedLibraries();

    // ========== 6. 预加载文本资源 ==========
    preloadTextResources();

    // ========== 7. 预加载WebView(如果需要) ==========
    WebViewFactory.prepareWebViewInZygote();
}

预加载类列表

/system/etc/preloaded-classes文件包含需要预加载的类:

lua 复制代码
# Android 15预加载类列表(部分)
android.app.Activity
android.app.Application
android.app.Service
android.content.Context
android.content.ContentProvider
android.content.Intent
android.os.Bundle
android.os.Handler
android.os.Looper
android.os.Message
android.view.View
android.view.ViewGroup
android.widget.TextView
android.widget.Button
android.widget.ImageView
# ... 约6000个类

如何生成这个列表?

bash 复制代码
# Android编译时,通过分析应用启动日志生成
# frameworks/base/tools/preload/WritePreloadedClassFile.java

# 手动重新生成(需要root权限)
adb shell am start-activity some.test.app
adb shell cat /data/dalvik-cache/profiles/preloaded-classes > preloaded-classes.txt

预加载耗时分析

阶段 耗时(ms) 占比
PreloadClasses ~1800 60%
PreloadResources ~600 20%
PreloadOpenGL ~300 10%
PreloadSharedLibraries ~200 7%
其他 ~100 3%
总计 ~3000 100%

Android 15优化:

  • 延迟预加载(--enable-lazy-preload):非热路径类延后加载
  • 并行预加载:利用多核CPU并行加载类
  • 预加载裁剪:移除不常用的类(减少5%)

fork SystemServer:系统服务的诞生

forkSystemServer()源码分析

java 复制代码
// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
private static Runnable forkSystemServer(String abiList, String socketName,
        ZygoteServer zygoteServer) {
    // ========== 1. 准备SystemServer的启动参数 ==========
    String[] args = {
        "--setuid=1000",              // UID = system (1000)
        "--setgid=1000",              // GID = system (1000)
        "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
            + "1024,1032,1065,3001,3002,3003,3005,3006,3007,3009,3010,3011,3012",
        "--capabilities=" + capabilities + "," + capabilities,
        "--nice-name=system_server",  // 进程名
        "--runtime-args",
        "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
        "com.android.server.SystemServer",  // ← 启动类
    };

    int pid;
    try {
        // ========== 2. fork子进程 ==========
        ZygoteArguments parsedArgs = new ZygoteArguments(args);
        Zygote.applyDebuggerSystemProperty(parsedArgs);
        Zygote.applyInvokeWithSystemProperty(parsedArgs);

        // 检查是否支持USAP(Unspecialized App Process)
        if (shouldProfileSystemServer()) {
            parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
        }

        // ========== 核心:调用fork() ==========
        pid = Zygote.forkSystemServer(
                parsedArgs.mUid,          // 1000
                parsedArgs.mGid,          // 1000
                parsedArgs.mGids,         // 附加组
                parsedArgs.mRuntimeFlags,
                null,
                parsedArgs.mPermittedCapabilities,
                parsedArgs.mEffectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    // ========== 3. 父子进程分道扬镳 ==========
    if (pid == 0) {
        // ========== 子进程(SystemServer) ==========
        if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }

        // 关闭从父进程继承的Socket
        zygoteServer.closeServerSocket();

        // 返回Runnable,执行SystemServer.main()
        return handleSystemServerProcess(parsedArgs);
    }

    // ========== 父进程(Zygote)继续 ==========
    return null;
}

Zygote.forkSystemServer() Native实现

cpp 复制代码
// frameworks/base/core/jni/com_android_internal_os_Zygote.cpp (Android 15)
static jint com_android_internal_os_Zygote_forkSystemServer(
        JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
        jint runtime_flags, jobjectArray rlimits,
        jlong permitted_capabilities, jlong effective_capabilities) {

    // ========== 1. fork前的准备 ==========
    // 调用dalvik.system.ZygoteHooks.preFork()
    // 停止4个Daemon线程:
    // - HeapTaskDaemon: GC线程
    // - ReferenceQueueDaemon: 引用队列处理
    // - FinalizerDaemon: finalizer处理
    // - FinalizerWatchdogDaemon: finalizer超时监控
    if (!ZygoteHooks_nativePreFork(env)) {
        RuntimeAbort(env, __LINE__, "Native pre-fork failed");
    }

    // ========== 2. 执行fork()系统调用 ==========
    pid_t pid = fork();

    if (pid == 0) {
        // ========== 子进程(SystemServer) ==========

        // 设置进程名称
        if (prctl(PR_SET_NAME, (unsigned long) "system_server", 0, 0, 0) != 0) {
            ALOGE("prctl(PR_SET_NAME) failed: %s", strerror(errno));
        }

        // 设置UID/GID
        if (setresgid(gid, gid, gid) == -1) {
            ALOGE("setresgid(%d) failed: %s", gid, strerror(errno));
            RuntimeAbort(env, __LINE__, "setresgid failed");
        }
        if (setresuid(uid, uid, uid) == -1) {
            ALOGE("setresuid(%d) failed: %s", uid, strerror(errno));
            RuntimeAbort(env, __LINE__, "setresuid failed");
        }

        // 设置附加组
        if (gids != nullptr && gids->GetLength() > 0) {
            jsize size = gids->GetLength();
            std::unique_ptr<gid_t[]> gid_array(new gid_t[size]);
            for (int i = 0; i < size; i++) {
                gid_array[i] = gids->GetElements()[i];
            }
            if (setgroups(size, gid_array.get()) == -1) {
                ALOGE("setgroups failed: %s", strerror(errno));
                RuntimeAbort(env, __LINE__, "setgroups failed");
            }
        }

        // 设置Capabilities(特权能力)
        if (effective_capabilities != 0) {
            SetCapabilities(effective_capabilities, permitted_capabilities, permitted_capabilities);
        }

        // 设置SELinux上下文
        if (selinux_android_setcontext(uid, false, NULL, NULL) == -1) {
            ALOGE("selinux_android_setcontext failed");
            RuntimeAbort(env, __LINE__, "selinux_android_setcontext failed");
        }

        // 设置调度器策略和优先级
        if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_SYSTEM_SERVER) != 0) {
            ALOGE("setpriority failed: %s", strerror(errno));
        }

        // 恢复默认信号处理器(从Zygote继承的信号处理器可能不适用)
        UnsetChldSignalHandler();
    } else if (pid > 0) {
        // ========== 父进程(Zygote) ==========
        // 记录SystemServer的PID
        gSystemServerPid = pid;
    }

    // ========== 3. fork后的清理工作 ==========
    // 调用dalvik.system.ZygoteHooks.postForkCommon()
    // 恢复4个Daemon线程
    ZygoteHooks_nativePostForkCommon(env, pid == 0 /* is_child */);

    return pid;
}

COW(Copy-On-Write)机制详解

什么是COW?

Copy-On-Write(写时复制)是Linux内核的一种内存优化技术:

ini 复制代码
父进程内存布局:
┌────────────────────────────┐
│  代码段 (Text Segment)     │ ← 只读,可共享
│  [ART虚拟机代码]           │
├────────────────────────────┤
│  数据段 (Data Segment)     │ ← COW共享
│  [预加载的类和资源]        │
├────────────────────────────┤
│  堆 (Heap)                 │ ← COW共享
│  [对象实例]                │
├────────────────────────────┤
│  栈 (Stack)                │ ← 不共享(每个进程独立)
└────────────────────────────┘

fork()后:
┌──────────────────┐        ┌──────────────────┐
│  父进程(Zygote)  │        │  子进程(App)     │
├──────────────────┤        ├──────────────────┤
│  代码段          │◄───────┤  代码段(共享)    │
│  [指向同一物理内存]        [页表指向父进程]  │
├──────────────────┤        ├──────────────────┤
│  数据段          │◄───────┤  数据段(COW)     │
│  [设置只读标志]  │        [设置只读标志]    │
└──────────────────┘        └──────────────────┘

当子进程写入数据段时:
1. 触发Page Fault(页错误)
2. 内核复制该页到新的物理页
3. 更新子进程的页表,指向新页
4. 设置为可写

COW的优势:

perl 复制代码
传统fork(全量复制):
  父进程内存: 200MB
      ↓ fork()
  复制200MB到子进程
  总内存: 400MB
  耗时: ~200ms

COW fork:
  父进程内存: 200MB
      ↓ fork()
  只复制页表(~1MB)
  总内存: 201MB (共享199MB)
  耗时: ~5ms
  写入时才复制单个页(通常<1%)

Android中的COW优化

Zygote预加载的资源都是只读的,因此可以被所有应用进程共享:

java 复制代码
// 示例:Activity类在Zygote中预加载
// frameworks/base/core/java/android/app/Activity.java

// 所有应用进程共享这个类的代码和常量
public class Activity extends ContextThemeWrapper {
    private static final String TAG = "Activity";  // ← 共享
    private static final boolean DEBUG = false;    // ← 共享

    // 实例变量在每个进程中独立
    private Application mApplication;  // ← 各进程独立
    private Intent mIntent;            // ← 各进程独立
}

内存占用对比:

场景 传统方式 Zygote COW 节省
10个应用进程 10 × 200MB = 2GB 200MB + 10 × 20MB = 400MB 80%
50个应用进程 50 × 200MB = 10GB 200MB + 50 × 20MB = 1.2GB 88%

Socket循环:接收fork请求

ZygoteServer.runSelectLoop()

java 复制代码
// frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
Runnable runSelectLoop(String abiList) {
    ArrayList<FileDescriptor> socketFDs = new ArrayList<>();
    ArrayList<ZygoteConnection> peers = new ArrayList<>();

    // 添加Zygote主Socket
    socketFDs.add(mZygoteSocket.getFileDescriptor());
    peers.add(null);

    // 添加USAP Pool Socket(Android 10+)
    socketFDs.add(mUsapPoolSocket.getFileDescriptor());
    peers.add(null);

    // ========== 无限循环,等待连接 ==========
    while (true) {
        // 从StructPollfd数组中移除失效的连接
        int[] usapPipeFDs = Zygote.getUsapPipeFDs();
        StructPollfd[] pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length];

        // 设置pollFDs
        int pollIndex = 0;
        for (FileDescriptor socketFD : socketFDs) {
            pollFDs[pollIndex] = new StructPollfd();
            pollFDs[pollIndex].fd = socketFD;
            pollFDs[pollIndex].events = (short) POLLIN;
            ++pollIndex;
        }

        int pollTimeoutMs;
        if (mUsapPoolEnabled) {
            pollTimeoutMs = -1;  // 阻塞等待
        } else {
            pollTimeoutMs = ZYGOTE_IDLE_TIMEOUT_MS;
        }

        // ========== 阻塞等待事件 ==========
        int pollReturnValue;
        try {
            pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
        } catch (ErrnoException ex) {
            throw new RuntimeException("poll failed", ex);
        }

        // ========== 处理事件 ==========
        boolean usapPoolFDRead = false;
        while (--pollIndex >= 0) {
            if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
                continue;  // 没有输入事件
            }

            if (pollIndex == 0) {
                // ========== Zygote主Socket有新连接 ==========
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                socketFDs.add(newPeer.getFileDescriptor());
            } else if (pollIndex == 1) {
                // ========== USAP Pool Socket事件 ==========
                Runnable command = handleUsapPoolStatusChange(usapPoolEventFD);
                if (command != null) {
                    return command;
                }
                usapPoolFDRead = true;
            } else {
                // ========== 处理来自AMS的fork请求 ==========
                try {
                    ZygoteConnection connection = peers.get(pollIndex);
                    boolean multipleForksOK = !isUsapPoolEnabled() && ZygoteHooks.isIndefiniteThreadSuspensionSafe();

                    // ========== 核心:处理fork命令 ==========
                    final Runnable command = connection.processCommand(this, multipleForksOK);

                    if (command == null) {
                        // 连接关闭
                        peers.remove(pollIndex);
                        socketFDs.remove(pollIndex);
                    } else {
                        // ========== fork成功,子进程返回Runnable ==========
                        // 关闭所有连接
                        for (ZygoteConnection conn : peers) {
                            conn.close();
                        }
                        // 执行应用的main方法
                        return command;
                    }
                } catch (Exception e) {
                    // 异常处理
                    peers.remove(pollIndex);
                    socketFDs.remove(pollIndex);
                }
            }
        }

        // 填充USAP Pool
        if (usapPoolFDRead) {
            fillUsapPool();
        }
    }
}

processCommand():执行fork

java 复制代码
// frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
    // ========== 1. 读取fork参数 ==========
    ZygoteArguments parsedArgs;
    try {
        parsedArgs = ZygoteArguments.getInstance(mSocketReader);
    } catch (IOException ex) {
        throw new IllegalStateException("IOException on command socket", ex);
    }

    // ========== 2. 执行fork ==========
    int pid;
    FileDescriptor childPipeFd = null;
    FileDescriptor serverPipeFd = null;

    try {
        // 核心:调用Zygote.forkAndSpecialize()
        pid = Zygote.forkAndSpecialize(
                parsedArgs.mUid,
                parsedArgs.mGid,
                parsedArgs.mGids,
                parsedArgs.mRuntimeFlags,
                rlimits,
                parsedArgs.mMountExternal,
                parsedArgs.mSeInfo,
                parsedArgs.mNiceName,
                fdsToClose,
                fdsToIgnore,
                parsedArgs.mStartChildZygote,
                parsedArgs.mInstructionSet,
                parsedArgs.mAppDataDir,
                parsedArgs.mIsTopApp,
                parsedArgs.mPkgDataInfoList,
                parsedArgs.mAllowlistedDataInfoList,
                parsedArgs.mBindMountAppDataDirs,
                parsedArgs.mBindMountAppStorageDirs);

        if (pid == 0) {
            // ========== 子进程(新应用) ==========
            zygoteServer.setForkChild();
            zygoteServer.closeServerSocket();

            // 返回Runnable,执行ActivityThread.main()
            return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
        } else {
            // ========== 父进程(Zygote)继续 ==========
            childPipeFd = null;
            handleParentProc(pid, serverPipeFd);
            return null;
        }
    } finally {
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

应用进程创建完整流程

从Launcher点击到应用启动

时间分布:

阶段 耗时(ms) 说明
1-4: Launcher→ATMS ~50 Binder IPC开销
5: 连接Zygote ~5 Socket连接
6: fork()系统调用 ~5 COW机制,很快
7: 子进程初始化 ~20 设置UID/SELinux
8-10: Application初始化 ~200 加载APK,创建Application
11: Activity启动 ~100 onCreate/onStart/onResume
12: 首帧渲染 ~50 布局、绘制、显示
总计 ~430ms

进程优先级(adj)管理

OOM Adj:决定进程生死

OOM Adj(Out-Of-Memory Adjustment)是Android的进程优先级分数:

复制代码
分数越低,优先级越高,越不容易被杀死
分数越高,优先级越低,内存不足时优先杀死

核心adj值:

adj值 名称 说明 示例
-1000 NATIVE 系统Native进程 init, servicemanager
-900 SYSTEM SystemServer system_server
-800 PERSISTENT 持久化系统应用 Phone, Settings
0 FOREGROUND 前台Activity 用户正在使用的应用
100 VISIBLE 可见但非前台 后台可见的Activity
200 PERCEPTIBLE 可感知(音乐播放等) 音乐播放器
250 BACKUP 备份进程 BackupAgent
300 SERVICE 服务进程 后台Service
400 HOME Launcher 桌面应用
500 PREVIOUS 上一个Activity 最近使用的应用
600 SERVICE_B 较旧的Service 长时间未交互的Service
700 CACHED_EMPTY 空缓存进程 已退出但缓存的进程
900 CACHED 缓存进程 历史应用

adj更新时机

java 复制代码
// frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java
// (Android 15)

// 触发adj更新的场景:
1. Activity生命周期变化(启动/销毁/暂停/恢复)
2. Service启动/停止/绑定/解绑
3. ContentProvider被访问
4. 广播接收器执行
5. 进程启动/退出
6. 内存压力变化

updateOomAdj()核心逻辑:

java 复制代码
boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
        ProcessRecord TOP_APP, long now) {

    if (app.thread == null) {
        return false;  // 进程已死亡
    }

    final int prevAdj = app.curAdj;
    int adj = UNKNOWN_ADJ;

    // ========== 1. 计算进程adj ==========
    if (app == TOP_APP) {
        // 前台应用
        adj = FOREGROUND_APP_ADJ;
        app.adjType = "top-activity";
    } else if (app.runningRemoteAnimation) {
        // 正在运行动画
        adj = VISIBLE_APP_ADJ;
        app.adjType = "running-remote-anim";
    } else if (app.hasTopUi) {
        // 有顶层UI(如悬浮窗)
        adj = PERCEPTIBLE_APP_ADJ;
        app.adjType = "top-ui";
    } else if (app.hasOverlayUi) {
        // 有Overlay UI
        adj = PERCEPTIBLE_APP_ADJ;
        app.adjType = "overlay-ui";
    } else if (app.getCachedHasActivities()) {
        // 有缓存的Activity
        adj = computeOomAdjForActivitiesLocked(app, adj);
    } else if (app.getCachedIsHeavyWeight()) {
        // 重量级进程(如浏览器)
        adj = HEAVY_WEIGHT_APP_ADJ;
        app.adjType = "heavy";
    } else if (app.getCachedIsHomeProcess()) {
        // Launcher进程
        adj = HOME_APP_ADJ;
        app.adjType = "home";
    }

    // ========== 2. 考虑Service和ContentProvider ==========
    adj = Math.min(adj, computeOomAdjForServices(app));
    adj = Math.min(adj, computeOomAdjForProviders(app));

    // ========== 3. 设置adj ==========
    if (adj != prevAdj) {
        setOomAdj(app.pid, app.uid, adj);
        app.curAdj = adj;
    }

    return true;
}

LMK(Low Memory Killer)

当系统内存不足时,LMK会根据adj值杀死进程:

makefile 复制代码
内存压力等级:
┌────────────────────────────────────┐
│  Critical (临界)                   │ ← 杀死adj >= 900的进程
│  - 可用内存 < 50MB                 │
├────────────────────────────────────┤
│  Moderate (中等)                   │ ← 杀死adj >= 700的进程
│  - 可用内存 < 100MB                │
├────────────────────────────────────┤
│  Low (较低)                        │ ← 杀死adj >= 600的进程
│  - 可用内存 < 200MB                │
├────────────────────────────────────┤
│  Medium (一般)                     │ ← 不杀进程
│  - 可用内存 < 300MB                │
├────────────────────────────────────┤
│  Normal (正常)                     │ ← 不杀进程
│  - 可用内存 >= 300MB               │
└────────────────────────────────────┘

LMK触发流程:

bash 复制代码
# 1. 内核检测到内存压力
# 2. 触发lmkd守护进程
# 3. lmkd读取/proc/meminfo,计算可用内存
# 4. 根据内存压力等级,选择要杀死的进程
# 5. 发送SIGKILL信号杀死进程
# 6. 内核回收进程内存

# 查看lmkd日志
adb logcat -s lmkd

# 输出示例:
# lmkd: memory pressure event: MEDIUM
# lmkd: killing 'com.example.app' (12345), adj 900, to free 150MB

常见问题与解答

Q1: Zygote为什么不使用线程池而是fork?

A : 主要原因是安全性和隔离性

markdown 复制代码
线程池模式(假设):
  Zygote
    ├─ 线程1 → 运行App A
    ├─ 线程2 → 运行App B
    └─ 线程3 → 运行App C

问题:
  1. 同一进程空间,App可能互相干扰
  2. 一个App崩溃可能导致Zygote崩溃
  3. 无法实现UID/GID隔离
  4. 无法使用SELinux沙箱

fork模式:
  Zygote
    ├─ fork → App A进程(独立空间)
    ├─ fork → App B进程(独立空间)
    └─ fork → App C进程(独立空间)

优势:
  1. 完全隔离,互不干扰
  2. 一个App崩溃不影响其他App
  3. 每个App有独立的UID/GID
  4. 每个App有独立的SELinux上下文

Q2: 为什么预加载的类要在fork之前完成?

A : 为了最大化COW共享

markdown 复制代码
正确顺序(当前实现):
  1. Zygote启动
  2. 预加载6000个类 → 占用200MB内存
  3. fork App A → 共享200MB(COW)
  4. fork App B → 共享200MB(COW)
  5. fork App C → 共享200MB(COW)
  总内存: 200MB + 3×20MB = 260MB

错误顺序(如果fork后预加载):
  1. Zygote启动
  2. fork App A
  3. App A预加载6000个类 → 占用200MB
  4. fork App B
  5. App B预加载6000个类 → 占用200MB
  6. fork App C
  7. App C预加载6000个类 → 占用200MB
  总内存: 3×200MB = 600MB (无法共享!)

Q3: USAP Pool是什么?

A : USAP(Unspecialized App Process)是Android 10引入的优化技术。

perl 复制代码
传统模式:
  AMS请求fork → Zygote执行fork() → 返回PID
  耗时: ~50ms

USAP Pool模式:
  Zygote预先fork一批"空白进程"(USAP)
    ↓
  USAP进程等待专用化(specialize)
    ↓
  AMS请求进程 → 从Pool中取一个USAP
    ↓
  USAP专用化(设置UID/包名/SELinux)
    ↓
  返回PID
  耗时: ~10ms

性能提升: 80%

Pool大小:

java 复制代码
// frameworks/base/core/java/com/android/internal/os/Zygote.java
private static final int USAP_POOL_SIZE_MIN = 1;
private static final int USAP_POOL_SIZE_MAX = 3;

// 动态调整:
// - 应用启动频繁时,Pool增大到MAX
// - 空闲时,Pool缩小到MIN

Q4: 应用启动的"冷启动"和"热启动"有什么区别?

A : 主要区别在于进程是否存在

冷启动(Cold Start):

scss 复制代码
进程不存在
  ↓
需要fork新进程
  ↓
Application.onCreate()
  ↓
Activity.onCreate/onStart/onResume()
  ↓
首帧渲染
总耗时: ~430ms

热启动(Warm Start):

scss 复制代码
进程已存在(在后台)
  ↓
Activity已创建(在后台栈)
  ↓
Activity.onRestart/onStart/onResume()
  ↓
重新渲染
总耗时: ~150ms

温启动(Lukewarm Start):

bash 复制代码
进程存在,但Activity被销毁
  ↓
Activity.onCreate/onStart/onResume()
  ↓
首帧渲染
总耗时: ~300ms

Q5: 如何优化应用启动速度?

A: 多方面优化:

1. 减少Application.onCreate()耗时:

java 复制代码
// ❌ 错误:在主线程执行耗时操作
public void onCreate() {
    super.onCreate();
    initDatabase();      // 500ms
    loadConfig();        // 200ms
    initSDK();          // 300ms
    // 总计1000ms阻塞主线程!
}

// ✅ 正确:异步初始化
public void onCreate() {
    super.onCreate();
    Executors.newSingleThreadExecutor().execute(() -> {
        initDatabase();
        loadConfig();
        initSDK();
    });
    // 主线程立即返回
}

2. 延迟初始化非关键组件:

java 复制代码
// 仅初始化首屏必需的组件
// 其他组件在后台懒加载

3. 使用启动窗口(Splash Screen):

xml 复制代码
<!-- 给用户即时反馈,掩盖启动延迟 -->
<style name="AppTheme" parent="Theme.AppCompat.Light">
    <item name="android:windowBackground">@drawable/splash_background</item>
</style>

4. 避免在Activity.onCreate()中执行耗时操作:

kotlin 复制代码
// 使用ViewModel和LiveData异步加载数据

Android 15优化

1. 并行预加载

java 复制代码
// Android 15使用多线程并行预加载类
ExecutorService preloadExecutor = Executors.newFixedThreadPool(4);

for (String className : preloadClasses) {
    preloadExecutor.submit(() -> {
        Class.forName(className);
    });
}

preloadExecutor.shutdown();
preloadExecutor.awaitTermination(30, TimeUnit.SECONDS);

效果: 预加载时间从1800ms减少到1200ms(提升33%)

2. 延迟预加载(Lazy Preload)

java 复制代码
// 不常用的类延后加载
if (enableLazyPreload) {
    // 只预加载热路径类(前1000个)
    preloadClasses(hotPathClasses);

    // 冷路径类在后台加载
    new Thread(() -> {
        preloadClasses(coldPathClasses);
    }).start();
}

3. USAP Pool动态调整

java 复制代码
// 根据应用启动频率动态调整Pool大小
if (recentLaunchCount > THRESHOLD_HIGH) {
    usapPoolSize = USAP_POOL_SIZE_MAX;  // 3
} else if (recentLaunchCount > THRESHOLD_LOW) {
    usapPoolSize = USAP_POOL_SIZE_MID;  // 2
} else {
    usapPoolSize = USAP_POOL_SIZE_MIN;  // 1
}

总结

本文深入分析了Zygote进程的孵化机制和应用启动流程。

核心要点回顾:

  1. Zygote的角色:

    • 应用进程的"母体"
    • 预加载中心
    • SystemServer的父进程
  2. fork+COW机制:

    • fork()创建子进程
    • COW共享内存,节省80%以上内存
    • 写入时才复制单个页
  3. 预加载优化:

    • 预加载6000个系统类
    • 预加载系统资源
    • 预加载共享库
    • 所有应用进程共享(COW)
  4. Socket循环:

    • 监听/dev/socket/zygote
    • 接收AMS的fork请求
    • 执行fork并返回PID
  5. 进程优先级管理:

    • OOM Adj决定进程优先级
    • 前台应用adj=0,优先级最高
    • 缓存进程adj=900,优先被杀
  6. Android 15优化:

    • 并行预加载(提升33%)
    • 延迟预加载
    • USAP Pool动态调整

参考资料

系列文章


本文基于Android 15 (API Level 35)源码分析,不同厂商的定制ROM可能存在差异。 欢迎来我中的个人主页找到更多有用的知识和有趣的产品

相关推荐
雨白13 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk13 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
LING13 小时前
RN容器启动优化实践
android·react native
恋猫de小郭16 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker21 小时前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴21 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭1 天前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab1 天前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe2 天前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农2 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos