Хакер - Bluetooth для андроида. Портируем с Linux на Android драйвер USB-адаптера

Хакер - Bluetooth для андроида. Портируем с Linux на Android драйвер USB-адаптера

hacker_frei

https://t.me/hacker_frei

Игорь Орещенков

Содержание статьи

  • Архитектура подсистемы Bluetooth в Android
  • Рекогносцировка
  • Модуль ядра с драйвером USB-адаптера
  • Библиотека взаимодействия с драйвером
  • Доработки
  • Выводы
  • Использованное ПО
  • Использованная документация

Не все USB-устрой­ства начина­ют работать на Android сра­зу пос­ле под­клю­чения. В этой статье я покажу, как решить проб­лему, на при­мере широко рас­простра­нен­ного Bluetooth-адап­тера CSR 4.0. Нам понадо­бит­ся соб­рать из исходни­ков ядро Linux и покопать­ся в интерфей­сной биб­лиоте­ке Android.

Сов­ремен­ное железо ред­ко пред­полага­ет что‑то доделы­вать руками или допили­вать в про­шив­ках. Одна­ко есть целый класс устрой­ств «ноунейм», которые прос­то‑таки взы­вают к уме­лым рукам и пыт­ливым умам. Нем­ного сме­кал­ки, и мож­но зас­тавить их работать не хуже име­нитых ана­логов.

Вот, нап­ример, ничем не при­меча­тель­ная ТВ‑прис­тавка в виде чер­ной квад­ратной плас­тиковой короб­ки с над­писью «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 и рас­ширени­ям пос­тавщи­ка (в дво­ичных биб­лиоте­ках).

Ар­хитек­тура под­систе­мы Bluetooth в Android 7

Эту схе­му мож­но про­дол­жить вниз по сис­темной иерар­хии, и тог­да ста­нет вид­но, что биб­лиоте­ки HAL исполь­зуют интерфейс hci0 для дос­тупа к HCI-сокетам ядра опе­раци­онной сис­темы, которые через драй­вер поз­воля­ют вза­имо­дей­ство­вать с аппа­рат­ным Bluetooth-модулем, под­клю­чен­ным к сис­темной пла­те шиной SDIO, UART или USB.

Ниж­ний уро­вень под­систе­мы Bluetooth в Android

Ос­талось выяс­нить, на каком имен­но уров­не у нас проб­лема, которая меша­ет адап­теру взять и зарабо­тать.

Опе­раци­онная сис­тема Android — это ядро Linux, поверх которо­го работа­ет гипер­визор вир­туаль­ных машин Dalvik. Начинать ана­лиз разум­но с ниж­него уров­ня, пос­ледова­тель­но убеж­даясь в том, что есть физичес­кое под­клю­чение, опе­раци­онная сис­тема и драй­вер видят адап­тер, он дос­тупен на уров­не HAL и так далее — до момен­та, ког­да он дол­жен работать.

Что­бы иссле­довать ОС и вно­сить в нее изме­нения, нужен дос­туп к коман­дной обо­лоч­ке с пра­вами супер­поль­зовате­ля. Об осно­вах исполь­зования кон­соли Android мож­но про­читать в статье «Кон­соль­ный Android».

WARNING

Вме­шатель­ство в опе­раци­онную сис­тему с пра­вами супер­поль­зовате­ля может нарушить работос­пособ­ность устрой­ства и вывес­ти его из строя. При­нимая решение выпол­нить опи­сан­ные в статье рекомен­дации, иссле­дова­тель берет на себя пол­ную ответс­твен­ность за воз­можные негатив­ные пос­ледс­твия сво­их дей­ствий.

РЕКОГНОСЦИРОВКА

В сис­темных сооб­щени­ях dmesg упо­мина­ния о Bluetooth встре­чают­ся в сле­дующих кон­тек­стах:

[1] Bluetooth: Core ver 2.16

[2] NET: Registered protocol family 31

[3] Bluetooth: HCI device and connection manager initialized

[4] Bluetooth: HCI socket layer initialized

[5] Bluetooth: L2CAP socket layer initialized

[6] Bluetooth: SCO socket layer initialized

. . .

[7] Bluetooth: HCI UART driver ver 2.2

[8] Bluetooth: HCI H4 protocol initialized

[9] Bluetooth: HCILL protocol initialized

[10] rtk_btusb: RTKBT_RELEASE_NAME: 20170109_TV_ANDROID_6.x

[11] rtk_btusb: Realtek Bluetooth USB driver module init, version 4.1.2

[12] rtk_btusb: Register usb char device interface for BT driver

[13] usbcore: registered new interface driver rtk_btusb

. . .

[14] Bluetooth: RFCOMM TTY layer initialized

[15] Bluetooth: RFCOMM socket layer initialized

[16] Bluetooth: RFCOMM ver 1.11

[17] Bluetooth: BNEP (Ethernet Emulation) ver 1.3

[18] Bluetooth: BNEP filters: protocol multicast

[19] Bluetooth: BNEP socket layer initialized

[20] Bluetooth: HIDP (Human Interface Emulation) ver 1.2

[21] Bluetooth: HIDP socket layer initialized

. . .

[23] usb 5-1: New USB device found, idVendor=0a12, idProduct=0001

[24] usb 5-1: New USB device strings: Mfr=0, Product=2, SerialNumber=0

[25] usb 5-1: Product: CSR8510 A10

Стро­ка 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 в опе­раци­онной сис­теме иссле­дуемой ТВ‑прис­тавки

Соб­ранной информа­ции дос­таточ­но, что­бы пред­положить, что драй­веры на ТВ‑прис­тавке не под­держи­вают Bluetooth-адап­теры на кон­трол­лерах CSR. Пос­коль­ку ядро име­ет под­дер­жку модулей, мож­но попытать­ся испра­вить дело, соб­рав соот­ветс­тву­ющий модуль с необ­ходимым драй­вером.

МОДУЛЬ ЯДРА С ДРАЙВЕРОМ USB-АДАПТЕРА

В качес­тве плат­формы для сбор­ки я исполь­зовал 64-бит­ную ОС Bodhi Linux 6.0.0 (осно­ван­ную на Ubuntu 20.04 LTS). У нее есть минима­лис­тичный уста­новоч­ный образ, в который вхо­дят инс­тру­мен­ты метапа­кета build essential. Для наших работ дос­таточ­но вир­туаль­ной машины с опе­ратив­ной памятью 1 Гбайт и накопи­телем 20 Гбайт. Пос­ле уста­нов­ки сис­темы и син­хро­низа­ции с репози­тори­ем надо уста­новить допол­нитель­ные пакеты unzippython2 и 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

Те­перь надо рас­паковать получен­ный архив в рабочий каталог и про­верить, соот­ветс­тву­ет ли вер­сия ядра ожи­дани­ям:

$ cd kernel-release-3.10

$ head Makefile

VERSION = 3

PATCHLEVEL = 10

SUBLEVEL = 104

Что­бы пос­мотреть, какие кон­фигура­ции дос­тупны для плат­формы Rockchip, выпол­ним коман­ду

$ make help | grep rockchip

rockchip_chromium_defconfig - Build for rockchip_chromium

rockchip_defconfig - Build for rockchip

Ва­риант для опе­раци­онной сис­темы Chromium OS отбра­сыва­ем, оста­ется rockchip_defconfig. Ищем нуж­ный кон­фиг:

$ find ./arch -name 'rockchip_defconfig'

./arch/arm64/configs/rockchip_defconfig

./arch/arm/configs/rockchip_defconfig

В нашей прис­тавке сто­ит чип RK3229. Он 32-раз­рядный, поэто­му нам акту­ален вто­рой вари­ант. Для кон­фигури­рова­ния ядра, как написа­но в kernel-release-3.10/README и kernel-release-3.10/android/configs/README, надо выпол­нить коман­ды

$ 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 is not set), что­бы вклю­чить под­дер­жку модулей ядром, а так­же стро­ку CONFIG_BT_HCIBTUSB=m (пос­ле стро­ки CONFIG_BT_HCIBTUSB is not set) — для сбор­ки драй­вера USB-адап­теров Bluetooth как модуля ядра. Пос­ле это­го выпол­ним коман­ду

$ ARCH=arm make olddefconfig

Ис­ходные тек­сты ядра скон­фигури­рова­ны и готовы к сбор­ке модуля. Собирать будем с помощью инс­тру­мен­тов Linaro. Их нуж­но извлечь из архи­ва gcc-linaro-4.9.4-2017.01-x86_64_arm-eabi.tar.xz в каталог tvbox, пос­ле чего из под­катало­га kernel-release-3.10 выпол­няем коман­ду

$ 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.10/drivers/bluetooth/btusb.ko. Этот файл надо записать на ТВ‑прис­тавку в каталог /system/lib/modules и поп­робовать запус­тить:

# insmod /system/lib/modules/btusb.ko

insmod: failed to load btusb.ko: Exec format error

Не­уда­ча: нам сооб­щили, что файл име­ет неп­равиль­ный фор­мат. Деталь­ное опи­сание проб­лемы мож­но най­ти в сооб­щени­ях ядра:

# dmesg | tail

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 is not set добавить параметр CONFIG_MODULE_UNLOAD=y, а затем пов­торить сбор­ку:

$ make clean

$ make olddefconfig

$ make modules

За­писы­ваем новый модуль на ТВ‑прис­тавку и запус­каем:

# insmod /system/lib/modules/btusb.ko

Про­веря­ем резуль­тат:

# dmesg | tail

usbcore: registered new interface driver btusb

# lsmod

Module Size Used by

btusb 14685 0 [permanent]

Не­уже­ли получи­лось? Пока что все говорит о том, что модуль зарабо­тал. Для про­вер­ки вос­поль­зуем­ся коман­дой rfkill (она ста­новит­ся дос­тупной пос­ле уста­нов­ки BusyBox). Сна­чала надо выпол­нить коман­ду rfkill list без под­клю­чен­ного модуля и запом­нить ее вывод (если он не пус­той). Затем под­клю­чить модуль и пов­торить выпол­нение коман­ды:

# rfkill list

0: hci0: bluetooth

Soft blocked: no

Hard blocked: no

В выводе дол­жны появить­ся стро­ки, соот­ветс­тву­ющие под­клю­чен­ному адап­теру. Потом адап­тер надо отклю­чить и сно­ва выпол­нить rfkill list. Теперь стро­ки, соот­ветс­тву­ющие адап­теру, дол­жны исчезнуть из вывода. Толь­ко такое динамич­ное поведе­ние говорит о работос­пособ­ности драй­вера.

Аль­тер­натив­ный спо­соб про­вер­ки — наб­людение за содер­жимым катало­га /sys/class/rfkill. При под­клю­чении адап­тера Bluetooth в нем дол­жен соз­давать­ся под­каталог rfkillN (где N — номер устрой­ства), а при отклю­чении — исче­зать.

Из фай­ла /init.connectivity.rc, который содер­жит коман­ды, выпол­няемые при заг­рузке сис­темы для ини­циали­зации ком­муника­цион­ных устрой­ств, мож­но узнать, что фай­лам /sys/class/rfkill/rfkillN/{type,state} надо наз­начить вла­дель­ца bluetooth:net_bt_stack, а фай­лу state — еще и пра­ва дос­тупа 0664. Сде­лаем это и попыта­емся акти­виро­вать Bluetooth в нас­трой­ках Android. Увы, но бегунок эле­мен­та управле­ния сно­ва воз­вра­щает­ся в положе­ние «Выкл.».

На этом эта­пе воз­ника­ет соб­лазн раз­добыть ути­литы hciconfig и hcitool, что­бы про­дол­жить нас­тра­ивать под­систе­му Bluetooth над ядром Linux, но это тупико­вый путь. Наша задача — зас­тавить работать Bluetooth в Android. А для это­го надо при­нять, что задача обес­печить работу драй­вера на уров­не ядра выпол­нена, и обра­тить­ся к нашей схе­ме за сле­дующей целью. Ей ока­залась «биб­лиоте­ка про­изво­дите­ля» libbt-vendor.so — имен­но она дол­жна обес­печить интерфейс меж­ду драй­вером ядра и под­систе­мой Bluetooth в Android.

WWW

Для авто­мати­зации опи­сан­ной выше работы — получе­ния исходных тек­стов ядра, его нас­трой­ки и сбор­ки модуля — можешь вос­поль­зовать­ся моими сце­нари­ями на bash.

БИБЛИОТЕКА ВЗАИМОДЕЙСТВИЯ С ДРАЙВЕРОМ

С биб­лиоте­кой libbt-vendor.so дело ока­залось нес­коль­ко слож­нее, чем с драй­вером. На сай­те с исходни­ками Android обна­ружи­лись толь­ко матери­алы по биб­лиоте­кам для адап­теров на чипах Realtek и Broadcom. Единс­твен­ный все­ляющий надеж­ду репози­торий на GitHub с опи­сани­ем «A libbt-vendor.so for usb bluetooth on Android» датиро­ван сен­тябрем 2014 года и содер­жит единс­твен­ный ком­мит — форк какого‑то дав­но исчезнув­шего источни­ка.

Вы­ходит, задача не име­ет решения? Или все‑таки поп­робовать? Эрнест Хемин­гуэй в романе «По ком зво­нит колокол» писал: есть толь­ко один спо­соб убе­дить­ся в том, что при­каз невыпол­ним, — попытать­ся его выпол­нить. Такой под­ход не всег­да раци­она­лен с праг­матичес­кой точ­ки зре­ния, но по край­ней мере даже в слу­чае неуда­чи поз­волит заявить: «Я сде­лал все, что мог. Кто может — пусть сде­лает луч­ше!» Поэто­му про­дол­жаем. В кон­це кон­цов, цена нашей неуда­чи нич­тожна в срав­нении с ситу­ациями, в которых ока­зыва­лись герои Хемин­гуэя.

В качес­тве сбо­роч­ной плат­формы будем исполь­зовать ту же вир­туаль­ную машину, что и для сбор­ки модуля ядра, — ее ресур­сов более чем дос­таточ­но. Что­бы получить динами­чес­кую биб­лиоте­ку для Android, пот­ребу­ется набор инс­тру­мен­тов Android NDK, вклю­чающий кросс‑ком­пилятор и заголо­воч­ные фай­лы. Пос­коль­ку целевая сис­тема — Android 7.1.2 Nougat, я выб­рал инс­тру­мен­тарий вер­сии r16b, соот­ветс­тву­ющий пери­оду рас­цве­та этой сис­темы. С таким же успе­хом мож­но взять r14b или r15c, но дру­гие вер­сии пот­ребу­ют серь­езной адап­тации исходни­ков.

Что­бы соб­рать биб­лиоте­ку libbt-vendor.so, под­держи­вающую USB-адап­теры Bluetooth, пот­ребу­ются:

  • ис­ходные коды этой биб­лиоте­ки libbt-usb-master.zip, получен­ные из репози­тория liangxiaoju/libbt-usb;
  • ис­ходные коды час­тей сис­темы Android utils.tar.gzcutils.tar.gz и log.tar.gz из вет­ви nougat-release (которая соот­ветс­тву­ет седь­мой вер­сии) с android.googlesource.com;
  • ис­ходные тек­сты под­систе­мы Bluedroid bluedroid.tar.gz самой пос­ледней вер­сии из того же репози­тория;
  • файл биб­лиоте­ки libcutils.so из катало­га /system/lib фай­ловой сис­темы телеп­ристав­ки.

Эти ингре­диен­ты надо ском­поновать в иерар­хичес­кую фай­ловую струк­туру про­екта NDK. В даль­нейшем пред­полага­ется, что дис­три­бутив NDK рас­пакован в каталог $HOME/tvbox, а для про­екта соз­дан под­каталог $HOME/tvbox/libbt-usb-master, внут­ри которо­го:

  • jni — содер­жимое катало­га libbt-usb-master, находя­щего­ся в архи­ве libbt-usb-master.zip;
  • jni/include/utils — содер­жимое архи­ва utils.tar.gz;
  • jni/include/cutils — содер­жимое архи­ва cutils.tar.gz;
  • jni/include/log — содер­жимое архи­ва log.tar.gz;
  • jni/lib/libcutils.so — дво­ичный файл, получен­ный с телеп­ристав­ки;
  • external/bluetooth/bluedroid — содер­жимое архи­ва bluedroid.tar.gz.

По­мимо это­го, надо соз­дать файл tvbox/libbt-usb-master/jni/Application.mk, в котором будет задана минималь­ная вер­сия Android API и архи­тек­тура целевой сис­темы:

PP_PLATFORM := android-21

PP_ABI := armeabi-v7a

WWW

Ты можешь исполь­зовать мои скрип­ты для получе­ния исходни­ков и фор­мирова­ния фай­лового дерева про­екта NDK. Скрипт vendor-prepare.sh допол­нитель­но модифи­циру­ет исходни­ки, без чего сбор­ка про­екта не будет успешной.

Те­перь про­цесс сбор­ки мож­но запус­кать из катало­га tvbox/libbt-usb-master:

$ ../android-ndk-r16b/ndk-build

Во вре­мя сбор­ки будут выданы пре­дуп­режде­ния:

  • об отсутс­твии обра­бот­чиков для опе­раций BT_VND_OP_SET_AUDIO_STATE и BT_VND_OP_EPILOG в селек­торе switch (opcode) фай­ла jni/src/bt_vendor_hci.c;
  • о пов­торном опре­деле­нии кон­стан­ты HCI_MAX_FRAME_SIZE в фай­ле jni/src/hci.h.

Вто­рое пре­дуп­режде­ние мож­но сме­ло игно­риро­вать, а что до пер­вого, то пока оста­ется наде­ять­ся, что оно каса­ется ауди­опро­филей Bluetooth и не отра­зит­ся на работе джой­сти­ка.

Соб­ранная биб­лиоте­ка находит­ся по пути tvbox/libbt-usb-master/libs/armeabi-v7a/libbt-vendor.so. Ее надо записать в каталог /system/vendor/lib телеп­ристав­ки, пос­ле чего мож­но прис­тупать к испы­тани­ям. Перед этим, конеч­но, не будет лиш­ним про­верить, что адап­тер вклю­чен в USB, его драй­вер заг­ружен, а фай­лам в под­катало­ге /sys/class/rfkill/rfkillN/ даны необ­ходимые раз­решения, как это было опи­сано выше.

От­кры­ваем нас­трой­ки Android, вклю­чаем Bluetooth — и прис­тавка сра­зу вык­люча­ется. Вклю­чаем прис­тавку и пов­торя­ем про­цеду­ру — резуль­тат тот же, отри­цатель­ный. Обид­но, одна­ко это сви­детель­ству­ет, что мы чего‑то дос­тигли и Android вза­имо­дей­ству­ет с драй­вером для Linux. Пусть и в такой неудач­ной фор­ме.

Взгля­нем еще раз на схе­му, что­бы оце­нить прой­ден­ный путь. Но что это? Из схе­мы вид­но, что биб­лиоте­ка libbt-vendor.so исполь­зует нас­трой­ки, которые записа­ны в фай­ле /system/etc/bluetooth/bt_vendor.conf, а на текущий момент там ука­зано, что адап­тер Bluetooth будет под­клю­чать­ся к пос­ледова­тель­ному пор­ту. Мы под­клю­чаем его к шине USB, но какими тог­да дол­жны быть парамет­ры?

Заг­лядыва­ем в исходни­ки libbt-vendor.so и в катало­ге tvbox/libbt-usb-master/jni/conf находим эта­лон­ный bt_vendor.conf. Берем его и заменя­ем толь­ко два парамет­ра:

  • HCIDevice = N, где N — номер Bluetooth-адап­тера, который ука­зан в пути /sys/class/rfkill/rfkillN/;
  • Type = hci, то есть Bluetooth-адап­тер нап­рямую пре­дос­тавля­ет интерфейс HCI.

За­пишем исправ­ленный кон­фигура­цион­ный файл на прис­тавку вмес­то сущес­тву­юще­го и пов­торим испы­тание. Пос­ле попыт­ки вклю­чить Bluetooth сис­тема сооб­щает, что ищет устрой­ства. Все работа­ет!

ДОРАБОТКИ

Со вре­менем я стол­кнул­ся с новой проб­лемой: прис­тавка иног­да перес­тавала видеть кон­трол­лер, и для вос­ста­нов­ления его работы нуж­но было перезаг­ружать и его, и прис­тавку. Это уби­вало всю радость!

Вско­ре выяс­нилось, что ста­биль­ность работы этой связ­ки силь­но зависит от рас­сто­яния меж­ду прис­тавкой и кон­трол­лером. По всей видимос­ти, виной тому — сла­бая связь меж­ду мини­атюр­ным адап­тером и кон­трол­лером, который может пол­ностью пря­тать­ся в руках. Было эмпи­ричес­ки уста­нов­лено, что ради­ус нор­маль­ной работы — это 1,5–2 мет­ра от прис­тавки.

Спать спо­кой­но мешали и два пре­дуп­режде­ния об ошиб­ках, которые я про­игно­риро­вал при сбор­ке интерфей­сной биб­лиоте­ки. Давай поищем кон­стан­ту по фай­лам в катало­ге libbt-usb-master:

$ grep -R 'BT_VND_OP_EPILOG' *

Я нашел упо­мина­ние в заголо­воч­ном фай­ле external/bluetooth/bluedroid/hci/include/bt_vendor_lib.h. Он наряду с переч­нем иден­тифика­торов сооб­щений содер­жит опи­сание пра­вил их обра­бот­ки. Отту­да мож­но узнать, что сооб­щение BT_VND_OP_SET_AUDIO_STATE отправ­ляет­ся, что­бы про­информи­ровать о сос­тоянии зву­ково­го устрой­ства, и в нашем слу­чае его дей­стви­тель­но мож­но игно­риро­вать. А вот сооб­щение BT_VND_OP_EPILOG говорит о завер­шении работы с устрой­ством, и его нуж­но отправ­лять сте­ку Bluetooth, что­бы сооб­щить, что устрой­ство мож­но отклю­чать вызовом фун­кции epilog_cb.

До­пол­ним конс­трук­цию мно­жес­твен­ного выбора в фай­ле libbt-usb-master/jni/src/bt_vendor_hci.c сле­дующи­ми стро­ками по ана­логии с дру­гими обра­бот­чиками:

case BT_VND_OP_SET_AUDIO_STATE:

break;

case BT_VND_OP_EPILOG:

if (bt_vendor_cbacks) {

ALOGE ("vendor lib op epilog done");

bt_vendor_cbacks -> epilog_cb (BT_VND_OP_RESULT_SUCCESS);

}

break;

Пос­ле это­го ком­пиляция биб­лиоте­ки не вызыва­ет воп­росов. Одна­ко нель­зя исклю­чать, что в каких‑то слу­чаях обра­бот­ка сооб­щений тре­бует более слож­ных дей­ствий. Каких имен­но? Что­бы отве­тить на этот воп­рос, надо глуб­же пог­рузить­ся в прин­ципы вза­имо­дей­ствия под­систе­мы Bluetooth с USB-адап­тером. Воз­можно, кто‑нибудь из читате­лей уви­дит в этом свою задачу, решит ее и рас­ска­жет об этом!

ВЫВОДЫ

Итак, задача пол­ностью решена. Давай напос­ледок вспом­ним и сис­темати­зиру­ем про­делан­ные шаги, что­бы в слу­чае надоб­ности пов­торить их с дру­гим устрой­ством. Мне пот­ребова­лось:

  • соб­рать и уста­новить драй­вер USB-адап­тера, пред­став­ляющий собой модуль ядра /system/lib/modules/btusb.ko;
  • адап­тировать исходни­ки динами­чес­кой биб­лиоте­ки интерфей­са меж­ду под­систе­мой Bluetooth и драй­вером адап­тера libbt-vendor.so к заголо­воч­ным фай­лам и инс­тру­мен­там NDK;
  • под­готовить про­ект NDK, соб­рать и уста­новить файл биб­лиоте­ки /system/vendor/lib/libbt-vendor.so;
  • ак­туали­зиро­вать кон­фигура­цион­ный файл /system/etc/bluetooth/bt_vendor.conf.

По­мимо это­го, для авто­мати­зации запус­ка модуля ядра и уста­нов­ки раз­решений на вир­туаль­ные фай­лы при заг­рузке ОС я сде­лал кон­фигура­цион­ный файл сис­темы ини­циали­зации /system/etc/init/btusb.rc со сле­дующим содер­жимым:

on boot

insmod /system/lib/modules/btusb.ko

chown bluetooth net_bt_stack /sys/class/rfkill/rfkill0/type

chown bluetooth net_bt_stack /sys/class/rfkill/rfkill0/state

chmod 0664 /sys/class/rfkill/rfkill0/state

В име­ни rfkill0 циф­ру 0 может пот­ребовать­ся заменить дру­гим номером, который прис­ваивает­ся USB-адап­теру опе­раци­онной сис­темой.

Вот и все. Это был не самый лег­кий путь, зато мы узна­ли мно­го нового!

Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei



Report Page