This page describes how to connect two peripherals (Bluetooth and Wi-Fi) to the AAOS emulator. In this process, three areas specific to driver support are key:
- Guest kernel
- Guest Android
- Linux host
First, you compile and enable the relevant USB drivers in the Guest kernel. Next, Guest Android must select the right HAL and services to bring up the drivers. Finally, the Linux host must get access to the USB driver and then transfer it to QEMU.
Dongles tested
The following dongles were tested:
- ASUS USB-BT400 USB Adapter USBBT400
- USB Wi-Fi Bluetooth Adapter by Auscomer
Other dongles may work, however, no others were tested.
Native USB support
QEMU comes with options to pass USB to the emulator. The AAOS system image already handles a connected phone. For details, see Android Open Accessory (AOA).
Because the phone changes values for vendorID
and productID
upon
establishing an AOA connection, the new USB interface (as well as the original
USB interface) sees the device when the phone is in AOA mode.
To determine the values for vendorID
and productID
before and after AOA
mode, use lsusb
:
# Note Vendor ID and Product ID of your phone
$ lsusb
Bus 001 Device 079: ID 18d1:4ee1 Google Inc. Nexus/Pixel Device (MTP)
# Start up an emulator!
$ ./emulator @AVD_NAME -no-snapshot -qemu -device usb-ehci,id=ehci -device usb-host,bus=ehci.0,vendorid=0x18d1,productid=0x4ee1 -device usb-host,bus=ehci.0,vendorid=0x18d1,productid=0x2d00
Alternatively, pass the physical port to QEMU:
# First plug something into the interested USB port and note the Bus and Device number.
$ lsusb
Bus 001 Device 012: ID 0bda:c820 Realtek Semiconductor Corp. 802.11ac NIC
# Now figure out where the Port number is.
$ lsusb -t
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/12p, 480M
|__ Port 4: Dev 12, If 1, Class=Wireless, Driver=btusb, 480M
|__ Port 4: Dev 12, If 2, Class=Vendor Specific Class, Driver=, 480M
|__ Port 4: Dev 12, If 0, Class=Wireless, Driver=btusb, 480M
# Launch the emulator
./emulator @AVD_NAME -no-snapshot -qemu -device usb-ehci,id=ehci -device usb-host,bus=ehci.0,hostbus=1,hostport=4
# Now, whatever you plug into the emulator, USB passthrough will happen on the fly.
The AAOS system image recognizes the phone, puts it in AOA mode, and recognizes it again when AOA mode is running.
To support USB passthrough, confirm you're using Emulator 30.5.0:
# Check for the emulator version
$ emulator --version
Emulator 30.5.0 includes a libusb
upgrade and temporary workaround to
address speed compatibility of ASUS dongle support:
- https://android-review.googlesource.com/c/platform/external/qemu/+/1573247
- https://android-review.googlesource.com/c/platform/external/qemu/+/1580924
- https://android-review.googlesource.com/c/platform/external/libusb/+/1580923
Bluetooth support
To support Bluetooth passthrough, Google tested ASUS USB-BT400 USB Adapter USBBT400 and USB Wi-Fi Bluetooth Adapter by Auscomer.
First, you need to add kernel support for the dongle. To understand the Android Bluetooth stack, see Bluetooth. For HIDL, the emulator uses simulated implementation. Therefore, switch that with a native Linux implementation.
Guest kernel
To support a USB Bluetooth dongle:
Add the missing
btusb.ko
to your kernel:--- a/goldfish_defconfig.fragment +++ b/goldfish_defconfig.fragment @@ -1,6 +1,7 @@ # CONFIG_CRYPTO_DEV_VIRTIO is not set CONFIG_BLK_DEV_MD=m +CONFIG_BT_HCIBTUSB=m CONFIG_CPUFREQ_DUMMY=m
Guest Android
In the
vendor.mk
file, include the Linux native HIDL and several permissions:PRODUCT_PACKAGES += \ android.hardware.bluetooth@1.1-service.btlinux PRODUCT_COPY_FILES += \ frameworks/native/data/etc/android.hardware.usb.host.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.usb.host.xml
Create a one-way path property to switch out the HIDL such that it uses a Linux native HIDL implementation:
selinux/common/domain.te get_prop(domain, qemu_prop) +get_prop(domain, vendor_build_prop)
selinux/common/property_contexts qemu.cmdline u:object_r:qemu_cmdline:s0 +qemu.preferred.bt.service u:object_r:qemu_prop:s0
Whenever a property
qemu.preferred.bt.service
is set topassthrough
, you'll switch out the HIDL implementation:service btlinux-1.1 /vendor/bin/hw/android.hardware.bluetooth@1.1-service.btlinux class hal user bluetooth group bluetooth net_admin net_bt_admin capabilities NET_ADMIN NET_RAW SYS_NICE disabled on property:qemu.preferred.bt.service=passthrough stop vendor.bluetooth-1-1 start btlinux-1.1
Add a Bluetooth configuration file to get full features, such as on a real USB device:
hal/bluetooth/bdroid_buildcfg.h #ifndef _BDROID_BUILDCFG_H #define _BDROID_BUILDCFG_H #define BTM_DEF_LOCAL_NAME "gCar Emulator" #define BTA_AV_SINK_INCLUDED TRUE /* Handsfree device */ #define BTA_DM_COD {0x26, 0x04, 0x08} #endif
Modify the
BoardConfig.mk
file to determine where the configuration file is saved:BoardConfig.mk # Bluetooth BOARD_HAVE_BLUETOOTH := true BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR := vendor/auto/embedded/hal/bluetooth
Linux host
On the Linux host:
Update
udev
settings to allow the user process (for example, QEMU) to have read/write permissions:$ echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="0b05", ATTRS{idProduct}=="17cb", MODE="0666", GROUP="plugdev"' | sudo tee /etc/udev/rules.d/99-mynew.rules >/dev/null $ sudo udevadm control --reload $ sudo udevadm trigger
To run the emulator, set the following command line parameters:
# Start up an emulator! $ ./emulator @AVD_NAME -no-snapshot -prop qemu.preferred.bt.service=passthrough -qemu -device usb-ehci,id=ehci -device usb-host,bus=ehci.0,vendorid=0x0b05,productid=0x17cb # Start Bluetooth Passthrough
Wi-Fi support
To validate dual Bluetooth and Wi-Fi, Google tested with the USB Wi-Fi Bluetooth Adapter.
Guest kernel
This particular USB dongle uses the RTL8821CU chip, which the mainline kernel upstream doesn't yet support. You can find a newly developed kernel module at 8821cu.
Then, in changelist 1575108, the external kernel modules were integrated into the goldfish kernel source to get it compiled.
Finally, the kernel module compiles but with some CFI crashes. You need to patch the code manually to fix this. For details, see Control Flow Integrity in the Android kernel.
It may be helpful to enable CONFIG_CFI_PERMISSIVE
and move forward with
debugging the rest of the stack first:
--- a/goldfish_defconfig.fragment
+++ b/goldfish_defconfig.fragment
@@ -1,6 +1,7 @@
CONFIG_CFI_CLANG=m
+CONFIG_CFI_PERMISSIVE=m
In any case, go to changelist 1575109 to see the proper fix for the CFI crashes.
Guest Android
To learn more about the Wi-Fi stack, see Wi-Fi Overview. The emulator comes with the settings to make Wi-Fi work.
Linux host
On the Linux host, you must update udev
settings to enable the user process
(for example, QEMU) to have read/write permissions.
# /lib/udev/rules.d/40-usb_modeswitch.rules
$ ATTR{idVendor}=="0bda", ATTR{idProduct}=="1a2b", RUN+="usb_modeswitch '/%k'"
$ echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="c820", MODE="0666", GROUP="plugdev"' | sudo tee /etc/udev/rules.d/99-mynew2.rules >/dev/null
$ sudo udevadm control --reload
$ sudo udevadm trigger
To pass the dongle to QEMU:
# Start up an emulator!
$ ./emulator @AVD_NAME -no-snapshot -qemu -device usb-ehci,id=ehci -device usb-host,bus=ehci.0,vendorid=0x0bda,productid=0xc820
Port changelists
Port the following changelists: