fix: 修复BufferQueue abandoned导致进程崩溃重启
- cleanupVirtualDisplayOnly()释放顺序修正:先释放VirtualDisplay(消费者)再关闭ImageReader(生产者),防止Surface的BufferQueue被abandon后VirtualDisplay仍持有引用继续dequeueBuffer - 所有资源释放路径统一先置null再释放,防止其他线程在释放过程中继续使用 - reinitializeVirtualDisplayForAndroid15()释放顺序同步修正 - setupMediaProjectionResources()中Surface无效时的释放顺序修正 - refreshSurfaceForAndroid15()移除危险的surface.release()直接调用,改为完整重建ImageReader+VirtualDisplay - reinitializeImageReaderForAndroid15()先释放VirtualDisplay再重建ImageReader,重建后创建新VirtualDisplay关联 - 清理重复的catch代码块
This commit is contained in:
@@ -1244,10 +1244,13 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
val createdSurface = imageReader?.surface
|
||||
if (createdSurface == null || !createdSurface.isValid) {
|
||||
Log.e(TAG, "VirtualDisplay创建后Surface无效(null=${createdSurface == null}, isValid=${createdSurface?.isValid}), 清理资源")
|
||||
virtualDisplay?.release()
|
||||
// 释放顺序:先VirtualDisplay再ImageReader
|
||||
val failVd = virtualDisplay
|
||||
val failIr = imageReader
|
||||
virtualDisplay = null
|
||||
imageReader?.close()
|
||||
imageReader = null
|
||||
try { failVd?.release() } catch (_: Exception) {}
|
||||
try { failIr?.close() } catch (_: Exception) {}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2260,18 +2263,35 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
|
||||
/**
|
||||
* 只清理VirtualDisplay和ImageReader,保留MediaProjection权限
|
||||
*
|
||||
* 释放顺序至关重要:必须先释放VirtualDisplay(消费者),再关闭ImageReader(生产者)
|
||||
* 如果先关闭ImageReader,其内部Surface的BufferQueue会被abandon,
|
||||
* 但VirtualDisplay仍持有该Surface引用并继续dequeueBuffer,
|
||||
* 导致大量"BufferQueue has been abandoned"错误日志洪泛,最终进程崩溃
|
||||
*/
|
||||
private fun cleanupVirtualDisplayOnly() {
|
||||
try {
|
||||
// 清理VirtualDisplay
|
||||
virtualDisplay?.release()
|
||||
// 第一步:保存引用并立即置null,防止其他线程继续使用
|
||||
val vd = virtualDisplay
|
||||
val ir = imageReader
|
||||
virtualDisplay = null
|
||||
|
||||
// 清理ImageReader
|
||||
imageReader?.close()
|
||||
imageReader = null
|
||||
|
||||
// 安全清理缓存的Bitmap,防止多线程并发导致native crash (SIGSEGV)
|
||||
// 第二步:先释放VirtualDisplay(消费者),断开与Surface的连接
|
||||
try {
|
||||
vd?.release()
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "释放VirtualDisplay异常: ${e.message}")
|
||||
}
|
||||
|
||||
// 第三步:再关闭ImageReader(生产者),此时Surface不再被引用
|
||||
try {
|
||||
ir?.close()
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "关闭ImageReader异常: ${e.message}")
|
||||
}
|
||||
|
||||
// 第四步:安全清理缓存的Bitmap
|
||||
safeRecycleLastValidBitmap()
|
||||
lastCaptureTime = 0L
|
||||
|
||||
@@ -2455,11 +2475,18 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
isVirtualDisplayRecreating = true
|
||||
Log.i(TAG, "[VirtualDisplay重建] 开始重新创建(第${consecutiveRecreationCount}次),抑制权限保活检查")
|
||||
|
||||
// 清理当前的VirtualDisplay和ImageReader,完全重新创建
|
||||
virtualDisplay?.release()
|
||||
// 清理当前的VirtualDisplay和ImageReader
|
||||
// 释放顺序:先VirtualDisplay(消费者)再ImageReader(生产者)
|
||||
val oldVd = virtualDisplay
|
||||
val oldIr = imageReader
|
||||
virtualDisplay = null
|
||||
imageReader?.close()
|
||||
imageReader = null
|
||||
try { oldVd?.release() } catch (e: Exception) {
|
||||
Log.w(TAG, "重建时释放VirtualDisplay异常: ${e.message}")
|
||||
}
|
||||
try { oldIr?.close() } catch (e: Exception) {
|
||||
Log.w(TAG, "重建时关闭ImageReader异常: ${e.message}")
|
||||
}
|
||||
|
||||
// 等待系统完全清理
|
||||
Thread.sleep(500)
|
||||
@@ -2495,10 +2522,12 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
val rebuiltSurface = imageReader?.surface
|
||||
if (rebuiltSurface == null || !rebuiltSurface.isValid) {
|
||||
Log.e(TAG, "Android 15 VirtualDisplay重建后Surface无效, 放弃")
|
||||
virtualDisplay?.release()
|
||||
val failVd = virtualDisplay
|
||||
val failIr = imageReader
|
||||
virtualDisplay = null
|
||||
imageReader?.close()
|
||||
imageReader = null
|
||||
try { failVd?.release() } catch (_: Exception) {}
|
||||
try { failIr?.close() } catch (_: Exception) {}
|
||||
isVirtualDisplayRecreating = false
|
||||
return false
|
||||
}
|
||||
@@ -2733,21 +2762,37 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
|
||||
/**
|
||||
* 为Android 15强制刷新Surface
|
||||
* 通过完整重建ImageReader实现,不直接release Surface(会导致悬空引用)
|
||||
*/
|
||||
private suspend fun refreshSurfaceForAndroid15() {
|
||||
try {
|
||||
imageReader?.let { reader ->
|
||||
val surface = reader.surface
|
||||
if (surface.isValid) {
|
||||
Log.d(TAG, "Android 15强制刷新Surface")
|
||||
// 通过重设Surface的方式强制刷新
|
||||
surface.release()
|
||||
delay(500)
|
||||
|
||||
// 重新创建ImageReader(如果需要)
|
||||
if (isVirtualDisplayCreated()) {
|
||||
createImageReader()
|
||||
}
|
||||
// 不能直接release ImageReader的Surface,这会导致ImageReader持有悬空引用
|
||||
// 正确做法:先释放VirtualDisplay,再重建ImageReader,最后重建VirtualDisplay
|
||||
val oldVd = virtualDisplay
|
||||
val oldIr = imageReader
|
||||
virtualDisplay = null
|
||||
imageReader = null
|
||||
try { oldVd?.release() } catch (_: Exception) {}
|
||||
try { oldIr?.close() } catch (_: Exception) {}
|
||||
|
||||
delay(500)
|
||||
|
||||
// 重新创建ImageReader
|
||||
createImageReader()
|
||||
|
||||
// 重新创建VirtualDisplay关联新的Surface
|
||||
if (imageReader != null && mediaProjection != null) {
|
||||
virtualDisplay = mediaProjection?.createVirtualDisplay(
|
||||
"RemoteControlCaptureRefresh_${System.currentTimeMillis()}",
|
||||
screenWidth, screenHeight,
|
||||
service.resources.displayMetrics.densityDpi,
|
||||
android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
|
||||
imageReader?.surface, null, null
|
||||
)
|
||||
if (virtualDisplay != null) {
|
||||
Log.i(TAG, "Android 15 Surface刷新完成,VirtualDisplay已重建")
|
||||
} else {
|
||||
Log.w(TAG, "Android 15 Surface刷新后VirtualDisplay创建失败")
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
@@ -2757,12 +2802,17 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
|
||||
/**
|
||||
* 为Android 15重新初始化ImageReader
|
||||
* 必须先释放VirtualDisplay再重建ImageReader,防止Surface悬空引用
|
||||
*/
|
||||
private suspend fun reinitializeImageReaderForAndroid15() {
|
||||
try {
|
||||
Log.d(TAG, "Android 15重新初始化ImageReader")
|
||||
|
||||
// 释放现有ImageReader
|
||||
// 先释放VirtualDisplay(消费者),再释放ImageReader(生产者)
|
||||
val oldVd = virtualDisplay
|
||||
virtualDisplay = null
|
||||
try { oldVd?.release() } catch (_: Exception) {}
|
||||
|
||||
releaseImageReader()
|
||||
delay(1000)
|
||||
|
||||
@@ -2770,11 +2820,19 @@ class ScreenCaptureManager(private val service: AccessibilityRemoteService) {
|
||||
createImageReader()
|
||||
delay(1000)
|
||||
|
||||
// 如果VirtualDisplay存在,重新关联Surface
|
||||
virtualDisplay?.let { display ->
|
||||
imageReader?.let { reader ->
|
||||
display.surface = reader.surface
|
||||
Log.d(TAG, "Android 15已重新关联ImageReader和VirtualDisplay")
|
||||
// 重新创建VirtualDisplay关联新的ImageReader Surface
|
||||
if (imageReader != null && mediaProjection != null) {
|
||||
virtualDisplay = mediaProjection?.createVirtualDisplay(
|
||||
"RemoteControlCaptureReinit_${System.currentTimeMillis()}",
|
||||
screenWidth, screenHeight,
|
||||
service.resources.displayMetrics.densityDpi,
|
||||
android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
|
||||
imageReader?.surface, null, null
|
||||
)
|
||||
if (virtualDisplay != null) {
|
||||
Log.d(TAG, "Android 15已重建VirtualDisplay关联新ImageReader")
|
||||
} else {
|
||||
Log.w(TAG, "Android 15重建VirtualDisplay失败")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user