自动化工具 解决自动化测试设备掉线:软件方案

甬力君 · June 28, 2017 · Last by 甬力君 replied at June 02, 2021 · 3578 hits
本帖已被设为精华帖!

前几天发帖讨论自动化测试中 adb 掉线的解决方法,大家在下面回复了一些软件解决方案。

https://testerhome.com/topics/9122#reply9

本着折腾精神,这几天收集了一些软件方案,现总结下,方便碰到同样问题的小伙伴参考。

windows 软件解决方案

设备实例路径查看办法:win+r 打开运行窗口 ——> 输入 devmgmt.msc 打开设备管理器 ——> 选择你的设备双击 ——> 切换到属性 tab 页 ——> 在属性下拉框选择设备实例路径

linux/ubuntu 软件解决方案

  • python 代码实现:
    • 原理:ioctl
    • 代码:
# coding:utf-8
import os
import fcntl
import subprocess

USBDEVFS_RESET = ord('U') << (4 * 2) | 20

def get_adb_usb_devices():
    lines = os.popen('lsusb').readlines()
    target_lines = []
    for line in lines:
        if 'MediaTek' in line or 'Spreadtrum' in line or 'Qualcomm' in line:
            target_lines.append(line)
    adb_usb_devices = []
    for line in target_lines:
        parts = line.split()
        # print parts
        bus = parts[1]
        dev = parts[3][:3]
        adb_usb_devices.append('/dev/bus/usb/%s/%s' % (bus, dev))
    return adb_usb_devices


def send_reset(adb_device_path):
    fd = os.open(adb_device_path, os.O_WRONLY)
    print fd
    try:
        ret = fcntl.ioctl(fd, USBDEVFS_RESET, 0)
    finally:
        os.close(fd)
    if ret < 0:
        return False
    else:
        return True

def main():
    # 请求root权限
    if (os.getuid() != 0):
        exe = subprocess.Popen(['sudo', 'python', __file__])
        exe.wait()
        exit(1)

    # 打印信息
    print '-' * 75
    print 'Usage   : USB device Reset Tool for android QCom|Sprd|MTK device'
    print 'Coder  : Wanyor'
    print '-' * 75

    adb_usb_devices = get_adb_usb_devices()

    print 'usb:', adb_usb_devices
    for adb_device_path in adb_usb_devices:
                if (send_reset(adb_device_path)):
                    print 'Reset {0} Success!'.format(adb_device_path)
                else:
                    print 'Reset {0} Fail!'.format(adb_device_path)


if __name__ == '__main__':
    main()
  • c 语言编写 cli 程序实现:
    • 原理:ioctl
    • 代码:

usbreset.c

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>

#include <linux/usbdevice_fs.h>


int main(int argc, char **argv)
{
    const char *filename;
    int fd;
    int rc;

    if (argc != 2) {
        fprintf(stderr, "Usage: usbreset device-filename\n");
        return 1;
    }
    filename = argv[1];

    fd = open(filename, O_WRONLY);
    if (fd < 0) {
        perror("Error opening output file");
        return 1;
    }

    printf("Resetting USB device %s\n", filename);
    rc = ioctl(fd, USBDEVFS_RESET, 0);
    if (rc < 0) {
        perror("Error in ioctl");
        return 1;
    }
    printf("Reset successful\n");

    close(fd);
    return 0;
}

然后用 gcc usbreset.c -o usbreset 编译下,sudo chmod a+x usbreset 给 cli 程序执行权限即可运行,参数为设备的挂载路径(例如:/dev/bus/usb/002/007)
设备挂载路径查看办法:lsusb 即可查看

跨平台解决方案

  • libusb 库实现:
    • 原理:libusb 自带 usb_reset 函数,写个 c 代码调用下就可以了
    • 代码:

usbreset.c

#include <stdio.h>
#include <stdlib.h>
#include <libusb-1.0/libusb.h>

//compile: gcc usbreset.c -o usbreset -lusb-1.0

//usage: ./usbreset 2 6

//use lsusb to check out the bus number and device number


struct libusb_device_handle *devh;
struct libusb_device *dev;
struct libusb_device **devs;

void resetUSB() {

    int success;
    int bpoint = 0;

    do {
        success = libusb_reset_device(devh);
        if ((bpoint % 10) == 0) {
            printf(".");
        }

        ++bpoint;

        if (bpoint > 100) {
            success = 1;
        }
    } while (success < 0);

    if (success) {
        printf("nreset usb device failed:%dn", success);
    } else {
        printf("nreset usb device okn");
    }
}


struct libusb_device* search_device(int _busNum, int _devNum) { 

    libusb_device *l_dev;
    int i = 0;
    int l_busNum, l_devNum;

    while ((l_dev = devs[i++]) != NULL) {
        printf("check against %d devicen", i);
        l_busNum =(int) libusb_get_bus_number(l_dev);
        l_devNum =(int) libusb_get_device_address(l_dev);
        printf("bus number: %d; device number: %dn", l_busNum, l_devNum);
        if ((l_busNum == _busNum) && (l_devNum == _devNum)) {
            printf("found devicen");
            return l_dev;
        }
    }
    return NULL;
}


int main(int argc, char **argv) {

    //parse the input parameters to get the bus number and device number
    int l_busNum, l_devNum;
    int l_ret;

    printf("program started!n");
    if (argc < 3) {
        printf("not enough arguments!n");
        printf("usage: ./usbreset <bus number> <dev number>n");
        return 0;
    }

    printf("bus number: %sn", argv[1]);
    printf("dev number: %sn", argv[2]);

    l_busNum = atoi(argv[1]);
    l_devNum = atoi(argv[2]);
    printf("bus number: %d; dev number: %dn", l_busNum, l_devNum);

    l_ret = libusb_init(NULL);
    if (l_ret < 0) {
        return l_ret;
    }

    l_ret = libusb_get_device_list(NULL, &devs);

    if (l_ret < 0) {
        return (int) l_ret;
    }

    dev = search_device(l_busNum, l_devNum);

    if (dev == NULL) {
        printf("device not foundn");
        return 0;
    }

    l_ret = libusb_open(dev, &devh);    

    if (l_ret == 0) {
        printf("got the usb handle successfully.n");
    } else {
        printf("error getting usb handle.n");
    }

    //reset the usb device
    resetUSB();

    //free the device list
    libusb_free_device_list(devs, 1);

    libusb_exit(NULL);

    return 0;
}

使用 gcc usbreset.c -o usbreset -lusb-1.0 编译下,sudo chmod a+x usbreset 给 cli 程序执行权限即可运行,参数为设备的 bus id 和 device id

跨平台方案也可以使用 python 的 libusb 的 cython 封装写,各位小伙伴可自由尝试。

😆😆汇报完毕...😆😆

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 13 条回复 时间 点赞
思寒_seveniruby 将本帖设为了精华贴 28 Jun 19:46

赞赞赞。

在 linux 的 Linux/include/uapi/linux/usbdevice_fs.h 中,重置_IO('U', 20) 可以重置 usb 设备。

具体代码可以参考我的文章:http://www.cnblogs.com/alexkn/p/6742536.html

我认为 adb 掉线的原因是电源供电不足,这是其一,后面我在 STF 官网上面看到他们的分析另一个原因是 usb3.0 驱动与 adb 间的问题,只要选择使用 usb2.0 的 usb-hub 就可以了。已经通过实践证明,双管齐下后 usb 都很正常。

不要用数据线连,用 wifi 连的话呢?

幽幽 回复

WiFi 更容易掉线啊

0x88 回复

adb 掉线的原因不完全是电源供电不足的问题,其实可以分为三个方面:
1、usb 连接线的抖动(不是线被动了,而是电信号的抖动)
2、usb 接口/usb hub 的抖动
3、adb server 和 adbd 之间的 socket 通道稳定性

幽幽 回复

用数据线连接的话,其实就极度依赖于 wifi 的稳定性了,wifi 信号不稳定的情况下,其实挺容易断开的

小学徒V 回复

什么叫 usb 抖动?没有听说过。我不是写了一篇 USB 连接相关的么?

0x88 回复

跟 1 一个道理,只是一个是线的,一个是 hub 或者 usb 接口的问题

小学徒V 回复

我怎么觉得我现在不能碰数据线,一碰就掉

想请教下,windows 下的方案有人测试通过了吗?

大神 我的 linux 插上手机后 lsusb 不显示设备,可知咋回事?

甬力君 #16 · June 02, 2021 Author
Elsie 回复

5 年前整的,看看安卓调试模式打开没?

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up