This is apparently semi-documented behavior, if comments from Dianne Hackborn on a G+ post constitute "documented": https://plus.google.com/+AndroidDevelopers/posts/94jCkmG4jff but foreground services associated with a notification icon should be allowed to keep a wake lock during doze mode.
It seems this is not valid when you have a top-activity in addition to the foreground service.
I have create a minimal implementation which demonstrates this: https://github.com/petrnalevka/dozetest/blob/master/src/com/urbandroid/doze/DozeService.java
The problem can be reproduced on
Android M, MRA58K Nexus 5 and MRA58N Nexus 6
My foreground service has an associated notification and I hold a partial wake lock. Unfortunately Doze mode takes over and my wake lock is broken. I was only able to prevent this by an opt-out from battery optimization or leaving the top activity.
I believe this is a bug in Android as there is no reason why foreground services should keep the wake lock but not if they have an activity on top.
I'm putting this issue on SO even I have already reported this on Androdi issue tracker here https://code.google.com/p/android/issues/detail?id=193802 in order to find workarounds as this is a crutial feature in order to not need the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS which apparently only mean REQUEST_REMOVAL_FROM_PLAYSTORE_BY_GOOGLE at the moment.
Here is how I was able to reproduce the issue using adb thanks to hints from +Dianne Hackborn:
It seems that when I keep an Activity in the foreground while having also the foreground service running my app is recognized by the Power manager as:
PARTIAL_WAKE_LOCK 'Doze lock' DISABLED (uid=10112, pid=24649, ws=null)
Proc # 0: fore F/A/TS trm: 0 24649:com.urbandroid.doze/u0a112 (top-activity)
If I press home and leave the activity I get into the state:
PARTIAL_WAKE_LOCK 'Doze lock' (uid=10112, pid=24649, ws=null)
Proc # 4: prcp F/S/SF trm: 0 24649:com.urbandroid.doze/u0a112 (fg-service)
If a user leaves a device unplugged and stationary for a period of time, with the screen off, the device enters Doze mode. In Doze mode, the system attempts to conserve battery by restricting apps' access to network and CPU-intensive services.
Doze. Doze extends battery life by deferring app background CPU and network activity when a device is unused for long periods. Idle devices in Doze periodically enter a maintenance window, during which apps can complete pending work (syncs, jobs, etc.).
This is an answer by Dianne Hackborn posted under https://plus.google.com/+AndroidDevelopers/posts/94jCkmG4jff. Still we can brainstorm more workarounds here as separating the processes may not always be straightforward.
Dianne Hackborn: +Petr Nalevka Sorry yes this does seem like a bug in the platform. I will look into getting it fixed when possible.
Your work-around is in the right direction, but please don't do that kind of thing with moving your state in screen on/off. Well, it is okay to move to the back and do that when the screen turns off... however, it is very wrong to force yourself to the front when the screen turns on, because it could be turning on for other reasons (to launch camera, voice interaction, etc). This is actually probably something the platform should be better at protecting itself against.
What I would suggest is listening for doze mode to start, and just putting your activity to the back in that case. You can do that by listening for the broadcast http://developer.android.com/reference/android/os/PowerManager.html#ACTION_DEVICE_IDLE_MODE_CHANGED and sending yourself to the back when you see that device idle is true. I would suggest just not worrying about trying to get yourself back to the foreground -- in the case where the user actually hasn't been using their device for a long time and this happens, coming back to it and being in home shouldn't be a surprise.
EDIT (by Dianne Hackborn): Actually, another solution -- have your foreground service run in a different process than the activity. From what I can see, this will work fine. I would be interesting in seeing if you get the desired behavior there.
Also this is actually our recommended practice for this situation -- if you have a long-running foreground service, it should be in a separate process from the activity, so it doesn't force all of the memory associated with the activity to be kept around. (This is also why this bug got through, all of our apps use this pattern.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With