Skip to content

ForegroundServiceStartNotAllowedException not caught when Player uses non-default ApplicationLooper #2499

@rugged-bl

Description

@rugged-bl

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.

  1. Create a Player with non-default Player.getApplicplicationLooper().
  2. (optional) Override MediaSesssionService.onUpdateNotification with startInForegroundRequired == true (which seems legal according to the documentation provided and library API).
  3. MediaSesssionService.onUpdateNotificationInternal is the only place in stack that catches the ForegroundServiceStartNotAllowedException exception. Documentation says "Triggers notification update and handles {@code ForegroundServiceStartNotAllowedException}".
  4. onUpdateNotificationInternal directly calls onUpdateNotification, onUpdateNotification directly calls getMediaNotificationManager().updateNotification. Calls happen on main thread according to documentation.
  5. In MediaNotificationManager.updateNotification there is a call to Util.postOrRun with session.getPlayer().getApplicationLooper().
  6. Lambda that creates (createNotification) and shows (updateNotificationInternal) the notification is posted to Player's Looper (which is not main thread's Looper), therefore the catch expression 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

Metadata

Metadata

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions