• Latest Articles
  • Atom Feed
  • About
  • Setting Up USB Device Pass-Through on Android Emulator on Linux Tommie's blog

    If you are trying to get a USB device to work with your Android app, it can be useful to be able to do it in an emulator. In my case, my intended tablet can’t provide enough current, so until I have a USB hub (or even Y-cable,) I could use my desktop’s USB port instead. Or so I thought. Trying to get it up and running took a few hours of reading. Here is a short history of what I tried, and a step-by-step at the end.

    The app is based on Flutter and usb_serial. I was running a virtual device (AVD) using API level 34 (UpsideDownCake), with Google APIs, the “recommended” image, on Ubuntu 22.04/x86_64.


    The basics are in the official Emulator USB passthrough integration guide. The studio.emu.params environment variable doesn’t work, because it splits on comma and joins with space, thereby ruining the -device parameters the guide suggests using.

    I created a wrapper script to add parameters to the emulator command line. No luck, though. And sadly, it seems the emulator looks for the script in only one location, ignoring PATH, so you have to keep overwriting it after upgrades. Sigh. My app was still showing no signs of seeing the USB device. And adb logcat showed no sign of USB activity.

    It turns out there is also a -usb-passthrough option to the emulator, so I don’t have to use the low-level QEMU parameters. This didn’t help, but is a nicer interface. It also uses comma, so the script is still needed.

    There is a description about using a custom USB device in a Gist by Alabate. It explains how to run a custom kernel, but the interesting piece is the /system/etc/permissions file. Trying to run adb root failed with

    adbd cannot run as root in production builds
    

    Searching for a debug build of the AVD image yielded nothing. However, this answer says the Google Play API images are really the “production builds” they are talking about. So I downloaded the Default Android System Image variant of UpsideDownCake and made the permission file changes. I couldn’t get the adb remount command to do anything useful, so did a manual remount.

    Finally, my app picked up the USB device!

    Summary

    1. Install a script that allows you to add emulator command line parameters.
    2. Set emulator parameters -usb-passthrough vendorid=0x1234,productid=0x5678 -writable-system, for whatever vendor and product IDs are. E.g. writing the emulator parameters to a file and using the AVDX_EMU_PARAMS_FILE environment variable to point the script to that file.
    3. Start Android Studio, ensuring it has the environment variable.
    4. Start an AVD with a Default Android System Image.
    5. Run
      adb root
      adb shell
      
    6. In adb: run
      mount -o remount,rw /system
      echo '<permissions><feature name="android.hardware.usb.host"/></permissions>' > /system/etc/permissions/android.hardware.usb.host.xml
      reboot
      

    Your USB device intent filters should now work. The permissions are persistent, so you only need to do this once. However, you’ll always need the -usb-passthrough command line option.