Keep a Service Running Even When Phone Is Asleep

Keep a Service running even when phone is asleep?

Note: This post has been updated to include the JobScheduler API of the Android Lollipop release. The following is still a viable way, but can be considered deprecated if you're targeting Android Lollipop and beyond. See the second half for the JobScheduler alternative.

One way to do recurrent tasks is this:

  • Create a class AlarmReceiver

    public class AlarmReceiver extends BroadcastReceiver 
    {
    @Override
    public void onReceive(Context context, Intent intent)
    {
    Intent myService = new Intent(context, YourService.class);
    context.startService(myService);
    }
    }

    with YourService being your service ;-)

If you require a wake lock for your Task, it is advisable to extend from WakefulBroadcastReceiver. Don't forget to add the WAKE_LOCK permission in your Manifest in this case!

  • Create a Pending Intent

To start your recurrent polling, execute this code in your activity:

Intent myAlarm = new Intent(getApplicationContext(), AlarmReceiver.class);
//myAlarm.putExtra("project_id", project_id); //Put Extra if needed
PendingIntent recurringAlarm = PendingIntent.getBroadcast(getApplicationContext(), 0, myAlarm, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarms = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
Calendar updateTime = Calendar.getInstance();
//updateTime.setWhatever(0); //set time to start first occurence of alarm
alarms.setInexactRepeating(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), AlarmManager.INTERVAL_DAY, recurringAlarm); //you can modify the interval of course

This code sets up an alarm and a canceable pendingIntent. The alarmManager gets the job to repeat the recurringAlarm every day (third argument), but inexact so the CPU does wake up approximately after the interval but not exactly (It lets the OS choose the optimal time, which reduces battery drain). The first time the alarm (and thus the service) is started will be the time you choose to be updateTime.

  • last but not least: here is how to kill the recurring alarm

    Intent myAlarm = new Intent(getApplicationContext(), AlarmReceiver.class);
    //myAlarm.putExtra("project_id",project_id); //put the SAME extras
    PendingIntent recurringAlarm = PendingIntent.getBroadcast(getApplicationContext(), 0, myAlarm, PendingIntent.FLAG_CANCEL_CURRENT);
    AlarmManager alarms = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
    alarms.cancel(recurringAlarm);

This code creates a copy of your (probably) existing alarm and tells the alarmManager to cancel all alarms of that kind.

  • of course there is also something to do in the Manifest:

include these two lines

  < receiver android:name=".AlarmReceiver"></receiver>
< service android:name=".YourService"></service>

inside the < application>-tag. Without it, the system does not accept the start of recurrent alarm of a service.


Starting with the Android Lollipop release, there's a new way of solving this task elegantly.
This also makes it easier to only perform an action if certain criteria such as network state are met.

// wrap your stuff in a componentName
ComponentName mServiceComponent = new ComponentName(context, MyJobService.class);
// set up conditions for the job
JobInfo task = JobInfo.Builder(mJobId, mServiceComponent)
.setPeriodic(mIntervalMillis)
.setRequiresCharging(true) // default is "false"
.setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED) // Parameter may be "ANY", "NONE" (=default) or "UNMETERED"
.build();
// inform the system of the job
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(task);

You may also provide a deadline with setOverrideDeadline(maxExecutionDelayMillis).

To get rid of such a task, just call jobScheduler.cancel(mJobId); or jobScheduler.cancelAll();.

How to make service run even in sleep mode?

If you want to ensure that your service is not killed/reclaimed by the OS you need to make it a foreground service. By default all services are background, meaning they will be killed when the OS needs resources. For details refer to this doc

Basically, you need to create a Notification for your service and indicate that it is foreground. This way the user will see a persistent notification so he knows your app is running, and the OS will not kill your service.

Here is a simple example of how to create a notification (do this in your service) and make it foreground:

Intent intent = new Intent(this, typeof(SomeActivityInYourApp));
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this);

builder.setSmallIcon(Resource.Drawable.my_icon);
builder.setTicker("App info string");
builder.setContentIntent(pi);
builder.setOngoing(true);
builder.setOnlyAlertOnce(true);

Notification notification = builder.build();

// optionally set a custom view

startForeground(SERVICE_NOTIFICATION_ID, notification);

Please note that the above example is rudimentary and does not contain code to cancel the notification, amongst other things. Also, when your app no longer needs the service it should call stopForeground in order to remove the notification and allow your service to be killed, not doing so is a waste of resources.

Keep app service active during device sleep

It depends on the Android version, for version older than 6 a partial wakelock is enough to keep the device awake, for Android 6 you also need a foreground service, that's a Service that calls startForeground() and shows a notification, but to keep the device awake has a big impact in battery usage.

You do not necessarily need to transfer all the code to the Service due it is the whole application that stays awake.

A more elegant solution to replace all this would probably be to use Push Notifications, it is what most messaging applications use. Firebase has Push Notifications.

Service is killed in sleep mode.Why?

The murder mystery has been solved, and I know what killed my service. Here's what I did:

  1. After I realized that startsticky, startforeground, alarmmanager, scheduleTaskExecutor, and even wakelock were unable to save my service, I realized the murderer couldn't be the Android system, because I had taken every measure possible to prevent the system from killing my service and it still would get killed.
  2. I realized I needed to look for another suspect, since the service wasn't dying because of the system. For that, I had to run an investigation. I ran the following command:

    adb shell dumpsys activity processes > tmp.txt

This would give me a detailed log of all the processes running and their system priorities. Essentially, tmp.txt would be the detective in this murder mystery.


  1. I looked through the file with lots of detail. It looked like my service was prioritized properly by the system:

    Proc #31: adj=prcp /FS trm= 0 2205:servicename.service/uID (fg-service)

The above line indicates the exact priority of a process running on the Android device. adj=prcp means the service is a visible foreground service.

At this point, I realized that my service must be encountering some error a couple hours after running, so I let it run and die. After it died, I produced a dumpsys again to examine the error:


  1. At this point, my service wasn't listed as a task in the tmp.txt file. Excited, I scrolled to the bottom of the dumpsys and solved the mystery!

com.curlybrace.ruchir.appName.MyService$2.onForeground(MyService.java:199)
at com.rvalerio.fgchecker.AppChecker$2.run(AppChecker.java:118)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)

The stack trace that caused the killing of my service was displayed right there! Essentially, a variable that would check for the foreground app being used would become null after a few hours of inactivity, which would cause an exception, and kill the service!

Key Takeaways:
If your service is getting killed, and you've done everything you can to make sure that it shouldn't be killed, perform a dumpsys and examine the nitty gritty of your device's activity process. I guarantee you will find the issue that way.

I still would like to have the bounty awarded to @Khemraj since his answer could be a great solution for someone who hasn't started their service properly. However, I am accepting this answer since it is the solution that actually fixed the issue.



Related Topics



Leave a reply



Submit