From 5296e534ed27184e5c8a99d947ca1bb8e421ce01 Mon Sep 17 00:00:00 2001 From: yuanyuanxiang <962914132@qq.com> Date: Thu, 25 Jun 2026 17:30:23 +0200 Subject: [PATCH] Fix: Android client stops service when server sends BYE (delete client) ConnectionThread now calls CaptureService.onNativeExit() via JNI on exit when g_bExit == S_CLIENT_EXIT (server-initiated). The Java side posts stopSelf() on the service handler. Guard: instance is null in the user-initiated teardown path (onDestroy nulls it before nativeStop), so onNativeExit is a no-op in that case. Co-Authored-By: Claude Sonnet 4.6 --- android/app/src/main/cpp/main.cpp | 18 ++++++++++++++++++ .../java/com/yama/client/CaptureService.kt | 7 +++++++ 2 files changed, 25 insertions(+) diff --git a/android/app/src/main/cpp/main.cpp b/android/app/src/main/cpp/main.cpp index 10beb6c..c5d7265 100644 --- a/android/app/src/main/cpp/main.cpp +++ b/android/app/src/main/cpp/main.cpp @@ -202,6 +202,7 @@ static jclass g_captureClass = nullptr; static jmethodID g_requestIdrMid = nullptr; static jmethodID g_forceFirstFrameMid = nullptr; static jmethodID g_statusMid = nullptr; // CaptureService.onNativeStatus(String) +static jmethodID g_nativeExitMid = nullptr; // CaptureService.onNativeExit() — 服务端主动断开时停止服务 // 心跳日志限流:每 60 秒最多打一次 static std::atomic g_lastHbLogMs{0}; @@ -674,6 +675,20 @@ static void ConnectionThread() g_running.store(false); LOGI("ConnectionThread exit"); + + if (g_bExit == S_CLIENT_EXIT && g_jvm && g_captureClass && g_nativeExitMid) { + JNIEnv* jenv = nullptr; + bool attached = false; + if (g_jvm->GetEnv((void**)&jenv, JNI_VERSION_1_6) == JNI_EDETACHED) { + g_jvm->AttachCurrentThread(&jenv, nullptr); + attached = true; + } + if (jenv) { + jenv->CallStaticVoidMethod(g_captureClass, g_nativeExitMid); + if (jenv->ExceptionCheck()) jenv->ExceptionClear(); + } + if (attached) g_jvm->DetachCurrentThread(); + } } // ------------------------------------------------------------------ JNI @@ -743,6 +758,9 @@ Java_com_yama_client_YamaBridge_nativeInit( g_statusMid = env->GetStaticMethodID(g_captureClass, "onNativeStatus", "(Ljava/lang/String;)V"); if (env->ExceptionCheck()) { env->ExceptionClear(); g_statusMid = nullptr; } if (!g_statusMid) LOGE("CaptureService.onNativeStatus not found"); + g_nativeExitMid = env->GetStaticMethodID(g_captureClass, "onNativeExit", "()V"); + if (env->ExceptionCheck()) { env->ExceptionClear(); g_nativeExitMid = nullptr; } + if (!g_nativeExitMid) LOGE("CaptureService.onNativeExit not found"); UseAndroidLog(PostStatus); } else { LOGE("CaptureService class not found"); diff --git a/android/app/src/main/java/com/yama/client/CaptureService.kt b/android/app/src/main/java/com/yama/client/CaptureService.kt index c28effd..6af7152 100644 --- a/android/app/src/main/java/com/yama/client/CaptureService.kt +++ b/android/app/src/main/java/com/yama/client/CaptureService.kt @@ -48,6 +48,13 @@ class CaptureService : Service() { } } + @JvmStatic + fun onNativeExit() { + val svc = instance ?: return + Log.i(TAG, "onNativeExit: server requested disconnect, stopping service") + svc.idrHandler.post { svc.stopSelf() } + } + @JvmStatic fun requestIdr() { val svc = instance ?: return