Behaviour in Android Doze when using different Scheduler - android

I'm trying to optimize our app for Doze and AppStandBy and have implemented a
test application to understand the behaviour of the system when using different background schedulers.
However I'm very confused about the behaviour when using AlarmManager and Observable.intervall().
AlarmManager
I have registered an alarm through an Activity and then brought the device via adb in Doze.
The system behaves as expected, the alarm is not fired.
Rx-Observable.intervall
I have started a Service through an Activity and then brought the device via adb in Doze. The Service is NOT a foreground service.
The system does not behave as expected in my eyes and the ticks are continuous delivered to the app.
To veryfy that the device was really in Doze I also reviewed the battery statistics with adb bugreport, and the historian tells me that the device was in Doze in that timespan.
Is there any documentation how the different schedulers work in Doze or AppStandBy?
Thanks for any advice.

The problem seems to be that adb keeps the CPU running (if the device is connected via usb) even if the device brought to doze by adb with the commands
$ adb shell dumpsys battery unplug
$ adb shell input keyevent KEYCODE_POWER
adb shell dumpsys deviceidle step
The interval timer scheduled by ScheduledThreadPoolExecutor (used by rxjava) seems not to be restricted in doze mode but alarms via AlarmManager do.

Related

Android - Disable Forced DozeMode or AppStandByMode

I have an application that uses a ForegroundService to send location updates to a server. Basically a tracker.
This ForegroundService has a Handler that periodically (using postDelayed) executes a block of code to send the location.
This works perfectly fine, when the app is in the foreground and even in the background, but I started to notice a delay when the phone is locked, with the screen off for about 15minutes. I mean, 15 minutes of no user activity and no charger plugged.
This is happening on a Android Q (v10) device. I'm assuming this would also happen on any device running Oreo onwards.
Let's make it clear... My app send the location every 30sec, but when entering what I suppose is the DozeMode or AppStandByMode, it continues sending the location, but every 2 minutes (more or less). If I turn the screen on, or plug-in the charger it inmediately come back to the 30sec pace. That's what makes me thing about the DozeMode or AppStandByMode. Moreover, if I leave the phone untouched, but with the charger plugged in, then this never happens.
As said, I'm pretty sure the DozeMode or AppStandByMode is kicking in, and I know I can whitelist my app to prevent that. But before going further I would like to reproduce this without the need to wait those 15minutes every time I want to test the behavior of my app.
So I "googled" how I can force this and here's what I've found:
For DozeMode (see source)
adb shell dumpsys battery unplug
adb shell dumpsys deviceidle step deep
And continue to execute the last command until reaching IDLE state.
For AppStandByeMode (see source)
adb shell dumpsys battery unplug
adb shell am set-inactive packageName true
And query the state with this other command:
adb shell am get-inactive packageName
which I confirm it returns Idle=true
I also even do as this other blog suggest, issuing:
adb shell dumpsys deviceidle force-idle
I though I was not getting in this mode, but now it seems I am and I can not get out of it... See the update
UPDATE
At first I thought I was not entering the DozeMode... Now I can confirm I'm in, but it always triggers inmediately. (no more waiting those 15min)
Whenever I lock the phone and screen goes off, it automatically enters the doze mode and begin spacing the location updates. I plug the charger and then again sends them at 30sec.
I've try:
adb shell dumpsys deviceidle unforce
adb shell dumpsys deviceidle disable
adb shell dumpsys battery reset
and still the same.
Also:
power-down and power back up the phone
uninstall the app
change battery optimization to NOT OPTIMZE inside the app settings
Did I miss a step?
Except for Doze mode, Android 9 extended the concept of AppStandby with App Standby Buckets.
Along with network restrictions, an app that is in a low priority bucket will be affected in the frequency of running Jobs, triggering Alarms, and receiving FCM messages.
You can get your app's current bucket using this command:
adb shell am get-standby-bucket your.package.name
You can set the bucket and see how your app behaves using this command:
adb shell am set-standby-bucket your.package.name <never/rare>
I wrote an article that summarizes all changes regarding background process limitations over the years: https://rotemmatityahu.medium.com/workmanager-does-it-always-manage-to-work-fd8518655052

Should a device behave as if nothing happened during Battery tests?

I need to test whether an app behaves correctly after restoring from Doze / App standby. The thing is that when I use commands from the Android Developers site, nothing happens with either the app nor with the device itself. The command prompt seems to respond correctly though.
Commands for Doze:
adb shell dumpsys deviceidle unforce
adb shell dumpsys battery reset
Commands for App Standby:
adb shell dumpsys battery unplug
adb shell am set-inactive <packageName> true
Wake up from App Standby:
adb shell am set-inactive <packageName> false
adb shell am get-inactive <packageName>
https://developer.android.com/training/monitoring-device-state/doze-standby.html#testing_doze_and_app_standby
Do you think that if nothing bad happens to the app, it means that it is behaving correctly? Or have I made some mistakes during the tests? I'm asking because from what I've read on the internet, the Doze should trigger with at least locked screen, so it all looks suspicious to me. I don't have any other ideas how to confirm whether these commands actually work.
With the Doze test, make sure you force the system into idle mode by running the following command first:
adb shell dumpsys deviceidle force-idle
But otherwise the commands you are running look correct.
You primarily want to test that the app returns to a good state after being in Doze or App Standby mode, and that any restrictions in place during that mode are lifted. The restrictions Doze and App Standby may impose on apps include limited or no network access, suspended background tasks, suspended Notifications, ignored wake requests, and alarms.
If your app can send notifications or trigger alarms, you can test that those are blocked during this mode.
According to the Android docs:
Observe the behavior of your app when it is woken. Make sure it
recovers gracefully from standby mode. In particular, you should check
if your app's Notifications and background jobs continue to function
as expected.

How long does an App need to be idle for App Standby to kick in (Android Marshmallow)

I've looked all over the internet to find specifics about App Standby mode in Android Marshmallow, but I've not found any specific data for when it happens, other than some listed conditions that might cause it to happen. I also see a nebulous "If the device is idle for long periods of time, the system allows idle apps network access around once a day" without any specifics about how long this window would be.
Doze mode seems pretty well researched (This gist was particularly helpful and consistent with my findings), but I haven't been able to see App Standby in action. I created a test app that sends data to a server every 5 minutes via an Alarm and ran it for a week, and it continued to hit the server every 5 minutes unless the phone went into Doze mode and only hit the server in maintenance periods, then go back to every 5 minutes when the phone was awoken, so it did not appear that Android ever put it in "App Standby" state even though I didn't directly interact with the app.
Is there any specific data on how App Standby works?
You can force the device to enter this mode using the code below:
adb shell dumpsys deviceidle enable
adb shell dumpsys battery unplug
adb shell dumpsys deviceidle step
adb shell dumpsys deviceidle force-idle

Doze mode and foreground service

Checking my app's behavior on M Preview device, it seems that its foreground (with active notification) service playing music is not affected by Doze mode.
But reading docs it seems that foreground services are exempt only from AppStandby.
What is the real rule?
In this post's comments on Sep 17 Dianne Hackborn writes:
Apps that have been running foreground services (with the associated notification) are not restricted by doze.
So yes, your findings seem to be the intended behavior.
Attention, Foreground service can prevent your app never into app standby, but not doze.
Here use adb cmd to test
$ adb shell dumpsys battery unplug
$ adb shell am set-inactive <packageName> true

Does the Android M Doze state have multiple states itself?

I slightly modified this app :https://github.com/commonsguy/cw-omnibus/tree/master/JobScheduler
It set alarms using setExactAndAllowWhileIdle and schedules an alarm to go off every 1 minute and log it.
According to Doze documentation, if this app is running while the phone is in Doze mode, only one alarm should be going off per 15 minutes. I'm not seeing that behavior .
On a a nexus 5 running Android M. After starting the app and the whole alarm scheduling process, I put the phone into Doze using the provided abd commands...
adb shell dumpsys battery unplug
adb shell dumpsys deviceidle step
adb shell dumpsys deviceidle -h
...From the log, I have seen around 30 minutes of alarms going off once per minute, then finally they are 15 minutes apart for about an hour. Then back to once per minute, and then back to 15 minutes apart. The phone was completely undisturbed during the test.
Does anyone know why this is? I was under the impression that the phone would immediately be in Doze mode after those adb commands , and that the alarms would be going off 15 minutes apart from the start.
Thanks for your help.
For one thing, the relevant adb command docs are incomplete, as you noted in the link to ISSUE 2930.
The following command merely prints usage info:
adb shell dumpsys deviceidle -h
The following command will display the current state including the prerequisites (enabled, not moving, not charging, screen off) for getting into IDLE:
adb shell dumpsys deviceidle
Settings:
...
Whitelist (except idle) system apps:
...
Whitelist (except idle) all app ids:
...
mEnabled=true
mForceIdle=false
mSigMotionSensor=null
mCurDisplay=...
mScreenOn=false
mCharging=false
mSigMotionActive=false
mState=INACTIVE
That shows whether you need to do more setup. E.g. it seems to take 2 or 3 taps on the emulator's power button to get mScreenOn=false.
The following command steps towards IDLE mode, but ISSUE 2930 explains that you need to step multiple times to get to INACTIVE, IDLE_PENDING, SENSING, then IDLE:
adb shell dumpsys deviceidle step
The following command will force it into idle:
adb shell dumpsys deviceidle force-idle
BTW the developer docs on Doze and App Standby were improved recently.
The rate limit for setExactAndAllowWhileIdle is different when the device is in idle mode. I'm guessing it's taking you 30 minutes for your phone to enter idle mode via Doze, at which point you'll be limited to calling setExactAndAllowWhileIdle once every 15 minutes.
In Doze mode, your phone will wake up periodically for an Idle Maintenance period of up to 10 minutes. During those 10 minutes it will wake up from idle mode and your rate limit will be adjusted to once every minute. After the maintenance window ends, you're seeing it go back to once every 15 minutes.
The Idle Maintenance windows are described in the docs: http://developer.android.com/training/monitoring-device-state/doze-standby.html#understand_doze

Categories

Resources