如何通过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状态:
进程存活检测
- 基础检查:用
ps | grep adbd确认进程是否存在,或通过kill -0 <adbd_pid>(无输出则进程存活)判断进程状态。但进程存活不代表功能正常,需结合其他指标。
- 基础检查:用
文件描述符持有情况检查
- 定期执行
lsof -p <adbd_pid> | grep -E "(usb-ffs|socket)",检查adbd是否仍持有/dev/usb-ffs/adb/ep0/ep1/ep2及关键socket文件描述符。若这些FD消失,说明adbd已异常。
- 定期执行
UNIX套接字连通性测试
- 从netstat输出可见adbd监听
@jdwp-controlUNIX套接字,可尝试连接该套接字并发送简单命令验证:#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已无法处理请求,需重启。
- 从netstat输出可见adbd监听
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命令的大致步骤
建立连接(CNXN包)
- 向ep2(OUT端点)发送:
命令: CNXN arg0: 0x01000000 (ADB协议版本) arg1: 0x10000 (最大数据传输长度) 数据长度: 6 数据: "host::" - 从ep1(IN端点)接收设备响应的CNXN包,确认连接建立。
- 向ep2(OUT端点)发送:
请求shell会话(OPEN包)
- 发送:
命令: OPEN arg0: 0 arg1: 0 数据长度: 6 数据: "shell:" - 接收设备返回的
OKAY包,表示会话已打开。
- 发送:
发送命令内容(DATA包)
- 发送:
命令: DATA arg0: 0 (传输ID) arg1: 0 数据长度: 字符串长度(如"echo hello\n"长度为10) 数据: "echo hello\n" - 从ep1接收返回的DATA包,包含命令执行结果。
- 发送:
关闭会话(CLSE包)
- 发送CLSE包结束会话。
注意:实际实现需处理字节序转换、包拼接及错误重试,且若设备开启ADB认证,还需额外处理AUTH包交互,复杂度较高。
内容的提问来源于stack exchange,提问作者wangt13
相关产品推荐
相关产品推荐

