RemoteServiceException in Android 12 and Lower
@marcbaechinger is already working on this.
Since Jun 19, 2026.
- Dominant language
- Java
- Stars
- 3k
- Forks
- 955
- Avg merge
- 12d 14h
- Merged PRs (30d)
- 2
Description
Version
Media3 1.9.2
More version details
No response
Devices that reproduce the issue
Samsung, Xiaomi, Motorola are the top 3 devices that being reported.
Android 10, 11, & 12 are the majority while 13+ is less than 1%
Devices that do not reproduce the issue
No response
Reproducible in the demo app?
Not tested
Reproduction steps
Hey team, this is not our first time reporting the issue and I know we have an extensive issue that's now closed about this particular crash. But we've been trying integrate the media3 MediaSessionService again to replace our own playback service, but after some experimentations on multiple release versions, we still cannot get rid of this crash.
Here's the summary of the implementation that have (some code preview are available in the next section):
- We're using the media3
MediaSessionService - We're starting the service by connecting to the controller
- We're extending
androidx.media3.session.MediaButtonReceiverand overriding theshouldStartForegroundService - We're implemented the
MediaSession.Callback#onPlaybackResumption, as of now this is just replaying latest playlist, if it's empty we're playing one silent media item, this is our latest effort on fixing the crash. - Before doing the silent media item, we're implementing a "force stopper" for the
MediaSessionService, with this approach, the crash rate was actually better. - We have some custom media buttons that we setup in
MediaSession.Callback
Now, some analysis on the crash itself. We're adding some logs across components above and we can say that:
- When the crash happen there's no trace of the media button receiver is being invoked
- When the crash happen there's no trace of playback resumption is being invoked
- Most of the crashes follow this pattern:
Service.onCreate -> onStartCommand -> Service.onDestroy, but some logs also just having theService.onDestroylog, we haven't exactly log theonGetSessionandonUpdateNotification
Code Preview
AndroidManifest.xml
<service
android:name="com.app.MediaSessionPlaybackService"
android:exported="false"
android:foregroundServiceType="mediaPlayback">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService" />
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</service>
<receiver
android:name="com.app.MediaButtonReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
MediaSessionPlaybackService.kt
class MediaSessionPlaybackService : MediaSessionService() {
@Inject private lateinit var sessionFactory: MediaSessionFactory
@Inject private lateinit var callback: MediaSessionCallback
@Inject private lateinit var player: AppPlayer
private var mediaSession: MediaSessionFactory.ReleasableMediaSession? = null
private val serviceJob = SupervisorJob()
internal val serviceScope = CoroutineScope(Dispatchers.Main + serviceJob)
private var scheduleStopJob: Job? = null
override fun onCreate() {
super.onCreate()
mediaSession = sessionFactory.createSession(callback)
setMediaNotificationProvider(MediaNotificationProvider(applicationContext))
setForegroundServiceTimeoutMs(FOREGROUND_TIMEOUT_IM_MS)
}
override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? = mediaSession?.session
override fun onDestroy() {
releaseMediaSession()
serviceJob.cancel()
super.onDestroy()
}
override fun onTaskRemoved(rootIntent: Intent?) {
appPlayer.stopPlayback() // This eventually will triger Player.stop, we need this for some UX thing in our app
releaseMediaSession()
stopSelf()
}
private fun releaseMediaSession() {
mediaSession?.release()
mediaSession = null
}
companion object {
private const val FOREGROUND_TIMEOUT_IM_MS = 0L
fun stop(context: Context) {
context.stopService(Intent(context, MediaSessionPlaybackService::class.java))
}
}
}
internal class MediaNotificationProvider(context: Context) : DefaultMediaNotificationProvider(
/* context = */ context,
/* notificationIdProvider = */ { _ -> DEFAULT_NOTIFICATION_ID },
/* channelId = */ MediaNotificationChannel.channelId,
/* channelNameResourceId = */ Strings.media_notifications_channel_title
) {
init { setSmallIcon(Icons.ic_icon) }
}
Service Starter
SessionToken(context, ComponentName(context, MediaSessionPlaybackService::class.java))
val newFuture = MediaController.Builder(context, sessionToken)
.setListener(object : MediaController.Listener {
override fun onDisconnected(controller: MediaController) {
MediaSessionPlaybackService.stop(context)
}
})
.buildAsync()
MediaButtonReceiver.kt
class MediaButtonReceiver : Media3ButtonReceiver() {
private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
private var shouldStartService: Boolean = false
override fun onReceive(context: Context, intent: Intent?) {
scope.launch {
// non-blocking load, if it's fails or not loaded, it will fallback to the default value which is `false`
loadShouldStartServiceFlag(context, intent)
super.onReceive(context, intent)
}
}
override fun shouldStartForegroundService(context: Context, intent: Intent): Boolean = shouldStartService
}
Stacktrace
Fatal Exception: android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{45e37c7 u0 com.app/com.app.MediaSessionPlaybackService}
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2188)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:8167)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
Expected result
Do not crash. If it's crash, we want to know the actual cause of error.
Actual result
Crashing.
Media
Bug Report
- You will email the zip file produced by
adb bugreportto android-media-github@google.com after filing this issue.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.