This article is aimed both at application developers and engineers troubleshooting the power management on Android devices.
Since Android Marshmallow, there have been significant improvements in the Android platform to increase the battery life of devices and mitigate against applications that consume excessive power. Doze mode, background restrictions, app standby, background location limits and other changes have all placed restrictions on how much power an individual app can consume but it is still important to consider power management during development and not attempt to circumvent these restrictions without understanding the implications.
How to measure what is using a device’s power
The most straight-forward way to determine which apps or services are using the most power is to use the standard Android ‘Battery usage’ settings. Under Settings, then ‘Battery’, then the three dots, then ‘Battery Usage’ you can identify any apps that are consuming excessive battery. Clicking three dots again, then ‘Show full device usage’ will show the consumption of device features like Bluetooth or Wi-Fi
Android does not expose any APIs to programmatically determine which apps are using the most battery, at least not publicly.
Common Device configuration and app behaviour that can cause excessive battery usage:
- Setting an excessive display timeout
Just like with consumer smartphones, the screen is the largest consumer of power in most Enterprise deployments. Not only does the screen itself consume power but having the screen on prevents the device from entering doze mode. Having a shorter display timeout will save power, particularly where your users are only intermittently interacting with the device and an administrator can control this timeout using the MX Display Manager through StageNow or through your EMM’s setting.
Related to screen timeout is screen brightness. A high screen brightness (e.g., 100%) will use significantly more battery than a reduced screen brightness (e.g., 50%); only use a high brightness if your users are working continuously outdoors, in bright sunlight. For mixed indoor / outdoor use cases or for climates where bright sunlight is uncommon, you could use adaptive brightness (also controllable through the MX Display Manager) or set the brightness to an intermediate value (e.g., 80%).
2. Holding wake locks or exempting the app from doze mode
Many apps will exempt themselves from doze mode (also known as removing themselves from battery optimizations) and / or hold a wake lock to allow the app to perform work in the background that would not have otherwise be possible. Zebra expose the ability for an administrator to exempt a specific app from doze mode or disable doze mode entirely on the device but this approach should only be used as a last resort, when all other methods of achieving your app’s background use cases have been explored, for example, by using the WorkManager.
The primary drawback to exempting yourself from doze mode and holding a wake lock is that, depending on how your app behaves, it can have a significant impact on the battery use of the device.
To find out which apps on your device are exempt from Doze mode go to Settings, then ‘Apps & notification’, then ‘Special app access’, then ‘Battery optimization’. Apps listed under ‘Not optimized’ have the potential to use increased battery.
You can also run the adb command
adb shell dumpsys deviceidle
to see non-optimized apps listed under the ‘Whitelist user apps’ section.
Whitelist user apps:
To determine which apps on your device are holding wake locks you can run:
adb shell dumpsys power
and look for the ‘Wake Locks’ section. Note that a ‘partial’ wake lock will keep the device running but allow the screen to turn off whereas a ‘full’ wake lock will do the same but keep the screen on.
Wake Locks: size=1
PARTIAL_WAKE_LOCK 'WakeLockExampleAppTag1' ACQ=-31s465ms (uid=10184 pid=15963, ws=null)
All wake locks will be cleared when the device enters doze mode but if your application is exempted from doze mode, that will never happen.
3. Enabling device radios which are not needed
Bluetooth, Wi-Fi, WWAN, NFC and GPS all consume power. If your device does not intend on using any one of these radios, then the device administrator should turn them ‘off’ using the MX Wireless Manager or the equivalent setting in their EMM. Individual radios may also have more granular settings such as the ability to turn off BT Discoverability, which will save on device power consumption.
Developers also have control over device radios and they can be turned ‘on’ or ‘off’ at runtime using the EMDK Profile Manager without user interaction. Great care should be taken with this approach however since disabling a radio will affect ALL apps.
Related to device radios is the Wi-Fi and Bluetooth Scanning feature, which is used by Android to enhance the location returned by the Fused Location Provider. Both Wi-Fi and Bluetooth scanning can be disabled using the MX Wireless Manager or by putting the device into GMS Restricted mode.
4. Using a Foreground Service
Applications that need to perform background work will often opt to use a foreground service, which allows the app to avoid background processing limitations but also causes a notification to be displayed to the end user.
Developers should be mindful of the power they consume in a foreground service to ensure it does not become excessive, especially if the app is determining the device location.
Identifying applications that are potentially misusing a foreground service is easy because every foreground service needs to have a visible Android notification associated with it. If you see a notification appear saying “syncing mail” or “retrieving data”, this is likely coming from a foreground service.
Polling will always have a detrimental effect on your device’s battery life, particularly if your application is preventing the device from sleeping. Polling should be replaced by push mechanisms wherever possible.
Some common enterprise examples:
- If your application needs to report its status to a server every X minutes, consider using a WorkManager periodic job instead of keeping the device awake.
- If you need to remotely push data to a device, consider using either Firebase Cloud Messaging or an MQTT-based alternative if Google services are unavailable.
- If you need to detect when a thread is finished, have your thread notify you when it is done rather than rely on an isFinished variable that you check in a tight loop.
Is there a way to suspend the device (put it to sleep as though the power button had been tapped or the inactivity timeout had expired) programmatically, perhaps via the Zebra EMDK?
Context: I'm a developer working on a warehouse selection app. Within the app, the user can signal that they are going on a break. When this happens, I know that the device isn't going to be used for a while. It would be nice if the app could make the device sleep at this point.
Right now, my workaround is to temporarily set the display timeout to the shortest possible value, then restore the previous value on resume...