引言
在上一篇文章中,我们见证了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新增:延迟预加载
lazilyLoadPreloadClasses();
}
// ========== 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进程的孵化机制和应用启动流程。
核心要点回顾:
-
Zygote的角色:
- 应用进程的"母体"
- 预加载中心
- SystemServer的父进程
-
fork+COW机制:
- fork()创建子进程
- COW共享内存,节省80%以上内存
- 写入时才复制单个页
-
预加载优化:
- 预加载6000个系统类
- 预加载系统资源
- 预加载共享库
- 所有应用进程共享(COW)
-
Socket循环:
- 监听/dev/socket/zygote
- 接收AMS的fork请求
- 执行fork并返回PID
-
进程优先级管理:
- OOM Adj决定进程优先级
- 前台应用adj=0,优先级最高
- 缓存进程adj=900,优先被杀
-
Android 15优化:
- 并行预加载(提升33%)
- 延迟预加载
- USAP Pool动态调整
参考资料
系列文章
本文基于Android 15 (API Level 35)源码分析,不同厂商的定制ROM可能存在差异。 欢迎来我中的个人主页找到更多有用的知识和有趣的产品