media
media copied to clipboard
java.lang.SecurityException - Session rejected the connection request.
Media3 Version
Media3 1.0.1
Devices that reproduce the issue
Devices that do not reproduce the issue
No response
Reproducible in the demo app?
Not tested
Reproduction steps
- Rollout Voice 7.0.12: https://github.com/PaulWoitaschek/Voice/blob/7.0.12/playback/src/main/kotlin/voice/playback/session/PlaybackService.kt
- See crashes in Crashlytics
Expected result
It doesn't crash
Actual result
I'm seeing a ton of crashes with a stack trace that doesn't relate to application code. I assume, this is related to broken device implementations which I can not catch as they are in the library internal space.
Additionally with media3 I see a lot of user reports where people state that the playback doesn't start. I assume that this might be related to this issue.
Fatal Exception: java.lang.SecurityException: Session rejected the connection request.
at androidx.media3.session.MediaControllerHolder.maybeSetException(MediaControllerHolder.java:62)
at androidx.media3.session.MediaControllerHolder.onRejected(MediaControllerHolder.java:62)
at androidx.media3.session.MediaController.release(MediaController.java:62)
at androidx.media3.common.util.Util.postOrRun(Util.java:25)
at androidx.media3.session.MediaController.runOnApplicationLooper(MediaController.java:2)
at androidx.media3.session.MediaControllerStub.lambda$onDisconnected$1(MediaControllerStub.java:3)
at androidx.media3.session.MediaControllerStub.lambda$dispatchControllerTaskOnHandler$11(MediaControllerStub.java:521)
at androidx.media3.common.util.Util.postOrRun(Util.java:25)
at androidx.media3.session.MediaControllerStub.dispatchControllerTaskOnHandler(MediaControllerStub.java:29)
at androidx.media3.session.MediaControllerStub.onDisconnected(MediaControllerStub.java:6)
at androidx.media3.session.MediaSessionService$MediaSessionServiceStub.lambda$connect$0(MediaSessionService.java:82)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7682)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
Media
no media
Bug Report
- [ ] You will email the zip file produced by
adb bugreport
to [email protected] after filing this issue.
This is the sort of exception that the controller also gets if the media session does not start properly (e.g. crash in init
or onCreate
).
Such errors in MediaLibraryService
/MediaSessionService
don't show in crash logs by default because they're caught and reported as warnings in MSSImpl
.
any solution for this?
Thanks for asking, @iaarav We would need some more details from you.
This was reported for 1.0.1. Can you repro this with the actual 1.2.0 version? If so can you please describe your repro steps and do a bug report just after this happens and then upload here?
If you're unable to share bug reports or test content publicly, please send them to [email protected] using a subject in the format "Issue #423". Please also update this issue to indicate you’ve done this.
@marcbaechinger I can reproduce with 1.2.0
Caused by java.lang.SecurityException: Session rejected the connection request.
at androidx.media3.session.MediaControllerHolder.maybeSetException(MediaControllerHolder.java:67)
at androidx.media3.session.MediaControllerHolder.onRejected(MediaControllerHolder.java:57)
at androidx.media3.session.MediaController.release(MediaController.java:530)
at androidx.media3.session.MediaControllerImplBase$$ExternalSyntheticLambda41.run(:2)
at androidx.media3.common.util.Util.postOrRun(Util.java:752)
at androidx.media3.session.MediaController.runOnApplicationLooper(MediaController.java:1926)
at androidx.media3.session.MediaControllerStub.lambda$onDisconnected$1(MediaControllerStub.java:96)
at androidx.media3.session.MediaControllerStub$$ExternalSyntheticLambda4.run()
at androidx.media3.session.MediaControllerStub.lambda$dispatchControllerTaskOnHandler$12(MediaControllerStub.java:310)
at androidx.media3.session.MediaControllerStub$$ExternalSyntheticLambda13.run(:4)
at androidx.media3.common.util.Util.postOrRun(Util.java:752)
at androidx.media3.session.MediaControllerStub.dispatchControllerTaskOnHandler(MediaControllerStub.java:302)
at androidx.media3.session.MediaControllerStub.onDisconnected(MediaControllerStub.java:94)
at androidx.media3.session.MediaSessionService$MediaSessionServiceStub.release(MediaSessionService.java:747)
at androidx.media3.session.MediaSessionService.onDestroy(MediaSessionService.java:485)
at com.wowbody.ui.player.PlaybackService.onDestroy(PlaybackService.kt:77)
at android.app.ActivityThread.handleStopService(ActivityThread.java:5273)
at android.app.ActivityThread.-$$Nest$mhandleStopService()
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2452)
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:8762)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:604)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
Hey @PaulWoitaschek. We need more information to resolve this issue but there hasn't been an update in 14 weekdays. I'm marking the issue as stale and if there are no new updates in the next 7 days I will close it automatically.
If you have more information that will help us get to the bottom of this, just add a comment!
What kind of information are you missing?
Sorry, the bot doesn't recognize the reply from someone else (who is not the issue poster) and was still in the "need more info" stage. Your last question today actually fixed that ;)
Looking at the stack trace again, I wonder if this is an issue in you app where the ListenableFuture
returned from MediaController.Builder.buildAsync()
is not checked for failures before calling get()
. The stack trace shows expected behavior that the session rejected the request (e.g. because it was already released, crashed or similar), but this just sets the ListenableFuture
to an error state. I assume the real stack trace actually has more lines above the snippets shown here that highlight where it is actually thrown from?
class Base @Inject constructor(
private val controllerFuture: ListenableFuture<MediaController>,
) : MediaControllerWrapper {
private val controller: MediaController?
get() = if (controllerFuture.isDone) controllerFuture.get() else null
override fun getCurrentMediaItemIndex(function: (Int) -> Unit) {
if(controller!=null) function.invoke(controller?.currentMediaItemIndex?:-1)
else controllerFuture.addListener({},{
function.invoke(controller?.currentMediaItemIndex?:-1)
})
}
i dont understand why it is crashing on some devices
Caused by java.util.concurrent.ExecutionException: java.lang.SecurityException: Session rejected the connection request.
at com.google.common.util.concurrent.AbstractFuture.g(AbstractFuture.java:21)
at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:21)
at com.kamancho.melisma.trending.presentation.MediaControllerWrapper$Base.getController(MediaControllerWrapper.kt:1)
at com.kamancho.melisma.trending.presentation.MediaControllerWrapper$Base.getCurrentMediaItemIndex$lambda$19(MediaControllerWrapper.kt:22)
at com.google.common.util.concurrent.AbstractFuture.executeListener(AbstractFuture.java:1)
at com.google.common.util.concurrent.AbstractFuture.complete(AbstractFuture.java:91)
at com.google.common.util.concurrent.AbstractFuture.setException(AbstractFuture.java:19)
at androidx.media3.session.MediaControllerHolder.maybeSetException(MediaControllerHolder.java:63)
at androidx.media3.session.MediaControllerHolder.onRejected(MediaControllerHolder.java:63)
at androidx.media3.session.MediaController.release(MediaController.java:63)
at androidx.media3.common.util.Util.postOrRun(Util.java:1)
at androidx.media3.session.MediaController.runOnApplicationLooper(MediaController.java:1)
at androidx.media3.session.MediaControllerStub.lambda$onDisconnected$1(MediaControllerStub.java:20)
at androidx.media3.session.MediaControllerStub.lambda$dispatchControllerTaskOnHandler$12(MediaControllerStub.java:450)
at androidx.media3.common.util.Util.postOrRun(Util.java:1)
at androidx.media3.session.MediaControllerStub.dispatchControllerTaskOnHandler(MediaControllerStub.java:30)
at androidx.media3.session.MediaControllerStub.onDisconnected(MediaControllerStub.java:1)
at androidx.media3.session.MediaSessionService$MediaSessionServiceStub.lambda$connect$0(MediaSessionService.java:99)
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:8010)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:566)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:957)
@Singleton
@Provides
fun provideControllerFuture(context: Context): ListenableFuture<MediaController> {
return MediaController.Builder(
context,
SessionToken(context, ComponentName(context, PlayerService::class.java))
).buildAsync()
}
@Provides
@Singleton
fun provideMediaPlayer(
context: Context,
listener: ControllerListener,
): ExoPlayer {
return ExoPlayer.Builder(context)
.setAudioAttributes(
AudioAttributes.Builder()
.setUsage(C.USAGE_MEDIA)
.setContentType(C.AUDIO_CONTENT_TYPE_MUSIC)
.build()
,true)
.setHandleAudioBecomingNoisy(true)
.build().also {
it.addListener(listener)
}
}
@Provides
@Singleton
fun providePendingIntent(context: Context): PendingIntent {
return TaskStackBuilder.create(context).run {
addNextIntent(Intent(context, MainActivity::class.java))
getPendingIntent(0, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
}
}
@Provides
@Singleton
fun provideMediaSession(
context: Context,
player: ExoPlayer,
pendingIntent: PendingIntent,
callBack: MediaSessionCallBack,
): MediaSession {
return MediaSession.Builder(context, player)
.setSessionActivity(pendingIntent)
.setCallback(callBack)
.build()
}
class MediaSessionCallBack @Inject constructor(
private val temporaryTracksCache: TemporaryTracksCache,
private val playbackResumptionRepository: PlaybackResumptionRepository,
private val dispatchersList: DispatchersList,
private val playerCommunication: PlayerCommunication,
private val playingTrackIdCommunication: PlayingTrackIdCommunication,
private val trackPlaybackPositionCommunication: TrackPlaybackPositionCommunication,
private val controller: MediaControllerWrapper,
) : MediaSession.Callback {
private var job: Job? = null
private val scope = CoroutineScope(Dispatchers.IO)
private val lastQueue = mutableListOf<MediaItem>()
init {
controller.getCurrentMediaItemIndex { currentMediaItemIndex ->
Log.d("tag", ": currentMediaItemIndex $currentMediaItemIndex ${controller.mediaItemCount}")
if (currentMediaItemIndex == -1 || currentMediaItemIndex==0 && controller.mediaItemCount==0) {
job = scope.launch(dispatchersList.io()) {
val tracks = playbackResumptionRepository.fetchLastQueue()
val position = playbackResumptionRepository.fetchLastPosition()
val pos = if (position < 0) 0
else if (position > tracks.lastIndex) tracks.lastIndex
else position
if (tracks.isEmpty()) return@launch
val newQueue = tracks.map {
MediaItem.Builder()
.setMediaId(it.mediaId)
.build()
}
withContext(dispatchersList.ui()) {
playerCommunication.map(
PlayerCommunicationState.InflateWithoutPlaying(
newQueue,
tracks,
pos
)
)
}
lastQueue.clear()
lastQueue.addAll(tracks)
}
}
}
}
override fun onSetMediaItems(
mediaSession: MediaSession,
controller: MediaSession.ControllerInfo,
mediaItems: MutableList<MediaItem>,
startIndex: Int,
startPositionMs: Long,
): ListenableFuture<MediaSession.MediaItemsWithStartPosition> {
val tracks =
if (lastQueue.isEmpty()) temporaryTracksCache.readCurrentPageTracks()
else lastQueue
return Futures.immediateFuture(
MediaSession.MediaItemsWithStartPosition(
tracks,
startIndex,
startPositionMs
)
).apply { lastQueue.clear() }
}
override fun onPlaybackResumption(
mediaSession: MediaSession,
controller: MediaSession.ControllerInfo,
): ListenableFuture<MediaSession.MediaItemsWithStartPosition> {
job?.cancel()
val tracks = scope.async(dispatchersList.io()) {
playbackResumptionRepository.fetchLastQueue()
}.asCompletableFuture().get()
lastQueue.addAll(tracks)
val position = scope.async(dispatchersList.io()) {
playbackResumptionRepository.fetchLastPosition()
}.asCompletableFuture().get()
return if (tracks.isNotEmpty()) {
val pos = if (position < 0) 0
else if (position > tracks.lastIndex) tracks.lastIndex
else position
playerCommunication.map(PlayerCommunicationState.PlaybackResumption(tracks, pos))
playingTrackIdCommunication.map(tracks[pos].mediaId)
trackPlaybackPositionCommunication.clearPosition()
Futures.immediateFuture(
MediaSession.MediaItemsWithStartPosition(
tracks,
pos,
0
)
).apply { lastQueue.clear() }
} else super.onPlaybackResumption(mediaSession, controller)
}
}
i am dooing that because i want to load last queue when app launches, maybe you have another way of that?
It's difficult to help you here. It's for instance unclear when this problem happens in the lifecycle of the app, the session or the controller. The dependency injection code for instance does hide a bit how the app is bootstrapped.
if (controllerFuture.isDone) controllerFuture.get() else null
From the JavaDoc of Future.isDone
: Returns true if this task completed. Completion may be due to normal termination, an exception, or cancellation -- in all of these cases, this method will return true.
If you call get()
on a Future
that isDone
but did not successfully complete, you get an exception. See JavaDoc of get()
.
I think this can happen if there is a problem on the session side, that doesn't allow a controller to connect. Another reason can be that the controller is released before the session notified the connection back to the controller.
I think I would search for another exception happening somewhere that makes the connection fail. A first step would be to search the logs for other problems, for instance on the session side. And catch the exception thrown by controllerFuture.get()
and see if there for instance in an executionException.cause
that gives you more information about why the execution of the future failed.
AndroidSessionCallback.kt return if (isThirdPartyController(context, controller) && !thirdPartyApiEnabled) {
fun isThirdPartyController(context: Context, controller: ControllerInfo) =
controller.packageName !in
listOf(context.packageName, context.getString(R.string.config_mediaControlsPackage),context.getString(R.string.config_google_wts))
}
I am seeing this same issue.
I get random
java.lang.SecurityException: Session rejected the connection request.
when I start the app.
Then when I reopen the app, it works fine.
The stack trace, like above is library code.
java.lang.SecurityException: Session rejected the connection request.
at androidx.media3.session.MediaControllerHolder.maybeSetException(MediaControllerHolder.java:67)
at androidx.media3.session.MediaControllerHolder.onRejected(MediaControllerHolder.java:57)
at androidx.media3.session.MediaController.release(MediaController.java:530)
at androidx.media3.session.MediaControllerImplBase$$ExternalSyntheticLambda40.run(D8$$SyntheticClass:0)
at androidx.media3.common.util.Util.postOrRun(Util.java:752)
at androidx.media3.session.MediaController.runOnApplicationLooper(MediaController.java:1926)
at androidx.media3.session.MediaControllerStub.lambda$onDisconnected$1(MediaControllerStub.java:96)
at androidx.media3.session.MediaControllerStub$$ExternalSyntheticLambda6.run(D8$$SyntheticClass:0)
at androidx.media3.session.MediaControllerStub.lambda$dispatchControllerTaskOnHandler$12(MediaControllerStub.java:310)
at androidx.media3.session.MediaControllerStub$$ExternalSyntheticLambda4.run(D8$$SyntheticClass:0)
at androidx.media3.common.util.Util.postOrRun(Util.java:752)
at androidx.media3.session.MediaControllerStub.dispatchControllerTaskOnHandler(MediaControllerStub.java:302)
at androidx.media3.session.MediaControllerStub.onDisconnected(MediaControllerStub.java:94)
at androidx.media3.session.MediaSessionService$MediaSessionServiceStub.lambda$connect$0$androidx-media3-session-MediaSessionService$MediaSessionServiceStub(MediaSessionService.java:729)
at androidx.media3.session.MediaSessionService$MediaSessionServiceStub$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)
at android.os.Handler.handleCallback(Handler.java:959)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loopOnce(Looper.java:232)
at android.os.Looper.loop(Looper.java:317)
at android.app.ActivityThread.main(ActivityThread.java:8501)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:878)
Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@ff9c8f, Dispatchers.Default]
MediaLibrarySession.Builder.Build() is only called in the Service onCreate method, and the releasing in the onDestroy method, so there should never be a duplicate.
Weirdly, if I reopen the app after the exception is thrown, sometimes the app runs fine and the exception is not thrown.
In my case, it ended up being that this code works if inside onCreate of the Service.
// Set up the player synchronously
...
mediaSession = MediaLibrarySession.Builder(
this@ServiceMediaLibrary,
player,
callback
).build()
but this code does not work intermittently
applicationScope.launch(Dispatchers.IO) {
// Used to initialize player
val respectAudioFocus = settingsRepository.respectAudioFocus.first()
applicationScope.launch(Dispatchers.Main.immediate) {
// Set up the player synchronously
...
mediaSession = MediaLibrarySession.Builder(
this@ServiceMediaLibrary,
player,
callback
).build()
}
I see this in regards to a Tile Service on 1.3.1:
Fatal Exception: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:558)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1149)
Caused by java.lang.reflect.InvocationTargetException:
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1149)
Caused by java.util.concurrent.ExecutionException: java.lang.SecurityException: Session rejected the connection request.
at com.google.common.util.concurrent.AbstractFuture.getDoneValue(AbstractFuture.java:592)
at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:551)
at com.example.myapp.core.data.repository.MyPlayerRepository.controllerFuture$lambda$1$lambda$0(MyPlayerRepository.java:33)
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:7935)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1149)
Caused by java.lang.SecurityException: Session rejected the connection request.
at androidx.media3.session.MediaControllerHolder.maybeSetException(MediaControllerHolder.java:67)
at androidx.media3.session.MediaControllerHolder.onRejected(MediaControllerHolder.java:57)
at androidx.media3.session.MediaController.release(MediaController.java:547)
at androidx.media3.common.util.Util.postOrRun(Util.java:824)
at androidx.media3.session.MediaController.runOnApplicationLooper(MediaController.java:1957)
at androidx.media3.session.MediaControllerImplBase.connect(MediaControllerImplBase.java:204)
at androidx.media3.session.MediaController.<init>(MediaController.java:493)
at androidx.media3.session.MediaController$Builder.buildAsync(MediaController.java:335)
at com.example.myapp.core.data.repository.MyPlayerRepository.<init>(MyPlayerRepository.java:30)
at com.example.myapp.MyTileService.onCreate(MyTileService.kt:39)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:4522)
at android.app.ActivityThread.-$$Nest$mhandleCreateService()
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2169)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7935)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1149)
Code in question:
class MyTileService : TileService() {
private lateinit var player: MyPlayerRepository
@Override
override fun onCreate() {
super.onCreate()
player = MyPlayerRepository(application) // CRASH is on this line.
}
// ...
}
class MyPlayerRepository(app: Application) {
private val sessionToken = SessionToken(app, ComponentName(app, MyPlayerService::class.java))
private val controllerFuture = MediaController.Builder(app, sessionToken).buildAsync() // CRASH references this line
.apply {
addListener({
val controller = get() // CRASH is on this line
controller.addListener(object : Player.Listener {
override fun onPlayerErrorChanged(e: PlaybackException?) {
error = e
}
})
}, ContextCompat.getMainExecutor(app))
}
// ...
}
Similar crash happened.
In my case I observe a media session updates with MediaSessionManager.OnActiveSessionsChangedListener
and pick the first controller then create a androidx.media3.session.MediaController
from it.
This could happen when OnActiveSessionsChangedListener
tells me that multiple media controllers are available and keep force-stopping the media player apps in a short period.
As this is happening inside the library, it's impossible to catch this other than UnhandledExceptionHandler
.
The same issue could potentially happen when we call MediaController#release
without checking if Player.COMMAND_RELEASE
is available or not (as long as I can see the doc says we should check this before calling release
).
- Media library version: 1.3.1
- Android version: Android 15 beta
FATAL EXCEPTION: main
Process: com.example.music_controller, PID: 22169
java.lang.SecurityException: Session rejected the connection request.
at androidx.media3.session.MediaControllerHolder.maybeSetException(MediaControllerHolder.java:67)
at androidx.media3.session.MediaControllerHolder.onRejected(MediaControllerHolder.java:57)
at androidx.media3.session.MediaController.release(MediaController.java:547)
at androidx.media3.session.MediaControllerImplLegacy$ControllerCompatCallback.onSessionDestroyed(MediaControllerImplLegacy.java:1810)
at android.support.v4.media.session.MediaControllerCompat$Callback$MediaControllerCallbackApi21.onSessionDestroyed(MediaControllerCompat.java:842)
at android.media.session.MediaController$MessageHandler.handleMessage(MediaController.java:1230)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loopOnce(Looper.java:232)
at android.os.Looper.loop(Looper.java:317)
at android.app.ActivityThread.main(ActivityThread.java:8699)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:886)
Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@a4d77f6, Dispatchers.Main]