In my app, I make an internet connection every 10 minutes via the AlarmManager APIs to download data.
I would like the app to make at least 6 attempts to connect, one every 30 seconds if there a problem with the network connectivity.
Is it possible?
It isn't possible to do that on a modern Android device where by modern I mean Android 6 or greater.
6: Doze [Doze that comes on roughly an hour after the screen is turned OFF]
7: Doze++ [Doze that comes on shortly after the screen is turned OFF]
8: Background restrictions [Inability to run services that are not in the foreground]
Google's recommended way of doing syncing like this is to use a JobScheduler or Firebase Cloud Messaging if you have luxury of doing a server implementation.
With out knowing all the requirements, it sounds like the app may need to use the AlarmManager if you're determined to sync more frequently than the JobScheduler allows.
There is only 1 API in the AlarmManager that is guaranteed to be called reliably once every 30 seconds and that is setAlarmClock. However, it cannot be used to start a service. It can only send a user-facing alarm and a PendingIntent that will be executed when the user clicks on the alarm.
The two APis most likely to be useful to you are setAndAllowWhileIdle and setExactAndAllowWhileIdle. Both these APIs can be used to start a service. The alarms will execute frequently when the screen is ON or the device is charging. However, when the device is in the power saving mode called Doze they can only execute during Doze maintenance windows. This means they can still run at least once every 9 minutes during most normal doze windows.
Now apps targeting Android 8 must address another new restriction, they have to call startServiceInForeground. A foreground service sets an on going notification like your media player for example. So it makes the user more aware that the service is running and usually gives them an option to stop it.
Now foreground services are 'exempt' from doze, a few things to be aware of:
When a foreground service is active it prevents the entire device from dozing which greatly increases the battery usage
In Android 6 foreground services will be dozed anyway unless they are in a separate process due to a framework defect
I've heard that some devices will eventually kill a foreground service if you leave it running for an extraordinary amount of time
But the real answer to your question is: "Don't do it". Does the app really need to use that much battery and data? Running every 30 seconds is extraordinary and even if was possible it would make the app a "bad citizen" on the phone...
Related
Our app can connect to a HVAC device, and need to sample its state every 10 seconds.
The HVAC device expose a Modbus interface and CANNOT buffer samples. We ACTUALLY need to wake up the service every 10 seconds. A typical sample session last from 1 hour to a few hours.
(There are various connection types/cables/bridges: OTG + RS232 USB converter, TCP trough a RS232/TCP bridge, Bluetooth classic and BLE through RS232/BT or BLE bridges.)
Of course the user should be able to turn off the display to save battery, and to navigate to other apps, while the sampling session is taking place.
Until Nougat 7.0 our working solution was:
Start an IntenService, then set it to Foreground Service
Bound to that service, so it's also a Bounded Service (to stop it, propagate interaction with the HVAC device from the GUI, etc.)
Acquire a PowerManager.PARTIAL_WAKE_LOCK
Use a Thread.Sleep() for the 10 seconds cycle, but also to manage timeouts in the transport implementation of the various connections
Should I post the code? The relevant parts are most common boilerplate.
Despite having no documented guarantees, Thread.Sleep() with a PowerManager.PARTIAL_WAKE_LOCK in a Foreground Service was working perfectly until Nougat 7.0
On our testing Oreo device, both compiling targeting API 26 and 23 (as our previous released version), while not interacting with the app activities (turned off display, other apps in foreground etc.), the service does not wake up, it sleeps until the first interaction with the app.
To be able to start a foreground service on Oreo targeting API 26, I implemented Bikram Pandit's solution from Android O - Old start foreground service still working?.
Nothing changed.
I asked for a Battery Optimizations exception, with ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS (as descripted in https://developer.android.com/training/monitoring-device-state/doze-standby#whitelisting-cases ), and granted it. Nothing changed. (And the app was working without it until Nougat 7.0)
The documentation about Oreo's Background Execution Limits, https://developer.android.com/about/versions/oreo/background, states that Bounded Services or Foreground Services should NOT be subjected to these limits. And yet the service doens't wake up.
AlarmManager cannot be used, since from Oreo it can fire at most every 9 minutes, even with setAndAllowWhileIdle() nor setExactAndAllowWhileIdle(). (Again in https://developer.android.com/training/monitoring-device-state/doze-standby#whitelisting-cases)
I also tried using a wait(sleepTime) instead of the Thread.sleep(): it's even worse, it doesn't even wake up when restarting interacting.
I stopped short before re-implementing as a JobIntentService or using JobScheduler/JobService, to reframe every sample as a job, but:
IMPORTANT: I would still need the Thread.Sleep() in some of the transport level connection implementations, will that wake up during a job?
Would JobScheduler actually allow to run jobs every 10 seconds, or would it bundle them together on Oreo? We actually need a sample every 10 seconds. We probably could relax to 1 minute, but not any larger.
Can I retain very complex state (my ModbusDevice object) in JobService, to share it among all those jobs or there would be limitations?
Again, should I post some code? It's most common boilerplate.
My app has a background service running that gets users current location and update it to a server every five minutes. To run this location update process continuously, I use alarm manager to set its next execution time from the service itself. However, when I install the app in my Nokia 6 running Android 8.1 it works for some time and if I keep the phone idle for some time, my service will get killed with the next alarms by the application also being cleared from system alarm manager. My guess was that the idle time makes the phone enter doze mode. However, I don't understand why the alarm managers got cleared. To my understanding, the doze mode should open up maintenance windows periodically to execute any pending tasks.
To mitigate this issue, I tried to apply a JobScheduler service on top of AlarmManager, which runs every 15 minutes. Purpose of this jobscheduler was to re-start the service which has the alarmmanager in it, so even if it gets killed and the alarm is cleared, jobscheduler would re-up the service.
After I tested this patch and keeping it for some time to go into idle mode, it resulted in getting both JobScheduler Service and Service which has the alarm in it killed with the scheduled jobs and alarms getting cleared from the system.
It is said in the Android documentation that we can use JobScheduler to mitigate its background execution limitations. And to test this out I forced killed the two services when I tested the app, but the already scheduled job did not get cleared, and it made the service with the alarm run again successfully. I don't understand the reason for this behavior, although the Evernote guys give an explanation that could match this scenario in here Android Job by Evernote
Any ideas for this abnormal behavior?
Test Environment Details
Device : Nokia 6 (TA-1021)
OS : Android 8.1.0
You would not be able to run background services long running in Oreo as there are behaviour changes, now Oreo to optimise system memory, battery etc, it kills background service, to solve your issue you should use foreground service.
Have a look at Background execution limits https://developer.android.com/about/versions/oreo/android-8.0-changes
A suggestion from me, if you can use FCM then go for it, becasue apps like WeChat, Facebook uses it, to deliver notifications and they don't face any problem...
Hope this helps in understanding the issue....
In Doze more, the alarms do not get reset, but get deferred to a later time. You have two mainstream options here:
Use either setAndAllowWhileIdle() or setExactAndAllowWhileIdle(). However, these too can fire at the maximum frequency of 1 time per 9 minutes. So you'll have to decrease the frequency at which you get location in your app.
Use a foreground service by way of showing a foreground notification. Everyone does that (apps like Uber, Google Maps etc). That way, your service won't get killed, and be treated as though you have an app open.
I'm currently facing the same issue and doing the same workaraound like you do. That is, setting the Jobscheduler to a periodic job to launch my Foreground Service every 15 min in case it is getting killed for whatever reasons like a killed task. This works like a charm on pre Oreo Versions.
For Oreo the only solution I am awared of at the moment is, to allow the app to autostart in the settings. Under installed apps that is. Then it should work like pre Oreo again.
What Ive heard but not tested yet, is to set the setPersisted(true) option in the Job Scheduler.
Let me know if that helps
I assumed currently DOZE mode not allowed to background service so you need to find a way that DOZE mode will not affect on your app.To solve your issue you should use foreground service. or make some battery setting. Any way my better option is you should go with Firebase Cloud Messaging
Recently, I'm working on an app that needs to run a Service every day at a certain time.
To do this, I use AlarmManager.
My question is: After activating the AlarmManager (from the Service), can I destroy the Service, and the AlarmManager will still call me in time?
If not, is there any way at a certain time to send me BroadcastRecerver, without running a Service all the time in OS?
Would appreciate help
The short answer to your question: service can still be started from the alarm manager anytime the alarm receiver is able to run. The long answer: usually it's good practice trying to use job schedulers though. They can both decide a better time to run, while ensuring you have the necessary resources to run successfully, such as network or high battery among other criteria.
Alarm managers are only reasonably reliable before Nougat. It's been long announced that developers should stop using it, and start using job schedulers for most use cases. They are meant to replace both the alarm setup and receiver, and allow the phone to save more battery by putting the phone in doze mode for longer and waking up and doing multiple tasks all at once.
Even if you get alarm manager working on your particular phone google makes less and less reliable with each OS release. There are very specific cases where alarms are still the way to go, but unless you're certain to be in one of these try to use job schedulers for all devices running lollipop and later. You can still use alarm manager reliably for kitkat and older, where job schedulers don't exist. More details on: https://developer.android.com/training/monitoring-device-state/doze-standby.html
In either case I think you need to listen for phone's boot so you can register your alarm/job scheduler:
https://developer.android.com/training/scheduling/alarms.html
Job scheduler info:
https://developer.android.com/topic/performance/scheduling.html
For reliability issues: Android AlarmManager not working on some devices when the app is closed
I'm developing an app which connects to a special device via wifi. I need to make status updates in a short interval, resp. keep the status of my special device in the app up to date. FCM is not an option. My idea is to give the user two options: Fast updates using a foreground service or "slow" updates using a periodical update mechanism to save battery.
My question is about the second option. The interval should be around five minutes. Using JobScheduler therefore is not possible. But even using the AlarmManager seems not to be an option because I'm not able to get network access during the doze maintenance windows.
I thought about using a WakefulBroadcastReceiver to receive the Intent by the AlarmManager, require a WakeLock and turn my long running Service into foreground by calling startForeground(). But it seems that the startForeground() method has no effect on the Service as long as the device stays in doze mode.
I read many pages about doze and services but have no clue how to solve my problem... Does anyone got an idea?
you should use GcmTaskService. You can schedule some interval for your operations and it would work fine even in doze mode, check more information by link
You can use setAlarmClock, but it is not recommended for your purposes.
Instead you can use setExactAndAllowWhileIdle with manual re-programming with an interval of 15 minutes.
Best way: GCM.
I have application which for every 10 seconds do some request to server (http client). I read a lot about application life cycle. My application has service with foreground flag and it's work well (application work all time) when android is "active". I don't have phone with real android, so I am testing on emulator, but my friend testing it on smartphone and he notice that when he leave his phone, request are post for 10, 30 minutes, even hour. If he turn on screen, then request time is back to 10 seconds (he have access to server so he see logs). Is this known behavior? Because he installed gmail notifier from google, and this same problem (big delay). Any solution for this? My service have timer task (so request is sent in async task)
Regards
First of all, if you're polling every 10 seconds, that's gonna drain a lot of battery and network bandwidth.
I recommend using a lower frequency or server push.
For the polling issue, how do you implemented the polling ?
Do you use timers ? if so, what options do you pass in ? Or do you use a thread that sleeps for 10 seconds ?
Depending on the version, Android may turn off all processes, or delay network requests to run every 30 minutes to preserver battery power and bandwidth. (Starting up the network components drain a lot of battery than keeping them running. So If your app turns ON network, do a poll, then simply turn it off, Android may schedule it to align with all other requests on the system.)
Can you provide us more info about how you do the polling ?
UPDATE
You might have to schedule a 'WakeLock' so android knows when to wake up for your service. I think, by default, android doesn't wake up for timer requests that are scheduled very frequently and it schedules them as I explained. WakeLocks on the other hand can force android to wake up.
See this question and WakeLock Documentation
Make sure you pass the correct parameters, so you don't turn the screen ON. (Would be really annoying.)
UPDATE
I still recommend using server push for this, which will save battery and bandwidth while keeping the updates real time.