Zygote socket注册
Android 17 的 socket 入口不是 Java 进程自己重新 bind 一个名字,而是 init 先创建 socket,再把 fd 编号放入 ANDROID_SOCKET_<name> 环境变量。Zygote 通过 Zygote.createManagedSocketFromInitSocket() 读取这个编号,包装为 LocalServerSocket,交给 ZygoteServer 的 poll 循环。
1. init创建者
源码文件:system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin \
--zygote --start-system-server --socket-name=zygote
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root systemsocket zygote stream 660 root system 是 init 的资源声明。init 创建并监听 socket、设置权限和环境变量;app_process/Zygote 不拥有这个 bind 动作。usap_pool_primary 是另一条 fd,供 USAP 管理使用,不能和主 Zygote socket 混为一个监听器。
2. 环境变量取fd
源码文件:frameworks/base/core/java/com/android/internal/os/Zygote.java
相关函数:createManagedSocketFromInitSocket()
static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(
"Socket unset or invalid: " + fullSocketName, ex);
}
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
return new LocalServerSocket(fd);
} catch (IOException ex) {
throw new RuntimeException(
"Error building socket from file descriptor: " + fileDesc, ex);
}
}这里没有复制 fd,也没有按名称再次创建 socket:fd.setInt$(fileDesc) 只是把已有整数放进 Java FileDescriptor。LocalServerSocket(fd) 接管后续 Java 包装和 accept 调用。环境变量缺失、非数字或 fd 不能构造为本地服务 socket,都会在启动阶段抛出 RuntimeException。
3. Server owner
源码文件:frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
ZygoteServer(boolean isPrimaryZygote) {
mUsapPoolEventFD = Zygote.getUsapPoolEventFD();
if (isPrimaryZygote) {
mZygoteSocket = Zygote.createManagedSocketFromInitSocket(
Zygote.PRIMARY_SOCKET_NAME);
mUsapPoolSocket = Zygote.createManagedSocketFromInitSocket(
Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
} else {
mZygoteSocket = Zygote.createManagedSocketFromInitSocket(
Zygote.SECONDARY_SOCKET_NAME);
mUsapPoolSocket = Zygote.createManagedSocketFromInitSocket(
Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
}
mUsapPoolSupported = true;
fetchUsapPoolPolicyProps();
}isPrimaryZygote 决定读取 zygote 还是 zygote_secondary,同时决定对应的 USAP socket。ZygoteServer 保存的是 Java socket wrapper;真正的 fd 仍由 init 创建。构造函数还读取 USAP 策略,但不会在这里启动 poll,poll 由后续 runSelectLoop() 承担。
4. accept与消费
源码文件:frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
private ZygoteConnection acceptCommandPeer(String abiList) {
try {
return createNewConnection(
mZygoteSocket.accept(), abiList);
} catch (IOException ex) {
throw new RuntimeException(
"IOException during accept()", ex);
}
}accept() 返回新的连接 socket,主监听 socket 继续留在 mZygoteSocket。ZygoteConnection 消费客户端发送的 fork 参数;因此“主 socket fd”与“每次命令连接 fd”是两种不同 owner。accept 失败会中止当前 ZygoteServer 循环,不是普通的服务查询空结果。
5. 关闭与fork边界
源码文件:frameworks/base/core/java/com/android/internal/os/ZygoteServer.java、frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
void closeServerSocket() {
try {
if (mZygoteSocket != null) {
FileDescriptor fd = mZygoteSocket.getFileDescriptor();
mZygoteSocket.close();
if (fd != null && mCloseSocketFd) {
Os.close(fd);
}
}
} catch (IOException ex) {
Log.e(TAG, "Zygote: error closing sockets", ex);
} catch (ErrnoException ex) {
Log.e(TAG, "Zygote: error closing descriptor", ex);
}
}fork SystemServer 后,子进程必须关闭继承的 Zygote 监听 socket,否则 SystemServer 会继续持有一个不应消费的监听 fd。mCloseSocketFd 区分 fd 是否由 ZygoteServer 创建/拥有;关闭 wrapper 与显式 Os.close(fd) 不是无条件重复执行。SS004 的 finally 也会在异常和退出路径调用该清理。
6. 失败定位
# init 的 socket 声明、权限和服务参数
rg -n "service zygote|socket zygote|socket usap_pool" \
system/core/rootdir/init.zygote*.rc
# 环境变量名称、fd 包装和异常文本
rg -n "ANDROID_SOCKET_|createManagedSocketFromInitSocket|setInt\$|Socket unset" \
frameworks/base/core/java/com/android/internal/os/Zygote.java
# ZygoteServer owner、accept 和关闭
rg -n "mZygoteSocket|acceptCommandPeer|runSelectLoop|closeServerSocket" \
frameworks/base/core/java/com/android/internal/os/ZygoteServer.java排查时先确认 init 是否声明了目标 socket,再确认环境变量是否存在且为有效 fd,最后检查 ZygoteServer 是否在子进程关闭监听器。不能因为 LocalServerSocket 构造成功就推断客户端连接已建立;连接只有在 accept() 后才交给 ZygoteConnection。
下一篇将展开 preload() 的 classes/resources/libraries 三条路径,解释预加载如何在 fork 前建立可共享状态;不会重复本文的 socket fd 包装。
