Tweak exemption for sync requests made by FG apps
Exemption given to a sync request made by a foreground app (including
PROCESS_STATE_IMPORTANT_FOREGROUND).
At the schedule time, we promote the sync adapter app for a higher bucket:
- If the device is not dozing (so the sync will start right away)
promote to ACTIVE for 1 hour.
- If the device is dozing (so the sync *won't* start right away),
promote to WORKING_SET for 4 hours, so it'll get a higher chance to be started once the
device comes out of doze.
- When the sync actually starts, we promote the sync adapter app to ACTIVE for 10 minutes,
so it can schedule and start more syncs without getting throttled, even when the first
operation was canceled and now we're retrying.
Test: atest cts/tests/tests/syncmanager/
Test: Manual test with "requestsync -f" and "am set-standby-bucket", while checking
"dumpsys usagestats"
Test: settings put global app_idle_constants \
exempted_sync_scheduled_nd_duration=1,exempted_sync_scheduled_d_duration=2,exempted_sync_start_duration=3
and check "dumpsys usagestats" and make sure the constants are properly updated.
Fixes: 72443754
Change-Id: I233d8e4be85769150830bac798abc04810f4cc7b
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index d7057f4..2c9a494 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -1310,10 +1310,10 @@
: ActivityManager.PROCESS_STATE_NONEXISTENT;
if (procState <= ActivityManager.PROCESS_STATE_TOP) {
- return ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP;
+ return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP;
}
if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
- return ContentResolver.SYNC_EXEMPTION_ACTIVE;
+ return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET;
}
return ContentResolver.SYNC_EXEMPTION_NONE;
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 33cf11b..0a640b8 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1656,7 +1656,7 @@
}
if (syncOperation.syncExemptionFlag
- == ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP) {
+ == ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP) {
DeviceIdleController.LocalService dic =
LocalServices.getService(DeviceIdleController.LocalService.class);
if (dic != null) {
@@ -1668,6 +1668,15 @@
}
}
+ if (syncOperation.isAppStandbyExempted()) {
+ final UsageStatsManagerInternal usmi = LocalServices.getService(
+ UsageStatsManagerInternal.class);
+ if (usmi != null) {
+ usmi.reportExemptedSyncScheduled(syncOperation.owningPackage,
+ UserHandle.getUserId(syncOperation.owningUid));
+ }
+ }
+
getJobScheduler().scheduleAsPackage(b.build(), syncOperation.owningPackage,
syncOperation.target.userId, syncOperation.wakeLockName());
}
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index d097563..25edf40 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -390,10 +390,10 @@
switch (syncExemptionFlag) {
case ContentResolver.SYNC_EXEMPTION_NONE:
break;
- case ContentResolver.SYNC_EXEMPTION_ACTIVE:
+ case ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET:
sb.append(" STANDBY-EXEMPTED");
break;
- case ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP:
+ case ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP:
sb.append(" STANDBY-EXEMPTED(TOP)");
break;
default:
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 6a343f8..11f0701 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -341,6 +341,7 @@
boolean initialization;
Bundle extras;
int reason;
+ int syncExemptionFlag;
}
public static class DayStats {
@@ -1142,6 +1143,7 @@
item.reason = op.reason;
item.extras = op.extras;
item.event = EVENT_START;
+ item.syncExemptionFlag = op.syncExemptionFlag;
mSyncHistory.add(0, item);
while (mSyncHistory.size() > MAX_HISTORY) {
mSyncHistory.remove(mSyncHistory.size()-1);
@@ -1262,6 +1264,20 @@
SyncManager.formatDurationHMS(event, elapsedTime);
event.append(" Reason=");
event.append(SyncOperation.reasonToString(null, item.reason));
+ if (item.syncExemptionFlag != ContentResolver.SYNC_EXEMPTION_NONE) {
+ event.append(" Exemption=");
+ switch (item.syncExemptionFlag) {
+ case ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET:
+ event.append("fg");
+ break;
+ case ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP:
+ event.append("top");
+ break;
+ default:
+ event.append(item.syncExemptionFlag);
+ break;
+ }
+ }
event.append(" Extras=");
SyncOperation.extrasToStringBuilder(item.extras, event);
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index dee2556..8461166 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -218,6 +218,11 @@
+ "stable_charging_threshold=" + STABLE_CHARGING_THRESHOLD;
}
+ @Override
+ public boolean isDeviceIdleMode() {
+ return false;
+ }
+
// Internal methods
void setDisplayOn(boolean on) {
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 3378897..9c62700 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -24,6 +24,8 @@
import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
@@ -194,8 +196,9 @@
static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
/** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
- static final int MSG_REPORT_EXEMPTED_SYNC_START = 12;
- static final int MSG_UPDATE_STABLE_CHARGING= 13;
+ static final int MSG_REPORT_EXEMPTED_SYNC_SCHEDULED = 12;
+ static final int MSG_REPORT_EXEMPTED_SYNC_START = 13;
+ static final int MSG_UPDATE_STABLE_CHARGING= 14;
long mCheckIdleIntervalMillis;
long mAppIdleParoleIntervalMillis;
@@ -213,8 +216,20 @@
long mPredictionTimeoutMillis;
/** Maximum time a sync adapter associated with a CP should keep the buckets elevated. */
long mSyncAdapterTimeoutMillis;
- /** Maximum time an exempted sync should keep the buckets elevated. */
- long mExemptedSyncAdapterTimeoutMillis;
+ /**
+ * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in
+ * non-doze
+ */
+ long mExemptedSyncScheduledNonDozeTimeoutMillis;
+ /**
+ * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in
+ * doze
+ */
+ long mExemptedSyncScheduledDozeTimeoutMillis;
+ /**
+ * Maximum time an exempted sync should keep the buckets elevated, when sync is started.
+ */
+ long mExemptedSyncStartTimeoutMillis;
/** Maximum time a system interaction should keep the buckets elevated. */
long mSystemInteractionTimeoutMillis;
/** The length of time phone must be charging before considered stable enough to run jobs */
@@ -393,6 +408,37 @@
}
}
+ void reportExemptedSyncScheduled(String packageName, int userId) {
+ if (!mAppIdleEnabled) return;
+
+ final int bucketToPromote;
+ final int usageReason;
+ final long durationMillis;
+
+ if (!mInjector.isDeviceIdleMode()) {
+ // Not dozing.
+ bucketToPromote = STANDBY_BUCKET_ACTIVE;
+ usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
+ durationMillis = mExemptedSyncScheduledNonDozeTimeoutMillis;
+ } else {
+ // Dozing.
+ bucketToPromote = STANDBY_BUCKET_WORKING_SET;
+ usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE;
+ durationMillis = mExemptedSyncScheduledDozeTimeoutMillis;
+ }
+
+ final long elapsedRealtime = mInjector.elapsedRealtime();
+
+ synchronized (mAppIdleLock) {
+ AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId,
+ bucketToPromote, usageReason,
+ 0,
+ elapsedRealtime + durationMillis);
+ maybeInformListeners(packageName, userId, elapsedRealtime,
+ appUsage.currentBucket, appUsage.bucketingReason, false);
+ }
+ }
+
void reportExemptedSyncStart(String packageName, int userId) {
if (!mAppIdleEnabled) return;
@@ -402,7 +448,7 @@
AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId,
STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_EXEMPTED_SYNC_START,
0,
- elapsedRealtime + mExemptedSyncAdapterTimeoutMillis);
+ elapsedRealtime + mExemptedSyncStartTimeoutMillis);
maybeInformListeners(packageName, userId, elapsedRealtime,
appUsage.currentBucket, appUsage.bucketingReason, false);
}
@@ -1365,6 +1411,11 @@
.sendToTarget();
}
+ void postReportExemptedSyncScheduled(String packageName, int userId) {
+ mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_SCHEDULED, userId, 0, packageName)
+ .sendToTarget();
+ }
+
void postReportExemptedSyncStart(String packageName, int userId) {
mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_START, userId, 0, packageName)
.sendToTarget();
@@ -1401,6 +1452,16 @@
TimeUtils.formatDuration(mAppIdleParoleDurationMillis, pw);
pw.println();
+ pw.print(" mExemptedSyncScheduledNonDozeTimeoutMillis=");
+ TimeUtils.formatDuration(mExemptedSyncScheduledNonDozeTimeoutMillis, pw);
+ pw.println();
+ pw.print(" mExemptedSyncScheduledDozeTimeoutMillis=");
+ TimeUtils.formatDuration(mExemptedSyncScheduledDozeTimeoutMillis, pw);
+ pw.println();
+ pw.print(" mExemptedSyncStartTimeoutMillis=");
+ TimeUtils.formatDuration(mExemptedSyncStartTimeoutMillis, pw);
+ pw.println();
+
pw.println();
pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
pw.print(" mAppIdleTempParoled="); pw.print(mAppIdleTempParoled);
@@ -1429,6 +1490,7 @@
private IBatteryStats mBatteryStats;
private PackageManagerInternal mPackageManagerInternal;
private DisplayManager mDisplayManager;
+ private PowerManager mPowerManager;
int mBootPhase;
Injector(Context context, Looper looper) {
@@ -1453,6 +1515,7 @@
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mDisplayManager = (DisplayManager) mContext.getSystemService(
Context.DISPLAY_SERVICE);
+ mPowerManager = mContext.getSystemService(PowerManager.class);
}
mBootPhase = phase;
}
@@ -1532,6 +1595,11 @@
return Global.getString(mContext.getContentResolver(),
Global.APP_IDLE_CONSTANTS);
}
+
+ /** Whether the device is in doze or not. */
+ public boolean isDeviceIdleMode() {
+ return mPowerManager.isDeviceIdleMode();
+ }
}
class AppStandbyHandler extends Handler {
@@ -1595,6 +1663,10 @@
mInjector.elapsedRealtime());
break;
+ case MSG_REPORT_EXEMPTED_SYNC_SCHEDULED:
+ reportExemptedSyncScheduled((String) msg.obj, msg.arg1);
+ break;
+
case MSG_REPORT_EXEMPTED_SYNC_START:
reportExemptedSyncStart((String) msg.obj, msg.arg1);
break;
@@ -1684,7 +1756,12 @@
"system_update_usage_duration";
private static final String KEY_PREDICTION_TIMEOUT = "prediction_timeout";
private static final String KEY_SYNC_ADAPTER_HOLD_DURATION = "sync_adapter_duration";
- private static final String KEY_EXEMPTED_SYNC_HOLD_DURATION = "exempted_sync_duration";
+ private static final String KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION
+ = "exempted_sync_scheduled_nd_duration";
+ private static final String KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION
+ = "exempted_sync_scheduled_d_duration";
+ private static final String KEY_EXEMPTED_SYNC_START_HOLD_DURATION
+ = "exempted_sync_start_duration";
private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION =
"system_interaction_duration";
private static final String KEY_STABLE_CHARGING_THRESHOLD = "stable_charging_threshold";
@@ -1693,7 +1770,9 @@
public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR;
public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT = 10 * ONE_MINUTE;
public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT = 10 * ONE_MINUTE;
- public static final long DEFAULT_EXEMPTED_SYNC_TIMEOUT = 10 * ONE_MINUTE;
+ public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT = 10 * ONE_MINUTE;
+ public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT = 4 * ONE_HOUR;
+ public static final long DEFAULT_EXEMPTED_SYNC_START_TIMEOUT = 10 * ONE_MINUTE;
public static final long DEFAULT_STABLE_CHARGING_THRESHOLD = 10 * ONE_MINUTE;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -1778,9 +1857,22 @@
mSyncAdapterTimeoutMillis = mParser.getDurationMillis
(KEY_SYNC_ADAPTER_HOLD_DURATION,
COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYNC_ADAPTER_TIMEOUT);
- mExemptedSyncAdapterTimeoutMillis = mParser.getDurationMillis
- (KEY_EXEMPTED_SYNC_HOLD_DURATION,
- COMPRESS_TIME ? ONE_MINUTE : DEFAULT_EXEMPTED_SYNC_TIMEOUT);
+
+ mExemptedSyncScheduledNonDozeTimeoutMillis = mParser.getDurationMillis
+ (KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION,
+ COMPRESS_TIME ? (ONE_MINUTE / 2)
+ : DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT);
+
+ mExemptedSyncScheduledDozeTimeoutMillis = mParser.getDurationMillis
+ (KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION,
+ COMPRESS_TIME ? ONE_MINUTE
+ : DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT);
+
+ mExemptedSyncStartTimeoutMillis = mParser.getDurationMillis
+ (KEY_EXEMPTED_SYNC_START_HOLD_DURATION,
+ COMPRESS_TIME ? ONE_MINUTE
+ : DEFAULT_EXEMPTED_SYNC_START_TIMEOUT);
+
mSystemInteractionTimeoutMillis = mParser.getDurationMillis
(KEY_SYSTEM_INTERACTION_HOLD_DURATION,
COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYSTEM_INTERACTION_TIMEOUT);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 7d42eb3..16f8fba 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1305,6 +1305,11 @@
}
@Override
+ public void reportExemptedSyncScheduled(String packageName, int userId) {
+ mAppStandby.postReportExemptedSyncScheduled(packageName, userId);
+ }
+
+ @Override
public void reportExemptedSyncStart(String packageName, int userId) {
mAppStandby.postReportExemptedSyncStart(packageName, userId);
}