エミュレータ USB パススルー統合ガイド

この記事では、2 台の周辺機器(Bluetooth と Wi-Fi)を AAOS エミュレータに接続する方法について説明します。このプロセスでは、ドライバ サポートに固有の 3 つの重要な領域があります。

  • ゲストカーネル
  • ゲスト Android
  • Linux ホスト

まず、ゲストカーネルで関連する USB ドライバをコンパイルして有効にします。 次にゲスト Android が、ドライバを起動する適切な HAL とサービスを選択します。最後に、Linux ホストが USB ドライバにアクセスして、QEMU に転送します。

テスト済みのドングル

以下のドングルがテストされました。

他のドングルも動作する可能性がありますが、テストは行われていません。

ネイティブ USB のサポート

QEMU には、USB をエミュレータに渡すオプションが用意されています。AAOS システム イメージは、接続されているスマートフォンをすでに処理しています。詳細については、Android Open Accessory(AOA)をご覧ください。

スマートフォンでは AOA 接続の確立時に vendorIDproductID の値が変更されるため、スマートフォンが AOA モードのときに新しい USB インターフェース(および元の USB インターフェース)でデバイスを確認できます。

AOA モードの前後に vendorIDproductID の値を判別するには、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

または、物理ポートを 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.

AAOS システム イメージはスマートフォンを認識し、AOA モードにして、AOA モードの実行中にもう一度認識します。

USB パススルーをサポートするには、エミュレータ 30.5.0 を使用していることを確認してください。

# Check for the emulator version
$ emulator --version

エミュレータ 30.5.0 には libusb のアップグレードと、ASUS ドングルに対応する速度を確保するための一時的な回避策が含まれています。

Bluetooth のサポート

Bluetooth パススルーをサポートするために、Google は ASUS USB-BT400 USB アダプター USBBT400 と Auscomer の USB Wi-Fi Bluetooth アダプターをテストしました。

まず、ドングルのカーネル サポートを追加する必要があります。Android Bluetooth スタックの詳細については、Bluetooth をご覧ください。HIDL の場合、エミュレータはシミュレートされた実装を使用します。これをネイティブ Linux の実装に切り替えます。

ゲストカーネル

USB Bluetooth ドングルをサポートする方法:

  1. 欠落している btusb.ko をカーネルに追加します。

    --- 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
    

ゲスト Android

  1. vendor.mk ファイルに、Linux ネイティブ HIDL と複数の権限を含めます。

    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
    
  2. Linux ネイティブ HIDL の実装を使用するように HIDL を切り替えるには、一方向のパスプロパティを作成します。

    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
    
  3. プロパティ qemu.preferred.bt.servicepassthrough に設定すると、HIDL 実装がオフになります。

    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
    
  4. Bluetooth 構成ファイルを追加して、実際の USB デバイスと同様の完全な機能を利用できるようにします。

    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
    
  5. BoardConfig.mk ファイルを変更して、構成ファイルの保存場所を決定します。

    BoardConfig.mk
    
    # Bluetooth
    BOARD_HAVE_BLUETOOTH := true
    BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR := vendor/auto/embedded/hal/bluetooth
    

Linux ホスト

Linux ホストで次のようにします。

  1. udev 設定を更新し、ユーザー プロセス(QEMU など)に読み取り / 書き込み権限を付与します。

    $ 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
    
  2. エミュレータを実行するには、次のコマンドライン パラメータを設定します。

    # 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
    

WiFi のサポート

デュアル Bluetooth と Wi-Fi を検証するため、Google は USB WiFi Bluetooth アダプターでテストしました。

ゲストカーネル

この USB ドングルは、アップストリームのメインライン カーネルではまだサポートされていない、RTL8821CU チップを使用します。新たに開発されたカーネル モジュールは 8821cu にあります。

次に変更リスト 1575108 で、外部カーネル モジュールが goldfish カーネルソースに統合され、コンパイルされます。

最後にカーネル モジュールがコンパイルされますが、CFI でなんらかのクラッシュが発生します。この問題を修正するには、手動でパッチを適用する必要があります。詳細については、Android カーネルの制御フローの整合性をご覧ください。

まず CONFIG_CFI_PERMISSIVE を有効にしてから、残りのスタックをデバッグすることをおすすめします。

--- a/goldfish_defconfig.fragment
+++ b/goldfish_defconfig.fragment
@@ -1,6 +1,7 @@
 CONFIG_CFI_CLANG=m
+CONFIG_CFI_PERMISSIVE=m

いずれにしても変更リスト 1575109 にアクセスして、CFI クラッシュの適切な修正方法を確認してください。

ゲスト Android

Wi-Fi スタックの詳細については、Wi-Fi の概要をご覧ください。エミュレータには、Wi-Fi に対応するための設定が用意されています。

Linux ホスト

Linux ホストでユーザー プロセス(QEMU など)に読み取り / 書き込み権限を付与するには、udev 設定を更新する必要があります。

# /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

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

変更リストの移行

次の変更リストを移行します。