Android 9.0: Not allowed to start service: app is in background.. after onResume()

Tim Malseed picture Tim Malseed · Aug 25, 2018 · Viewed 28.8k times · Source

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.

Answer

Mateusz Kaflowski picture Mateusz Kaflowski · Mar 27, 2019

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);