致命 Android 12:异常:由于 mAllowStartForeground false 而不允许 startForegroundService()
Fatal Android 12: Exception: startForegroundService() not allowed due to mAllowStartForeground false
我注意到 Pixel 5 和 Pixel 4a(都在 Android 12 上)有一个异常(Firebase Crashlytics),没有其他设备,只发生了两次,每个设备一次。
这是什么意思? Android 11 和 12 使用前台服务的规则相同,但没有问题 Android 11. 这是 Pixel 的错误吗?
来自 Firebase Crashlytics:
Fatal Exception: android.app.ForegroundServiceStartNotAllowedException
startForegroundService() not allowed due to mAllowStartForeground false: service com.helge.droiddashcam/.service.RecorderService
android.app.ForegroundServiceStartNotAllowedException.createFromParcel (ForegroundServiceStartNotAllowedException.java:54)
androidx.core.content.ContextCompat.startForegroundService (ContextCompat.java:6)
MyAppPackageHidden.service.RecorderService$Companion.startService (RecorderService.java:2)
MyAppPackageHidden.ui.rec.RecActivity$getConnectionRecorderService.onServiceConnected (RecActivity.java:4)
android.app.LoadedApk$ServiceDispatcher.doConnected (LoadedApk.java:2077)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1003)
Fatal Exception: android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false: service MyAppPackageHidden/.service.RecorderService
at android.app.ForegroundServiceStartNotAllowedException.createFromParcel(ForegroundServiceStartNotAllowedException.java:54)
at android.app.ForegroundServiceStartNotAllowedException.createFromParcel(ForegroundServiceStartNotAllowedException.java:50)
at android.os.Parcel.readParcelable(Parcel.java:3333)
at android.os.Parcel.createExceptionOrNull(Parcel.java:2420)
at android.os.Parcel.createException(Parcel.java:2409)
at android.os.Parcel.readException(Parcel.java:2392)
at android.os.Parcel.readException(Parcel.java:2334)
at android.app.IActivityManager$Stub$Proxy.startService(IActivityManager.java:5971)
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1847)
at android.app.ContextImpl.startForegroundService(ContextImpl.java:1823)
at android.content.ContextWrapper.startForegroundService(ContextWrapper.java:779)
at androidx.core.content.ContextCompat$Api26Impl.startForegroundService(ContextCompat.java)
at androidx.core.content.ContextCompat.startForegroundService(ContextCompat.java:6)
at MyAppPackageHidden.service.RecorderService$Companion.startService(RecorderService.java:2)
at MyAppPackageHidden.ui.rec.RecActivity$getConnectionRecorderService.onServiceConnected(RecActivity.java:4)
at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:2077)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:2110)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7838)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Caused by android.os.RemoteException: Remote stack trace:
at com.android.server.am.ActiveServices.startServiceLocked(ActiveServices.java:691)
at com.android.server.am.ActiveServices.startServiceLocked(ActiveServices.java:616)
at com.android.server.am.ActivityManagerService.startService(ActivityManagerService.java:11839)
at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2519)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2498)
针对 Android 12(API 级别 31)或更高版本的应用无法在 运行 处于后台时启动前台服务,少数特殊情况除外。如果应用程序在后台 运行 时尝试启动前台服务,并且前台服务不满足其中一种异常情况,系统将抛出 ForegroundServiceStartNotAllowedException。
免除后台启动限制
在以下情况下,即使您的应用 运行 在后台,您的应用也可以启动前台服务:
- 您的应用从用户可见状态转换,例如 activity。
- 您的应用可以从后台启动 activity,除了
应用程序在现有的返回堆栈中有一个 activity 的情况
任务。
- 您的应用使用 Firebase 云接收高优先级消息
消息。
- 用户对与您的应用相关的 UI 元素执行了操作。为了
例如,他们可能会与气泡、通知、小部件或
activity.
- 您的应用调用确切的警报来完成用户的操作
请求。
- 您的应用是设备当前的输入法。
- 您的应用收到与地理围栏或 activity 相关的事件
识别转换。
- 设备重启并收到ACTION_BOOT_COMPLETED后,
ACTION_LOCKED_BOOT_COMPLETED 或 ACTION_MY_PACKAGE_REPLACED 意图
广播接收器中的操作。
更多信息请查看link1
要在 android 12 或更高版本中解决此问题,请更新您的应用逻辑:
如果您发现您的应用在 运行 从后台启动前台服务,请更新您的应用逻辑以在 GitHub 上使用 WorkManager. To view an example of how to update your app, look through the WorkManagerSample。
之前我们使用Service
到运行后台任务,比如备份数据,设置提醒通知等,而之前调用服务的代码如下
Intent serviceIntent = new Intent ( context, BackupService.class );
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService ( serviceIntent );
} else {
context.startService ( serviceIntent );
}
但是,由于Android 12 - Foreground service launch restrictions
,我们将无法调用服务来执行后台任务。要了解有关此限制的更多信息,请参阅 Android 12 Behavior Changes。
所以从现在开始,(即)从targetSdk 31 / Android 12+,Service
只能在应用程序在前台时调用。当应用程序关闭或应用程序进入后台时,使用 startForegroundService
调用 Service
将导致 ForegroundServiceStartNotAllowedException
。所以要在Android 12及以上执行后台任务,我们需要使用Worker
而不是Service
。要了解有关 Worker
的更多信息,请参阅 Work Requests。
所以针对SDK 31 / Android 12+的应用,调用后台任务的代码如下,
Intent serviceIntent = new Intent ( context, BackupService.class );
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder ( BackupWorker.class ).addTag ( "BACKUP_WORKER_TAG" ).build ();
WorkManager.getInstance ( context ).enqueue ( request );
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService ( serviceIntent );
} else {
context.startService ( serviceIntent );
}
BackupService
(现有)的示例代码。
public class BackupService extends Service {
private static final String TAG = "BackupService";
@Nullable
@Override
public IBinder onBind ( Intent intent ) {
return null;
}
@Override
public int onStartCommand ( Intent intent, int flags, int startId ) {
Log.d ( TAG, "onStartCommand" );
startForeground ( BACKUP_SERVICE_NOTIFICATION_ID, createServiceNotification () );
//call methods to perform background task
return super.onStartCommand ( intent, flags, startId );
}
}
BackupWorker
的示例代码(新增)。
public class BackupWorker extends Worker {
private static final String TAG = "BackupWorker";
public BackupWorker ( @NonNull Context context, @NonNull WorkerParameters workerParams ) {
super ( context, workerParams );
}
@NonNull
@Override
public Result doWork () {
//call methods to perform background task
return Result.success ();
}
}
确保在 module-level gradle
文件中添加以下依赖项
implementation 'androidx.work:work-runtime:2.7.1'
implementation 'com.google.guava:guava:27.0.1-android'
我已经测试了上面的代码与 Android 5, Android 8, Android 11 & Android 12 一起工作。在我的情况下按预期工作。
希望此解决方案可以帮助那些将其应用程序定位为 SDK 31 / Android 12+ 的人。
就我而言,我们使用进行 SIP 通信 (VoIP) 的服务,并且我们正在启动前台服务来执行时间敏感的操作(例如注册)或在 运行ning SIP 呼叫时。这些任务不能 运行 在 Worker
.
中
要处理此用例,Android allows you to declare your service's "foregroundServiceType
", and some types are allowed to create foreground services from the background。这有意义的另一个值得注意的用例是媒体播放。
我注意到 Pixel 5 和 Pixel 4a(都在 Android 12 上)有一个异常(Firebase Crashlytics),没有其他设备,只发生了两次,每个设备一次。
这是什么意思? Android 11 和 12 使用前台服务的规则相同,但没有问题 Android 11. 这是 Pixel 的错误吗?
来自 Firebase Crashlytics:
Fatal Exception: android.app.ForegroundServiceStartNotAllowedException
startForegroundService() not allowed due to mAllowStartForeground false: service com.helge.droiddashcam/.service.RecorderService
android.app.ForegroundServiceStartNotAllowedException.createFromParcel (ForegroundServiceStartNotAllowedException.java:54)
androidx.core.content.ContextCompat.startForegroundService (ContextCompat.java:6)
MyAppPackageHidden.service.RecorderService$Companion.startService (RecorderService.java:2)
MyAppPackageHidden.ui.rec.RecActivity$getConnectionRecorderService.onServiceConnected (RecActivity.java:4)
android.app.LoadedApk$ServiceDispatcher.doConnected (LoadedApk.java:2077)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1003)
Fatal Exception: android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false: service MyAppPackageHidden/.service.RecorderService
at android.app.ForegroundServiceStartNotAllowedException.createFromParcel(ForegroundServiceStartNotAllowedException.java:54)
at android.app.ForegroundServiceStartNotAllowedException.createFromParcel(ForegroundServiceStartNotAllowedException.java:50)
at android.os.Parcel.readParcelable(Parcel.java:3333)
at android.os.Parcel.createExceptionOrNull(Parcel.java:2420)
at android.os.Parcel.createException(Parcel.java:2409)
at android.os.Parcel.readException(Parcel.java:2392)
at android.os.Parcel.readException(Parcel.java:2334)
at android.app.IActivityManager$Stub$Proxy.startService(IActivityManager.java:5971)
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1847)
at android.app.ContextImpl.startForegroundService(ContextImpl.java:1823)
at android.content.ContextWrapper.startForegroundService(ContextWrapper.java:779)
at androidx.core.content.ContextCompat$Api26Impl.startForegroundService(ContextCompat.java)
at androidx.core.content.ContextCompat.startForegroundService(ContextCompat.java:6)
at MyAppPackageHidden.service.RecorderService$Companion.startService(RecorderService.java:2)
at MyAppPackageHidden.ui.rec.RecActivity$getConnectionRecorderService.onServiceConnected(RecActivity.java:4)
at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:2077)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:2110)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7838)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Caused by android.os.RemoteException: Remote stack trace:
at com.android.server.am.ActiveServices.startServiceLocked(ActiveServices.java:691)
at com.android.server.am.ActiveServices.startServiceLocked(ActiveServices.java:616)
at com.android.server.am.ActivityManagerService.startService(ActivityManagerService.java:11839)
at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2519)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2498)
针对 Android 12(API 级别 31)或更高版本的应用无法在 运行 处于后台时启动前台服务,少数特殊情况除外。如果应用程序在后台 运行 时尝试启动前台服务,并且前台服务不满足其中一种异常情况,系统将抛出 ForegroundServiceStartNotAllowedException。
免除后台启动限制
在以下情况下,即使您的应用 运行 在后台,您的应用也可以启动前台服务:
- 您的应用从用户可见状态转换,例如 activity。
- 您的应用可以从后台启动 activity,除了 应用程序在现有的返回堆栈中有一个 activity 的情况 任务。
- 您的应用使用 Firebase 云接收高优先级消息 消息。
- 用户对与您的应用相关的 UI 元素执行了操作。为了 例如,他们可能会与气泡、通知、小部件或 activity.
- 您的应用调用确切的警报来完成用户的操作 请求。
- 您的应用是设备当前的输入法。
- 您的应用收到与地理围栏或 activity 相关的事件 识别转换。
- 设备重启并收到ACTION_BOOT_COMPLETED后, ACTION_LOCKED_BOOT_COMPLETED 或 ACTION_MY_PACKAGE_REPLACED 意图 广播接收器中的操作。
更多信息请查看link1
要在 android 12 或更高版本中解决此问题,请更新您的应用逻辑:
如果您发现您的应用在 运行 从后台启动前台服务,请更新您的应用逻辑以在 GitHub 上使用 WorkManager. To view an example of how to update your app, look through the WorkManagerSample。
之前我们使用Service
到运行后台任务,比如备份数据,设置提醒通知等,而之前调用服务的代码如下
Intent serviceIntent = new Intent ( context, BackupService.class );
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService ( serviceIntent );
} else {
context.startService ( serviceIntent );
}
但是,由于Android 12 - Foreground service launch restrictions
,我们将无法调用服务来执行后台任务。要了解有关此限制的更多信息,请参阅 Android 12 Behavior Changes。
所以从现在开始,(即)从targetSdk 31 / Android 12+,Service
只能在应用程序在前台时调用。当应用程序关闭或应用程序进入后台时,使用 startForegroundService
调用 Service
将导致 ForegroundServiceStartNotAllowedException
。所以要在Android 12及以上执行后台任务,我们需要使用Worker
而不是Service
。要了解有关 Worker
的更多信息,请参阅 Work Requests。
所以针对SDK 31 / Android 12+的应用,调用后台任务的代码如下,
Intent serviceIntent = new Intent ( context, BackupService.class );
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder ( BackupWorker.class ).addTag ( "BACKUP_WORKER_TAG" ).build ();
WorkManager.getInstance ( context ).enqueue ( request );
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService ( serviceIntent );
} else {
context.startService ( serviceIntent );
}
BackupService
(现有)的示例代码。
public class BackupService extends Service {
private static final String TAG = "BackupService";
@Nullable
@Override
public IBinder onBind ( Intent intent ) {
return null;
}
@Override
public int onStartCommand ( Intent intent, int flags, int startId ) {
Log.d ( TAG, "onStartCommand" );
startForeground ( BACKUP_SERVICE_NOTIFICATION_ID, createServiceNotification () );
//call methods to perform background task
return super.onStartCommand ( intent, flags, startId );
}
}
BackupWorker
的示例代码(新增)。
public class BackupWorker extends Worker {
private static final String TAG = "BackupWorker";
public BackupWorker ( @NonNull Context context, @NonNull WorkerParameters workerParams ) {
super ( context, workerParams );
}
@NonNull
@Override
public Result doWork () {
//call methods to perform background task
return Result.success ();
}
}
确保在 module-level gradle
文件中添加以下依赖项
implementation 'androidx.work:work-runtime:2.7.1'
implementation 'com.google.guava:guava:27.0.1-android'
我已经测试了上面的代码与 Android 5, Android 8, Android 11 & Android 12 一起工作。在我的情况下按预期工作。
希望此解决方案可以帮助那些将其应用程序定位为 SDK 31 / Android 12+ 的人。
就我而言,我们使用进行 SIP 通信 (VoIP) 的服务,并且我们正在启动前台服务来执行时间敏感的操作(例如注册)或在 运行ning SIP 呼叫时。这些任务不能 运行 在 Worker
.
要处理此用例,Android allows you to declare your service's "foregroundServiceType
", and some types are allowed to create foreground services from the background。这有意义的另一个值得注意的用例是媒体播放。