Getting location updates when in doze mode

6k views Asked by At

I'm trying to get location updates in my android app when in doze mode, this used to work up to android 5.x. With android 6 and the advent of doze, no matter what I do, the updates stop at some point. After reading a few articles and stackoverflow answers on the topic I made the following changes:

  • made my service a foreground service
  • made the service hold a partial wake lock
  • I've given my app the WAKE_LOCK permission
  • made the service run in a separate process (for a workaround to some android bug)
  • I've disabled battery optimizations for my app

But still, I'm not getting location updates when doze kicks in. I've verified that my service thread keeps running when doze starts (by periodically logging a message), but somehow the location manager stops sending updates. The documentation on doze and the LocationManager is pretty scant in this regard, so I was wondering if somebody knows of a way to keep the location manager alive in doze? Is there some method on LocationManager that if called periodically will keep the LocationManager active? Note that I'm interested in GPS updates only, with a high update frequency, once every second.

3

There are 3 answers

3
Kornelius Elstner On BEST ANSWER

In the end I found a workaround for the issue, after reading through the source code of com.android.internal.location.GpsLocationProvider I noticed that sending it an com.android.internal.location.ALARM_WAKEUP Intent prevented the location provider from dozing. So to keep the GPS from dozing I broadcast the Intent every 10 seconds, I added the following in my service class:

[...]
private Handler handler;
private PowerManager powerManager;

private PendingIntent wakeupIntent;
private final Runnable heartbeat = new Runnable() {
    public void run() {
        try {
            if (isRecording && powerManager != null && powerManager.isDeviceIdleMode()) {
                LOG.trace("Poking location service");
                try {
                    wakeupIntent.send();
                } catch (SecurityException | PendingIntent.CanceledException e) {
                    LOG.info("Heartbeat location manager keep-alive failed", e);
                }
            }
        } finally {
            if (handler != null) {
                handler.postDelayed(this, 10000);
            }
        }
    }
};

@Override
public void onCreate() {
    handler = new Handler();
    wakeupIntent = PendingIntent.getBroadcast(getBaseContext(), 0,
        new Intent("com.android.internal.location.ALARM_WAKEUP"), 0);
    locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
    powerManager = (PowerManager) getSystemService(POWER_SERVICE);
    wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "TrackService");
    [...]
}
3
mattm On

Your application's behavior is precisely what doze is designed to stop. Doze, introduced in Android 6, reduces a device's power usage by deferring activity to maintenance windows. GPS is a huge power draw and is not allowed to run constantly in doze mode. If this were allowed, the battery could run down at a rate similar to with the screen on; the optimizations for network traffic would not achieve increased battery life. If you want GPS location updates every 1 second, you must stop the device from entering doze mode.

There was no doze mode in Android 5.

0
Mateusz Wołkowicz On

If you test location and doze mode on the emulator with commands like "adb shell dumpsys deviceidle force-idle" etc. You probably noticed that location stops in Doze Mode.

But ... as "documentation" stands for :

"As soon as the user wakes the device by moving it, turning on the screen, or connecting a charger, the system exits Doze and all apps return to normal activity"

Source : https://developer.android.com/training/monitoring-device-state/doze-standby

So ... move Your emulator with GPS Joystick App or similar and You will notice that location wakes up from Doze Mode.