排查前台服务问题

本页面讨论了前台服务可能失败的一些常见原因,并帮助您确定导致问题的原因。

本文档讨论了以下问题:

排查问题之前的准备工作

检查前台服务最近是否发生了变化

如果前台服务使用不当,可能会对设备性能和电池续航时间产生负面影响。因此,Android 平台版本通常会更改前台服务行为,以限制这些不良影响。

如果您在使用前台服务时遇到问题,应查看前台服务变更文档,了解是否有任何近期变更可以解释您遇到的问题。在以下情况下,检查更改尤为重要:

  • 之前可正常运行的前台服务代码现在无法运行
  • 您刚刚开始在新的平台版本上进行测试,或者您更改了应用的目标 API 级别

此外,如果您在平台的开发者预览版上测试设备,请务必查看最新版本的开发者预览版文档。

应用无响应 (ANR) 错误

在某些情况下,应用应关闭其前台服务。如果应用未停止该服务,系统会停止该服务并触发应用无响应 (ANR) 错误。

短期服务运行时间过长,导致 ANR

使用短时服务类型的前台服务必须快速完成,大约在三分钟内。当时间用尽时,系统会调用服务的 Service.onTimeout(int,int) 方法。服务有几秒钟的时间来调用 stopSelf()。如果服务未自行停止,系统会触发“应用无响应”错误。

诊断:

如果 ANR 是由前台服务未能自行停止引起的,系统会抛出内部异常。您可以通过查看 ANR 报告来验证是否存在此问题。如果问题确实如此,报告中将包含以下消息:

Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type FOREGROUND_SERVICE_TYPE_SHORT_SERVICE did not stop within its timeout:
[component name]"

修复方法:

确保所有有时间限制的前台服务都在系统时间限制内完成工作并调用 stopForeground(int)。

让前台服务实现 Service.onTimeout(int,int)。 请确保您对该方法的实现会立即调用 stopSelf()。

前台服务例外情况

本部分介绍了可能导致系统抛出异常的几个前台服务问题。如果应用未捕获该异常,用户会看到一个对话框,告知他们应用已停止。

在某些情况下,系统会抛出内部异常。在这种情况下,您可以通过查看堆栈轨迹来找出异常,还可以查看 Logcat 了解更详细的错误信息。

内部异常:超时

系统会限制当应用在后台运行时,数据同步和媒体处理前台服务可以运行的时长。如果服务超出该限制,系统会调用服务的 Service.onTimeout(int,int) 方法。服务有几秒钟的时间来调用 stopSelf()。如果服务未自行停止,系统会生成内部 RemoteServiceException,导致应用崩溃。

诊断:

您可以通过查看堆栈轨迹来了解异常是什么,还可以查看 Logcat 以获取更详细的错误信息。在这种情况下,Logcat 会显示以下错误消息:

Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type [service type] did not stop within its timeout: [component name]"

修复方法:

确保所有限时前台服务都在系统时间限制内完成工作并调用 stopForeground(int)。

让前台服务实现 Service.onTimeout(int,int)。 请确保您对该方法的实现会立即调用 stopSelf()。

内部异常:ForegroundServiceDidNotStartInTimeException

当您通过调用 context.startForegroundService() 启动服务时,该服务有几秒钟的时间通过调用 ServiceCompat.startForeground() 将自己提升为前台服务。如果服务未执行此操作,则会抛出内部 ForegroundServiceDidNotStartInTimeException。

诊断:

您可以通过查看堆栈轨迹来了解异常是什么,还可以查看 Logcat 以获取更详细的错误信息。在这种情况下,Logcat 会显示以下错误消息:

android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException:
Context.startForegroundService() did not then call Service.startForeground()

修复方法:

确保所有新创建的前台服务都会在几秒钟内调用 ServiceCompat.startForeground()。

WorkManager:

执行前台服务(调用 setForegound 或 setForegroundAsync)的 WorkManager worker 也可能会出现此异常。当两个前台 worker 的生命周期重叠时,即一个 worker 尝试启动前台服务,而之前运行的前台服务尝试关闭时,此崩溃会伴随以下日志:

Re-initializing SystemForegroundService after a request to shut-down

WorkManager 2.10.5 版中引入了针对此崩溃问题的修复。

如果您的应用遇到此异常,请更新到最新版本的 WorkManager,并向 WorkManager 问题跟踪器报告任何持续存在的问题。

ForegroundServiceStartNotAllowedException

错误:

系统会抛出 ForegroundServiceStartNotAllowedException。

原因:

这通常是因为应用在没有有效豁免的情况下从后台启动前台服务。

从 Android 12(API 级别 31)开始,应用在后台运行时无法启动前台服务,但少数特定情况除外。 如果您尝试从后台启动前台服务,但您不满足任何豁免条件的要求,系统会抛出 ForegroundServiceStartNotAllowedException。如果您不符合豁免要求,系统也会执行此操作。

例如,应用可能有一个可供用户点击的按钮,点击该按钮会导致应用执行一些处理,然后启动前台服务。在这种情况下,用户可能会点击该按钮,然后立即将应用置于后台。然后,应用会尝试从后台启动该服务。如果应用不符合任何指定的豁免条件,系统会抛出 ForegroundServiceStartNotAllowedException。

此外,部分豁免有较短的时限。例如,如果您的应用为响应高优先级 FCM 消息而启动前台服务,则可享有短暂的豁免。如果您未足够快地启动服务,则会收到 ForegroundServiceStartNotAllowedException。

随着新 Android 版本的发布,特定豁免有时会变得更加严格。如果您更改了应用的目标 Android 版本,请查看前台服务的变更文档,并确认您的应用仍符合其中一项允许的豁免条件。

修复方法:

更改应用的工作流,使其在后台运行时无需启动前台服务,或确认应用符合其中一项豁免条件。

您可以使用生命周期感知型组件来管理应用的生命周期,这样您就不会在无意中尝试从后台启动前台服务。

SecurityException

错误:

系统会抛出 SecurityException。

原因:

您的应用在未获得必要权限的情况下尝试启动前台服务。

  • 如果应用以 Android 9(API 级别 28)或更高版本为目标平台,则必须具有 FOREGROUND_SERVICE 权限才能启动前台服务。
  • 如果应用以 Android 14(API 级别 34)或更高版本为目标平台,则必须满足其前台服务类型的所有前提条件。前台服务类型文档中详细介绍了这些前提条件。请特别注意以下要求:
    • 多种前台服务类型需要特定的运行时权限。例如,远程消息传递前台服务必须具有 FOREGROUND_SERVICE_REMOTE_MESSAGING 权限。
  • 在某些情况下,某些前台服务类型所需的权限还存在额外的“使用时”限制。这些权限仅在应用在前台运行时授予应用(少数特定情况除外)。这意味着,即使您的应用已请求并获得其中一项权限,如果应用在后台运行时尝试启动前台服务,系统也会抛出 SecurityException,即使应用有权从后台启动前台服务也是如此。如需了解详情,请参阅关于启动需要“使用时”权限的前台服务的限制。
    • 如果您请求了必要的权限,但在确认已获得所需权限之前启动了前台服务,则可能会收到 SecurityException。

修复方法:

在启动前台服务之前,请请求所有适当的前台服务权限,并确认您已满足所有其他运行时前提条件。