You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过5037端口/USB FFS与设备内adbd通信及检测状态

嵌入式Linux下adbd异常检测与USB FFS端点操作问题

问题背景

搭载kernel-5.10.188内核、busybox及adbd的嵌入式Linux系统,偶尔出现adb shell登录失败,报错error: no devices/emulators found,需通过串口控制台重启adbd恢复功能。需找到adbd异常检测及重启方法,同时了解设备内通过USB FFS端点模拟adb命令的可行性。

现有adbd相关系统信息

lsof输出

# lsof | grep adbd
201     /usr/bin/adbd   0       /dev/null
201     /usr/bin/adbd   1       /dev/console
201     /usr/bin/adbd   2       /dev/console
201     /usr/bin/adbd   3       socket:[3341]
201     /usr/bin/adbd   4       socket:[3342]
201     /usr/bin/adbd   5       socket:[3343]
201     /usr/bin/adbd   6       socket:[3344]
201     /usr/bin/adbd   7       socket:[3345]
201     /usr/bin/adbd   8       socket:[3346]
201     /usr/bin/adbd   9       /dev/usb-ffs/adb/ep0
201     /usr/bin/adbd   10      /dev/usb-ffs/adb/ep1
201     /usr/bin/adbd   11      /dev/usb-ffs/adb/ep2
201     /usr/bin/adbd   12      socket:[3943]
201     /usr/bin/adbd   13      socket:[3944]
201     /usr/bin/adbd   14      /dev/ptmx

netstat输出

# netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 192.168.0.1:www         0.0.0.0:*               LISTEN
tcp        0      0 192.168.0.1:domain      0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:56797           0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:56800           0.0.0.0:*               LISTEN
tcp        0      0 localhost:5037          0.0.0.0:*               LISTEN
udp        0      0 0.0.0.0:56797           0.0.0.0:*
udp        0      0 192.168.0.1:domain      0.0.0.0:*
udp        0      0 0.0.0.0:bootps          0.0.0.0:*
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node Path
unix  2      [ ]         DGRAM                      1565 /var/run/hostapd/wlan0
unix  5      [ ]         DGRAM                      1212 /dev/log
unix  2      [ ACC ]     STREAM     LISTENING       3344 @jdwp-control
unix  3      [ ]         STREAM     CONNECTED       3346
unix  2      [ ]         DGRAM                      1553
unix  3      [ ]         STREAM     CONNECTED       3944
unix  3      [ ]         STREAM     CONNECTED       3341
unix  3      [ ]         STREAM     CONNECTED       3342
unix  2      [ ]         DGRAM                      1213
unix  3      [ ]         STREAM     CONNECTED       3345
unix  3      [ ]         STREAM     CONNECTED       3943
unix  2      [ ]         DGRAM                      1541

已尝试的方法(无效)

因adbd编译时设置ADB_HOST=0,不接受host:version等host命令,以下代码无法获取有效响应:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define ADB_HOST "127.0.0.1"
#define ADB_PORT 5037

void send_adb_command(const char *command) {
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port = htons(ADB_PORT),
        .sin_addr.s_addr = inet_addr(ADB_HOST)
    };

    struct timeval timeout = {2, 0};
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

    connect(sock, (struct sockaddr*)&addr, sizeof(addr));

    char header[5];
    snprintf(header, sizeof(header), "%04X", (unsigned int)strlen(command));
    send(sock, header, 4, 0);
    send(sock, command, strlen(command), 0);

    char response[1024];
    recv(sock, response, sizeof(response)-1, 0);
    printf("Response: %s\n", response);

    close(sock);
}

int main() {
    send_adb_command("host:version");
    send_adb_command("host:devices");
    return 0;
}

问题解答

一、设备内检测adbd异常的有效方法

由于ADB_HOST=0禁用了host端命令接口,可从以下维度检测adbd状态:

  1. 进程存活检测

    • 基础检查:用ps | grep adbd确认进程是否存在,或通过kill -0 <adbd_pid>(无输出则进程存活)判断进程状态。但进程存活不代表功能正常,需结合其他指标。
  2. 文件描述符持有情况检查

    • 定期执行lsof -p <adbd_pid> | grep -E "(usb-ffs|socket)",检查adbd是否仍持有/dev/usb-ffs/adb/ep0/ep1/ep2及关键socket文件描述符。若这些FD消失,说明adbd已异常。
  3. UNIX套接字连通性测试

    • 从netstat输出可见adbd监听@jdwp-control UNIX套接字,可尝试连接该套接字并发送简单命令验证:
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <unistd.h>
      #include <sys/socket.h>
      #include <sys/un.h>
      
      void test_jdwp_socket() {
          int sock = socket(AF_UNIX, SOCK_STREAM, 0);
          struct sockaddr_un addr = {
              .sun_family = AF_UNIX,
              .sun_path = "@jdwp-control"
          };
      
          struct timeval timeout = {2, 0};
          setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
      
          if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
              // 发送ADB格式的命令:4位十六进制长度 + 命令内容
              const char* cmd = "shell:echo ok";
              char header[5];
              snprintf(header, sizeof(header), "%04X", (unsigned int)strlen(cmd));
              send(sock, header, 4, 0);
              send(sock, cmd, strlen(cmd), 0);
      
              char response[1024];
              ssize_t n = recv(sock, response, sizeof(response)-1, 0);
              if (n > 0) {
                  response[n] = '\0';
                  printf("JDWP socket response: %s\n", response);
              } else {
                  printf("JDWP socket无响应,adbd异常\n");
              }
              close(sock);
          } else {
              printf("无法连接JDWP套接字,adbd异常\n");
          }
      }
      
      int main() {
          test_jdwp_socket();
          return 0;
      }
      
    • 若连接失败或无响应,说明adbd已无法处理请求,需重启。
  4. USB FFS设备状态检查

    • 尝试打开/dev/usb-ffs/adb/ep0,若打开失败,说明USB ADB功能异常,可触发adbd重启。

二、USB FFS端点模拟adb命令的可行性与格式

可以通过读写/dev/usb-ffs/adb/ep1和ep2模拟adb命令,但需严格遵循ADB USB协议格式,且需注意adbd已占用这些设备节点,直接读写可能导致冲突,建议仅用于调试或特殊场景。

ADB USB协议基本格式

每个ADB USB包由以下部分组成:

  • 命令字段:4字节ASCII字符串(如CNXN、OPEN、DATA、OKAY)
  • 参数0:4字节无符号整数(小端序)
  • 参数1:4字节无符号整数(小端序)
  • 数据长度:4字节无符号整数(小端序)
  • 数据内容:长度对应的数据(可选)

模拟adb shell命令的大致步骤

  1. 建立连接(CNXN包)

    • 向ep2(OUT端点)发送:
      命令: CNXN
      arg0: 0x01000000 (ADB协议版本)
      arg1: 0x10000 (最大数据传输长度)
      数据长度: 6
      数据: "host::"
      
    • 从ep1(IN端点)接收设备响应的CNXN包,确认连接建立。
  2. 请求shell会话(OPEN包)

    • 发送:
      命令: OPEN
      arg0: 0
      arg1: 0
      数据长度: 6
      数据: "shell:"
      
    • 接收设备返回的OKAY包,表示会话已打开。
  3. 发送命令内容(DATA包)

    • 发送:
      命令: DATA
      arg0: 0 (传输ID)
      arg1: 0
      数据长度: 字符串长度(如"echo hello\n"长度为10)
      数据: "echo hello\n"
      
    • 从ep1接收返回的DATA包,包含命令执行结果。
  4. 关闭会话(CLSE包)

    • 发送CLSE包结束会话。

注意:实际实现需处理字节序转换、包拼接及错误重试,且若设备开启ADB认证,还需额外处理AUTH包交互,复杂度较高。


内容的提问来源于stack exchange,提问作者wangt13

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 06:30:56