Skip to content

Zygote socket注册

追踪 init 创建的 Zygote socket、ANDROID_SOCKET 环境变量、FileDescriptor 包装和子进程关闭路径。

基于android-17.0.0_r1
AndroidZygoteLocalSocket源码阅读

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

text
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 system

socket 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()

java
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

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

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

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. 失败定位 ​

bash
# 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 包装。