24

I have a service that gets started (not bound) by an activity. If the activity gets destroyed (e.g. by pressing the back button), the service continues to run, this is of course intended. However, if I swipe the activity out of the 'recent apps' list, the service gets restarted immediately. This is reproducible, every time the activity/app is swiped out of the list, there is a new call to the service's onCreate-method. No call to onDestroy in between!

First I thought the service gets killed by android, even though I saw no reason for the kill (neither the activity nor the service do resource consuming things, in fact they are minimalistic and do nothing). But then I noticed that the service actually crashes.

V/MainActivity(856): onDestroy // swipe out of the list
I/ActivityManager(287): Killing 856:com.example.myapp/u0a10050: remove task
W/ActivityManager(287): Scheduling restart of crashed service com.example.myapp/.TestService in 5000ms

The code is not noteworthy, but here it is

Activity:

public class MainActivity extends Activity {

    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.v(TAG, "onCreate, starting service...");
        startService(new Intent(this, TestService.class));
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.v(TAG, "onStart");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.v(TAG, "onDestroy");
    }

    //[...]
}

Service:

public class TestService extends Service {

    private static final String TAG = "Service";

    // onBind omitted

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.v(TAG, "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.v(TAG, "onDestroy");
    }

}

In short: My service is independent of the activity's lifecycle, but only as long as I don't swipe out the app of the recent apps list. In that case, the service gets restarted but without a call to onDestroy.

Every time this happens, not only the state of the service, but also the work the service is doing is lost. I just want to know why the swipe is the reason for this.

David Wasser
  • 93,459
  • 16
  • 209
  • 274
alapeno
  • 2,724
  • 6
  • 36
  • 53

4 Answers4

21

Swiping the app from the recent tasks list actually kills the operating system process that hosts the app. Since your service is running in the same process as your activities, this effectively kills the service. It does NOT call onDestroy() on the service. It just kills the process. Boom. Dead. Gone. Your service does not crash.

Since your service returned START_STICKY from the call to onStartCommand(), Android recognizes that your service should be restarted and schedules a restart of the killed service. However, when your service is restarted it will be in a newly created process (you can see onCreate() called in the service), so it will have to start the work all over again.

Rule #1: Don't ever swipe apps from the recent tasks list ;-)

David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • Thanks for your help David, that sounds reasonable. I never (ok, rarely) swipe apps out of the list, but I don't know if this is true for all users ;-). Would it help to outsource the service to an own process per default (via android:process)? Not that I will do it, just out of curiosity. Edit: I thought it crashed because the log clearly said " Scheduling restart of **crashed** service." – alapeno Sep 04 '13 at 16:21
  • 7
    Nope. That won't help. I just verified that with an App we have where the service runs in a separate process. Swiping the App from the recent tasks list kills the process hosting the service too. The log message "Scheduling restart of crashed service" is just one of 10 thousand things that is less-than-perfect in Android. Android will schedule a restart of the service if the process disappears, no matter how it happens. For example, if your app is running and you install an update, the installer needs to kill the service to install the update. Android reschedules the service here too! – David Wasser Sep 04 '13 at 16:31
  • 1
    Thanks again. An additional service was no help indeed, but a foreground service behaves the way I was looking for. – alapeno Sep 05 '13 at 10:32
  • This does not happen to foreground services. They are not terminated and continue running uninterrupted. Additionally in 4.4, Android will *not* restart a swiped-away app's non-foreground sticky service. A foreground sticky service is the only way to ensure it never terminates and restarts without fail. – Monstieur Apr 16 '14 at 10:00
  • 2
    @Locutus: I can't reproduce that on KitKat 4.4.4 and Lollipop 5.0. My sticky service is always restarted after it's task has been removed. – corsair992 Jan 31 '15 at 13:21
  • Note that this behavior seems to have been introduced in Jelly Bean. Background services were not killed upon task removal in ICS, and the `onTaskRemoved()` callback was introduced to allow them to handle it themselves. Additionally, there was a new flag `FLAG_STOP_WITH_TASK` introduced that was supposed to correspond to a `stopWithTask` attribute that would be defined in the manifest entry, but that attribute was [never introduced](http://b.android.com/74667) for the `` element. – corsair992 Jan 31 '15 at 13:28
  • Does *Activity's* `onDestroy()` gets called on swiping from recent (killing process)? – Muhammad Babar Feb 13 '15 at 13:59
  • @MuhammadBabar Activity `onDestroy()` is also NOT called when Android kills the process hosting your application. – David Wasser Feb 13 '15 at 14:21
  • I'm not talking about OS killing process. i meant for user swiping away the app from recent (while app is alive). – Muhammad Babar Feb 13 '15 at 14:23
  • @MuhammadBabar Testing this on a few phones indicates that Activity `onDestroy()` is called when swiping an application from the list of recent tasks. However, I wouldn't count on this happening. I think this behaviour may be different in different Android versions and may be different from device to device. Secondly, Android can kill the app's process if it is in the background at any time, for any reason. So you cannot assume that `onDestroy()` will be called. – David Wasser Feb 13 '15 at 15:42
  • Yeah this is strange thing that i noticed today that `onDestroy()` is getting called often but not every time btw i do know about the os killing process of background apps when it needs memory. Thanks – Muhammad Babar Feb 13 '15 at 17:04
  • @Locutus On 4.4, non-sticky foreground services are destroyed with a call to `onDestroy()` and restarted within a few milliseconds. Sticky non-foreground services are stopped *without* a call to `onDestroy()` and restarted after several seconds. – Kevin Krumwiede Aug 04 '15 at 03:54
  • 4
    Whats the solution then to actually prevent this service crash when we swipe left? – gandharv09 Sep 17 '15 at 15:23
  • I am facing a similar problem. I have a service that is starting ON_BOOT, sticky which monitors the phone status. I also have an application that binds to that service. When I force quit the application, the service will (as expected) restart. I read @DavidWasser 's RULE "do not swipe apps", but you can force that to users. Since onDestroy is not called, the service does not update certain files it should do. Is there a signal I can monitor when this happens? – Konstantinos Nov 11 '15 at 17:43
  • @Konstantinos Do this: Use a boolean in shared preferences. In `onCreate()` of your `Service`, check that the boolen is `false`, meaning that the `Service` was correctly shutdown. Then set the boolean to `true`. In `onDestroy()` set the boolean to `false`. If the boolean is `true` in `onCreate()`, it means that your `Service` was killed and then restarted by Android. – David Wasser Nov 11 '15 at 18:51
  • Thanks for the tip @DavidWasser. However, my problem is that in onDestroy, I save certain information to a file (smthg like summary). If the service crashes, any data that is not saved to the file will be lost. That's why I wanted to 'catch' the signal that forces the service to crash. – Konstantinos Nov 12 '15 at 17:06
  • You can't catch that signal. The operating system kills your process. You probably need to update your summary on a regular basis and not assume that `onDestroy()` will be called. – David Wasser Nov 13 '15 at 15:19
  • I found that with `onTaskRemoved(Intent intent)` I can catch those events and close my files properly. – Konstantinos Dec 11 '15 at 10:11
0

Maybe it can be a problem with Broadcast receivers defined in the manifest.

Do you have some receiver / intent-filter defined in your manifest at application level ? I used to have same kind of problem and it was due to receiver declared in the manifest at the application level

guikk
  • 195
  • 5
0

By swiping, your process is NOT guaranteed to be killed by the system get killed. No. You only remove the applciation task (or back stack). Application task is NOT equal to the application process.

So if you have any background jobs (threads, services etc) tied to your back stack and you have a good cancellation policy. The system may try to cache your process if it's suitable for later.

If you kill the app process(es) from the Task Manager though, then it means that your process will be removed and so your JVM/sandbox aggressively by the system.

stdout
  • 2,471
  • 2
  • 31
  • 40
  • This isn't true. The behaviour of "swipe from recent task list" is different in different Android versions. On some versions of Android, swiping a task from the list does indeed kill all of the app's processes. – David Wasser Nov 13 '15 at 15:21
  • Himm then It doesn't wrong either :). Could u please provide the versions? – stdout Nov 14 '15 at 18:35
  • I believe there isn't any concrete documentation that clearly identifies the point. But from the definitions of task, process and application I read from different resources it strongly seems to me that removing a task from Recents (or Overview screen) may or may not delete the process(es) itself, depending on the current situation of the device. If there is no enough space for other/foreground/important (you name it) processes then it will brutally kill the process either but if there is no such thing, then the process will be alive since it's the point of the android design - multitasking. – stdout Nov 16 '15 at 07:38
-2

Use *START_NOT_STICKY* as onStartCommand return

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.v(TAG, "onStartCommand");
    return START_NOT_STICKY;
}
Walter
  • 67
  • 12
  • 5
    This will just prevent the service from automatically restarting after it's killed, but it wont prevent the service from getting killed. – levi Dec 25 '13 at 16:27
  • @levi of course it doesn't prevent from getting killed, it's simply avoid crash of app after swipe out – Walter Sep 09 '14 at 14:39