排查前台服务问题

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

本文档讨论了以下问题:

排查问题之前的准备工作

检查前台服务的近期更改

如果前台服务使用不当,可能会对设备性能和电池续航时间产生负面影响。因此,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

您还可能会看到 WorkManager worker 出现此异常,这些 worker 执行 前台服务 (调用 setForegoundsetForegroundAsync)。当两个 前台 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

修复方法

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