50

I am using Service in my application and it needs to run until my application is uninstalled, but the problem is it gets killed by OS.

How can we prevent it from being killed by OS? Or if it gets killed can we restart that service again through programmatically?

Andrew T.
  • 4,701
  • 8
  • 43
  • 62
Rahul
  • 757
  • 2
  • 8
  • 13

11 Answers11

48

You may run the service in the foreground using startForeground().

A foreground service is a service that's considered to be something the user is actively aware of and thus not a candidate for the system to kill when low on memory.

But bear in mind that a foreground service must provide a notification for the status bar (read here), and that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.

Note: This still does not absolutely guarantee that the service won't be killed under extremely low memory conditions. It only makes it less likely to be killed.

Community
  • 1
  • 1
Dheeraj Vepakomma
  • 26,870
  • 17
  • 81
  • 104
  • 3
    Thanks for ur reply Dheeraj but i dont need notification in service is there any other way to run service without gets killed by os.. Did you know Wake_Lock.. – Rahul Mar 14 '12 at 06:58
  • 2
    i have merged code in my service what u have given me a link startForeground(). but my service is also gets killed by os after sometimes . – Rahul Mar 14 '12 at 08:56
  • @Rahul u got any solution for this? – PankajAndroid Nov 13 '13 at 05:54
  • 6
    It's just the way Android handles low memory situations. If you really needed Android not to kill your service, your best bet would be to make it a System App, or make your service return `START_STICKY` in your `onStartCommand()` method. This way, if your service gets killed, then it will be queued to restart automatically. – Jason John Jul 18 '14 at 17:09
  • Or return START_REDELIVER_INTENT ( as well as returning START_STICKY ) from onStartCommand() method. – stdout Aug 15 '16 at 12:25
  • I did it still closing it. – Neon Warge Mar 08 '17 at 04:08
  • Does android:process=”: remote will work if background data is OFF or Battery Saver is ON? – Rajesh N Sep 30 '17 at 07:09
21

I've been puzzled by the same issue to yours recently.but now,I've found a good solution. First of all,you should know that, even your service was killed by OS, the onCreate method of your service would be invoked by OS in a short while.So you can do someting with the onCreate method like this:

@Override
public void onCreate() {
    Log.d(LOGTAG, "NotificationService.onCreate()...");
    //start this service from another class
    ServiceManager.startService();
}
@Override
public void onStart(Intent intent, int startId) {
    Log.d(LOGTAG, "onStart()...");
    //some code of your service starting,such as establish a connection,create a TimerTask or something else
}

the content of "ServiceManager.startService()" is:

public static void startService() {
    Log.i(LOGTAG, "ServiceManager.startSerivce()...");
    Intent intent = new Intent(NotificationService.class.getName());
    context.startService(intent);
}

However, this solution is just available for the situation of your service being killed by GC.Sometimes our service might be killed by user with Programme Manager.In this situation,your prosses will be killed,and your service will never been re-instantiated.So your service can not be restarted. But the good news is,when the PM kill your service,it will call your onDestroy method.So we can do something with that method.

    @Override
public void onDestroy() {
    Intent in = new Intent();
    in.setAction("YouWillNeverKillMe");
    sendBroadcast(in);
    Log.d(LOGTAG, "onDestroy()...");
}

The string of "YouWillNeverKillMe" is a custom action. The most important thing of this method is,don't add any code before send the broadcast.As system will not wait for completion of onDestroy(),you must send out the broadcast as soon as posible. Then regist a receiver in manifast.xml:

<receiver android:name=".app.ServiceDestroyReceiver" >
        <intent-filter>
            <action android:name="YouWillNeverKillMe" >
            </action>
        </intent-filter>
    </receiver>

Finally,create a BroadcastReceiver,and start your service in the onReceive method:

@Override
public void onReceive(Context context, Intent intent) {
    Log.d(LOGTAG, "ServeiceDestroy onReceive...");
    Log.d(LOGTAG, "action:" + intent.getAction());
    Log.d(LOGTAG, "ServeiceDestroy auto start service...");
    ServiceManager.startService();
}

Hope this will be helpful to you,and excuse my poor written english.

Alaowan
  • 251
  • 2
  • 3
  • Tested on Android 4.0.4 and looks promising so far! – Alexandre Lavoie Apr 12 '14 at 06:51
  • 3
    @Alaowan: You have placed the restart code in different places.If the service is killed by GC or for that matter PM,then in either case if onDestroy is called,then isnt it much better to called startService in the onDestroy itself,as mentioned in the answer by [at]androidiseverythingforme ? – Basher51 Oct 07 '14 at 06:49
  • I don't think your code to stop the service being killed by the GC even makes sense; you have to wait for the service to be restarted by the OS in order to run code to restart your service. What's the point of the service starting itself when it's started? I even tested this out and confirmed that it doesn't work. And I've generally found it takes a couple of minutes before the OS restarts a sticky service. – Sam May 08 '15 at 08:42
  • 2
    Your code to prevent users from stopping the service does more harm than good since I think users should have control over their own devices; it's annoying for them if you try to stop them from manually killing your services. I know there could be some situations where this is appropriate, but this question is about stopping the *OS* from killing the service. – Sam May 08 '15 at 08:43
  • On Note 5 and Galaxy S6 running 5.0.1, OnDestroy() is not called in case where service is killed by GC. Do you have any idea how to resolve this ? – DaniZ Feb 17 '16 at 07:21
  • 3
    Please do not upvote this answer. This is not correct. – blueether Jul 05 '16 at 02:57
  • I'm gonna lay this out there with arms wide open for criticism, but if devs want a service running forever for app's intended behavior, it kinda trumps user's ad-hoc control. Effective control is never taken away with Uninstall. System apps WILL do this, while snooping or serving ads or even providing backdoors, and they pass Google certification. Some even grey out Disable... Away from Android, even Win and *nix have things you can't control. The problem isn't the OS killing the service - it's the fact JVM has a "godmode" GC that won't always warrant graceful degradation, thus apps can't cope – leRobot Mar 23 '18 at 17:33
10

Override method onStartCommand() in your service class and simply return START_STICKY (as suggested by "Its not blank"). That's all you need. If the process that runs your service gets killed (by a low memory condition for example), the Android system will restart it automatically (usually with some delay, like 5 seconds).

Don't use onStart() anymore as suggested in another answer, it's deprecated.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
Chris
  • 1,559
  • 1
  • 12
  • 6
  • 1
    Note that this is the default behaviour for services anyway, so I don't think you even need to explicitly do this. – Sam May 08 '15 at 08:27
9

use

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    //**Your code **
    // We want this service to continue running until it is explicitly
    // stopped, so return sticky.
    return START_STICKY;
} 

ref Documentation lifecycle of Service.

Edit added method.

Ziem
  • 6,579
  • 8
  • 53
  • 86
Its not blank
  • 3,055
  • 22
  • 37
  • 2
    Vincent i have used your method but my service is again gets killed by os after sometimes..is there any other way to do that. – Rahul Mar 14 '12 at 10:43
  • I use START_NOT_STICKY – yozawiratama Jul 21 '14 at 04:07
  • 6
    This seems misleading to me; I don't think `START_STICKY` stops the service from being killed. I think it causes it to restart if it crashes or is killed by the OS. – Sam May 08 '15 at 08:28
7

As far i know, onDestroy() will be called only when the service is explicitly stopped(Force Stop). But this method won't get called in case the service gets killed by OS/swiping the Recent Apps list. In those cases another event handler named onTaskRemoved(Intent) gets called. This is due to a defect in Android 4.3-4.4 as per the link here. Try using the below code:-

public void onTaskRemoved(Intent intent){
super.onTaskRemoved(intent);
Intent intent=new Intent(this,this.getClass()); 
startService(intent); 
}
Karthik
  • 184
  • 1
  • 3
  • 11
5

I found another solution of the problem which gurantees that your service will be always alive. In my case, this scheme resloves also the problem with FileObserver, which stops work after some period of time.

  1. Use an activity (StartServicesActivity) to start the service (FileObserverService) as Foreground service.
  2. Use BroadcastReceiver class (in example CommonReceiver) to restart your service in some special situations and in case it was killed.

I used this code in my app "Email Pictures Automatically" https://play.google.com/store/apps/details?id=com.alexpap.EmailPicturesFree

Here is CommonReceiver class.

public class CommonReceiver extends BroadcastReceiver {

    public void onReceive(Context paramContext, Intent paramIntent)
    {
        paramContext.startService(new Intent(paramContext, FileObserverService.class));
    }
}

Here is its definition in AndroidManifest.xml just before application closing tag.

<receiver android:name="com.alexpap.services.CommonReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
    </intent-filter>
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.USER_PRESENT"/>
    </intent-filter>
</receiver>

Start service in StartServicesActivity activity.

Intent iFileObserver = new Intent(StartServicesActivity.this, FileObserverService.class);
StartServicesActivity.this.startService(iFileObserver);

Here is onStartCommand() method of the service.

public int onStartCommand(Intent intent, int flags,  int startId) {

    int res = super.onStartCommand(intent, flags, startId);

    /*** Put your code here ***/

    startServiceForeground(intent, flags, startId);

    return Service.START_STICKY;  
}

public int startServiceForeground(Intent intent, int flags, int startId) {

    Intent notificationIntent = new Intent(this, StartServicesActivity.class); 
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

    Notification notification = new NotificationCompat.Builder(this)
        .setContentTitle("File Observer Service")
        .setContentIntent(pendingIntent)
        .setOngoing(true)
            .build();

    startForeground(300, notification);

    return START_STICKY;
}

I tested this code using Task Killer app, and each time the service was killed, it was restarted again almost immediately (performs onStartCommand()). It is restarted also each time you turn on the phone and after rebooting. I use this code in my application, which emails every picture you take with your phone to predefinde list of emails. The sending email and list of receiving emails are set in another activity and are stored in Shared Preferences. I took about 100 pictures in several hours and all they were sent properly to receiving emails.

AlexPap
  • 191
  • 2
  • 5
  • 1
    Not workign on Lenovo K3 Note. Problem is that when app is killed from launcher, onTaskRemoved / onDestroy are not called. Also, once app is killed, the broadcast receivers are also not invoked for the event filters indicated above (boot_complete/connectivity_change), etc. The best you can do in these scenarios is to start as foreground service, as mentioned by @Dheeraj – blueether Jul 05 '16 at 03:17
3
@Override
public void onDestroy() {

    super.onDestroy();
    startService(new Intent(this, YourService.class));

}

write above code in your service and your service will never stop even user want to destroy it or they want to kill it it will never kill untill your app not get uninstall from your device

  • Is onDestroy of a service called in everycase when a service is killed(say due to GC,Process manager etc etc) ? If so then your solution looks the most sleek .Can you please confirm this as I am facing this issue for quiet sometime of service getting killed? – Basher51 Oct 07 '14 at 06:52
  • 1
    @Basher51, no; from my experience, `onDestroy` isn't always called when a service is killed. – Sam Nov 14 '14 at 23:32
  • 1
    @Sam: Could you please share any specific cases were you have observed that the onDestroy is not called ? – Basher51 Nov 15 '14 at 12:45
  • 4
    @Basher51, 1. When the app is upgraded; 2. When the OS kills it due to low RAM; 3. When the app crashes. – Sam May 08 '15 at 08:22
  • 1
    In my opinion, this code makes things worse. When the OS kills your service, this doesn't work. When the user kills your service, this *does* work, which I think is a bad thing since it takes control away from the user. Also, when you try to stop the service in your code using `stopService`, this prevents it from working, which I think is also a bad thing. – Sam May 08 '15 at 08:28
  • 1
    This works well, just what I was looking for and much simpler than other answers, thanks. Even if I kill it, it again starts :) – Shahbaz Talpur Oct 23 '16 at 17:20
2

You can try to start your service repeatedly, for example every 5 sec. This way, when your service is running, it will perform onStartCommand() every 5 sec. I tested this scheme and it is very reliable, but unfortunately it increases slightly phone overhead. Here is the code in your activity where you start the service.

Intent iFileObserver = new Intent(StartServicesActivity.this, FileObserverService.class);
PendingIntent pendingIntentFileObserver = PendingIntent.getService(StartServicesActivity.this, 0, iFileObserver, 0);
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
Date now = new Date();

    //start every 5 seconds
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, now.getTime(), 5*1000, pendingIntentFileObserver);

And here is onStartCommand() of the service.

//class variable
public static boolean isStarted = false;

public int onStartCommand(Intent intent, int flags,  int startId) {

    int res = super.onStartCommand(intent, flags, startId);

    //check if your service is already started
    if (isStarted){      //yes - do nothing
        return Service.START_STICKY;
    } else {             //no 
        isStarted = true;
    }


    /**** the rest of your code  ***/

    return Service.START_STICKY;

}
AlexPap
  • 191
  • 2
  • 5
0

First create service in another process, and write broadcaster which runs in recursion in time intervals

protected CountDownTimer rebootService = new CountDownTimer(9000, 9000) {


    @Override
    public void onTick(long millisUntilFinished) {


    }

    @Override
    public void onFinish() {

        sendBroadcast(reboot);
        this.start();
        Log.d(TAG, "rebootService sending PREVENT AUTOREBOT broadcast");


    }

};

After that register broadcast receiver in main process also with timer recursion that is launched after first broadcast from service arrived

protected static class ServiceAutoRebooter extends BroadcastReceiver {

    private static   ServiceAutoRebooter instance = null;
    private  RebootTimer rebootTimer = null;

    private static ServiceAutoRebooter getInstance() {

        if (instance == null) {

            instance = new ServiceAutoRebooter();

        }
        return instance;

    }





    public class RebootTimer extends CountDownTimer {

        private Context _context;
        private Intent _service;


        public RebootTimer(long millisInFuture, long countDownInterval) {
            super(millisInFuture, countDownInterval);
        }


        @Override
        public void onTick(long millisUntilFinished) {

        }


        @Override
        public void onFinish() {

            _context.startService(_service);
            this.cancel();
            Log.d(TAG, "Service AutoRebooted");


        }


    }


    @Override
    public void onReceive(Context context, Intent intent) {

        if (rebootTimer == null) {
            Log.d(TAG, "rebootTimer == null");

            rebootTimer = new RebootTimer(10000, 10000);
            rebootTimer._context = context;

            Intent service = new Intent(context, SomeService.class);
            rebootTimer._service = service;
            rebootTimer.start();

        } else {

            rebootTimer.cancel();
            rebootTimer.start();
            Log.d(TAG, "rebootTimer is restarted");

        }


    }


}

Service will be auto-rebooted if time at RebootTimer (main process) expires, which means that "PREVENT AUTOREBOT" broadcast from service hasn't arrived

-3

i found a solution .... late answer but i wanted to answer...

we can send a broadcast in the ondestroy of the service and create a receiver that receives the broadcast and starts the service again.... when it is destroyed by any reasons...

user1106888
  • 245
  • 3
  • 14
  • This isn't true; it only seems to cover the cases when the user or developer stop the service in my experience. – Sam May 08 '15 at 08:30
-4

pls try following:

final Messenger mMessenger = new Messenger(new IncomingHandler()); 
class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            default:
                super.handleMessage(msg);
            }
        }
}

@Override
public void onCreate() {
    super.onCreate();
    makeServiceForeground();
}


@Override
public IBinder onBind(Intent arg0) {
    return mMessenger.getBinder();
}


private void makeServiceForeground() {
    IActivityManager am = ActivityManagerNative.getDefault();
    try {
        am.setProcessForeground(onBind(null), android.os.Process.myPid(), true);
    } catch (RemoteException e) {
        Log.e("", "cant set to foreground" + e.toString());
    }
}

also need add in manifest.xml

<uses-permission android:name="android.permission.SET_PROCESS_LIMIT"/>
m0narX
  • 1
  • 3
  • yeah)) but on system apps – m0narX Aug 24 '13 at 13:11
  • 2
    This is overcomplicated. You can just use the public method, `Service.startForeground` rather than these private APIs. And foreground processes can still be killed by the OS in low memory situations. – Sam May 08 '15 at 08:32