Closed
Description
Media3 Version
1.0.0-beta03
Devices that reproduce the issue
Various devices running android 12 and android 13
Devices that do not reproduce the issue
No response
Reproducible in the demo app?
Not tested
Reproduction steps
Wasn't able to reproduce it myself but I'm still reporting this because it was mentioned in #111 that we should report it if it happens on Android 13. According to crashlytics this happens 100% in background. By the logs I see various scenarios how this happens but most common one is when player is auto transitioning to next item.
Some additional info that might help indicate the problem:
- We are releasing
MediaController
when user goes to background - On media item transition we are saving current item to DB, if it was listened before we are seeking to it's last listened position and adjusting
playWhenReady
if user has turned off/on autoplay. (But doubt this is causing any issues since crashes happen not only when item is transitioning) onTaskRemoved
we are doingstopSelf
ifplayer.playWhenReady != true
- We do not override
onUpdateNotification
, but we are setting a customMediaNotification.Provider
I can provide any additional info or logs if needed
Expected result
Not getting ForegroundServiceStartNotAllowedException
and successfully continuing playback in background.
Actual result
Fatal Exception: android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false: service com.podimo/.app.core.media.MediaService
at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:54)
at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:50)
at android.os.Parcel.readParcelable(Parcel.java:3345)
at android.os.Parcel.createExceptionOrNull(Parcel.java:2432)
at android.os.Parcel.createException(Parcel.java:2421)
at android.os.Parcel.readException(Parcel.java:2404)
at android.os.Parcel.readException(Parcel.java:2346)
at android.app.IActivityManager$Stub$Proxy.startService(IActivityManager.java:6968)
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1927)
at android.app.ContextImpl.startForegroundService(ContextImpl.java:1893)
at android.content.ContextWrapper.startForegroundService(ContextWrapper.java:798)
at com.podimo.app.core.media.MediaService.startForegroundService(MediaService.kt:153)
at androidx.core.content.ContextCompat$Api26Impl.startForegroundService(ContextCompat.java:931)
at androidx.core.content.ContextCompat.startForegroundService(ContextCompat.java:703)
at androidx.media3.session.MediaNotificationManager.updateNotificationInternal(MediaNotificationManager.java:206)
at androidx.media3.session.MediaNotificationManager.updateNotification(MediaNotificationManager.java:182)
at androidx.media3.session.MediaSessionService.onUpdateNotification(MediaSessionService.java:411)
at androidx.media3.session.MediaNotificationManager$MediaControllerListener.onEvents(MediaNotificationManager.java:299)
at androidx.media3.session.MediaControllerImplBase.lambda$new$0(MediaControllerImplBase.java:151)
at androidx.media3.session.MediaControllerImplBase$$InternalSyntheticLambda$3$10aed4c532fdc841d63f0af013a047ffd34a0b4b9b1d6da420408b3dbfb435a8$0.invoke(MediaControllerImplBase.java:1)
at androidx.media3.common.util.ListenerSet$ListenerHolder.iterationFinished(ListenerSet.java:295)
at androidx.media3.common.util.ListenerSet.handleMessage(ListenerSet.java:246)
at androidx.media3.common.util.ListenerSet$$InternalSyntheticLambda$1$0a1dffe138e30e7ad8eb5a169bfb4852f73945d310b0f0a49ed6bc74e8c308ab$0.handleMessage$bridge(ListenerSet.java:57)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8669)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit
$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
Media
Bug Report
- You will email the zip file produced by
adb bugreport
to dev.exoplayer@gmail.com after filing this issue.
Metadata
Metadata
Assignees
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
marcbaechinger commentedon Jan 24, 2023
Thanks for the report.
The service is put to/removed from foreground when
playWhenReady
changes.I can't think of why that should happen when the player transitions playback from one item to the next. Even when a seek is performed within or across media items,
playWhenReady
is not changed by the player internally.Accordingly, this seems to be a potential source of the problem, but I'm not sure I understand how. As far as I understand, we have the following scenarios:
playWhenReady
is false: In this case we would not see an automatic transition because playback is paused.playWhenReady
is true andautoplay off
: In this case the transition would happen and thenplayWhenReady
is set to false. This would cause the service to be removed from the foreground. This does not result in the reportedForegroundServiceStartNotAllowedException
.playWhenReady
is true andautoplay on
: In this caseplayWhenReady
is not changed and the service remains in the foreground. No change in the state of the service is requested.The only thing I can think of is that 'adjusting playWhenReady' involves switching
playWhenReady
to false and then to true again, which would be like resuming playback but I actually wouldn't expect you doing that.One way to verify what is happening would be that you add an
EventLogger
to the app. This would make visible what happens on the player side. However, this would only help in case we get a bug report from such a device just after the crash has occured. We would then be able to see the logs ofEventLogger
to see whether the crash was following a change in the player state.JaCobbMedia commentedon Jan 25, 2023
Thank you for the response @marcbaechinger . I'll investigate more our autoplay logic, but it's pretty basic oneliner -
player?.playWhenReady = player?.playWhenReady == true && autoplay
. Also got some logs from latest release and noticed few scenarios:STATE_IDLE
and right back toSTATE_READY
ERROR_CODE_DECODER_INIT_FAILED
which caused same state change as previously described. I will look into it more, but ifPlaybackException
is thrown we just callplayer.stop()
and send some events to UI, we don't really retry restarting playback without user interaction.I added
EventLogger
to new app version, so I should get more info when users crash on that version. Will update this issue more thenmarcbaechinger commentedon Jan 25, 2023
Yeah, agreed the
playWhenReady
thing should be trivial.But good call regarding the playback error! I haven't taken this case into account. We (the Media3 team) need to think about this case well. Auto re-starting in the background wouldn't work like you say. This would remove the service from and put it back to the foreground. Thanks for bringing this up!
Having the logs from
EventLogger
would give as some more insight in any case!JaCobbMedia commentedon Jan 27, 2023
Okay, so I got some logs from latest release.
EventLogger
and then I realised it was happening onCastPlayer
(confirmed that by looking into our events). Then tried reproducing it by myself and it was pretty easy - I just let one item transition to other item while casting and immediately got FgS exception. Then tried it with UAMP project on media3 branch, same happened there :(java.net.SocketTimeoutException
while in background, might be because of their poor internet connection.DataSource
tries couple of times to retry the connection and fails, then 10s later goes to buffering state andisPlaying
changes to false and immediately FgS exception.I'll be looking into more cases, but if you need any full logs from these cases, I can send it via email.
marcbaechinger commentedon Jan 27, 2023
Thanks for the analysis.
We definitely should look into
CastPlayer
and why the state is changing when transitioning. It defo sounds like a bug to me as this should not happen. I'll change the title of this issue accordingly if that's ok with you.googlequicksearchbox - Yeah, as you mention. Known issue on Android 12.
InternalError - This is actually an obvious one when thinking about it. I haven't noticed this yet though, so thanks for reporting. There is not much we can do about it with the current best practice implementation that is to take the service out of the foreground when not playing. The exception, and the resumption of playback after the error causes interrupts the playback and a retry will cause the
ForegroundServiceStartNotAllowedException
. We are internally advocating for a different implementation approach that would possible help in this case as well. So thanks for giving us another argument! On the other hand, I don't think we can possibly do something right now for this case. The only thing an app can do is posting aNotification
to ask the user to start the retry by user intervention. This would then give a way to resume from the foreground.I have updated #111 accordingly and I rename this issue to focus on the
CastPlayer
transitions only. Please shout if you thing that doesn't make sense. :)[-]ForegroundServiceStartNotAllowedException on Android 13 devices[/-][+]`CastPlayer` produces `ForegroundServiceStartNotAllowedException` on media item transition[/+]JaCobbMedia commentedon Jan 27, 2023
Thank you once again.
I just have to mention few things. After receiving an internal error we don't actually try restarting playback by ourselves. We have
DefaultLoadErrorHandlingPolicy
added to ourDefaultMediaSourceFactory
. In the logs I can't see thatPlaybackException
has been thrown yet because then we would have stopped player, so my guess is that crash happened during load error handling process. Could that be the case?And
googlequicksearchbox
case happened on Android 13 actually (Galaxy XCover 5)marcbaechinger commentedon Jan 27, 2023
Thanks for clarification. What is the playback state doing when this happens? Because I'd only expect a fatal error changing the playback state to
IDLE
as a consequence ofstop
being called. I think we need to investigate this a bit more in this case. I think when we retry (as in terms ofLoadErrorHandlingPolicy
) and in the end successfully start loading again we should somehow be able to not getting the service off the foreground, so this should actually work.The case I mentioned regarding retry after a
PlaybackException
is harder to fix I think.That's odd. I'll test this. Thanks for mentioning.
JaCobbMedia commentedon Jan 27, 2023
What I can see from the logs:
STATE_READY
playWhenReady = true
,isPlaying = true
MediaController
internalErrors
each with 8s intervalinternalError
8s passed and state changed toSTATE_BUFFERING
and isPlaying changed tofalse
marcbaechinger commentedon Jan 27, 2023
With the scenario above, the service should not be taken off the foreground as far as I can tell. Being in state
BUFFERING
isn't enough to get off the foreground. The player either needs to be inSTATE_IDLE
orSTATE_ENDED
orplayWhenReady==false
to take the service off the foreground.We need to investigate this. Many thanks for your detailed report. Much appreciated.
marcbaechinger commentedon Jan 30, 2023
I can confirm that the
CastPlayer
transitions toSTATE_IDLE
when playback transitions automatically from one item in the playlist to the next. Then it immediately goes toSTATE_READY
again.This explains why the service is taken off the foreground and then produces the reported exception. We will look into
CastPlayer
and we will update this issue when we have submitted a change regarding this problem. Thanks for reporting again.8 remaining items