USBFS IOCTL 调用 witn JNA 在 64 位架构中不起作用
USBFS IOCTL call witn JNA doesn't work in 64 bits architectures
在 Android 中,我使用 class (UsbIso.java) 从连接的 USB 设备以同步方式传输数据。由于 Android 本身不支持同步传输,我不得不通过 JNA 库使用 USBFS 本机 Linux 机制来进行正确的 ioctl 调用。
在 Android 具有 32 位架构的设备(armeabi、armeabi-v7a)中一切正常。 Android 64 位架构设备 (arm64-v8a) ioctl 调用 reap URB (USBDEVFS_REAPURB, 在 reapRequest 方法中, 见下面的相关代码) returns 错误 14, 错误地址.我猜这是由 USBDEVFS_REAPURB 参数或 PointerByReference 参数引起的,它指向一个无效的虚拟地址,但我不知道如何解决它。
导致这个错误的UsbIso.javaclass中的相关代码是这样的:
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;
}
}
...
}
您正在使用针对 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
和urbBaseSize
需要从 44 增加到 52([=14=+4],[=23=+4]。
我看到其他一些 int
变量代表需要变成 long
的内存地址。我可能错过了其他需要更改的地方。
如本other question by Peter Stoiber, there exists a class which solves this problem: https://github.com/Peter-St/Android-UVC-Camera/tree/master/app/src/main/java/humer/uvc_camera/UsbIso64
的最后一个答案所述
在 Android 中,我使用 class (UsbIso.java) 从连接的 USB 设备以同步方式传输数据。由于 Android 本身不支持同步传输,我不得不通过 JNA 库使用 USBFS 本机 Linux 机制来进行正确的 ioctl 调用。
在 Android 具有 32 位架构的设备(armeabi、armeabi-v7a)中一切正常。 Android 64 位架构设备 (arm64-v8a) ioctl 调用 reap URB (USBDEVFS_REAPURB, 在 reapRequest 方法中, 见下面的相关代码) returns 错误 14, 错误地址.我猜这是由 USBDEVFS_REAPURB 参数或 PointerByReference 参数引起的,它指向一个无效的虚拟地址,但我不知道如何解决它。
导致这个错误的UsbIso.javaclass中的相关代码是这样的:
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;
}
}
...
}
您正在使用针对 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
和urbBaseSize
需要从 44 增加到 52([=14=+4],[=23=+4]。
我看到其他一些 int
变量代表需要变成 long
的内存地址。我可能错过了其他需要更改的地方。
如本other question by Peter Stoiber, there exists a class which solves this problem: https://github.com/Peter-St/Android-UVC-Camera/tree/master/app/src/main/java/humer/uvc_camera/UsbIso64
的最后一个答案所述