tmo1 / sms-ie

SMS Import / Export is a simple Android app that imports and exports SMS and MMS messages, call logs, and contacts from and to JSON / NDJSON files.
GNU General Public License v3.0
319 stars 38 forks source link

Try to run scheduled exports in foreground service where possible #131

Closed chenxiaolong closed 8 months ago

chenxiaolong commented 9 months ago

Android 14 introduced a change in the CachedAppOptimizer component that kills apps that perform too many binder transactions in the background [1]. This can happen where there are many messages to export (2000 or so from empirical testing).

This restriction does not apply to foreground services, so this commit adds support for opportunistically running ExportWorker inside WorkManager's foreground service. Unfortunately, on Android 12+, this is not allowed by default because ExportWorker's startup method of using a delay on a OneTimeWorkRequestBuilder is not one of the exemptions for running a foreground service.

To allow a foreground service to run, the user must disable Android's battery optimizations for the app. This commit adds a toggle to do so in the sms-ie's own settings so the user doesn't need to dig into Android's Settings to find the option. If foreground service access is not available (because eg. battery optimizations are enabled or the app is running on an old version of Android), then the worker will fall back to running in a plain old background service like before.

[1] https://android.googlesource.com/platform/frameworks/base.git/+/71d75c09b9a06732a6edb4d1488d2aa3eb779e14%5E%21/ [2] https://developer.android.com/guide/components/foreground-services#background-start-restriction-exemptions

Fixes: #129

chenxiaolong commented 9 months ago

I've tested this with Android 14 on a Pixel device, but unfortunately, I don't have any devices running Android <=13 that are capable of calls/SMS. I'd appreciate it if someone could help test there to make sure I haven't broken anything.

To manually trigger the scheduled job:

  1. Enable scheduled exports from the UI.

  2. Get the job ID by running:

    adb shell dumpsys jobscheduler | grep 'JOB #.*sms_ie'

    It will print out something like the following. The number after the first slash is the job ID (8 in this example).

      JOB #u0a312/8: c66a305 com.github.tmo1.sms_ie/androidx.work.impl.background.systemjob.SystemJobService
  3. Trigger the job ID.

    adb shell cmd jobscheduler run -f com.github.tmo1.sms_ie <job ID>

    Note that the ID will change after every run.

AndroFlipper commented 9 months ago

Trying it tonight (Android 11). Will let you know...