Android Doze Tweaks

understand and tune Android Doze parameter to save power

Tsungi
7 min readApr 9, 2018

Finally! I upgraded my four year old Sony Xperia phone to the newer Android Nougat by replacing stock ROM with LineageOS. With the custom ROM and root access I can configure my phone pretty as much as I want. The most important thing to me is to have a phone with only useful Apps installed and efficient battery usage. Being satisfied with getting rid of bloatware from stock ROM, I also miss probably one of the most useful Android feature from Sony: STAMINA mode. With STAMINA I could keep my phone never turn off during hiking for almost one week long without charging battery and still having working cell network, GPS and map Apps when I needed them.

To make smart phones, manufacturers use precious raw materials that must be extracted and processed, and consume natural resources and energy that can affect our air, land, and water, as well as plants and animals. — The Secret Life of a Smart Phone

It didn’t take me long to realize that the newer Android has already implemented built-in battery saving features. Besides usual App Standby the Doze mode is probably mostly mentioned since then. Unfortunately I was very disappointed with the battery usage after using my phone with the new Android features for several days. The Doze or any new battery saving feature performance just could not be compared with Sony’s STAMINA one! Or probably I misunderstand Doze and the whole battery saving features?

To understand how Doze works there are some Google’s document and great blogs, but they are rather for developers to make a Doze friendly App. There are also several Apps like Doze-Settings-Editor and ForceDoze for users to configure Doze with more intensive battery saving, however it was not really clear and trivial to me how exactly I could tune Doze. There are more than twenty parameters to configure Doze and I had no idea what a good combination should be and what exactly I can achieve. My goal is very simple:

  • I try to avoid installing extra Apps whenever possible.
  • I would only use root access for setup purpose.
  • I would like my phone stay as less battery usage as possible whenever the screen is locked (and without battery charging).
  • I don’t need immediate notification from Email, calendar and messaging Apps. I don’t need location tracking in background and just need location service performing precisely when I read maps on my phone.

Probably there are already a bunch of posts and discussion about the design of Doze, but at the end I still decide to directly review its implementation DeviceIdleController and somehow reconstruct the insight of Doze with following state diagrams.

Light Doze
Deep Doze

There are a few things worth to know:

  • The original Doze, or Deep Doze, is available since Android Marshmallow (6.0) and Light Doze is since Android Nougat (7.0).
  • There are actually two state machines running in parallel for both Deep and Light Doze.
  • Once either Deep or Light Doze enters its IDLE state, the battery saving actions are enabled. Namely, more time in IDLE less battery would be consumed.
  • However, Apps having WakeLock or without respecting Doze IDLE state can still trigger activities consuming precious battery any time! For example, Google Play Service alone can totally kill battery regardless Doze or not!
  • Whenever Deep Doze enters IDLE state, Light Doze will be overridden, or suspended, (i.e. in OVERRIDE state) until any motion is detected.
  • Deep Doze would only work if there is any motion sensor available and would fallback on significant motion sensor if necessary. Without any sensor (e.g. on older phones) Deep Doze will never enter IDLE state (but Light Doze will still work).
  • Some system service might be only affected by Deep Doze (e.g. UsageStatsService, GnssLocationProvider) and battery usage might be better in Deep Doze than Light Doze.
  • Some battery saving Apps would disable (i.e. actually restrict) sensors to other Apps, but Deep Doze will still need to depend on motion sensors.
  • The illusion that Light Doze always run before Deep Doze kicks in has to depend on proper settings (i.e. device_idle_constants for usual phone or device_idle_constants_watch for wearable watch).

There is one thing really impressive to me. The introduction of Light Doze did not change the existing Deep Doze implementation at all (except that Deep Doze has to override Light Doze). The way to have a second state machine running in parallel and to lift existing limitation without touch existing code is really a good example for any software development lesson.

I couldn’t understand why the original Deep Doze was designed to be always dependent on motion. It would be for me a useless feature during hiking or just daily commuting. It probably only makes sense for users wearing Android watches and they have to check Email constantly while walking between office and running on treadmill.

Once understanding Doze idle state transition and those more than twenty parameters from the both state machines, now I can tune the Doze on my phone in various ways with adb tool.

To ignore Deep Doze and discard any motion, I can just increase inactive_to (and motion_inactive_to) timeout to a very large number (e.g. 30 days) so that Deep Doze never goes into its IDLE state and only Light Doze can manage to its IDLE state. (Caveat: Deep Doze might have better impact on battery than Light Doze.)

$ adb shell settings put global device_idle_constants inactive_to=2592000000,motion_inactive_to=2592000000

To ignore Light Doze for whatever reason, I would do the similar setup with light_after_inactive_to so that Light Doze probably never enters IDLE state.

$ adb shell settings put global device_idle_constants light_after_inactive_to=2592000000

To have Deep Doze timing without taking motion into consideration (i.e. any motion won’t wake up Doze from idle), I have to ignore the real Deep Doze and more and less apply Deep Doze timing parameters to Light Doze so that Light Doze behaves like Deep Doze but without motion detection. Now it takes about one hour (e.g. light_after_inactive_to is set to 50 minutes) to enter Light Doze’s IDLE state if screen is kept off and battery is not charging. It will stay idle up to 6 hours before running any maintenance task for 30 seconds to maximal 10 minutes.

$ adb shell settings put global device_idle_constants inactive_to=2592000000,motion_inactive_to=2592000000,light_after_inactive_to=3000000,light_max_idle_to=21600000,light_idle_to=3600000,light_idle_maintenance_max_budget=600000,light_idle_maintenance_max_budget=600000,min_light_maintenance_time=30000

To have casual Light Doze without taking motion into account, I would ignore the real Deep Doze and tune Light Doze so that it will begin idle less than one minute after phone inactive and stay idle from 30 minutes to 24 hours with increasing factor 1.5; Maintenance task would be performed for maximal 30 seconds and any alarm allowed to wake up Doze from idle would take less effect.

$ adb shell settings put global device_idle_constants inactive_to=2592000000,motion_inactive_to=2592000000,light_after_inactive_to=20000,light_pre_idle_to=30000,light_max_idle_to=86400000,light_idle_to=1800000,light_idle_factor=1.5,light_idle_maintenance_max_budget=30000,light_idle_maintenance_min_budget=10000,min_time_to_alarm=60000

To have limbo Light Doze without taking motion into account, I would ignore the real Deep Doze and tune Light Doze so that it will be just trapped in IDLE state as long as possible. Maintenance task would be performed about twice a day for maximal 30 seconds and any alarm allowed to wake up Doze from idle would take less effect.

$ adb shell settings put global device_idle_constants inactive_to=2592000000,motion_inactive_to=2592000000,light_after_inactive_to=15000,light_pre_idle_to=30000,light_max_idle_to=86400000,light_idle_to=43200000,light_idle_maintenance_max_budget=30000,light_idle_maintenance_min_budget=10000,min_time_to_alarm=60000

To verify current Doze settings used by deviceidle (root access required):

$ adb shell dumpsys deviceidle  Settings:
light_after_inactive_to=+5m0s0ms
light_pre_idle_to=+10m0s0ms
light_idle_to=+5m0s0ms
light_idle_factor=2.0
light_max_idle_to=+15m0s0ms
light_idle_maintenance_min_budget=+1m0s0ms
light_idle_maintenance_max_budget=+5m0s0ms
min_light_maintenance_time=+5s0ms
min_deep_maintenance_time=+30s0ms
inactive_to=+30m0s0ms
sensing_to=+4m0s0ms
locating_to=+30s0ms
...

To reset any customized setting back to default values (or before tuning any new setting combination):

$ adb shell settings delete global device_idle_constants

Unfortunately Google Play service will periodically reset device_idle_constants, and the simple solution requires root access.

$ adb shell "su -c 'pm disable --user 0 com.google.android.gms/.phenotype.service.sync.PhenotypeConfigurator'"

There are some system Apps which are white-listed, namely not restricted during idle, consume pretty much resource. For instance: Google Play Service. To remove it from white-list also requires root access.

As mentioned before any App having WakeLock or insisting doing stuff during Doze IDLE or inactive phone will still consume battery power any time. The most notorious one is again Google Play Service itself.

My recommendation before any further tweak would be

  • If you care about privacy and battery saving, you can consider disable every activity tracking of your account from Google, otherwise Google Play Service will be very busy constantly with collecting and uploading your activities.
  • Profile your battery usage and analyse it with Battery Historian. In a simple way: just run adb bugreport, upload report to https://bathist.ef.lc/, and identify the actual problem. Here is a good introduction guide to understand it.

After identifying Apps which keep consuming resource during idle state, you can have some options to avoid them:

  • Find another better App and focus on what you really need. For example, use Messenger Lite rather then original Messenger or the complete Facebook App if you only need messaging feature.
  • Uninstall, if possible, or completely disable any App which you don’t need with adb shell pm disable [package name]
  • Allowing Apps run in background but disabling their WAKE_LOCK makes Apps only active when your phone not idle is (e.g. during Doze maintenance period). This can be done by setting WAKE_LOCK to ignore. For example, adb shell cmd appops set com.whatsapp WAKE_LOCK ignore
  • Disable specific component or feature from an App, if disable the whole App is not an option. This is especially for Apps like Google Play Service. For example I don’t need any fitness stuff from Google Play Service and I can disable them with pm disable again, e.g. adb shell pm disable com.google.android.gms/.fitness.sync.FitnessContentProvider. You can have an overview of all features and sub-components of an App with adb shell dumpsys package. Here is an attempt to disable most stuff from Google Play Service. Caution: disabling features or specific components of an App is not always reliable and you never know how App developer design their software…

Caveat: Using adb from a computer to change the Doze behaviour of your phone is probably not the most convenient solution if you want to tune your Doze frequently and directly on your phone.

Anyway, instead of buying another new sustainable ethical smartphone, I would rather keep using my existing phone for another five years…with less energy consumption.

--

--

Tsungi
Tsungi

Written by Tsungi

Mastodon: @tsungi@climatejustice.social

Responses (1)