Files
rayneo-vm/BLOCKERS.md
T
subochev e5d2fa24a1 mercury 0.1.1-SNAPSHOT (fixed enableWirelessAdb URI); B-2 resolved
Phone now self-provisions after a glasses reboot: BLE enableWirelessAdb ->
glasses start wireless adb -> address back over BLE -> adb connect ->
Shizuku started + accessibility/media grants applied. Verified on device
16:22 (glasses rebooted, adb_wifi_enabled=0, nothing activated over USB).
2026-09-27 16:24:33 +03:00

174 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 не работал — РЕШЕНО
**Когда выяснено:** 2026-09-27. **Симптом:** после ребута очков provisioning не
проходил — телефон писал «не удалось получить адрес ADB over WiFi на очках»,
Shizuku на очках не поднимался (хотя Wi-Fi и BLE у обоих были живы).
**Настоящая причина — одна и она наша:** библиотека `rayneo-mercury` слала команду
не на тот URI.
1. Очки разбирают входящие кадры по таблице `RESPONSE_MAP[uri]` (`BleResponse` из
`RayNeoLauncher`), и debug-ответ зарегистрирован **только** как
`"ble.response.debug"` → `DebugResponse`.
2. Наша `Commands.Debug.enableWirelessAdb()` слала `"ble.request.debug"` — это
направление очки→телефон.
3. Итог: кадр доходил до очков и **молча выбрасывался** в
`BleServerV2.handleMobileCommand` — не совпал ни с `"brt"`, ни с `RESPONSE_MAP`.
Ни обработки, ни ошибки, ни лога.
Полный JSON, который уходил: `{"uri":"ble.request.debug","payload":{"cmd":"enableWirelessAdb"}}`.
Раньше «адрес не приходит» трактовалось как «очки не отвечают» — на деле очки не
получали команду, поэтому и адрес было некому слать. (Сам адрес очки шлют назад как
`ble.request.debug` + `payload.cmd="WirelessAdbAddress"` — это направление
корректно и у нас уже разобрано.)
**Ground truth — стоковое приложение телефона `com.rayneo.mercury`:**
`cn.rayneo.mercury.connectivity.util.GlassesDebugCommands.enableWirelessAdb()` кладёт
в `BleResponsePipeline` именно `DebugResponse(Payload(cmd="enableWirelessAdb"))`, а у
`DebugResponse` `uri == "ble.response.debug"`. Лишние поля не читаются — обработчик
очков (`DebugKnife.observeBleWirelessDebugCommand`) матчит только `payload.cmd` и сам
вызывает `RayNeoAdbService.enableWirelessAdb(true, <текущий ssid>)`.
**Фикс:** `Commands.Debug.enableWirelessAdb()/disableWirelessAdb()` → `Uris.RESPONSE_DEBUG`;
библиотека опубликована как `0.1.1-SNAPSHOT`, в `rayneo-vm/gradle/libs.versions.toml`
`mercury = "0.1.1-SNAPSHOT"`.
**Проверено на устройстве 2026-09-27 16:22** (очки перезагружены, `adb_wifi_enabled=0`,
по USB ничего не активировал — всё делает телефон):
1. `ble.response.debug` → `DebugResponse dispatched` → `RayNeoAdbService: alwaysAllow=true,
bssid=O2 5` → `open wireless adb success: true` → на телефон вернулся адрес
`192.168.76.248:41395`. Первый ответ бывает `ip:-1` (порт ещё не назначен), через ~0.6 c
приходит второй, валидный.
2. Телефон: `ShizukuProvisioner: starting server... shizuku_starter exit with 0` →
`Shizuku поднят` (`pidof shizuku_server` = 4104).
3. `AccessibilityProvisioner` включил `VmAccessibilityService` через тот же adb.
mDNS-fallback в `AdbController` остаётся как страховка.
**Побочный урок:** `~/.gradle/gradle.properties` содержал левый
`mercuryVersion=0.1.0-SNAPSHOT`, который перебивал проектный, — `publish` молча уходил
в старую версию. Строку убрали.
---
## 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 подтверждён в конце ночной сессии).
---
## B-5 · Телефон показывал «подключено» при мёртвом TCP-канале — РЕШЕНО
**Когда замечено:** 2026-09-27, пользователь: «телефон говорит подключено, очки говорят что нет связи».
**Причина:** у очков Wi-Fi был выключен (`wifi_on=0`, нет default network) — реального Канала 1 не
было. Очки при выключении Wi-Fi локально теряют сокеты мгновенно и честно писали «нет связи».
Телефон же об этом не узнавал: FIN/RST до него не доходит (у очков уже нет интерфейса), а у
**клиента `:transport` не было ни пинга, ни таймаута** — `WifiTransport.connect` вечно висел в
`for (frame in s.incoming)`. TCP-сокет телефона оставался в `ESTAB`, `onDisconnected` не срабатывал,
`VmPhoneController` оставался в `Connected` → UI показывал «подключено».
**Доказательство (воспроизведено):** выключили Wi-Fi очкам — через 20 c с телефона:
```
ESTAB 192.168.76.121:50438 → 192.168.76.248:8080
```
сокет так и висел, телефон даже не переподключался (те же local-порты после возврата Wi-Fi).
**Фикс (`rayneo-mercury :transport` 0.1.1-SNAPSHOT):** клиентским транспортам добавлен
`install(WebSockets) { pingIntervalMillis = WS_PING_INTERVAL_MS }` (15 c) — `WifiTransport` и
`WifiByteTransport`; константа в `Transport.kt`. Серверные транспорты пингуют и так
(`pingPeriod=15s`, `timeout=30s`), но они ловят мёртвого клиента, а не наоборот.
**Проверено вживую 2026-09-27:** Wi-Fi очкам выключен → на 10-й секунде у телефона `Send-Q=82`
(пошли пинги, недоставленные) → на ~41-й секунде сокет ушёл в `FIN-WAIT-1` (клиент сам закрыл
мёртвую сессию, `onDisconnected` сработал) → после возврата Wi-Fi новый `ESTAB :57996` и в логах
очков `Phone connected: ws-83ad…` (авто-реконнект).
**Побочно:** в UI телефона обе строки назывались одинаково — «Связь» (Канал 1 WebSocket и
Канал 2 Mercury BLE), из-за чего статус BLE читался как статус TCP. Теперь вверху вкладки «Очки»
сводка «Связь» с отдельными строками **BLE (Mercury)** и **TCP/IP (Wi-Fi)**, а в секциях каналов
строки переименованы в «BLE» и «TCP/IP».