doc: android client bugs found and fixed 2026-05-25
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
# 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 |
|
||||
Reference in New Issue
Block a user