Search code examples
androidandroid-emulatorandroid-serviceandroid-12android-13

Can't replicate ForegroundServiceStartNotAllowedException within emulator


According to Google Play Console Crashes and ANRs, my app is experiencing a lot of ForegroundServiceStartNotAllowedException crashes on Android 12+ devices. This is since Google introduced the restriction that apps in the background cannot start foreground services.

The app is a music player.

I don't have an Android 12+ device, so I set up the emulator, running Android 13, to replicate. However, I cannot replicate this crash and I wondered if this is because I'm using the emulator. Is there a way of setting up the emulator to make sure it occurs?

Example stack trace

Here's an example stack trace reported by Google Play Console:

Exception java.lang.RuntimeException:
  at android.app.ActivityThread.handleServiceArgs (ActivityThread.java:5261)
  at android.app.ActivityThread.-$$Nest$mhandleServiceArgs
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2447)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loopOnce (Looper.java:226)
  at android.os.Looper.loop (Looper.java:313)
  at android.app.ActivityThread.main (ActivityThread.java:8757)
  at java.lang.reflect.Method.invoke
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:571)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1067)
Caused by android.app.ForegroundServiceStartNotAllowedException:
  at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel (ForegroundServiceStartNotAllowedException.java:54)
  at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel (ForegroundServiceStartNotAllowedException.java:50)
  at android.os.Parcel.readParcelableInternal (Parcel.java:4787)
  at android.os.Parcel.readParcelable (Parcel.java:4755)
  at android.os.Parcel.createExceptionOrNull (Parcel.java:3018)
  at android.os.Parcel.createException (Parcel.java:3007)
  at android.os.Parcel.readException (Parcel.java:2990)
  at android.os.Parcel.readException (Parcel.java:2932)
  at android.app.IActivityManager$Stub$Proxy.setServiceForeground (IActivityManager.java:6978)
  at android.app.Service.startForeground (Service.java:743)
  at github.daneren2005.dsub.util.Notifications.startForeground (Notifications.java:462)
  at github.daneren2005.dsub.util.Notifications.shutGoogleUpNotification (Notifications.java:384)
  at github.daneren2005.dsub.service.DownloadService.onStartCommand (DownloadService.java:317)
  at android.app.ActivityThread.handleServiceArgs (ActivityThread.java:5243)

Current replication process

  1. Start music playing in my app.
  2. Click the Home button.
  3. Click CALL DEVICE on the emulator. (At this point the music is paused).
  4. Hang up on the call. (After a short pause, the music starts playing again - this is where I expect the crash).

I know the crash should happen, because I have added logging to my code that starts the foreground service:

...
Log.d(TAG, "Notifications, current state: " + ProcessLifecycleOwner.get().getLifecycle().getCurrentState());
downloadService.startForeground(notificationId, notification);
...

At this point, the lifecycle state is CREATED which I believe means it's in the background. However, the crash doesn't appear to occur and the app keeps running.

Things I've tried

  • Make sure battery optimisation is enabled for the app - tried "Optimized" and "Restricted".
  • Changed the battery settings in the emulator.
  • Enabled ActivityManager logging restricted foreground starts. With this I have seen ActivityManager: Service.startForeground() not allowed due to bg restriction: service ga.asti.android/github.daneren2005.dsub.service.DownloadService in logcat. Is this the same issue occurring? Why does it not cause a crash?

There are a number of guides about around fixing this, but I want to know how to replicate it first so I know my fixes are working.


Solution

  • I'm going to leave this as an answer for now, unless someone can provide a way to produce a more visual crash in the emulator.

    The only indication I've found that my app requests foreground services when running in the background is to configure ActivityManager to alert such cases and then follow and grep logcat to report them.

    1. Enable ActivityManager logging restricted foreground starts.

      adb shell device_config put activity_manager \
         default_fgs_starts_restriction_notification_enabled true
      
    2. Put app into background by clicking the Home key

    3. Start watching logcat:

      adb logcat -T 1 | grep ActivityManager
      
    4. Cause the behaviour which might run startForeground (in my app, a music player: while music is playing, make a call to the phone in the emulator, receive the call, then hang up).

    5. Observe logcat output for something like:

      Service.startForeground() not allowed due to bg restriction: service my.app.packagename/my.app.XyzService