From 82d1f48271ac629b2a0a0c3b4b17b446ff553697 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Thu, 4 Jun 2026 08:30:10 -0400 Subject: [PATCH] fix(scanner): prevent ANR from uncaught ImageProxy.close() exception ImageProxy.close() in the finally block of MultiCodeAnalyzer.analyze() can throw IllegalArgumentException when CameraX pipeline is already torn down. With no CoroutineExceptionHandler on the scope, the exception propagated to ThreadGroup.uncaughtException and killed the app. - Wrap image.close() with runCatching to absorb the benign failure - Add CoroutineExceptionHandler to route any future uncaught exceptions to the caller onError handler instead of the process kill path Fixes: Bugsnag 69eada8ad5699cd63c22712a Signed-off-by: Brandon McAnsh --- .../getcode/ui/scanner/processing/MultiCodeAnalyzer.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ui/scanner/src/main/kotlin/com/getcode/ui/scanner/processing/MultiCodeAnalyzer.kt b/ui/scanner/src/main/kotlin/com/getcode/ui/scanner/processing/MultiCodeAnalyzer.kt index 42dd74826..d040f17e7 100644 --- a/ui/scanner/src/main/kotlin/com/getcode/ui/scanner/processing/MultiCodeAnalyzer.kt +++ b/ui/scanner/src/main/kotlin/com/getcode/ui/scanner/processing/MultiCodeAnalyzer.kt @@ -12,6 +12,7 @@ import com.getcode.libs.code.detection.CodeScanResult import com.getcode.libs.qr.QrCodeAnalyzer import com.kik.kikx.kikcodes.implementation.KikCodeAnalyzer import com.kik.kikx.kikcodes.implementation.KikCodeScannerImpl +import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob @@ -76,7 +77,10 @@ class MultiCodeAnalyzer( private var onError: (Throwable) -> Unit = { } private val job = SupervisorJob() - private val scope = CoroutineScope(Dispatchers.IO + job) + private val exceptionHandler = CoroutineExceptionHandler { _, throwable -> + onError(throwable) + } + private val scope = CoroutineScope(Dispatchers.IO + job + exceptionHandler) fun listen(listener: CodeScanListener) { onCodeScanned = listener::onCodeScanned @@ -111,7 +115,7 @@ class MultiCodeAnalyzer( } catch (e: Exception) { onError(e) } finally { - image.close() + runCatching { image.close() } } } }