I've got a music player which attempts to start a Service
in onResume()
of an Activity
. I've removed a few lines for clarity, but the code is effectively:
@Override protected void onResume() { super.onResume(); startService(new Intent(this, MusicService.class)); }
According to the crash logs, this is throwing an Exception on some devices running Android P:
Caused by java.lang.IllegalStateException: Not allowed to start service Intent { cmp=another.music.player/com.simplecity.amp_library.playback.MusicService }: app is in background uid UidRecord{6a4a9c6 u0a143 TPSL bg:+3m25s199ms idle change:cached procs:1 seq(1283,1283,1283)} at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1577) at android.app.ContextImpl.startService(ContextImpl.java:1532) at android.content.ContextWrapper.startService(ContextWrapper.java:664) at android.content.ContextWrapper.startService(ContextWrapper.java:664) at com.simplecity.amp_library.utils.MusicServiceConnectionUtils.bindToService(SourceFile:36) at com.simplecity.amp_library.ui.activities.BaseActivity.bindService(SourceFile:129) at com.simplecity.amp_library.ui.activities.BaseActivity.onResume(SourceFile:96)
How is it possible that my app is in the background, immediately after onResume()
(and super.onResume()
) is called?
This doesn't make any sense to me. Could this be a platform bug? All 3500+ users affected by this crash are on Android P.
There is a workaround from Google:
The issue has been addressed in future Android release.
There is a workaround to avoid application crash. Applications can get the process state in Activity.onResume() by calling ActivityManager.getRunningAppProcesses() and avoid starting Service if the importance level is lower than ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND. If the device hasn’t fully awake, activities would be paused immediately and eventually be resumed again after its fully awake.
So I think it should like that:
// hack for https://issuetracker.google.com/issues/113122354 List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses(); if (runningAppProcesses != null) { int importance = runningAppProcesses.get(0).importance; // higher importance has lower number (?) if (importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) URLPlayerService.startActionBroadcastServiceData(PlayerActivity.this); }
I have used handler as a workaround and it works pretty good but not 100%:
// hack for https://issuetracker.google.com/issues/113122354 handler.postDelayed(() -> URLPlayerService.startService(PlayerActivity.this),200);
UPDATE: This is working for us in Prod, but it's not 100%. I have received one crash report over the past month and a half when there would have been well over a hundred otherwise. Until this is properly fixed, this seems like our best option for now. Maybe if I raised the time beyond 300 that one crash would never have happened?
We're testing this out right now which so far seems to be working. Will update as we see more results
class ResumingServiceManager(val lifecycle: Lifecycle) : LifecycleObserver { init { lifecycle.addObserver(this) } val disposable: CompositeDisposable = CompositeDisposable() fun startService(context: Context, intent: Intent) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { context.startService(intent) } else { Single.just(true) .delaySubscription(300, TimeUnit.MILLISECONDS) .subscribeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribeBy( onSuccess = { context.startService(intent) } ).addTo(disposable) } } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun stopped() { disposable.clear() } @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun destroy() { lifecycle.removeObserver(this) } }
In onCreate()
initialize it and then anytime you want to start a service in onResume just call resumingServiceManager.startService(this, intent)
It's lifecycle aware so it will clear the disposable if it pauses cancelling the onSuccess from triggering when it might be on the way to the background with an immediate open/close.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With