Android-adb源码 : Socket 的用法

879 阅读3分钟

在 Android Framework 源码中,ADB(Android Debug Bridge)使用了 Android 系统的本地 socket 通信机制。ADB 服务在 Android 系统启动时会被启动,它监听一个本地 socket,等待来自客户端的连接请求。客户端可以通过 socket 连接到 ADB 服务,发送命令并接收返回结果,以实现与设备的通信。

下面简单介绍一下 ADB 在 Android Framework 中创建 socket 的过程:

  1. ADB 服务在启动时会创建一个本地 socket,用于监听来自客户端的连接请求。该 socket 的地址通常为 /dev/socket/adb
  2. 当客户端连接到 ADB 服务时,客户端会创建一个本地 socket,用于与 ADB 服务进行通信。客户端 socket 的地址通常为 /dev/socket/ 加上一个随机的字符串,例如 /dev/socket/adb-123
  3. 客户端通过 socket 连接到 ADB 服务,并发送命令或数据。ADB 服务接收到命令或数据后进行处理,并将处理结果返回给客户端。

Note

需要注意的是,ADB 的 socket 通信机制是基于 Unix 域套接字实现的,因此只能在本地进行通信,无法通过网络进行通信。

源码


/* create_local_service_socket函数用于创建本地 socket,并返回 socket 的文件描述符 */
int create_local_service_socket(const char *name, bool server, mode_t perm)
{
    struct sockaddr_un addr;
    int fd, ret;

    /* 创建 Unix 域套接字 */
    fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (fd < 0) {
        D("cannot create socket\n");
        return -1;
    }

    /* 设置 socket 地址 */
    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, name, sizeof(addr.sun_path) - 1);
    addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';

    /* 如果 server 参数为真,则将 socket 绑定到指定地址 */
    if (server) {
        unlink(name);
        ret = bind(fd, (struct sockaddr *) &addr, sizeof(addr));
        if (ret < 0) {
            D("cannot bind to '%s': %s\n", name, strerror(errno));
            close(fd);
            return -1;
        }

        /* 设置 socket 的权限 */
        if (perm) {
            fchmod(fd, perm);
        }

        /* 监听连接请求 */
        ret = listen(fd, 4);
        if (ret < 0) {
            D("cannot listen on '%s': %s\n", name, strerror(errno));
            close(fd);
            return -1;
        }
    } else {
        /* 如果 server 参数为假,则尝试连接到指定地址 */
        ret = connect(fd, (struct sockaddr *) &addr, sizeof(addr));
        if (ret < 0) {
            D("cannot connect to '%s': %s\n", name, strerror(errno));
            close(fd);
            return -1;
        }
    }

    /* 返回 socket 的文件描述符 */
    return fd;
}

重点

fd = socket(AF_UNIX, SOCK_STREAM, 0);

具体解释如下:

  • AF_UNIX:地址族,表示使用 Unix 域套接字(Unix domain socket)。Unix 域套接字是一种特殊的套接字,用于在同一台计算机上的进程间通信。与网络套接字不同,Unix 域套接字并不使用 IP 地址和端口号,而是使用文件系统中的文件路径作为套接字的地址。
  • SOCK_STREAM:套接字类型,表示使用流式套接字(stream socket)。流式套接字提供可靠的、面向连接的、基于数据流的双向通信服务,类似于 TCP 协议提供的服务。与之相对的是数据报套接字(datagram socket),它提供不可靠的、无连接的、基于数据报的单向通信服务,类似于 UDP 协议提供的服务。
  • 0:协议,表示使用默认协议。在 Unix 域套接字中,一般使用默认协议即可。