KISS

Keep It Simple Stupid

USB AOA: EBADF while sending data

| comments

Hello there! It’s been a while since my last post, and I’m back here again.

Today I’d like to write a small note about the USB Android Open Accessory protocol. In short, it allows an android device to communicate with external devices over USB, even if it can’t be a host. When using it on Android, I got an IOException with EBADF code. What to do?

First of all, I had used this very helpful page with sources as the basis for both parts (Android and computer): http://android.serverbox.ch/?p=262.

The stacktrace I got when trying to send data after a certain delay looks like this:

1
2
3
4
5
6
7
8
9
10
11
java.io.IOException: write failed: EBADF (Bad file number)
    at libcore.io.IoBridge.write(IoBridge.java:452)
    at java.io.FileOutputStream.write(FileOutputStream.java:187)
Caused by: libcore.io.ErrnoException: write failed: EBADF (Bad file number)
    at libcore.io.Posix.writeBytes(Native Method)
    at libcore.io.Posix.write(Posix.java:178)
    at libcore.io.BlockGuardOs.write(BlockGuardOs.java:191)
    at libcore.io.IoBridge.write(IoBridge.java:447)
    at java.io.FileOutputStream.write(FileOutputStream.java:187)

When opening a USB accessory, I saved the references to the following variables required for communication:

1
2
3
4
5
6
// the opened USB accessory
private UsbAccessory mAccessory = null;
// stream to read data from
private InputStream mInputStream = null;
// stream to write data to
private OutputStream mOutputStream = null;

Long story short, turned out the parent FileDescriptor got garbage collected and thus invalid, causing the aforementioned exception. So I need to keep

1
2
// accessory's file descriptor
private ParcelFileDescriptor mParcelFD = null;

as well.

Here’s some extract of the connecting code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
try {
    mParcelFD = getUsbManager().openAccessory(mAccessory);
} catch (SecurityException e) {
    final String msg = "Have no permission to open the accessory";
    logE(msg, e);
    return false;
}
if (mParcelFD == null) {
    logW("Can't open accessory!");
    return false;
}
FileDescriptor fd = mParcelFD.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);

All in all, the AOA protocol seems to be somewhat incomplete. For example, when one end disconnects, the other one doesn’t get notified. In case of Android code, the read() call is blocking and cannot be interrupted only by new data or physical USB disconnect. But that’s another story…

Later!

Comments