fix: 修复Bitmap并发回收闪退和缓存帧竞态问题

- lastValidBitmap/lastCaptureTime添加@Volatile确保多协程可见性
- safeRecycleLastValidBitmap()添加@Synchronized防止并发double-recycle
- 新增updateLastValidBitmap()原子替换缓存帧(synchronized)
- 新增compressCachedFrame()安全压缩缓存帧(synchronized)
- 新增safeCopyLastValidBitmap()安全复制缓存帧(synchronized)
- 替换所有直接访问lastValidBitmap的代码为synchronized方法调用
- 涉及方法: startMediaProjectionCapture/startAccessibilityScreenCapture/handleAndroid11ScreenshotFailure/captureWithMediaProjection/forceRefreshAndroid15Images
- 清理MainActivity和SocketIOManager中日志的emoji符号
This commit is contained in:
wdvipa
2026-02-15 14:57:38 +08:00
parent 0c516f7307
commit 410219f382
3 changed files with 183 additions and 152 deletions

View File

@@ -342,9 +342,9 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
socket?.let { socket ->
socket.on(Socket.EVENT_CONNECT) {
Log.e(TAG, "✅✅✅ Socket.IO v4 连接成功!!! ✅✅✅")
Log.i(TAG, "Socket.IO v4 连接成功")
isConnected = true
isDeviceRegistered = false // 重置注册状态,等待重新注册
isDeviceRegistered = false // 重置注册状态,等待重新注册
// ✅ 记录连接成功时间和网络类型
lastConnectTime = System.currentTimeMillis()
@@ -383,7 +383,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
socket.on(Socket.EVENT_DISCONNECT) { args ->
val reason = if (args.isNotEmpty()) args[0].toString() else "unknown"
Log.e(TAG, "📴📴📴 Socket.IO v4 断开: $reason 📴📴📴")
Log.w(TAG, "Socket.IO v4 断开: $reason")
// ✅ 增强断开原因分析和统计
val currentTime = System.currentTimeMillis()
@@ -426,7 +426,7 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
socket.on(Socket.EVENT_CONNECT_ERROR) { args ->
val error = if (args.isNotEmpty()) args[0].toString() else "unknown"
Log.e(TAG, "Socket.IO v4 连接错误: $error")
Log.e(TAG, "Socket.IO v4 连接错误: $error")
connectionFailureCount++
updateNetworkQualityScore(false, "connect_error", 0)
}
@@ -684,14 +684,14 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
// 🔧 大小检查避免发送过大数据导致transport error
if (frameData.size > maxScreenDataSize) {
Log.w(TAG, "⚠️ 屏幕数据过大被跳过: ${frameData.size} bytes > ${maxScreenDataSize} bytes")
Log.w(TAG, "屏幕数据过大被跳过: ${frameData.size} bytes > ${maxScreenDataSize} bytes")
return
}
// 🔧 连接饥饿检查:如果长时间无法发送数据,可能连接有问题
if (lastSuccessfulDataSend > 0 && currentTime - lastSuccessfulDataSend > dataStarvationTimeout) {
if (!isDataStarved) {
Log.w(TAG, "⚠️ 检测到数据发送饥饿(${currentTime - lastSuccessfulDataSend}ms),连接可能有问题")
Log.w(TAG, "检测到数据发送饥饿(${currentTime - lastSuccessfulDataSend}ms),连接可能有问题")
isDataStarved = true
// 不立即重连,而是给连接一些时间恢复
}
@@ -724,19 +724,17 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
// 🎯 优化:记录压缩和编码效率,监控优化效果
val base64Size = base64Data.length
val overhead = if (frameData.size > 0) "%.1f%%".format(((base64Size - frameData.size).toFloat() / frameData.size) * 100) else "N/A"
Log.d(TAG, "发送屏幕数据: JPEG${frameData.size}B -> Base64${base64Size}B (+$overhead 开销, 间隔${currentTime - (lastScreenDataTime - screenDataInterval)}ms, isLocked=${isScreenLocked})")
Log.d(TAG, "发送屏幕数据: JPEG${frameData.size}B -> Base64${base64Size}B (+$overhead 开销, isLocked=${isScreenLocked})")
} catch (emitException: Exception) {
screenDataFailureCount++
Log.e(TAG, "发送屏幕数据失败(${screenDataFailureCount}次): ${emitException.message}")
Log.e(TAG, "发送屏幕数据失败(${screenDataFailureCount}次): ${emitException.message}")
// 🔧 大幅提高重连阈值,避免服务端正常丢弃数据被误判为网络错误
if (screenDataFailureCount >= 20) {
Log.e(TAG, "❌❌❌ 屏幕数据发送连续失败${screenDataFailureCount}次,触发重连检测!!! ❌❌❌")
Log.e(TAG, "屏幕数据发送连续失败${screenDataFailureCount}次,触发重连检测")
checkConnectionAndReconnect()
screenDataFailureCount = 0 // 重置计数
screenDataFailureCount = 0
}
// 🔧 不再抛出异常避免ScreenCaptureManager误判为发送失败
Log.w(TAG, "⚠️ 屏幕数据发送失败,但不影响后续发送")
Log.w(TAG, "屏幕数据发送失败,但不影响后续发送")
}
} else {
@@ -1806,109 +1804,118 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
private fun checkConnectionAndReconnect() {
scope.launch {
try {
Log.e(TAG, "🔍🔍🔍 立即检测连接状态!!! 🔍🔍🔍")
Log.d(TAG, "立即检测连接状态")
// 检查Socket连接状态
val socketConnected = socket?.connected() == true
if (!socketConnected || !isConnected) {
Log.e(TAG, "❌❌❌ 连接已断开,立即重连!!! ❌❌❌")
Log.w(TAG, "连接已断开,立即重连")
forceReconnect()
} else {
Log.w(TAG, "✅✅✅ 连接状态正常 ✅✅✅")
Log.d(TAG, "连接状态正常")
}
} catch (e: Exception) {
Log.e(TAG, "❌❌❌ 连接检测异常!!! ❌❌❌", e)
Log.e(TAG, "连接检测异常", e)
}
}
}
/**
* 智能重新连接 - 增强稳定性版本针对transport error问题
* 智能重新连接 - 增强稳定性版本针对transport error问题
* 添加重连深度限制,防止无限递归导致协程泄漏和内存耗尽
*/
private var forceReconnectDepth = 0
private val MAX_FORCE_RECONNECT_DEPTH = 3
fun forceReconnect() {
scope.launch {
try {
Log.e(TAG, "🚀🚀🚀 开始智能重连针对transport error优化!!! 🚀🚀🚀")
forceReconnectDepth++
if (forceReconnectDepth > MAX_FORCE_RECONNECT_DEPTH) {
Log.e(TAG, "重连深度超限(${forceReconnectDepth}/${MAX_FORCE_RECONNECT_DEPTH})停止递归重连等待Socket.IO自动重连")
forceReconnectDepth = 0
return@launch
}
Log.i(TAG, "开始智能重连(深度${forceReconnectDepth}/${MAX_FORCE_RECONNECT_DEPTH})")
// 重置所有状态
isConnected = false
isDeviceRegistered = false
connectionCheckJob?.cancel()
// 优雅断开旧连接,给系统清理时间
// 优雅断开旧连接,给系统清理时间
try {
socket?.disconnect()
delay(1000) // 等待断开完成
delay(1000)
socket?.close()
} catch (e: Exception) {
Log.w(TAG, "断开旧连接时出现异常(可忽略)", e)
}
Log.e(TAG, "🔄 旧连接已断开,等待智能延迟后重新连接...")
Log.i(TAG, "旧连接已断开,等待智能延迟后重新连接...")
// 智能延迟:根据网络环境调整等待时间 + 随机化避免多设备同时重连
// 智能延迟:根据网络环境调整等待时间 + 随机化避免多设备同时重连
val baseDelay = if (Build.VERSION.SDK_INT >= 35) {
8000L // Android 15需要更长恢复时间
8000L
} else {
5000L // 其他版本5秒
5000L
}
val randomDelay = (1000..4000).random().toLong() // 1-4秒随机延迟
val totalDelay = baseDelay + randomDelay + (transportErrorCount * 2000L) // 根据错误次数增加延迟
val randomDelay = (1000..4000).random().toLong()
// 限制transportErrorCount对延迟的影响防止延迟无限增长
val errorIncrement = minOf(transportErrorCount, 5) * 2000L
val totalDelay = baseDelay + randomDelay + errorIncrement
Log.i(TAG, "🔄 智能重连延迟: ${totalDelay}ms (基础: ${baseDelay}ms + 随机: ${randomDelay}ms + 错误增量: ${transportErrorCount * 2000L}ms)")
Log.i(TAG, "智能重连延迟: ${totalDelay}ms (基础: ${baseDelay}ms + 随机: ${randomDelay}ms + 错误增量: ${errorIncrement}ms)")
delay(totalDelay)
// 重新创建Socket实例使用增强配置
Log.e(TAG, "🔄 重新创建增强Socket实例...")
// 重新创建Socket实例使用增强配置
Log.i(TAG, "重新创建增强Socket实例...")
try {
// ✅ 根据transport error历史决定使用的策略
val useConservativeStrategy = shouldUseConservativeReconnect()
Log.i(TAG, "📊 重连策略选择: 保守策略=$useConservativeStrategy, transportErrorCount=$transportErrorCount")
Log.i(TAG, "重连策略选择: 保守策略=$useConservativeStrategy, transportErrorCount=$transportErrorCount")
val options = IO.Options().apply {
// ✅ 针对transport error的保守配置 + 网络质量自适应
val isVeryPoorNetwork = networkQualityScore < 30
timeout = when {
isVeryPoorNetwork -> 90000 // 网络很差时使用90秒超时
useConservativeStrategy -> 60000 // 保守策略使用60秒超时
else -> 45000 // 标准45秒超时
isVeryPoorNetwork -> 90000
useConservativeStrategy -> 60000
else -> 45000
}
reconnection = true
reconnectionAttempts = when {
isVeryPoorNetwork -> 3 // 网络很差时只重试3次
useConservativeStrategy -> 5 // 保守策略重试5次
else -> 10 // 标准重试10次
isVeryPoorNetwork -> 3
useConservativeStrategy -> 5
else -> 10
}
reconnectionDelay = when {
isVeryPoorNetwork -> 8000L
useConservativeStrategy -> 5000L
else -> 3000L
}
reconnectionDelayMax = when {
isVeryPoorNetwork -> 30000L
useConservativeStrategy -> 20000L
else -> 12000L
}
reconnectionDelay = when {
isVeryPoorNetwork -> 8000L // 网络很差时延迟8秒
useConservativeStrategy -> 5000L // 保守策略延迟5秒
else -> 3000L // 标准延迟3秒
}
reconnectionDelayMax = when {
isVeryPoorNetwork -> 30000L // 网络很差时最大延迟30秒
useConservativeStrategy -> 20000L // 保守策略最大延迟20秒
else -> 12000L // 标准最大延迟12秒
}
// 传输策略:根据网络质量和历史情况调整
// 传输策略:根据网络质量和历史情况调整
transports = when {
isVeryPoorNetwork || networkQualityScore < 40 -> {
arrayOf("polling") // 网络质量差时只使用轮询,更稳定
arrayOf("polling")
}
useConservativeStrategy -> {
arrayOf("polling") // 保守策略只使用轮询
arrayOf("polling")
}
else -> {
arrayOf("polling", "websocket") // 标准策略先轮询再websocket
arrayOf("polling", "websocket")
}
}
upgrade = !useConservativeStrategy // 保守策略禁用升级
upgrade = !useConservativeStrategy
rememberUpgrade = true
forceNew = true // 强制创建新连接
forceNew = true
// ✅ 添加重连标识,便于服务器识别
query = "reconnect=true&strategy=${if (useConservativeStrategy) "conservative" else "standard"}&timestamp=${System.currentTimeMillis()}"
}
@@ -1916,20 +1923,23 @@ class SocketIOManager(private val service: AccessibilityRemoteService) {
setupEventListeners()
socket?.connect()
Log.e(TAG, "🔄🔄🔄 增强Socket实例已创建并连接!!! 🔄🔄🔄")
Log.i(TAG, "增强Socket实例已创建并连接")
// 重连成功,重置深度计数
forceReconnectDepth = 0
} catch (e: Exception) {
Log.e(TAG, "❌❌❌ 重新创建Socket失败!!! ❌❌❌", e)
Log.e(TAG, "重新创建Socket失败", e)
// 重连失败时的回退策略
delay(10000) // 等待10秒后再次尝试
// 重连失败时的回退策略,有深度限制保护
delay(10000)
if (!isConnected) {
Log.w(TAG, "🔄 首次重连失败10秒后再次尝试...")
forceReconnect() // 递归重试,但有延迟保护
Log.w(TAG, "重连失败10秒后再次尝试(深度${forceReconnectDepth}/${MAX_FORCE_RECONNECT_DEPTH})...")
forceReconnect()
}
}
} catch (e: Exception) {
Log.e(TAG, "❌❌❌ 智能重连异常!!! ❌❌❌", e)
Log.e(TAG, "智能重连异常", e)
forceReconnectDepth = 0
}
}
}