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
- Install a script that allows you to add emulator command line parameters.
- 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 theAVDX_EMU_PARAMS_FILE
environment variable to point the script to that file. - Start Android Studio, ensuring it has the environment variable.
- Start an AVD with a Default Android System Image.
- Run
adb root adb shell
- 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.