Many of us have been in this situation: Phone is charged to 100% in the morning, and by lunchtime, it is close to 30%. Now we’re upset and we look for the app responsible. Sometimes, we see that it was an app that was used excessively (Facebook, Netflix, some news app), but other times it turns out to be an app that was not actively used. If it’s the latter, most likely we won’t care to figure out why the app is draining battery, it will just be deleted and we’ll probably leave a bad review on the app store.
As mobile app developers, the scenario described above is the worst case scenario. Not only are battery issues notoriously difficult to debug, they can also be difficult to remedy. We work on a platform with limited resources that needs to be used wisely, and this is taken to heart here at Life360. It’s actually so ingrained in all that we do, that we have created software, libraries (for example Project-Falx), and entire workflows just to monitor and understand battery consumption associated to our app. We have even torn devices apart to measure power consumption directly!
The big power hogs I’ll be talking about are CPU usage and radios (GPS, Wifi, Cellular) and I’ll explain how each could fall into a battery guzzling mess of epic proportions. Also, just to forewarn, this will be more Android-centric, as most of my work has been with Android, but iOS developers should definitely take note, as these concepts relate to mobile development as a whole.
Note: The following power numbers and software used for the screenshots are from the Monsoon Power Monitor and associated software from their website.
All about the CPU
The core of what runs all those great apps also becomes the worst power consumption perpetrator. Obviously the CPU needs to be running (it is the heart of the device after all), and its usage fluctuates depending on what the OS or apps are doing and how active the user is on their device, but how bad can it be to perform some tasks in our apps when the user isn’t using their device? It’s bad enough to have multiple articles, toolsets, and apps created for monitoring CPU usage, specifically WakeLocks on Android.
To provide insight for you non-Android folks, normally Android will allow the CPU to “sleep”, essentially putting it into a very low power state, but keeping it running for OS maintenance. At this state, no app is active, screen is off, and basically nothing is happening with the device. When an app needs to perform some task in the background, it would need to “wake up” the CPU (bringing it back to a powered state) and keep it awake while it performs the task. In order to do this, it would acquire a wakelock (typically a partial wakelock, which won’t turn on the screen).
Note: The “Battery Size” here is just the default setting. I did not adjust it to match that of the Nexus 5.
The above image shows power usage before acquiring a wakelock, which averaged to ~12 mW over the duration of this test (30 minutes). Notice the “Expected Battery Life”? It would amazing having a device last over 13 days, but to achieve this, it would basically have to be a paperweight. Now let’s see what happens when we acquire that partial wakelock.
So we went from ~12 mW to ~70 mW (all tests are 30 minutes) by just having a partial wakelock. It’s a significant increase in power consumption, basically turning our 13-day powered paperweight into a 2-day higher-powered paperweight. However, let me emphasize this… there was no load on the CPU! If you are constantly scanning WiFi changes (ignoring WiFi radio power costs), prefetching and parsing data, or doing some useless but intense CPU processing, you can expect the battery consumption to be much worse!
Every good Android developer knows not to hold on to a wakelock forever. Even Google has a warning about this in their docs!
“Device battery life will be significantly affected by the use of this API.” Warning from their PowerManager docs regarding WakeLocks.
However, most apps just wake up the device sporadically or at an interval when the app is in the background to do some quick processing, and then it lets the CPU go back to “sleep”. No big deal, right? Well, I have some bad news: depending on how often the device is woken up, that could be worse for battery life. It could cost more power to “wake up” the CPU than it does to keep it on. Confused? So was I, until I ran some tests on the power monitor. Here’s what I found:
Everytime the CPU was spun up from the “sleep” state, there was a huge spike in power consumption (195 mA * 3.85 V = 750.75 mW at the peak)! The tests above just had the AlarmManager trigger a wakeup alarm and acquire a wakelock for some period of time (labeled below each graph), which isn’t a CPU-intensive task. A second surprise from this was that putting the CPU into a sleep state also cost a smaller, but still significant amount of power. Now, these short bursts of power usage might not seem like much compared to how long it maintains the peak, but they do add up if they are done constantly! This is actually the very thing Doze mode tries to prevent by forcing all apps to honor the maintenance windows.
General steps to save power
Great! Now we’ve determined that running in the background and waking up the device unnecessarily is bad, it’s bad for your user’s battery, and you should feel bad if you are doing so purposefully. So what can be done to help reduce battery drain?
First off, don’t do any intense processing in the background! If you need to run multiple threads to process some ridiculously large data set to get a result that the user does not need immediately, it might be cheaper to upload that large data set to a backend and have some server deal with it.
Secondly, if a phone is sitting on a table somewhere, and no one is around to use it, should an app make a function call? No, this isn’t some philosophical thought experiment, but a serious question I ask myself whenever I write any app. If the device hasn’t been touched for a couple of hours, consider suspending everything until the user comes back. There are plenty of triggers mobile devices offer to give hints on when this occurs (Significant Motion sensor is a big help with this problem on Android). If your app has to do some task while the CPU is sleeping, use whatever features there are on the OS to ensure your tasks are batched with that of the other apps.
Finally, batching is your friend! Get into the habit of questioning if some background task has to be done immediately. If a group of tasks are highly related, consider running them together. Wait for a user event (such as a external power connected event) to trigger all your pending tasks.
In the next article, we’ll be talking about mobile radios, specifically GPS, WiFi, and Cellular. Stay tuned!
Come join us
Life360 is creating the largest membership service for families by developing technology that helps managing family life easier and safer. There is so much more to do as we get there and we’re looking for talented people to join the team: check out our jobs page.