docs(call): record validated Bluetooth lifecycle fix and regressions
This commit is contained in:
1 parent
2e8885548b
commit
b84a6ab3b9
2 files changed
+139
-1
No files matched your search
+126
-1
@@ -25,7 +25,11 @@ desktop-профиль25/25 PASS; подтверждён дефект Android mu
|
||||
Новая регрессия5/5, voice/desktop30/30, Android timing/trace14/14,
|
||||
assembleDebug для двух ABI и check203/203 PASS,proxy9/9,burst1/1,load8/8,168с.
|
||||
Диагностика/план — раздел13, внедрение/актуальная проверка — раздел14.
|
||||
База проверки: f79b9261, чистое рабочее дерево после предыдущего push stream.
|
||||
Продолжена проверка Android playback/router. После отдельного согласования
|
||||
плана исправлено владение Bluetooth proxy при позднем callback, disconnect
|
||||
и restart; постоянные JVM-регрессии15/15, прежний профиль26/26,
|
||||
voice30/30, сборки и check204/204 PASS. Подробности — раздел15.
|
||||
Исходная база аудита: f79b9261, чистое дерево после предыдущего push stream.
|
||||
|
||||
1. Подтверждённый дефект: call_start не проверяет обычную занятость
|
||||
|
||||
@@ -1036,3 +1040,124 @@ IPv6/lo включены только в отдельном sudo unshare --net;
|
||||
запускались. Реальная акустика/переключение mute на устройстве требуют отдельного
|
||||
контроля; непосредственное последействие lossy Opus-декодера этим тестом не измеряется.
|
||||
Новые коммиты локальные, push в этом шаге не выполнялся.
|
||||
|
||||
15. Android I/O: владение Bluetooth profile proxy и проверка исправления
|
||||
|
||||
База этого продолжения — опубликованный fa76447f, после rebase Android mute.
|
||||
Прочитаны CallAudioEngine/CallAudioOutput, playback clock/buffer/recovery,
|
||||
CallAudioRouter, владельцы в CallController/MediaAudioController и native
|
||||
android_call_output_jni.c. Это продолжение платформенной проверки голоса;
|
||||
видео и оставшиеся core/platform контракты целиком не закрыты.
|
||||
|
||||
Подтверждённый дефект и SDK-контракт
|
||||
|
||||
Прежний router принимал onServiceConnected без проверки started/поколения.
|
||||
stop до первого callback оставлял принятый Android proxy открытым;
|
||||
disconnect обнулял btHeadset/btProfileProxyBound, хотя владение сохранялось;
|
||||
при stop/start старый callback мог подменить proxy нового lifecycle.
|
||||
При последующем connected новый proxy перезаписывал ссылку на старый.
|
||||
|
||||
Сверены локальные исходники установленного Android SDK36:
|
||||
BluetoothAdapter.java:884–931,3412–3491,3495–3539,3690–3740;
|
||||
BluetoothHeadset.java:498–512 в /home/user/android/sources/android-36/android/bluetooth/.
|
||||
getProfileProxy регистрирует proxy до доставки callback через main Handler.
|
||||
Отключение сервиса/Bluetooth сохраняет регистрацию до closeProfileProxy;
|
||||
закрытие идемпотентно, getConnectedDevices без сервиса возвращает пустой список.
|
||||
MediaAudioController действительно вызывает router.start из I/O executor,
|
||||
поэтому одного сравнения поколения вне общей критической секции недостаточно.
|
||||
|
||||
Сначала без изменений проекта проверены два штатных контроля PASS и три
|
||||
ожидаемых FAIL старого router: late, disconnected, pending_restart.
|
||||
Временная модель в /tmp/call-router-audit управляет порядком API callbacks;
|
||||
читает приватное состояние только для диагностики, не подставляет его.
|
||||
Кандидат /tmp/call-router-audit/CallAudioRouterCandidate.kt:9/9 PASS,
|
||||
включая64 конкурентных callback/stop; после cleanup нет открытых proxy.
|
||||
Компиляция кандидата с настоящими типами SDK36 PASS; прежний Android
|
||||
timing/trace/buffer/recovery профиль26/26 PASS. Проект/документы/чек-лист
|
||||
на этапе обсуждения плана не менялись, новых коммитов не было.
|
||||
/tmp/call-router-plan-candidate.diff, /tmp/call-router-plan-{build,results,sdk-build,validation}.log;
|
||||
исходные логи /tmp/call-router-audit-*.log.
|
||||
|
||||
Согласованный план и внедрение
|
||||
|
||||
По запросу пользователя план сначала изложен в чате и проверен на временном
|
||||
кандидате; после следующего «ok» внедрён в production CallAudioRouter:
|
||||
1) btHeadset означает владение; btProfileAdapter хранит создавший adapter.
|
||||
Удалён дублирующий флаг btProfileProxyBound. started/proxy имеют volatile
|
||||
для читателей вне монитора; adapter/поколение используются под монитором.
|
||||
2) start, уже синхронизированный stop и оба BT callbacks используют один
|
||||
существующий монитор router. Новых потоков и объектов lock нет.
|
||||
3) Запрос захватывает поколение/adapter. Текущий connected принимает proxy;
|
||||
поздний connected закрывает его через захваченный adapter, не меняя owner.
|
||||
4) Текущий disconnected сохраняет ссылки и обновляет доступность устройств;
|
||||
старый disconnected игнорируется. Reconnect того же proxy разрешён.
|
||||
5) stop инвалидирует поколение до раннего return, отсоединяет ссылки до
|
||||
Android close и закрывает также proxy отключённого сервиса. Повтор stop
|
||||
не закрывает тот же owner повторно. Пока pending-запрос не дал proxy,
|
||||
публичный API не позволяет закрыть его: очистка происходит при connected.
|
||||
|
||||
Логи CallAudioRouter содержат generation/current, proxy, accepted,
|
||||
connected/retained/owned closed/stale closed/ignored. Отказ запроса и API
|
||||
exceptions имеют WARN/ERROR; успешный media hot path не получил новых логов.
|
||||
Сигнатуры публичного router, wire, JNI, DSP и алгоритмы playback не менялись.
|
||||
|
||||
Постоянная регрессия и отрицательный контроль
|
||||
|
||||
Добавлен отдельный Kotlin/JVM Gradle-модуль tools/chatgui-android/router-tests.
|
||||
Он компилирует реальный CallAudioRouter.kt приложения с минимальными моделями
|
||||
Android API. Поля router не подменяются и не читаются через reflection;
|
||||
критерии — публичная доступность/route, callbacks, API close и реестр proxy
|
||||
на стороне fixture. Модель не создаёт системных Bluetooth/Binder-ресурсов.
|
||||
JUnit15/15 PASS, failures0/errors0/skipped0:
|
||||
- connected/stop, два штатных restart, duplicate start и повтор stop;
|
||||
- late connected после stop, disconnect/stop, pending stop/start;
|
||||
- reconnect одного proxy, старый disconnected после принятия нового proxy;
|
||||
-64 конкурентных callback/stop с join и проверкой ownership после каждого;
|
||||
- I/O start, задержанный внутри getProfileProxy барьером, одновременные
|
||||
callback/stop: все потоки завершаются, proxy/device callback освобождены;
|
||||
- rejected request, exception, отсутствие adapter, отзыв permission после acquire.
|
||||
Все положительные cleanup оставляют0 proxy и0 зарегистрированных device callbacks;
|
||||
неожиданных ERROR нет. Два WARN намеренно проверяют rejected/throw request.
|
||||
|
||||
Обычная задача :app:testDebugUnitTest зависит от :router-tests:test только
|
||||
через зависимость задач. JVM fixtures не включены в classpath приложения/APK.
|
||||
JUnit используется той же версии4.13.2, Kotlin1.9.20; новых внешних библиотек нет.
|
||||
Параметры routerSourceDir/routerTestsBuildDir позволяют независимый старый
|
||||
исходник/выход сборки в /tmp без замены production файлов или положительных результатов.
|
||||
С router из fa76447f: штатный connectedStop PASS, late/disconnected/pendingRestart
|
||||
дают ровно три ожидаемых FAIL из четырёх тестов, Gradle exit1.
|
||||
Каждый FAIL показывает оставшееся владение; @After очищает только объекты
|
||||
fixture. Это проверка чувствительности к исходному дефекту, не сбой исправления.
|
||||
/tmp/call-bt-fix-negative.log и /tmp/call-bt-fix-negative-build/test-results/test/.
|
||||
Положительный и отрицательный вывод новых сценариев прочитан полностью.
|
||||
|
||||
Сборка и общий профиль
|
||||
|
||||
./build.sh --no-gui -j4 PASS. Android Gradle одним запуском выполняет
|
||||
:router-tests:test, :app:testDebugUnitTest для Timing8/Trace6/PlaybackBuffer10/
|
||||
OutputRecovery2 и assembleDebug:15+26 PASS, BUILD SUCCESSFUL13с.
|
||||
APK содержит arm64-v8a/x86_64 libutun.so, fixture-маркеров в DEX нет.
|
||||
Известное предупреждение AGP8.2 о compileSdk36 и четыре unused-параметра
|
||||
моделей API не являются ошибками сборки. APK не устанавливался.
|
||||
После уточнения только комментария снимка устройств финальный assembleDebug
|
||||
также PASS,1с; поведение router после положительных тестов не менялось.
|
||||
/tmp/call-bt-fix-{native-build,android-build,android-final-build,gradle}.log;
|
||||
JUnit XML в router-tests/build/test-results/test и app/build/test-results/testDebugUnitTest.
|
||||
|
||||
CMake configure/build и voice/desktop30/30 PASS,20,41с. Включены прежние
|
||||
тесты mute/TX/часов/очередей/восстановления. Эти тесты не выполняют Bluetooth.
|
||||
/tmp/call-bt-fix-voice-{configure,build,tests,details}.log.
|
||||
Полный ./check.sh:204 passed,0 failed,0 skipped,exit0,173с;
|
||||
proxy9/9,burst1/1 (8388608 байт),load8/8 (134217728 байт), обе стороны rc0.
|
||||
JVM-регрессии15 и CMake voice30 в число C-only204 не входят.
|
||||
/tmp/call-bt-fix-{full-check,check-runner}.log и {check,netns}.sh.
|
||||
Весь общий вывод прочитан. IPv6/lo включались только в отдельном network
|
||||
namespace; check работал от user. Host all/default/lo disable_ipv6=1 сохранены.
|
||||
|
||||
Задача закрыта, doc/chat_call_arch.md обновлён: BT ownership, AAudio20мс/
|
||||
AudioTrack40мс, reporter resize и переоткрытие выхода playback worker,
|
||||
сохранение незаписанного хвоста и база общего счётчика без обещания replay
|
||||
прежней принятой устройством очереди. Runtime playback этим исправлением не менялся.
|
||||
Общий аудит остаётся частичным:call0[V]/11[~]/10[ ],desktop8[~],архитектура[~],видео[ ].
|
||||
Настоящие Binder callbacks, акустика/BT на телефоне, новый sanitizer и
|
||||
Windows/FreeBSD runtime не проверялись. Коммиты локальные, push не выполнялся.
|
||||
@@ -33,6 +33,19 @@
|
||||
Подробности: [dm_audit_findings.txt](dm_audit_findings.txt),раздел9; /tmp/dm-utf8-fix-*.log.
|
||||
Исправление закрыто; полный аудит DM остаётся частичным, аппаратные GUI/Android не проверялись.
|
||||
|
||||
[+] **Android CallAudioRouter: владение Bluetooth proxy при stop/restart** — исправлено 26.10.2026.
|
||||
Поколение запроса и общий монитор start/stop/BT callbacks исключают принятие proxy старого lifecycle.
|
||||
Disconnect сохраняет owner до close; stop отсоединяет ссылки и закрывает через создавший adapter,
|
||||
поздний connected закрывает свой proxy. Диагностика содержит proxy/generation/accepted и ошибки API.
|
||||
Отдельный JVM-модуль компилирует production router с управляемой моделью Android API:15/15 PASS,
|
||||
включая64 конкурентных callback/stop и I/O start с задержанным callback; после cleanup0 proxy/callbacks.
|
||||
Прежний исходник:штатный контроль PASS,три ownership-сценария ожидаемо FAIL.
|
||||
Android clock/trace/buffer/recovery26/26,voice/desktop30/30,нативная сборка и assembleDebug для двух ABI PASS.
|
||||
check.sh204/204 PASS,0 failed/0 skipped;proxy9/9,burst1/1,load8/8,exit0,173с.
|
||||
Fixtures не входят в APK;Bluetooth/Binder/звук на устройстве не проверялись. Общий аудит call остаётся частичным.
|
||||
Подробности: [call_audit_findings.txt](call_audit_findings.txt),раздел15;
|
||||
/tmp/call-bt-fix-{gradle,negative,voice-tests,full-check}.log.
|
||||
|
||||
[+] **Android call mute: настоящий PCM и флаг mute передаются через JNI до core** — исправлено 26.10.2026.
|
||||
Kotlin передаёт исходный buf и snapshot muted на кадр; NativeLib/JNI/C bridge вызывают feed_pcm_muted.
|
||||
AEC/AGC продолжают получать микрофон, mute зануляет PCM непосредственно перед Opus; wire/DSP/desktop не менялись.
|
||||
|
||||
Reference in new issue
Block a user