You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何保障Wear OS 24/7健康监控服务持续运行及故障检测恢复?

三星Wear OS健康与位置监控服务稳定性优化方案

问题背景

我正在开发一款用于三星设备的Wear OS应用,作为研究项目的一部分,需7×24小时监控用户的健康数据与位置数据。当前方案虽能运行,但存在数据一致性问题,有时数据收集会停止或变慢。

现有实现代码

MainActivity启动前台服务

class MainActivity: ComponentActivity() {
    override fun onStart() {
        checkForegroundPermissions()
        // 权限授予后执行launchForegroundService
    }
    
    private fun launchForegroundService() {
        val serviceIntent = Intent(this, ForegroundMonitoringService::class.java)
        startForegroundService(serviceIntent)
        bindService(serviceIntent, foregroundOnlyServiceConnection, BIND_AUTO_CREATE)
    }
}

注:同时启动并绑定服务,以便访问服务方法。

ForegroundMonitoringService核心逻辑

class ForegroundMonitoringService : Service() {
    private val serviceJob = SupervisorJob()
    private val serviceScope = CoroutineScope(serviceJob + Dispatchers.Default)
    
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        super.onStartCommand(intent, flags, startId)
        startForeground()
        startMonitoringJob()
        return START_STICKY
    }
    
    private fun startForeground() {
        val serviceTypes = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            FOREGROUND_SERVICE_TYPE_LOCATION or FOREGROUND_SERVICE_TYPE_HEALTH
        } else {
            0
        }

        ServiceCompat.startForeground(
            this,
            SERVICE_ID,
            generateNotification(isMonitoring = false),
            serviceTypes
        )
    }
    
    private fun startMonitoringJob() {
        while (isActive) {
            monitoringJob?.cancel()
            monitoringJob = serviceScope.launch {
                val result = monitoringRepository.sendData()
                result
                    .onSuccess {}
                    .onFailure { error -> ... }
        
                delay(SEND_DATA_INTERVAL)
            }
        }
    }
}

监控补充说明

监控仓库收集4-6路传感器数据流(来自Android Health Services与三星Health Tracking Service),合并为一个数据类并转为JSON,按SEND_DATA_INTERVAL间隔发送至服务器。若因网络问题无法发送,会本地存储数据,待网络恢复后由WorkManager尝试补发。

核心问题

不确定监控停止/变慢的具体原因,但明确数据完整性优先于设备健康,需解决:

  1. 如何可靠检测、预防并恢复前台服务被杀死的情况?
  2. 如何无需手动监控就能验证服务长期持续运行?

解决方案

一、预防服务被系统杀死

1. 修正任务调度逻辑

当前startMonitoringJobwhile(isActive)循环会反复cancel并重启协程,容易导致任务混乱。改为单次启动循环任务:

private fun startMonitoringJob() {
    monitoringJob = serviceScope.launch {
        while (isActive) {
            val result = monitoringRepository.sendData()
            result
                .onSuccess {}
                .onFailure { error -> ... }
            delay(SEND_DATA_INTERVAL)
        }
    }
}

2. 优化绑定服务的使用

同时启动并长期绑定服务,会在宿主Activity销毁后增加被系统回收的风险。如果仅需偶尔调用服务方法,建议:

  • 改用MessengerAIDL实现跨进程通信,避免长期绑定
  • 在Activity的onStop方法中手动解绑服务,保留startForegroundService的启动逻辑

3. 适配三星设备的后台限制

三星Wear OS有独立的后台管控策略,必须引导用户完成以下设置:

  • 关闭应用的「电池优化」,设置为「不优化」
  • 开启「后台活动权限」
  • 将位置/健康权限设置为「始终允许」

4. 合理使用唤醒锁

仅在数据收集发送的短时间内持有PARTIAL_WAKE_LOCK,避免长期持有导致耗电:

private val wakeLock = PowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Monitoring:WakeLock")

fun sendData(): Result<Unit> {
    wakeLock.acquire(10*1000) // 最多持有10秒,防止意外泄漏
    return try {
        // 收集并发送数据逻辑
        Result.success(Unit)
    } catch (e: Exception) {
        Result.failure(e)
    } finally {
        if (wakeLock.isHeld) wakeLock.release()
    }
}

二、检测与恢复服务

1. WorkManager周期性检查

创建周期性Worker,每15分钟检查服务是否在前台运行,若未运行则重启:

class ServiceCheckWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
    override suspend fun doWork(): Result {
        val isServiceRunning = isForegroundServiceRunning(ForegroundMonitoringService::class.java)
        if (!isServiceRunning) {
            val intent = Intent(applicationContext, ForegroundMonitoringService::class.java)
            ContextCompat.startForegroundService(applicationContext, intent)
        }
        return Result.success()
    }

    private fun isForegroundServiceRunning(serviceClass: Class<*>): Boolean {
        val manager = applicationContext.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        return manager.getRunningServices(Int.MAX_VALUE).any {
            it.service.className == serviceClass.name && it.foreground
        }
    }
}

// 应用启动时调度检查任务
val checkRequest = PeriodicWorkRequestBuilder<ServiceCheckWorker>(15, TimeUnit.MINUTES)
    .setConstraints(Constraints.Builder().setRequiresBatteryNotLow(false).build())
    .build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork("ServiceCheck", ExistingPeriodicWorkPolicy.REPLACE, checkRequest)

2. 系统广播触发重启

注册开机完成广播,设备重启后自动启动服务;同时监听应用进程重启广播,及时恢复监控:

  • 在Manifest中添加权限与广播接收器:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<receiver android:name=".ServiceRestartReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
    </intent-filter>
</receiver>
  • 实现广播接收器:
class ServiceRestartReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        context?.let {
            val serviceIntent = Intent(it, ForegroundMonitoringService::class.java)
            ContextCompat.startForegroundService(it, serviceIntent)
        }
    }
}

3. 服务心跳监控

在服务中每5分钟向本地数据库写入心跳时间戳,WorkManager的检查任务可同时验证心跳是否超时(比如超过20分钟无更新),若超时则强制重启服务,避免服务假死。

三、自动化验证服务长期运行

1. 日志与远程上报

在服务的启动、数据发送、任务重启等关键节点写入本地日志,并定期将日志上传至服务器。通过服务器端的日志分析,可统计服务的运行时长、中断次数、异常原因。

2. 心跳数据可视化

在服务器端维护服务的心跳上报记录,生成运行状态折线图,直观展示服务是否持续运行,无需手动检查设备。

3. 自动化稳定性测试

  • 使用Android Instrumentation编写长期运行测试,模拟设备休眠、低电量、系统杀进程等场景,验证服务的恢复能力
  • 借助Firebase Test Lab进行多设备的长期稳定性测试,覆盖不同三星Wear OS版本

内容的提问来源于stack exchange,提问作者theproductivepickle

火山引擎 最新活动