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:
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user