【问题标题】:libusb_open_device_with_vid_pid failed when trying to access USB device尝试访问 USB 设备时 libusb_open_device_with_vid_pid 失败
【发布时间】:2015-08-19 09:41:52
【问题描述】:

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

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

环顾四周,我遇到了this answer,我尝试了this libusb fork,但是现在我遇到了一个新错误

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

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

这仍然是权限问题,还是我遗漏了什么可以使这项工作正常进行?

【问题讨论】:

    标签: java android android-ndk java-native-interface libusb-1.0


    【解决方案1】:

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

    将设备挂载为USB大容量存储的过程不一致 跨设备和特定制造商。当您通过 USB 电缆将设备连接到桌面时,某些设备(如 Nexus S)会提供“打开 USB 存储”。 Galaxy S3 等其他设备现在需要一个应用程序才能将该设备作为大容量存储启动。无论哪种方式,Android 设备通常都提供这样的功能,您必须创建一个符合您设备制造商规范的文件。

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

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

    将 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>
    

    为了帮助您的 APP 发现特定的 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 数据线,然后重新插入。系统应该会提示您“打开 USB”存储。如果是这种情况,请继续尝试在 Android 上浏览到 设置 → 更多...,然后寻找 USB 大容量存储选项。


    (来源:pocketables.com

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

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

    根据您的development environment,您还必须相应地调整您的设置。如果您在 Windows 上开发,请按照 USB 驱动程序安装instructions available。如果您在 Linux 上进行开发,请按照setting up 您的设备的说明进行开发。

    另外,还值得一提的是,之前发布的很多Android驱动的设备只能充当USB设备,无法发起与外部USB设备的连接。 Android 开放式附件 (AOA) 支持克服了这一限制,并允许您通过允许附件启动 connection 来构建可以与各种 Android 设备进行交互的附件。在项目中可以找到 Android Open Accessory 的常见用法示例:使用 USB host mode 录制和播放音频 - 当然这需要 USB 模式启动并运行。

    让 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 将是一个简单的选择。

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

    【讨论】:

    • 这对UsbDeviceUsbAccessory 是否有效?
    • 是的,它有效。但是对于 UsbAccessry,您必须使用 USB_ACCESSORY_ATTACHED 意图。
    【解决方案2】:

    有问题提到的那个usb补丁可以通过下一个方式工作:

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

    该命令确实有效。

    【讨论】:

      【解决方案3】:

      在 Android 上,您不能在没有 root 的情况下使用 libusb_open_device_with_vid_pid。 要访问 USB 设备,您必须使用 UsbDeviceManager Android API。

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

      您将永远无法获得对 /dev/bus/usb/xxx/yyy 的读/写访问权限。 Android 的做法是,系统服务通过 binder 向您发送您请求的特定 /dev/bus/usb/xxx/yyy 设备上已经打开的文件描述符。

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

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

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

      【讨论】:

        【解决方案4】:

        你的错误与权限无关,与I/O有关,-1错误相当于

        LIBUSB_ERROR_IO - Input/output error. 
        

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-11-07
          • 2011-07-08
          • 2021-03-04
          • 1970-01-01
          • 2014-04-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多