Skip to content

ForegroundServiceDidNotStartInTimeException due to dropped KeyCode. KEYCODE_HEADSETHOOK #2768

Closed

Description

@johngray1965

Version

Media3 main branch

More version details

No response

Devices that reproduce the issue

Samsung devices are the vast majority of the crashes.

Devices that do not reproduce the issue

No response

Reproducible in the demo app?

No

Reproduction steps

I can reproduce the issue via unit tests

Expected result

The app doesn't crash.

Actual result

      Fatal Exception: android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{f5d3566 u0 xxxx/xxxxService}
   at android.app.ActivityThread.generateForegroundServiceDidNotStartInTimeException(ActivityThread.java:2118)
   at android.app.ActivityThread.throwRemoteServiceException(ActivityThread.java:2089)
   at android.app.ActivityThread.-$$Nest$mthrowRemoteServiceException()
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2354)
   at android.os.Handler.dispatchMessage(Handler.java:106)
   at android.os.Looper.loopOnce(Looper.java:211)
   at android.os.Looper.loop(Looper.java:300)
   at android.app.ActivityThread.main(ActivityThread.java:8227)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1028)

Media

I've had an ongoing issue with ForegroundServiceDidNotStartInTimeExceptions. I implement onPlaybackResumption, and I have a MediaButtonReceiver that implements shouldStartForegroundService to verify I have something to play. My service implements MediaLibraryService and I have a custom player. Over the past few months, I've been adding Google Analytics events at various points. When the crashes occur, onPlaybackResumption isn't called. I just overrode onMediaButtonEvent, it just logs an event and returns super. onMediaButtonEvent is called. It's called from onMediaButtonEvent in MediaSessionImpl. I'm also logging the intent. The intent is always something like this:
Intent { act=android.intent.action.MEDIA_BUTTON flg=0x10000010 cmp=xxxx/xxxxrService (has extras) } Bundle[android.intent.extra.PACKAGE_NAME=android, android.intent.extra.KEY_EVENT=KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_HEADSETHOOK, scanCode=0, metaState=0, flags=0x8, repeatCount=0, eventTime=617362637000000, downTime=617362634000000, deviceId=-1, source=0x101, displayId=-1 }]
Its always KEYCODE_HEADSETHOOK, always repeatCount=0. I've traced through the code in MediaSessionImpl, I see right after callback.onMediaButtonEvent, it does a swicth with a case for KEYCODE_HEADSETHOOK. With the info I have, it's hard to know which branch its hits there. One branch tries to play/pause without calling onPlaybackResumption (so I haven't loaded anything to play). I see doubleTapCompleted is true, then the KEYCODE_HEADSETHOOK will be changed to KEYCODE_MEDIA_NEXT in applyMediaButtonKeyEvent (called at the bottom MediaSessionImpl.onMediaButtonEvent). Otherwise KEYCODE_HEADSETHOOK doesn't appear to get handled. I may well have missed something in my walk through on the code, but regardless, the bottom line is onPlaybackResumption is never called, so we don't even attempt to play anything. Thus the timeout.

Bug Report

Activity

  1. johngray1965 commented on Sep 14, 2025

    @johngray1965
    ContributorAuthor

    Now I have tests that confirm this. They aren't very well structured tests, the tests just start the service with an KeyCode. I need to read to logs to get the results, but here's. the gist. KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE results on onPlaybackRsumption being called. KeyEvent.KEYCODE_HEADSETHOOK does not. All the crashes I see are KeyEvent.KEYCODE_HEADSETHOOK.

  2. changed the title [-]ForegroundServiceDidNotStartInTimeException due dropped KeyCode[/-] [+]ForegroundServiceDidNotStartInTimeException due to dropped KeyCode. KEYCODE_HEADSETHOOK[/+] on Sep 14, 2025
  3. johngray1965 commented on Sep 14, 2025

    @johngray1965
    ContributorAuthor

    Now I have tests that don't require reading the logs. They are dependent on the fact that my MediaLibrarySession.Callback impl is injected into my service, allowing me to replace it for the tests (really wrap it with a spy, so I can flag whether onPlaybackResumption was called or not). I'm toying with the idea of creating a minimal project that will demo the issue. I don't think the demo app will work without reworking it to inject at least the callback.

  4. johngray1965 commented on Sep 14, 2025

    @johngray1965
    ContributorAuthor

    https://github.com/johngray1965/Media3KeycodeTest. Note there two tests, one sets the expectation to should see a call onPlaybackResumption, the other sets it to should not. I believe they should both set it. If I am wrong about that, please explain.

  5. johngray1965 commented on Sep 14, 2025

    @johngray1965
    ContributorAuthor

    Better yet, now they both are set to expect a call to onPlaybackResumption, one test fails.

  6. johngray1965 commented on Sep 15, 2025

    @johngray1965
    ContributorAuthor

    I see that according to: https://developer.android.com/reference/androidx/media3/session/MediaSession#media-key-events-mapping. KEYCODE_HEADSETHOOK is expected to act like KEYCODE_MEDIA_PLAY_PAUSE. It does not. in MediaSessionImpl::applyMediaButtonKeyEvent there's a switch statement that has a case for KEYCODE_MEDIA_PLAY_PAUSE, but not for KEYCODE_HEADSETHOOK.

  7. johngray1965 commented on Sep 15, 2025

    @johngray1965
    ContributorAuthor

    Since its documented that KEYCODE_MEDIA_PLAY_PAUSE and KEYCODE_HEADSETHOOK should do the same thing I searched for KEYCODE_MEDIA_PLAY_PAUSE, to see if there were other places that KEYCODE_HEADSETHOOK wasn't being handled. Besides the place I mentioned above, I see MediaSessionKeyEventTest has tests for KEYCODE_HEADSETHOOK double click, but not a single. MediaSessionTest tests KEYCODE_MEDIA_PLAY_PAUSE, but doesn't test KEYCODE_HEADSETHOOK at all. I'd bet extending those tests to cover KEYCODE_HEADSETHOOK will bear out the issue I've been seeing. I had been leery of suggesting a fix, not being sure I fully understood the issue, I think I'm past that now.

  8. johngray1965 commented on Sep 16, 2025

    @johngray1965
    ContributorAuthor

    @marcbaechinger I hope you'll find time to take a look at the PR I submitted for this. I believe you'll find it both simple and important.

  9. marcbaechinger commented on Sep 17, 2025

    @marcbaechinger
    Contributor

    Yeah, totally. Thanks for all the analysis! Really appreciated. I try to get to this asap.

  10. johngray1965 commented on Sep 26, 2025

    @johngray1965
    ContributorAuthor

    FYI I'm using a local build with these changes in the latest release of my app. Happily the crash is gone.

  11. johngray1965 commented on Oct 4, 2025

    @johngray1965
    ContributorAuthor

    #2816 has been merged, so this can be closed.

  12. locked and limited conversation to collaborators on Dec 3, 2025
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