Skip to content

MediaLibraryService throws ForegroundServiceDidNotStartInTimeException #167

Closed

Description

@ItsBenyaamin

Media3 Version

1.0.0-beta02

Devices that reproduce the issue

Firebase crashlytics report these devices:

  • Galaxy Note20 running Android 12
  • Galaxy S21 FE 5G running Android 12
  • Xiaomi 11T Pro running Android 12
  • Redmi Note 9 Pro running Android 11

Devices that do not reproduce the issue

No response

Reproducible in the demo app?

Not tested

Reproduction steps

It's happened on some devices. I think It has related to MediaController not properly handling the service.

Expected result

not crash?

Actual result

Fatal Exception: android.app.ForegroundServiceDidNotStartInTimeException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{ac0645b u0 player.PlaybackService}
       at android.app.ActivityThread.throwRemoteServiceException(ActivityThread.java:2147)
       at android.app.ActivityThread.access$2900(ActivityThread.java:310)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2376)
       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: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

Activity

  1. vanniktech commented on Sep 19, 2022

    @vanniktech

    I've also seen this in Crashlytics, although I'm myself have been unable to reproduce this.

  2. marcbaechinger commented on Sep 20, 2022

    @marcbaechinger
    Contributor

    Thanks for reporting!

    Do you have some more context what command has been sent to the service when this happens?

    I'm asking because I probably have found an execution path that could cause this problem, but I can not repro this and hence I can not verify a fix.

    I think the reason for this could be that the pending intent of 'pause' is starting a foreground service and then does not call Service.startForeground().

    I will provide a fix for the case described above. However, I can't be really sure whether this is the root case of the exception above because I can't repro now. I think it may be a corner case that sends the pause command when the service actually has been destroyed, but that's a wild guess.

    You have already reported that this happens on Android 12. Can you let me know the targetSkdVersion that you use for the app that is producing the stack trace above?

  3. vanniktech commented on Sep 20, 2022

    @vanniktech

    So in my case, I have both target & compile SDK set to 33.

    Screen Shot 2022-09-20 at 21 10 05

    Full stacktrace:

    Fatal Exception: android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{ad7d394 u0 com.vanniktech.rssreader/com.vanniktech.feature.rssreader.itemdownload.RssReaderItemDownloadBackgroundService}
           at android.app.ActivityThread.generateForegroundServiceDidNotStartInTimeException(ActivityThread.java:2006)
           at android.app.ActivityThread.throwRemoteServiceException(ActivityThread.java:1977)
           at android.app.ActivityThread.-$$Nest$mthrowRemoteServiceException()
           at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2242)
           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:7898)
           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:936)
    
  4. ItsBenyaamin commented on Sep 21, 2022

    @ItsBenyaamin
    Author

    @marcbaechinger
    My project is an online streaming application that streams songs. So basic commands are play/pause/seek/stop.
    and the targetSkdVersion is 32

    This crash is reported a lot
    And when are we gonna get stable v1? any news?

  5. ItsBenyaamin commented on Sep 23, 2022

    @ItsBenyaamin
    Author

    ***** EDIT *****
    I found the reason. when you play a song and then pause it and close the app the notification remains
    If you click on play, after a few seconds it will crash.
    service is not foreground but notification is not dismissed and the problem is when pressing the play button it will crash


    Hi, I reproduce the crash with media session demo app
    here is the stack trace. I don't know if It's the exact same, but in bottom of crash it contains the ForegroundServiceDidNotStartInTimeException exception.
    It happens in the background playing when pressing play/pause a few times On both the Lock screen and unlocked.
    Also, the crash is insanely reporting in crashlytics for me!

    2022-09-23 11:59:43.721 7087-7087/androidx.media3.demo.session E/AbstractFuture: RuntimeException while executing runnable androidx.media3.demo.session.MainActivity$$ExternalSyntheticLambda2@51ce0f3 with executor MoreExecutors.directExecutor()
        java.util.concurrent.CancellationException: Task was cancelled.
            at com.google.common.util.concurrent.AbstractFuture.cancellationExceptionWithCause(AbstractFuture.java:1496)
            at com.google.common.util.concurrent.AbstractFuture.getDoneValue(AbstractFuture.java:586)
            at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:547)
            at androidx.media3.demo.session.MainActivity.getBrowser(MainActivity.kt:42)
            at androidx.media3.demo.session.MainActivity.pushRoot(MainActivity.kt:160)
            at androidx.media3.demo.session.MainActivity.initializeBrowser$lambda-3(MainActivity.kt:108)
            at androidx.media3.demo.session.MainActivity.$r8$lambda$zcr2almQqmFxiCBoT1PwekCQLVg(Unknown Source:0)
            at androidx.media3.demo.session.MainActivity$$ExternalSyntheticLambda2.run(Unknown Source:2)
            at com.google.common.util.concurrent.DirectExecutor.execute(DirectExecutor.java:31)
            at com.google.common.util.concurrent.AbstractFuture.executeListener(AbstractFuture.java:1277)
            at com.google.common.util.concurrent.AbstractFuture.complete(AbstractFuture.java:1038)
            at com.google.common.util.concurrent.AbstractFuture.cancel(AbstractFuture.java:665)
            at androidx.media3.session.MediaController.releaseFuture(MediaController.java:479)
            at androidx.media3.demo.session.MainActivity.releaseBrowser(MainActivity.kt:112)
            at androidx.media3.demo.session.MainActivity.onStop(MainActivity.kt:97)
            at android.app.Instrumentation.callActivityOnStop(Instrumentation.java:1496)
            at android.app.Activity.performStop(Activity.java:8502)
            at android.app.ActivityThread.callActivityOnStop(ActivityThread.java:5298)
            at android.app.ActivityThread.performStopActivityInner(ActivityThread.java:5278)
            at android.app.ActivityThread.handleStopActivity(ActivityThread.java:5343)
            at android.app.servertransaction.StopActivityItem.execute(StopActivityItem.java:43)
            at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
            at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
            at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2282)
            at android.os.Handler.dispatchMessage(Handler.java:106)
            at android.os.Looper.loopOnce(Looper.java:210)
            at android.os.Looper.loop(Looper.java:299)
            at android.app.ActivityThread.main(ActivityThread.java:8250)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1045)
    2022-09-23 11:59:43.800 7087-7087/androidx.media3.demo.session E/AbstractFuture: RuntimeException while executing runnable androidx.media3.demo.session.PlayerActivity$$ExternalSyntheticLambda3@82c155b with executor MoreExecutors.directExecutor()
        java.util.concurrent.CancellationException: Task was cancelled.
            at com.google.common.util.concurrent.AbstractFuture.cancellationExceptionWithCause(AbstractFuture.java:1496)
            at com.google.common.util.concurrent.AbstractFuture.getDoneValue(AbstractFuture.java:586)
            at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:547)
            at androidx.media3.demo.session.PlayerActivity.getController(PlayerActivity.kt:44)
            at androidx.media3.demo.session.PlayerActivity.setController(PlayerActivity.kt:128)
            at androidx.media3.demo.session.PlayerActivity.initializeController$lambda-4(PlayerActivity.kt:120)
            at androidx.media3.demo.session.PlayerActivity.$r8$lambda$_NhsfsieB1wweFfLvjToeliIJGM(Unknown Source:0)
            at androidx.media3.demo.session.PlayerActivity$$ExternalSyntheticLambda3.run(Unknown Source:2)
            at com.google.common.util.concurrent.DirectExecutor.execute(DirectExecutor.java:31)
            at com.google.common.util.concurrent.AbstractFuture.executeListener(AbstractFuture.java:1277)
            at com.google.common.util.concurrent.AbstractFuture.complete(AbstractFuture.java:1038)
            at com.google.common.util.concurrent.AbstractFuture.cancel(AbstractFuture.java:665)
            at androidx.media3.session.MediaController.releaseFuture(MediaController.java:479)
            at androidx.media3.demo.session.PlayerActivity.releaseController(PlayerActivity.kt:124)
            at androidx.media3.demo.session.PlayerActivity.onStop(PlayerActivity.kt:102)
            at android.app.Instrumentation.callActivityOnStop(Instrumentation.java:1496)
            at android.app.Activity.performStop(Activity.java:8502)
            at android.app.ActivityThread.callActivityOnStop(ActivityThread.java:5298)
            at android.app.ActivityThread.performStopActivityInner(ActivityThread.java:5278)
            at android.app.ActivityThread.handleStopActivity(ActivityThread.java:5343)
            at android.app.servertransaction.StopActivityItem.execute(StopActivityItem.java:43)
            at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
            at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
            at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2282)
            at android.os.Handler.dispatchMessage(Handler.java:106)
            at android.os.Looper.loopOnce(Looper.java:210)
            at android.os.Looper.loop(Looper.java:299)
            at android.app.ActivityThread.main(ActivityThread.java:8250)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1045)
    2022-09-23 11:59:48.639 8393-8393/androidx.media3.demo.session E/AndroidRuntime: FATAL EXCEPTION: main
        Process: androidx.media3.demo.session, PID: 8393
        android.app.ForegroundServiceDidNotStartInTimeException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{73168c0 u0 androidx.media3.demo.session/.PlaybackService}
            at android.app.ActivityThread.throwRemoteServiceException(ActivityThread.java:1995)
            at android.app.ActivityThread.access$2800(ActivityThread.java:271)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2220)
            at android.os.Handler.dispatchMessage(Handler.java:106)
            at android.os.Looper.loopOnce(Looper.java:210)
            at android.os.Looper.loop(Looper.java:299)
            at android.app.ActivityThread.main(ActivityThread.java:8250)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1045)
    
  6. marcbaechinger commented on Sep 23, 2022

    @marcbaechinger
    Contributor

    Thanks for digging some further. That give me some further data points.

    when you play a song and then pause it and close the app the notification remains.

    Yes, indeed, these cases are always about closing the app and having only the service playing in the background. As soon as your app is in the foreground with a controller connected you are bound to the service, and you will never see such an exception.

    If you click on play, after a few seconds it will crash.

    With the default behaviour of the MediaSessionService (your app does not override updateNotification()), I don't think that play should produce a ForegroundServiceDidNotStartInTimeException, because after you pressed play, playWhenReady is true and the player is not STATE_IDLE which results in service.startForeground() being called. With play I would only expect a ForegroundServiceStartNotAllowedException in some cases but not when pressing PLAY on a notification on Android 12 (PendingIntent with exception) and Android 13 (MediaSession with exemption).

    I still think it's the PAUSE case for which we will provide a fix.

  7. ItsBenyaamin commented on Sep 27, 2022

    @ItsBenyaamin
    Author

    Hi @marcbaechinger,
    When we can expect this bug fix on the repo? and any news about the next release?

  8. marcbaechinger commented on Sep 30, 2022

    @marcbaechinger
    Contributor

    This should be fixed with this commit. Please re-open if you think you still see this issue with this commit.

  9. 243 remaining items

  10. ksvslk commented on Oct 22, 2024

    @ksvslk

    @jackyhieu1211 Thanks for the suggestion.

    MedisSessionService/MediaLibraryService need to be started by building a controller or browser. With that, the service is a bound service as long as the controller/browser is connected. You'll never get a ForegroundServiceDidNotStartInTimeException in the bound state.

    The problem of ForegroundServiceDidNotStartInTimeException is only relevant when starting the service for playback resumption, because then, no controller is bound and the service needs to be started into the foreground immediately. That's why playback has to start immediately in the case of playback resumption, because when playing the service is started into the foreground.

    From this your approach isn't really matching the problem I think. In onCreate(), we don't have a notification. A notification can be created when there is a MediaItem available that gives the metadata for the notification.

    For these reasons I think the current approach is the right thing to do:

    1. Playback resumption should be disabled if the app can't start playback when started externally without a binding controller/browser.
    2. If playaback resumption is enabled, the app needs to start playback which is ensured by overriding onPlaybackResumption().

    So is the approach described possible with 1.5.0-beta01?

  11. debz-eight commented on Nov 15, 2024

    @debz-eight

    Any update on this issue.

  12. johngray1965 commented on Nov 19, 2024

    @johngray1965
    Contributor

    I'm working with 1.5.0-rc01 now. I was able to reproduce this locally by removing the recently played item. Once I implemented shouldStartForegroundService, I could not reproduce it locally. But I still see crashes on Android 14, and some of Android 13. On Samsung and Xiaomi devices (so far).

    I don't have a test device that matches those that are showing the crash.

    It seems to me we would expect the crash if

    1. We don't have an item to play (should be handled with shouldStartForegroundService)
    2. We have an item to play, but we didn't load it and start playing it fast enough.

    I've tried to find something to that I would expect to be particularly expensive to load, but I can always load and start well within the limit. But again, it only seems to happen on certain devices and I don't currently have one. Of course, you never know what the load on the users device might be.

    It's disappointing the number of crashes I still see in crashlytics with shouldStartForegroundService implemented.

    Is there something other than the cases I listed above? Perhaps there's something else in my code. Perhaps the problematic devices have a shorter timeout? Other possibilities.

    I am adding some additional logging so I can see if some edge cases that I don't believe should happen are in fact happening. They are basically cases where we failed to load the item, that I believe should be caught by shouldStartForegroundService.

  13. Tr736 commented on Dec 12, 2024

    @Tr736

    So for me this is happening when the app is has been playing in the background for an extended period of time usually around 1 hour.

    Once triggered the position from the player always returns the same value.

    im using a controller like so...

    ` init {
    Log.d("MediaController", "onCreate")
    _playerListener = PlayerListener()
    val sessionToken =
    SessionToken(context, ComponentName(context, PlaybackService::class.java))
    initController(sessionToken)
    initBrowser(sessionToken)
    }

    private fun initController(sessionToken: SessionToken) {
        _controllerFuture =
            MediaController.Builder(context, sessionToken).buildAsync()
    
        _controllerFuture.addListener({
            // Log.d("MediaController", "controllerFuture")
            _controller = _controllerFuture.get()
            _controller?.addListener(_playerListener)
            playerController = PlayerController(_controller)
        },
            MoreExecutors.directExecutor()
        )
    }`
    

    looks like the controller somehow gets destroyed however Im still able to play/pause

    I think I need to figure a way to bind controller to prevent the os from destroying it.

  14. marcbaechinger commented on Dec 12, 2024

    @marcbaechinger
    Contributor

    @Tr736 I think this is something different than ForegroundServiceDidNotStartInTimeException.

    I think I need to figure a way to bind controller to prevent the os from destroying it.

    You already do the right thing with MediaController.Builder(context, sessionToken).buildAsync() which creates a service binding and when playing the service is in the foreground. Else the service wouldn't survive an hour.

    It looks like you can repro this on your device. If that's the case it would be great if you please file a new bug. If you do this best would be to do a bug report right after you see that it happened. Please upload the bug report to the new bug . If you're unable to share bug reports publicly, please send them to android-media-github@google.com using a subject in the format "Issue #1234", where "#1234" should be replaced with your issue number. Please also update the issue to indicate you’ve done this.

    I think we see in the logcat why the app/service was terminated.

    I'm interested in the entire logcat and in the output of

    adb shell dumpsys activity exit-info $APP_PACKAGE
    

    that all we be included in the bug report.

  15. andrewille commented on Dec 13, 2024

    @andrewille

    I am currently starting to write a media player app and face the same Exception. I just followed the basic guide on developer.android.com. The background service runs and starts playing but stops after a few seconds when the Exception is thrown. There is no notification appearing at all and startForeground is never called apparently.
    I use Android 15 on Xiaomi Poco F3 but I even tried it in the device emulator! It failed as well.

    AndroidManifest.xml:

    <service
        android:name=".PlayerService"
        android:foregroundServiceType="mediaPlayback"
        android:exported="true">
            <intent-filter>
                <action android:name="androidx.media3.session.MediaSessionService"/>
            </intent-filter>
    </service>

    PlayerService.java

    private ExoPlayer player;
    private MediaSession mediaSession;
    
    @Override
    public void onCreate() {
        super.onCreate();
        startPlayer();
    }
    
    @Nullable
    @Override
    public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) {
        return mediaSession;
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        if (player != null) {
            player.release();
            player = null;
        }
        if (mediaSession != null) {
            mediaSession.release();
            mediaSession = null;
        }
        stopSelf();
    }
    
    private void startPlayer() {
        player = new ExoPlayer.Builder(this).build();
        mediaSession = new MediaSession.Builder(this, player)
                .build();
        MediaItem item = MediaItem.fromUri("/sdcard/test123.mp3");
        player.setMediaItem(item);
        player.prepare();
        player.play();
    }

    MainActivity.java

    @Override
    protected void onResume() {
        super.onResume();
    
        /* getting storage permission here (omitted) */
    
        Intent serviceIntent = new Intent(this, PlayerService.class);
        ContextCompat.startForegroundService(this, serviceIntent);
    }

    So I got this very simple basic setup by following the guide and it is still crashing even on the emulator :x What is wrong with that?

  16. marcbaechinger commented on Dec 13, 2024

    @marcbaechinger
    Contributor

    You should build a MediaController instead of starting the service manually. Read on in the docs a bit and it will tell (sorry, for not sending a link as I'm afk at the moment)

  17. debz-eight commented on Dec 16, 2024

    @debz-eight

    So for me this is happening when the app is has been playing in the background for an extended period of time usually around 1 hour.

    Once triggered the position from the player always returns the same value.

    im using a controller like so...

    ` init { Log.d("MediaController", "onCreate") _playerListener = PlayerListener() val sessionToken = SessionToken(context, ComponentName(context, PlaybackService::class.java)) initController(sessionToken) initBrowser(sessionToken) }

    private fun initController(sessionToken: SessionToken) {
        _controllerFuture =
            MediaController.Builder(context, sessionToken).buildAsync()
    
        _controllerFuture.addListener({
            // Log.d("MediaController", "controllerFuture")
            _controller = _controllerFuture.get()
            _controller?.addListener(_playerListener)
            playerController = PlayerController(_controller)
        },
            MoreExecutors.directExecutor()
        )
    }`
    

    looks like the controller somehow gets destroyed however Im still able to play/pause

    I think I need to figure a way to bind controller to prevent the os from destroying it.

    So I have faced somewhat of a similar thing where my controller is getting destroyed after the user is in paused state for extended period of time. I have solved this issue by doing the below:

    I have a single source for initialization of my controller and I have made the function to initialize the controller public. So whenever the user is trying to play something, I check if the controller is connected or null, if so, I re-initialize the controller, else I use the existing controller instance to do the necessary.

    So whenever my controller is disconnected or killed, I just re-initialize it. I don't know if its the correct way or not but it works. Perhaps @marcbaechinger can provide some insights on this.

  18. XilinJia commented on Dec 16, 2024

    @XilinJia

    My app has been getting this issue (noticed from time to time). From the documentation, I can't figure out a solution. Google Play Console complains about this. But it's amazing to see this issue standing here for over 2 years and many people suffering on the same problem. Would I get more comfort just by visiting this page to find company?

    Anyone looking to reproduce this, feel free to check out my open-source Youtube/podcast app Podcini: https://github.com/XilinJia/Podcini, currently being launched on Google Play.

  19. marcbaechinger commented on Dec 16, 2024

    @marcbaechinger
    Contributor

    getting this issue @XilinJia

    Yeah, I agree we should close this issue. If you need support, please start a new issue where you describe what you are facing or then add some more information. Saying this issue is unclear unfortunately people describe all sorts of problems they have with the service here.

  20. XilinJia commented on Dec 16, 2024

    @XilinJia

    getting this issue @XilinJia

    Yeah, I agree we should close this issue. If you need support, please start a new issue where you describe what you are facing or then add some more information. Saying this issue is unclear unfortunately people describe all sorts of problems they have with the service here.

    To me, this is an in-fighting between media3 and Android, and we app developers are unfortunately caught in the middle. My app just uses MediaLibraryService and a MediaController according to what has been described, so I expect media3 to settle down any Android complaints, but apparently that's not what's happening. And my issue doesn't appear unique from the large list of issues reported here. I'm not sure how to report anything new.

  21. marcbaechinger commented on Dec 16, 2024

    @marcbaechinger
    Contributor

    @XilinJia Thanks for your opinion. If you want us to look into your issue, please file a new issue and explain it in terms of the output of your app (like bugreport). Thanks.

  22. marcbaechinger commented on Dec 16, 2024

    @marcbaechinger
    Contributor

    I'm closing this issue. It doesn't work anymore as it has grown too big.

    As a general advise on this issue:

    1. The only way to start the service by an app is connecting a controller or browser because this creates a service binding: https://developer.android.com/media/media3/session/connect-to-media-app

    2. The only exception for that is when playback resumption is triggered by a key event or the Sytem UI resumption notification. This is only expected when playback resumption is implemented and then playback must start immediately when the service is started else the service is not started into the foreground and a ForegroundServiceDidNotStartInTimeException is thrown: https://developer.android.com/media/media3/session/background-playback#resumption

    If you haven't enabled playback resumption and you see that an OEM device is starting the service either way, please file a new bug report and describe how the OS starts the service.

    If you think you are still affected by a ForegroundServiceDidNotStartInTimeException after doing it right, please file a new bug and describe exactly what the app is doing and why you think the problem you see happens. Best is to repro with the demo app because then people like me can't say it's an app issue.

    Thanks to everyone who helped us with this issue and contributed to make the service more robust on all available API levels, OEM devices and in the many use cases apps use the service. You helped us to make Media3 better. That's very much appreciated. Thank you! ♥︎

  23. locked and limited conversation to collaborators on Dec 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions