Zygote参数传递协议
Zygote 参数协议是有顺序和类型约束的文本协议,不是任意 --key=value 集合。客户端先写参数数量,再逐行写字符串;服务端 ZygoteArguments.parseArgs() 按顺序识别控制参数,遇到第一个未知/非 option 参数后把剩余内容交给目标 Java main。关键安全字段禁止重复,--rlimit 和 compat changes 允许累积,管理命令禁止尾随 spawn 参数。
1. Wire framing
源码文件:frameworks/base/core/java/android/os/ZygoteProcess.java
String msgStr = args.size() + "\n"
+ String.join("\n", args) + "\n";首行是 argc,之后必须恰好有 argc 行参数。参数中的 newline、carriage return、NUL 在发送前拒绝,因为它们会破坏 framing。响应由具体命令决定:spawn 返回 pid/usingWrapper,ABI/PID query 返回长度前缀字节,状态命令返回 int。
2. Spawn参数前缀
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
argsForZygote.add(
"--runtime-flags=" + runtimeFlags);
argsForZygote.add(
"--target-sdk-version=" + targetSdkVersion);源码注释要求 runtime/setuid/setgid/setgroups 位于前部。--runtime-args 是普通 spawn 命令的标志;parser 在需要 runtime args 却没见到它时拒绝请求。
3. 禁止重复参数
源码文件:frameworks/base/core/java/com/android/internal/os/ZygoteArguments.java
if (arg.startsWith("--setuid=")) {
if (mUidSpecified) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
mUidSpecified = true;
mUid = Integer.parseInt(
getAssignmentValue(arg));
} else if (arg.startsWith("--setgid=")) {
if (mGidSpecified) {
throw new IllegalArgumentException(
"Duplicate arg specified");
}
...
}uid、gid、target SDK、seInfo、capabilities、setgroups、invoke-with、nice-name、package-name 等关键字段禁止重复。安全审查注释明确这样做是为了降低参数注入和“后一个值覆盖前一个值”的歧义。
4. 允许累积参数
} else if (arg.startsWith("--rlimit=")) {
String[] values = getAssignmentList(arg);
if (values.length != 3) {
throw new IllegalArgumentException(
"--rlimit= should have 3 comma-delimited ints");
}
if (mRLimits == null) {
mRLimits = new ArrayList<>();
}
mRLimits.add(parseRlimit(values));
} else if (arg.startsWith(
"--disabled-compat-changes=")) {
mDisabledCompatChanges =
parseAndMergeCompatChanges(
arg, mDisabledCompatChanges);
}一个进程可以有多个 rlimit tuple;compat changes 也允许多次出现并合并、排序、去重,以支持多个调用层追加配置。空 compat 项被忽略,不使用 Set 以减少关键路径分配。
5. Mount与数据map
if (bindMountAppStorageDirs) {
argsForZygote.add(
Zygote.BIND_MOUNT_APP_STORAGE_DIRS);
}
if (bindMountAppsData) {
argsForZygote.add(
Zygote.BIND_MOUNT_APP_DATA_DIRS);
}
argsForZygote.add(
Zygote.PKG_DATA_INFO_MAP + "="
+ encodedPackageVolumeInodeTriples);mount 采用布尔 flag,data info map 使用逗号列表编码 package、volume UUID、inode 三元组。parser 只拆分字符串,结构长度和 inode 语义还要由 native isolation 代码校验。
6. processClass分界
argsForZygote.add(processClass);
Collections.addAll(argsForZygote, extraArgs);
argsForZygote.add(
"--use-deliqueue=" + useDeliQueue);parser 遇到第一个未识别 option/普通字符串后停止读取 Zygote 控制参数,将它和后续内容放入 mRemainingArgs。对普通应用,第一个 remaining arg 是 android.app.ActivityThread,后面的 seq=、deli queue 由 ActivityThread.main 消费。
7. 管理命令独占性
if (mBootCompleted) {
if (argCount > curArg) {
throw new IllegalArgumentException(
"Unexpected arguments after --boot-completed");
}
} else if (mAbiListQuery || mPidQuery) {
if (argCount > curArg) {
throw new IllegalArgumentException(
"Unexpected arguments after --query-abi-list.");
}
} else if (mPreloadApp != null) {
if (argCount > curArg) {
throw new IllegalArgumentException(
"Unexpected arguments after --preload-app.");
}
}ABI/PID/boot/preload-app 等 standalone 命令不能混入 spawn 参数,避免一个请求同时改变 Zygote 全局状态和 fork child。API denylist 命令则显式消费所有剩余参数。
8. Child Zygote约束
if (mStartChildZygote) {
boolean seenChildSocketArg = false;
for (String arg : mRemainingArgs) {
if (arg.startsWith(
Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
seenChildSocketArg = true;
break;
}
}
if (!seenChildSocketArg) {
throw new IllegalArgumentException(
"--start-child-zygote specified without socket name");
}
}child zygote 必须在 remaining args 中包含随机/专用 socket 名,否则新 Zygote 没有命令通道。accepted ABI list 和 UID range 同样由 child zygote 参数消费者解析。
9. 错误与导航
- argc 与实际行数不一致:command buffer EOF/解析失败;
- 数字格式错误:Integer/Long parse 异常;
- 重复安全字段:拒绝整个请求;
- 缺
--runtime-args:普通 spawn 被拒绝; - processClass 前后顺序错误:Zygote 控制参数变成应用参数或相反;
- child zygote 缺 socket:拒绝启动;
- data map 结构异常:可能在 native isolation 阶段失败。
# 客户端编码顺序和条件参数。
rg -n "startViaZygote|argsForZygote|runtime-args|setuid|setgroups|PKG_DATA_INFO_MAP|disabled-compat-changes|processClass|use-deliqueue" \
frameworks/base/core/java/android/os/ZygoteProcess.java
# 服务端 parser、重复限制、管理命令和 remaining args。
rg -n "parseArgs|Duplicate arg|expectRuntimeArgs|seenRuntimeArgs|mRemainingArgs|Unexpected arguments|mStartChildZygote|parseAndMergeCompatChanges" \
frameworks/base/core/java/com/android/internal/os/ZygoteArguments.java下一篇将分析 child PID 在 Zygote、SystemServer 和 ProcessRecord 之间的流转;不会重复参数解析规则。
