В этой статье рассказывается о полезных советах и приемах по отладке звука на устройствах Android.
Раковина
"Тройник" – это функция отладки AudioFlinger, доступная только в специальных сборках. Она позволяет сохранять короткий фрагмент недавнего аудио для последующего анализа. Это позволяет сравнивать то, что было воспроизведено или записано, с тем, что ожидалось.
В целях конфиденциальности приемник tee отключен по умолчанию как во время компиляции, так и во время выполнения. Чтобы использовать приемник tee, его нужно включить, выполнив повторную компиляцию и задав свойство. Не забудьте отключить эту функцию после завершения отладки. В рабочих сборках tee sink не должен быть включен.
Инструкции в этом разделе предназначены для Android 7.x и более поздних версий. Для Android 5.x и 6.x замените /data/misc/audioserver на /data/misc/media. Кроме того, необходимо использовать сборку userdebug или eng. Если вы используете сборку userdebug, отключите проверку с помощью следующей команды:
adb root && adb disable-verity && adb reboot
Настройка во время компиляции
cd frameworks/av/services/audioflinger- Изменить набор "
Configuration.h". - Раскомментируйте
#define TEE_SINK. - Пересоздайте
libaudioflinger.so. adb rootadb remount- Отправьте или синхронизируйте новый файл
libaudioflinger.soс файлом/system/libна устройстве.
Настройка во время выполнения
adb shell getprop | grep ro.debuggable
Убедитесь, что результат выглядит так:[ro.debuggable]: [1]adb shellls -ld /data/misc/audioserver
Убедитесь, что вывод выглядит следующим образом:
drwx------ media media ... media
Если каталога нет, создайте его, выполнив следующие действия:
mkdir /data/misc/audioserverchown media:media /data/misc/audioserverecho af.tee=# > /data/local.prop
где значениеaf.tee– это число, описанное ниже.chmod 644 /data/local.propreboot
Значения для свойства af.tee
Значение атрибута af.tee – это число от 0 до 7, представляющее собой сумму нескольких битов, по одному на каждый признак.
Описание каждого бита приведено в коде по адресу AudioFlinger::AudioFlinger() в AudioFlinger.cpp, но вкратце:
- 1 – вход;
- 2 – выход FastMixer.
- 4 – AudioRecord и AudioTrack для каждой дорожки.
Пока нет бита для глубокого буфера или обычного микшера, но вы можете получить похожие результаты, используя "4".
Тестирование и получение данных
- Запустите проверку аудио.
adb shell dumpsys media.audio_flinger- Найдите в выходных данных
dumpsysстроку, похожую на следующую:
tee copied to /data/misc/audioserver/20131010101147_2.wav
Это PCM-файл в формате WAV. - Затем
adb pullнужные файлы/data/misc/audioserver/*.wav. Обратите внимание, что названия дампов, относящихся к определенным трекам, не появляются в выходных данныхdumpsys, но сохраняются в/data/misc/audioserverпосле закрытия трека. - Прежде чем делиться файлами дампа с другими пользователями, проверьте их на наличие конфиденциальной информации.
Рекомендации
Вот несколько советов, которые помогут вам получать более полезные результаты:
- Отключите звуки нажатия клавиш и касания экрана, чтобы они не мешали тестированию.
- Увеличьте громкость до максимума.
- Отключите приложения, которые воспроизводят звук или записывают его с микрофона, если они не нужны для тестирования.
- Дампы, относящиеся к определенному треку, сохраняются только при закрытии трека. Чтобы получить дампы, относящиеся к определенному треку, может потребоваться принудительно закрыть приложение.
- Выполните
dumpsysсразу после теста, так как объем памяти для записи ограничен. - Чтобы не потерять файлы дампа, периодически загружайте их на хост. Сохраняется только ограниченное количество файлов дампа. Когда это количество достигнуто, более старые файлы удаляются.
Восстановить
Как отмечалось выше, функцию tee sink не следует оставлять включенной. Чтобы восстановить сборку и устройство, выполните следующие действия:
- Отмените изменения в исходном коде для
Configuration.h. - Пересоздайте
libaudioflinger.so. - Отправьте или синхронизируйте восстановленный файл
libaudioflinger.soс файлом/system/libна устройстве. adb shellrm /data/local.proprm /data/misc/audioserver/*.wavreboot
media.log
Макросы ALOGx
Стандартный API ведения журналов на языке Java в Android SDK – android.util.Log.
Соответствующий API на языке C в Android NDK:
__android_log_print
объявлен в <android/log.h>.
В нативной части фреймворка Android мы предпочитаем макросы с именами ALOGE, ALOGW, ALOGI, ALOGV и т. д. Они объявлены в <utils/Log.h>, и в этой статье мы будем называть их ALOGx.
Все эти API просты в использовании и понятны, поэтому они широко распространены на платформе Android. В частности, процесс mediaserver, в который входит звуковой сервер AudioFlinger, активно использует ALOGx.
Однако у ALOGx и его друзей есть ограничения:
-
Они подвержены "спаму журнала": буфер журнала является общим ресурсом, поэтому он может легко переполниться из-за несвязанных записей в журнале, что приведет к потере информации. Вариант
ALOGVпо умолчанию отключен во время компиляции. Но, конечно, даже это может привести к спаму в журнале, если он включен. -
Системные вызовы ядра могут блокироваться, что может привести к инверсии приоритетов и, как следствие, к нарушениям и неточностям измерений. Это особенно важно для потоков, критичных ко времени, таких как
FastMixerиFastCapture. - Если определенный журнал отключен, чтобы уменьшить количество спама в журналах, то любая информация, которая могла бы быть записана в этот журнал, будет потеряна. Нельзя включить определенный журнал после того, как станет ясно, что он мог бы быть полезен.
NBLOG, media.log и MediaLogService
API NBLOG и связанные с ними media.logпроцесс и MediaLogServiceсервис образуют новую систему регистрации медиаконтента, специально разработанную для решения перечисленных выше проблем. Мы будем использовать термин "media.log" для обозначения всех трех, но строго говоря, NBLOG – это Logging API C++, media.log – название процесса Linux, а MediaLogService – сервис Android binder для просмотра журналов.
media.log «хронология» – это серия записей в журнале, относительный порядок которых сохранен.
По соглашению каждый поток должен использовать собственную временную шкалу.
Преимущества
Преимущества системы media.log:
- Не засоряет основной журнал, пока это не потребуется.
- Его можно изучить, даже если
mediaserverаварийно завершает работу или зависает. - Неблокирующий по хронологии.
- Меньше влияет на эффективность. (Конечно, любой способ ведения журнала в той или иной степени влияет на работу системы.)
Архитектура
На схеме ниже показано, как связаны процессы mediaserver и init до внедрения media.log.
Рисунок 1. Архитектура до media.log
Важные моменты:
initfork и execmediaserver.initобнаруживает смертьmediaserverи при необходимости повторно разветвляется.- Журналы
ALOGxне показываются.
На диаграмме ниже показана новая взаимосвязь компонентов после добавления в архитектуру свойства media.log.
Рисунок 2. Архитектура после media.log
Важные изменения
-
Клиенты используют API
NBLOGдля создания записей в журнале и добавления их в кольцевой буфер в общей памяти. -
MediaLogServiceможет в любой момент сбросить содержимое циклического буфера. -
Круговой буфер разработан таким образом, что повреждение общей памяти не приведет к сбою
MediaLogService. При этом он сможет сохранить ту часть буфера, которая не была повреждена. - Кольцевой буфер не блокируется и не блокирует запись новых и чтение существующих записей.
- Для записи в кольцевой буфер или чтения из него не требуются системные вызовы ядра (за исключением необязательных временных меток).
Поддерживаемые страны
В Android 4.4 есть лишь несколько точек регистрации в AudioFlinger, которые используют систему media.log. Новые API не так просты в использовании, как ALOGx, но и не слишком сложны.
Рекомендуем вам изучить новую систему ведения журналов, чтобы использовать ее в тех случаях, когда она необходима.
В частности, его рекомендуется использовать для потоков AudioFlinger, которые должны выполняться часто, периодически и без блокировки, например для потоков FastMixer и FastCapture.
Как использовать презентацию
Как добавить журналы
Сначала добавьте в код журналы.
В цепочках FastMixer и FastCapture используйте следующий код:
logWriter->log("string");
logWriter->logf("format", parameters);
logWriter->logTimestamp();
Поскольку эта временная шкала NBLog используется только потоками FastMixer и FastCapture, взаимное исключение не требуется.
В других потоках AudioFlinger используйте mNBLogWriter:
mNBLogWriter->log("string");
mNBLogWriter->logf("format", parameters);
mNBLogWriter->logTimestamp();
Для потоков, отличных от FastMixer и FastCapture, временную шкалу NBLog потока можно использовать как для самого потока, так и для операций связывания. NBLog::Writer не обеспечивает неявное взаимное исключение для временной шкалы, поэтому убедитесь, что все записи журнала выполняются в контексте, в котором удерживается мьютекс потока mLock.
После того как вы добавите журналы, пересоберите AudioFlinger.
Внимание!
Для каждого потока требуется отдельная временная шкала NBLog::Writer, чтобы обеспечить безопасность потока, поскольку временные шкалы по умолчанию не содержат мьютексов. Если вы хотите, чтобы несколько потоков использовали одну и ту же временную шкалу, защитите ее с помощью существующего мьютекса (как описано выше для mLock). Также можно использовать оболочку NBLog::LockedWriter вместо NBLog::Writer.
Однако это нивелирует основное преимущество API – его неблокирующее поведение.
Полная документация по API NBLog доступна на странице frameworks/av/include/media/nbaio/NBLog.h.
Как включить media.log
media.log по умолчанию отключен. Оно активно, только если свойство ro.test_harness имеет значение 1. Чтобы включить ее:
adb rootadb shellecho ro.test_harness=1 > /data/local.propchmod 644 /data/local.propreboot
Во время перезагрузки подключение будет потеряно, поэтому:
adb shell
ps media покажет два процесса:
- media.log
- mediaserver
Запишите идентификатор процесса mediaserver.
Как посмотреть хронологию
Вы можете вручную запросить дамп журнала в любое время. Эта команда показывает журналы всех активных и недавних временных шкал, а затем очищает их:
dumpsys media.log
Обратите внимание, что временные шкалы независимы друг от друга и их нельзя объединить.
Восстановление журналов после сбоя медиасервера
Теперь попробуйте завершить процесс mediaserver: kill -9 #, где # – это идентификатор процесса, который вы записали ранее. В основном файле logcat должен появиться дамп из media.log, в котором будут показаны все журналы, предшествующие сбою.
dumpsys media.log