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

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

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

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

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

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

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

Ответ 1

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

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

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

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

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