Android. Is WorkManager running when app is closed? - android

I want to schedule nightly database updates. So I use new Android WorkManager. My understanding is that once scheduled it will always run in the background independently from the app's lifecycle.
Is that right? My first tests show that Work is only being performed when the app is running.
val locationWork = PeriodicWorkRequest.Builder(UpdateDatabaseWorker::class.java, 24, TimeUnit.HOURS)
.addTag("DATABASE_UPDATE_SERVICE")
.build()
WorkManager.getInstance().enqueue(locationWork)

Based on various issues reported on the WorkManager bugtracker, their documentation is not completely precise about the exact behavior of the WorkManager in such edge cases.
On certain devices, apps are force stopped when the app is cleared from task manager, so that part is expected. ... source
Unfortunately, some devices implement killing the app from the recents menu as a force stop. Stock Android does not do this. When an app is force stopped, it cannot execute jobs, receive alarms or broadcasts, etc. So unfortunately, it's infeasible for us to address it - the problem lies in the OS and there is no workaround. source
The only issue that we have come across is the case where some Chinese OEMs treat swipe to dismiss from Recents as a force stop. When that happens, WorkManager will reschedule all pending jobs, next time the app starts up. Given that this is a CDD violation, there is not much more that WorkManager can do given its a client library. source
To add to this, if a device manufacturer has decided to modify stock Android to force-stop the app, WorkManager will stop working (as will JobScheduler, alarms, broadcast receivers, etc.). There is no way to work around this. Some device manufacturers do this, unfortunately, so in those cases WorkManager will stop working until the next time the app is launched. source
With intense testing of a OneTimeWorkRequest (without constraints) on a Pixel 2 XL with stock android the behavior is the following:
Task manager close:
Work continues (after a bit)
Reboot device (work running):
Work continues after reboot done
App info "Force stop":
Work stops, will only continue when app is started again
Reboot device (work was "Force Stopped"):
Work does not continue until the app is started again
You can find a complete list of different OEM behaviors on dontkillmyapp.com. It seems the Android team also acknowledges this issue and added a test for this into their CTS test for Android Q. source

My understanding is that once scheduled it will always run in the
background independently from the app's lifecycle. Is that right?
Yes. Based on the documentation
The task is still guaranteed to run, even if your app is force-quit or
the device is rebooted.
WorkManager chooses the appropriate way to run your task based on factors such as the device API level and the app state. If WorkManager executes one of your tasks while the app is running, WorkManager can run your task in a new thread in your app's process. If your app is not running, WorkManager chooses an appropriate way to schedule a background task--depending on the device API level.
WorkManager might use JobScheduler, Firebase JobDispatcher, or AlarmManager depending on the API level. It will repect the Doze and conaider all other constraints before executing the Work. You can expect some delay in Doze mode since it could wait for maintenance window.
Note:
WorkManager is intended for tasks that require a guarantee that the system will run them even if the app exits, like uploading app data to a server. It is not intended for in-process background work that can safely be terminated if the app process goes away; for situations like that, we recommend using ThreadPools.

This is what documentation is saying:
Note: WorkManager is intended for tasks that require a guarantee that the system will run them even if the app exits, like uploading app data to a server. It is not intended for in-process background work that can safely be terminated if the app process goes away; for situations like that, we recommend using ThreadPools.
But there must be some condition. if that condition meet then WorkManager will run the task (this is important). Conditions like "only while device is charging and online"
Read this carefully, The WorkManager attempts to run your task at the interval you request, subject to the constraints you impose and its other requirements.
Here I found a good tutorial about how to use WorkManager for scheduling tasks : https://android.jlelse.eu/how-scheduling-work-with-new-android-jetpack-component-workmanager-852163f4825b

Related

Can Android WorkManager able to run in Standby mode or App is Killed

Work manager of course can run if the phone is runing and the app is in the background.
But what if I killed the APP, or switch off the screen of the phone? What is it affect to the WorkManager?
Yes. That's the reason why WorkManager has been designed.
Even if your device off and have a periodic work request, the system will take care of you worker once the device has been restarted.
This is well tested by the Android team, no need to test it.
However, there are 2 scenarios when the Worker doesn't get triggered:
Low memory, Android forces stop your app.
You force stop the app on your own.
For both scenarios, in order for the WorkManager to be started you need to re-launch the closed app.
Take a look at the docs for more: https://developer.android.com/topic/libraries/architecture/workmanager

Perform critical un-deferrable work in a system application service

I am working with a system application. It has to perform some extremely critical tasks in a service that are triggered by broadcasts from the system.
Due to the background execution limits introduced in Oreo, I've been thinking a lot about how to perform the tasks in the background.
The tasks have the following requirements:
They may not be deferred, they have to be started instantly.
They shall be started even if the phone is idle (or dozing, I haven't really understood the difference)
They are highly critical. They shall complete after being started, under all circumstances.
I looked into using IntentService. But, they recommend using JobIntentService instead due to the background execution restrictions. However, this doesn't comply with my requirement of not deferring the work. It also says that JobScheduler does not run during doze. When running on O or later, JobIntentService will perform the task as a JobService Job:
When running as a Job, it will be subject to standard JobScheduler policies for a Job with a setOverrideDeadline(long) of 0: the job will not run while the device is dozing, it may get delayed more than a service if the device is under strong memory pressure with lots of demand to run jobs.
It seems like using a regular IntentService may expose the tasks to the possibility to be stopped/killed by the system under certain circumstances, imposed by the new restrictions from Oreo and above.
The safest option seems to be to launch a foreground service. But, I don't necessarily want to show a notification during the service's lifetime. Also, I believe that if the user accidentally disables the notification channel in the settings, the service cannot be started anymore. I'm also worried about edge cases where the system may arbitrarily kill or stop my service, or simply stop my work in some other way by not honoring my wake lock etc.
I recently came across the android:persistent in the application tag in the manifest. It says it can only be used by system applications. According to this blog post from 2011 setting this attribute to true renders your application and it's services un-killable. It also implies that it can let you have a background service that is "always alive". But how does this relate to doze, battery optimizations etc? Do I still have to acquire a wake lock and whitelist my app from battery optimizations in order to continue performing the background work during doze conditions?
Thanks a lot for reading and I hope you have some valuable input. I am currently a bit confused, trying to put all the pieces together. It doesn't help that the documentation is (as per usual)... lacking.

JobScheduler Android Oreo Issue

In my current application for a company Im having a ForegroundService that is running while the workers are on duty (logged in to the app).
It is important to keep that foreground service running while users are logged in. To recover from cases where this foreground service gets killed somehow (User task swipe accidently or System kill) ive implemented a periodic JOB with Jobscheduler which reactivates the ForegroundService in case it gets shut down. This technique works well pre Android 8 OREO. START_STICKY and other techniques alone did not do the trick for me.
In Android 8, as soon as the foreground service gets killed, the periodic job gets killed as well. Im getting the notification in logcat that the job is not allowed to run. To my understanding, Jobs schould be able to run even when app is in background or killed. And its working on pre OREO devices the way it should.
To my knowledge, I can fix that by enable the option "autostart" in app settings. But since there is no way to know if employees tunred that on, its not a reliable thing as well.
So my questions:
- Why does the Job scheduler stops working as it should in Android 8?
- Are there any other reliable techniques I could use to let my ForegroundService recover from shutdowns in ANDROID OREO?
Ive read https://medium.com/exploring-android/exploring-background-execution-limits-on-android-oreo-ab384762a66c but that did not answer my questions
Thank you very much
did you try to put
.setPersisted(true)
Note: Requires the RECEIVE_BOOT_COMPLETED permission.
you can also see this question.
Job Scheduler not running on Android N
reading some references:
1- The services in andreo oreo if posses a buggle oreo will kill it for energy loss in 7 is a warning but in 8 applies more strict
2 - The jobs scheduler has a time of 15 minutes and avaces is not executed in the precise time debit that they look for the precise moment to execute the event without that the battery of the cellular one is descaste
I recommend that you use this library that provides evernote that is very good and very specific:
https://github.com/evernote/android-job

Should a WorkManager be used with a SyncAdapter?

Previously one could assure a series of updates using an IntentService or SyncAdapter w/ a WakeLock.
Now with the new Doze mode, and limitations to save battery, is WakeLock still reliable enough, or should longer processes be started in the IntentService or SyncAdapter using WorkManager?
Also is WorkManager api production-ready?
As far as I understand it, the WorkManager can replace IntentService and SyncAdapter completely. E.g. everything you're doing in SyncAdapter.onPerformSync() can now be in WorkManager.doWork().
It got a stable release 2.4.0 and is ready for production.
Regarding wake locks: In Android 8.0 there is the following change:
As one of the changes that Android 8.0 (API level 26) introduces to improve battery life, when your app enters the cached state, with no active components, the system releases any wakelocks that the app holds.
So I wouldn't rely on wake locks anymore. I think they will be completely removed in future Android versions. And most of the time you don't need them with the WorkManager.
I wouldn't bother using JobScheduler or AlarmManager. WorkManager sits on top of these, and handles everything for you, doesn't matter what android version your app runs on.
https://codelabs.developers.google.com/codelabs/android-workmanager
Here's a good example about WorkManager, where they use a Worker for image processing, but it's perfectly good to do any long-running tasks.
You can specify constraints on various things, including if you want the device to be idle to run the worker. You can also chain the workers, pass data from one to other, even group them and run some parallel, wait for all to finish and then continue with another (or more) worker(s).
Depending on your use case, you can basically start a worker from anywhere (activity, broadcast receiver, stc).
In fact I use workers started from a broadcast receiver to do some api calls, only when you have internet connection of course (settable constraint) and it's so easy to set up and works so well, I only can recommend it to use (and bless Google for finally making these AC libraries).
I also really like the fact that the WorkManager saves works to db with room, so it can pick it up whenever all the conditions check out, even if you restart the device between. If you have some monitoring set up (like for example stetho), you can actually see how it saves the jobs to its own database.
It's still in alpha, but it's so solidly built, I don't think they'll change too much until they release the final version.

Android - JobScheduler or BroadcastReceiver?

In my Android app I need to do some work every time the user plugs their device. For this purpose right now I use a BroadcastReceiver, which starts my IntentService to do the work when the user plugs the device and stops it when the device becomes unplugged.
Right now I'm thinking of using JobScheduler for Android 5.0+, but what I'm seeing is that with JobScheduler, I would have to schedule my job within the app, by calling
JobScheduler.schedule(JobInfo);
But this is a problem to me, because I want my job to run every time the user connects their device to the charger, even without the user having to open my app.
For this reason, I think one way would be to schedule it the first time the user opens the app, and then always force reschedule, since I cannot trust on the user opening my app every day (which, due to the nature of my app, certainly won't happen).
So, should I stick with BroadcastReceiver or use JobScheduler for Android 5.0+?
And in the case of using JobScheduler, should I schedule my job only once and then always return true in order to force rescheduling?
Thank you.
So, should I stick with BroadcastReceiver or use JobScheduler for Android 5.0+?
Use JobScheduler, this can improve your app’s performance, along with aspects of system health such as battery life. Also, JobScheduler persists through device reboots and supports batch scheduling by which the android system can combine pending jobs thus reducing battery usage. Moreover, you can do distinguish between android versions thus using JobScheduler on Lollipop and up, and AlarmManager on older versions.
And in the case of using JobScheduler, should I schedule my job only once and then always return true in order to force rescheduling?
Now, there are 2 ways to do this :
As you guessed, scheduling your job only once and always returning true in jobFinished() - this should do the trick.
Upon completing a job (originally scheduled by you by calling JobScheduler.schedule(JobInfo)), you schedule another job by calling the same. This will schedule consequent jobs once each job is about to be completed.
Jobscheduler runs in the background and persists through reboots so you should be fine.

Categories

Resources