Browse Source

android: utun shutdown diagnostics + non-blocking stop + logreceiver doc

- instance_lite: cleanup moved to uasync thread (self-detach), events on start/stop
- udp_log: cancel_timer before uasync_destroy, flush on stop, stopping flag
- jni_bridge: fixed UDP stop order (cancel_timer → destroy → flush)
- instance_lite: u_report_unfreed_blocks at all shutdown paths
- chat_event: CHAT_EVT_SERVICE_STARTED/STOPPED for GUI notifications
- AGENTS: logreceiver section
topo_upd
evgeny 2 months ago
parent
commit
0216b0bf50
  1. 2
      src/chat/chat_event.h
  2. 18
      tools/chatgui-android/AGENTS.md
  3. 4
      tools/chatgui-android/jni_bridge/android_jni_bridge.c
  4. 12
      tools/chatgui-android/jni_bridge/android_udp_log.c
  5. 5
      tools/chatgui-android/jni_bridge/android_udp_log.h
  6. 39
      tools/chatgui-android/libutun_lite/instance_lite.c

2
src/chat/chat_event.h

@ -30,6 +30,8 @@ extern "C" {
#define CHAT_EVT_DB_READY 9 /* data: none */
#define CHAT_EVT_STATUS_REFRESH 10 /* data: status text */
#define CHAT_EVT_KEYS_GENERATED 11 /* [pub_hex:64] */
#define CHAT_EVT_SERVICE_STARTED 12 /* data: none */
#define CHAT_EVT_SERVICE_STOPPED 13 /* data: none */
typedef void (*chat_event_handler_fn)(int type, const uint8_t* data, int len);

18
tools/chatgui-android/AGENTS.md

@ -109,6 +109,24 @@ nc localhost 9999
> {"id":2,"cmd":"join","link":"utun://..."}
```
## Логирование через logreceiver (только Android)
Debug-сообщения с телефона дублируются через UDP на приёмник `tools/logreceiver/`.
Запуск (всегда через скрипт, до старта utun):
```bash
tools/logreceiver/logreceiver_restart.sh
```
Скрипт ротирует логи (история 10 запусков: `.log` → `.log.1` → … → `.log.10`),
убивает старый демон и запускает новый на `0.0.0.0:9999`, вывод в `logreceiver_output.log`.
При каждом запуске логи фиксируются в истории и начинается свежий лог.
В конфиге Android:
```ini
log_udp_ip = <ip хоста>
log_udp_port = 9999
```
## Ключевые файлы для доработок
### C-слой

4
tools/chatgui-android/jni_bridge/android_jni_bridge.c

@ -358,6 +358,7 @@ JNIEXPORT void JNICALL Java_com_utun_chat_data_NativeLib_nativeStop(
JNIEnv* env, jobject thiz) {
(void)env; (void)thiz;
utun_bridge_destroy();
udp_log_stop();
}
/* ── nativeInit (legacy, just saves callbacks) ── */
@ -441,8 +442,9 @@ JNIEXPORT void JNICALL Java_com_utun_chat_data_NativeLib_nativeSetEventCallback(
JNIEXPORT void JNICALL Java_com_utun_chat_data_NativeLib_nativeDestroy(
JNIEnv* env, jobject thiz) {
(void)thiz;
udp_log_stop();
udp_log_cancel_timer();
utun_bridge_destroy();
udp_log_stop();
if (g_config_callback) { (*env)->DeleteGlobalRef(env, g_config_callback); g_config_callback = NULL; }
if (g_log_callback) { (*env)->DeleteGlobalRef(env, g_log_callback); g_log_callback = NULL; }
if (g_event_callback) { (*env)->DeleteGlobalRef(env, g_event_callback); g_event_callback = NULL; }

12
tools/chatgui-android/jni_bridge/android_udp_log.c

@ -22,11 +22,13 @@
static int g_udp_fd = -1;
static struct sockaddr_in g_udp_addr;
static int g_udp_has_addr = 0;
static int g_udp_stopping = 0;
static char g_udp_buf[UDP_BUF_SIZE];
static int g_udp_buf_len = 0;
static void* g_udp_timer = NULL;
static void udp_reschedule_timer(void) {
if (g_udp_stopping) return;
struct UASYNC* ua = instance_lite_get_uasync();
if (ua) g_udp_timer = uasync_set_timeout(ua, UDP_FLUSH_TB, NULL, udp_trampoline, "udp_log_flush");
}
@ -63,6 +65,7 @@ void udp_trampoline(void* arg) {
void udp_log_set_target(const char* ip, int port) {
g_udp_buf_len = 0;
g_udp_stopping = 0;
if (ip && port > 0) {
memset(&g_udp_addr, 0, sizeof(g_udp_addr));
g_udp_addr.sin_family = AF_INET;
@ -90,11 +93,16 @@ void udp_log_write(const char* data, int len) {
}
}
void udp_log_stop(void) {
void udp_log_cancel_timer(void) {
g_udp_stopping = 1;
struct UASYNC* ua = instance_lite_get_uasync();
if (ua && g_udp_timer) uasync_cancel_timeout(ua, g_udp_timer);
g_udp_timer = NULL;
}
void udp_log_stop(void) {
g_udp_stopping = 1;
if (g_udp_buf_len > 0) { udp_do_send(g_udp_buf, g_udp_buf_len); g_udp_buf_len = 0; }
if (g_udp_fd >= 0) { close(g_udp_fd); g_udp_fd = -1; }
g_udp_has_addr = 0;
g_udp_buf_len = 0;
}

5
tools/chatgui-android/jni_bridge/android_udp_log.h

@ -19,7 +19,10 @@ void udp_log_set_target(const char* ip, int port);
* Thread-safe — call from any thread (bridge_debug_hook). */
void udp_log_write(const char* data, int len);
/* Stop sending, close socket, cancel timer. Call from any thread. */
/* Cancel flush timer (call before uasync_destroy, while ua is alive). */
void udp_log_cancel_timer(void);
/* Flush buffer, close socket. Call after instance shutdown. */
void udp_log_stop(void);
void udp_trampoline(void* arg);

39
tools/chatgui-android/libutun_lite/instance_lite.c

@ -175,6 +175,7 @@ static void* instance_thread(void* arg) {
IL_LOGE("utun_instance_create_from_config failed");
uasync_destroy(g_ua, 0);
g_ua = NULL;
u_report_unfreed_blocks();
g_running = 0;
return NULL;
}
@ -207,6 +208,7 @@ static void* instance_thread(void* arg) {
g_inst = NULL;
uasync_destroy(g_ua, 0);
g_ua = NULL;
u_report_unfreed_blocks();
g_running = 0;
return NULL;
}
@ -223,12 +225,28 @@ static void* instance_thread(void* arg) {
}
g_running = 1;
chat_event_post(CHAT_EVT_SERVICE_STARTED, NULL, 0);
while (!g_stop) {
uasync_poll(g_ua, 100);
}
IL_LOGI("poll loop exit");
IL_LOGI("poll loop exit, cleaning up");
if (g_inst) {
utun_instance_destroy(g_inst);
g_inst = NULL;
}
if (g_ua) {
uasync_destroy(g_ua, 0);
g_ua = NULL;
}
u_report_unfreed_blocks();
g_running = 0;
chat_event_post(CHAT_EVT_SERVICE_STOPPED, NULL, 0);
g_event_handler = NULL;
pthread_detach(pthread_self());
IL_LOGI("cleanup complete");
return NULL;
}
@ -272,27 +290,10 @@ int instance_lite_start(const char* config_text) {
}
void instance_lite_stop(void) {
if (!g_running && !g_inst) return;
if (!g_inst && !g_running) return;
IL_LOGI("stopping...");
g_stop = 1;
if (g_ua) uasync_wakeup(g_ua);
pthread_join(g_thread, NULL);
if (g_inst) {
etcp_router_bind(g_inst, ETCP_RT_ID_CHAT_SYNC, NULL);
chat_sync_destroy(g_inst);
chat_core_destroy(g_inst);
utun_instance_destroy(g_inst);
g_inst = NULL;
}
if (g_ua) {
uasync_destroy(g_ua, 0);
g_ua = NULL;
}
g_running = 0;
g_event_handler = NULL;
IL_LOGI("stopped");
}
int instance_lite_is_running(void) {

Loading…
Cancel
Save