【问题标题】:USBFS IOCTL call witn JNA doesn't work in 64 bits architectures带有 JNA 的 USBFS IOCTL 调用在 64 位架构中不起作用
【发布时间】:2019-07-18 06:48:12
【问题描述】:

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

在具有 32 位架构的 Android 设备(armeabi、armeabi-v7a)中,一切正常。在具有 64 位架构 (arm64-v8a) 的 Android 设备中,对 reap URB (USBDEVFS_REAPURB,reapRequest 方法内部,请参见下面的相关代码) 的 ioctl 调用返回错误 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; 
            }
        }
...

}

【问题讨论】:

    标签: java android usb jna


    【解决方案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 字节 vs. 4 字节,所以 setUserContext()getUserContext() 需要处理 long 而不是 inturbBaseSize 需要从 44 递增到 52(+ buffer 为 4,userContext 为 +4。

    我看到了一些其他的int 变量,它们表示需要变为longs 的内存地址。我可能错过了其他一些更改。

    【讨论】:

      【解决方案2】:

      正如 Peter Stoiber 对 other question 的最后一个答案所述,有一个类可以解决这个问题:https://github.com/Peter-St/Android-UVC-Camera/tree/master/app/src/main/java/humer/uvc_camera/UsbIso64

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-14
        • 2019-03-16
        • 1970-01-01
        • 2014-12-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多