【架构安全修复 - 防止协程未捕获异常导致应用崩溃】
## 问题背景
协程中的未捕获异常会传播行为:
1. 子协程中的异常会传播到父协程
2. SupervisorJob 虽然防止子协程失败取消其他子协程,但不捕获异常
3. 未处理的异常最终会导致应用崩溃
## 存在的风险
### 场景 1: 后台消息收集失败
- 原问题: messageCollectionJob 中网络异常未捕获
- 后果: 整个 repositoryScope 取消,所有后台任务停止 → 功能完全失效
### 场景 2: 事件订阅异常
- 原问题: sessionEventJob 中解析事件数据异常
- 后果: 事件订阅中断,无法接收后续事件 → 签名/密钥生成卡住
### 场景 3: RPC 调用失败
- 原问题: getBalance 等方法中 JSON 解析失败
- 后果: 应用崩溃 → 用户体验极差
## 修复方案
### 添加 CoroutineExceptionHandler
在 repositoryScope 中配置全局异常处理器:
### 异常分类处理
根据异常类型采取不同策略:
1. CancellationException - 正常的协程取消,仅记录日志
2. 网络异常 (SocketTimeoutException, UnknownHostException, IOException)
- 记录警告日志
- 可以触发重连逻辑
3. 状态异常 (IllegalStateException, IllegalArgumentException)
- 记录错误日志和堆栈
- 可以重置状态或通知 UI
4. 其他未知异常
- 记录详细错误信息
- 防止应用崩溃,保持功能可用
## 修复的崩溃场景
### 场景 1: 网络突然断开时消息收集崩溃
- 原问题: messageCollectionJob 中 grpcClient.routeMessage() 抛出 IOException
- 修复前: 异常传播导致 repositoryScope 取消 → 所有后台任务停止
- 修复后: 异常被 CoroutineExceptionHandler 捕获 → 记录日志,其他任务继续运行
### 场景 2: 服务端返回格式错误导致解析崩溃
- 原问题: JSON 解析失败抛出 JsonSyntaxException
- 修复前: 应用直接崩溃
- 修复后: 异常被捕获,记录错误日志,用户可继续使用其他功能
### 场景 3: partyId 未初始化导致的崩溃
- 原问题: 虽然已添加 requirePartyId() 检查,但如果异常未捕获仍会崩溃
- 修复前: IllegalStateException 导致应用崩溃
- 修复后: 异常被捕获,用户看到错误提示而非应用崩溃
### 场景 4: 并发竞态条件导致的状态异常
- 原问题: 快速切换页面时状态不一致抛出 IllegalStateException
- 修复前: 应用崩溃,用户丢失所有未保存数据
- 修复后: 异常被捕获,状态可以恢复,功能继续可用
## 影响范围
### 修改的代码位置
- TssRepository.kt - 添加 coroutineExceptionHandler
- repositoryScope 配置 - 添加异常处理器到 CoroutineScope
### 行为变化
- BEFORE: 协程中未捕获异常导致应用崩溃
- AFTER: 异常被捕获并记录,应用继续运行
### 日志增强
所有未捕获异常都会记录:
- 异常类型和消息
- 协程上下文信息
- 完整堆栈跟踪
- 根据异常类型的分类标签
## 测试验证
编译状态: ✅ BUILD SUCCESSFUL in 42s
- 无编译错误
- 仅有警告 (unused parameters),不影响功能
## 最佳实践
这个修复符合 Kotlin 协程最佳实践:
1. SupervisorJob - 子协程隔离
2. CoroutineExceptionHandler - 全局异常捕获
3. 明确的异常分类处理
4. 详细的日志记录
## 注意事项
1. CoroutineExceptionHandler 仅捕获未处理的异常
- 已在 try-catch 中捕获的异常不会触发
- 这是最后一道防线,不应替代局部异常处理
2. CancellationException 不应被捕获
- 它是协程取消的正常机制
- 在 handler 中识别并忽略
3. 重要操作仍应使用 try-catch
- 关键路径(签名、密钥生成)应保留局部 try-catch
- 这样可以提供更精确的错误处理和恢复
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
||
|---|---|---|
| .. | ||
| app | ||
| contracts | ||
| gradle/wrapper | ||
| tsslib | ||
| .gitignore | ||
| IMPLEMENTATION_PLAN.md | ||
| README.md | ||
| build-apk.bat | ||
| build.gradle.kts | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| settings.gradle.kts | ||
README.md
TSS Party Android
Android 版本的 TSS (Threshold Signature Scheme) Party 应用,用于多方共管钱包的密钥生成和签名。
项目结构
service-party-android/
├── app/ # Android 应用模块
│ ├── src/main/
│ │ ├── java/com/durian/tssparty/
│ │ │ ├── data/ # 数据层
│ │ │ │ ├── local/ # 本地存储 (Room, TSS Bridge)
│ │ │ │ ├── remote/ # 远程通信 (gRPC)
│ │ │ │ └── repository/ # 数据仓库
│ │ │ ├── domain/model/ # 领域模型
│ │ │ ├── presentation/ # UI 层
│ │ │ │ ├── screens/ # Compose 屏幕
│ │ │ │ └── viewmodel/ # ViewModels
│ │ │ ├── di/ # Hilt 依赖注入
│ │ │ ├── ui/theme/ # Material Theme
│ │ │ └── util/ # 工具类
│ │ ├── proto/ # gRPC Proto 文件
│ │ └── res/ # Android 资源
│ └── libs/ # TSS 原生库 (.aar)
├── tsslib/ # Go TSS 库源码
│ ├── tsslib.go # gomobile 绑定
│ ├── go.mod
│ ├── build.sh # Linux/macOS 构建脚本
│ └── build.bat # Windows 构建脚本
└── gradle/ # Gradle Wrapper
技术栈
- UI: Jetpack Compose + Material 3
- 架构: MVVM + Repository Pattern
- 依赖注入: Hilt
- 数据库: Room
- 网络: gRPC (protobuf-lite)
- TSS 核心: Go + gomobile (BnB Chain tss-lib v2)
构建步骤
1. 构建 TSS 原生库 (可选,需要 Go 环境)
# 安装 gomobile
go install golang.org/x/mobile/cmd/gomobile@latest
gomobile init
# 构建 Android AAR
cd tsslib
./build.sh # Linux/macOS
# 或
build.bat # Windows
这将在 app/libs/ 生成 tsslib.aar。
注意: 当前版本使用 Kotlin stub 实现,无需编译 Go 库即可构建 APK。 实际运行需要真正的
tsslib.aar。
2. 构建 APK
# Debug 版本
./gradlew assembleDebug
# Release 版本 (需要签名配置)
./gradlew assembleRelease
APK 输出路径: app/build/outputs/apk/debug/app-debug.apk
功能
- 加入 Keygen 会话 - 扫描/输入邀请码,参与多方密钥生成
- 查看钱包 - 显示已创建的共管钱包列表
- 签名交易 - 使用密钥份额参与多方签名
- 设置 - 配置 Message Router 服务器地址
配置
默认服务器配置:
- Message Router:
localhost:50051 - Kava RPC:
https://evm.kava.io
与 Electron 版本的对应关系
| Electron 版本 | Android 版本 |
|---|---|
electron/main.ts |
TssNativeBridge.kt + GrpcClient.kt |
electron/preload.ts |
TssRepository.kt |
src/pages/*.tsx |
presentation/screens/*.kt |
tss-party/ (Go 子进程) |
tsslib/ (gomobile .aar) |
| sql.js | Room Database |
许可证
MIT