Java.io.IOException,“异常”;“错误的文件号”;USB连接

Java.io.IOException,“异常”;“错误的文件号”;USB连接,java,android,usb,Java,Android,Usb,我正在安卓手机和其他设备之间建立USB附件连接。现在只是来回发送字节进行测试。一开始,我得到了一些明确的通信,但在大约一秒钟后,它总是以Java.io.IOException:write failed:EBADF(坏文件号)而告终。有时读取仍然有效,但写入却消失了;其他的都消失了 我没有做任何超乎想象的事情,像谷歌文档一样阅读和写作: 初始连接(在广播接收器内部,我知道这部分至少在最初工作): 阅读: Thread thread = new Thread(new Runnable() {

我正在安卓手机和其他设备之间建立USB附件连接。现在只是来回发送字节进行测试。一开始,我得到了一些明确的通信,但在大约一秒钟后,它总是以
Java.io.IOException:write failed:EBADF(坏文件号)
而告终。有时读取仍然有效,但写入却消失了;其他的都消失了

我没有做任何超乎想象的事情,像谷歌文档一样阅读和写作:

初始连接(在广播接收器内部,我知道这部分至少在最初工作):

阅读:

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
我到处都有日志记录,因此我知道这不是什么太明显的事情,比如收到另一个权限请求(因此文件流在读取过程中被重新初始化)。流也不会关闭,因为我的代码中从未发生过这种情况(目前为止)。我也没有收到任何分离或附加的事件(如果真的发生了,我会记录下来。)没有什么事情看起来太不寻常了,它只是死了

我想这可能是并发性问题,所以我玩了锁和休眠,但我尝试了什么都不起作用。我也不认为这是吞吐量问题,因为每次读取(两端)休眠,每次读取一个数据包(超慢比特率)时,这种情况仍然会发生。另一端的缓冲区是否有可能被溢出?我该如何清除?我确实可以访问另一端的代码,它也是Android设备,使用主机模式。如果有问题,我也可以发布代码-标准批量传输

这部手机对安卓附件模式的支持不够吗?我试过两部手机,但都失败了,所以我怀疑是不是这样


我想知道在Android上从USB写入或读取数据时,通常是什么原因导致此错误?

好的,我注意到有几件事似乎与我在开放附件模式下所做的不同,我主要遵循USB附件的文档,所以应该非常类似,那就是您的
mIn.read(buf)据我所知,
应该是
mIn.read(buf,0,64);

另外,您应该在类声明中声明
thread myThread;
。然后在创建新的
FileInput/OutputStream
后的
BroadcastReceiver中,让
myThread=new thread(myHandler,myInputStream);
跟随my
myThread.start();

现在我注意到您正在从线程直接与UI通信。您应该使用线程将与之通信的处理程序,然后该处理程序将与您的UI通信,至少从我所读的内容来看是这样的

下面是我的处理程序和线程的示例:

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

            }
        }
    }
}
此外,还有一些演示开放附件应用程序。它们可能有助于您了解附件模式

此外,应用程序未以编程方式接收连接的
操作\u USB\u附件/设备\u的BroadcastReceiver也存在已知问题。它将仅通过清单文件接收。您可以找到有关此和的详细信息

实际上,我没有测试将
dataReceived
变量放入处理程序中,只是最近才更改了代码的这一部分。我测试了它,但它不起作用,所以试图记住我读到的内容,我认为这不是关于线程内的变量通信,而是试图使用类似
.setText()的东西
。我已更新代码,将
dataReceived=true
包含在线程中。然后,处理程序将用于更新UI上的项目,如
TextView
s等

线

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

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


我最终使用了作为基础。

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

我通过在活动(或服务)中添加ParcelFileDescriptor字段修复了这个问题

我检查了您的第一个代码段和您基于的代码,后者在线程中有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);
    }
} 

你使用的是什么版本的Android?还有,你想和什么交流?我相信在附件模式下(你使用的是Android开放附件模式吗?),你需要一个兼容的主机设备,比如arduino或FT311D.Android 4.0.4。我可以很好地获得初始连接,而且没有“兼容”这类东西"设备-如果您发送了正确的控制请求,手机将进入附件模式(如果支持)。我的手机上会弹出一个对话框,说明它看到了附件-只是在保持连接方面有问题。哦,好的,等等,它会看到附件,这意味着您的手机处于主机模式,而不是附件模式。对吗?哪个设备提供了power,电话到设备还是设备提供给手机?不,Android文档实际上有点混淆术语。它看到附件,意味着它进入附件模式。当你在手机上处于附件模式时,你可以遍历
UsbAccessory
对象-你在附件模式下看到它们。设备有点像Android平板电脑(我想也是4.0.4);它为我的手机供电。它通过主机模式进行通信。这一切一开始都很好,只是这个“坏文件号”最终出现了。好吧,我主要使用开放附件模式,所以我只是想了解更多细节,看看我能为您提供多少帮助…所以听起来您有两台android设备通过USB相互通信,一台主机,一个附件?对吗?您得到的是“坏文件号”在附属的android设备上?谢谢你的提示,但我没有直接与UI通信;你从哪里得到的?从
mReadParcelFileDescriptor 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);
    }
}