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可能存在差异。 欢迎来我中的个人主页找到更多有用的知识和有趣的产品

相关推荐
姜行运3 小时前
【Linux】基础指令2
android·linux·服务器
大模型玩家七七4 小时前
技术抉择:微调还是 RAG?——以春节祝福生成为例
android·java·大数据·开发语言·人工智能·算法·安全
低调小一5 小时前
Fresco 图片加载全链路解析:从 SimpleDraweeView 到 Producer 责任链
android·开发语言·fresco
Asmewill5 小时前
Kotlin高阶函数
android
我命由我123456 小时前
Android Studio - 在 Android Studio 中直观查看 Git 代码的更改
android·java·开发语言·git·java-ee·android studio·android jetpack
hewence16 小时前
Kotlin协程启动方式详解
android·开发语言·kotlin
城东米粉儿6 小时前
Android EventHub的Epoll原理 笔记
android
城东米粉儿6 小时前
Android音频系统 笔记
android
半切西瓜7 小时前
Android Studio 创建应用自动指定SDK目录
android·ide·android studio