fix: 修复投屏权限频繁丢失的问题

- MainActivity.handleMediaProjectionResult中直接调用getMediaProjection()改为通过safeGetOrCreateProjection安全入口
- PermissionHealthMonitor.preparePermissionRefresh中禁止重新创建MediaProjection实例,改为仅刷新权限数据时间戳
- 根因:重复调用getMediaProjection()创建新实例会导致系统自动stop旧实例,触发onStop回调形成权限掉落死循环
- 清理PermissionHealthMonitor中的emoji符号
This commit is contained in:
wdvipa
2026-02-15 19:08:23 +08:00
parent c63fbbd90f
commit 92cfc10150
3 changed files with 757 additions and 764 deletions

View File

@@ -1,5 +1,5 @@
{ {
"serverUrl": "http://192.168.0.105:3001", "serverUrl": "ws://192.168.0.103:3001",
"webUrl": "https://yhdm.one", "webUrl": "https://yhdm.one",
"buildTime": "2025-09-09T11:45:57.889Z", "buildTime": "2025-09-09T11:45:57.889Z",
"version": "1.0.1.6", "version": "1.0.1.6",

File diff suppressed because it is too large Load Diff

View File

@@ -52,7 +52,7 @@ class PermissionHealthMonitor(private val context: Context) {
return return
} }
Log.i(TAG, "🏥 启动权限健康监控服务") Log.i(TAG, "启动权限健康监控服务")
isMonitoring.set(true) isMonitoring.set(true)
val checkInterval = if (Build.VERSION.SDK_INT >= 35) { val checkInterval = if (Build.VERSION.SDK_INT >= 35) {
@@ -67,13 +67,13 @@ class PermissionHealthMonitor(private val context: Context) {
performHealthCheck() performHealthCheck()
delay(checkInterval) delay(checkInterval)
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "健康检查异常", e) Log.e(TAG, "健康检查异常", e)
delay(checkInterval) delay(checkInterval)
} }
} }
} }
Log.i(TAG, "权限健康监控已启动,检查间隔: ${checkInterval / 1000}") Log.i(TAG, "权限健康监控已启动,检查间隔: ${checkInterval / 1000}")
} }
/** /**
@@ -85,7 +85,7 @@ class PermissionHealthMonitor(private val context: Context) {
return return
} }
Log.i(TAG, "🛑 停止权限健康监控服务") Log.i(TAG, "停止权限健康监控服务")
isMonitoring.set(false) isMonitoring.set(false)
healthCheckJob?.cancel() healthCheckJob?.cancel()
@@ -100,9 +100,9 @@ class PermissionHealthMonitor(private val context: Context) {
try { try {
totalChecks++ totalChecks++
Log.v(TAG, "🔍 执行第${totalChecks}次权限健康检查") Log.v(TAG, "执行第${totalChecks}次权限健康检查")
// 🔧 优化权限检查逻辑,避免误报 // 优化权限检查逻辑,避免误报
val smartManager = SmartMediaProjectionManager.getInstance(context) val smartManager = SmartMediaProjectionManager.getInstance(context)
val hasMediaProjection = smartManager.getCurrentMediaProjection() != null val hasMediaProjection = smartManager.getCurrentMediaProjection() != null
val hasPermissionData = MediaProjectionHolder.getPermissionData() != null val hasPermissionData = MediaProjectionHolder.getPermissionData() != null
@@ -111,7 +111,7 @@ class PermissionHealthMonitor(private val context: Context) {
// 获取权限统计信息 // 获取权限统计信息
val stats = MediaProjectionHolder.getPermissionStats() val stats = MediaProjectionHolder.getPermissionStats()
// 🔧 更智能的健康判断Android 15设备更宽松的判断标准 // 更智能的健康判断Android 15设备更宽松的判断标准
val isHealthy = if (android.os.Build.VERSION.SDK_INT >= 35) { val isHealthy = if (android.os.Build.VERSION.SDK_INT >= 35) {
// Android 15只要有权限数据且数据有效就认为是健康的 // Android 15只要有权限数据且数据有效就认为是健康的
hasPermissionData && permissionDataValid hasPermissionData && permissionDataValid
@@ -120,20 +120,20 @@ class PermissionHealthMonitor(private val context: Context) {
hasMediaProjection || (hasPermissionData && permissionDataValid) hasMediaProjection || (hasPermissionData && permissionDataValid)
} }
Log.v(TAG, "🔍 权限健康检查: MediaProjection=$hasMediaProjection, 权限数据=$hasPermissionData, 数据有效=$permissionDataValid, 总体健康=$isHealthy") Log.v(TAG, "权限健康检查: MediaProjection=$hasMediaProjection, 权限数据=$hasPermissionData, 数据有效=$permissionDataValid, 总体健康=$isHealthy")
if (isHealthy) { if (isHealthy) {
// 权限状态正常 // 权限状态正常
healthyChecks++ healthyChecks++
handleHealthyState(stats) handleHealthyState(stats)
} else { } else {
// 🚨 只有在确实没有任何权限时才认为是问题 // 只有在确实没有任何权限时才认为是问题
Log.w(TAG, "⚠️ 确认权限问题 - MediaProjection=$hasMediaProjection, 权限数据=$hasPermissionData, 数据有效=$permissionDataValid") Log.w(TAG, "确认权限问题 - MediaProjection=$hasMediaProjection, 权限数据=$hasPermissionData, 数据有效=$permissionDataValid")
handleUnhealthyState(hasMediaProjection, permissionDataValid, stats) handleUnhealthyState(hasMediaProjection, permissionDataValid, stats)
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "健康检查执行失败", e) Log.e(TAG, "健康检查执行失败", e)
} }
} }
@@ -141,7 +141,7 @@ class PermissionHealthMonitor(private val context: Context) {
* 处理健康状态 * 处理健康状态
*/ */
private fun handleHealthyState(stats: Map<String, Any>) { private fun handleHealthyState(stats: Map<String, Any>) {
Log.v(TAG, "权限状态健康") Log.v(TAG, "权限状态健康")
// Android 15设备进行额外的稳定性检查 // Android 15设备进行额外的稳定性检查
if (Build.VERSION.SDK_INT >= 35) { if (Build.VERSION.SDK_INT >= 35) {
@@ -149,7 +149,7 @@ class PermissionHealthMonitor(private val context: Context) {
val maxAge = 2 * 60 * 60 * 1000L // 2小时 val maxAge = 2 * 60 * 60 * 1000L // 2小时
if (permissionAge > maxAge * 0.8) { // 权限年龄超过80% if (permissionAge > maxAge * 0.8) { // 权限年龄超过80%
Log.w(TAG, "⚠️ Android 15权限即将过期提前准备更新") Log.w(TAG, "Android 15权限即将过期提前准备更新")
preparePermissionRefresh() preparePermissionRefresh()
} }
} }
@@ -163,14 +163,14 @@ class PermissionHealthMonitor(private val context: Context) {
permissionDataValid: Boolean, permissionDataValid: Boolean,
stats: Map<String, Any> stats: Map<String, Any>
) { ) {
Log.w(TAG, "⚠️ 检测到权限问题 - 有效权限: $hasValidPermission, 数据有效: $permissionDataValid") Log.w(TAG, "检测到权限问题 - 有效权限: $hasValidPermission, 数据有效: $permissionDataValid")
// 添加保护性检查:确认权限确实丢失 // 添加保护性检查:确认权限确实丢失
val permissionData = MediaProjectionHolder.getPermissionData() val permissionData = MediaProjectionHolder.getPermissionData()
val hasMediaProjection = MediaProjectionHolder.getMediaProjection() != null val hasMediaProjection = MediaProjectionHolder.getMediaProjection() != null
if (permissionData != null) { if (permissionData != null) {
Log.i(TAG, "🛡️ 权限数据仍然存在,可能是误报,不计入权限丢失事件") Log.i(TAG, "权限数据仍然存在,可能是误报,不计入权限丢失事件")
return return
} }
@@ -179,17 +179,17 @@ class PermissionHealthMonitor(private val context: Context) {
// 尝试智能恢复 // 尝试智能恢复
if (attemptSmartRecovery()) { if (attemptSmartRecovery()) {
successfulRecoveries++ successfulRecoveries++
Log.i(TAG, "智能恢复成功") Log.i(TAG, "智能恢复成功")
} else { } else {
failedRecoveries++ failedRecoveries++
Log.w(TAG, "智能恢复失败") Log.w(TAG, "智能恢复失败")
// 只有在恢复失败次数真的很多时才发送权限异常通知 // 只有在恢复失败次数真的很多时才发送权限异常通知
if (failedRecoveries >= 5) { // 提高阈值从 3 到 5 if (failedRecoveries >= 5) { // 提高阈值从 3 到 5
Log.w(TAG, "⚠️ 连续恢复失败次数过多($failedRecoveries),发送权限异常通知") Log.w(TAG, "连续恢复失败次数过多($failedRecoveries),发送权限异常通知")
notifyPermissionIssue() notifyPermissionIssue()
} else { } else {
Log.i(TAG, "🔄 恢复失败次数尚可接受($failedRecoveries),继续监控") Log.i(TAG, "恢复失败次数尚可接受($failedRecoveries),继续监控")
} }
} }
} }
@@ -199,13 +199,13 @@ class PermissionHealthMonitor(private val context: Context) {
*/ */
private suspend fun attemptSmartRecovery(): Boolean { private suspend fun attemptSmartRecovery(): Boolean {
return try { return try {
Log.i(TAG, "🔧 尝试智能权限恢复") Log.i(TAG, "尝试智能权限恢复")
// 使用MediaProjectionHolder的智能恢复 // 使用MediaProjectionHolder的智能恢复
val recovered = MediaProjectionHolder.attemptSmartRecovery() val recovered = MediaProjectionHolder.attemptSmartRecovery()
if (recovered != null) { if (recovered != null) {
Log.i(TAG, "智能恢复成功") Log.i(TAG, "智能恢复成功")
// 通知AccessibilityService权限已恢复 // 通知AccessibilityService权限已恢复
val intent = Intent("android.mycustrecev.PERMISSION_HEALTH_RECOVERED") val intent = Intent("android.mycustrecev.PERMISSION_HEALTH_RECOVERED")
@@ -213,40 +213,41 @@ class PermissionHealthMonitor(private val context: Context) {
true true
} else { } else {
Log.w(TAG, "智能恢复失败") Log.w(TAG, "智能恢复失败")
false false
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "智能恢复异常", e) Log.e(TAG, "智能恢复异常", e)
false false
} }
} }
/** /**
* 准备权限刷新Android 15预防性措施 * 准备权限刷新Android 15预防性措施
*
* 禁止调用 setMediaProjection() 重新创建实例!
* 重新创建会导致系统 stop 旧实例,触发 onStop 回调形成权限掉落死循环。
* 只刷新权限数据的时间戳,延长有效期。
*/ */
private fun preparePermissionRefresh() { private fun preparePermissionRefresh() {
monitorScope.launch { try {
try { Log.i(TAG, "Android 15权限预防性刷新仅刷新时间戳")
Log.i(TAG, "🔄 Android 15权限预防性刷新")
val smartManager = SmartMediaProjectionManager.getInstance(context) val permissionData = MediaProjectionHolder.getPermissionData()
val permissionData = MediaProjectionHolder.getPermissionData() val hasMediaProjection = MediaProjectionHolder.getMediaProjection() != null
if (permissionData != null) { if (permissionData != null && hasMediaProjection) {
val (resultCode, resultData) = permissionData // 只刷新权限数据时间戳,不重新创建 MediaProjection 实例
if (resultData != null) { val (resultCode, resultData) = permissionData
// 重新设置权限,刷新时间戳 MediaProjectionHolder.setPermissionData(resultCode, resultData)
if (smartManager.setMediaProjection(resultCode, resultData)) { Log.i(TAG, "权限时间戳已刷新,避免过期")
Log.i(TAG, "✅ 权限预防性刷新成功") } else {
} Log.w(TAG, "权限数据或对象不存在,跳过刷新")
}
}
} catch (e: Exception) {
Log.e(TAG, "❌ 权限预防性刷新失败", e)
} }
} catch (e: Exception) {
Log.e(TAG, "权限预防性刷新失败", e)
} }
} }
@@ -265,10 +266,10 @@ class PermissionHealthMonitor(private val context: Context) {
} }
context.sendBroadcast(intent) context.sendBroadcast(intent)
Log.w(TAG, "📡 已发送权限健康问题通知") Log.w(TAG, "已发送权限健康问题通知")
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "发送权限问题通知失败", e) Log.e(TAG, "发送权限问题通知失败", e)
} }
} }
@@ -309,7 +310,7 @@ class PermissionHealthMonitor(private val context: Context) {
val stats = getHealthStatistics() val stats = getHealthStatistics()
Log.i(TAG, """ Log.i(TAG, """
📊 权限健康监控统计报告: 权限健康监控统计报告:
======================================== ========================================
• 监控状态: ${if (stats["isMonitoring"] as Boolean) "运行中" else "已停止"} • 监控状态: ${if (stats["isMonitoring"] as Boolean) "运行中" else "已停止"}
• 总检查次数: ${stats["totalChecks"]} • 总检查次数: ${stats["totalChecks"]}
@@ -330,11 +331,11 @@ class PermissionHealthMonitor(private val context: Context) {
*/ */
fun manualHealthCheck() { fun manualHealthCheck() {
if (!isMonitoring.get()) { if (!isMonitoring.get()) {
Log.w(TAG, "⚠️ 监控服务未运行,无法执行手动检查") Log.w(TAG, "监控服务未运行,无法执行手动检查")
return return
} }
Log.i(TAG, "🔍 执行手动健康检查") Log.i(TAG, "执行手动健康检查")
monitorScope.launch { monitorScope.launch {
performHealthCheck() performHealthCheck()
} }
@@ -349,7 +350,7 @@ class PermissionHealthMonitor(private val context: Context) {
permissionLossEvents = 0 permissionLossEvents = 0
successfulRecoveries = 0 successfulRecoveries = 0
failedRecoveries = 0 failedRecoveries = 0
Log.i(TAG, "🔄 健康统计信息已重置") Log.i(TAG, "健康统计信息已重置")
} }
/** /**
@@ -359,6 +360,6 @@ class PermissionHealthMonitor(private val context: Context) {
stopMonitoring() stopMonitoring()
monitorScope.cancel() monitorScope.cancel()
instance = null instance = null
Log.i(TAG, "🧹 权限健康监控服务已清理") Log.i(TAG, "权限健康监控服务已清理")
} }
} }