libusb_open_device_with_vid_pid failed when trying to access USB device
Asked Answered
T

4

19

I am trying to get a USB device to connect to an Android 5.1.1 device. Previously I had been using regular libusb for KitKat, but Lollipop has increased security and this no longer works.

This is well documented, requiring root to set the SELinux level. I do not want to have to root the device to get the USB device to connect to it.

Having looked around, I came across this answer and I have tried this libusb fork, however now I am getting a new error

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

I have not changed any of the code, only the library.

Is this still a permission issue, or is there something I'm missing that will make this work?

Telegu answered 4/6, 2015 at 16:43 Comment(0)
P
14

The following steps can be used to solve the issues you mentioned.

The process of mounting the device as USB mass storage is inconsistent across devices and manufacturer-specific. Some devices like the Nexus S offer to "Turn on USB storage" when you connect the device to the desktop via USB cable. Other devices like the Galaxy S3 require an app now to launch the device as mass storage. Either way, Android devices typically offer such a feature, and you’ll have to create a file that matches your device's manufacturer specification.

You need to add to your application's manifest file before working with the USB host APIs:

  • Because not all Android-powered devices are guaranteed to support the USB host APIs, include an element that declares that your application uses the android.hardware.usb.host feature.
  • If you want your application to be notified of an attached USB device, specify an and element pair for the android.hardware.usb.action.USB_DEVICE_ATTACHED intent in your main activity.

Add USB_DEVICE_ATTACHED to your manisfest file:

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

To help your APP discover a particular USB device you can use intent filter:

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

You have also to specify your device and vendor id:

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

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

This should be enough to deal with your USB host connection. Now call USB:

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

Use the descriptor to open connection to the usb device - e.g.:

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);

If you still have problems with SELinux level, here you have some edits you can use to make your program run smoothly:

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

As SELinux is by default set to enforce highest security, and you want to grant a client access to your Android device through USB.

enter image description here

Depending on your Android make and model, try unplugging the USB cable connecting your device and the desktop, and plug it back in. You should be prompted to "Turn on USB" storage. If this is the case, go ahead and try browsing to Settings → More... on the Android, and look for an USB mass storage option.

enter image description here
(source: pocketables.com)

Alternatively look for the USB mass storage process recommended by your device manufacturer. When you Turn on USB storage , the device let’s you know that some apps will stop, go ahead and OK that. Now move over to your desktop computer and browse to your USB mass storage medium, often called NO NAME if you’ve not renamed it. Click on your mass storage device, and right there in the foot folder, find a file called data.tsv .

enter image description here

You can also check data.tsv by opening it in your favorite text editor. You’ll find two columns there neatly separated by a tab; in each row, you’ll find a pair of integer values. This is perfectly sufficient for our project. More complex data projects typically require a unique identifier for each row, a row in one table to point to a specific record in another.

enter image description here

According to your 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 your device for development.

enter image description here

In addition, is also worth to mention that many previously released Android-powered devices are only capable of acting as a USB device and cannot initiate connections with external USB devices. Android Open Accessory (AOA) support overcomes this limitation and allows you to build accessories that can interact with an assortment of Android-powered devices by allowing the accessory to initiate the 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 - which of course requires the USB mode to be up and running.

enter image description here

Putting Android to communicate through USB with Arduino microcontrolers is also a type of implementation that showed to become very successful most recently, as it allows you to extend your Android capabilities integrating additional features through a multi-device solution approach. A typical Arduino Sketch to allow the device communication with your Android USB would look like this:

// 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);
}

All Arduino projects must have a setup() and a loop() method declared otherwise your Android will not communicate properly.

Also remember that a list of minimum requirements needed to use AOA:

  • An AOA-compatible Android device. To test compatibility before trying this example, please refer to the “Supported Android Devices” section for links to the Microchip AOA demonstration apps available on the Google Play.
  • A compatible microcontroller board. The Arduino Mega ADK would be an easy option if you are unsure.

enter image description here

Possibilities of Android devices using USB are amazing, and the demand for innovative APPs that are capable of taking full advantage such features is set to grow remarkably.

Pajamas answered 20/6, 2015 at 9:42 Comment(2)
Does this work for UsbDevice as well as UsbAccessory?Telegu
Yes it works. But for UsbAccessry you have to use USB_ACCESSORY_ATTACHED intent.Pajamas
S
1

Your error is not related to permissions is related to I/O, the -1 error is equivalent to

LIBUSB_ERROR_IO - Input/output error. 

You can modifiy the JNI interface to put libusb in debug mode calling libusb_set_debug(), I think that is the one and only way to know what's really happening.

Anyway, first check you VID/PID to ensure that is on the list of connected devices.

Schade answered 19/6, 2015 at 11:41 Comment(0)
A
0

On Android, you can't use libusb_open_device_with_vid_pid without root. To get access to an USB device, you must use UsbDeviceManager Android API.

The only example I know of public source code connecting libusb to Android without root is: https://github.com/martinmarinov/rtl_tcp_andro-/

You won't ever get read/write access to /dev/bus/usb/xxx/yyy. Android's way of doing it, is a system services sends you, via binder, an already open file descriptor on the specific /dev/bus/usb/xxx/yyy device you asked for.

There are already plenty of documentations on how to handle UsbHost from java in Android, so I'll point to what's left after that.

  • You need a patched libusb (the one in rtl_tcp_andro- will do), which can take a filedescriptor instead of a device name/pid/vid
  • You need to call libusb_open2 (that's how this new function with fd is called in rtl_tcp_andro's libusb) with the fd you'll retrieve with UsbDeviceConnection.getFileDescriptor()

Edit: I'm seeing rtl_tcp_andro- also added a libusb_init2, I'm don't understand why ATM, but the commit says it's for L support, so I guess it's also needed.

Athanasius answered 20/6, 2015 at 13:20 Comment(0)
E
0

That usb patch mentioned in question works in next way:

  1. you MUST open device by UsbManager
  2. open by libusb
  3. close by libusb
  4. close by UsbManager

exactly that order will work.

Encarnalize answered 14/5, 2016 at 3:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.