Подтвердить что ты не робот

Java.io.IOException, "неправильный номер файла" USB-соединение

Я настраиваю USB-аксессуар между моим телефоном Android и другим устройством. Просто отправьте байты туда и обратно, чтобы проверить. Сначала я получаю определенное сообщение, но он всегда заканчивается с Java.io.IOException: write failed: EBADF (Bad file number)" через секунду или около того. Иногда чтение остается живым, но письмо умирает; другие умирают.

Я не делаю ничего сверхъестественного, читаю и пишу, как документация Google:

Исходное соединение (внутри широковещательного приемника, я знаю, что эта часть работает хотя бы изначально):

if (action.equals(ACTION_USB_PERMISSION))
{
    ParcelFileDescriptor pfd = manager.openAccessory(accessory);
    if (pfd != null) {
        FileDescriptor fd = pfd.getFileDescriptor();
        mIn = new FileInputStream(fd);
        mOut = new FileOutputStream(fd);
    }
}

Чтение:

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        byte[] buf = new byte[BUF_SIZE];
        while (true)
        {
            try {
                int recvd = mIn.read(buf);
                if (recvd > 0) {
                    byte[] b = new byte[recvd];
                    System.arraycopy(buf, 0, b, 0, recvd);
                    //Parse message
                }
            }
            catch (IOException e) {
                Log.e("read error", "failed to read from stream");
                e.printStackTrace();
            }
        }
    }
});
thread.start();

Запись:

synchronized(mWriteLock) {
    if (mOut !=null && byteArray.length>0) {
        try {
            //mOut.flush();
            mOut.write(byteArray, 0, byteArray.length);
        }
        catch (IOException e) {
            Log.e("error", "error writing");
            e.printStackTrace();
            return false;
        }
    }
    else {
        Log.e(TAG, "Can't send data, serial stream is null");
        return false;
    }
}

Ошибка stacktrace:

java.io.IOException: write failed: EBADF (Bad file number)
W/System.err(14028):     at libcore.io.IoBridge.write(IoBridge.java:452)
W/System.err(14028):     at java.io.FileOutputStream.write(FileOutputStream.java:187)
W/System.err(14028):     at com.my.android.transport.MyUSBService$5.send(MyUSBService.java:468)
W/System.err(14028):     at com.my.android.transport.MyUSBService$3.onReceive(MyUSBService.java:164)
W/System.err(14028):     at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:781)
W/System.err(14028):     at android.os.Handler.handleCallback(Handler.java:608)
W/System.err(14028):     at android.os.Handler.dispatchMessage(Handler.java:92)
W/System.err(14028):     at android.os.Looper.loop(Looper.java:156)
W/System.err(14028):     at android.app.ActivityThread.main(ActivityThread.java:5045)
W/System.err(14028):     at java.lang.reflect.Method.invokeNative(Native Method)
W/System.err(14028):     at java.lang.reflect.Method.invoke(Method.java:511)
W/System.err(14028):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
W/System.err(14028):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
W/System.err(14028):     at dalvik.system.NativeStart.main(Native Method)
W/System.err(14028): Caused by: libcore.io.ErrnoException: write failed: EBADF (Bad file number)
W/System.err(14028):     at libcore.io.Posix.writeBytes(Native Method)
W/System.err(14028):     at libcore.io.Posix.write(Posix.java:178)
W/System.err(14028):     at libcore.io.BlockGuardOs.write(BlockGuardOs.java:191)
W/System.err(14028):     at libcore.io.IoBridge.write(IoBridge.java:447)
W/System.err(14028):     ... 13 more

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

Я подумал, что это была проблема concurrency, поэтому я играл с замками и спит, ничего не работало, что я пытался. Я не думаю, что это проблема пропускной способности, потому что это все еще происходит, когда я сплю каждое прочитанное (с обоих концов) и читаю один единственный пакет за раз (супер медленный биттрейт). Есть ли вероятность того, что буфер каким-то образом переполняется на другом конце? Как я могу это исправить? У меня есть доступ к другому конечному коде, это также устройство Android, используя режим Host. В случае, если это имеет значение, я тоже могу отправить этот код - стандартные массовые переводы.

Есть ли у телефона просто тусклая поддержка Android-аксессуаров? Я пробовал два телефона, и они оба терпели неудачу, поэтому я сомневаюсь в этом.

Мне интересно, что вызывает эту ошибку вообще при записи или чтении с USB на Android?

4b9b3361

Ответ 1

В конечном итоге это проблема с потоками. Мне нужно было более точно отделить даже письмо, а не просто читать.

В итоге я использовал этот код в качестве основы.

Ответ 2

У меня такая же проблема в моем коде, и я обнаружил, что это происходит потому, что объект FileDescriptor был GCed.

Я исправил эту проблему, добавив поле ParcelFileDescriptor в Activity (или Service).

Я проверил ваш первый фрагмент кода и код, на котором вы основывались, и у последнего есть поле ParcelFileDescriptor в Thread.

Я думаю, что если вы отредактируете свой код, как показано ниже, он будет работать хорошо.

ParcelFileDescriptor mPfd;
...

if (action.equals(ACTION_USB_PERMISSION))
{
    mPfd = manager.openAccessory(accessory);
    if (mPfd != null) {
        FileDescriptor fd = mPfd.getFileDescriptor();
        mIn = new FileInputStream(fd);
        mOut = new FileOutputStream(fd);
    }
} 

Ответ 3

ОК, несколько замечаний, которые я заметил, просто отличались от того, что я делаю для Open Accessory Mode, и я в основном соблюдал документацию для USB-аксессуаров, поэтому она должна быть очень похожей, заключается в том, что ваш mIn.read(buf); должен быть mIn.read(buf, 0, 64); насколько я знаю.

Кроме того, вы должны объявить в объявлениях класса thread myThread;. Затем в вашем BroadcastReceiver после создания нового FileInput/OutputStream, myThread = new thread(myHandler, myInputStream); следует за моим myThread.start();.

Теперь я заметил, что вы напрямую общаетесь с пользовательским интерфейсом из своего потока. Вместо этого вы должны использовать обработчик, с которым поток будет взаимодействовать, а затем он свяжется с вашим пользовательским интерфейсом, по крайней мере, из того, что я прочитал.

Вот пример моего обработчика и потока:

final Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg){

    }
};

private class USB_Thread extends Thread {
    Handler thisHandler;
    FileInputStream thisInputStream;

    USB_Thread(Handler handler, FileInputStream instream){
        thisHandler = handler;
        thisInputStream = instream;
    }
    @Override
    public void run(){
        while(true) {
            try{
                if((thisInputStream != null) && (dataReceived == false)) {
                    Message msg = thisHandler.obtainMessage();
                    int bytesRead = thisInputStream.read(USB_Data_In, 0, 63);
                    if (bytesRead > 0){
                        dataReceived = true;
                        thisHandler.sendMessage(msg);
                    }
                }
            }
            catch(IOException e){

            }
        }
    }
}

Кроме того, есть несколько демонстрационных открытых аксессуаров здесь. Они могут помочь с пониманием режима аксессуаров.

А также есть известные проблемы с приложением, не получающим BroadcastReceiver для ACTION_USB_ACCESSORY/DEVICE_ATTACHED программно. Он получит его только через файл манифеста. Вы можете найти здесь здесь и здесь.

На самом деле я не тестировал перенос переменной dataReceived в обработчик и только недавно изменил эту часть моего кода. Я тестировал его, и это не сработало, поэтому, пытаясь вспомнить, что я читал, я думаю, что речь идет не о переменных, связанных в потоках, а о попытке использовать что-то вроде .setText(). Я обновил свой код, чтобы включить dataReceived=true в поток. Обработчик затем будет использоваться для обновления элементов в пользовательском интерфейсе, таких как TextView s и т.д.

Тема

FileDescriptor fd = mFileDescriptor.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
usbThread = new USB_Thread(mHandler, mInputStream);
usbThread.start();