From 988fbd9dbd0721c534f33cf49166831e0de68c51 Mon Sep 17 00:00:00 2001 From: jjangddu Date: Thu, 23 Apr 2026 14:09:16 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20watchdog=EC=9D=84=20=EB=B3=84=EB=8F=84?= =?UTF-8?q?=20Thread=EB=A1=9C=20=EB=B6=84=EB=A6=AC=20(handler=20=EB=B8=94?= =?UTF-8?q?=EB=A1=9C=ED=82=B9=20=EB=B0=A9=EC=A7=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존: handler.postDelayed로 watchdog 실행 → BLE 스택이 handler를 블로킹하면 watchdog도 멈춤 (좀비 상태 감지 불가) 변경: 별도 daemon Thread에서 5초마다 lastRxTimestamp 체크 → BLE handler가 블로킹되어도 독립적으로 15초 타임아웃 감지 → 감지 시 handler.post로 메인 스레드에서 forceDisconnectAndReconnect 실행 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../medilightv2android/ble/BleManager.kt | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/example/medilightv2android/ble/BleManager.kt b/app/src/main/java/com/example/medilightv2android/ble/BleManager.kt index d96607b..f9a4f0e 100644 --- a/app/src/main/java/com/example/medilightv2android/ble/BleManager.kt +++ b/app/src/main/java/com/example/medilightv2android/ble/BleManager.kt @@ -352,31 +352,39 @@ class BleManager private constructor(private val context: Context) { batteryTimer = null } - // ── Watchdog (zombie connection detection) ── + // ── Watchdog (zombie connection detection, runs on separate thread) ── + + private var watchdogJob: Thread? = null + @Volatile private var watchdogRunning = false private fun startWatchdog() { stopWatchdog() lastRxTimestamp = System.currentTimeMillis() - val check = object : Runnable { - override fun run() { - if (!isConnected.value) return + watchdogRunning = true + + watchdogJob = Thread({ + while (watchdogRunning) { + try { Thread.sleep(5000) } catch (_: InterruptedException) { break } + if (!watchdogRunning) break + if (!isConnected.value) continue + val silenceMs = System.currentTimeMillis() - lastRxTimestamp if (silenceMs > watchdogTimeoutMs) { - logw { "Watchdog: no RX for ${silenceMs}ms — forcing disconnect + reconnect" } - debugLogger.error("WATCHDOG_TIMEOUT silence=${silenceMs}ms — forcing reconnect") - forceDisconnectAndReconnect() - return + handler.post { + logw { "Watchdog: no RX for ${silenceMs}ms — forcing disconnect + reconnect" } + debugLogger.error("WATCHDOG_TIMEOUT silence=${silenceMs}ms — forcing reconnect") + forceDisconnectAndReconnect() + } + break } - handler.postDelayed(this, 5000) } - } - watchdogTimer = check - handler.postDelayed(check, 5000) + }, "BLE-Watchdog").also { it.isDaemon = true; it.start() } } private fun stopWatchdog() { - watchdogTimer?.let { handler.removeCallbacks(it) } - watchdogTimer = null + watchdogRunning = false + watchdogJob?.interrupt() + watchdogJob = null } private fun forceDisconnectAndReconnect() {