JNA无法在64位体系结构中使用USBFS IOCTL调用

时间:2019-07-18 06:48:12

标签: java android usb jna

在Android中,我正在使用类(UsbIso.java)从连接的USB设备以等时方式传输数据。由于Android本身不支持同步传输,因此我不得不通过JNA库使用USBFS本机Linux机制进行正确的ioctl调用。

在具有32位架构(armeabi,armeabi-v7a)的Android设备上,所有功能均正常运行。在具有64位体系结构(arm64-v8a)的Android设备中,要获取URB的ioctl调用(reapRequest方法内部的USBDEVFS_REAPURB,请参见下面的相关代码)将返回错误14,错误的地址。我猜这是由USBDEVFS_REAPURB参数或PointerByReference参数引起的,该参数指向无效的虚拟地址,但是我不知道如何解决它。

UsbIso.java类中导致此错误的相关代码是:

public Request reapRequest (boolean wait) throws IOException {
        PointerByReference urbPointer = new PointerByReference();
        int func = wait ? USBDEVFS_REAPURB : USBDEVFS_REAPURBNDELAY;
        int rc;
        try {
            rc = libc.ioctl(fileDescriptor, func, urbPointer);  // <-- Error 14, bad address
        } catch (LastErrorException e) {
            if (e.getErrorCode() == EAGAIN && !wait) {
                return null; 
            }
        }
...

}

2 个答案:

答案 0 :(得分:1)

您正在使用针对32位进行了优化的源代码:

// Note: The layout and size of the USBFS structures matches that of Linux Kernel 3.2 and 3.14
// for ARM 32 bit. For other environments (X86, 64 bit, future Linux kernels), it might be
// necessary to adjust some values.

尽管JNA通常会针对32位和64位调整结构映射,但此代码认为JNA太慢,因此需要手动映射这些偏移量:

// This class is modeled after struct usbdevfs_urb in <linuxKernel>/include/linux/usbdevice_fs.h
// At first I implemented the URB structure directly using com.sun.jna.Structure, but that was extremely slow.
// Therefore byte offsets are now used to access the fields of the structure.

如果您查看structure mapping for usbdevfs_urb,则有3个指针字段需要从4字节偏移量调整为8字节偏移量。例如,第5个字段buffer从4个字节更改为8个字节,因此此代码中断:

   public void setBuffer (Pointer buffer) {
      urbBuf.putInt(12, (int)Pointer.nativeValue(buffer)); }
   public void setBufferLength (int bufferLength) {
      urbBuf.putInt(16, bufferLength); }

特别是,putInt(12, (int) ...)应该是putLong(12, ...),下一次调用中的16应该是20(以此类推,将剩余的偏移量加4。)

最后两个字段也是8字节和4字节,因此setUserContext()getUserContext()需要处理long而不是int和{{1 }}需要从44增至52(urbBaseSize为+4,buffer为+4。

我看到另外一些userContext变量,它们代表需要成为int的内存地址。我可能还需要其他更改。

答案 1 :(得分:0)

正如彼得·斯托伯(Peter Stoiber)在此other question的最后答案中所述,存在一个可解决此问题的类:https://github.com/Peter-St/Android-UVC-Camera/tree/master/app/src/main/java/humer/uvc_camera/UsbIso64