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 9e19dd06..48fd7cd3 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 @@ -259,10 +259,34 @@ class TssRepository @Inject constructor( } } - // HTTP client for API calls + /** + * HTTP client for API calls + * + * 【架构安全修复 - 配置连接池防止资源泄漏】 + * + * OkHttpClient 内部维护资源: + * - ConnectionPool: 连接池,复用 HTTP 连接 + * - Dispatcher: 调度器,管理线程池 + * - Cache: 可选的响应缓存 + * + * 如果不配置连接池参数和不清理资源,会导致: + * 1. 连接池无限增长 → 内存泄漏 + * 2. 空闲连接永久保持 → 占用系统资源 + * 3. Dispatcher 线程池未关闭 → 线程泄漏 + * + * 配置策略: + * - maxIdleConnections: 5 (最多保留 5 个空闲连接) + * - keepAliveDuration: 5 分钟 (空闲连接保活时间) + * - 在 cleanup() 中清理所有资源 + */ private val httpClient = okhttp3.OkHttpClient.Builder() .connectTimeout(30, java.util.concurrent.TimeUnit.SECONDS) .readTimeout(30, java.util.concurrent.TimeUnit.SECONDS) + .connectionPool(okhttp3.ConnectionPool( + maxIdleConnections = 5, + keepAliveDuration = 5, + timeUnit = java.util.concurrent.TimeUnit.MINUTES + )) .build() /** @@ -294,12 +318,34 @@ class TssRepository @Inject constructor( * * 【架构安全修复 - 使用 JobManager 统一清理】 * 替换手动取消每个 Job 的方式,防止遗漏导致内存泄漏 + * + * 【架构安全修复 - 清理 OkHttpClient 资源】 + * OkHttpClient 维护连接池和线程池,必须显式清理: + * 1. evictAll() - 关闭并移除所有空闲连接 + * 2. executorService().shutdown() - 关闭调度器线程池 + * 3. connectionPool().evictAll() - 清空连接池 */ fun cleanup() { // 使用 JobManager 统一取消所有后台任务 jobManager.cancelAll() repositoryScope.cancel() grpcClient.disconnect() + + // 清理 OkHttpClient 资源 + try { + // 1. 关闭所有空闲连接 + httpClient.connectionPool.evictAll() + + // 2. 关闭调度器线程池 + httpClient.dispatcher.executorService.shutdown() + + // 3. 如果配置了缓存,清理缓存 + httpClient.cache?.close() + + android.util.Log.d("TssRepository", "OkHttpClient resources cleaned up successfully") + } catch (e: Exception) { + android.util.Log.e("TssRepository", "Failed to cleanup OkHttpClient resources", e) + } } /** diff --git a/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/util/TransactionUtils.kt b/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/util/TransactionUtils.kt index 36e0ca6d..75f9117a 100644 --- a/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/util/TransactionUtils.kt +++ b/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/util/TransactionUtils.kt @@ -23,13 +23,50 @@ import java.util.concurrent.TimeUnit */ object TransactionUtils { + /** + * HTTP client for blockchain RPC calls + * + * 【架构安全修复 - 配置连接池防止资源泄漏】 + * + * 配置连接池参数限制资源占用: + * - maxIdleConnections: 5 (最多保留 5 个空闲连接) + * - keepAliveDuration: 5 分钟 (空闲连接保活时间) + * + * 注意: TransactionUtils 是 object 单例,生命周期与应用一致 + * 如果应用需要完全清理资源,可调用 cleanup() 方法 + */ private val client = OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) + .connectionPool(okhttp3.ConnectionPool( + maxIdleConnections = 5, + keepAliveDuration = 5, + timeUnit = TimeUnit.MINUTES + )) .build() private val jsonMediaType = "application/json; charset=utf-8".toMediaType() + /** + * Cleanup OkHttpClient resources + * + * 【架构安全修复 - 提供资源清理方法】 + * + * 虽然 TransactionUtils 是 object 单例,但提供此方法允许: + * 1. 测试环境清理资源 + * 2. 应用完全退出时释放资源 + * 3. 内存紧张时主动清理 + */ + fun cleanup() { + try { + client.connectionPool.evictAll() + client.dispatcher.executorService.shutdown() + client.cache?.close() + } catch (e: Exception) { + // 静默失败,因为这是清理操作 + } + } + // Chain IDs const val KAVA_TESTNET_CHAIN_ID = 2221 const val KAVA_MAINNET_CHAIN_ID = 2222