fix: Android event handler lost after restart — g_event_handler now preserved
Root cause: instance_lite_restart was creating new thread without re-setting g_event_handler, causing all chat events (CHANNEL_UPDATED, CONNECT_RESULT, etc.) to be silently dropped after app restart. Fixes: - instance_lite_restart: save/restore g_event_handler across hard restart - instance_thread restart loop: re-call chat_event_set_handler after uasync_create - utun_bridge_restart: call instance_lite_set_event_handler before restart - AppEventHandler SharedFlow replay: 1 → 16 to not lose early init events - ViewModel: added diagnostic logging for channel/connect events - Keep diagnostic logs in instance_lite (set_handler, chat_event_forward NULL check) - instance_event_handler: removed static for cross-block forward declaration
This commit is contained in:
1 parent
ef637d33a6
commit
38eb51c679
5 files changed
+37
-9
No files matched your search
@@ -10,7 +10,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
|
||||
object AppEventHandler : ChatEventCallback {
|
||||
private val _events = MutableSharedFlow<Pair<Int, ByteArray?>>(replay = 1, extraBufferCapacity = 64)
|
||||
private val _events = MutableSharedFlow<Pair<Int, ByteArray?>>(replay = 16, extraBufferCapacity = 64)
|
||||
val events: SharedFlow<Pair<Int, ByteArray?>> = _events
|
||||
|
||||
override fun onEvent(type: Int, data: ByteArray?) {
|
||||
|
||||
@@ -181,7 +181,7 @@ class ChatViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
2 -> { /* CONNECT_RESULT: [node_id:8][result:4][channel_id:8] */
|
||||
if (repo == null || data == null || data.size < 20) return
|
||||
if (repo == null || data == null || data.size < 20) { LogManager.addLog("WARN", "VM", "CONNECT_RESULT skipped repo=${repo != null} data=${data != null}"); return }
|
||||
val buf = java.nio.ByteBuffer.wrap(data).order(java.nio.ByteOrder.LITTLE_ENDIAN)
|
||||
val nodeId = buf.getLong()
|
||||
val result = buf.getInt()
|
||||
@@ -189,9 +189,10 @@ class ChatViewModel : ViewModel() {
|
||||
LogManager.addLog(
|
||||
if (result == 0) "INFO" else "ERROR",
|
||||
"JOIN", "connect to 0x%016x ch=$chId result=$result".format(nodeId))
|
||||
LogManager.addLog("INFO", "VM", "CONNECT_RESULT result=$result — refreshChannels")
|
||||
if (result == 0) refreshChannels()
|
||||
}
|
||||
4 -> if (repo != null) refreshChannels() /* CHANNEL_UPDATED */
|
||||
4 -> { if (repo != null) { LogManager.addLog("INFO", "VM", "CHANNEL_UPDATED — refreshChannels"); refreshChannels() } else { LogManager.addLog("WARN", "VM", "CHANNEL_UPDATED skipped — repo is NULL") } }
|
||||
12 -> LogManager.addLog("INFO", "VM", "service started")
|
||||
13 -> LogManager.addLog("INFO", "VM", "service stopped")
|
||||
16 -> { /* NODEINFO_UPDATED: [node_id:8][presence:1][up:1][best_rtt:2] */
|
||||
|
||||
@@ -1021,6 +1021,12 @@ char* utun_bridge_get_member_links_json(uint64_t node_id) {
|
||||
|
||||
void utun_bridge_restart(const char* config_text) {
|
||||
bridge_log(BLEV_INFO, "bridge restart: posting to instance");
|
||||
#ifdef __ANDROID__
|
||||
{
|
||||
void instance_event_handler(int type, const uint8_t* data, int len);
|
||||
instance_lite_set_event_handler(instance_event_handler);
|
||||
}
|
||||
#endif
|
||||
instance_lite_restart(config_text);
|
||||
}
|
||||
|
||||
@@ -1235,14 +1241,20 @@ static void jni_on_log(int level, const char* category, const char* message) {
|
||||
/* ── JNI event callback (chat_event → Kotlin) ── */
|
||||
|
||||
static void jni_on_event(int type, const uint8_t* data, int len) {
|
||||
if (!g_jvm || !g_event_callback || !g_event_mid) return;
|
||||
if (!g_jvm) { bridge_log(BLEV_ERROR, "[EVT_DIAG] jni_on_event: g_jvm=NULL"); return; }
|
||||
if (!g_event_callback) { bridge_log(BLEV_ERROR, "[EVT_DIAG] jni_on_event: g_event_callback=NULL"); return; }
|
||||
if (!g_event_mid) { bridge_log(BLEV_ERROR, "[EVT_DIAG] jni_on_event: g_event_mid=NULL"); return; }
|
||||
JNIEnv* env = NULL;
|
||||
int attached = 0;
|
||||
jint res = (*g_jvm)->GetEnv(g_jvm, (void**)&env, JNI_VERSION_1_6);
|
||||
if (res == JNI_EDETACHED) {
|
||||
if ((*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL) != JNI_OK) return;
|
||||
if ((*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL) != JNI_OK) {
|
||||
bridge_log(BLEV_ERROR, "[EVT_DIAG] jni_on_event: AttachCurrentThread failed");
|
||||
return;
|
||||
}
|
||||
attached = 1;
|
||||
} else if (res != JNI_OK) {
|
||||
bridge_log(BLEV_ERROR, "[EVT_DIAG] jni_on_event: GetEnv failed res=%d", (int)res);
|
||||
return;
|
||||
}
|
||||
jbyteArray jdata = NULL;
|
||||
@@ -1255,8 +1267,8 @@ static void jni_on_event(int type, const uint8_t* data, int len) {
|
||||
if (attached) (*g_jvm)->DetachCurrentThread(g_jvm);
|
||||
}
|
||||
|
||||
static void instance_event_handler(int type, const uint8_t* data, int len) {
|
||||
bridge_log(BLEV_DEBUG, "event type=%d len=%d", type, len);
|
||||
void instance_event_handler(int type, const uint8_t* data, int len) {
|
||||
bridge_log(BLEV_DEBUG, "[EVT_DIAG] event type=%d len=%d", type, len);
|
||||
jni_on_event(type, data, len);
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +137,8 @@ static void cfg_get_val(const char* text, const char* key, char* out, size_t out
|
||||
/* ── Chat event forward → Kotlin callback ── */
|
||||
|
||||
static void chat_event_forward(int type, const uint8_t* data, int len) {
|
||||
if (g_event_handler) g_event_handler(type, data, len);
|
||||
if (g_event_handler) { g_event_handler(type, data, len); return; }
|
||||
IL_LOGE("[EVT_DIAG] chat_event_forward: g_event_handler is NULL! type=%d len=%d", type, len);
|
||||
}
|
||||
|
||||
static void nodeinfo_event_cb(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* nq, void* arg) {
|
||||
@@ -214,6 +215,7 @@ static void* instance_thread(void* arg) {
|
||||
uasync_set_timeout(g_ua, 2000, NULL, udp_trampoline, "udp_log_flush");
|
||||
}
|
||||
|
||||
IL_LOGI("[EVT_DIAG] thread: about to set chat_event handler, g_event_handler=%p", (void*)g_event_handler);
|
||||
chat_event_set_handler(chat_event_forward);
|
||||
ensure_keys(config);
|
||||
|
||||
@@ -301,6 +303,8 @@ static void* instance_thread(void* arg) {
|
||||
g_ua = uasync_create();
|
||||
if (!g_ua) { IL_LOGE("poll exit: uasync_create failed"); break; }
|
||||
|
||||
chat_event_set_handler(chat_event_forward);
|
||||
|
||||
char* cfg = g_restart_config;
|
||||
g_restart_config = NULL;
|
||||
g_do_restart = 0;
|
||||
@@ -407,9 +411,11 @@ void instance_lite_stop(void) {
|
||||
|
||||
void instance_lite_restart(const char* new_config_text) {
|
||||
if (!new_config_text) return;
|
||||
instance_lite_event_fn saved_handler = g_event_handler;
|
||||
if (!g_ua || !g_inst || !g_running) {
|
||||
IL_LOGI("restart: instance dead, doing hard restart via stop+start");
|
||||
IL_LOGI("restart: instance dead, doing hard restart via stop+start (saved_handler=%p)", (void*)saved_handler);
|
||||
if (g_inst) instance_lite_stop();
|
||||
g_event_handler = saved_handler;
|
||||
instance_lite_start(new_config_text);
|
||||
return;
|
||||
}
|
||||
@@ -477,6 +483,7 @@ void instance_lite_regenerate_keys(void) {
|
||||
}
|
||||
|
||||
void instance_lite_set_event_handler(instance_lite_event_fn handler) {
|
||||
IL_LOGI("[EVT_DIAG] instance_lite_set_event_handler handler=%p g_running=%d", (void*)handler, g_running);
|
||||
g_event_handler = handler;
|
||||
if (g_running) chat_event_set_handler(chat_event_forward);
|
||||
}
|
||||
Reference in new issue
Block a user