3808281d42
- MainActivity: requestTick собирается в repeatOnLifecycle(RESUMED) + флаг AudioBridge.activityResumed - requestProjection(): не дёргает startActivity(MainActivity), пока Activity RESUMED (гонка с grant) - ensureAudioCaptureLoop(): запрос проекции один раз, повтор не чаще 20 c (было 2.5 c) - AudioBridge/GlassesAudioCapture: проекция одна на процесс и не гасится, переиспользуется - ShizukuProvisioner: PROJECT_MEDIA per-UID (на Android 12 package-level = no-op) - отладочные логи phone-side audio; BLOCKERS.md B-3 закрыт (E2E проверен)
124 lines
8.8 KiB
Markdown
124 lines
8.8 KiB
Markdown
# Blockers
|
||
|
||
Сюда пишутся только те задачи/проблемы, в которых застряли. Каждая запись — задача,
|
||
что сделано, в чём стена, что проверено, варианты обхода. Записи ведутся по правилам
|
||
ночной сессии (см. `TASKS.md`, секция «Правила ночной сессии»).
|
||
|
||
---
|
||
|
||
## B-1 · Периодический лаунч `Mercury/.NetConfigActivity` — ПОДТВЕРЖДЁН, источник не найден
|
||
|
||
**Когда замечено:** 2026-09-27, во время тестов запуска Zona через `DEBUG_LAUNCH`.
|
||
|
||
**Что я видел в логах:** `ShizukuVdService: launchActivity pkg=com.ffalconxr.mercury.launcher
|
||
cls=com.ffalconxr.mercury.launcher.wizard.netconfig.NetConfigActivity displayId=2` повторялось
|
||
каждые 5 секунд, постоянно.
|
||
|
||
**Что это на самом деле:** Непонятно. Это мог быть мой собственный `GlassesDebugReceiver`,
|
||
который я перепосылал несколько раз и он где-то зациклился; мог быть артефакт system-job’а;
|
||
мог быть какой-то fallback в `VmGlassesController.ensureNetworking()`.
|
||
|
||
**Повторно замечено:** 2026-09-27 12:28:40, `START ... NetConfigActivity from uid 2000` (shell)
|
||
в логах очков во время отладки звука. `uid 2000` = shell ⇒ запускает **Shizuku UserService**
|
||
(наш код через Shizuku). Значит источник — где-то в нашем Shizuku-пути (не Mercury BLE).
|
||
На аудио-grant влияния не оказал (график grant сломался по другой причине — см. B-3).
|
||
|
||
**Что НЕ сделано:** не остановил очки в момент пика, не нашёл источник цикла. Пользователь
|
||
утром сказал «сейчас вижу наше приложение», значит цикл или закончился, или не повторяется.
|
||
|
||
**Следующий шаг:** если повторится — переписать GlassesDebugReceiver с rate-limit + проверить
|
||
нет ли в `VmService`/`VmGlassesController` периодического `launchActivity(Mercury)` для
|
||
Wi-Fi/network fallback.
|
||
|
||
---
|
||
|
||
## B-2 · rayneo-mercury: `enableWirelessAdb` через BLE на X3 Pro не возвращает адрес
|
||
|
||
**Когда выяснено:** 2026-09-27, аудит прошивки RayNeoLauncher по smali
|
||
(`adb pull /system/app/RayNeoLauncher`).
|
||
|
||
**Что происходит (по smali + логам):**
|
||
1. Телефон шлёт BLE-команду `ble.request.debug` с `payload.cmd="enableWirelessAdb"`.
|
||
2. Очки **принимают** команду и реально поднимают беспроводной adb (мы видим
|
||
`adb_wifi_enabled=1` и `service.adb.tcp.port` после). **Это работает.**
|
||
3. Очки **должны** прислать событие `WirelessAdbAddress` обратно. **Это не происходит.**
|
||
4. В smali `BleResponse` есть `RESPONSE_MAP`, в котором зарегистрированы Wi-Fi / media /
|
||
netconfig ответы — но **`DebugResponse` отсутствует**. Поэтому маршрутизация ответа
|
||
по URI `ble.request.debug` не настроена, и событие теряется.
|
||
5. Телефон вечно ждёт `Event.WirelessAdbAddress`, не получает его и уходит в таймаут.
|
||
|
||
**Что это значит для provisioning:**
|
||
- Команда `enableWirelessAdb` через BLE **включает adb** — но адрес `ip:port` мы узнать не можем.
|
||
- Provisioning сейчас работает только потому, что **adb уже был включён раньше** (например,
|
||
руками или через shizuku) и не выключился после ребута. После ребута очков — если
|
||
`adb_wifi_enabled` сбросится в 0 — provisioning сломается, потому что новый адрес мы
|
||
узнать не сможем.
|
||
|
||
**Обходной путь (уже работает):**
|
||
```bash
|
||
# Через shizuku shell на очках:
|
||
service call adb 4 i32 1 s16 'Caffeine Portable' # включить adb
|
||
settings put global adb_wifi_enabled 1 # не дать ему автоотключиться
|
||
```
|
||
После этого `adb_wifi_enabled` остаётся 1, телефон через mDNS `_adb-tls-connect._tcp`
|
||
находит `ip:port` и подключается. Это уже используется как fallback в `AdbController`.
|
||
|
||
**Следующий шаг:** при первом удобном случае — поднять через shizuku-shell и убедиться,
|
||
что provisioning пройдёт полностью через этот путь.
|
||
|
||
---
|
||
|
||
## B-3 · Звук end-to-end — РЕШЕНО
|
||
|
||
**Когда замечено:** 2026-09-27, E2E-проверка после восстановления общей сети «O2 5».
|
||
|
||
**Симптом:** звук на телефон работал только в первый раз; после `ON_GLASSES` → `ON_PHONE` тишина
|
||
и на очках, и на телефоне.
|
||
|
||
**Корень (найден по логам 2026-09-27):** не сеть и не телефон, а **grant MediaProjection на очках**.
|
||
`ensureAudioCaptureLoop` ре-запрашивал проекцию каждые 2.5 c, а `requestProjection()` каждый раз
|
||
дёргал `startActivity(MainActivity, NEW_TASK|SINGLE_TOP)`. Система:
|
||
```
|
||
START com.android.systemui/.media.MediaProjectionPermissionActivity from uid 10090
|
||
→ UsageStats event :23 (ACTIVITY_STOPPED) через ~30 мс
|
||
→ MainActivity: MediaProjection не выдан: resultCode=0
|
||
```
|
||
то есть grant-активити гасится, если её запускает только что перезапущенная Activity. Ручной
|
||
`KEYCODE_HOME` (уводит нашу Activity с переднего плана) «разблокировал» grant — подтверждало
|
||
гипотезу гонки.
|
||
|
||
**Фикс (вариант A):**
|
||
1. `MainActivity` собирает `requestTick` в `repeatOnLifecycle(**RESUMED**)` (был `STARTED`) и флагом
|
||
`AudioBridge.activityResumed` сообщает сервису, что она наверху.
|
||
2. `requestProjection()` больше **не** вызывает `startActivity(MainActivity)`, пока Activity уже
|
||
`RESUMED` (убрана гонка с запуском consent-активити).
|
||
3. `ensureAudioCaptureLoop` запрашивает проекцию **один раз**; повтор — не чаще `AUDIO_RETRY_MS=20 c`.
|
||
4. Проекция **одна на процесс и не гасится**: `GlassesAudioCapture.stop()` останавливает только
|
||
`AudioRecord`, а `AudioBridge.onProjectionGranted` не трогает уже имеющуюся. Следующий `ON_PHONE`
|
||
переиспользует ту же проекцию — новый grant не нужен вовсе.
|
||
|
||
**Проверено вживую 2026-09-27 (очки A06B4AB933C4103 → телефон AXGL024B05001337):**
|
||
- `[1] ON_PHONE` → `MediaProjection получен` **без HOME** → захват запущен.
|
||
- `[2] ON_GLASSES` → `остановлен (проекцию сохраняю)`.
|
||
- `[3] ON_PHONE` → `аудио-захват поднят`, **без нового grant** (переиспользование).
|
||
- Тестовый тон 440 Гц: очки `rms=5673`, телефон `playing ... rms=5620..5698`, байты совпали
|
||
(`bytes=4751360` с обеих сторон). **PCM реально дошёл по `/vm-audio`.**
|
||
|
||
**Проверено с руки пользователя 2026-09-27:** полный сценарий с Zona — `ON_PHONE` → `ON_GLASSES`
|
||
→ `ON_PHONE` — звук корректно переключается, повторный `ON_PHONE` больше не ломается.
|
||
**B-3 закрыт полностью.**
|
||
|
||
---
|
||
|
||
## B-4 · Финал: гашение экрана обязательно в конце
|
||
|
||
По ночным правилам — на завершении всех задач ИЛИ при невозможности продолжать —
|
||
выполняется:
|
||
```
|
||
adb -s A06B4AB933C4103 shell input keyevent 223
|
||
```
|
||
и проверка `mWakefulness=Dozing/Asleep`. Если не работает — через `ScreenControl` (Канал 1) /
|
||
Shizuku `SET_SCREEN`.
|
||
|
||
**Статус:** выполнено (mWakefulness=Dozing подтверждён в конце ночной сессии).
|