Rob Pridham
Rob Pridham

Reputation: 4928

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?

Upvotes: 6

Views: 1933

Answers (3)

Mayur Dabhi
Mayur Dabhi

Reputation: 3926

you should set priority of notification "LOW" and in Service destroy method you can manually remove notification by below code,

 notificationManager.cancelAll();

Upvotes: 0

Rob Pridham
Rob Pridham

Reputation: 4928

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.

Upvotes: 3

Amir Uval
Amir Uval

Reputation: 14873

Try adding this flag in the manifest to stop the service with the app when it's killed:

<service
    ...
    android:stopWithTask="true"/>

If it doesn't remove the notification, setting it to false should trigger a callback in the service, where you should be able to remove the notification

@Override 
public void onTaskRemoved(Intent rootIntent) {
    ...
}

Also, this answer might be related.

Update

Since the above didn't work, I looked on how the native Music app is declared in the manifest, and they don't use what I suggested. What they do use, and it may be related is

<service
   ...
   android:process=":main" />

in all the services and also in the receivers that change the notifications. Worth a try.

Upvotes: 1

Related Questions