'Understanding & testing Android M+ Doze Mode

I am working on making my Android app a good citizen of the post Android M world which imposes severe constraints on what an app can/cannot do when the device goes into doze. My understanding of the issues involved is still rather fragmentary so I am hoping that someone here can fill the gaps.

The duration of doze

My own empirical findings here

  • Doze first starts within about half an hour of stationary, screen-off, inactivity
  • The first maintenance window happens within 30 minutes
  • The next one happens in about an hour
  • The ones after than in ca 2, 4 and 6 h. I have not tested beyond that

Are these the official Android doze periods or is it just one empirical observation.

All of the above on an Android N device.

Testing Apps in Doze Mode

  • Connect the device to a computer with ADB
  • Bring the app to the foreground
  • Turn off the device screen
  • From the command line issue adb shell dumpsys battery unplug
  • Now cycle through the commands `adb shell dumpsys deviceidle step light OR deep
  • finally issue adb shell dumpsys battery reset

Entering/Exiting Doze

  • Happens when the screen is off and the device is not being subjected to movement

  • Presumably this uses the motion sensor in the phone so a phone sitting quietly on a remarkably smoothly moving train will still enter doze?

  • If I pick up a dozing phone and start walking around with it without otherwise interacting with it will it automatically exit doze?

  • Suppose my app is not in the foreground when its host device enters doze. Then I start using the device again but without visiting that app. Will it automatically start "working" again, i.e.

  • Its broadcast receivers will become functional?

  • Its handlers will start working?

  • Its scheduled jobs with setRequiresDeviceIdle(true) will stop being called?

The various modes of Doze & Job Scheduling

  • From what I have understood there are two doze modes LIGHT & DEEP. They both have sub-modes

  • LIGHT:Active, Idle, Idle_Maintenance,Override. I do not understand what the various modes do. From ADB I have issued step light with the screen on and seen the return value ACTIVE. With the screen off step light returns IDLE.

  • DEEP: Active,IDLE_PENDING,SENSING,LOCATING,IDLE,IDLE_MAINTENANCE with the screen on too returns ACTIVE but with the screen off it returns IDLE_PENDING. So when exactly do the other sub modes, IDLE, SENSING... happen?

I assume that IDLE_MAINTENANCE happens when the device enters a maintenance window from DOZE and attempts to run pending Job requests from various apps.

But if that is the case why is it that PowerManager.isDeviceIdleMode() and PowerManger.isPowerSaveMode() ALWAYS return false when I check them when a schedule job in my app runs?

JobInfo.Builder very kindly allows you to set criteria such as setMinimumLatency and setOverrideDeadline but as far as I can tell the OS hen goes and blithely ignores them - at times I have had jobs running withtin seconds of each other and at other times as far as two hours apart.

Why is there no API function to test for Doze and its sub modes? I would expect to find it in PowerManager but all I find there are isDeviceIdleMode and isPowerSaveMode which consistently return false whenever tested

The App in Doze Mode

  • Will have all its background services destroyed?

  • Will not get normal priority push messages?

  • Will not respond to alarms - but is that with the exception of setAndAllowWhenIdle?

  • Will get no comms from any of its broadcast receivers?

  • Will not be able to connect to the outside world on sockets - so push messaging, pub/sub etc will not work?

  • Will immediately destroy any broadcast receivers declared in the Android manifest. This has been my own finding - receivers that I create from Java code stay put, though they do not work during doze.

My own app watches for geo location changes by setting up a broadcast receiver and calling .FusedLocationApi.requestLocationUpdates. This receiver survives the doze/wakeup cycle. However, is there a guarantee my LocationUpdates request still being honored after wake up?

I have run into a rather peculiar bug. I found that my scheduled jobs in doze ran too close to one another on occassion even though I have given them a latency of 900,000 ms (15 minutes) and a deadline of 1,000,000 ms. I thought I would get round this by testing for the last time the job was run by keeping track of the last run time which I did thus

private static Boolean shortInstantGap()
{
  Long instantNow = Instant.now().getEpochSecond();
  if (300 > (instantNow - this.lastInstant)) return true;
  //ignore the job opportunity if the last one was
  //less than 300s (5 minutes) ago
  this.lastInstant = instantNow;
  return false;
 }

and then aborting the job slot

private static Runnable timeRunner = new Runnable() 
{
 @Override
 public void run() 
 {
  if (shortInstantGap()) return;
  callMyHandlerCode();
 }
};

However, I found that this code causes the OS to abruptly terminate my app if it is on screen when I go through a screen-off screen-on cycle. Why was that happening?

Finally, is there not an API call I can use to test that the device has just returned from doze so I get an opportunity to do some post doze housekeeping?



Solution 1:[1]

I think good post and questions on this thread, thanks. Really hope Android OS will improve push notification delays. Sometimes it doesnt get notification for an hour if you dont touch the screen. It may be good for some users due to battery saving but optimising push notification along with battery optimisation can be win win for everyone.

Anyway, here my 2 cents, are a few little tips my for those who want to analyse dozing stuff and those not aware of these already:

Wireless debugging feature can be used to connect device with computer/adb tools. So no need a usb cable and charging the phone while connected doing tests. I think since Android 11 most devices has wireless debugging option under developer options, this works natively without a usb cable setup. If no wifi debugging available(Android versions before 11) then usb cable can be used to setup it.

"adb shell dumpsys deviceidle" this command summarize some info like status of doze and sub states, can be used to check current status during doze/app testings.

You can check other adb doze commands and their effects like forcing doze, enable/disable it etc. online.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1