ZygoteProcess.start
SS033 解释了 AMS 如何决定启动参数;本篇只讲 ZygoteProcess 怎样把这些字段变成 Zygote wire protocol。它先同步 USAP pool 开关,startViaZygote() 按固定顺序构造字符串参数,在 mLock 内选择支持目标 ABI 的 ZygoteState,再把 argc + 每行一个参数 写入普通 Zygote 或 USAP socket,读取 pid 和 wrapper 标志。
1. start入口
源码文件:frameworks/base/core/java/android/os/ZygoteProcess.java
public final Process.ProcessStartResult start(
String processClass, String niceName,
int uid, int gid, int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion, String seInfo,
String abi, String instructionSet,
String appDataDir, String invokeWith,
String packageName, int zygotePolicyFlags,
boolean isTopApp, ... ) {
if (fetchUsapPoolEnabledPropWithMinInterval()) {
informZygotesOfUsapPoolStatus();
}
try {
return startViaZygote(...);
} catch (ZygoteStartFailedEx ex) {
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}USAP 配置属性按最小间隔刷新,变化时通知 primary/secondary Zygote;随后才开始本次进程命令。内部失败统一包装为 RuntimeException 返回给 ProcessList。
2. 固定参数前缀
源码文件:frameworks/base/core/java/android/os/ZygoteProcess.java
ArrayList<String> argsForZygote = new ArrayList<>();
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
argsForZygote.add("--runtime-flags=" + runtimeFlags);
argsForZygote.add(
"--target-sdk-version=" + targetSdkVersion);
if (gids != null && gids.length > 0) {
argsForZygote.add(
"--setgroups=" + commaSeparatedGids);
}源码注释要求 runtime/setuid/setgid/setgroups 位于前部,ZygoteArguments parser 依赖该协议。mountExternal 根据枚举转成不同 flag;nice name、seInfo、instruction set、app data dir、invoke-with 等按非空条件加入。
3. 隔离与兼容参数
if (pkgDataInfoMap != null
&& !pkgDataInfoMap.isEmpty()) {
argsForZygote.add(
Zygote.PKG_DATA_INFO_MAP + "="
+ encodeDataInfo(pkgDataInfoMap));
}
if (bindMountAppStorageDirs) {
argsForZygote.add(
Zygote.BIND_MOUNT_APP_STORAGE_DIRS);
}
if (bindMountAppsData) {
argsForZygote.add(
Zygote.BIND_MOUNT_APP_DATA_DIRS);
}
if (disabledCompatChanges != null
&& disabledCompatChanges.length > 0) {
argsForZygote.add(
"--disabled-compat-changes="
+ join(disabledCompatChanges));
}data info map 被编码为 package、volume UUID、inode 三元组序列;mount flag 只表达是否执行绑定。compat change 数组以逗号列表传输,接收端在 specialization 后写入 VMRuntime/AppCompatCallbacks。
4. 入口类与额外参数
argsForZygote.add(processClass);
if (extraArgs != null) {
Collections.addAll(argsForZygote, extraArgs);
}
argsForZygote.add(
"--use-deliqueue=" + useDeliQueue);参数顺序具有语义:processClass 之前由 Zygote parser 消费,之后的参数传给 ActivityThread 等目标 main。start sequence 和 deli queue 参数位于目标类之后,最终由应用入口读取。把 Zygote 控制 flag 放在 processClass 后会变成应用参数而失效。
5. ABI连接与锁
synchronized (mLock) {
ZygoteState state =
openZygoteSocketIfNeeded(abi);
return zygoteSendArgsAndGetResult(
state, zygotePolicyFlags,
argsForZygote);
}mLock 保护 primary/secondary ZygoteState、output writer 和 input stream,确保多个启动请求不会把请求/响应字节交叉。openZygoteSocketIfNeeded() 先尝试 primary ABI,再尝试 secondary;返回的 state 是长连接缓存。
6. wire format校验
for (String arg : args) {
if (arg.indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx(
"Embedded newlines not allowed");
} else if (arg.indexOf('\r') >= 0) {
throw new ZygoteStartFailedEx(
"Embedded carriage returns not allowed");
} else if (arg.indexOf('\u0000') >= 0) {
throw new ZygoteStartFailedEx(
"Embedded nulls not allowed");
}
}
String msgStr = args.size() + "\n"
+ String.join("\n", args) + "\n";协议是首行参数数量,后续每行一个参数。换行、回车和 NUL 会破坏 framing,因此写 socket 前全部拒绝,避免向 Zygote 留下半个请求。
7. USAP与普通Zygote
源码文件:frameworks/base/core/java/android/os/ZygoteProcess.java
if (shouldAttemptUsapLaunch(
zygotePolicyFlags, args)) {
try {
return attemptUsapSendArgsAndGetResult(
zygoteState, msgStr);
} catch (IOException ex) {
Log.e(LOG_TAG,
"IO Exception while communicating with USAP pool");
}
}
return attemptZygoteSendArgsAndGetResult(
zygoteState, msgStr);只有 policy/参数允许时才尝试 USAP;USAP socket I/O 失败会回退普通 Zygote,而 USAP 返回负 pid 表示 specialization 失败并抛异常。USAP 不能用于需要 wrapper 的进程,所以返回 usingWrapper=false。
8. PID与wrapper响应
zygoteWriter.write(msgStr);
zygoteWriter.flush();
Process.ProcessStartResult result =
new Process.ProcessStartResult();
result.pid = zygoteInputStream.readInt();
result.usingWrapper =
zygoteInputStream.readBoolean();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}客户端总是读取完整 pid+boolean,避免残留字节污染下一次启动。普通 I/O 异常会关闭 ZygoteState,下一次请求重新连接;负 pid 转成 fork failure。成功返回只表示 Zygote 已给出 child pid,不表示应用已 attach AMS。
9. 失败与导航
- 参数含协议字符:写 socket 前失败;
- ABI 不支持:连接选择失败;
- USAP I/O 失败:回退普通 Zygote;
- USAP specialization 负 pid:启动失败,不回退重复 fork;
- 普通 socket I/O 失败:关闭缓存 state 并抛异常;
- pid 成功但应用未 attach:进入 AMS attach timeout/子进程崩溃路径。
# 参数编码、processClass 分界和 mount/compat flags。
rg -n "startViaZygote|argsForZygote|PKG_DATA_INFO_MAP|disabled-compat-changes|processClass|use-deliqueue" \
frameworks/base/core/java/android/os/ZygoteProcess.java
# ABI 连接、wire format、USAP 回退和 pid 响应。
rg -n "openZygoteSocketIfNeeded|zygoteSendArgsAndGetResult|attemptUsapSendArgsAndGetResult|attemptZygoteSendArgsAndGetResult|Embedded newlines|readBoolean" \
frameworks/base/core/java/android/os/ZygoteProcess.java下一篇将进入 USAP 池本身:池大小、预 fork、specialization、reporting pipe 和 refill;不会重复本篇的通用命令协议。
