Introduction to Waydroid and Custom USB Peripherals
Waydroid provides a convenient and performant method for running Android within a Linux environment, leveraging containerization technologies like LXC. While it excels at general Android application execution, supporting custom USB peripherals – especially those not natively recognized by the Android Open Source Project (AOSP) kernel or requiring specific drivers – presents a unique challenge. This guide delves into the expert-level techniques required to achieve USB passthrough and subsequently reverse engineer the device’s interaction within the Waydroid environment, focusing on using adb over USB passthrough for virtualized Android.
The Challenge of USB Passthrough in Waydroid
Waydroid’s architecture isolates the Android system within a container. This isolation, while beneficial for security and stability, means direct hardware access, particularly for USB devices, is not straightforward. Standard container approaches often virtualize or abstract away hardware. For custom peripherals, direct access to the device’s raw USB endpoints or specific drivers is crucial. This often necessitates a method to ‘pass through’ the USB device from the host Linux system directly into the Waydroid container, making it appear as a natively connected device to the Android system. The usbip project provides an elegant solution for this, allowing USB devices to be shared over a network, effectively creating a virtual USB bus.
Prerequisites and Setup
Host System Requirements
Ensure your host Linux system has the necessary tools and kernel modules. You’ll need usbip-utils, which provides the command-line interface for the usbip protocol, and the relevant kernel modules loaded.
sudo apt update && sudo apt install usbip-utils
Confirm the usbip service is running if your distribution manages it (though direct module loading and command execution is often sufficient).
Identifying Your USB Device
Before passthrough, you must identify your target USB device. Plug the device into your host machine and use the lsusb command to list all connected USB devices. Note down its Bus ID, Vendor ID (VID), and Product ID (PID). The Bus ID (e.g., 1-1) is critical for binding.
lsusb
Example output:
Bus 001 Device 002: ID 046d:c077 Logitech, Inc. M105 Optical MouseBus 001 Device 003: ID 1a86:7523 QinHeng Electronics CH340 serial converter
In this example, the CH340 serial converter has Bus ID 1-3 (assuming it appeared as Device 003 on Bus 001) and VID:PID 1a86:7523.
Preparing the Host for USB Passthrough
Loading USBIP Kernel Modules
Load the required usbip kernel modules on your host system. These modules enable your host to act as a usbip server.
sudo modprobe usbip_coresudo modprobe usbip_host
You can verify they are loaded using lsmod | grep usbip.
Exporting the USB Device
First, list the locally connected USB devices that are available for binding. You’ll need the Bus ID noted earlier.
sudo usbip list -l
This command will show devices with their Bus IDs (e.g., 1-1, 1-2, etc.). Once you’ve identified your device’s Bus ID, bind it to the usbip_host driver. This makes the device available for remote attachment.
sudo usbip bind --busid=1-3 # Replace 1-3 with your device's Bus ID
After binding, verify that the device is now exported and ready for attachment by listing available remote devices (even if connecting to localhost):
sudo usbip list -r 127.0.0.1
You should see your device listed, indicating it’s successfully exported.
Connecting to Waydroid and Attaching the Device
Accessing the Waydroid Container Shell
To interact with Waydroid’s internal system, you’ll need a shell within the container. If Waydroid is running, you can access its shell directly.
sudo waydroid shell
This drops you into the Android shell, where you have root privileges.
Loading USBIP Modules within Waydroid
Inside the Waydroid shell, you need to load the client-side usbip modules, which enable the container to act as a usbip client.
modprobe usbip_stubmodprobe vhci_hcd
These modules allow Waydroid to receive a virtual USB device from the host.
Attaching the USB Device
Now, from within the Waydroid shell, attach the exported device from the host. Waydroid typically uses a network bridge (e.g., waydroid0) with the host acting as the gateway (often 192.168.240.1) and the Waydroid container having an IP like 192.168.240.2. You will attach to the host’s IP address on this internal network.
usbip attach -r 192.168.240.1 -b 1-3 # Use your device's Bus ID
Upon successful attachment, you should see output indicating a new virtual USB device has been added.
Verifying USB Passthrough and ADB Connectivity
Device Presence Check
Inside the Waydroid shell, run lsusb again. Your device should now appear as if it were directly connected to the Android system.
lsusb
You should see the VID:PID of your device. For example:
Bus 001 Device 002: ID 1a86:7523 QinHeng Electronics CH340 serial converter
ADB Connection Verification
If your device is an Android phone or development board you want to debug, ensure ADB debugging is enabled in Waydroid’s developer options. Then, from your *host* system, check for connected ADB devices:
adb devices
You should see your Waydroid instance (and potentially the passed-through device if it’s an ADB-capable device) listed.
Reverse Engineering USB Device Interaction
Once the USB device is successfully passed into Waydroid, the next step is to understand how Android and applications interact with it. This is where the reverse engineering process begins.
Monitoring System Logs with logcat
logcat is your primary tool for observing application and system-level events related to your USB device. You can filter for USB-related messages or messages from your specific application.
adb logcat | grep -i usb # General USB messagesadb logcat -s MyUsbApp:V *:S # Filter for a specific app's verbose output
Look for messages indicating device discovery, permission requests (if the app uses UsbManager), data transfer attempts, or errors. Many apps will log their interaction with peripherals, which can reveal the sequence of commands or data exchanged.
Observing Device Nodes
Android’s Linux kernel exposes hardware devices as special files in the /dev directory. Depending on your peripheral’s type, it will create different device nodes. Knowing these can help in understanding how an app is interacting:
- Raw USB devices: Found under
/dev/bus/usb/. Direct access is less common for apps, but useful for system-level tools. - Serial devices: Often appear as
/dev/ttyUSB0,/dev/ttyACM0, etc. If your device is a serial-to-USB converter, an app might open and communicate with this node. - HID devices: Human Interface Devices (keyboards, mice, gamepads) often show up as
/dev/hidraw0,/dev/input/eventX.
ls -l /dev/bus/usb/ls -l /dev/ttyUSB* /dev/ttyACM* /dev/hidraw*
Observing which nodes appear or change after device attachment and during app interaction can pinpoint the communication channel.
Leveraging dmesg for Kernel Messages
The kernel’s message buffer provides low-level insights into device enumeration, driver loading, and any hardware-related errors. This can be crucial if your device isn’t behaving as expected, indicating driver issues or hardware malfunctions.
dmesg | grep -i usb
Look for messages indicating successful device registration, driver binding (e.g., cdc_acm for serial devices, usbhid for HID), or errors during initialization.
Analyzing Application Behavior
If you are developing an app or have access to the target app’s source code, investigate its use of the android.hardware.usb API. Pay attention to:
UsbManager: How the app requests device lists, permissions, and opens connections.UsbDevice,UsbInterface,UsbEndpoint: Which interfaces and endpoints the app tries to claim and communicate with.
For closed-source applications, observing logcat for messages related to these APIs (often prefixed with
Android Mobile Specs & Compare Directory
Are you researching mobile hardware properties, processor SoCs, GPU chipsets, or RAM configurations? Access our complete specs catalog to compare up to 5 devices side-by-side!
Compare Devices Specs →