'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 valueACTIVE
. With the screen offstep light
returnsIDLE
.DEEP: Active,IDLE_PENDING,SENSING,LOCATING,IDLE,IDLE_MAINTENANCE with the screen on too returns
ACTIVE
but with the screen off it returnsIDLE_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 |