Чтение с Android USB-аксессуаров вызывает ENODEV IOException

Поэтому я реализовал API-интерфейс USB для Android, чтобы я мог подключить свой телефон к ноутбуку под управлением Linux, и он помещает телефон в режим USB-аксессуаров. Затем я могу получить доступ к аксессуару, открыть его и начать читать письмо. Мой код выглядит почти идентично примеру в документации . Основное различие заключается в том, что я использую отдельные методы чтения и записи и получаю их через JNI из собственного кода.

Вот где это становится интересным. После успешного чтения / записи на секунду или два, массовый перенос записи с моего ноутбука начинает давать ошибки таймаута, а затем вызов чтения на USB-аксессуар в Android выдает исключение IOEx с кодом ошибки ENODEV. Это связано с подключенным кабелем, и UsbManager по-прежнему перечисляет аксессуар в списке, и у меня все еще есть разрешение на это.

Чтобы добавить к нечетности, я обнаружил, что если я поставлю сон в 100 мс в цикле чтения, проблема в основном уходит (хотя это все равно случается). Сон в нем не просто ужасный kludge, но он вводит невыносимую латентность в мое приложение. Чем ниже время сна, тем менее эффективен взлом, где он неэффективен при 10 мс сна.

Я передаю около 20-30 Кбит / с данных в режиме реального времени, используя массовые переводы (но не так в режиме реального времени, что массовый перенос не будет достаточным), а размер передачи составляет от 50 до 800 байтов примерно на 20-30 Гц. Это может быть ограничение USB? У меня нет большого опыта с этим, поэтому я в основном рассматриваю его примерно так же, как сетевой сокет. Должен ли я помещать в очередь небольшие сообщения и отправлять их вместе в менее частые, но более крупные передачи? Есть ли проблема с малыми передачами на высоких частотах? Я рассмотрю это, но я в основном хватаюсь за соломинку здесь.

Оборудование:

  • Ноутбук работает под управлением Ubuntu 10.04 и использует libusb 1.0.0.
  • Телефон Galaxy Nexus S работает под управлением Android 4.1.2.

Итак, пока я все еще не понимаю все, что происходит, реализация двойной буферной схемы устранила мою проблему.

Я обнаружил, что приложение Java Android App на полной скорости не имеет проблем с проблемой ENODEV, что приводит меня к выводу, что основной интерфейс Java является корнем моих проблем.

Раньше я читал из UsbAccessory непосредственно из методов, называемых JNI, в опросе. Что-то о переходе от нативного кода к Java, а затем из Java в исходное ядро ​​Android, очевидно, сделало все сварливым.

Мое исправление заключалось в том, чтобы читать / записывать в UsbAccessory из потоков Java-only (без вызовов JNI), а затем буферизовать эти данные для чтения / записи из методов, вызванных JNI.

Кажется, это работает как шарм. Прежде, чем я получал таймауты отправки очень последовательно на стороне аксессуаров, а затем, в конце концов, IOExeception на стороне Android, как описано выше, и теперь у меня нет тайм-аутов, нет IOExceptions. Мне все еще немного любопытно, что именно вызывает это поведение, но я подозреваю, что это требует сильного понимания JNI Kung-fu.