[LINUX] USB device programming with native C on Android 5.0 and above

I want to handle USB devices with C library on Android Lolipop or later

Since Lolipop, Android devices are based on SELinux, so it's a little difficult to handle Permission. This article describes the points to note when using / writing a library in C language that handles USB devices on an Android device as a USB host.

Why C language?

Traditionally, the layers closer to device drivers are mostly libraries written in C. Since Android is a derivative of Linux, it is the same in that it handles usbfs for USB drivers, and basically you can use libraries related to Linux USB devices. There is no need to reinvent the wheel using Android's unique USB library.

Constraints in C

For example, libusb is a C library that handles USB devices on Android, but libusb's [README](https://github. If you look at com / libusb / libusb / blob / master / android / README), you will see the following.

The default system configuration on most Android device will not allow access to USB devices. There are several options for changing this.

If you have control of the system image then you can modify the ueventd.rc used in the image to change the permissions on /dev/bus/usb//. If using this approach then it is advisable to create a new Android permission to protect access to these files. It is not advisable to give all applications read and write permissions to these files.

For rooted devices the code using libusb could be executed as root using the "su" command. An alternative would be to use the "su" command to change the permissions on the appropriate /dev/bus/usb/ files.

Users have reported success in using android.hardware.usb.UsbManager to request permission to use the UsbDevice and then opening the device. The difficulties in this method is that there is no guarantee that it will continue to work in the future Android versions, it requires invoking Java APIs and running code to match each android.hardware.usb.UsbDevice to a libusb_device.

Indeed, SELinux restricts access under / dev / bus / usb /, so the approach is written that you should do your best by giving permission yourself. This is correct when viewed as Android as SELinux, but it is out of focus for the majority of Android app developers who have to develop without root privileges. Of course, this information alone is difficult to solve.

Procedure with libusb etc.

Normally, when using the C library, the program is as follows.

  1. Open the port and get the file descriptor.
  2. Load the USB Descriptor of the device using the file disk printer. (Reference: SyncHack-USB / Descriptor)
  3. Identify the USB interface or USB endpoint from the USB Descriptor and communicate with the device.

usb.c


const char* port_name = "/dev/bus/usb/000/001"; //USB device(It changes every time you connect, so actually search etc.)
int fd; //File disk printer
int rc;
int n_read;
byte[] desc; //Storage location of USB Descriptor

fd = open(port_name, 0_RDWR); //Port open
...
rc = read(fd, desc, n_read); //First loading of USB Descriptor
...

Problems with this code-permissions

This code works fine on Android devices as long as you can run it with root privileges or customize your device. However, on a non-root terminal, opening a port causes a permission error and it does not work. Then what should we do?

Workaround

If you follow the steps to access a USB device on the Android SDK, you can get permission to the device properly. How to get access to a USB device normally on the Android SDK is described in USB Host of Developer Guide. If you follow the procedure, you can get it without any problem. If you don't use the C library, [ʻUsbManager](https://developer.android.com/reference/android/hardware/usb/UsbManager.html), [ʻUsbDevice](https://developer. android.com/reference/android/hardware/usb/UsbDevice.html), [ʻUsbDeviceConnection](https://developer.android.com/reference/android/hardware/usb/UsbDeviceConnection.html) Just go. However, for example, even if you execute the above ʻusb.c after executing ʻUSBManager # openDevice (), an error will occur. This is because there is actually a file disk printer issued inside the SDK when ʻopenDevice () is executed, and access only via that is permitted. It is not allowed to open a new file, and it is necessary to use only the file disk printer. The file descriptor can be obtained with ʻUsbDeviceConnection # getFileDescpritor () ](https://developer.android.com/reference/android/hardware/usb/UsbDeviceConnection.html#getFileDescriptor ()). There is also a [libusb branch](https://github.com/kuldeepdhaka/libusb/tree/android-open2) that supports this "reuse of file disk preta". Get from the SDK world to the argument of the function [ʻop_open2 () as below It is designed to give a file descriptor.

static int op_open2(struct libusb_device_handle *handle, int fd)

Further issues-USB Descpritor

Now, even if you reuse the file disk printer, another problem will occur. That is, I / O error occurs when reading the USB Descpritor. Actually, the SDK reads the USB Descpritor at the same time as ʻUSBManager # openDevice (), so if you reuse the file disk preta, it has already been read and you cannot read it with your own code. So where did the loaded USB Descriptor go? [ʻUSBDeviceConnection # getRawDescpritors () ](https://developer.android.com/reference/android/hardware/usb/UsbDeviceConnection.html#getRawDescriptors ()) It can be taken out with.

Completed form

So, it was confirmed that if the C library of the USB device is used by the following procedure, the existing library can be used while avoiding the permission problem and the USB Descpritor problem.

Usb.java


UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();  
for(UsbDevice device : deviceList.values()) {
  if(device.getVenforId() == 0xZZ && device.getProductId() == 0xYY) { //When controlling by product specification
    UsbDeviceConnection connection = manager.openDevice(device); //Open at this point(), read()Is being executed.
    int fd = connection.getFileDescptitor(); //Communicatable file disk printers allowed by the SDK
    byte[] descpritors = connection.getRawDescpritors(); //Device, Configuration, Interface,Includes all Descpritors such as Endpoint
    callJNIUsbLib(fd, descpritors); //It can be processed by passing these two pieces of information to the JNI side.
  }
}

On the C library side, the implementation should be "use the file disk pretter instead of opening the file" and "use the one passed without acquiring the USB Descpritor".

Recommended Posts

USB device programming with native C on Android 5.0 and above
Create and run Discord Bot on one Android device
Programming with Python and Tkinter
Solving with Ruby and Python AtCoder ABC011 C Dynamic programming
Import of japandas with pandas 1.0 and above
X86 assembler on Linux (linkage with C)
A memo with Python2.7 and Python3 on CentOS
[C] [python] Read with AquesTalk on Linux
Programming normally with Node-RED programming on Raspberry Pi 3
Share VLC playlists on PC and Android
RaspberryPi L Chika with Python and C #