5

TL;DR

Did the 'June 5, 2017' security updates for Android 7.1.2 cause Android to start ignoring the battery optimization whitelist (i.e. the thing that's meant to let an app disable Doze mode)?

And if so, how can an app now programmatically disable Doze mode if it has a use-case that requires the CPU and wifi be kept continuously active?

Context

I have an Android app which supports casting local audio files to a networked Chromecast receiver (using an embedded HTTP server to stream the file content to the receiver).

To get this working on Android M (in terms of not having the Chromecast session drop while the device is casting audio but otherwise idle), I had to use the approach in this answer to disable Doze mode.

Specifically, in my AndroidManifest.xml I have:

<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

...and the following code executes whenever a Chromecast session is established:

if (Build.VERSION.SDK_INT >= 23) {
    String packageName = context.getPackageName();
    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    if (! pm.isIgnoringBatteryOptimizations(packageName)) {
        //reguest that Doze mode be disabled
        Intent intent = new Intent();
        intent.setAction(
            Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
        intent.setData(Uri.parse("package:" + packageName));

        context.startActivity(intent);
    }

}

...and I'm also acquiring wake/wifi locks in the standard way, while Chromecast playback is active:

PowerManager powerManager = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "myapp-cast-server-cpu");
wakeLock.acquire();

WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "myapp-cast-server-net");
wifiLock.acquire(); 

The app appears in the battery whitelist, and as recently as a few weeks ago this was all working fine. However, the app is now getting caught by Doze mode.

The testing device hasn't changed; it's a Google Pixel running Android 7.1.2. The only software change is that I installed the June 5, 2017 security patches.

The Android system log reports the following (while actively casting):

06-16 17:44:24.842 1095-1150/? I/DreamManagerService: Entering dreamland.
06-16 17:44:24.846 1095-1145/? I/DreamController: Starting dream: name=ComponentInfo{com.android.systemui/com.android.systemui.doze.DozeService}, isTest=false, canDoze=true, userId=0

At which point (after a few seconds delay) my Chromecast onConnectionSuspended() method is called, with a value of CAUSE_NETWORK_LOST. Which would of course be because Doze mode has turned off the wifi.

Did the 'June 5, 2017' security updates for Android 7.1.2 cause Android to start ignoring the battery optimization whitelist (i.e. the thing that's meant to let an app disable Doze mode)?

And if so, how can an app now programmatically disable Doze mode if it has a use-case that requires the CPU and wifi be kept continuously active?

Edit

Here's a minimal example project that demonstrates the issue (at least on my Google Pixel):

https://github.com/adam-roth/droid-doze-test

This is the result I get, running the test on my Pixel:

enter image description here

aroth
  • 54,026
  • 20
  • 135
  • 176
  • "Did the 'June 5, 2017' security updates for Android 7.1.2 cause Android to start ignoring the battery optimization whitelist" -- if that is the case, that should be a bug. If you can create a simple test case, file an issue. I for one would be interested to see it. – CommonsWare Jun 16 '17 at 16:46
  • I don't know about testcase (that seems like a steep hill to climb just to prove that there's a bug), but I can confirm that the same app running on an older device (Sony Xperia) _does not_ kill the network/CPU while the app is holding wake/wifi locks. – aroth Jun 22 '17 at 07:48
  • "that seems like a steep hill to climb just to prove that there's a bug" -- then please don't complain when people can't help you, if the issue is slow to be fixed, etc. For example, perhaps the issue is not universal, but is limited to the Google Pixel, or is limited to the Google Pixel when connected to some specific brand of WiFi access point, or something else narrower that happens to cover your situation. Without reproducibility, your analysis is a data point, not a call to action. – CommonsWare Jun 22 '17 at 11:05
  • I don't recall complaining; just asking. Though I assume there are people whose job is _literally_ to prevent these sort of bugs from occurring and to fix them when they do. It would be most appropriate for one of them to come up with a minimal testcase. Making Chromecast work is only my hobby. But...it really takes very little code beyond what's in the post. [See for yourself](https://github.com/adam-roth/droid-doze-test). – aroth Jun 22 '17 at 14:38
  • That code does not seem demonstrate the symptom that you have identified ("Which would of course be because Doze mode has turned off the wifi"). What is the expected behavior from your code, and what is the difference in that behavior when this particular security update was applied? – CommonsWare Jun 22 '17 at 15:06
  • The expected behavior is that Doze will not trigger (while the timer is running), as evidenced by emission of a logcat message like `DreamController: Starting dream: name=ComponentInfo{com.android.systemui/com.android.systemui.doze.DozeService}, isTest=false, canDoze=true, userId=0`. What actually happens is that message is emitted (be sure to turn off filtering when viewing the logcat output). I'm unsure how to make it more clear without making the code less simple. Doze mode should not start, because the app is whitelisted and holding wake locks. Doze mode starts. That's the bug. – aroth Jun 22 '17 at 15:21
  • "The expected behavior is that Doze will not trigger" -- Doze is supposed to trigger. Quoting [the documentation](https://developer.android.com/training/monitoring-device-state/doze-standby.html#support_for_other_use_cases), "An app that is whitelisted can use the network and hold partial wake locks during Doze and App Standby. However, **other restrictions still apply to the whitelisted app, just as they do to other apps**". If a whitelisted app has an outstanding `WifiLock`, I would expect the WiFi to remain on. You see it turning off; that is what I am hoping to be able to reproduce somehow – CommonsWare Jun 22 '17 at 15:34
  • Fair point; the Chromecast session always dies shortly after that message occurs in the full app, so my assumption is they're correlated (i.e the message and the loss wifi). But that _is_ an assumption. I've added a slow background file download to the testcase, which should prove more conclusive. First run through and the download was indeed interrupted. Second run going now for confirmation. Edit: Second run, also failed. – aroth Jun 22 '17 at 16:02
  • And github is updated, if you want to try again. – aroth Jun 22 '17 at 16:08
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/147396/discussion-between-aroth-and-commonsware). – aroth Jun 22 '17 at 16:38
  • I can't reproduce your problem on my Pixel, which also has the June patches. I clicked the acquire button and added your app to the whitelist. I clicked the acquire button again, saw the counter start, and put the device aside. 15 minutes later, the counter and download are continuing to chug along, despite the `DreamController` messages showing up. I did this twice, with the same results each time. – CommonsWare Jun 22 '17 at 22:31
  • Interesting. It always fails for me, consistently around the 9:00 mark. I've had runs as short as 7:00, and as long as 11:30, but never a successful download. Maybe some setting on my device then? I've already confirmed that power-saver mode is off, and cleared the app cache. Anything else I should look at? – aroth Jun 23 '17 at 02:16
  • "but never a successful download" -- note that the download was continuing in my tests after 15 minutes, but neither time did I let it run to completion. I wasn't sure how long that would take. "Maybe some setting on my device then?" -- possibly. I just realized that my Pixel's WiFi was set to "always" for "Keep Wi-Fi on during sleep". I don't recall manually changing that on this device, but perhaps I did. What's yours set to? (Settings > WiFi > (gear icon)). – CommonsWare Jun 23 '17 at 11:47
  • Mine was set to 'Always' as well. But since it was clear that the wifi was in fact turning off periodically, I decided to go through and toggle all the power-saving options on/off. The Settings app crashed when I did this. After bringing it back up and toggling all the power options, it now appears to be working correctly. Bizarre, but looks like something is/was wrong with the device settings. Still possibly a bug, though now it's unclear what initial conditions are needed to trigger it. The security patch doesn't seem a likely culprit. – aroth Jun 23 '17 at 13:55

0 Answers0