How Google is Laying the Foundation to Kill Rogue Background Services
Google has major plans in the works to further improve the battery life of Android devices. In a talk during Google I/O (which you can watch below), the company shared their current and future plans with developers regarding optimizing for battery life.
Google is planning on killing unbound background receivers and will force developers to coalesce their background services. The only problem is that we don’t know when these new requirements will go into effect. But from the details Google has shared so far, we can tell these changes will yield massive improvements in battery life thanks to finally taking drastic measures against wakelocks.
Note: All slides in this piece were reproduced from the Google I/O talk. All credit for the slides belongs to Google.
The Current State of Battery Life
To the everyday user, managing battery life can be an immensely complex task because of how many apps we install. For Google, however, they aren’t concerned with how many apps you have installed or what you do with them. What they are concerned with is managing battery life in the macro-level, meaning there’s only three primary sources of battery life drain to consider: CPU, Radios, and the Screen.
Google has very little control over the power draw due to the screen, and so they are focusing all of their efforts on controlling wakelocks and network activity due to background syncs. Google wants to make sure the apps you have installed don’t ruin your battery life without your knowledge or consent. Survey after survey reveals that the people want better battery life. So how do they tackle these issues?
Google’s approach can be summarized in three words: reduce, defer, and coalesce. Reduce background activity wherever possible, defer background activity until a more suitable time, and coalesce background activities with other jobs to reduce CPU overhead. In Android 6.0 Marshmallow, Google introduced two new features intended to save us some battery life: Doze mode and App Standby. In addition, Google hoped that developers would continue to migrate towards using their JobScheduler API to let Google determine when their background service would launch.
The JobScheduler API has actually existed since Android Lollipop, and is intended to be used by developers looking to defer their background service until the system is ready to run the action. Developers can use the API to choose what criteria should be met for when the background service should launch. For instance, developers can schedule their service to run when the device is charging, when the network type changes, or within a certain time window (eg. “sometime in the next 4-6 hours”). JobScheduler then uses these criteria to pick a time that allows it to coalesce this job with other pending background activities. Doing so allows for efficient use of CPU cycles and network traffic, reducing power draw from the radio and CPU.
Next up, there’s App Standby. This feature was introduced in Android Marshmallow and is often misunderstood or rather is lumped together with Doze. App Standby is actually quite different, though. What it does is track inactive apps (apps that do not have any foreground service/notification and have not been opened for some time). The inactive app loses access to network access and its syncs are deferred until the device is plugged into power. Inactive apps can still be awoken by high-priority cloud messages, but otherwise do not do anything until you explicitly open the app again. This is Google’s way of preventing those rarely used, but necessary apps, from doing anything until you need to actually use the app.
Finally, there’s Doze mode. Initially hailed as the savior of battery life in Android, many users were actually quite disappointed in its implementation. Although Google claims significant improvement in battery life due to doze mode (according to a review of Googler’s devices, they claim screen-off battery life improvements up to 30%), in reality the way doze mode was implemented in Marshmallow made it inapplicable for most users.
Let’s review how doze mode works in Android Marshmallow. After the screen is off, the device is running off of its battery, AND the device has been stationary for some time, the device will enter doze mode. When the device enters doze mode, all apps that have not been whitelisted by the user in the battery optimization setting will have the following deferred: network access, wake locks, standard AlarmManager alarms (not to be confused with actual alarms designed to wake you up), WiFi scans, or sync adapters. These actions are deferred until the next maintenance window, whereby the system wakes the device up and allows all of these actions to run for a brief period at the same time (ie. coalesces them).
It’s a sound theory for improving battery life, but the trouble is in the implementation. Doze mode requires a device to have a significant motion sensor as it uses the sensor to actually detect whether or not the device is stationary. By default, Android waits 30 minutes after the screen goes off to flip on the significant motion sensor and determine if the phone is stationary. The sensor is active for 4 minutes and detects any motion from the device whether it be walking, running, biking, etc. In addition, the device attempts to pull the location of the device within 20 meters of accuracy. If the device is deemed to be stationary, it will then check the device again after 10 minutes. If after 3 additional checks of the device being stationary (ie. 30 minutes later) the device is STILL stationary, then and only then will the device actually enter doze mode. And then, after a grace period of 5 minutes which Android gives to applications telling them the device is about to enter doze mode, the device will enter the idle state and stay there for 60 minutes until the first maintenance window. This cycle of idle <–> maintenance continues until the significant motion detector or location service detects that the device has been moving.
Sounds pretty complicated, right? For whatever reason, Google missed a pretty significant detail for millions of users out there: a lot of us aren’t stationary. Just having your phone in your pocket and walking around is enough to prevent doze from activating. In my case, I used Tasker to write to a text file whenever doze mode fired after a screen-off event. In a 24 hour period, doze activated only twice. My device was in my pocket for most of the day while working, and I rarely used it during work. If doze is supposed to improve standby battery life, then why was doze mode designed in such a way?
What’s new in Android N
We’ve actually known about Android N’s changes to doze mode and the new restrictions on several broadcast receivers since March, but at Google I/O they laid out their full plans for the future. Doze mode in Android N improves on its Marshmallow counterpart by introducing an intermediary, lighter doze mode that only defers network access and jobs/syncs. This intermediary doze does not require the significant motion detector to determine whether or not the device is stationary; instead it always kicks in 5 minutes after the device’s screen goes off.
This intermediary doze mode has its own cycle much like the doze in Android Marshmallow, however, after 30 minutes the regular doze mode checks kick in to determine if the device is stationary. Then, the device may enter the full idle state where all background services are restricted. These changes to doze allow the device to enter a semi-idle state even when the device is moving, for the most part.
Another change to Android N comes from the removal of three implicit broadcasts: CONNECTIVITY_CHANGE, ACTION_NEW_PICTURE, and ACTION_NEW_VIDEO. A broadcast receiver is a component of an Android app that responds to system-wide broadcasts. If you were to take a guess by the name of the broadcasts I listed above, the CONNECTIVITY_CHANGE broadcast will wake up an app that has the appropriate broadcast receiver whenever the network changes between mobile data and WiFi. The NEW_PICTURE and NEW_VIDEO broadcasts were used to send broadcasts to apps whenever they took a new picture or video.
Any application that defines a broadcast receiver inside their Android manifest can launch a background service whenever the broadcast is sent by the system (or by another app). An implicit broadcast can be picked up by any app whereas an explicit broadcast is targeted to a specific app.
For instance, here is the manifest file for Dropbox. Dropbox currently fires a background service whenever any of the three broadcasts mentioned earlier are received. This makes sense for Dropbox, as it can launch a service to backup new photos/videos whenever they’re taken or to backup as soon as you plug in. However, Android N is getting rid of these three most-commonly used implicit broadcasts because their existence has caused a mess of apps launching background services whenever these broadcasts are fired. Instead, developers will now be forced to use JobScheduler to launch a bounded background service, meaning the system in N is forcing developers to defer their service.
Apps running on Android N will not trigger based on these three broadcast receivers, and must instead listen for one of the new trigger types on a Content Provider update. Although this results in delayed action for some apps, this allows Android to prioritize jobs set by foreground apps as well as prioritize jobs based on RAM availability. For lower power devices, this is a godsend as it will improve the UX whenever you’re operating a foreground app as the accumulation of background services won’t be eating up memory and stealing CPU cycles from whatever it is you’re focusing on.
Furthermore, Google wants developers to re-code ALL of their apps to remove usage of implicit broadcast receivers, and they are doing so by introducing Firebase JobDispatcher. This is a new SDK that provides most of the JobScheduler functionality on pre-Lollipop devices (and soon, even iOS!). It relies on Google Play Services being installed to function as the backbone, which isn’t a problem for most users.
The Death Sentence of the Implicit Broadcast
By far the biggest news for the future of Android battery optimization is the fact that the removal of the three broadcasts I mentioned above is just the first step. In a future release, Google is planning on killing ALL unbound background services by removing ALL statically-declared implicit broadcasts and will force developers to use JobScheduler.
Google is hoping to slowly ease out the use of implicit broadcast receivers by teaching developers to phase out some of the most commonly used ones. They’re also introducing some really powerful battery analysis tools to help developers analyze and determine where their app is going wrong.
Google has a long road ahead of them. At the I/O event, only about half the attendees raised their hands when they were asked if they had ever heard of JobScheduler. This is a major problem if they expect to force developers to switch over to them. Still, there is plenty of time for developers to get educated about these upcoming changes. Users have much to be excited about, as these changes are extremely significant for killing the widespread plague of wakelocks infecting Android.
Correction: JsChiSurf rightly pointed out that CONNECTIVITY_CHANGE broadcast is for network changes, while the article mentioned plug/unplug state change. The sentence has been amended.