LocalSocket与Zygote通信
Zygote 通信使用 Unix domain LocalSocket:init 创建并命名监听 socket,ZygoteServer 包装 fd 并 accept,客户端 ZygoteProcess 建立 session socket 后先查询 ABI,再发送 spawn/preload 命令。连接的 owner、权限和关闭责任分布在三层:init/内核持有监听资源,ZygoteServer 持有服务端 wrapper,ZygoteState 持有客户端读写流。
1. 客户端状态
源码文件:frameworks/base/core/java/android/os/ZygoteProcess.java
private static class ZygoteState implements AutoCloseable {
final LocalSocketAddress mZygoteSocketAddress;
final LocalSocketAddress mUsapSocketAddress;
private final LocalSocket mZygoteSessionSocket;
final DataInputStream mZygoteInputStream;
final BufferedWriter mZygoteOutputWriter;
private final List<String> mAbiList;
private boolean mClosed;
}ZygoteState 缓存一次连接的地址、session socket、输入/输出流和服务端 ABI list。mLock 保护多个线程对 writer/input 的串行访问,避免一条命令的字节与另一条命令交叉。
2. 建连与回滚
static ZygoteState connect(
LocalSocketAddress zygoteSocketAddress,
LocalSocketAddress usapSocketAddress)
throws IOException {
LocalSocket socket = new LocalSocket();
if (zygoteSocketAddress == null) {
throw new IllegalArgumentException(
"zygoteSocketAddress can't be null");
}
try {
socket.connect(zygoteSocketAddress);
DataInputStream input = new DataInputStream(
socket.getInputStream());
BufferedWriter output = new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream()),
Zygote.SOCKET_BUFFER_SIZE);
return new ZygoteState(...,
input, output,
getAbiList(output, input));
} catch (IOException ex) {
socket.close();
throw ex;
}
}连接、流创建或 ABI 握手任一步失败,临时 socket 都会关闭;不会把半初始化 state 放入 primary/secondary 缓存。成功的 ZygoteState 由 attemptConnectionToPrimaryZygote() 或 secondary 对象持有。连接构造中的 getAbiList() 随即在同一 session 上完成下面的握手。
3. ABI握手
writer.write("1");
writer.newLine();
writer.write("--query-abi-list");
writer.newLine();
writer.flush();
int numBytes = inputStream.readInt();
byte[] bytes = new byte[numBytes];
inputStream.readFully(bytes);
String rawList = new String(
bytes, StandardCharsets.US_ASCII);
return Arrays.asList(rawList.split(","));握手本身也使用 Zygote 文本命令:参数数量 1、命令名 --query-abi-list;响应是 int 长度加 ASCII ABI 列表。客户端保存列表后,后续 matches(abi) 只做本地判断,不再每次启动重复查询。
4. 服务端接入
源码文件:frameworks/base/core/java/com/android/internal/os/ZygoteServer.java、frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
private ZygoteConnection acceptCommandPeer(
String abiList) {
try {
return createNewConnection(
mZygoteSocket.accept(), abiList);
} catch (IOException ex) {
throw new RuntimeException(
"IOException during accept()", ex);
}
}accept 只完成服务端 fd 接收;新连接构造时还必须读取 Unix peer credentials 并应用 Zygote 的 system UID 门槛。
ZygoteConnection(LocalSocket socket,
String abiList) throws IOException {
mSocket = socket;
peer = mSocket.getPeerCredentials();
if (peer.getUid() != Process.SYSTEM_UID) {
throw new ZygoteSecurityException(
"Only system UID is allowed to connect to Zygote.");
}
}accept 返回的是每次客户端连接的 session socket,构造 ZygoteConnection 时立即读取 peer credentials,仅允许 system UID。主监听 socket继续由 ZygoteServer持有;权限失败只影响当前连接。
5. 命令连接生命周期
session socket是双向流:客户端写命令、服务端返回 pid/status。服务端在 processCommand() 中识别 EOF;客户端在 IOException 时关闭缓存 state,让下一次启动重新 connect/handshake。
6. 命令发送与阻塞
synchronized (mLock) {
ZygoteState state =
openZygoteSocketIfNeeded(abi);
return zygoteSendArgsAndGetResult(
state, zygotePolicyFlags,
argsForZygote);
}同一 ZygoteState 的 writer/input 必须在锁内成对使用:写完整请求、flush、读取完整响应。connect 本身可能阻塞,ABI 不匹配时还会顺序尝试 secondary;因此锁粒度覆盖整个请求,保证 pid 响应与调用方一一对应。
7. 关闭与重试
public void close() {
try {
mZygoteSessionSocket.close();
} catch (IOException ex) {
Log.e(LOG_TAG,
"I/O exception on routine close", ex);
}
mClosed = true;
}ZygoteState.close 只关闭客户端 session 并标记 closed;下一次 attemptConnectionToPrimaryZygote() 发现 closed 后重新连接。启动时等待 Zygote 的辅助方法按 500ms 间隔重试,到达超时后记录 WTF;它只验证 socket 可连接,不发送 spawn 命令。
8. init fd边界
SS005 已说明 init 创建的 socket fd 通过环境变量进入 Zygote。ZygoteServer 的 mCloseSocketFd 区分 wrapper 是否拥有底层 fd;由 init 提供的 fd 在子进程关闭时需要 wrapper close 加显式 Os.close,避免 LocalSocket wrapper 不拥有原始 fd 导致泄漏。客户端 session socket 则由 LocalSocket 自身创建和关闭。
9. 失败定位与导航
- connect 失败:检查 socket name/namespace、init service 和 Zygote 是否监听;
- ABI 握手失败:检查服务端响应长度、ASCII 列表和 stream 是否残留;
- peer UID 拒绝:检查调用进程 credentials,不是 ABI 问题;
- 命令写入阻塞:检查 mLock 持有者、服务端 poll 和 session 消费;
- I/O 后重复使用旧 state:检查
ZygoteState.close()和缓存重建; - 子进程 fd 泄漏:检查 init fd wrapper、mCloseSocketFd 和显式 Os.close。
# 客户端连接、ABI握手、锁和关闭。
rg -n "class ZygoteState|connect\(|getAbiList|openZygoteSocketIfNeeded|mLock|close\(\)|waitForConnectionToZygote" \
frameworks/base/core/java/android/os/ZygoteProcess.java
# 服务端 accept、peer credentials、命令连接和 socket close。
rg -n "acceptCommandPeer|createNewConnection|PeerCredentials|SYSTEM_UID|processCommand|closeServerSocket" \
frameworks/base/core/java/com/android/internal/os/ZygoteServer.java \
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java下一篇将分析 ZygoteConnection.processCommand() 的参数解析、权限策略和 fork 命令处理;不会重复 LocalSocket 建连和 ABI 握手。
