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