fix: 彻底修复BufferQueue abandoned持续报错
- cleanupVirtualDisplayOnly先setSurface(null)切断生产者再release - createVirtualDisplay注册Callback监听onStopped事件 - 新增bufferQueueAbandoned volatile标志位,回调无延迟设置 - 采集循环双重检测:标志位+Surface.isValid - Android 15重试createVirtualDisplay同步添加Callback - cleanup时主动设置bufferQueueAbandoned=true
This commit is contained in:
@@ -89,6 +89,10 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
|||||||
private var virtualDisplayRebuildCount = 0
|
private var virtualDisplayRebuildCount = 0
|
||||||
private val MAX_VIRTUAL_DISPLAY_REBUILD_ATTEMPTS = 3 // 最多重建3次,之后直接回退到无障碍截图
|
private val MAX_VIRTUAL_DISPLAY_REBUILD_ATTEMPTS = 3 // 最多重建3次,之后直接回退到无障碍截图
|
||||||
|
|
||||||
|
// ✅ BufferQueue abandoned 标志:由VirtualDisplay回调或Surface检测设置,采集循环读取
|
||||||
|
@Volatile
|
||||||
|
private var bufferQueueAbandoned = false
|
||||||
|
|
||||||
// 🔑 新增:AccessibilityService截图模式开关
|
// 🔑 新增:AccessibilityService截图模式开关
|
||||||
private var useAccessibilityScreenshot = false
|
private var useAccessibilityScreenshot = false
|
||||||
|
|
||||||
@@ -405,15 +409,16 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
|||||||
val MAX_BLACK_FRAMES_BEFORE_FALLBACK = 30 // 连续30个黑屏帧后切换到无障碍截图
|
val MAX_BLACK_FRAMES_BEFORE_FALLBACK = 30 // 连续30个黑屏帧后切换到无障碍截图
|
||||||
|
|
||||||
while (isCapturing) {
|
while (isCapturing) {
|
||||||
// ✅ BufferQueue abandoned 检测:Surface失效时立即回退,避免大量错误日志
|
// ✅ BufferQueue abandoned 检测:标志位 + Surface失效双重检查
|
||||||
|
// bufferQueueAbandoned 由 VirtualDisplay.Callback.onStopped 设置,无延迟
|
||||||
val surfaceValid = try {
|
val surfaceValid = try {
|
||||||
imageReader?.surface?.isValid == true
|
!bufferQueueAbandoned && imageReader?.surface?.isValid == true
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.w(TAG, "⚠️ Surface有效性检查异常: ${e.message}")
|
Log.w(TAG, "⚠️ Surface有效性检查异常: ${e.message}")
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
if (!surfaceValid) {
|
if (!surfaceValid) {
|
||||||
Log.w(TAG, "🚨 Surface已失效(BufferQueue abandoned),停止MediaProjection采集")
|
Log.w(TAG, "🚨 Surface已失效(BufferQueue abandoned=${bufferQueueAbandoned}),停止MediaProjection采集")
|
||||||
cleanupVirtualDisplayOnly()
|
cleanupVirtualDisplayOnly()
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
Log.i(TAG, "🔄 回退到无障碍截图模式")
|
Log.i(TAG, "🔄 回退到无障碍截图模式")
|
||||||
@@ -1199,15 +1204,25 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
|||||||
|
|
||||||
Log.i(TAG, "ImageReader创建完成")
|
Log.i(TAG, "ImageReader创建完成")
|
||||||
|
|
||||||
// 创建VirtualDisplay
|
// 创建VirtualDisplay,注册Callback监听停止事件
|
||||||
|
val displayCallback = object : android.hardware.display.VirtualDisplay.Callback() {
|
||||||
|
override fun onStopped() {
|
||||||
|
Log.w(TAG, "🚨 VirtualDisplay.Callback.onStopped: 系统已停止VirtualDisplay")
|
||||||
|
bufferQueueAbandoned = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtualDisplay = mediaProjection?.createVirtualDisplay(
|
virtualDisplay = mediaProjection?.createVirtualDisplay(
|
||||||
"RemoteControlCapture",
|
"RemoteControlCapture",
|
||||||
screenWidth, screenHeight,
|
screenWidth, screenHeight,
|
||||||
service.resources.displayMetrics.densityDpi,
|
service.resources.displayMetrics.densityDpi,
|
||||||
android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
|
android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
|
||||||
imageReader?.surface, null, null
|
imageReader?.surface, displayCallback, backgroundHandler
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 重置abandoned标志(新的VirtualDisplay创建成功)
|
||||||
|
bufferQueueAbandoned = false
|
||||||
|
|
||||||
if (virtualDisplay != null) {
|
if (virtualDisplay != null) {
|
||||||
Log.i(TAG, "VirtualDisplay创建成功")
|
Log.i(TAG, "VirtualDisplay创建成功")
|
||||||
|
|
||||||
@@ -2245,14 +2260,25 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
|||||||
*/
|
*/
|
||||||
private fun cleanupVirtualDisplayOnly() {
|
private fun cleanupVirtualDisplayOnly() {
|
||||||
try {
|
try {
|
||||||
// 清理VirtualDisplay
|
// ✅ 先切断VirtualDisplay与Surface的连接,阻止生产者继续dequeueBuffer
|
||||||
|
// 这是解决 "BufferQueue has been abandoned" 持续报错的关键
|
||||||
|
try {
|
||||||
|
virtualDisplay?.surface = null
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "⚠️ 切断VirtualDisplay Surface连接失败: ${e.message}")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 释放VirtualDisplay
|
||||||
virtualDisplay?.release()
|
virtualDisplay?.release()
|
||||||
virtualDisplay = null
|
virtualDisplay = null
|
||||||
|
|
||||||
// 清理ImageReader
|
// 关闭ImageReader(Surface随之销毁)
|
||||||
imageReader?.close()
|
imageReader?.close()
|
||||||
imageReader = null
|
imageReader = null
|
||||||
|
|
||||||
|
// 标记abandoned状态
|
||||||
|
bufferQueueAbandoned = true
|
||||||
|
|
||||||
// ✅ 安全清理缓存的Bitmap,防止多线程并发导致native crash (SIGSEGV)
|
// ✅ 安全清理缓存的Bitmap,防止多线程并发导致native crash (SIGSEGV)
|
||||||
safeRecycleLastValidBitmap()
|
safeRecycleLastValidBitmap()
|
||||||
lastCaptureTime = 0L
|
lastCaptureTime = 0L
|
||||||
@@ -2454,14 +2480,21 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
|||||||
|
|
||||||
Log.i(TAG, "🔧 Android 15:ImageReader重新创建完成")
|
Log.i(TAG, "🔧 Android 15:ImageReader重新创建完成")
|
||||||
|
|
||||||
// 重新创建VirtualDisplay
|
// 重新创建VirtualDisplay(带Callback监听停止事件)
|
||||||
|
val retryDisplayCallback = object : android.hardware.display.VirtualDisplay.Callback() {
|
||||||
|
override fun onStopped() {
|
||||||
|
Log.w(TAG, "🚨 Android 15重试VirtualDisplay.Callback.onStopped")
|
||||||
|
bufferQueueAbandoned = true
|
||||||
|
}
|
||||||
|
}
|
||||||
virtualDisplay = mediaProjection?.createVirtualDisplay(
|
virtualDisplay = mediaProjection?.createVirtualDisplay(
|
||||||
"RemoteControlCaptureRetry_${System.currentTimeMillis()}",
|
"RemoteControlCaptureRetry_${System.currentTimeMillis()}",
|
||||||
screenWidth, screenHeight,
|
screenWidth, screenHeight,
|
||||||
service.resources.displayMetrics.densityDpi,
|
service.resources.displayMetrics.densityDpi,
|
||||||
android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
|
android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
|
||||||
imageReader?.surface, null, null
|
imageReader?.surface, retryDisplayCallback, backgroundHandler
|
||||||
)
|
)
|
||||||
|
bufferQueueAbandoned = false
|
||||||
|
|
||||||
if (virtualDisplay != null) {
|
if (virtualDisplay != null) {
|
||||||
Log.i(TAG, "✅ Android 15 VirtualDisplay完全重新创建成功")
|
Log.i(TAG, "✅ Android 15 VirtualDisplay完全重新创建成功")
|
||||||
|
|||||||
Reference in New Issue
Block a user