Files
elmer/doc/android-bugs-2026-05-25.md
T

111 lines
4.6 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.
# 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 |