4.6 KiB
Android-клиент: баги найденные при ревизии (2026-05-25)
Коммиты с исправлениями: d57336a (предыдущий раунд) → 7f9b83c (этот раунд).
Баг 1 — КРИТИЧЕСКИЙ: NetworkOnMainThreadException при подключении
Что было неверно
onStartCommand вызывался на главном (UI) потоке. Из него напрямую вызывались btConnect() и tcpConnect().
Внутри btConnect():
btSocket?.connect() // ← БЛОКИРУЮЩИЙ вызов на main thread
Внутри tcpConnect():
tcpSocket = Socket(host, port) // ← БЛОКИРУЮЩИЙ вызов на main thread
Почему это баг
Android с версии 3.0 (Honeycomb, API 11) запрещает сетевые операции на главном потоке. Если нарушение — NetworkOnMainThreadException и краш при запуске. Даже если бы не падало — UI зависал бы на время соединения (ANR через 5 секунд).
Как исправлено
Оба вызова обёрнуты в thread { }:
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-режима:
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):
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() при накоплении байт из устройства:
} 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 внутри многострочного ответа — он остаётся. Сервер должен быть устойчив, но лучше не давать мусор.
Как исправлено
} else if (c != '\r' && c != '\n') sb.append(c)
Итог по файлам
| Файл | Изменение |
|---|---|
ElmForwardService.kt |
btConnect/tcpConnect → в thread {}, скип \n |
MainActivity.kt |
TCP-режим → URL из IP устройства + порт 5005 |