안드로이드 개발을 처음 접한 2017년에는 안드로이드 에뮬레이터의 성능이 좋지 않았다. 그 당시에 에뮬레이터의 성능이 좋지 않으니, 테스트는 실기기를 연결하여 진행했다. (실기기도 성능이 좋진 않았지만, 에뮬레이터보다는 확실히 빨랐다) 테스트하는 동안 유선으로 연결하고 있는 것이 불편하여 이후에는 무선으로 연결하는 방법을 찾아서 사용했었다. 이 방법도 연결할 때 1회는 유선으로 연결해야 했다.

한동안 안드로이드 개발을 하지 않다가 최근에 안드로이드 개발을 다시 시작하면서 에뮬레이터를 사용해 보니 성능이 괜찮았다. 이 정도면 실기기를 사용하지 않고 에뮬레이터를 사용해도 괜찮을 것 같았다. 다만, 한 가지 문제가 있었는데 앱이 블루투스 기능을 사용하고 있다는 점이었다.

안드로이드 에뮬레이터는 아래와 같이 블루투스 기능을 지원하지 않는다. 안드로이드 에뮬레이터의 제약 사항

https://developer.android.com/studio/run/advanced-emulator-usage

호스트의 블루투스를 사용할 수 있는 방법

PC의 블루투스를 VM이나 에뮬레이터에서 사용할 수 있는 방법을 찾아보니 아래와 같이 2가지 방법이 있었다.

  1. google/bumble, Android Emulator를 사용한 방법
  2. VirtualBox, Android x86 를 사용한 방법

1, 2번 방법 모두 USB 블루투스 동글이 필요하고 환경에 따라 안될 가능성이 높아 보인다. 2번 방법은 VirtualBox가 아니더라도 호스트의 USB를 사용할 수 있는 VM이면 가능할 것으로 보인다.

아래와 같은 이유로 두 방법 중 1번 방법을 선택해서 진행했다.

  • Android x86 이미지가 Android 9.0까지만 존재
  • VirtualBox를 설치하고 싶지 않고 다른 VM을 찾아보는 것도 시간이 오래 걸릴 것 같은 점
  • bumble 프로젝트는 알파버전이지만 꾸준히 개발되고 있고 구글 개발자 문서에 bumble 프로젝트를 사용한 예시가 있어 지원이 더 좋아질 가능성이 있음

사실, 이런 문제는 성공한 사람의 환경을 그대로 따라가는 것이 최선이다…

bumble

bumble은 구글의 오픈소스로 앱, 에뮬레이션, 테스트 및 실험을 위한 블루투스 스택이다. Python으로 개발되었고 아래와 같이 여러 프로토콜과 프로파일을 지원한다.

Bluetooth Stack for Apps, Emulation, Test and Experimentation

Bumble is a full-featured Bluetooth stack written entirely in Python. It supports most of the common Bluetooth Low Energy (BLE) and Bluetooth Classic (BR/EDR) protocols and profiles, including GAP, L2CAP, ATT, GATT, SMP, SDP, RFCOMM, HFP, HID and A2DP. The stack can be used with physical radios via HCI over USB, UART, or the Linux VHCI, as well as virtual radios, including the virtual Bluetooth support of the Android emulator.

https://github.com/google/bumble?tab=readme-ov-file#bluetooth-stack-for-apps-emulation-test-and-experimentation

README.mdUsing Bumble With a USB Dongle 내용을 보면 전용 USB 동글을 사용하는 것이 가장 쉽다는 내용이 있는데, 아래 적용 방법에 소개할 usb_probe 툴을 사용하기 위해서는 블루투스 USB 동글은 쉬운 선택 사항이 아니라 필수 사항으로 보인다.

윈도우 환경에서는 드라이버를 변경하기 때문에 별도의 USB 블루투스 동글이 없어도 적용이 가능할 것 같으나, 드라이버 변경 시 기존에 페어링 된 블루투스 장비들의 연결이 해제된다. 그냥 별도의 동글을 사용하는 것이 수월하다.

적용 방법

사전 준비 및 환경

적용하기 위한 사전 준비 및 환경은 아래와 같다.

  • USB 블루투스 동글: 리얼텍 (Realtek) 칩셋을 권장
  • 안드로이드 에뮬레이터: 버전 33.1.4.0 이상

Android Studio Emulator Bluetooth not working 이슈와 같이 bumble-rtk-util로 펌웨어(firmware)를 로드해야 하는 경우가 있을 수 있다. 리얼텍 칩셋의 경우 bumble에 펌웨어를 다운로드 및 로드할 수 있는 기능이 있어서 리얼텍 칩셋을 사용한 USB 블루투스 동글을 쓸 것을 권장한다.

안드로이드 에뮬레이터 버전 기준

안드로이드 에뮬레이터 버전 기준

# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------

LINUX_KERNEL_GIT_SOURCE = (
    "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/rtl_bt",
    False,
)

REALTEK_OPENSOURCE_SOURCE = (
    "https://github.com/Realtek-OpenSource/android_hardware_realtek/raw/rtk1395/bt/rtkbt/Firmware/BT",
    True,
)

LINUX_FROM_SCRATCH_SOURCE = (
    "https://anduin.linuxfromscratch.org/sources/linux-firmware/rtl_bt",
    False,
)

tools/rtk_fw_download.py

설치

Getting Started를 참고하여 설치를 진행했다. 먼저, 아래 명령을 입력해 Github Repository로 부터 Bumble을 설치한다.

  • Github Repository로부터 Bumble 설치
> python3 -m pip install git+https://github.com/google/bumble.git                            

...
Successfully built bumble
Installing collected packages: bumble
  Attempting uninstall: bumble
    Found existing installation: bumble 0.0.195
    Uninstalling bumble-0.0.195:
      Successfully uninstalled bumble-0.0.195
Successfully installed bumble-0.0.195

설치가 완료되면 bumble-console, bumble-scan, bumble-usb-probe 등의 명령을 사용할 수 있다. 해당 명령이 실행되지 않으면 설치 경로를 환경변수에 추가한다.

  • bin 폴더의 하위 목록
> ls

bumble-bench               bumble-gatt-dump           bumble-pandora-server      bumble-show                pip3
bumble-ble-rpa-tool        bumble-hci-bridge          bumble-rfcomm-bridge       bumble-speaker             pip3.9
bumble-console             bumble-l2cap-bridge        bumble-rtk-fw-download     bumble-unbond              pyserial-miniterm
bumble-controller-info     bumble-link-relay          bumble-rtk-util            bumble-usb-probe           pyserial-ports
bumble-controller-loopback bumble-pair                bumble-scan                pip

다른 방법으로는 Bumble Repository를 Clone하고 apps, tools 폴더의 Python 파일을 실행해도 된다.

플랫폼(맥, 윈도우) 별 설정

플랫폼(맥, 윈도우)에 따라 아래 내용을 참고하여 설정한다.

맥 OS(macOS)

MACOS PLATFORM문서를 참고하여 아래 명령을 실행한다.

> sudo nvram bluetoothHostControllerSwitchBehavior="never"

윈도우(Windows)

WINDOWS PLATFORM 문서를 참고하여 진행했다. Zadig tool.을 설치 및 실행한 뒤 Options > List All Devices를 선택한다. 드롭다운에서 USB 블루투스 동글을 선택한 뒤 Reinstall Driver 버튼을 눌러 드라이버를 설치한다.

Zadig 실행 화면

정상적으로 할당되면, 장치 관리자에서 블루투스가 아닌 범용 직렬 버스 장치에 우리가 연결한 USB 블루투스 동글이 있는 것을 확인할 수 있다. 추가로 드라이버 세부 정보의 드라이버 파일 목록에서 winusb.sys를 확인할 수 있다.

장치 관리자 화면

장치관리자의 블루투스 장치 표시 현황

블루투스 스캔 기능 확인

스캔 기능을 확인하기 위해서 먼저 bumble-usb-probe 명령으로 USB 블루투스 동글의 Bumble Transport Names를 확인한다. 아래 내용처럼 Transport를 입력하는 곳에 usb:0 or usb:0BDA:A729 or usb:0BDA:A729/00E04C239987를 사용할 수 있다.

> bumble-usb-probe
or
> python3 /apps/usb_probe.py

ID 0BDA:A729
  Bumble Transport Names: usb:0 or usb:0BDA:A729 or usb:0BDA:A729/00E04C239987
  Bus/Device:             005/004
  Class:                  Wireless Controller
  Subclass/Protocol:      1/1 [Bluetooth]
  Serial:                 00000C239987
  Manufacturer:           Realtek
  Product:                Bluetooth 5.3 Radio
...

bumble-console에서 scan on 명령을 실행하면 아래 그림과 같이 블루투스 스캔이 정상적으로 작동하는 지 확인할 수 있다.

> bumble-console usb:0
or
> python3 /apps/console.py usb:0

bumble-console 화면

CONSOLE APP을 사용한 블루투스 스캔

안드로이드 에뮬레이터와 연결

안드로이드 에뮬레이터와 연결하기 위해서는 아래 두 명령을 실행한다. 첫 번째 명령은 bumble-hci-bridge를 사용하여 안드로이드 에뮬레이터의 가상 Bluetooth ControllerNetsim과 USB 블루투스 동글을 연결한다. 두 번째 명령은 에뮬레이터를 Bumble HCI Bridge에 연결하여 실행한다.

  • bumble-hci-bridge 실행
> bumble-hci-bridge android-netsim:_:8877,mode=controller usb:0
or
> python3 /apps/hci_bridge.py android-netsim:_:8877,mode=controller usb:0
  • 안드로이드 에뮬레이터 실행
> emulator -packet-streamer-endpoint localhost:8877 -avd [Emulator Name] -no-snapshot-load

Connecting a Custom Virtual Controller

참고로, 안드로이드 에뮬레이터 이름은 아래 명령으로 확인할 수 있다.

> emulator -list-avds

Pixel_3a_API_34_extension_level_7_arm64-v8a
Resizable_Experimental_API_34

결과

문제가 없다면 아래 그림와 같이 안드로이드 에뮬레이터에서 블루투스를 사용할 수 있다.

안드로이드 에뮬레이터에서의 블루투스 스캔

참고사항

안드로이드 에뮬레이터에서 블루투스가 계속 꺼지거나 주변 기기가 검색되지 않는 경우

Android Studio Emulator Bluetooth not working 이슈와 같이 안드로이드 에뮬레이터에서 블루투스가 계속 꺼지는 현상이 발생하거나 아래 그림과 같이 bumble-console에서 주변 기기가 검색되지 않는 경우가 있다.

  • 주변 기기가 검색되지 않는 경우

이런 경우 위 이슈의 답변처럼 bumble-rtk-fw-download, bumble-rtk-util를 사용하여 펌웨어를 다운로드 및 로드하여 해결할 수 있다. 리얼텍 칩셋을 사용한 블루투스 동글을 사용 중이나 아래와 같이 지원하지 않는 USB 장치라고 나온다면 명시적으로 driver=rtk을 입력하여 진행하면 된다.

  • USB 블루투스 동글의 펌웨어 정보 확인
> bumble-rtk-util info usb:0
or
> python3 /tools/rtk_util.py info usb:0

USB device not supported by this RTK driver
  • 지원하지 않는 USB 장치라고 나오는 경우 명시적으로 driver=rtk를 입력하여 진행
> bumble-rtk-util info "usb:[driver=rtk]0"
or 
> python3 /tools/rtk_util.py info "usb:[driver=rtk]0"

Driver:
  ROM:      8761
  Firmware: rtl8761bu_fw.bin
  Config:   rtl8761bu_config.bin
  • USB 블루투스 동글에 펌웨어 로드
> bumble-rtk-util load usb:"[driver=rtk]0"
or 
> python3 /tools/rtk_util.py load "usb:[driver=rtk]0"

WARNING:bumble.drivers.rtk:Firmware file rtl8761bu_fw.bin not found
WARNING:bumble.drivers.rtk:See https://google.github.io/bumble/drivers/realtek.html
Firmware already loaded or no supported driver for this device.
  • 펌웨어가 없는 경우 bumble-rtk-fw-download를 사용하여 펌웨어 다운로드
> bumble-rtk-fw-download --single rtl8761bu
or
> python3 /tools/rtk-fw-download --single rtl8761bu

Downloading
FROM: https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/rtl_bt
TO: ...
---
Downloaded rtl8761bu_fw.bin: 44484 bytes
Downloaded rtl8761bu_config.bin: 6 bytes
  • USB 블루투스 동글에 펌웨어를 다시 로드
> bumble-rtk-util load usb:"[driver=rtk]0"
or 
> python3 /tools/rtk_util.py load "usb:[driver=rtk]0"

참고: 리얼텍(Realtek) 펌웨어 다운 및 로드

이슈의 답변을 보면 자동으로 펌웨어를 로드한다고 하나, 내 환경에서는 USB 블루투스 동글을 제거하거나 PC를 재부팅 할 경우 위 명령을 다시 입력해서 펌웨어를 다시 로드해야 에뮬레이터 내부에서 블루투스를 사용할 수 있었다.

안드로이드 에뮬레이터 버전이 낮은 경우

안드로이드 에뮬레이터 버전이 33.1.4.0 이하인 경우 --packet-streamer-endpoint 옵션이 존재하지 않는다. Android StudioSDK Manager 메뉴에서 Android Emulator를 업데이트 후 진행하면 된다.

> emulator -packet-streamer-endpoint localhost:8877 -avd Resizable_Experimental_API_34 -no-snapshot-load
INFO    | Android emulator version 32.1.14.0 (build_id 10330179) (CL:N/A)
...
INFO    | Duplicate loglines will be removed, if you wish to see each indiviudal line launch with the -log-nofilter flag.
unknown option: -packet-streamer-endpoint
please use -help for a list of valid options

후기

안드로이드 에뮬레이터에서 블루투스를 사용할 수 있게 되니 개발 중에 실기기를 사용하여 테스트할 이유가 없어졌다. 변경 사항 반영도 에뮬레이터를 사용하는 경우가 더 빨라서 테스트 및 기능 확인도 수월하고 훨씬 편하게 개발할 수 있게 됐다. 에뮬레이터에서 블루투스를 사용하는 것이 목적이라 이번에는 필요한 부분만 확인했지만, 블루투스를 깊게 사용하는 경우라면 이 글에서 사용한 Bumble 프로젝트를 살펴볼 만 할 것 같다.