Содержание статьи
Современное железо редко предполагает что‑то доделывать руками или допиливать в прошивках. Однако есть целый класс устройств «ноунейм», которые просто‑таки взывают к умелым рукам и пытливым умам. Немного смекалки, и можно заставить их работать не хуже именитых аналогов.
Вот, например, ничем не примечательная ТВ‑приставка в виде черной квадратной пластиковой коробки с надписью «MXQ Pro 4K» на крышке и бюджетной начинкой: SOC RK3229, 1 Гбайт RAM и 8 Гбайт NAND. У меня она уже около года почти бесперебойно транслировала на телевизор YouTube и каналы интернет‑телевидения, музицировала и сообщала свежие новости.
В самом начале ее мультимедийной жизни характер у приставки был строптивый, и при каждом удобном случае она норовила зависнуть или перезагрузиться. Эту проблему удалось решить, установив сглаживающий фильтр в цепи питания и заменив комплектный блок питания более качественным.
В какой‑то момент я подумал, не использовать ли мне эту приставку еще и для игр. Беспроводной контроллер подошел бы для этого как нельзя лучше.
В целом контроллеры можно разделить на две категории: RF (Radio Frequency, радиочастотные) и BT (Bluetooth), оба в итоге работают по радиоканалу. Вариант с RF требует использовать проприетарный донгл (и занимать им порт USB), а Bluetooth должен поддерживаться на стороне приставки.
Зато Bluetooth универсален и, помимо подключения устройств ввода, может быть использован для вывода звука на беспроводные колонки, файлового обмена со смартфоном и так далее. Мой выбор был предопределен тем, что в ближайшем магазине нашелся лишь BT-контроллер VR-PARK. Не образец изящного дизайна, но не любоваться же на него!
К сожалению, на плате ТВ‑приставки отсутствует аппаратный BT-модуль, однако в настройках ее операционной системы Android 7.1.2 я видел пункт включения Bluetooth, что вроде бы позволяло надеяться на поддержку стека протоколов. Возможно, после подключения модуля Bluetooth в USB сработает магия и сразу представится возможность насладиться игрой?
С этими мыслями я прикупил USB-адаптер Bluetooth с лаконичной надписью «CSR 4.0» на корпусе. Вернувшись домой, я вставил его в порт приставки, и тот весело замигал светодиодом. А после включения Bluetooth в настройках... ничего не произошло. То есть почти ничего, если не считать возникновения задачи, решению которой посвящена эта статья: настроить ТВ‑приставку на использование адаптера USB Bluetooth.
Когда возникает проблема, исследователь первым делом идет в интернет, чтобы собрать сведения о ней. На удивление, материалов оказалось немного. То ли никто не подключал USB-адаптер к приставке, то ли у всех он работал из коробки, но последние содержательные обсуждения датировались 2013 годом и относились к автомобильной системе мультимедиа.
Результат бессистемных попыток отыскать работающие настройки не порадовал: я только потерял несколько часов и осознал, что придется искать собственный путь. А для этого необходимо понимать, как подсистема Bluetooth встроена в Android.
Архитектура подсистемы Bluetooth в Android
С точки зрения программиста, центральный компонент подсистемы Bluetooth в Android — системная служба Bluetooth (представляющая собой приложение для Android), которая через Binder IPC дает приложениям доступ к услугам Bluetooth-профилей, а сама использует при этом JNI-интерфейсы, реализованные на уровне HAL и ведущие к компонентам стека Bluetooth и расширениям поставщика (в двоичных библиотеках).
Эту схему можно продолжить вниз по системной иерархии, и тогда станет видно, что библиотеки HAL используют интерфейс hci0
для доступа к HCI-сокетам ядра операционной системы, которые через драйвер позволяют взаимодействовать с аппаратным Bluetooth-модулем, подключенным к системной плате шиной SDIO, UART или USB.
Осталось выяснить, на каком именно уровне у нас проблема, которая мешает адаптеру взять и заработать.
Операционная система Android — это ядро Linux, поверх которого работает гипервизор виртуальных машин Dalvik. Начинать анализ разумно с нижнего уровня, последовательно убеждаясь в том, что есть физическое подключение, операционная система и драйвер видят адаптер, он доступен на уровне HAL и так далее — до момента, когда он должен работать.
Чтобы исследовать ОС и вносить в нее изменения, нужен доступ к командной оболочке с правами суперпользователя. Об основах использования консоли Android можно прочитать в статье «Консольный Android».
warning
Вмешательство в операционную систему с правами суперпользователя может нарушить работоспособность устройства и вывести его из строя. Принимая решение выполнить описанные в статье рекомендации, исследователь берет на себя полную ответственность за возможные негативные последствия своих действий.
Рекогносцировка
В системных сообщениях dmesg
упоминания о Bluetooth встречаются в следующих контекстах:
[
[
[
[
[
[
. . .[
[
[
[
[
[
[
. . .[
[
[
[
[
[
[
[
. . .[
[
[
Строка 1 говорит о том, что ядро Linux собрано с поддержкой стека Bluetooth, строка 2 сообщает о регистрации в ядре семейства протоколов Bluetooth. Сразу после этого инициализируются слои сокетов HCI, L2CAP и SCO (3–6).
Затем активируются драйверы, предназначенные для взаимодействия с адаптерами Bluetooth, подключаемыми по шинам UART и USB (7–13). К сожалению, последний «понимает» только контроллеры Realtek, а наш адаптер CSR этим драйвером не поддерживается.
Последний блок сообщений (14–21) информирует об инициализации высокоуровневых протоколов RFCOMM, BNEP и HIDP стека Bluetooth. Строки 23–25 соответствуют реакции операционной системы на подключение USB-адаптера и говорят о том, что на физическом уровне он опознается шиной USB.
Интересно, где же находится драйвер адаптера? Команда lsmod
выдала список из двух модулей, среди которых rtk_btusb
не оказалось. Значит, он интегрирован в ядро Linux. Но список непустой, а значит, ядро собрано с поддержкой модулей. Запомним это на будущее.
Я изучил файловую систему ТВ‑приставки и нашел следующие компоненты, имеющие отношение к подсистеме Bluetooth:
/app/Bluetooth/Bluetooth.apk
/system/lib/libbluetooth_jni.so
/system/lib/hw/audio.a2dp.default.so
/system/lib/hw/bluetooth.default.so
/system/lib/hw/bluetooth_rtk.default.so
/system/lib/libbt-vendor_uart.so
/system/lib/libbt-vendor_usb.so
/system/lib/rtkbt/...
/system/vendor/libbt-vendor.so
/system/etc/bluetooth/bt_did.conf
/system/etc/bluetooth/bt_stack.conf
/system/etc/bluetooth/bt_vendor.conf
/system/etc/bluetooth/rtkbt.conf
/system/etc/bluetooth/rtkbt_plugins.conf
Следующие команды, последовательно примененные к файлам библиотек, помогут нам понять их зависимость друг от друга:
$ strings /system/lib/hw/название-библиотеки.so | grep '.so'$ strings /system/lib/hw/название-библиотеки.so | grep '.conf'
Добавив эти компоненты на схему, я получил следующую картину.
Собранной информации достаточно, чтобы предположить, что драйверы на ТВ‑приставке не поддерживают Bluetooth-адаптеры на контроллерах CSR. Поскольку ядро имеет поддержку модулей, можно попытаться исправить дело, собрав соответствующий модуль с необходимым драйвером.
Модуль ядра с драйвером USB-адаптера
В качестве платформы для сборки я использовал 64-битную ОС Bodhi Linux 6.0.0 (основанную на Ubuntu 20.04 LTS). У нее есть минималистичный установочный образ, в который входят инструменты метапакета build essential. Для наших работ достаточно виртуальной машины с оперативной памятью 1 Гбайт и накопителем 20 Гбайт. После установки системы и синхронизации с репозиторием надо установить дополнительные пакеты unzip
, python2
и libncurses5
и создать символическую ссылку на интерпретатор:
$ sudo ln -s /usr/bin/python2.7 /usr/bin/python
Создадим каталог для работы:
$ mkdir $HOME/tvbox && cd $HOME/tvbox
Чтобы собрать модуль драйвера, нужны исходники ядра Linux той версии, которая используется в операционной системе ТВ‑приставки, в данном случае 3.10.104. К счастью, на GitHub быстро нашелся репозиторий с ядрами Linux, адаптированными для устройств на платформе Rockchip. Забираем исходники из него:
$ wget -C kernel-release-3.10.zip https://github.com/rockchip-linux/kernel/archive/refs/heads/release-3.10.zip
Теперь надо распаковать полученный архив в рабочий каталог и проверить, соответствует ли версия ядра ожиданиям:
$
$
VERSION = 3
PATCHLEVEL = 10
SUBLEVEL = 104
Чтобы посмотреть, какие конфигурации доступны для платформы Rockchip, выполним команду
$
rockchip_chromium_defconfig - Build for rockchip_chromium
rockchip_defconfig - Build for rockchip
Вариант для операционной системы Chromium OS отбрасываем, остается rockchip_defconfig
. Ищем нужный конфиг:
$
./arch/arm64/configs/rockchip_defconfig
./arch/arm/configs/rockchip_defconfig
В нашей приставке стоит чип RK3229. Он 32-разрядный, поэтому нам актуален второй вариант. Для конфигурирования ядра, как написано в kernel-release-3.
и kernel-release-3.
, надо выполнить команды
$ ARCH=arm scripts/kconfig/merge_config.sh \ arch/arm/configs/rockchip_defconfig \ android/configs/android-base.cfg \ android/configs/android-recommended.cfg
Далее в только что созданный файл .config надо добавить строку CONFIG_MODULES=y
(после строки CONFIG_MODULES
), чтобы включить поддержку модулей ядром, а также строку CONFIG_BT_HCIBTUSB=m
(после строки CONFIG_BT_HCIBTUSB
) — для сборки драйвера USB-адаптеров Bluetooth как модуля ядра. После этого выполним команду
$ ARCH=arm make olddefconfig
Исходные тексты ядра сконфигурированы и готовы к сборке модуля. Собирать будем с помощью инструментов Linaro. Их нужно извлечь из архива gcc-linaro-4.9.4-2017.01-x86_64_arm-eabi.tar.xz в каталог tvbox
, после чего из подкаталога kernel-release-3.
выполняем команду
$ PATH=$HOME/tvbox/gcc-linaro-4.9.4-2017.01-x86_64_arm-eabi/bin:$PATH \ARCH=arm CROSS_COMPILE=arm-eabi- make modules
Через непродолжительное время модуль ядра будет сформирован в файле kernel-release-3.
. Этот файл надо записать на ТВ‑приставку в каталог /
и попробовать запустить:
#
insmod: failed to load btusb.ko: Exec format error
Неудача: нам сообщили, что файл имеет неправильный формат. Детальное описание проблемы можно найти в сообщениях ядра:
#
btusb: version magic '3.10.104 SMP preempt ARMv7 p2v8 ' should be '3.10.104 SMP preempt mod_unload ARMv7 p2v8 '
Оказывается, собранная версия не имеет атрибута mod_unload
. Придется вернуться к исходным текстам и в файл .config после строки #
добавить параметр CONFIG_MODULE_UNLOAD=y
, а затем повторить сборку:
$ make clean
$ make olddefconfig
$ make modules
Записываем новый модуль на ТВ‑приставку и запускаем:
# insmod /system/lib/modules/btusb.ko
Проверяем результат:
#
usbcore: registered new interface driver btusb
#
Module Size Used by
btusb 14685 0 [permanent]
Неужели получилось? Пока что все говорит о том, что модуль заработал. Для проверки воспользуемся командой rfkill
(она становится доступной после установки BusyBox). Сначала надо выполнить команду rfkill
без подключенного модуля и запомнить ее вывод (если он не пустой). Затем подключить модуль и повторить выполнение команды:
#
0: hci0: bluetooth
Soft blocked: no
Hard blocked: no
В выводе должны появиться строки, соответствующие подключенному адаптеру. Потом адаптер надо отключить и снова выполнить rfkill
. Теперь строки, соответствующие адаптеру, должны исчезнуть из вывода. Только такое динамичное поведение говорит о работоспособности драйвера.
Альтернативный способ проверки — наблюдение за содержимым каталога /
. При подключении адаптера Bluetooth в нем должен создаваться подкаталог rfkillN
(где N
— номер устройства), а при отключении — исчезать.
Из файла /
, который содержит команды, выполняемые при загрузке системы для инициализации коммуникационных устройств, можно узнать, что файлам /
надо назначить владельца bluetooth:
, а файлу state
— еще и права доступа 0664
. Сделаем это и попытаемся активировать Bluetooth в настройках Android. Увы, но бегунок элемента управления снова возвращается в положение «Выкл.».
На этом этапе возникает соблазн раздобыть утилиты hciconfig и hcitool, чтобы продолжить настраивать подсистему Bluetooth над ядром Linux, но это тупиковый путь. Наша задача — заставить работать Bluetooth в Android. А для этого надо принять, что задача обеспечить работу драйвера на уровне ядра выполнена, и обратиться к нашей схеме за следующей целью. Ей оказалась «библиотека производителя» libbt-vendor.
— именно она должна обеспечить интерфейс между драйвером ядра и подсистемой Bluetooth в Android.
www
Для автоматизации описанной выше работы — получения исходных текстов ядра, его настройки и сборки модуля — можешь воспользоваться моими сценариями на bash.
Библиотека взаимодействия с драйвером
С библиотекой libbt-vendor.
дело оказалось несколько сложнее, чем с драйвером. На сайте с исходниками Android обнаружились только материалы по библиотекам для адаптеров на чипах Realtek и Broadcom. Единственный вселяющий надежду репозиторий на GitHub с описанием «A libbt-vendor.so for usb bluetooth on Android» датирован сентябрем 2014 года и содержит единственный коммит — форк какого‑то давно исчезнувшего источника.
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»