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.
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.
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.
Related
I opened this question to ask you a strange thing that i'm facing currently.
I have various assumptions on what the problem could be, and i want to share them with you to get a confirmation.
I premise that my intent is not to use FCM. The application right now was a test to send a scheduled notification with the module "flutter_local_notifications". When the scheduled notification reaches the scheduled time, it fires if:
The application is open
The application is not open, but the smartphone is on
The application is on debug mode, is not open and the smartphone is off
I set on my smartphone some permissions for the application to ignore battery-saving mode, to enable autostart, lock the application to avoid the Android's memory management.
But still, when i turn off the screen of my smartphone the app's notification won't fire at the scheduled time.
I tried to do some tests on other smartphone's and the outcome is pretty different. For the other smartphones it works pretty well.
I am currently using a "Realme 8 5G", i was asking, is it possible to find a solution to overcome this problem or the problem is just out of my hands?
Thank you for reading and your time.
I have an open source gps tracking application that has been around for many years. Recently, I have been getting complaints that in android nougat, instead of getting updates once a minute, people are getting updates from the phone once every five minutes when the phone is unplugged.
There is something going on with the power saver mode even though we tried turning it off.
Is there a way to force a phone to get gps updates at a specified time when unplugged?
Here is the code if anyone wants to see it but I don't think it's a problem with the code. It has been very stable for years.
https://github.com/nickfox/GpsTracker/blob/master/phoneClients/android/app/src/main/java/com/websmithing/gpstracker/LocationService.java
thanks.
One change in Android 7/Nougat was that the Doze is now "more aggressive". In Android 6/Marshmallow the doze mode kicked in when the screen was off, the device was running on battery and it was stationary.
(This is documented in Optimizing for Doze and App Standby)
Now in Android 7 the conditions are just screen off and running on battery.
(This is documented in Android 7.0 Behavior Changes)
Apps can be white-listed to be exempt of the restrictions if they break the core functionalility of it. In your case they do as the GPS tracker needs to record coordinates in real time.
There's a list of Acceptable Use Cases for Whitelisting
This includes:
Task automation app | App's core function is scheduling automated
actions, such as for instant messaging, voice calling, new photo
management, or location actions.
Users can white list an app manually on their own in the device settings or whitelisting can be requested by the app and approved or rejected by the user.
This is covered in Support for Other Use Cases
Quoting:
An app can fire the ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS intent
to take the user directly to the Battery Optimization, where they can
add the app.
An app holding the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission can
trigger a system dialog to let the user add the app to the whitelist
directly, without going to settings. The app fires a
ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS Intent to trigger the
dialog.
The user can manually remove apps from the whitelist as needed.
The last point is important of course, but luckily the whitelisting status can be checked programmatically:
An app can check whether it is currently on the exemption whitelist by
calling isIgnoringBatteryOptimizations().
So, dealing with the Doze mode is one thing to study at least.
Another issue is keeping the Service running in general. But the Service getting killed by the system might result in more random time intervals. There are of course the classic things like using START_STICKY or running as a foreground service.
I have a foreground notification service that continuously monitors user's actions, using ActivityRecognition, and writes them to AWS anytime user's state changes. It works good for some time. However I noticed when user is idle for longer time, such as user is sleeping overnight, then the app (activity and service) silently dies. I assume this is because of doze mode (because I whitelisted the same app on a different phone and it is working fine for over 2 days now)
How to WhiteList app in Doze mode Android 6.0 gives good overview on how to disable doze mode with user intervention. But #commonsware blog below suggests about Google 'possibly' banning the apps that show the corresponding popup box
https://commonsware.com/blog/2015/11/11/google-anti-trust-issues.html
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.
Can someone help me in understanding what features can possibly comprise "core functions", so Google would not ban my app. We know doze mode doesn't affect some apps like WhatsApp
EDIT
I see this on Samsung phones with 6.0.1
Android does not kill services in the background with Doze. Per the ActivityRecognitionApi documentation:
To conserve battery, activity reporting may stop when the device is 'STILL' for an extended period of time. It will resume once the device moves again. This only happens on devices that support the Sensor.TYPE_SIGNIFICANT_MOTION hardware.
Therefore it is entirely expected to have a significant period of time where you won't get any activity recognition callbacks. In those cases, you can assume that the last received activity (STILL) is still applicable.
I have an android app which records voice using a service - and a thread inside the service(obviously the app can record while in background..)
The app will be affected by the new Doze app state?
https://developer.android.com/training/monitoring-device-state/doze-standby.html#whitelisting-cases
I don't have a phone with 6.0 yet and the simulator cannot record voice in general...
If your service is running in the foreground (with an associated notification) when the device enters Doze mode, it should not be affected according to a comment by Dianne Hackborn to this post. See a documented experience that seems to prove this behavior here.
On the other hand, tests show, that access to certain sensors like GPS are restricted in Doze mode, so this might also apply to the microphone.
Since Doze mode is poorly documented up to now, unfortunately at this point you probably do not get around running your own tests on a physical device.
Yes, every app can be "killed" by Doze. If your service runs in foreground you can avoid App Standby however. Remember that asking to the user to put the app in the whitelist it's prohibited from Google Terms of services, so you can't do it. If you want to do something like that you need to add a permission to your manifest and with cross fingers hope in the Google review of your app.
I'm developing and Android application on CodenameOne that needs to send a web request every 5 minutes even when minimized. How can I achieve this behavior in order to prevent that the request get stopped or paused by the OS?
You cant do that from the activity, you'll need to create background service.
http://developer.android.com/training/run-background-service/create-service.html
Use AlarmManager to set up your every-five-minute operation. Have it trigger a BroadcastReceiver, which in turn passes control to my WakefulIntentService (or your own IntentService that handles the WakeLock, that you will need so that the device stays awake while you do your work). Have the service do the "web request".
This is still not 100% guaranteed:
The user can Force Stop you from Settings, in which case your alarms are gone and nothing will happen until the user manually runs your app again
The user might block alarms from firing on certain devices, like various SONY Xperia models, that offer "stamina mode" or the equivalent
However, it is the best that you are going to get, short of rolling your own Android OS version.
The other guys answers are correct that you need to create a service but they somehow ignored the mention of Codename One.
Under Codename One you need to create a native directory for android and just place the service source code there (just use a blank service class that doesn't really do anything). Then you need to add to the build arguments the option android.xapplication where you would state the service XML attributes.
Having said that what you are trying to do is VERY wrong and you shouldn't do it in Android! You will drain the battery life from the device in no time and the service will be killed by the OS eventually (since it will be a battery drain). The solution is to send a push notification to the device to wake up the application.
In Android 9 and newer you can prevent your App falling asleep with a battery setting.
Long click on your App -> App info -> battery -> optimize battery consumption
Here add your App from the list.Hint: maybe the menu entries have a different name, depending on your phone.