diff --git a/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/data/repository/TssRepository.kt b/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/data/repository/TssRepository.kt index 48fd7cd3..43089b3c 100644 --- a/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/data/repository/TssRepository.kt +++ b/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/data/repository/TssRepository.kt @@ -150,9 +150,68 @@ class TssRepository @Inject constructor( // Called when TSS protocol progress updates (round/totalRounds) private var progressCallback: ((Int, Int) -> Unit)? = null - // Repository-level CoroutineScope for background tasks - // Uses SupervisorJob so individual task failures don't cancel other tasks - private val repositoryScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + /** + * 全局协程异常处理器 + * + * 【架构安全修复 - 防止未捕获异常导致应用崩溃】 + * + * 问题背景: + * - 协程中的未捕获异常会传播到父协程 + * - SupervisorJob 虽然防止子协程失败取消其他子协程,但不捕获异常 + * - 未处理的异常最终会导致应用崩溃 + * + * 修复方案: + * - 添加 CoroutineExceptionHandler 捕获所有未处理的异常 + * - 记录详细的异常信息(协程上下文、堆栈) + * - 防止应用崩溃,保持功能可用 + * + * 适用场景: + * 1. 后台消息收集失败 - 不应导致整个应用崩溃 + * 2. 事件订阅异常 - 记录错误但继续运行 + * 3. RPC 调用失败 - 优雅降级而非崩溃 + */ + private val coroutineExceptionHandler = CoroutineExceptionHandler { context, exception -> + android.util.Log.e("TssRepository", "Uncaught coroutine exception in context: $context", exception) + + // 根据异常类型进行不同处理 + when (exception) { + is CancellationException -> { + // CancellationException 是正常的协程取消,不需要特殊处理 + android.util.Log.d("TssRepository", "Coroutine cancelled: ${exception.message}") + } + is java.net.SocketTimeoutException, + is java.net.UnknownHostException, + is java.io.IOException -> { + // 网络异常 - 可能需要重连 + android.util.Log.w("TssRepository", "Network error in coroutine: ${exception.message}") + // 可以触发重连逻辑或通知 UI + } + is IllegalStateException, + is IllegalArgumentException -> { + // 状态异常 - 可能是编程错误 + android.util.Log.e("TssRepository", "State error in coroutine: ${exception.message}", exception) + // 可以重置状态或通知 UI + } + else -> { + // 其他未知异常 + android.util.Log.e("TssRepository", "Unknown error in coroutine: ${exception.javaClass.simpleName}", exception) + } + } + } + + /** + * Repository-level CoroutineScope for background tasks + * + * 配置: + * - SupervisorJob: 子协程失败不影响其他子协程 + * - Dispatchers.IO: 使用 IO 线程池(适合网络/数据库操作) + * - CoroutineExceptionHandler: 捕获所有未处理的异常,防止崩溃 + */ + private val repositoryScope = CoroutineScope( + SupervisorJob() + + Dispatchers.IO + + coroutineExceptionHandler + ) companion object { // Job 名称常量