ZygoteConnection.processCommand
processCommand() 是 Zygote session socket 的命令分派器。它并非每次都 fork:ABI/PID 查询、boot completed、preload、USAP 开关、hidden API 配置等命令直接修改/查询 Zygote 状态;只有 spawn 请求才经过 capability、uid、invoke-with、fd 和 fork 路径。父 Zygote 返回 null 并写 pid,child 返回一个调用目标 main 的 Runnable。
1. 参数解析与EOF
源码文件:frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java、frameworks/base/core/java/com/android/internal/os/ZygoteArguments.java
try (ZygoteCommandBuffer argBuffer =
new ZygoteCommandBuffer(mSocket)) {
while (true) {
ZygoteArguments parsedArgs =
ZygoteArguments.getInstance(argBuffer);
if (parsedArgs == null) {
isEof = true;
return null;
}
...
}
}ZygoteArguments 按 argCount 读取并拒绝 setuid/setgid/target SDK/capabilities 等关键参数重复,降低参数注入歧义。EOF 标记连接被客户端关闭,ZygoteServer 下一轮会移除 peer。
2. 非fork管理命令
if (parsedArgs.mBootCompleted) {
handleBootCompleted();
return null;
}
if (parsedArgs.mAbiListQuery) {
handleAbiListQuery();
return null;
}
if (parsedArgs.mPidQuery) {
handlePidQuery();
return null;
}
if (parsedArgs.mPreloadDefault) {
handlePreload();
return null;
}这些命令直接写响应:ABI/PID 使用长度前缀字节,boot/preload 使用 int status。它们不创建 child,也不进入 uid specialization。USAP status、API denylist、hidden API sample rate 需要在释放当前 argBuffer 后处理,以免状态变化期间重开/冲突 command buffer。
3. Spawn安全检查
if (parsedArgs.mPermittedCapabilities != 0
|| parsedArgs.mEffectiveCapabilities != 0) {
throw new ZygoteSecurityException(
"Client may not specify capabilities");
}
Zygote.applyUidSecurityPolicy(parsedArgs, peer);
Zygote.applyInvokeWithSecurityPolicy(
parsedArgs, peer);
Zygote.applyDebuggerSystemProperty(parsedArgs);
Zygote.applyInvokeWithSystemProperty(parsedArgs);普通 session 客户端不能指定 capabilities;uid/gid 未指定时从 peer credentials 继承,低 UID/invoke-with 受安全策略限制。debug/system property 只能在安全校验后补充 runtime flags/wrapper。
4. wrapper管道与fd
int[] fdsToIgnore = null;
if (parsedArgs.mInvokeWith != null) {
FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
childPipeFd = pipeFds[1];
serverPipeFd = pipeFds[0];
Os.fcntlInt(childPipeFd, F_SETFD, 0);
fdsToIgnore = new int[] {
childPipeFd.getInt$(),
serverPipeFd.getInt$()
};
}
int[] fdsToClose = {-1, -1};
fdsToClose[0] = mSocket.getFileDescriptor().getInt$();
fdsToClose[1] = zygoteServer
.getZygoteSocketFileDescriptor().getInt$();wrapper 管道用于父进程获得 wrapper 后真正 child pid;这些 fd 要从 Zygote fd 检查中忽略。session socket 和主监听 socket 必须在 child 切换 uid 前关闭/替换,防止应用继承 Zygote 控制面。
5. Java fork路径
if (parsedArgs.mInvokeWith != null
|| parsedArgs.mStartChildZygote
|| !multipleOK
|| peer.getUid() != Process.SYSTEM_UID) {
int pid = Zygote.forkAndSpecialize(...);
try {
if (pid == 0) {
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
return handleChildProc(
parsedArgs, childPipeFd,
parsedArgs.mStartChildZygote);
} else {
IoUtils.closeQuietly(childPipeFd);
handleParentProc(pid, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}复杂/包装/child-zygote/非 system peer 请求走 Java forkAndSpecialize。child 关闭 server socket并返回 Runnable;parent 关闭 child pipe,handleParentProc() 写 pid/usingWrapper。finally 处理所有异常分支的 pipe ownership。
6. 简单fork路径
ZygoteHooks.preFork();
Runnable result = Zygote.forkSimpleApps(
argBuffer,
zygoteServer.getZygoteSocketFileDescriptor(),
peer.getUid(),
Zygote.minChildUid(peer),
parsedArgs.mNiceName,
parsedArgs.mIsTopApp);
if (result == null) {
ZygoteHooks.postForkCommon();
continue;
} else {
zygoteServer.setForkChild();
return result;
}当命令足够简单、peer 是 system、允许 multiple fork 时,native command buffer 可连续 fork 多个应用,减少 Java 往返。父进程返回 null 并继续当前 connection;child 返回 Runnable。遇到不支持命令时 argBuffer 保留,循环回到 Java 处理。
7. 状态变化与USAP
API denylist、hidden API sampling 等修改 Zygote 全局状态时,现有 USAP 已继承旧状态。stateChangeWithUsapPoolReset() 先 empty pool,执行状态变更,再 refill;若 refill 在 child 返回 Runnable,ZygoteServer 进入 child 分支。该流程确保新启动应用不会从旧配置 USAP specialization。
8. 失败边界
- 参数重复/格式错误:fork 前拒绝;
- capability/UID/invoke-with:安全异常,不产生 child;
- pipe 创建失败:wrapper 请求失败;
- fork pid < 0:parent 返回失败状态;
- child post-fork 异常:child 终止,parent Zygote继续;
- 管理命令写响应失败:关闭/移除当前 session;
- USAP 状态变更失败:可能清空池后无法及时 refill,但普通 fork 仍可作为 fallback。
9. 导航与后续
# processCommand 分支、权限、fd 和父子处理。
rg -n "processCommand|mAbiListQuery|mPreloadDefault|mPermittedCapabilities|applyUidSecurityPolicy|fdsToClose|forkAndSpecialize|forkSimpleApps|handleParentProc|handleChildProc" \
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
# 参数重复、Zygote 控制字段和 remaining args。
rg -n "parseArgs|Duplicate arg|--setuid|--setgid|--capabilities|--rlimit|--setgroups|--invoke-with" \
frameworks/base/core/java/com/android/internal/os/ZygoteArguments.java下一篇将专门分析 Zygote 文本参数协议及每个关键 flag 的解析规则;不会重复 processCommand 的 fork 分流。
