# Android-клиент: баги найденные при ревизии (2026-05-25) Коммиты с исправлениями: `d57336a` (предыдущий раунд) → `7f9b83c` (этот раунд). --- ## Баг 1 — КРИТИЧЕСКИЙ: NetworkOnMainThreadException при подключении ### Что было неверно `onStartCommand` вызывался на **главном (UI) потоке**. Из него напрямую вызывались `btConnect()` и `tcpConnect()`. Внутри `btConnect()`: ```kotlin btSocket?.connect() // ← БЛОКИРУЮЩИЙ вызов на main thread ``` Внутри `tcpConnect()`: ```kotlin tcpSocket = Socket(host, port) // ← БЛОКИРУЮЩИЙ вызов на main thread ``` ### Почему это баг Android с версии 3.0 (Honeycomb, API 11) запрещает сетевые операции на главном потоке. Если нарушение — **`NetworkOnMainThreadException`** и краш при запуске. Даже если бы не падало — UI зависал бы на время соединения (ANR через 5 секунд). ### Как исправлено Оба вызова обёрнуты в `thread { }`: ```kotlin if (debug != null) { val p = debug.split(":") thread(name = "ElmConnect", isDaemon = true) { tcpConnect(p[0], p.getOrNull(1)?.toIntOrNull() ?: 35000) } } else { intent.getStringExtra(EXTRA_DEVICE_MAC)?.let { mac -> thread(name = "ElmConnect", isDaemon = true) { btConnect(mac) } } } ``` `isDaemon = true` — поток не удерживает JVM, умирает вместе с сервисом. --- ## Баг 2 — КРИТИЧЕСКИЙ: TCP-режим слал данные на obdai.ru вместо локального сервера ### Что было неверно В `MainActivity`, в ветке TCP-режима: ```kotlin putExtra(ElmForwardService.EXTRA_SERVER_URL, "https://obdai.ru/api/v1/raw-obd") ``` URL захардкожен на продакшн-сервер. ### Почему это баг TCP-режим предназначен для **теста без ELM327**: mock ELM327 (`tools/mock_elm327.py`) и Flask-сервер (`web/app.py`) запускаются на одной машине в локальной сети. Поле URL в UI в этом режиме занято адресом mock-устройства (`192.168.X.X:35000`), поэтому у пользователя нет способа указать другой сервер. Результат: телефон подключается к локальному mock по TCP, но OBD-данные уходят на `obdai.ru` — тест ничего не проверяет. ### Как исправлено Сервер выводится автоматически из того же хоста, что и устройство, на стандартный порт Flask (5005): ```kotlin val deviceHost = debugHost.split(":")[0] val localServerUrl = "http://$deviceHost:5005/api/v1/raw-obd" ``` Итого: ввёл `192.168.1.42:35000` → mock на `:35000`, сервер на `http://192.168.1.42:5005`. --- ## Баг 3 — МАЛЫЙ: символ `\n` попадал в raw-строку ### Что было неверно В `loop()` при накоплении байт из устройства: ```kotlin } else if (c != '\r') sb.append(c) ``` Фильтровался только `\r`, но не `\n`. ### Почему это баг ELM327 отвечает в формате `DATA\r\n>`. Разделитель ответа — `>`. Код правильно использует `>` как признак конца пакета, но `\n` перед `>` или внутри многострочного ответа накапливается в `sb`. Пример: ответ `4 1 05 4B\r\n>` → в буфере будет `4 1 05 4B\n` вместо `4 1 05 4B`. `.trim()` при отправке на сервер снимает крайние `\n`, но если `\n` внутри многострочного ответа — он остаётся. Сервер должен быть устойчив, но лучше не давать мусор. ### Как исправлено ```kotlin } else if (c != '\r' && c != '\n') sb.append(c) ``` --- ## Итог по файлам | Файл | Изменение | |------|-----------| | `ElmForwardService.kt` | `btConnect`/`tcpConnect` → в `thread {}`, скип `\n` | | `MainActivity.kt` | TCP-режим → URL из IP устройства + порт 5005 |