Skip to content

MediaSessionService START_STICKY causes flaky restart behavior for apps with other foreground services #459

Open

Description

@bubenheimer

Media3 Version

Media3 1.0.2

Devices that reproduce the issue

Emulator API levels 27-33

Devices that do not reproduce the issue

Emulator API 26 & API 34 (Beta 3)

Reproducible in the demo app?

Not tested

Reproduction steps

Minimal repro project at https://github.com/bubenheimer/multifgsvcbugs

This project does not actually use MediaSessionService, but demonstrates the general problem. It has 2 START_STICKY services that, at times, are intended to run as foreground services. DataSyncService runs as a foreground service from onCreate() to onDestroy(), while SoundService does not initially run as a foreground service, but is intended to be running as a foreground service at various times. (The startForeground() code to make it a foreground service is commented out, it's not what I want to demonstrate here.) SoundService is meant to represent a MediaSessionService instance that is not currently running as a foreground service.

  1. Start app.
  2. Tap "Request POST_NOTIFICATIONS permission" for API 33+ (optional, to see foreground service notification).
  3. Tap "Start data sync service".
  4. Tap "Start sound service".
  5. Simulate the system being under memory pressure and killing the process that the 2 services run in (org.bubenheimer:ext). I believe this corresponds to "am kill". There are various ways to do this. ("Force stop" is NOT one of them.) I prefer doing it from the "Device Explorer" tab in Android Studio Giraffe+ ("Kill process" under "Processes"), but it may be possible from Logcat as well. Or "kill -9".

Expected result

In Logcat, observe process being killed and recreated shortly thereafter, and DataSyncService and SoundService logging from onCreate().

Actual result

Intermittently DataSyncService is not restarted automatically, only SoundService is recreated. Sometimes other weird stuff happens, e.g. onCreate() followed by instant onDestroy()`.

This can take several app runs to show up.

This behavior is not really the fault of MediaSessionService, it's an Android framework bug (and seems fixed in API 34). The problematic thing in MediaSessionService is its use of START_STICKY, which is the primary thing triggering the behavior. Of course, an overriding MediaSessionService instance can choose to return whatever it wants from onStartCommand().

Returning START_NOT_STICKY generally helps avoid the issue, at least to some degree. (In my complex production services setup it does not clear up the problem, but it does help.)

Is the use of START_STICKY in MediaSessionService intentional and recommended? Or is it optional or arbitrary and can be replaced?

Does MediaSessionService use START_STICKY because it restores some saved state upon automatic recreation after process death? I have not seen this myself, but I'd be interested in a pointer if it does.

Having more than one foreground service in an app is not so common because they can usually be combined. However, MediaSessionService (and MediaBrowserService, MediaBrowserServiceCompat, etc.) does not lend itself to combining, because it generally is exported. (Also I'd think it is not really designed to be flexibly combined with arbitrary other services that have different bind/unbind/start/stop lifecycles.)

Media

N/A

Bug Report

Activity

  1. bubenheimer commented on Jun 12, 2023

    @bubenheimer
    ContributorAuthor

    This issue has gained prominence for me while working on keeping my MediaSessionService instance running for longer stretches: #389 (comment). I may need to revert to keeping it running only during active playback; in my production use case I actually get crashes due to the foreground state not being the way it should, it's not just services failing to start as in the repro here.

  2. bubenheimer commented on Jun 12, 2023

    @bubenheimer
    ContributorAuthor

    Also, in case someone ends up chatting with the framework team, it would be useful to get confirmation that this issue was specifically addressed in API 34 and not just avoided for now due to general refactoring. A (CTS?) test case similar to my repro may help avoid future recurrence.

    A more reliable workaround would be of interest, too, if available. Currently my production app still crashes prior to API 34 upon process kill/restore during active playback despite my best workaround efforts (MediaSessionService in foreground state, NOT_STICKY). I've used additional workarounds that seem to help, but so far nothing has completely prevented crashing.

    UPDATE: I forgot to mention, I did a lengthy Android issuetracker search for the dual STICKY foreground service restart problem, which came up blank. I don't have access to Google-internal issues, of course.

  3. bubenheimer commented on Jun 12, 2023

    @bubenheimer
    ContributorAuthor

    One more potential workaround, at least in my case, may be to never run the MediaSessionService in the foreground, which, technically, I don't really need. However, would I still be able to use the special baked-in system media playback notification control thingy in this case? It became even more baked in on recent API levels.

  4. bubenheimer commented on Jun 12, 2023

    @bubenheimer
    ContributorAuthor

    I think a decent way to address this issue, besides changing the stickiness default, would be adding a flag to MediaSessionService to control whether it should go to the foreground at all. I am aware that I can control this myself by completely taking over notification handling via onUpdateNotification(), but then I'd have to redo that entire part myself, I think.

    This flag would be needed (for now) whenever there already is another service controlling foreground behavior in an app, to help work around the framework bug. This suggest that the functionality is general enough to be a part of the API. Even without the framework bug this can be architecturally desirable in an app to consolidate services controlling foreground behavior.

    This actually is the behavior I used in the old version of my app based on MediaBrowserServiceCompat (NOT_STICKY & not foreground). I had forgotten about the "not foreground" part.

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