Status Update
Comments
su...@google.com <su...@google.com> #2
If you are using location, you should be using the permissions API to ensure that you have the permissions you need to track background location before any attempts to use APIs that require that permission.
SystemForegroundService
just provides a convenient entry point for the ListenableWorker
. If you require additional permissions, its the app's responsibility to ask for permissions and check that those permissions are granted.
dr...@gmail.com <dr...@gmail.com> #3
We are performing location checks before submitting the WorkManager job. However, the problem exists if the location permission is removed by the User after the job has been submitted. The OS is force killing the app (when the location permission is removed), and the OS is trying to restart the SystemForegroundService which then crashes our app immediately on launch. We are not interacting with the WorkManager in this scenario other than initialising it which is necessary on app start, e.g.
val workManagerConfig = Configuration.Builder()
.setWorkerFactory(entryPoints.getWorkerFactory())
.build()
// Initialize WorkManager with the custom configuration.
WorkManager.initialize(context, workManagerConfig)
return WorkManager.getInstance(context)
ra...@google.com <ra...@google.com> #4
I think it might be best for now if your foreground worker does not declare that it is a location foreground service and instead it is either a 'short' service or a 'special use' service such that WorkManager's SystemForegroundService
redeliver intent restarts your foreground worker and in it you can check for location permission and then start a real foreground location service.
Meanwhile we have to adapt WorkManager's SystemForegroundService
to Android 14 requirements to have a foreground service type along with its permission runtime check as otherwise many of the types have runtime permissions pre-requisites.
dr...@gmail.com <dr...@gmail.com> #5
Sorry, I just re-read the changes for Android 14, and for this to work elegantly, we will need to change the implementation of SystemForegroundService
to do the right thing.
Will try to land this in the next WorkManager release.
ra...@google.com <ra...@google.com> #6
dr...@gmail.com <dr...@gmail.com> #7
ra...@google.com <ra...@google.com> #8
dr...@gmail.com <dr...@gmail.com> #9
Hey - We are working on a fix that will prevent WorkManager from crashing when the foreground worker is restarted due to permission loss. Be aware though that WorkManager won't be able to set the app in a foreground state and it is expected for the worker to self check the required permissions and to probably return a Result.failure()
from the work override.
ra...@google.com <ra...@google.com> #10
Branch: androidx-main
commit 4616a739983e6316819dc515057677edf40a41c1
Author: Daniel Santiago Rivera <danysantiago@google.com>
Date: Wed Jul 24 08:59:34 2024
Catch SecurityException in startForeground
In API 34, startForeground() will throw SecurityException if the service type prerequisites are not met. WorkManager won't be able to start the foreground service but the worker is likely to continue and ideally fail once it checks the permission needed to do the actual work. The worker will also be subject to JobScheduler limitations.
This change mitigates the crashing issue of a foreground worker running and the app losing the prerequisite permission, causing the app to restart and due to SystemForegroundService being sticky, it restarting too but failing at startForeground() due to missing permissions.
Bug: 333957914
Test: Manual
Change-Id: I96607f62fdd456290163ee6f2774f9d31c64e79e
M work/work-runtime/src/main/java/androidx/work/impl/foreground/SystemForegroundService.java
ap...@google.com <ap...@google.com> #11
Branch: androidx-main
commit c540fa0564df85fa4e3cfd2d98f532f4120e12d8
Author: Daniel Santiago Rivera <danysantiago@google.com>
Date: Wed Jul 24 09:48:38 2024
Add foreground worker with location
Updates WorkManager integration app to validate Android 14 foreground service type requirements, including the addition for a foreground worker who uses location APIs.
Bug: 333957914
Test: n/a
Change-Id: I9ac76d029ab0f0e4d1256145bdc2e3cb20b27c36
M work/integration-tests/testapp/lint-baseline.xml
M work/integration-tests/testapp/src/main/AndroidManifest.xml
A work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/ForegroundLocationWorker.kt
M work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/ForegroundWorker.kt
M work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/MainActivity.kt
M work/integration-tests/testapp/src/main/res/layout/activity_main.xml
M work/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
Description
When I set up a periodic job, I want the first in the series to be performed INSTANTLY (the user expects it... they hit a button and are waiting for an immediate result), and then for subsequent ones to be performed based on the periodic schedule (more vague timings is fine... the user is no longer waiting).
When you set up a periodic work request *without* a flex interval, it can run anytime in the set interval, i.e. from NOW until the end of the interval. If the device is awake when the periodic work request is scheduled, which is the case for me, I find that the first work in the series is generally performed at the START of the interval, i.e. NOW... though "NOW" may not be instantly (it's up to the device to decide... may be delayed a few seconds).
Because it cannot be guaranteed that the first periodic work will be performed *instantly*, instead I do an explicit call to the work-performing function outside of the WorkManager realm, and put a flexInterval on the periodic work of 5 mins so that the first periodic work will certainly not be performed straight away, but instead it will be near the end of the first period, most likely 5 mins before the end. This is not quite ideal (first gap between work runs is not quite a full interval) but it's OK... the user won't care or even notice it runs 5 mins "early" the first time.
Now, I thought that the ability to set an "initialDelay" in 2.1.0 would solve my problems... so that I could:
(a) still make an explicit call to the work-performing function to do the immediate work, guaranteed to be NOW (the user expects that)
(b) set up a periodic work request WITHOUT flexInterval (i.e. use the whole interval) and WITH an initial delay equal to the period "interval"
That way, I get the immediate work done, and then after "interval" the periodic work request is scheduled, and because (let's assume) the device is still awake, the first periodic work will likely perform at the START of the interval, i.e. almost straight away, i.e. pretty close to exactly one "interval" after the user set the schedule going.
BUT I'm not finding that. Let's say that "interval" of the periodic work is 15 mins, and I set an "initial delay" also of 15 mins, and I set this going when the user hits the button. I find that the immediate work is performed at 0 mins (triggered explicitly, not by WorkManager, so that's as expected), then at 15 mins NOTHING happens, and only at 30 mins does the first periodic work actually run.
It seems that either the first periodic work happens at the END of the first interval (15-30 mins) and not the start (like it usually does, if the device is awake and not busy), or WorkManager delayed first periodic interval to be at 30-45 mins, i.e. it waited 30 mins not 15 mins, twice what I asked for.
So, how is "setInitialDelay" for a periodic work request meant to work? It doesn't just wait "delay" (instead of not waiting at all) and then enqueue the periodic work request?