Repository navigation
ForegroundServiceStartNotAllowedException not caught when Player uses non-default ApplicationLooper #2499
Description
Version
Media3 main branch
More version details
Bug exists at least since version 1.4.1.
Devices that reproduce the issue
Any Android 12+
Devices that do not reproduce the issue
No response
Reproducible in the demo app?
Not tested
Reproduction steps
When a Player is configured with a non-default ApplicationLooper, the ForegroundServiceStartNotAllowedException handling in MediaSessionService fails because the exception is thrown on a different thread than where the try-catch block executes.
- Create a
Playerwith non-default Player.getApplicplicationLooper(). - (optional) Override MediaSesssionService.onUpdateNotification with
startInForegroundRequired == true(which seems legal according to the documentation provided and library API). - MediaSesssionService.onUpdateNotificationInternal is the only place in stack that catches the ForegroundServiceStartNotAllowedException exception. Documentation says "
Triggers notification update and handles {@code ForegroundServiceStartNotAllowedException}". onUpdateNotificationInternaldirectly callsonUpdateNotification,onUpdateNotificationdirectly callsgetMediaNotificationManager().updateNotification. Calls happen on main thread according to documentation.- In MediaNotificationManager.updateNotification there is a call to Util.postOrRun with
session.getPlayer().getApplicationLooper(). - Lambda that creates (
createNotification) and shows (updateNotificationInternal) the notification is posted toPlayer'sLooper(which is not main thread'sLooper), therefore thecatchexpression is no more in the needed stack and catches nothing.
Expected result
The ForegroundServiceStartNotAllowedException should be caught and passed to MediaSessionService.Listener.onForegroundServiceStartNotAllowedException() regardless of which looper the Player uses.
If main thread's Looper is used the exception is caught because both Util.postOrRun and mainExecutor (which is just a proxy to Util.postOrRun) are going through immediate OrRun branch and therefore are in the same call stack with catch.
Actual result
Fatal exception:
Exception 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:4828)
at android.os.Parcel.readParcelable (Parcel.java:4790)
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.startService (IActivityManager.java:5426)
at android.app.ContextImpl.startServiceCommon (ContextImpl.java:1899)
at android.app.ContextImpl.startForegroundService (ContextImpl.java:1875)
at android.content.ContextWrapper.startForegroundService (ContextWrapper.java:827)
at androidx.core.content.ContextCompat$Api26Impl.startForegroundService (ContextCompat.java:1128)
at androidx.core.content.ContextCompat.startForegroundService (ContextCompat.java:700)
at androidx.media3.session.MediaNotificationManager.startForeground (MediaNotificationManager.java:366)
at androidx.media3.session.MediaNotificationManager.updateNotificationInternal (MediaNotificationManager.java:223)
at androidx.media3.session.MediaNotificationManager.lambda$updateNotification$6 (MediaNotificationManager.java:179)
at android.os.Handler.handleCallback (Handler.java:942)
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:7962)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:550)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:952)
Media
Any media with media notification.
Bug Report
- You will email the zip file produced by
adb bugreportto android-media-github@google.com after filing this issue.
Activity
marcbaechinger commentedon Jun 4, 2025
Thanks for your report and the explanation. I look into a fix for that.
Out of interest: By what action was this
ForegroundServiceStartNotAllowedExceptiontriggered in your case. Is this something produced by the Media3 library, or is this caused because you start the service yourself in some ways not anticipated by the library?I'm asking because I'm working on a test fixture to later test the fix that I apply. When using the common ways to start the service, I'm not able to get the stack trace where you get it. I have an exception earlier and not inside
MediaNotificationManager.I have some guesses how this could be produced, but it would be great to hear what you are trying to achieve when you have noticed this problem.
Basically, I'd guess this is caused by an
Intentbeing sent to the service. An anticipatedIntentshould have an exemption from the system to not trigger this exception, so I wonder how comes you see this stack trace.Sorry for being curious. This is not related to providing a fix for that or not. I think your reasoning is correct and we should fix that in any case. Knowing what developers do, allows us to understand use cases that we haven't seen yet.
marcbaechinger commentedon Jun 4, 2025
I'm failing to repro with this issue I'm afraid.
Can you please give me some repro steps how I can produce the exception above. When I try this I never get into the service itself. Instead the exception is thrown earlier like in the component that tries to start the service from the background.
I crafted a broadcast receiver to send and
Intent, I get the exception but that's happening earlier. The intentnever goes through to where it throws in you case.
If you provide some repro steps, that would speed up the process on our end.
rugged-bl commentedon Jun 5, 2025
@marcbaechinger Thank you for looking into this issue and for your detailed questions!
Regarding real-world reproduction: unfortunately, I don't have a clear understanding of the exact real-world scenario that triggers this issue yet. Our users have somehow encountered this crash in production 🙂 , but the circumstances aren't fully clear to us at this point. To identify the specific use case, we'll need to roll out a new release with additional diagnostic logging, which will take some time.
My hypothesis: I suspect this occurs when the service gets demoted from foreground status (either through system logic or Media3's internal logic) but remains running, and then a notification update is triggered while the app is in the background.
I can reproduce the issue only in synthetic conditions:
delay(10000); player.seekToNextMediaItem().You raise a good point about how we start our service. We do use a somewhat unconventional approach, though I believe it's internally pretty similar to a MediaController connection/binding. We chose this method primarily just to avoid having an extra controller instance connected. There's quite a bit of reasoning behind our media integration architecture... but this particular approach seems to be working for us (or not). Here's how we handle it:
I really appreciate you taking the time to investigate this. If you need any additional details or have more questions, please don't hesitate to ask. And of course, if I gather more concrete information about the real-world triggers, I'll share it with you.
Sabelnikova commentedon Feb 24, 2026
@marcbaechinger Do you plan to address this issue? I’ve put together a reproducer for the crash: in the demo-session app, start playback, send the activity to the background, pause playback, then press the Shuffle button (it’s not actually shuffling in my setup).
I realize this isn’t a typical user flow, but we’re seeing the same crash in our app with a Spotify Connect–style feature—e.g., when a user starts playback from another device after foregroundServiceTimeoutMs.
Propagate ForegroundServiceStartNotAllowedException across threads
marcbaechinger commentedon Mar 30, 2026
We've pushed the commit above to the 'main' branch. This propagates the exception across the thread boundaries in case an app is using a different thread than the main thread as the application thread.
In practice this means that a
ForegroundServiceStartNotAllowedExceptionnow triggersListener.onForegroundServiceStartNotAllowedException.I'm closing this issue. Please let us know if this isn't sufficient by filing a new issue.
Propagate ForegroundServiceStartNotAllowedException across threads