前言
Activity 启动过程文章系列会按阶段拆开分析。上一篇已经停在 startProcessAsync() 把请求交给进程启动链;本文只聚焦 应用程序进程启动阶段:system_server 如何把启动请求转成一组 Zygote 参数,Zygote 如何接收这些参数并 fork 出新的应用进程。
启动流程梳理:
- Activity 启动流程(一)—— Launcher 阶段
- Activity 启动流程(二)—— AMS 处理阶段
- Activity 启动流程(三)—— 应用程序进程启动阶段
- Activity 启动流程(四)—— ActivityThread 初始化阶段
- Activity 启动流程(五)—— Activity 启动阶段
代码基于 android-14.0.0_r9。
本文只讲 “进程怎么被创建出来”。
1. 一句话总览
这一阶段的核心是:AMS 接到 ATMS 转来的进程启动请求后,先在 system_server 内准备 ProcessRecord 和启动参数,再通过 Process.start() → ZygoteProcess 把参数发给 Zygote;Zygote 收到请求后执行 forkAndSpecialize() 创建子进程,并把新 pid 返回给 system_server。
主链路如下:
ActivityManagerInternal.startProcess()→ActivityManagerService.startProcess()→ActivityManagerService.startProcessLocked()→ProcessList.startProcessLocked()→Process.start()→ZygoteProcess.start()→startViaZygote()→zygoteSendArgsAndGetResult()→ZygoteServer.runSelectLoop()→ZygoteConnection.processCommand()→Zygote.forkAndSpecialize()→ProcessStartResult
flowchart LR
A[ActivityManagerInternal.startProcess]
B[AMS.startProcess]
C[ProcessList.startProcessLocked]
D[Process.start]
E[ZygoteProcess.startViaZygote]
F[Socket 发送启动参数]
G[ZygoteServer.runSelectLoop]
H[ZygoteConnection.processCommand]
I[forkAndSpecialize]
J[返回 ProcessStartResult / pid]
A --> B --> C --> D --> E --> F --> G --> H --> I --> J
这条链路里,system_server 负责“组织启动请求”,Zygote 负责“真正 fork 进程”。当 Zygote 将 ProcessStartResult / pid 通过 ZygoteProcess 回传后,本文这一阶段就结束了。
2. 应用程序进程启动阶段源码分析
2.1 请求落到 AMS:本地服务把进程启动交给 ActivityManagerService
上一篇最后停在 ActivityManagerInternal.startProcess(...) 这条本地服务边界。它在 AMS 里的实现如下:
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead,
boolean isTop, String hostingType, ComponentName hostingName) {
try {
synchronized (ActivityManagerService.this) {
HostingRecord hostingRecord =
new HostingRecord(hostingType, hostingName, isTop);
ProcessRecord rec = getProcessRecordLocked(processName, info.uid);
ProcessRecord app = startProcessLocked(processName, info, knownToBeDead,
0 /* intentFlags */, hostingRecord,
ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,
false /* isolated */);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
这里做的事情并不复杂,但职责很明确:
- 接住 ATMS 交来的启动请求。
- 构造
HostingRecord,把“这次进程为什么被拉起”保存下来。 - 进入
startProcessLocked(),正式切到 AMS 的进程管理链路。
也就是说,从这一刻起,问题已经不再是“这个 Activity 该不该启动”,而是“承载它的应用进程怎么创建出来”。
2.2 system_server 侧准备:ProcessList 组装启动参数并选择入口类
AMS 自身的 startProcessLocked() 只是转发到 ProcessList:
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
boolean isolated) {
return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
false /* isSdkSandbox */, 0 /* sdkSandboxClientAppUid */,
null /* sdkSandboxClientAppPackage */,
null /* ABI override */, null /* entryPoint */,
null /* entryPointArgs */, null /* crashHandler */);
}
真正准备进程参数的地方在 ProcessList.startProcessLocked():
// frameworks/base/services/core/java/com/android/server/am/ProcessList.java
boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks,
String abiOverride) {
...
int uid = app.uid;
int[] gids = null;
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
boolean externalStorageAccess = false;
if (!app.isolated) {
...
gids = computeGidsForProcess(mountExternal, uid, permGids, externalStorageAccess);
}
...
final String entryPoint = "android.app.ActivityThread";
return startProcessLocked(hostingRecord, entryPoint, app, uid, gids,
runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi,
instructionSet, invokeWith, startTime);
}
这里最重要的不是每个参数的细枝末节,而是它说明了两件事:
- system_server 会先把 UID / GID / 挂载模式 / ABI / 运行时标志 / SELinux 信息 这些参数准备好;
- 新进程的 Java 入口类已经确定为
android.app.ActivityThread。
这意味着,到 ProcessList 这一层为止,AMS 已经把“要启动哪个进程、用什么身份启动、启动后先跑哪个入口”都确定下来了。下一步才是把这些信息发给 Zygote。
2.3 发给 Zygote:Process.start 只是桥接,真正通信由 ZygoteProcess 完成
ProcessList 继续调用 startProcess(...),最终落到 Process.start():
// frameworks/base/services/core/java/com/android/server/am/ProcessList.java
private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags,
int mountExternal, String seInfo, String requiredAbi, String instructionSet,
String invokeWith, long startTime) {
...
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,
isTopApp, app.getDisabledCompatChanges(), pkgDataInfoMap,
allowlistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
...
}
// frameworks/base/core/java/android/os/Process.java
public static ProcessStartResult start(@NonNull final String processClass,
@Nullable final String niceName, int uid, int gid, @Nullable int[] gids,
int runtimeFlags, int mountExternal, int targetSdkVersion, @Nullable String seInfo,
@NonNull String abi, @Nullable String instructionSet, @Nullable String appDataDir,
@Nullable String invokeWith, @Nullable String packageName, int zygotePolicyFlags,
boolean isTopApp, @Nullable long[] disabledCompatChanges,
@Nullable Map<String, Pair<String, Long>> pkgDataInfoMap,
@Nullable Map<String, Pair<String, Long>> whitelistedDataInfoMap,
boolean bindMountAppsData, boolean bindMountAppStorageDirs,
@Nullable String[] zygoteArgs) {
return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
zygotePolicyFlags, isTopApp, disabledCompatChanges,
pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
bindMountAppStorageDirs, zygoteArgs);
}
Process.start() 本身并不创建进程,它只是把参数继续转交给 ZygoteProcess。真正和 Zygote 通信的关键点有两个:
// frameworks/base/core/java/android/os/ZygoteProcess.java
public final Process.ProcessStartResult start(...) {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, false,
packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
pkgDataInfoMap, allowlistedDataInfoList, bindMountAppsData,
bindMountAppStorageDirs, zygoteArgs);
}
private Process.ProcessStartResult startViaZygote(...) throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<>();
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
argsForZygote.add("--runtime-flags=" + runtimeFlags);
...
synchronized (mLock) {
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
zygotePolicyFlags, argsForZygote);
}
}
这里表达的是一个很清楚的模型:
system_server 不直接 fork; 它只是把启动参数编码成 Zygote 协议,再通过 socket 发给 Zygote。
2.4 Zygote 接单并 fork:父进程返回 pid,子进程进入下一阶段
ZygoteProcess 在本端把参数发出去以后,会同步等待结果:
// frameworks/base/core/java/android/os/ZygoteProcess.java
private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(
ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
zygoteWriter.write(msgStr);
zygoteWriter.flush();
Process.ProcessStartResult result = new Process.ProcessStartResult();
result.pid = zygoteInputStream.readInt();
result.usingWrapper = zygoteInputStream.readBoolean();
...
return result;
}
另一侧,Zygote 一直在 runSelectLoop() 里等请求:
// frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> socketFDs = new ArrayList<>();
ArrayList<ZygoteConnection> peers = new ArrayList<>();
socketFDs.add(mZygoteSocket.getFileDescriptor());
peers.add(null);
while (true) {
...
if (pollIndex == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
socketFDs.add(newPeer.getFileDescriptor());
} else if (pollIndex < usapPoolEventFDIndex) {
ZygoteConnection connection = peers.get(pollIndex);
final Runnable command = connection.processCommand(this, multipleForksOK);
...
}
}
}
收到请求后,ZygoteConnection.processCommand() 才会真正调用 forkAndSpecialize():
// frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
...
pid = com.android.internal.os.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,
parsedArgs.mBindMountSyspropOverrides);
if (pid == 0) {
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
} else {
handleParentProc(pid, serverPipeFd);
return null;
}
}
这一段正好把边界切成父子两边:
- 父进程(Zygote):拿到
pid > 0,继续通过 socket 把结果回给 system_server; - 子进程(新应用进程):
pid == 0,进入handleChildProc(...),后续会切到ActivityThread.main()。
本文只停在父进程把 pid 返回给 system_server 这一刻。因为从这里开始,问题已经从“怎么 fork 出新进程”切换成“新进程起来之后怎么初始化自己”,那是下一篇的主题。
3. 关键设计点
3.1 system_server 只描述启动请求,Zygote 才真正 fork
AMS / ProcessList 负责准备身份、ABI、入口类和运行参数;真正调用 forkAndSpecialize() 的是 Zygote。这样分层后,进程管理策略和进程创建机制就被干净拆开了。
3.2 Java 入口在 fork 前就已经确定为 ActivityThread
ProcessList.startProcessLocked() 里直接把 entryPoint 设成 android.app.ActivityThread。这说明应用进程被拉起来之后,并不是“再随机找个入口”,而是从进程创建阶段就已经约定好了后续 Java 世界的接管点。
3.3 socket 协议是这里的桥接层
startViaZygote() 把参数组织成 Zygote 能识别的参数列表,attemptZygoteSendArgsAndGetResult() 负责收发结果。本质上,这一层就是 system_server 到 Zygote 的协议桥接。
4. 总结
应用程序进程启动阶段的本质,是 system_server 准备启动参数,Zygote 执行 fork,并把新进程 pid 回传给 system_server。
当 ProcessStartResult 返回时,这个阶段就结束了。接下来新的应用进程会从 ActivityThread.main() 开始进入主线程初始化和 bindApplication 绑定流程,这正是下一篇要讲的内容。