python-for-android icon indicating copy to clipboard operation
python-for-android copied to clipboard

WorkManager support

Open dbnicholson opened this issue 2 years ago • 1 comments

This enables WorkManager tasks via the --worker p4a option. This is based on the work in #2464, with the following differences:

  • Support is added in the common bootstrap rather than the service_library bootstrap so it can be used by p4a apps. I believe it should still work in the service_library context, but I haven't tested.
  • I removed the bound service addition. That might still be useful, but my goal was to support WorkManager tasks, and that wasn't needed. I believe in #2464 they were using the bound service as the target for the WorkManager tasks, but I changed it so that each worker has a generated service class. The generated service class is based on RemoteWorkerService, which itself implements a bound service.

An important thing to note is that since p4a only supports one python interpreter per process (see #2609), the work task is always run in a separate process via a RemoteListenableWorker. That seems to work well except that I couldn't get cancellation to work. The downside of this approach is that the androidx work-multiprocess release including this support requires SDK 30.

The bulk of the work is in the "Support WorkManager tasks" commit. Everything before that is preparation, which could be split out into a separate PR if that's preferred.

There are still a couple things I haven't completed:

  • [x] I added a --worker test in the on-device tests, but it's only being run in the flask webview app. It would be good to be able to test it in the kivy app, too.
  • [ ] I haven't tested foreground handling and the PythonWorker class doesn't implement the getForegroundInfoAsync() and getForegroundInfo() methods.
  • [x] Documentation
  • [ ] ~~Currently there's ugly WorkManager.initialize call in the generated worker service since the androidx startup handling doesn't seem to work on remote processes. It seems to work, but I don't think it's the right way to do it.~~ This isn't ideal, but I think it's fine this way.

dbnicholson avatar Jun 01 '22 17:06 dbnicholson

I fleshed this out some more and got cancellation to work. It turns out that I was just doing it wrong and blocking on the python thread in the worker. That's wrong as it doesn't allow the future to be returned and WorkManager doesn't get it until the python process has completed.

Otherwise, I spent some time trying to make sure the worker service always exits since you can get strange errors if you run python more than once in a process. That works most of the time, but sometimes if you cancel work and then run work to completion it won't exit since the service is still bound from the cancelled work. I think you'd need to address #2610 so that the python thread could be stopped without killing the whole process.

Lastly, I have some work in progress on getForegroundInfoAsync(), but I ran out of time right now to complete it. I might be able to get to that in the next week.

dbnicholson avatar Aug 03 '22 21:08 dbnicholson