Cyanogenmod 12.1 Battery Life – Fixed!

Some users of Cyanogenmod 12.1 have noticed poor battery life. Recently I encountered this, learned what was causing it and how to fix it. Posting this may help others.

My phone is a Galaxy Note 2 running Cyanogenmod 12.1 nightly build dated Nov 11 2015, but this problem has been reported across a variety of different phones. The GN2 has a big 3100 mAH battery and still makes it through the day despite this bug, but just barely. With this bug fixed, the battery lasts more than twice as long.

Symptoms

Short battery life, phone is always warm when I pick it up, Android’s battery usage screen shows a lot of CPU time spent in Android OS, and the battery life history details (when you touch the battery % graph) shows the device is almost always awake, even when the screen is off and it should be asleep.

Root Cause

If you Google this you can find a more detailed explanation; here is a summary.

The root cause is not in Cyanogenmod, but in Google Apps. The service called Google Play Services uses another service called SystemUpdateService. The notifies the device when a system update is available. This is used mainly by device manufacturers, not by ROMs like Cyanogenmod. The bug is in the Google Play service. It takes a wake lock before checking SystemUpdateService, and if it encounters an error during that check it never releases the wake lock. Basically, some Google programmer didn’t use a try..finally block to ensure the lock is always released. This surely violates Google’s coding standards, but stuff happens – sometimes bugs sneak past code review.

Solutions

I know of 3 ways to solve this. The first didn’t work well for me, but the latter two did.

One solution is to use Cyanogenmod’s Privacy Guard feature to deny wakelocks Google Play Services. This used to work well, but not any more. The current versions of Google Play Services crash when denied the wake lock, which throws a system modal dialog saying Google Play Services has stopped. This re-appears every 5 seconds or so, making the device completely unusable! Yet another violation of Google’s coding standards – if your app can’t get a resource it wants, handle it! Don’t crash and throw a system modal dialog for something as trivial as this.

Another solution is to turn on SystemUpdateService, so Google Play Services no longer fails when it tries to use it, and because it doesn’t fail, it follows the “happy” code path which releases the wake lock it acquired. You might ask, why isn’t this service running already? ROMs like Cyanogenmod don’t use it and usually turn it off to save RAM and battery. If your phone is rooted, you can enable it with this command:

su -c ‘pm enable com.google.android.gms/.update.SystemUpdateService’

NOTE: You might try enabling SystemUpdateService with an app like Disable Service, but I could not because this service never shows up in the list. The above command works whether or not the service appears in the list.

You’ll need to do this every time you boot your phone. You can use apps like Tasker to do that automatically.

The third solution is to prevent Google Play Services from connecting to SystemUpdateService. Apparently, if it can’t connect, it exits cleanly without leaking the wake lock. Yet if tries to connect but the service isn’t running, it does leak the wake lock. In this solution, you can leave SystemUpdateService disabled, which may save a little RAM and battery. The way I do this is with an app called Disable Service. Run the app, select the System tab, select Google Play services, scroll down the list of services it uses (there are hundreds!) to SystemUpdateService, and uncheck it – it will turn red.

You’ll need to do this every time you boot your phone. I haven’t yet found a way to automate it.

Final Note: Google, fix this @#!$%* bug in the Google Play Service! It’s been known for at least a year!!!