fix: 修复屏幕录制权限频繁掉落问题

- 根因:多处代码重复调用getMediaProjection()创建新实例,系统自动stop旧实例触发onStop回调,形成权限丢失恢复再丢失的死循环
- ScreenCaptureManager.ensureMediaProjection():禁止重复创建,只从Holder获取已有对象
- ScreenCaptureManager.captureWithMediaProjection():移除重复创建逻辑
- ScreenCaptureManager.triggerPermissionRecovery():优先从Holder和SmartManager获取已有对象
- ScreenCaptureManager.regenerateMediaProjectionForAndroid15():优先复用Holder中已有对象
- SmartMediaProjectionManager.attemptSilentRecovery():先检查Holder是否已有有效对象
- Android15MediaProjectionManager.attemptSilentRecovery():先检查Holder复用已有对象
- Android15MediaProjectionManager.determineStopReason():修复误判逻辑,Holder中仍有有效对象时识别为旧实例被替换而非用户主动停止
- AccessibilityRemoteService.attemptAndroid15SilentRecovery():优先复用Holder中已有对象
- AccessibilityRemoteService.handleMediaProjectionGranted():Android 11+优先从Holder获取
- RemoteControlForegroundService.handleStartMediaProjection():优先检查Holder避免重复创建
This commit is contained in:
wdvipa
2026-02-15 00:22:47 +08:00
parent de9aa4430c
commit 39bc5b47a0
5 changed files with 161 additions and 175 deletions

View File

@@ -5898,107 +5898,77 @@ class AccessibilityRemoteService : AccessibilityService() {
/**
* Android 15静默恢复方法
*
* 🚨 核心修复:优先检查 Holder 中是否已有有效 MediaProjection 对象,
* 避免重复调用 getMediaProjection() 创建新实例导致旧实例被系统 stop
* 这是权限频繁掉落的根因。
*/
private fun attemptAndroid15SilentRecovery(): Boolean {
return try {
Log.i(TAG, "🤫🤫🤫 AccessibilityService尝试Android 15静默权限恢复 🤫🤫🤫")
Log.i(TAG, "🤫 AccessibilityService尝试Android 15静默权限恢复")
logCurrentPermissionState("AccessibilityService静默恢复开始")
// 优先使用专用管理器恢复
// ✅ 第一步:检查 Holder 中是否已有有效的 MediaProjection 对象
val existingProjection = MediaProjectionHolder.getMediaProjection()
if (existingProjection != null) {
Log.i(TAG, "✅ Holder中已有有效MediaProjection直接复用无需重新创建")
setupScreenCaptureWithMediaProjection(existingProjection)
logCurrentPermissionState("复用已有对象恢复成功")
return true
}
// ✅ 第二步Holder 中无有效对象,使用专用管理器恢复(仅创建一次)
if (android15MediaProjectionManager != null) {
Log.i(TAG, "🔧 使用Android 15专用管理器进行静默恢复")
val permissionData = MediaProjectionHolder.getPermissionData()
Log.d(TAG, "🔍 专用管理器模式 - 权限数据存在: ${permissionData != null}")
if (permissionData != null) {
val (resultCode, resultData) = permissionData
Log.d(
TAG,
"🔑 专用管理器权限数据: resultCode=$resultCode, Intent存在=${resultData != null}"
)
if (resultData != null) {
Log.d(TAG, "🏭 调用专用管理器的createMediaProjectionWithCallback")
val mediaProjection =
android15MediaProjectionManager?.createMediaProjectionWithCallback(
resultCode,
resultData
resultCode, resultData
)
Log.d(TAG, "🏭 专用管理器恢复结果: ${mediaProjection?.hashCode()}")
if (mediaProjection != null) {
Log.i(TAG, "✅✅ Android 15专用管理器静默恢复成功 ✅✅✅")
Log.i(TAG, "✅ Android 15专用管理器静默恢复成功")
setupScreenCaptureWithMediaProjection(mediaProjection)
logCurrentPermissionState("专用管理器恢复成功")
return true
} else {
Log.w(TAG, "❌ 专用管理器createMediaProjectionWithCallback返回null")
}
} else {
Log.w(TAG, "❌ 专用管理器模式权限数据中的Intent为null")
Log.w(TAG, "❌ 专用管理器恢复返回null")
}
} else {
Log.w(TAG, "❌ 专用管理器模式:没有权限数据")
}
} else {
Log.w(TAG, "⚠️ Android 15专用管理器未初始化回退到直接恢复")
}
// 回退到直接恢复
// ✅ 第三步:专用管理器不可用,回退到直接恢复(仅创建一次)
Log.i(TAG, "🔄 回退到直接静默恢复模式")
val permissionData = MediaProjectionHolder.getPermissionData()
Log.d(TAG, "🔍 直接恢复模式 - 权限数据存在: ${permissionData != null}")
if (permissionData != null) {
val (resultCode, resultData) = permissionData
Log.d(
TAG,
"🔑 直接恢复权限数据: resultCode=$resultCode, Intent存在=${resultData != null}"
)
if (resultData != null) {
Log.i(TAG, "🔑 使用现有权限数据进行直接静默恢复")
val mediaProjectionManager =
getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
Log.d(
TAG,
"🏭 获取系统MediaProjectionManager: ${mediaProjectionManager.javaClass.name}"
)
val newMediaProjection =
mediaProjectionManager.getMediaProjection(resultCode, resultData)
Log.d(TAG, "🏭 直接恢复结果: ${newMediaProjection?.hashCode()}")
if (newMediaProjection != null) {
Log.d(TAG, "🔄 更新MediaProjectionHolder")
MediaProjectionHolder.setMediaProjection(newMediaProjection)
Log.i(TAG, "✅✅✅ Android 15直接静默恢复成功 ✅✅✅")
// 设置到屏幕捕获管理器
Log.d(TAG, "🎬 设置到屏幕捕获管理器")
Log.i(TAG, "✅ Android 15直接静默恢复成功")
setupScreenCaptureWithMediaProjection(newMediaProjection)
logCurrentPermissionState("直接恢复成功")
return true
} else {
Log.w(TAG, "❌ 系统MediaProjectionManager.getMediaProjection()返回null")
}
} else {
Log.w(TAG, "❌ 直接恢复模式权限数据中的Intent为null")
Log.w(TAG, "❌ getMediaProjection()返回null")
}
} else {
Log.w(TAG, "❌ 直接恢复模式:没有权限数据")
}
logCurrentPermissionState("AccessibilityService静默恢复失败")
Log.w(TAG, "❌❌ Android 15静默恢复失败 ❌❌❌")
Log.w(TAG, "❌ Android 15静默恢复失败")
false
} catch (e: Exception) {
Log.e(TAG, "❌❌ Android 15静默恢复异常 ❌❌❌", e)
Log.e(TAG, "❌ Android 15静默恢复异常", e)
logCurrentPermissionState("AccessibilityService静默恢复异常")
false
}
@@ -6101,34 +6071,45 @@ class AccessibilityRemoteService : AccessibilityService() {
if (Build.VERSION.SDK_INT >= 30) {
Log.i(TAG, "📱 Android 11+设备MediaProjection 权限获取成功,尝试切换采集模式")
val permissionData = MediaProjectionHolder.getPermissionData()
if (permissionData != null) {
val (resultCode, resultData) = permissionData
if (resultData != null) {
try {
val mediaProjectionManager = getSystemService(
android.content.Context.MEDIA_PROJECTION_SERVICE
) as android.media.projection.MediaProjectionManager
val mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, resultData)
if (mediaProjection != null) {
Log.i(TAG, "✅ Android 11+ MediaProjection 创建成功")
MediaProjectionHolder.setMediaProjection(mediaProjection)
setupScreenCaptureWithMediaProjection(mediaProjection)
// 切换到 MediaProjection 模式以获得更高帧率
if (::screenCaptureManager.isInitialized) {
screenCaptureManager.switchToMediaProjectionMode()
Log.i(TAG, "📱 Android 11+设备:已切换到 MediaProjection 模式")
// 🚨 核心修复:优先从 Holder 获取已有对象,避免重复创建导致权限掉落
var mediaProjection = MediaProjectionHolder.getMediaProjection()
if (mediaProjection != null) {
Log.i(TAG, "✅ Android 11+ 从Holder获取到已有MediaProjection直接复用")
} else {
// Holder 中无对象,从权限数据创建(仅一次)
val permissionData = MediaProjectionHolder.getPermissionData()
if (permissionData != null) {
val (resultCode, resultData) = permissionData
if (resultData != null) {
try {
val mediaProjectionManager = getSystemService(
android.content.Context.MEDIA_PROJECTION_SERVICE
) as android.media.projection.MediaProjectionManager
mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, resultData)
if (mediaProjection != null) {
Log.i(TAG, " Android 11+ MediaProjection 创建成功")
MediaProjectionHolder.setMediaProjection(mediaProjection)
}
} else {
Log.w(TAG, "⚠️ Android 11+ MediaProjection 创建返回 null")
} catch (e: Exception) {
Log.e(TAG, " Android 11+ 创建 MediaProjection 失败", e)
}
} catch (e: Exception) {
Log.e(TAG, "❌ Android 11+ 创建 MediaProjection 失败", e)
}
}
}
if (mediaProjection != null) {
setupScreenCaptureWithMediaProjection(mediaProjection)
// 切换到 MediaProjection 模式以获得更高帧率
if (::screenCaptureManager.isInitialized) {
screenCaptureManager.switchToMediaProjectionMode()
Log.i(TAG, "📱 Android 11+设备:已切换到 MediaProjection 模式")
}
} else {
Log.w(TAG, "⚠️ Android 11+ MediaProjection 不可用")
}
// 标记权限完成
permissionRequestInProgress = false
allPermissionsCompleted = true

View File

@@ -107,6 +107,15 @@ class RemoteControlForegroundService : Service() {
// 启动前台服务
startForegroundService()
// ✅ 优先检查 Holder 中是否已有有效的 MediaProjection 对象
val existingProjection = MediaProjectionHolder.getMediaProjection()
if (existingProjection != null) {
Log.i(TAG, "✅ Holder中已有有效MediaProjection直接复用避免重复创建")
mediaProjection = existingProjection
notifyAccessibilityService()
return
}
// 从MediaProjectionHolder获取权限数据
val permissionData = MediaProjectionHolder.getPermissionData()