11

因此,我实现了 Android USB 附件 API,这样我就可以将手机插入运行 linux 的笔记本电脑,并将手机置于 USB 附件模式。然后我可以访问附件,打开它,然后开始读取它的内容。我的代码看起来几乎与文档中的示例相同。主要区别在于我使用单独的读写方法并通过 JNI 从本机代码访问它们。

这就是有趣的地方。在成功读/写一两秒后,从我的笔记本电脑进行的批量传输写入开始出现超时错误,然后在 Android 中对 USB 附件的读取调用会引发带有 ENODEV 错误代码的 IOException。这是在电缆仍然连接并且 UsbManager 仍然在列表中列出附件的情况下,并且我仍然拥有它的权限。

更奇怪的是,我发现如果我在读取循环中设置 100 毫秒的睡眠时间,问题基本上就会消失(尽管有时仍会发生)。在那里睡觉不仅是一件可怕的事情,而且会给我的应用程序带来无法忍受的延迟。睡眠时间越短,hack 的效果就越差,在 10ms 的睡眠时间里它是无效的。

我正在使用批量传输传输大约 20-30kbps 的实时数据(但不是实时到批量传输不够),传输大小范围为 50 到 800 字节,频率约为 20-30Hz。会不会是 USB 的限制?我没有太多的经验,所以我基本上把它当作网络套接字来对待。我是否应该将较小的消息排队并以较低频率但较大的传输一起发送?小型高频批量传输是否存在问题?我会调查这个,但我基本上在这里抓住了稻草。

硬件:

  • 笔记本电脑正在运行 Ubuntu 10.04 并使用 libusb 1.0.0。
  • 手机是 Galaxy Nexus S,运行库存 Android 4.1.2。
4

1 回答 1

6

因此,虽然我仍然不了解正在发生的一切,但实施双缓冲方案解决了我的问题。

我发现全速读取的 Java Android 应用程序没有遇到 ENODEV 问题,这使我得出结论,Java 原生接口是我问题的根源。

以前,我以轮询方式直接从 JNI 调用的方法中读取 UsbAccessory。从本机代码到 Java,然后从 Java 到本机 Android 内核的过渡显然让一切变得暴躁。

我的解决方法是从纯 Java 线程(无 JNI 调用)读取/写入 UsbAccessory,然后缓冲该数据以从 JNI 调用的方法读取/写入。

似乎像魅力一样工作。在我在附件端非常一致地收到发送超时之前,然后最终在 Android 端出现如上所述的 IOExeception,现在我没有超时,也没有 IOExceptions。我仍然有点好奇究竟是什么导致了这种行为,但我怀疑它需要强大的 JNI Kung-fu 才能理解。

于 2012-11-07T07:12:08.617 回答