19

While it seems there are a few questions on here regarding Android 12 service restrictions, I have yet to see one specific to this use case.

Background: I am starting a foreground service to handle a very long running background media player (Exoplayer). Due to the setup of the app, I cannot use the built in notification manager from exoplayer. However I am seeing an odd behavior from Crashlytics. I am getting ForegroundServiceStartNotAllowedException While the app is undoubtedly in the foreground. Per the logs, it is easy to see the user is navigating the app within a second of the startForeground call.

I am also listening to

override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event)

to ensure the app is in a foreground state.

logs

crash

I am beginning to run out of ideas as to what would cause this. As you can see by the timestamps, less than 1 second had gone by. The app has no use cases where the service could even accidentally be started from the background.

Thanks

Edit:

I am also declaring my service type:

        <service
            android:name=".service.SoundPlayerService"
            android:enabled="true"
            android:exported="false"
            android:foregroundServiceType="mediaPlayback"
            android:stopWithTask="false">
            <intent-filter>
                <action android:name="android.media.browse.MediaBrowserService" />
            </intent-filter>
        </service>
        if (!audioFocusTakenBackground && Application.instance.isAppInForeground) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                startForeground(
                    ONGOING_NOTIFICATION_ID,
                    builder.build(),
                    ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
                )
            } else {
                startForeground(
                    ONGOING_NOTIFICATION_ID,
                    builder.build()
                )
            }
        }

Edit: Device State tab suggested by @Arlind

Device States

brettywhite
  • 521
  • 4
  • 14
  • Did you [try](https://stackoverflow.com/a/70378618/5695091) this solution? – ysfcyln Jan 14 '22 at 14:43
  • Hi @ysfcyln I did see that comment and tried that a few versions ago. Unfortunately it seems to have no effect. I edited my question above to show that. Thanks – brettywhite Jan 14 '22 at 14:48
  • 2
    did you get a success on this problem? – sam_k Jan 21 '22 at 23:31
  • I see a similar thing in my app. Do you receive any media button actions like KEYCODE_MEDIA_PLAY ? Then your app might be started as a reaction on this event in background. Especially Samsung devices do this nasty thing. I am still unsure how to solve it though. – slezadav Jan 23 '22 at 15:48
  • @sam_k for now I put my target back down to 30. I am still looking into as to why this is happening, I only have a pixel device to test Android 12 on so it's difficult for me to debug Samsung devices. @ slezadev I will look into that. Currently my notification only allows users to stop the sound through it, not start. I'm wondering if there's some system media controls that might allow it. – brettywhite Jan 23 '22 at 20:31
  • There is a Device states tab in firebase crashes, that should show 100% background for this crash – Arlind Hajredinaj Apr 11 '22 at 23:41
  • @Arlind I posted that tab. Because of this too, another interesting fact is that all of them are Samsung devices running Android 12 and in the foreground – brettywhite Apr 13 '22 at 13:02
  • @brettywhite that crash log is for a SecurityException. Add `` to the Manifest file. – Arlind Hajredinaj Apr 15 '22 at 14:18
  • @Arlind I've had that since day 1: – brettywhite Apr 15 '22 at 14:29
  • For the SecurityException take a look at https://stackoverflow.com/questions/48930204/securityexception-not-allowed-to-start-service – Arlind Hajredinaj Apr 15 '22 at 20:10
  • For ForegroundServiceStartNotAllowedException, also please share the crash log – Arlind Hajredinaj Apr 15 '22 at 20:10
  • 1
    @brettywhite did you figure this out – Arlind Hajredinaj May 12 '22 at 22:27
  • @Arlind unfortunately not yet. I've kept my target at 30 and I haven't had time to play with it since. – brettywhite Jun 21 '22 at 16:55
  • 2
    I believe this is a bug in Android 12, it is preventing foreground services even in situations which are supposed to be allowed. You can see some discussion here https://issuetracker.google.com/issues/229000935?utm_source=pocket_mylist&pli=1 – mbwasi Jun 30 '22 at 21:20
  • @mbwasi I think you are right. I added to the discussion there as well. Hopefully this is addressed soon since they are starting to force API 31 on google play submissions. I am definitely seeing my error count rise again – brettywhite Sep 29 '22 at 12:53

3 Answers3

5

One thing that's looking promising (I won't mark anything as answered until I get more data in) is by adding this bit to the notification builder:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    foregroundServiceBehavior = Notification.FOREGROUND_SERVICE_IMMEDIATE
}

Then to prevent crashes but still be notified of an issue I wrapped the startForeground in a try/catch that posts to crashlytics so i know there's an issue:

        if (!audioFocusTakenBackground && Application.instance.isAppInForeground && !isForegroundActive) {
            isForegroundActive = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                try {
                    startForeground(ONGOING_NOTIFICATION_ID, builder.build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK)
                    true
                } catch (e: Exception) {
                    Timber.e("Unable to start foreground: ${e.message}")
                    FirebaseCrashlytics.getInstance().recordException(e)
                    false
                }
            } else {
                try {
                    startForeground(ONGOING_NOTIFICATION_ID, builder.build())
                    true
                } catch (e: Exception) {
                    Timber.e("Unable to start foreground: ${e.message}")
                    FirebaseCrashlytics.getInstance().recordException(e)
                    false
                }
            }
        }

Note that in the area where Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q, it adds that the notification is a FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK. According to the google docs here: https://developer.android.com/guide/components/foreground-services#notification-immediate this should be enough to initially show the notification. I'm curious if some implementations don't use or listen to that.

I will update this when I get more data, but for now my crashes have subsided and I am not seeing any logging from the catch blocks in crashlytics. Hopefully someone else can use this and verify my findings.

EDIT:

After a few days my crashes from this error have gone down to 0 and no noticeable logs from the catch's have been observed. Finally calling this one closed

brettywhite
  • 521
  • 4
  • 14
0
Application.instance.isAppInForeground

Is this variable has right value? Maybe this variable gets wrong value. Could you check?

dralexnumber
  • 238
  • 2
  • 10
-4

Never try to play audio using your own Service. Always use the MediaSession API as described here: https://developer.android.com/guide/topics/media-apps/audio-app/building-an-audio-app

Erik Hellman
  • 529
  • 4
  • 11