libusb_open_device_with_vid_pid 尝试访问 USB 设备时失败

libusb_open_device_with_vid_pid failed when trying to access USB device

我正在尝试让 USB 设备连接到 Android 5.1.1 设备。以前我一直在为 KitKat 使用常规的 libusb,但 Lollipop 提高了安全性,这不再有效。

这有据可查,需要 root 设置 SELinux 级别。我不想让 USB 设备连接到设备上。

环顾四周,我遇到了 this answer and I have tried this libusb fork,但是现在我收到了一个新错误

libusb_open_device_with_vid_pid (29c2) failed.
Failed to setup USB
usb_setup: -1

我没有更改任何代码,只更改了库。

这仍然是一个权限问题,还是我遗漏了一些可以使这项工作成功的东西?

您的错误与权限无关与 I/O 有关,-1 错误等同于

LIBUSB_ERROR_IO - Input/output error. 

您可以修改 JNI interface 以将 libusb 置于调试模式调用 libusb_set_debug(),我认为这是唯一了解实际情况的方法。

无论如何,请先检查您 VID/PID 以确保它在已连接设备列表中。

以下步骤可用于解决您提到的问题。

将设备挂载为USB大容量存储的过程不一致 跨设备和特定于制造商。当您通过 USB 数据线将设备连接到桌面时,某些设备(如 Nexus S)会提供 "Turn on USB storage"。其他设备(如 Galaxy S3)现在需要一个应用程序才能将设备作为大容量存储器启动。无论哪种方式,Android 设备通常都提供此类功能,您必须创建一个符合设备制造商规格的文件。

在使用 USB 主机 API 之前,您需要添加到应用程序的清单文件中:

  • 因为并非所有 Android 驱动的设备都保证支持 USB 主机 API,因此请包含一个元素来声明您的应用程序使用 android.hardware.usb.host 功能。
  • 如果您希望应用程序收到连接的 USB 设备的通知,请在主 activity.
  • 中为 android.hardware.usb.action.USB_DEVICE_ATTACHED 意图指定一个和元素对

将 USB_DEVICE_ATTACHED 添加到您的清单文件:

<manifest ...>
    <uses-feature android:name="android.hardware.usb.host" />
    <uses-sdk android:minSdkVersion="12" />
    ...
    <application>
        <activity ...>
            ...
            <intent-filter>
                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
            </intent-filter>

            <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
            android:resource="@xml/device_filter" />
        </activity>
    </application>
</manifest>

为了帮助您的应用发现特定的 USB 设备,您可以使用 Intent 过滤器:

<activity ...>
    ...
    <intent-filter>
        <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
    </intent-filter>

    <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
    android:resource="@xml/device_filter" />
</activity>

您还必须指定您的设备和供应商 ID:

<?xml version="1.0" encoding="utf-8"?>

<resources>
    <usb-device vendor-id="1234" product-id="5678" />
</resources>

这应该足以处理您的 USB host 连接。现在调用 USB:

int LIBUSB_CALL libusb_open2(libusb_device *dev, libusb_device_handle **handle, int fd);

使用描述符打开与 usb device 的连接 - 例如:

UsbManager myUsbManager = (UsbManager) 
getSystemService(Context.USB_SERVICE);
UsbAccessory myUsbAccessory = (myUsbManager.getAccessoryList())[0];
ParcelFileDescriptor pfd = myUsbManager.openAccessory(myUsbAccessory);
FileDescriptor fileDescriptor = pfd.getFileDescriptor();
FileInputStream myFileInputStream = new FileInputStream(fileDescriptor);
FileOutputStream myFileOutputStream = new FileOutputStream(fileDescriptor);

如果您在 SELinux 级别上仍然有问题,这里有一些编辑可以用来使您的程序 运行 顺利进行:

// default.prop
ro.secure=1              -----------------> ro.secure=0
ro.adb.secure=1        -----------------> ro.adb.secure=0

//init.rc
setsebool debugfs 1   --------> setsebool debugfs 0
setenforce 0
setprop selinux.reload_policy 1  ------->  setprop selinux.reload_policy 0

// init.target.rc
setprop selinux.reload_policy 1   ----->  setprop selinux.reload_policy 0

由于 SELinux 默认设置为强制执行最高安全性,并且您希望授予客户端通过 USB 访问您的 Android 设备的权限。

根据您的 Android 品牌和型号,尝试拔下连接设备和桌面的 USB 电缆,然后重新插入。系统会提示您 "Turn on USB" 存储。如果是这种情况,请继续尝试在 Android 上浏览至 设置 → 更多...,然后寻找 USB 大容量存储选项。


(来源:pocketables.com

或者寻找您的设备制造商推荐的 USB 大容量存储过程。当您打开 USB 存储时,设备会让您知道某些应用程序将停止,继续并确定。现在转到您的台式计算机并浏览到您的 USB 大容量存储介质,如果您没有重命名它,通常称为 NO NAME。单击您的大容量存储设备,然后在 foot 文件夹中找到一个名为 data.tsv .

的文件

您还可以通过在您喜欢的文本编辑器中打开它来检查 data.tsv。您会发现那里有两列,用制表符整齐地分隔开;在每一行中,您都会找到一对整数值。这对我们的项目来说已经足够了。更复杂的数据项目通常需要每一行的唯一标识符,一个中的一行 table 指向另一个中的特定记录。

根据你的development environment, you also have to tune your settings accordingly. If you are developing on Windows, follow the USB driver installation instructions available. If you are developing on Linux, follow the instructions for setting up你的设备进行开发。

此外,还值得一提的是,之前发布的许多Android供电设备只能充当USB设备,无法与外部USB设备建立连接。 Android 开放配件 (AOA) 支持克服了这一限制,并允许您构建可以与各种 Android 供电设备交互的配件,方法是允许配件启动 connection. An example of common use of Android Open Accessory can be found in the project: record and play back audio using USB host mode - 其中当然需要 USB 模式启动并 运行ning.

让 Android 通过 USB 与 Arduino 微控制器通信也是一种最近非常成功的实施方式,因为它允许您扩展 Android 功能通过多设备解决方案方法集成附加功能。允许设备与您的 Android USB 通信的典型 Arduino Sketch 如下所示:

// the USB Host libraries
#include <Max3421e.h>
#include <Usb.h>
// the AOA library
#include <AndroidAccessory.h>

void setup();
void loop();

void setup()
{   // start serial debugging
    Serial.begin(115200);
    Serial.print("\r\nADK has run setup().");
    Serial.println("Ready to start USB communication...");
}

void loop()
{   // example - read the voltage from a sensor
    uint16_t val;
    val = analogRead(TEMP_SENSOR); // or any sort of input
    Serial.println(val,HEX);
    Serial.write(val);
    // Delay for 100 milliseconds.
    delay(100);
}

所有 Arduino 项目都必须声明一个 setup() 和一个 loop() 方法,否则您的 Android 将无法正常通信。

还要记住使用 AOA 所需的最低要求列表:

  • AOA 兼容 Android 设备。要在尝试此示例之前测试兼容性,请参阅“支持的 Android 设备”部分以获取指向 Google Play 上可用的 Microchip AOA 演示应用程序的链接。
  • 兼容的微控制器板。如果您不确定,Arduino Mega ADK 将是一个简单的选择。

Android 设备使用 USB 的可能性是惊人的,对能够充分利用这些功能的创新应用程序的需求将显着增长。

在 Android 上,没有 root 用户无法使用 libusb_open_device_with_vid_pid。 要访问 USB 设备,您必须使用 UsbDeviceManager Android API.

我所知道的 public 将 libusb 连接到 Android 的源代码的唯一示例是:https://github.com/martinmarinov/rtl_tcp_andro-/

您将永远无法 read/write 访问 /dev/bus/usb/xxx/yyy。 Android 的做法是系统服务通过活页夹向您发送在您要求的特定 /dev/bus/usb/xxx/yyy 设备上已经打开的文件描述符。

Android 中 java 已经有很多关于如何处理 UsbHost 的文档,所以我会指出在那之后剩下的内容。

  • 你需要一个打过补丁的 libusb(rtl_tcp_andro- 中的那个就可以),它可以使用文件描述符而不是设备 name/pid/vid
  • 您需要调用 libusb_open2(这就是在 rtl_tcp_andro 的 libusb 中调用带有 fd 的新函数的方式),您将使用 UsbDeviceConnection.getFileDescriptor()

编辑:我看到 rtl_tcp_andro- 也添加了一个 libusb_init2,我不明白为什么 ATM,但提交说它是为了 L 支持,所以我想它也是需要的.

问题中提到的那个 usb 补丁在接下来的工作方式中:

  1. 您必须通过 UsbManager 打开设备
  2. 通过 libusb 打开
  3. libusb 关闭
  4. 关闭 UsbManager

正是这个顺序有效。