From e32e4be28b7b549d7dd7165e8065a75a2b0ec750 Mon Sep 17 00:00:00 2001 From: evgeny Date: Wed, 28 Oct 2026 12:03:14 +0100 Subject: [PATCH] Document JNI log encoding and failure containment contracts --- tools/chatgui-android/doc/ARCHITECTURE.md | 19 +++++++++++++++++++ .../jni_bridge/android_jni_bridge.h | 6 +++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/tools/chatgui-android/doc/ARCHITECTURE.md b/tools/chatgui-android/doc/ARCHITECTURE.md index 463bf626..1eeaf013 100644 --- a/tools/chatgui-android/doc/ARCHITECTURE.md +++ b/tools/chatgui-android/doc/ARCHITECTURE.md @@ -204,6 +204,23 @@ LogManager хранит последние 100000 строк в памяти п video-фильтр через JNI. JNI callback получает уровни bridge 0=TRACE..4=ERROR, а не числовые DEBUG_LEVEL_*; неизвестный уровень фиксируется предупреждением. +Строки логов передаются через `onNativeLog(int, byte[], byte[])` как обычный UTF-8: +это сохраняет кириллицу/emoji без ограничений Modified UTF-8 `NewStringUTF`. +Повреждённые UTF-8-байты Kotlin отображает как U+FFFD. На каждый вызов JNI берёт +свой local ref callback под mutex; замена/очистка global ref не инвалидирует +уже начатую доставку. Java-код вызывается после освобождения mutex. Указатель +C log callback читается/меняется атомарно; отключение не ждёт начатых вызовов. +init включает пересылку, Activity подписывается на экране логов и отключает её +при выходе; stop снимает C callback, destroy дополнительно освобождает global ref. + +Ошибки JNI-доставки и повторный вход в callback того же потока фиксируются +напрямую в logcat, минуя debug hook, чтобы исключить рекурсию. Проверяются +attach, ссылки, method lookup, выделение/копирование массивов и Java callback. +Все свои local refs освобождаются; detach выполняется только после своего attach. +Исключение от собственной операции/callback описывается и снимается; исключение, +уже существовавшее при входе в logger, сохраняется, доставка этой строки пропускается. +Неудачная доставка не повторяется. Native logcat/файл/UDP работают независимо. + Экран логов показывает последние 10000 строк истории, обновляя снимок не чаще кадра. StateFlow передаёт объединяемую ревизию, строки читаются из общей истории: задержка UI и открытие экрана после последнего сообщения не теряют строки @@ -223,6 +240,8 @@ subscribe/quit управляют клиентом, ряд команд даёт Для Linux сетевых сценариев используются основной `src/utun`, `[chatserver] headless_control_bind=127.0.0.1:9999` и `tools/chatcli`. Для APK: `cd tools/chatgui-android && ./gradlew assembleDebug`. +На Linux `:app:testDebugUnitTest` также запускает 25 fault-сценариев настоящего +JNI logger через `:app:testJniLog`; окружение и границы модели: `tests/jni_log/README.md`. Проверки native bridge/standby доступны в `tests/Makefile.am`; проверка независимости media workers на устройстве описана в `../tests/stream_worker_smoke/README.md` и не проверяет сетевую доставку/UI. diff --git a/tools/chatgui-android/jni_bridge/android_jni_bridge.h b/tools/chatgui-android/jni_bridge/android_jni_bridge.h index 89f500bd..bb36a5e1 100644 --- a/tools/chatgui-android/jni_bridge/android_jni_bridge.h +++ b/tools/chatgui-android/jni_bridge/android_jni_bridge.h @@ -8,6 +8,9 @@ * reply_to в send/voice/photo/video для канала — обязательный указатель на 32 байта (нули = без ответа). * request_id коррелирует канальную публикацию с CHAT_EVT_MSG_SUBMITTED; постановка в очередь не означает доставку. * Аргументы строк/PCM заимствованы на вызов, асинхронные команды копируют их; сроки жизни файлов описаны ниже. + * JNI-логи передают обычный UTF-8 как byte[] в LogManager.onNativeLog(int, byte[], byte[]), а не через NewStringUTF. + * Каждый вызов удерживает свой local ref callback; замена/очистка global ref защищена mutex, пересылка C callback — atomic. + * Ошибки доставки/рекурсия идут прямо в logcat без debug hook. Свои Java-исключения снимаются, чужое pending exception сохраняется. */ #ifndef ANDROID_JNI_BRIDGE_H #define ANDROID_JNI_BRIDGE_H @@ -22,7 +25,8 @@ extern "C" { /* ── Callback types (C → Kotlin) ── */ -/* Native-поток; строки заимствованы на вызов. level: TRACE=0, DEBUG=1, INFO=2, WARN=3, ERROR=4. */ +/* Вызывающий native-поток; category/message — NUL-строки UTF-8, заимствованные на вызов. + * level: TRACE=0, DEBUG=1, INFO=2, WARN=3, ERROR=4. Пересылка в JNI синхронна; отключение не ждёт уже начатый callback. */ typedef void (*utun_log_fn)(int level, const char* category, const char* message); /* Отдельный C JSON-callback, вызываемый utun_bridge_event; это не бинарный CHAT_EVT_* callback JNI.