Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2247c3c6 authored by Makoto Onuki's avatar Makoto Onuki Committed by Android (Google) Code Review
Browse files

Merge "Add sync manager documentation on app-standby exemption"

parents ca8c7689 705e7865
Loading
Loading
Loading
Loading
+3 −3
Original line number Original line Diff line number Diff line
@@ -294,9 +294,9 @@ public class RequestSync {
                "       -a|--authority <AUTHORITY>\n" +
                "       -a|--authority <AUTHORITY>\n" +
                "    App-standby related options\n" +
                "    App-standby related options\n" +
                "\n" +
                "\n" +
                "       -f|--foreground (cause WORKING_SET, FREQUENT sync adapters" +
                "       -f|--foreground (defeat app-standby job throttling," +
                        " to run immediately)\n" +
                " but not battery saver)\n" +
                "       -F|--top (cause even RARE sync adapters to run immediately)\n" +
                "       -F|--top (defeat app-standby job throttling and battery saver)\n" +
                "    ContentResolver extra options:\n" +
                "    ContentResolver extra options:\n" +
                "      --is|--ignore-settings: Add SYNC_EXTRAS_IGNORE_SETTINGS\n" +
                "      --is|--ignore-settings: Add SYNC_EXTRAS_IGNORE_SETTINGS\n" +
                "      --ib|--ignore-backoff: Add SYNC_EXTRAS_IGNORE_BACKOFF\n" +
                "      --ib|--ignore-backoff: Add SYNC_EXTRAS_IGNORE_BACKOFF\n" +
+2 −0
Original line number Original line Diff line number Diff line
@@ -151,6 +151,8 @@ import java.util.function.Predicate;
 * run at a later time. Similarly, when a sync succeeds, backoff is cleared and all associated syncs
 * run at a later time. Similarly, when a sync succeeds, backoff is cleared and all associated syncs
 * are rescheduled. A rescheduled sync will get a new jobId.
 * are rescheduled. A rescheduled sync will get a new jobId.
 *
 *
 * See also {@code SyncManager.md} in the same directory for how app-standby affects sync adapters.
 *
 * @hide
 * @hide
 */
 */
public class SyncManager {
public class SyncManager {
+122 −0
Original line number Original line Diff line number Diff line
# Sync Manager notes

## App-standby and Sync Manager

Android 9 Pie introduced
["App Standby Buckets"](https://developer.android.com/topic/performance/appstandby), which throttles various things
including
[JobScheduler](https://developer.android.com/reference/android/app/job/JobScheduler)
and [AlarmManager](https://developer.android.com/reference/android/app/AlarmManager),
[among other things](https://developer.android.com/topic/performance/power/power-details),
for background applications.

Because SyncManager executes sync operations as JobScheduler jobs, sync operations are subject
to the same throttling.

However, unlike JobScheduler jobs, any apps (with the proper permission) can schedule a sync
operation in any other apps using
[ContentResolver.requestSync()](https://developer.android.com/reference/android/content/ContentResolver#requestSync(android.content.SyncRequest)),
whch means it's possible for a foreground app to request a sync in another app that is either in the
background or is not even running.
For example, when the user hits the refresh button on the Contacts app, it'll
request sync to all the contacts sync adapters, which are implemented in other packages (and they're
likely not in the foreground).

Because of this, calls to
[ContentResolver.requestSync()](https://developer.android.com/reference/android/content/ContentResolver#requestSync(android.content.SyncRequest))
made by foreground apps are special cased such that the resulting sync operations will be
exempted from app-standby throttling.

### Two Levels of Exemption
Specifically, there are two different levels of exemption, depending on the state of the caller:
1. `ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET`
2. `ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP`, which is more powerful than 1.

The exemption level is calculated in
[ContentService.getSyncExemptionAndCleanUpExtrasForCaller()](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/content/ContentService.java?q=%22int%20getSyncExemptionAndCleanUpExtrasForCaller%22&ss=android%2Fplatform%2Fsuperproject),
which was [implemented slightly differently](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/content/ContentService.java?q=%22int%20getSyncExemptionAndCleanUpExtrasForCaller%22&ss=android%2Fplatform%2Fsuperproject)
in Android 9, compared to Android 10 and later.

The logic is as follows:
- When the caller's procstate is `PROCESS_STATE_TOP` or above,
  meaning if the caller has a foreground activity,
  `SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP` will be set.

- Otherwise, when the caller's procstate is `PROCESS_STATE_IMPORTANT_FOREGROUND` or above,
  e.g. when the caller has a foreground service, a service bound by the system of a specific kind,
  `SYNC_EXEMPTION_PROMOTE_BUCKET` will be set.

- Additionally, on Android 10 and later, when the caller is
  "UID-active" (but the procstate is below `PROCESS_STATE_TOP`),
  `SYNC_EXEMPTION_PROMOTE_BUCKET` will be set.
  This is what happens when the app has just received a high-priority FCM, for example.
  Temp-allowlist is also used in various other situations.

### Behavior of Each Exemption

The exemptions are tracked in `SyncOperation.syncExemptionFlag`.

- Behavior of `SYNC_EXEMPTION_PROMOTE_BUCKET`
  - This will add `JobInfo.FLAG_EXEMPT_FROM_APP_STANDBY` to the sync job. This makes the job
    subject to "ACTIVE" app quota, so minimum deferral will be applied to it.

  - This also reports `AppStandbyController.reportExemptedSyncStart()`, so the package that owns
    the sync adapter is temporarily put in the "ACTIVE" bucket for the
    duration of `mExemptedSyncStartTimeoutMillis`, whose default is 10 minutes as of 2020-10-23.

    This will allow the app to access network, even if it has been in the `RARE` bucket
    (in which case, the system cuts its network access).

    Note if the device is dozing or in battery saver, promoting to the "ACTIVE" bucket will still
    _not_ give the app network access.

- Behavior of `SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP`
  - This gives all the perks given by `SYNC_EXEMPTION_PROMOTE_BUCKET`, plus puts the target app
    in the temp-allowlist (by calling `DeviceIdleInternal.addPowerSaveTempWhitelistApp()`)
    for the duration of `SyncManagerConstants.getKeyExemptionTempWhitelistDurationInSeconds()`,
    whose default is 10 minutes.

    Temp-allowlist will grant the app network access even if the device is in doze or in battery
    saver.

    (However, note that when the device is dozing, sync jobs will not run anyway.)

### How Retries Are Handled

- When a sync operation needs a retry, SyncManager creates a new operation (job) with a back-off
  (in `SyncManager.maybeRescheduleSync()`). In this case, the new sync operation will inherit
  `SyncOperation.syncExemptionFlag`, unless the number of retries (not counting the original sync
  job) is equal to or greater than `SyncManagerConstants.getMaxRetriesWithAppStandbyExemption()`,
  whose default is 5.

### Special-handling of Pre-installed Packages

- When a content provider is accessed, `AppStandbyController.reportContentProviderUsage()` is
  triggered, which elevates the standby bucket of the associated sync adapters' packages to `ACTIVE`
  for the duration of `mSyncAdapterTimeoutMillis`, whose default is 10 minutes, but _only for_
  pre-installed packages. This is to help pre-installed sync adapters, which often don't have UI,
  sync properly.

- Also, since Android 11, all the pre-installed apps with no activities will be kept in
  the `ACTIVE` bucket, which greatly relaxes app-standby throttling. But they're still subject
  to doze and battery saver.

### Summary

- When the device is dozing, no sync operations will be executed.

- Normally, sync operations are subject to App-Standby, which throttles jobs owned by background
  apps. Jobs owned by foreground apps are not affected.

- A sync operation requested by a foreground activity will be executed immediately even if the
  app owning the sync adapter is in RARE bucket, and the device is in battery saver.

- A sync operation requested by a foreground service (or a "bound foreground" service)
  will be executed immediately even if the app owning the sync adapter is in RARE bucket,
  *unless* the device is in battery saver.

  Since Android 9 and later, the same thing will happen if the requester is temp-allowlisted (e.g.
  when it has just received a "high-priority FCM").

- There are certain exemptions for pre-installed apps, but doze and battery saver will still
  block their sync adapters.
 No newline at end of file