fix: 修复屏幕录制权限频繁掉落的根因问题
- MediaProjectionHolder添加全局创建锁safeGetOrCreateProjection() - 所有创建点统一通过安全入口,禁止直接调用getMediaProjection() - 重复创建新实例会导致系统stop旧实例触发onStop死循环 - Android15MediaProjectionManager/SmartMediaProjectionManager的onStop回调添加isCreating检查 - RemoteControlForegroundService备用方案改用安全创建入口 - AccessibilityRemoteService静默恢复改用安全创建入口 - 添加最小创建间隔5秒防止短时间内重复创建
This commit is contained in:
@@ -5899,77 +5899,30 @@ class AccessibilityRemoteService : AccessibilityService() {
|
||||
/**
|
||||
* Android 15静默恢复方法
|
||||
*
|
||||
* 🚨 核心修复:优先检查 Holder 中是否已有有效 MediaProjection 对象,
|
||||
* 避免重复调用 getMediaProjection() 创建新实例导致旧实例被系统 stop,
|
||||
* 这是权限频繁掉落的根因。
|
||||
* 🚨 核心修复:禁止调用 getMediaProjection() 创建新实例!
|
||||
* 每次创建新实例,系统会自动 stop 旧实例,触发 onStop 回调,
|
||||
* 形成"权限丢失→恢复→再丢失"的死循环,这是权限频繁掉落的根因。
|
||||
*
|
||||
* 只从 Holder 获取已有对象,不重新创建。
|
||||
*/
|
||||
private fun attemptAndroid15SilentRecovery(): Boolean {
|
||||
return try {
|
||||
Log.i(TAG, "🤫 AccessibilityService尝试Android 15静默权限恢复")
|
||||
logCurrentPermissionState("AccessibilityService静默恢复开始")
|
||||
Log.i(TAG, "🤫 AccessibilityService尝试Android 15静默权限恢复(仅复用已有对象)")
|
||||
|
||||
// ✅ 第一步:检查 Holder 中是否已有有效的 MediaProjection 对象
|
||||
// 从 Holder 获取已有对象
|
||||
val existingProjection = MediaProjectionHolder.getMediaProjection()
|
||||
if (existingProjection != null) {
|
||||
Log.i(TAG, "✅ Holder中已有有效MediaProjection,直接复用,无需重新创建")
|
||||
Log.i(TAG, "✅ Holder中已有有效MediaProjection,直接复用")
|
||||
setupScreenCaptureWithMediaProjection(existingProjection)
|
||||
logCurrentPermissionState("复用已有对象恢复成功")
|
||||
return true
|
||||
}
|
||||
|
||||
// ✅ 第二步:Holder 中无有效对象,使用专用管理器恢复(仅创建一次)
|
||||
if (android15MediaProjectionManager != null) {
|
||||
Log.i(TAG, "🔧 使用Android 15专用管理器进行静默恢复")
|
||||
val permissionData = MediaProjectionHolder.getPermissionData()
|
||||
|
||||
if (permissionData != null) {
|
||||
val (resultCode, resultData) = permissionData
|
||||
if (resultData != null) {
|
||||
val mediaProjection =
|
||||
android15MediaProjectionManager?.createMediaProjectionWithCallback(
|
||||
resultCode, resultData
|
||||
)
|
||||
if (mediaProjection != null) {
|
||||
Log.i(TAG, "✅ Android 15专用管理器静默恢复成功")
|
||||
setupScreenCaptureWithMediaProjection(mediaProjection)
|
||||
logCurrentPermissionState("专用管理器恢复成功")
|
||||
return true
|
||||
}
|
||||
Log.w(TAG, "❌ 专用管理器恢复返回null")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ 第三步:专用管理器不可用,回退到直接恢复(仅创建一次)
|
||||
Log.i(TAG, "🔄 回退到直接静默恢复模式")
|
||||
val permissionData = MediaProjectionHolder.getPermissionData()
|
||||
|
||||
if (permissionData != null) {
|
||||
val (resultCode, resultData) = permissionData
|
||||
if (resultData != null) {
|
||||
val mediaProjectionManager =
|
||||
getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
|
||||
val newMediaProjection =
|
||||
mediaProjectionManager.getMediaProjection(resultCode, resultData)
|
||||
|
||||
if (newMediaProjection != null) {
|
||||
MediaProjectionHolder.setMediaProjection(newMediaProjection)
|
||||
Log.i(TAG, "✅ Android 15直接静默恢复成功")
|
||||
setupScreenCaptureWithMediaProjection(newMediaProjection)
|
||||
logCurrentPermissionState("直接恢复成功")
|
||||
return true
|
||||
}
|
||||
Log.w(TAG, "❌ getMediaProjection()返回null")
|
||||
}
|
||||
}
|
||||
|
||||
logCurrentPermissionState("AccessibilityService静默恢复失败")
|
||||
Log.w(TAG, "❌ Android 15静默恢复失败")
|
||||
// 🚨 不再重新创建!避免死循环
|
||||
Log.w(TAG, "❌ Holder中无有效MediaProjection,静默恢复失败,等待权限重新授予")
|
||||
false
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "❌ Android 15静默恢复异常", e)
|
||||
logCurrentPermissionState("AccessibilityService静默恢复异常")
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -6071,43 +6024,19 @@ class AccessibilityRemoteService : AccessibilityService() {
|
||||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
Log.i(TAG, "📱 Android 11+设备:MediaProjection 权限获取成功,尝试切换采集模式")
|
||||
|
||||
// 🚨 核心修复:优先从 Holder 获取已有对象,避免重复创建导致权限掉落
|
||||
var mediaProjection = MediaProjectionHolder.getMediaProjection()
|
||||
// 🚨 核心修复:只从 Holder 获取已有对象,禁止重复创建
|
||||
val 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)
|
||||
}
|
||||
} 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 不可用")
|
||||
Log.w(TAG, "⚠️ Android 11+ Holder中无有效MediaProjection,等待权限授予")
|
||||
}
|
||||
|
||||
// 标记权限完成
|
||||
|
||||
@@ -134,23 +134,30 @@ class RemoteControlForegroundService : Service() {
|
||||
Log.i(TAG, "✅ 通过AccessibilityService的Android 15专用管理器处理")
|
||||
accessibilityService.handleMediaProjectionGranted()
|
||||
} else {
|
||||
// 备用方案:直接创建但记录连接时间用于智能判断
|
||||
mediaProjection = mediaProjectionManager?.getMediaProjection(resultCode, resultData)
|
||||
// 备用方案:从 Holder 获取已有对象
|
||||
mediaProjection = MediaProjectionHolder.getMediaProjection()
|
||||
if (mediaProjection != null) {
|
||||
Log.i(TAG, "✅ Android 15 MediaProjection对象创建成功(备用方案)")
|
||||
MediaProjectionHolder.setMediaProjection(mediaProjection)
|
||||
Log.i(TAG, "✅ Android 15 从Holder获取到已有MediaProjection")
|
||||
notifyAccessibilityService()
|
||||
} else {
|
||||
// Holder 中无对象,通过安全创建入口创建
|
||||
mediaProjection = MediaProjectionHolder.safeGetOrCreateProjection(
|
||||
this@RemoteControlForegroundService, resultCode, resultData
|
||||
)
|
||||
if (mediaProjection != null) {
|
||||
Log.i(TAG, "✅ Android 15 MediaProjection对象创建成功(安全创建入口)")
|
||||
notifyAccessibilityService()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 其他版本的正常处理逻辑
|
||||
mediaProjection = mediaProjectionManager?.getMediaProjection(resultCode, resultData)
|
||||
// 其他版本:通过安全创建入口创建
|
||||
mediaProjection = MediaProjectionHolder.safeGetOrCreateProjection(
|
||||
this@RemoteControlForegroundService, resultCode, resultData
|
||||
)
|
||||
|
||||
if (mediaProjection != null) {
|
||||
Log.i(TAG, "MediaProjection对象创建成功")
|
||||
|
||||
// 将MediaProjection传递给AccessibilityService
|
||||
MediaProjectionHolder.setMediaProjection(mediaProjection)
|
||||
Log.i(TAG, "MediaProjection对象创建成功(安全创建入口)")
|
||||
|
||||
// 通知AccessibilityService
|
||||
notifyAccessibilityService()
|
||||
|
||||
Reference in New Issue
Block a user