summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Makoto Onuki <omakoto@google.com> 2020-10-22 14:32:56 -0700
committer Makoto Onuki <omakoto@google.com> 2020-10-28 18:45:22 +0000
commit705e7865e716f1a1060eb501c9e720e29404bbac (patch)
treedb2db1edb975860a7ecc68a85f25c755da4dbea9
parent0583d29f136d16793bcc5d74beb21431d364b2d8 (diff)
Add sync manager documentation on app-standby exemption
Also fix the command line flag help for "adb shell requestsync". Bug: n/a Test: n/a, doc only change Change-Id: I53ad0cae99d30050d1cd8bab349096605865b9fc
-rw-r--r--cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java6
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java2
-rw-r--r--services/core/java/com/android/server/content/SyncManager.md122
3 files changed, 127 insertions, 3 deletions
diff --git a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
index 8683ca163fb6..a0361d0a39d3 100644
--- a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
+++ b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
@@ -294,9 +294,9 @@ public class RequestSync {
" -a|--authority <AUTHORITY>\n" +
" App-standby related options\n" +
"\n" +
- " -f|--foreground (cause WORKING_SET, FREQUENT sync adapters" +
- " to run immediately)\n" +
- " -F|--top (cause even RARE sync adapters to run immediately)\n" +
+ " -f|--foreground (defeat app-standby job throttling," +
+ " but not battery saver)\n" +
+ " -F|--top (defeat app-standby job throttling and battery saver)\n" +
" ContentResolver extra options:\n" +
" --is|--ignore-settings: Add SYNC_EXTRAS_IGNORE_SETTINGS\n" +
" --ib|--ignore-backoff: Add SYNC_EXTRAS_IGNORE_BACKOFF\n" +
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index c686ba4c4b5c..853edcac0833 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -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
* 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
*/
public class SyncManager {
diff --git a/services/core/java/com/android/server/content/SyncManager.md b/services/core/java/com/android/server/content/SyncManager.md
new file mode 100644
index 000000000000..8507abdcc40e
--- /dev/null
+++ b/services/core/java/com/android/server/content/SyncManager.md
@@ -0,0 +1,122 @@
+# 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