Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cancelling Android notifications when the service is automatically killed by the system

I have an application that implements MediaBrowserServiceCompat. When playing music, it runs in the foreground, with a media control notification that the system makes non-dismissible. When paused, it comes out of the foreground, and the notification is retained. Standard stuff.

When this service is automatically killed by the system, the notification is not removed.

You can simulate this by putting the app in the non-foreground paused state, leaving the app, and issuing this command:

adb shell am kill com.myapp.package

The notification remains. You get this Logcat message:

W/ActivityManager: Scheduling restart of crashed service com.myapp.package/com.myapp.package.playback.platform.AndroidMediaService

None of the obvious hooks (e.g. onDestroy, onTaskRemoved etc) on the service appear to be called - it seems to be outright killed. Because the service is started with START_NOT_STICKY, we also don't get onCreate called on a new instance either.

A partial solution to this is to make the service sticky, and cancel the notifications when the service is revived. However this can take significant time to actually happen, during which the notification doesn't work, so isn't ideal. It may also have further consequences.

Other applications seem to have no trouble with this.

Repeat this scenario (pause, leave app) and carry out the commands, for example on Google Play Music:

adb shell am kill com.google.android.music

or Spotify:

adb shell am kill com.spotify.music

and you find that their notifications disappear immediately as if they are cancelled on teardown.

What might they be doing to make this happen?

like image 896
Rob Pridham Avatar asked Mar 15 '19 22:03

Rob Pridham


1 Answers

I've figured out the answer to this and it was, of course, my own fault. There is nothing special that other apps are doing - it's a platform behaviour and we were the outlier.

I belatedly discovered that when transitioning from foreground to background, we called:

ServiceCompat.stopForeground(service, ServiceCompat.STOP_FOREGROUND_DETACH)

I discovered this via dumpsys, e.g.:

adb shell dumpsys activity services com.google.android.music

and I found some differences.

My app:

ServiceRecord{294309d u0 com.myapp.debug/com.myapp.playback.platform.AndroidMediaService}
    intent={cmp=com.myapp.debug/com.myapp.playback.platform.AndroidMediaService}
    packageName=com.myapp.debug
    processName=com.myapp.debug:main
    baseDir=/data/app/com.myapp.debug-GM-nBaeXA_e47EmJKnM27g==/base.apk
    dataDir=/data/user/0/com.myapp.debug
    app=ProcessRecord{83fb4ffd0 23567:com.myapp.debug:main/u0a381}
    createTime=-27s211ms startingBgTimeout=--
    lastActivity=-26s911ms restartTime=-27s211ms createdFromFg=true
    startRequested=true delayedStop=false stopIfKilled=true callStart=true lastStartId=2

Play Music:

ServiceRecord{8693ccb u0 com.google.android.music/.playback2.MusicPlaybackService}
    intent={cmp=com.google.android.music/.playback2.MusicPlaybackService}
    packageName=com.google.android.music
    processName=com.google.android.music:main
    baseDir=/data/app/com.google.android.music-lrn1VQr_3_RDi5PMbqozdw==/base.apk
    dataDir=/data/user/0/com.google.android.music
    app=ProcessRecord{9a3c417d0 22921:com.google.android.music:main/u0a191}
    isForeground=false foregroundId=1 foregroundNoti=Notification(channel=playback_v1 pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x2 color=0xffff5722 category=transport actions=5 vis=PUBLIC semFlags=0x0 semPriority=0 semMissedCount=0)
    createTime=-9m33s792ms startingBgTimeout=--
    lastActivity=-20s825ms restartTime=-9m33s792ms createdFromFg=true
    startRequested=true delayedStop=false stopIfKilled=false callStart=true lastStartId=1

You can see the missing foregroundNoti attribute in my app's logs. This is a product of the detach call. We chose to do this at some point long ago to avoid the notification being collected by the system. On reflection, we should have allowed it to be killed as with other apps.

like image 108
Rob Pridham Avatar answered Sep 19 '22 13:09

Rob Pridham