Getting Bluetooth Working on LineageOS Android TV on the NVIDIA Jetson Nano 2GB

I wanted to use a Bluetooth Xbox controller with LineageOS Android TV running on an NVIDIA Jetson Nano 2GB. The Jetson Nano does not have built-in Bluetooth, so I used a TP-Link UB400 USB Bluetooth adapter.

The UB400 showed up as:

Vendor=0a12
Product=0001
Driver=btusb

This is what finally worked.

1. Confirm the adapter is detected

With the UB400 plugged in, check USB devices:

cat /sys/kernel/debug/usb/devices | grep -i -A14 -B4 -E 'bluetooth|0a12|csr|cambridge|tp-link'

The important part is:

Vendor=0a12 ProdID=0001
Driver=btusb

Then check for the Bluetooth HCI device:

ls -l /sys/class/bluetooth

A working result should show:

hci0

2. Load the Bluetooth modules at boot

The needed modules were already included in the LineageOS build:

btbcm
btintel
btrtl
btusb

The module load file was:

/vendor/lib/modules/modules.load

Remount /vendor as writable:

mount -o rw,remount /vendor

Then add these lines to the bottom of /vendor/lib/modules/modules.load:

btbcm
btintel
btrtl
btusb

Order matters. btusb should come last.

3. Patch SELinux for the Bluetooth HAL

Bluetooth worked only after the Bluetooth HAL was allowed to create and use its HCI socket.

The policy file was:

/vendor/etc/selinux/vendor_sepolicy.cil

Back it up:

cp /vendor/etc/selinux/vendor_sepolicy.cil /vendor/etc/selinux/vendor_sepolicy.cil.bak-btfix
mkdir -p /vendor/etc/selinux/backup-btfix

Add this rule to the bottom of vendor_sepolicy.cil:

; Jetson Nano USB Bluetooth HAL socket fix
(allow hal_bluetooth_default hal_bluetooth_default (socket (create bind read write)))

Because Android was using a precompiled SELinux policy, move that out of the way:

mv /vendor/etc/selinux/precompiled_sepolicy* /vendor/etc/selinux/backup-btfix/

Then reboot:

reboot

4. Disable LE vendor capabilities

The UB400 created hci0, but Android’s Bluetooth stack crashed while trying to query LE vendor capabilities.

The fix was:

setprop bluetooth.core.le.vendor_capabilities.enabled false

To make it persistent, add it to /vendor/build.prop:

mount -o rw,remount /vendor

grep -q '^bluetooth.core.le.vendor_capabilities.enabled=' /vendor/build.prop \
&& sed -i 's/^bluetooth.core.le.vendor_capabilities.enabled=.*/bluetooth.core.le.vendor_capabilities.enabled=false/' /vendor/build.prop \
|| echo 'bluetooth.core.le.vendor_capabilities.enabled=false' >> /vendor/build.prop

Then reboot again:

reboot

5. Test Bluetooth

After reboot:

getprop bluetooth.core.le.vendor_capabilities.enabled

Expected:

false

Then check Bluetooth status:

dumpsys bluetooth_manager | grep -i -E 'enabled|state|address|name'

A working result should show:

enabled: true
state: ON
name: SHIELD Android TV

6. Pair accessories

To open the Android TV pairing screen:

am start -n com.android.tv.settings/.accessories.AddAccessoryActivity

Then put the Xbox controller in pairing mode and select it from the list.

Final working setup

NVIDIA Jetson Nano 2GB
LineageOS Android TV
TP-Link UB400 USB Bluetooth adapter
Xbox Wireless Controller

After these changes, Bluetooth survived reboot and the Xbox controller connected normally.