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

UsbDeviceConnection.requestWait()异常:USB设备重连后无法恢复通信

问题背景

重构Android应用USB通信模块时,原实现采用同步方法UsbDeviceConnection.bulkTransfer()完成端点间数据传输,重构后改为组合调用UsbRequest.initialize()、UsbRequest.queue()、UsbDeviceConnection.requestWait()的实现。新实现在平板上冷启动运行正常,性能优于原实现,但外部设备发生USB中断、断开连接后,即使设备重新接入,新方案也无法恢复通信,旧的bulkTransfer()实现则可以在重连后正常工作。

相关实现代码

基于bulkTransfer()的旧实现

byte[] response = new byte[64];
int result = 0;
int tries = 0;

while (result < 1){
    if (tries > 5) {
        Log.d("PayloadTask", "PayloadTask Timed Out.");
        return null;
    } else if (isCancelled()) {
        Log.w("PayloadTask", "PayloadTask Cancelled!");
        return null;
    }

    /*synchronized (usbConnection)*/
       result = usbConnection.bulkTransfer(usbFromAggBoard, response, response.length, 25);
       
    tries += 1;

}
Log.i("PayloadTask", new Integer(response.length).toString() + " bytes received: ");
Log.d("PayloadTask", "doInBackground returning some payload from the aggboard.");
return Payload.CreatePayload(response);

基于UsbRequest/requestWait()的重构实现

byte[] response = new byte[64];
int result = 0;
int tries = 0;

while (result < 1){
    if (tries > 5) {
        Log.d("PayloadTask", "PayloadTask Timed Out.");
        return null;
    } else if (isCancelled()) {
        Log.w("PayloadTask", "PayloadTask Cancelled!");
        return null;
    }

    /*synchronized (usbConnection)*/
    if (usbConnection != null) {
        UsbRequest request = new UsbRequest();
       
        ByteBuffer byteBuffer = ByteBuffer.wrap(response);
        byteBuffer.rewind();
        try {
            request.initialize(usbConnection, usbFromAggBoard);
            
            if (!request.queue(byteBuffer, response.length)) {
                throw new IOException("Error queueing USB request.");
            }
            usbConnection.requestWait();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(usbConnection != null) {
                result = request.hashCode();
                request.close();
          
            }
            else{
                Log.d("PayloadTask", "Request not received by usbConnection");
            }
        }
    }
    tries += 1;

}
Log.i("PayloadTask", new Integer(response.length).toString() + " bytes received: ");
Log.d("PayloadTask", "doInBackground returning some payload from the aggboard.");
return Payload.CreatePayload(response);
问题根因

UsbRequest是和USB连接、端点强绑定的有状态对象,和无状态同步调用的bulkTransfer()生命周期逻辑完全不同,重构代码存在多处逻辑错误直接导致重连失效:

  • 连接有效性判断逻辑失效:仅判断usbConnection对象是否非空,但设备断开重连后,旧的UsbDeviceConnection、UsbEndpoint实例已经和新设备解绑,哪怕对象不为空也属于失效会话。bulkTransfer()内部会自动校验连接有效性,失效时直接返回错误码触发重试,但UsbRequest绑定到失效连接/端点时不会第一时间抛出明确错误,后续队列、等待操作会静默失败。
  • 传输结果判断完全错误:finally块中直接将result赋值为request.hashCode(),对象哈希值永远为正整数,导致result < 1的循环退出条件完全失效。哪怕请求实际传输失败,只要request对象创建成功,循环就会直接退出,根本没有拿到有效返回数据。
  • 未做请求返回值校验:没有校验requestWait()返回的请求对象是否为当前入队的request,设备断连时该方法可能返回null、或者队列中残留的其他无效请求,这些异常分支都没有处理,会导致无效请求残留在连接队列中,重连后阻塞新请求。
  • 缺少断连后的资源重置逻辑:设备断开时没有主动关闭持有的失效UsbRequest、释放旧连接,重连后继续复用断连前的旧连接、旧端点实例,没有重新走权限申请、接口占用、端点枚举流程,自然无法恢复通信。
修复方案
  • 注册USB设备连接状态广播:收到ACTION_USB_DEVICE_DETACHED广播时,立刻关闭所有持有的UsbRequest、调用usbConnection.close()释放连接,将全局保存的usbConnection、usbFromAggBoard实例置空,清空待处理请求队列。
  • 重连流程补全:收到ACTION_USB_DEVICE_ATTACHED广播,或者传输前检测到连接失效时,重新走USB设备权限申请、接口claim、端点枚举流程,拿到全新的连接和端点实例后再发起传输,禁止复用断连前的旧实例。
  • 修正传输结果判断逻辑:不要用request对象的哈希值作为传输结果,校验requestWait()返回的request对象是否为当前入队的实例,匹配成功后从ByteBuffer的position属性拿到实际接收的字节数,字节数大于0才判定为传输成功,作为循环退出的依据。
  • 补全异常分支处理:request.initialize()、request.queue()、requestWait()任意一步返回false、null或者抛出异常,立刻关闭当前request,标记连接为失效状态触发重置流程,不要静默吞掉异常继续用无效实例重试。

修正后的核心传输逻辑参考

byte[] response = new byte[64];
int result = 0;
int tries = 0;

while (result < 1){
    if (tries > 5) {
        Log.d("PayloadTask", "PayloadTask Timed Out.");
        return null;
    } else if (isCancelled()) {
        Log.w("PayloadTask", "PayloadTask Cancelled!");
        return null;
    }
    // 前置校验连接有效性,无效则触发重连
    if (!isUsbConnectionValid()) {
        resetUsbConnection();
        tries++;
        try {
            Thread.sleep(30);
        } catch (InterruptedException e) {
            return null;
        }
        continue;
    }

    UsbRequest request = new UsbRequest();
    ByteBuffer byteBuffer = ByteBuffer.allocate(64);
    try {
        if (!request.initialize(usbConnection, usbFromAggBoard)) {
            throw new IOException("UsbRequest init failed, connection invalid");
        }
        if (!request.queue(byteBuffer, 64)) {
            throw new IOException("UsbRequest queue failed");
        }
        UsbRequest finishedReq = usbConnection.requestWait();
        // 校验返回请求匹配当前提交的请求
        if (finishedReq != request) {
            if (finishedReq != null) finishedReq.close();
            throw new IOException("Wait returned invalid request");
        }
        // 读取实际传输字节长度
        result = byteBuffer.position();
        if (result > 0) {
            byteBuffer.flip();
            byteBuffer.get(response, 0, result);
        }
    } catch (Exception e) {
        Log.e("PayloadTask", "USB transfer failed", e);
        markConnectionInvalid();
    } finally {
        request.close();
    }
    tries++;
}
Log.i("PayloadTask", result + " bytes received: ");
Log.d("PayloadTask", "doInBackground returning some payload from the aggboard.");
// 传入实际接收长度,避免用整个数组长度导致解析脏数据
return Payload.CreatePayload(response, result);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 11:00:59