Android, не хрипи! Погружаемся в недра ОС, чтобы найти и устранить баг

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

  • В каком ухе у меня жужжит?
  • Методика и инструменты исследования
  • Звуковая подсистема приставки
  • Уровень аудиосервера
  • Сбор информации о службах
  • Переключение с колонок на цифровой выход
  • Настройка уровня громкости
  • Уровень ALSA
  • Изучение документации
  • Исследование /proc/asound
  • Применение утилиты tinymix
  • Управление аудиоконцентратором
  • Поиск свежих идей
  • Уровень слоя абстракции Audio HAL
  • Исследование файла audio.primary.cupid.so
  • Настройки в ac100_paths.xml
  • Дизассемблирование библиотеки HAL
  • Исправление библиотеки HAL
  • Испытание исправленной библиотеки
  • Заключение

Се­год­ня нас с тобой ждет нас­тоящая экспе­диция вглубь Android. Нашей сиюми­нут­ной целью будет устра­нить баг вос­про­изве­дения зву­ка на телеп­ристав­ке X96Q PRO. На пути к этой цели мы под­робно изу­чим все час­ти зву­ковой сис­темы и научим­ся вно­сить изме­нения в низ­коуров­невые нас­трой­ки, недос­тупные из гра­фичес­кого интерфей­са.

Android в нашей подопыт­ной прис­тавке точ­но такой же, как в телефо­нах и авто­маг­нитолах. Все прин­ципи­аль­ные све­дения, кро­ме кон­крет­ных схем и кон­крет­ного кода биб­лиоте­ки HAL, акту­аль­ны для всех устрой­ств на Android 10, и, с боль­шой долей веро­ятности, от Android 7 до Android 13 вклю­читель­но. Начиная с вер­сии 14 в Android ста­ли исполь­зовать язык опи­сания интерфей­са AIDL вмес­то HIDL, но это каса­ется в боль­шей сте­пени низ­коуров­невых раз­работ­чиков.

 

В каком ухе у меня жужжит?

Эта исто­рия началась с замены телеви­зион­ной прис­тавки. У меня был ста­рень­кий девайс с одним гигабай­том памяти — на сме­ну ему я выб­рал модель X96Q PRO в вари­анте с дву­мя гигабай­тами опе­ратив­ки. Ее опе­раци­онная сис­тема Android 10 не зах­ламле­на, в ней раз­бло­киро­вана воз­можность получе­ния прав супер­поль­зовате­ля. Кажет­ся, то что надо.

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

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

В художес­твен­ных филь­мах или новос­тных прог­раммах это поч­ти незамет­но, но в отдель­ных музыкаль­ных ком­позици­ях звук иска­жал­ся до невоз­можнос­ти. Я не ауди­офил и меня не испу­гать записью кон­церта в MP3 со ско­ростью потока 128 Кбит/с. Но щел­чки все же ста­ли дей­ство­вать на нер­вы. Я понял, что если это не испра­вить, то ско­ро нач­нет дер­гать­ся глаз.

Ес­ли у тебя есть устрой­ство с Android, ты можешь пря­мо сей­час про­верить, при­сущ ли ему опи­сыва­емый дефект. Для это­го вос­про­изве­ди файл 1TR110-1_Kap8.1_Waehlton.ogg с записью гуд­ка евро­пей­ской телефон­ной стан­ции (это синусо­ида с час­тотой 425 Гц). На качес­твен­ном устрой­стве тон дол­жен быть чис­тым, мяг­ким и ров­ным. Если же звук пла­вает, в нем слыш­ны пос­торон­ние шумы или пот­рески­вания, то сочувс­твую: твое устрой­ство под­верже­но проб­леме, которую мы будем решать в этой статье.

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

 

Методика и инструменты исследования

Сна­чала, как любой нор­маль­ный человек, я попытал­ся нас­тро­ить звук через интерфейс Android, но выбор там невелик: все­го‑то и мож­но, что вклю­чить или вык­лючить AUDIO_CODEC, AUDIO_HDMI и режим проб­роса зву­ка passthrough. Вне зависи­мос­ти от уста­нов­ленных флаж­ков, дефек­ты зву­ка про­дол­жали свое дес­трук­тивное воз­дей­ствие на пси­хику.

Я переб­рал нес­коль­ко меди­апро­игры­вате­лей, но это тоже не дало резуль­тата. Вот и все, обыч­ный поль­зователь потер­пел пораже­ние в этой схват­ке с Android. Поэто­му на сце­ну приш­лось вый­ти инже­неру. Инже­нер­ный под­ход к решению проб­лем под­разуме­вает сбор и изу­чение дос­тупной информа­ции об объ­екте, его диаг­ности­ку для выяс­нения при­чин проб­лемы, выбор решения и исправ­ление ситу­ации. Что ж, прис­тупим!

План иссле­дова­ния зву­ковой под­систе­мы Android сле­дующий:

  • Ана­лиз сис­темно­го жур­нала Android, который мож­но получить с помощью коман­ды logcat.
  • Изу­чение сос­тояний служб Android, све­дения о которых мож­но получить с помощью коман­ды dumpsys.
  • Изу­чение сос­тояния под­систе­мы ALSA по содер­жимому катало­га /proc/asound и с помощью ути­литы tinymix.
  • Ана­лиз динами­чес­кой биб­лиоте­ки слоя абс­трак­ции Audio HAL в сре­де Ubuntu с помощью дизас­сем­бле­ра objdump.
  • Ана­лиз исходных тек­стов опе­раци­онной сис­темы Android.
  • Осторожно, кирпич!

    Вно­ся изме­нения в кон­фигура­цион­ные фай­лы Android-устрой­ства, ока­залось уди­витель­но лег­ко при­вес­ти его в нерабо­тос­пособ­ное сос­тояние, или, как говорят, «окир­пичить». Нап­ример, если в теге HDMI Out фай­ла audio_policy_configuration.xml сло­во Out написать с малень­кой бук­вы, заг­рузка телеви­зион­ной прис­тавки будет оста­нав­ливать­ся на эта­пе демонс­тра­ции ани­миро­ван­ной зас­тавки.

    В боль­шинс­тве слу­чаев вос­ста­нов­ление работос­пособ­ности воз­можно, но для это­го пот­ребу­ются спе­циаль­ные зна­ния и софт. С пос­ледним слож­нее все­го. На стра­нич­ке прис­тавки X96Q PRO есть четыре вари­анта firmware, но толь­ко один под­ходит к моему экзем­пля­ру. Попыт­ка «про­шить» дру­гие при­водит к тому, что устрой­ство перес­тает опоз­навать­ся даже сер­висным ПО.

    По­это­му трез­во оце­ни свои силы перед тем, как что‑то сде­лать на реаль­ном обо­рудо­вании. Как минимум заранее озна­комь­ся с опы­том неудач­ников на темати­чес­ких форумах. Но все рав­но будь готов к тому, что устрой­ство может быть без­надеж­но испорче­но.

    Ко­ман­ды мож­но выпол­нять непос­редс­твен­но в кон­соли устрой­ства из при­ложе­ния‑тер­минала, нап­ример, Terminal Emulator for Android. Но я исполь­зовал воз­можнос­ти уда­лен­ной отладки устрой­ств с Android, для чего уста­новил на свой компь­ютер пакет SDK Platform Tools с ути­литой коман­дной стро­ки adb.

    Для замены кон­фигов и уста­нов­ки ути­литы tinymix я исполь­зовал при­ложе­ние Magisk, которое дает пра­ва супер­поль­зовате­ля и поз­воля­ет офор­млять модифи­кации в виде под­клю­чаемых модулей.

    Хоть прис­тавка и была изна­чаль­но рутова­на, в исполь­зовании Magisk наш­лось неос­поримое пре­иму­щес­тво. Если с новым вари­антом кон­фига прис­тавка не заг­ружа­ется, дос­таточ­но дваж­ды перезаг­рузить ее, перепод­клю­чая блок питания. Magisk под­счи­тыва­ет количес­тво неудач­ных вклю­чений и на тре­тий раз отклю­чает все уста­нов­ленные модули, что поз­воля­ет прис­тавке заг­рузить­ся в завод­ском исполне­нии.

    info

    Иног­да Magisk при­водит к инте­рес­ным побоч­ным эффектам. Я заметил, что при активном модуле с исправ­лени­ями пос­ле перезаг­рузки вос­ста­нав­лива­ется рас­положе­ние пли­ток на рабочем сто­ле ATV Launcher. Что­бы перемес­тить плит­ки «нав­сегда», надо сна­чала отклю­чить модуль, потом выпол­нить переме­щения, пос­ле чего сно­ва его вклю­чить. Такая защита от слу­чай­ного наруше­ния при­выч­ной рас­клад­ки интерфей­са мне показа­лась очень удоб­ной.

    Что такое цифровой звук

    Что­бы луч­ше понимать работу зву­ковой под­систе­мы прис­тавки, надо вспом­нить, что собой пред­став­ляют зву­ковые дан­ные. Как ты зна­ешь из школь­ного кур­са физики, человек слы­шит звук из‑за изме­нения дав­ления воз­духа на рас­положен­ную в ухе барабан­ную перепон­ку с час­тотой 20 — 20000 Гц. Этот про­цесс, как и все осталь­ные физичес­кие про­цес­сы в мак­ромире, бла­года­ря явле­нию инер­ции явля­ется плав­ным и неп­рерыв­ным.

    Для исполь­зования в компь­ютер­ной тех­нике ана­лого­вая физичес­кая величи­на — в дан­ном слу­чае дав­ление воз­духа — пред­став­ляет­ся конеч­ной пос­ледова­тель­ностью чисел из огра­ничен­ного набора с помощью двух под­ходов: дис­кре­тиза­ции по вре­мени и кван­тования по уров­ню.

    Оциф­ровка зву­ка про­исхо­дит путем дис­кре­тиза­ции по вре­мени и кван­тования по уров­ню

    Суть дис­кре­тиза­ции сос­тоит в записи зна­чений физичес­кой величи­ны не неп­рерыв­но, а толь­ко в опре­делен­ные момен­ты вре­мени, сле­дующие с опре­делен­ной час­тотой. Выбор час­тоты дис­кре­тиза­ции опре­деля­ется теоре­мой отсче­тов (Котель­никова — Най­квис­та — Шен­нона), которая гла­сит, что исходный сиг­нал, мак­сималь­ная час­тота ком­понен­тов которо­го не пре­выша­ет F, мож­но пол­ностью вос­ста­новить по изме­рен­ным отсче­там, сле­дующим с час­тотой не мень­ше 2 × F. Таким обра­зом, по отсче­там с час­тотой дис­кре­тиза­ции 44100 Гц мож­но вос­ста­новить сиг­нал, час­тота ком­понен­тов которо­го не пре­выша­ет 22050 Гц, что перек­рыва­ет ука­зан­ный выше диапа­зон зву­ков, слы­шимых челове­ком.

    Впро­чем, точ­ное вос­ста­нов­ление сиг­нала воз­можно лишь в том слу­чае, если изме­рен­ные зна­чения записа­ны без оши­бок. Одна­ко ана­лого‑циф­ровые пре­обра­зова­тели (АЦП) отоб­ража­ют изме­рен­ную дат­чиком физичес­кую величи­ну на конеч­ную раз­рядную сет­ку машин­ного пред­став­ления чис­ла, выпол­няя кван­тование зна­чения по уров­ню. Это неиз­бежно ведет к ошиб­кам (пог­решнос­тям) записи изме­рен­ных зна­чений. Нап­ример, 16-раз­рядные АЦП неп­рерыв­ный интервал изме­нения физичес­кой величи­ны отоб­ража­ют на 216 = 65536 уров­ней, которые могут быть про­нуме­рова­ны целыми чис­лами из диапа­зона -32768…+32767.

    Опи­сан­ный спо­соб записи ана­лого­вого сиг­нала в циф­ровой фор­ме называ­ется импуль­сно‑кодовой модуля­цией PCM (Pulse-Code Modulation). Для уве­личе­ния ком­пак­тнос­ти записей исполь­зуют­ся раз­ные методы их сжа­тия: с потеря­ми (AAC, MP3, OGG) или без потерь (FLAC, WMA Losseless). Но перед вос­про­изве­дени­ем дан­ные все рав­но пот­ребу­ется рас­паковать в импуль­сно‑кодовую фор­му, которая при­год­на для непос­редс­твен­ного пре­обра­зова­ния в физичес­кую величи­ну — звук.

     

    Звуковая подсистема приставки

    В Android зап­росы на работу со зву­ком обслу­жива­ет служ­ба Audio Flinger сер­вера зву­ка, которая через слой абс­трак­ции от аппа­рату­ры HAL (Hardware Abstraction Layer) управля­ет зву­ковой под­систе­мой ALSA (Advanced Linux Sound System) уров­ня ядра.

    При­ложе­ния для вос­про­изве­дения зву­ка в Android исполь­зуют объ­ект клас­са android.media.AudioTrack, с помощью которо­го дан­ные в кодиров­ке PCM из прог­рам­мно­го буфера нап­равля­ются в устрой­ство вос­про­изве­дения. Служ­ба Audio Flinger тес­но вза­имо­дей­ству­ет со служ­бой Audio Policy, которая на осно­ве кон­фига audio_policy_configuration.xml опре­деля­ет, какие устрой­ства и в каком режиме дол­жны исполь­зовать­ся для вос­про­изве­дения зву­ка.

    Ус­трой­ство зву­ковой под­систе­мы Android

    Слой аппа­рат­ной абс­трак­ции (HAL) сопос­тавля­ет стан­дар­тные вир­туаль­ные устрой­ства Android — такие как AUDIO_DEVICE_OUT_SPEAKER (встро­енный динамик), AUDIO_DEVICE_OUT_WIRED_HEADPHONE (про­вод­ные науш­ники) и AUDIO_DEVICE_OUT_AUX_DIGITAL (циф­ровой ауди­овы­ход) — с кон­крет­ным физичес­ким обо­рудо­вани­ем. Это обо­рудо­вание опре­деля­ется и нас­тра­ивает­ся на уров­не ядра Linux через опи­сание в дереве устрой­ств (Device Tree).

    Раз­работ­чики HAL перечис­ляют устрой­ства, которые могут исполь­зовать­ся ауди­осер­вером, в сек­ции <devicePorts> фай­ла audio_policy_configuration.xml, нап­ример:

    <devicePorts> <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink"></devicePort> <devicePort tagName="HDMI Out" type="AUDIO_DEVICE_OUT_AUX_DIGITAL" role="sink"></devicePort></devicePorts>

    В при­веден­ном при­мере вир­туаль­ному устрой­ству AUDIO_DEVICE_OUT_SPEAKER, которое игра­ет роль при­емни­ка зву­ка sink (в про­тиво­полож­ность источни­кам зву­ка — source), наз­нача­ется имя Speaker. По это­му име­ни на устрой­ство ссы­лают­ся в дру­гих мес­тах кон­фига. Нап­ример, при перечис­лении ауди­оус­трой­ств, которые встро­ены в прис­тавку (в про­тиво­полож­ность устрой­ствам, которые могут под­клю­чать­ся пери­оди­чес­ки):

    <attachedDevices> <item>Speaker</item></attachedDevices> 

    Уровень аудиосервера

     

    Сбор информации о службах

    Ана­лизи­ровать работу зву­ковой под­систе­мы Android на уров­не ауди­осер­вера помога­ет информа­ция о сос­тоянии служб, которую выводит коман­да dumpsys. В нашем слу­чае полез­ны два вари­анта этой коман­ды:

    dumpsys media.audio_policy dumpsys media.audio_flinger

    Пер­вая коман­да рас­ска­зыва­ет о том, как были интер­пре­тиро­ваны нас­трой­ки из audio_policy_configuration.xml. В час­тнос­ти, какой имен­но кон­фиг исполь­зует­ся:

    Config source: /vendor/etc/audio_policy_configuration.xml

    Да­лее dumpsys в понят­ной фор­ме отоб­ража­ет пра­вила, взя­тые из кон­фига. Нап­ример, све­дения об устрой­ствах и при­ори­тет­ном канале вос­про­изве­дения зву­ка опи­сыва­ются так:

    <modules> <module name="primary" halVersion="2.0"> <attachedDevices> <item>Speaker</item> ... </attachedDevices> <defaultOutputDevice>Speaker</defaultOutputDevice> <mixPorts> <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY"> <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> </mixPort> ... </mixPorts> <devicePorts> <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink"></devicePort> <devicePort tagName="HDMI Out" type="AUDIO_DEVICE_OUT_AUX_DIGITAL" role="sink"></devicePort> ... </devicePorts> <routes> <route type="mix" sink="Speaker" sources="primary output"/> <route type="mix" sink="HDMI Out" sources="primary output"/> ... </routes> </module></modules>

    А вот рас­шифров­ка:

    - Available output devices: Device 1: - id: 2 - tag name: Speaker - type: AUDIO_DEVICE_OUT_SPEAKER - Profiles: Profile 0:[dynamic format][dynamic channels][dynamic rates] ... HW Modules dump: - HW Module 1: - name: primary - handle: 10 - version: 2.0 - outputs: output 0: - name: primary output - Profiles: Profile 0: - format: AUDIO_FORMAT_PCM_16_BIT - sampling rates:48000 - channel masks:0x0003 - flags: 0x0002 (AUDIO_OUTPUT_FLAG_PRIMARY) - Supported devices: Device 1: - id: 2 - tag name: Speaker - type: AUDIO_DEVICE_OUT_SPEAKER ... Device 7: - tag name: HDMI Out - type: AUDIO_DEVICE_OUT_AUX_DIGITAL|AUDIO_DEVICE_OUT_HDMI

    Пор­ты мик­шера mixPort опи­сыва­ют раз­ные тех­нологии обра­бот­ки зву­ковых дан­ных, которые опре­деля­ются ком­бинаци­ей зна­чений в атри­буте flags. Нап­ример, в нас­трой­ках обя­затель­но дол­жен при­сутс­тво­вать единс­твен­ный при­ори­тет­ный порт мик­шера с фла­гом AUDIO_OUTPUT_FLAG_PRIMARY. Дру­гие вари­анты пор­тов: AUDIO_OUTPUT_FLAG_DEEP_BUFFER — исполь­зование «глу­боко­го» буфера для ауди­опо­токов, допус­кающих задер­жку вос­про­изве­дения, AUDIO_OUTPUT_FLAG_DIRECT — нап­равле­ние дан­ных непос­редс­твен­но на устрой­ство вос­про­изве­дения, AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD — обра­бот­ка упа­кован­ных дан­ных (MP3, AAC и дру­гих) с помощью аппа­рат­ного декоде­ра.

    Свя­зи пор­тов мик­шера с устрой­ства­ми вос­про­изве­дения зву­ка опи­сыва­ются в сек­ции мар­шру­тов <routes>. Для каж­дого устрой­ства‑при­емни­ка sink может быть ука­зано через запятую нес­коль­ко пор­тов‑источни­ков зву­ка sources.

    Источник: xakep.ru

    Ответить

    Ваш адрес email не будет опубликован. Обязательные поля помечены *