Java.io.IOException,“坏文件号”USB连接

我正在设置Android手机和其他设备之间的USB配件连接。 只是来回发送字节来testing。 首先我得到了一些明确的沟通,但是总是最终死于Java.io.IOException: write failed: EBADF (Bad file number)"在一秒钟之后Java.io.IOException: write failed: EBADF (Bad file number)"有时读取保持活动,但写入死亡;其他两个死。

我没有做任何超级幻想,像Google文档一样阅读和写作:

初始连接(在广播接收器内,我知道这个部分至less在初始阶段):

 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; } } 

错误堆栈跟踪:

 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 

我logging了所有的地方,因此我知道这不是太明显,如收到另一个权限请求(因此文件stream被重新初始化中读)。 stream也不closures,因为我从来没有发生过我的代码中的任何地方(现在)。 我没有得到任何分离或附加事件(我logging,如果它发生)。 没有什么似乎与众不同的。 它刚刚死亡。

我想也许这是一个并发问题,所以我玩锁和睡觉,没有任何工作,我试过。 我不认为这是一个吞吐量问题,要么是因为在每次读取(两端读取)时都会发生,而且一次只读取一个数据包(超慢比特率)。 有没有机会在另一端超出缓冲区? 我将如何去清除这个? 我可以访问另一端的代码,它也是一个Android设备,使用主机模式。 如果重要的话,我也可以发布这些代码 – 标准批量传输。

手机是否支持Android附件模式? 我已经尝试了两个电话,他们都失败了,所以我怀疑是这样的。

我想知道是什么原因导致这个错误在Android上写或从USB读取一般?

Solutions Collecting From Web of "Java.io.IOException,“坏文件号”USB连接"

它最终成为一个线程问题。 我还需要更好地隔离甚至写作,而不仅仅是阅读。

我最终使用这个代码作为基础。

我在代码中遇到了同样的问题,而且我发现这是因为FileDescriptor对象是GCed。

我通过添加活动(或服务)中的ParcelFileDescriptor字段解决了这个问题。

我检查了你的第一个代码片段和你基于的代码,后者在Thread中有ParcelFileDescriptor字段。

我想如果你像下面一样编辑你的代码,那么效果很好。

 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); } } 

好的,我注意到的一些事情,似乎不同于我为开放式配件模式做的,我主要跟随了USB配件的文档,所以它应该非常相似,就是您的mIn.read(buf); 应该是mIn.read(buf, 0, 64); 我所知道的。

另外,你应该在你的类的声明中声明thread myThread; 。 然后在你的BroadcastReceiver内创build新的FileInput/OutputStream ,让myThread = new thread(myHandler, myInputStream); 跟着我myThread.start();

现在我注意到你正在从你的线程直接与UI通信。 你应该使用一个处理程序,而不是线程将进行通信,然后将通信回到您的用户界面,至less从我读过的。

这里是我的处理程序和线程的一个例子:

 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){ } } } } 

此外,这里有一些演示开放的附件应用程序。 他们可能会帮助您了解配件模式。

还有一个应用程序没有以编程方式接收ACTION_USB_ACCESSORY/DEVICE_ATTACHED的BroadcastReceiver的已知问题。 它只会通过清单文件接收它。 你可以在这里和这里find更多。

我实际上没有testing把处理程序中的dataReceivedvariables,只是最近改变了我的代码的一部分。 我testing了一下,结果没有奏效,所以试图记住我读过的是什么,我想这不是关于线程内variables的通信,而是尝试使用诸如.setText()类的东西。 我已经更新了我的代码,在线程中包含了dataReceived=true 。 处理程序将被用于更新UI上的项目,如TextView等。

线

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