Exclude Android app from being put into standby bucket

4.8k views Asked by At

With Android 9 battery optimization has been pushed further and apps are classified into standby buckets depending on how much the user has recently interacted with the app (see Android documentation). The system limits the device resources available to each app based on which bucket the app is in.

How can I keep my app in the "working set" bucket, even if the user does not interact with it? (I do not find any permission or similar that allows to override this power management feature.)

More specifically, I have a PeriodicWorkRequest that must run once every 30 minutes with a flexibility of 10 minutes. However, if I understand the table of imposed power restrictions such a work request could be deferred up to 24 hours, if my app is put into the "rare" bucket. (Under the hood, the Work library uses the job scheduler.)

Further Details on the Scenario

The app is safety critical and not intended for public use but only meaningful to a restricted set of users. However, if anyone else uses this app nothing bad happens, but the app does not serve any purpose for him/her.

More precisely, the app is connected to the central fire alarm station of a specific building. All employees are asked to install the app on their smartphone. If the central fire alarm station of that building detects an event, it sends a push notification (via FCM) to all registered smartphones and the app plays an alarm sound. This implies nothing happens for (hopefully) a long time and the user has no intention to interact with the app in any way. The app itself does not provide any interaction, it only illustrates the current state (which is either a green "OK" sign or a red "ALERT" sign) and waits in the background for the rest of the time.

As the app is safety critical, the fault condition that the app looses the connection to the server must be detected. To this end, the server actually sends messages in the background periodically, i.e. a sequence idle, idle, idle, idle, alarm, alarm, alarm, alarm, idle, idle, idle, ... Normally, messages are broadcasted with low FCM-priority every 5 minutes. If the state changes, an additional message is immediately sent with high FCM-priority (cp. bold letters).

The app implements a watchdog using PeriodicWorkRequest as mentioned in the question above. This watchdog does twofold: Wake up the device and make the device receive all (low priority) FCM-messages that have been postponed and then check if the most recent message is not older than 1.5*5min. If this fails, the app tries to re-register itself with the server and waits if state messages start to come in again. If this fails too, the app presents a warning to the user.

Everything works fine so far. The only problem is the new kind of battery optimization which slows down the watchdog at some point of time. Of course, I could hand out a standing regulation that forces all employees to open the app once in a while and simply look at it, but that is a little bit silly.

I could re-phrase the question above: I totally understand why Android is pushing battery optimization to an edge. There are a lot of (insane) apps that have misused periodic tasks for purposes that should have been solved differently. And the web is still full of "idiotic" programming advises, like checking a specific webpage for modifications every 5secs. However, how am I expected to write safety critical apps that require a watchdog for legitimated purposes if battery optimization becomes more and more an obstacle. Google's thumb of rule "if the user does not use your app, it is obviously unimportant to him/her" does not apply here.

3

There are 3 answers

0
becke-ch On

I had/have the same issue in my app (https://play.google.com/store/apps/details?id=ch.becke.sftp_server__s0_v1) and ended up showing the following permission rational on my "permission request" startup screen:

Keep App Running in Doze and Standby Mode:

This app follows best practice to keep the SFTP server running in the background, until the user stops or closes the app. BUT on certain Android devices and versions not adhering to the standards the server gets paused, stopped or killed while in doze and/or standby mode! Please follow the instructions described in "Don't kill my app (https://dontkillmyapp.com)!" for your Android device: "{0}".

Selecting "Yes" will take you to the "App Info" screen where most of these settings can be accessed. Most of these settings are related to battery optimization. Once battery optimization has been disabled, this permission request will not show up anymore.

Select "Never" (or "No" if you are not sure) if your Android device: "{0}" adheres to the standards and/or you want to get rid of this permission request.

If the user selects "Yes" and clicks on the "Request Permissions" button then the following intent "activityResultLauncher.launch(new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)))" takes the user to the app info page where he can disable battery optimization as described in "https://dontkillmyapp.com".

All activities related to "Don't kill my app" are related to battery optimization and therefore if the following checks "((PowerManager) context.getSystemService(POWER_SERVICE)).isIgnoringBatteryOptimizations(applicationIdPackage)" returns true then the permission rational/request does not show up anymore on the startup screen.

In addition this permission request is only shown if the API Level is above API-Level 23: "@RequiresApi(api = Build.VERSION_CODES.M)" AND if "componentName = (new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS)).resolveActivity(context.getPackageManager())" is not null.

Regarding best practice I implemented this service as "Foreground Service", I put a "Wakelock" on the service and started the service sticky "START_STICKY". (But unfortunately this did not help on a lot of devices - see above).

1
Melquiades On

How can I keep my app in the "working set" bucket, even if the user does not interact with it?

You can't and you shouldn't. That same documentation says:

Do not try to manipulate the system into putting your app into one bucket or another. The system's bucketing methods can change, and every device manufacturer could choose to write their own bucketing app with its own algorithm. Instead, make sure your app behaves appropriately no matter which bucket it's in.

Even whitelisting won't work in your case because:

the whitelisted app’s jobs and syncs are deferred

There's this too:

Note: Google Play policies prohibit apps from requesting direct exemption from Power Management features in Android 6.0+ (Doze and App Standby) unless the core function of the app is adversely affected.

0
user3188445 On

If your app is site-specific and not distributed from the play store, you can ask your users to disable battery optimization for your app. That will exempt your app from the standby app bucketing system. Obviously it's not a great user experience to have to go through a bunch of menus to disable some obscure feature, but given that you are considering forcing users to open the app manually, disabling battery optimization would be preferable.