e5d2fa24a1
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).
174 lines
13 KiB
Markdown
174 lines
13 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 не работал — РЕШЕНО
|
||
|
||
**Когда выяснено:** 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».
|