AlarmManager setInexactRepeating not correct repeat after sleep app - android

i want to create repeating service by alarm manager. if app is running in live time then it is correct running every one min. it in sleep mode to running every five min. why it is not running every one min in sleep mode?
public static final long NOTIFY_INTERVAL = 60000;
AlarmManager alarms = getAlarmMAnager();
alarms.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), NOTIFY_INTERVAL, recurringAlarm);

That is very much expected and can happen due to various reasons
Android Oreo has limitations on running services in background, so you may face this on O devices
Doze mode on Android Marshmallow onwards can cause this, it will stop all network operations itself & take away CPU wake locks
AlarmManager is not meant to for doing repeated operations in background
I will suggest you to use JobsSchedulers or Firebase Dispatchers for tasks which you want to execute in background, as it will take care of Doze mode, background service limitations, no network scenarios etc.

Related

Check location every 15min even if app in foreground or killed state

I have a requirement, where my android app needs to check for location every 15 min and update it to SQLite DB. This process should happen even if app removed from background. I tried all the following ways, but none of them are working when app running for long time.
Runnable function with a foreground service. Below is the example
mHandlerTask = new Runnable() {
#Override
public void run() {
doCheckLocation();
mHandler.postDelayed(mHandlerTask, 60000 * 15);
}
};
mHandler.postDelayed(mHandlerTask, 60000 * 15);
This is working fine, but if screen turned off that runnable is not triggering. I think it's because of doze mode.
Work manager with Periodic Work Request: This is also not triggering when device goes to doze mode / screen turned off.
Alarm Manager: This has few functions setExactAndAllowWhileIdle(), setAlarmClock() for triggering at exact time. But the battery consumption is very high and phone gets heated up if I'm using setAlarmClock().
So I wanna try with a wake lock. When screen getting turned off I acquire it. I'll release it when screen is on. But wake lock is going to drain the battery, and most likely OS can kill my app.
Can anyone suggest a better way to solve this problem?
WorkManager and AlarmManager are in fact most efficient ways for scheduling some tasks in your app, but you just have requirements that aren't battery-efficient and won't be ever... both location tracking and "waking up" device every 15 minutes will cause high battery drain and I doubt you can prevent this

Android Job scheduler behavior when device goes for deep sleep

I am currently working with an android application that uses android job scheduler to call an api at certain interval(lets say every 4 hours).
Suppose my device is not on charge and there is no activity being done on it, so it goes to sleep after some time(lets say after 1 hour of last api call).
Now my device wakes up after 5 hours due to some activity that I did deleberatly. Will the scheduler call the api immediately(as its more than 4 hrs since last call)? or will it wait for next 3 hours to run the job?
(*I have not acquired the wake lock in this case so the device will go to sleep.)
I think you by Deep Sleep you mean Doze. When your device in doze mode your JobServices will not trigger. Periodic job can't be exact. A job is either exact or periodic. So periodic will trigger while in maintenance window between execution interval. If you running your jobs on Lollipop + with high frequency, then it's possible, that some periods are skipped, because the device is saving battery.
Check out restrictions for doze mode:
Network access is suspended.
The system ignores wake locks.
Standard AlarmManager alarms (including setExact() and setWindow()) are deferred to the next maintenance window.
If you need to set alarms that fire while in Doze, use setAndAllowWhileIdle() or setExactAndAllowWhileIdle().
Alarms set with setAlarmClock() continue to fire normally — the system exits Doze shortly before those alarms fire.
The system does not perform Wi-Fi scans.
The system does not allow sync adapters to run.
The system does not allow JobScheduler to run.
But you can use some hacks to make your job executes at specific time/immediately after scheduling.

Repeating Task in Foreground service in Doze mode

I'm working on an application in which I have to do some repeating task at fixed interval (let's say after 2 mins) which should complete even in doze mode. My observations are mentioned below -
Doing repeating task using Alarms (using RTC flag) aren't accurate. Android system batches alarms. If we use RTC_WAKEUP then it is better than RTC, but it shows WAKEUP count in Android Vitals which is not good.
Jobschedulers are useful but will not work for lesser interval like 2 mins. I had tried Firebase Jobdispatcher but that is also not very accurate, I started Job with 2 mins Trigger time but it was varying from 10-20 mins.
Used Handlers and Timers for repeating task in Foreground service. In this scenario Foreground service continue to run in Doze mode but handlers and timer stops repeating task. I read about Handlers.postDelayed() and found that this is also affected by doze mode.
I don't want to acquire WAKELOCK for this repeating task.
Can someone please suggest me some better/clean way by which we can do short interval repeating task in doze mode?
For reference -
Android: What is the best way to make repetitive Background Tasks Android Oreo ready?
How does doze mode affect background/foreground services, with/without partial/full wakelocks?
Not exactly a direct answer but still - I needed to schedule an action every minute in my foreground service (give or take a second).
Fortunately I was capturing sensors in this foreground service too, I made onSensorChanged event check if the right time has passed and act if needed.

Android AlarmManager elapsedTime fires wrong

Ok, so I'm setting an alarm:
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerTime, pendingIntent);
where
long triggerTime = SystemClock.elapsedRealtime() + mynterval;
I'm saving triggerTime for comparison in future.
And sometimes alarm is firing before triggerTime!
For example, I can see in logs:
scanTime: 702672466
SystemClock.elapsedRealtime: 702672132
What delta error is possible here - 1 second, 2-3 seconds or more?
And why is this happening?
This is happening due to Android Doze Mode.
If a user leaves a device unplugged and stationary for a period of time, with the screen off, the device enters Doze mode. In Doze mode, the system attempts to conserve battery by restricting apps' access to network and CPU-intensive services.
Now, alarm is the case of CPU-intensive services. As you can see in the image the intensive jobs are done together in so-called maintenance windows.
Standard AlarmManager alarms (including setExact() and setWindow()) are deferred to the next maintenance window.
If you need to set alarms that fire while in Doze, use setAndAllowWhileIdle() or setExactAndAllowWhileIdle().
Alarms set with setAlarmClock() continue to fire normally — the system exits Doze shortly before those alarms fire.

setExactAndAllowWhileIdle - is not exact as of developer reference

AlarmManager on API19 has the method setExact() to set an exact alarm.
Exact means --> If I set an alarm to 2:01 pm it will be triggered at 2:01 pm
On API 23 - Marhsmwallow (6.0) there is a new method setExactAndAllowWhileIdle(), but as of the reference it is not EXACT because it will trigger only every minute and in low power idle mode only every 15 minutes.
Exact != every 15 minutes :-)
So how can I achieve an exact alarm with AlarmManager in 6.0?
If a user adds a reminder or a calendar appointment and wants to be informed 10 minutes before the event it should show the alarm EXACT 10 minutes before the event. With setExactAndAllowWhileIdle() this seems is not possible.
Reference Link:
http://developer.android.com/reference/android/app/AlarmManager.html#setExactAndAllowWhileIdle(int, long, android.app.PendingIntent)
So how can I achieve an exact alarm with AlarmManager in 6.0?
You are welcome to try setAlarmClock(), as AFAIK it is unaffected by Doze mode. Otherwise, AlarmManager is not a viable option for you. Even having your app on the battery optimization whitelist will not help, as AlarmManager behavior does not change based on the whitelist.
You are welcome to use GCM, as a high-priority message should give you an opportunity to alert the user. This, of course, requires network connectivity.
The only offline solution that I am aware of — and that I am presently testing — is to have the user add your app to the battery optimization whitelist, then use a foreground service (to try to keep your process around), a ScheduledExecutorService (for the timing), and a partial WakeLock (to keep the CPU on). This will be fairly devastating to the user's battery.
Using setExactAndAllowWhileIdle() for a one-time alarm will fire exactly on the given time even in Doze idle mode. So this probably is the way to go.
Problems start, if you want to repeat the alarm at a rate of < 15 min (or set any other at a time < 15 min away from the last one), as this will not work in Doze idle mode, where such alarms are forced to the next 15 min or are executed when idle maintenance starts, which happens for about ten minutes first after 1 hour, then after another 2 hours, then after another 4 hours and so on.
- EDIT -
As of today Nov 17, Dianne Hackborn writes in this Post's comments:
"For what it's worth, the minimum time between while idle alarms will be changing to 9 minutes at some point relatively soon (even on devices running the current Marshmallow builds)."
This doesn't change anything fundamentally though.
Here are my discussion with Ian Lake on Google+!
setExactAndAllowWhileIdle() is exact and should work.
The 15 minutes time frame is wrong in the java doc.
I was trying to create an automation system running in the background. My frequency range was between 1-15 minutes. My wish was not to use a foreground service. By looking at the name of the method "setExactAndAllowWhileIdle", I thought that yeah it is safe to go with one-time alarms, scheduling the next one when done.
However, I couldn't find a way to run code in doze mode with alarms running more frequent than 15 minutes. Instead, I choose to start a foreground service when doze mode gets activated and stop that foreground service when phone awakes. User won't be seeing your foreground notification while using his/her phone. I don't care much about the ones in doze mode.
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if(intent.getAction().equals("android.os.action.DEVICE_IDLE_MODE_CHANGED")){
if (pm.isDeviceIdleMode()) {
//startAutomationForegroundService();
} else {
//stopAutomationForegroundService();
return;
}
AutomationReceiver.completeWakefulIntent(intent);
return;
}
}
You need to register "android.os.action.DEVICE_IDLE_MODE_CHANGED" intent filter into your WakefulBroadcastReceiver. Care putting it into manifest may not help.

Categories

Resources