I have read the Android documentation regarding the new background restrictions in Android API Level 26, and with those in mind, I have designed my app as follows:
The app has a BroadcastReceiver listening for the "SMS_RECEIVED" broadcast. This is an implicit broadcast, which are now restricted in Oreo, however it is one of those in their exceptions list.
When this BroadcastReceiver runs, it enqueues a new task to be performed by a JobIntentService. When receiving the broadcast, the app should be temporarily whitelisted and therefore, the JobIntentService given a window of opportunity to do its thing.
All of this seems to be working just fine, even if I close the app from the "recent apps" list. However, I'm getting reports from some users that apparently every few days, they have to open the app again because it suddenly stops working in the background.
Why does the OS suddenly stop sending the "SMS_RECEIVED" broadcast to my app? If it is not that, then it must be the JobIntentService not being allowed to run. Why not? The app should be whitelisted immediately after receiving the SMS. What am I misunderstanding?
Besides Doze, Android also contains functionality called App Standby. As per the documentation:
App Standby defers background network activity for apps with which the user has not recently interacted.
The default 'recently interacted' time frame is 3 days, which corresponds with your reports of things stopping 'apparently every few days'.
Therefore what seems to be happening is your JobIntentService fires (your app is indeed still whitelisted after receiving the broadcast), but App Standby is preventing your JobIntentService from connecting to the network.
You can confirm this is the case by following the Testing your app with App Standby instructions:
adb shell dumpsys battery unplug
adb shell am set-inactive <packageName> true
You might consider looking through the Acceptable use cases for whitelisting to see if asking to ignore battery optimizations is an option for your use case.
Related
Context
We are developing an android app that is supposed to do the following:
the user installs the app, registers and closes the app
once or twice a year an admin sends a Firebase data message with priority high to the user containing a geo fence
the FCM message starts a JobService that locates where the phone is
if the phone is inside the given area an Activity is started and user interaction starts
if the phone is outside the area the service is stopped and the user is never disturbed
I developed the app based on the Firebase push example found here
The problem
The application works fine on my older phones but on my new test phone (android 8.1.0, LineageOS 15.1) we have a problem when the phone is in sleep mode. In this case the FCM message arrives instantly but the service is first started once the phone is unlocked. So the message is stuck between 2. and 3.
We need the app to respond at once - not when the user decides to use his phone 2 hours later.
I assume the problem is due to the Doze mode introduced with android 6. I tried to solve it by adding the app to the whitelist in settings->battery->battery optimization but this did not solve the problem.
Questions
Is it Doze mode that delays my app between 2. and 3.? If so why is it not solved when the app is in the whitelist?
Is there any other way to start the location service at once? This post suggests that a foreground service can do it but this requires that a notification is shown which breaks with 5.
Is there another way to start my service at once besides whitelist and foreground service?
Yes! you are right this may be due to the Doze and App Standby features introduced in API 23 Marshmallow.
As mentioned in the documentation, the system do ignore wakelocks and system doesn't allow JobScheduler to run, which effectively prevents your app from running the Job.
An easy and effective workaround would be to run Location detecting routine inside a normal background service and start it using startService() when you receive FCM push.
Note that you might still need to white-list your app because as mentioned in another post here, only a whitelisted app can use the network and hold partial wake locks.
Is it Doze mode that delays my app between 2. and 3.?
From the documentation Doze mode affect Network access and blocks JobScheduler.
If so why is it not solved when the app is in the whitelist?
Also from the documentation: 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.
So the blocking of JobScheduler still applies.
Is there any other way to start the location service at once? This
post suggests that a foreground service can do it but this requires
that a notification is shown which breaks with 5.
Ignore Battery Optimizations (for Internet access) in combination with an AlarmManager with setAndAllowWhileIdle() or setExactAndAllowWhileIdle() should work.
Be careful with Ignore Battery Optimizations
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.
I think an important question here is: Do you really need to execute the JobScheduler immediately.
If a user leaves a device unplugged and stationary for a period of time, with the screen off, the device enters Doze mode.
If the device is in Doze mode, it means the user is not using it.
if the phone is inside the given area an Activity is started and user interaction starts
This is the step Doze blocks
We need the app to respond at once - not when the user decides to use his phone 2 hours later.
If the device is in Doze it means the user is not interacting with it. Even if you show the Activity the user is not using the phone, he will see it when he starts using it 2 hours later :)
I still didn't try that,
but you might use a WakefulBroadcastReceiver:
https://developer.android.com/training/scheduling/wakelock.html
https://developer.android.com/reference/android/support/v4/content/WakefulBroadcastReceiver.html
According with this links, you should declare your receiver as:
public class YourReceiver extends WakefulBroadcastReceiver {
Probably your receiver is already a WakefulBroadcastReceiver because notifications are showing..
In the receiver, you start the service (your service has to be an IntentService) using:
startWakefulService(context, your service);
Finally, remember to release the wake lock in the service:
#Override
protected void onHandleIntent(Intent intent) {
<Your_broadcast_receiver_class>.completeWakefulIntent(intent);
}
I hope it helped
We have an Android app that gets Push Notifications via FCM and Background Service that is working even when the app is not active.
We are experiencing some issues with Android Operating System killing the background service and in other cases automatically closing the Notifications for our app. ( By automatically turning off Notifications for our app ).
Our first suspect was Doze mode introduced in Android 6 and later but we are using AlarmManager with setAndAllowWhileIdle() for scheduling the process and this should be enough for firing even during the doze mode as documented here.
In addition we found out that in certain devices like Xiaomi and Huawei devices there is a known issue of Push Notifications not working and background services not running and we handle it.
But the issue still remains in different device types and Android Versions.
Any ideas for the reason this can happen? Thanks!
The System sometimes kills the service when the memory is low.
In your background Service, override onStartCommand() and return START_STICKY as the result.
It will tell the system that even if it will want to kill your service due to low memory, it should re-create it as soon as memory will be back to normal.
I made the device which monitors person's health in sleep time and it connects to a smartphone via BLE.
It's working great with the iOS app.
But since Doze mode came on Android world.
It's really hard to deal with it because my device is working in his sleep time.
The main feature is that it detects particular danger and notify to the user while he is sleeping with the device. I need a network connection when it occurs.
Many articles tell me that I can use a network even in the doze mode if my app is in the whitelist. But it does not seem true after I tested Doze mode.
Am I right?
I can ensure that I can find my app in the lists, when I fire
adb shell dumpsys deviceidle
What is the best approach that I can take to make my app working correctly?
foreground services
alarm manager with SetExactAndAllowWhileIdle.
GCM (it means push, right?)
anything else
Any tips will help me.
Thanks.
Edit
Unfortunately, I tested with using GCM but it only wakes my app in short time. It means I have to send GCM as many as I want to keep it awake. I don't think I can use it.
Many articles tell me that I can use a network even in the doze mode if my app is in the whitelist. But it does not seem true after I tested Doze mode. Am I right?
You are not right. One of the restrictions of doze that are lifted when your app is on the whitelist, is the ability to use the network when doze is active.
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. For example, the whitelisted app’s jobs and syncs are deferred (on API level 23 and below), and its regular AlarmManager alarms do not fire.
From here.
In other words: you should be able to use the network in doze if you are on the whitelist.
What is the best approach that I can take to make my app working correctly?
Considering your app is a health monitor and thus should be able to do its work constantly or at least very regularly, you could put the functionality in a foreground service. Foreground services are not effected by doze.
You should be aware that you should have a good reason to use a foreground service since the user is aware of them, but I think you have one with the health monitoring etc.
Note: You should only use a foreground service for tasks the user expects the system to execute immediately or without interruption. Such cases include uploading a photo to social media, or playing music even while the music-player app is not in the foreground. You should not start a foreground service simply to prevent the system from determining that your app is idle.
From here.
Scope: Hi, I am developing a Service in Android API. I need this Service for running whole time (while device is running), so receiver for BOOT
android.intent.action.BOOT_COMPLETED
was setup and Service is scheduled by AlarmManager every 10 minutes.
Problem: My OS got some updates and after updating, it kill my service, unschedule Service from AlarmManager. And as far as I do not reboot my device, Service is not started/scheduled.
Question: Is there any event for receivers, that OS is restarted but device is not? Or updates are installed, OS is resumed etc.?
EDIT
Hello, thanks for links and advice.
Nowadays, I'm using library Evernote for scheduling background jobs.
see https://github.com/evernote/android-job
I accepted the truth, that long-living Service is antipattern and BOOT broadcast can be tricky. As result, I used Evernote to schedule simple jobs to repeatly "do my needs". It nice works as expected, resumes after device restart & is compatible with "Android alarm planning" management.
Just a great library.
I am developing a Service in Android API. I need this Service for running whole time (while device is running)
That is generally an anti-pattern on Android.
Is there any event for receivers, that OS is restarted but device is not?
Not in the Android SDK, because there is no concept of "OS is restarted but device is not" in standard Android. When the OS updates, the entire device reboots (at least twice) as part of the update process.
Your device manufacturer must have done something that has the behavior your describe. You may wish to contact that manufacturer to see if they have advice regarding your scenario.
Note that these results ("it kill my service, unschedule Service from AlarmManager") will also occur when the user taps "Force Stop" on your app's screen in Settings. Your code will not run again, even after a reboot, until the user launches your app from the home screen, or something else explicitly invokes one of your components.
I am running whatsapp (we could call it appX from now on) in device A. I go to manage applications -> force close so appX gets closed and i no longer see appX as running services.
Now, after 5 minutes, I send a message from another device 's appX (device B) to device A appX (the one we killed it).
Here are the 2 scenarios i tested :
device A with android 2.1 : it never receives the message, therefore we could say that none of appX services got restarted. It ONLY receives the message if manually the user restarts the app.
device A with android 2.3.6 : for SOME magic reason, no matter how long it's been since appX got killed, as soon as we send the message from device B -> device A gets the message, therefore, appX's service gets restarted. Note : all the time that appX was closed and WITHOUT receiving any notification, i wasn't able to see any running services of appX in manage applications, so this means that this magic service gets restarted as soon as it receives a message/notification
I know it sounds weird, and lot of people will say this is impossible, but again, this has been tested on these 2 devices.
I am trying to accomplish this same behavior, so any help will be appreciated it.
I don't think it's some magic what happens here! It's just Android C2DM (see: https://developers.google.com/android/c2dm/), whereas the app has a registered Receiver for incoming Push Notifications and gets awaken by this message.
Android C2DM is/was available with Android 2.2, that's the reason why you can't see the same behaviour on your device with Android 2.1 up and running.
By the way: As you can see, C2DM is deprecated since June 26th, 2012. So instead of C2DM, one should use GCM (see: http://developer.android.com/guide/google/gcm/gs.html)
Useful Comment: GCM needs available internet connection. You can using any other broadcast receiver such as SMSReceiver for by passing this limitation.
Starting from Android 3.1 (API 12), if an application is force-stopped it will not restart until the user manually runs the app again.
This will happen even if the app contains a Service or an active BroadcastReceiver.
You can find the official documentation here.
i dont have idea about whatsApp service.
But it is possible that after force stop application, restart service of app.
i use START_STICKY service for my chatApp. i have to do same thing so i use START_STICKY service so when my app kill or force stop from setting, after few second my service get restart and i able to login to my xmpp server and get incoming message.
its nothing magical here appX uses push notifications via android GCM platform https://developer.android.com/google/gcm/index.html in GCM the app registers for a braodcast reciever and the broadcast receiver starts the service on getting the push notification.
Android GCM is dependent on google play services that are available on android 2.2 and beyond that therefore you didn't see the message on 2.1 device