Search code examples
androidandroid-servicesticky

START_STICKY does not work on Android KitKat


One of my apps has a backgrouod service that uses the START_STICKY return code from onStartCommand to automatically restart when the system kills it. It seems that this is no longer working on Android KitKat. Is there any solution for this ? Should I be doing something different on Kitkat to keep the service running ?

Note: There is a similar discussion on the Android-Devlopers group about swiping the app from the recent apps list behaves. Could this two issues be related ? https://groups.google.com/forum/#!topic/android-developers/H-DSQ4-tiac

Edit: Saw that there are open bugs on Android issue tracker:

https://code.google.com/p/android/issues/detail?id=63793 https://code.google.com/p/android/issues/detail?id=63618

Edit2: The same happens even if service is running using startForeground, in a separate process and with the flag android:stopWithTask="false" in the AndroidManifest.xml file...

Edit3: More related bugs on Android issue tracker:

https://code.google.com/p/android/issues/detail?id=62091 https://code.google.com/p/android/issues/detail?id=53313 https://code.google.com/p/android/issues/detail?id=104308

Is there some sort of workaround to get the previous behavior ?


Solution

  • This is not a 100% working solution but it's the best so far as it almost completely eliminates the problem. So far I integrated this solution along with overriding onTaskRemoved (See this answer) and a keep-alive notification (See this answer). Additional answers are very appreciated !

    After further investigation, it seems that the bug already exists in Jelly Bean and looks like there is a solution for that (At least in my case that seems to work. will keep on testing and update the answer if required).

    From what I observed this only happens with services that receive broadcasts set by AlarmManager.

    To reproduce the bug follow these steps:

    1. Start the app
    2. start the service as a foreground service (use startForeground for that) from within the app
    3. Swipe the app from "Recent Apps" list
    4. Send a broadcast that is handled by the service
    5. The service is killed !

    Using adb shell dumpsys >C:\dumpsys.txt you can monitor the state of the service between the different steps. (look for Process LRU list in the dumpsys output) on steps 2 and 3 you will see something like this:

    Proc # 2: prcp  F/S/IF trm: 0 11073:<your process name>/u0a102 (fg-service)
    

    Specifically, notice the F/S/IF and the (fg-service) that indicate the service is running as a foreground service (more details on how to analyze the dumpsys at this link: https://stackoverflow.com/a/14293528/624109).

    After step 4 you will not see your service in the Process LRU list. Instead, you can look at the device logcat and you will see the following:

    I/ActivityManager(449): Killing 11073:<your process name>/u0a102 (adj 0): remove task
    

    What seems to be causing that behavior is the fact that the received broadcast takes the service out of its foreground state and then killed.

    To avoid that, you can use this simple solution when creating your PendingIntent for the AlarmManager (Source: https://code.google.com/p/android/issues/detail?id=53313#c7)

    AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent("YOUR_ACTION_NAME");
    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, intent, 0);
    

    Pay attention to the following steps:

    1. Call addFlags on the intent and use FLAG_RECEIVER_FOREGROUND
    2. Use a non-zero request code in PendingIntent.getBroadcast

    If you leave any of those steps out it will not work.

    Note that the FLAG_RECEIVER_FOREGROUND was added on API 16 (Jelly Bean) so it makes sense that this is when the bug first appeared...

    Most likely that KitKat is just more aggressive when it comes to killing processes and this is why it was emphasized with KitKat, but looks like this was already relevant on Jelly Bean.

    Note 2: Notice the details in the question about the service configuration - running in a separate process, as a foreground service, with endWithTask set to false in the manifest.

    Note 3: The same thing happens when the app receives the android.appwidget.action.APPWIDGET_CONFIGURE message and shows a configuration activity for a new widget (Replace step 4 above with creating a new widget). I found that only happens when the widget provider (the receiver that handles android.appwidget.action.APPWIDGET_UPDATE) is set to run on a different process than the activity process. After changing that so both the configuration activity and the widget provider are on the same process, this no longer happens.