summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Kweku Adams <kwekua@google.com> 2019-10-15 15:41:28 -0700
committer Kweku Adams <kwekua@google.com> 2019-10-30 15:05:34 -0700
commit9e5ef1d8d18f6b6e80abb2b2e6c277f1fd48e9c0 (patch)
treeacd209d441d42f19586e3f54f887e2ae5aa4b280
parent181c51f18b7c1d856740da2cd54ff45673884a93 (diff)
Remove standby delay from AlarmManager in favor of quotas.
We're moving forward with the quota system, and so no longer need to keep the delay code or tests. Bug: 142569967 Test: atest com.android.server.AlarmManagerServiceTest Test: atest com.android.server.AppStateTrackerTest Test: atest AppStandbyControllerTests Test: atest CtsAlarmManagerTestCases Change-Id: I9ce96a6e050f8dcd14d02fd707c8f4693e397ac5
-rw-r--r--services/core/java/com/android/server/AlarmManagerService.java130
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java87
2 files changed, 30 insertions, 187 deletions
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index ff0044f6f1ad..1ce11378efda 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -154,7 +154,7 @@ class AlarmManagerService extends SystemService {
static final int TICK_HISTORY_DEPTH = 10;
static final long MILLIS_IN_DAY = 24 * 60 * 60 * 1000;
- // Indices into the APP_STANDBY_MIN_DELAYS and KEYS_APP_STANDBY_DELAY arrays
+ // Indices into the KEYS_APP_STANDBY_QUOTAS array.
static final int ACTIVE_INDEX = 0;
static final int WORKING_INDEX = 1;
static final int FREQUENT_INDEX = 2;
@@ -401,8 +401,6 @@ class AlarmManagerService extends SystemService {
static final String KEY_LISTENER_TIMEOUT = "listener_timeout";
@VisibleForTesting
static final String KEY_MAX_ALARMS_PER_UID = "max_alarms_per_uid";
- @VisibleForTesting
- static final String KEY_APP_STANDBY_QUOTAS_ENABLED = "app_standby_quotas_enabled";
private static final String KEY_APP_STANDBY_WINDOW = "app_standby_window";
@VisibleForTesting
final String[] KEYS_APP_STANDBY_QUOTAS = {
@@ -413,15 +411,6 @@ class AlarmManagerService extends SystemService {
"standby_never_quota",
};
- // Keys for specifying throttling delay based on app standby bucketing
- private final String[] KEYS_APP_STANDBY_DELAY = {
- "standby_active_delay",
- "standby_working_delay",
- "standby_frequent_delay",
- "standby_rare_delay",
- "standby_never_delay",
- };
-
private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
private static final long DEFAULT_MAX_INTERVAL = 365 * DateUtils.DAY_IN_MILLIS;
@@ -430,7 +419,6 @@ class AlarmManagerService extends SystemService {
private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000;
private static final int DEFAULT_MAX_ALARMS_PER_UID = 500;
- private static final boolean DEFAULT_APP_STANDBY_QUOTAS_ENABLED = true;
private static final long DEFAULT_APP_STANDBY_WINDOW = 60 * 60 * 1000; // 1 hr
/**
* Max number of times an app can receive alarms in {@link #APP_STANDBY_WINDOW}
@@ -442,13 +430,6 @@ class AlarmManagerService extends SystemService {
1, // Rare
0 // Never
};
- private final long[] DEFAULT_APP_STANDBY_DELAYS = {
- 0, // Active
- 6 * 60_000, // Working
- 30 * 60_000, // Frequent
- 2 * 60 * 60_000, // Rare
- 10 * 24 * 60 * 60_000 // Never
- };
// Minimum futurity of a new alarm
public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
@@ -473,10 +454,7 @@ class AlarmManagerService extends SystemService {
public long LISTENER_TIMEOUT = DEFAULT_LISTENER_TIMEOUT;
public int MAX_ALARMS_PER_UID = DEFAULT_MAX_ALARMS_PER_UID;
- public boolean APP_STANDBY_QUOTAS_ENABLED = DEFAULT_APP_STANDBY_QUOTAS_ENABLED;
-
public long APP_STANDBY_WINDOW = DEFAULT_APP_STANDBY_WINDOW;
- public long[] APP_STANDBY_MIN_DELAYS = new long[DEFAULT_APP_STANDBY_DELAYS.length];
public int[] APP_STANDBY_QUOTAS = new int[DEFAULT_APP_STANDBY_QUOTAS.length];
private ContentResolver mResolver;
@@ -532,16 +510,6 @@ class AlarmManagerService extends SystemService {
DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION);
LISTENER_TIMEOUT = mParser.getLong(KEY_LISTENER_TIMEOUT,
DEFAULT_LISTENER_TIMEOUT);
- APP_STANDBY_MIN_DELAYS[ACTIVE_INDEX] = mParser.getDurationMillis(
- KEYS_APP_STANDBY_DELAY[ACTIVE_INDEX],
- DEFAULT_APP_STANDBY_DELAYS[ACTIVE_INDEX]);
- for (int i = WORKING_INDEX; i < KEYS_APP_STANDBY_DELAY.length; i++) {
- APP_STANDBY_MIN_DELAYS[i] = mParser.getDurationMillis(KEYS_APP_STANDBY_DELAY[i],
- Math.max(APP_STANDBY_MIN_DELAYS[i - 1], DEFAULT_APP_STANDBY_DELAYS[i]));
- }
-
- APP_STANDBY_QUOTAS_ENABLED = mParser.getBoolean(KEY_APP_STANDBY_QUOTAS_ENABLED,
- DEFAULT_APP_STANDBY_QUOTAS_ENABLED);
APP_STANDBY_WINDOW = mParser.getLong(KEY_APP_STANDBY_WINDOW,
DEFAULT_APP_STANDBY_WINDOW);
@@ -614,15 +582,6 @@ class AlarmManagerService extends SystemService {
pw.print(KEY_MAX_ALARMS_PER_UID); pw.print("=");
pw.println(MAX_ALARMS_PER_UID);
- for (int i = 0; i < KEYS_APP_STANDBY_DELAY.length; i++) {
- pw.print(KEYS_APP_STANDBY_DELAY[i]); pw.print("=");
- TimeUtils.formatDuration(APP_STANDBY_MIN_DELAYS[i], pw);
- pw.println();
- }
-
- pw.print(KEY_APP_STANDBY_QUOTAS_ENABLED); pw.print("=");
- pw.println(APP_STANDBY_QUOTAS_ENABLED);
-
pw.print(KEY_APP_STANDBY_WINDOW); pw.print("=");
TimeUtils.formatDuration(APP_STANDBY_WINDOW, pw);
pw.println();
@@ -1826,27 +1785,6 @@ class AlarmManagerService extends SystemService {
}
/**
- * Return the minimum time that should elapse before an app in the specified bucket
- * can receive alarms again
- */
- @VisibleForTesting
- long getMinDelayForBucketLocked(int bucket) {
- // UsageStats bucket values are treated as floors of their behavioral range.
- // In other words, a bucket value between WORKING and ACTIVE is treated as
- // WORKING, not as ACTIVE. The ACTIVE and NEVER bucket apply only at specific
- // values.
- final int index;
-
- if (bucket == UsageStatsManager.STANDBY_BUCKET_NEVER) index = NEVER_INDEX;
- else if (bucket > UsageStatsManager.STANDBY_BUCKET_FREQUENT) index = RARE_INDEX;
- else if (bucket > UsageStatsManager.STANDBY_BUCKET_WORKING_SET) index = FREQUENT_INDEX;
- else if (bucket > UsageStatsManager.STANDBY_BUCKET_ACTIVE) index = WORKING_INDEX;
- else index = ACTIVE_INDEX;
-
- return mConstants.APP_STANDBY_MIN_DELAYS[index];
- }
-
- /**
* Adjusts the alarm delivery time based on the current app standby bucket.
* @param alarm The alarm to adjust
* @return true if the alarm delivery time was updated.
@@ -1872,50 +1810,34 @@ class AlarmManagerService extends SystemService {
final int standbyBucket = mUsageStatsManagerInternal.getAppStandbyBucket(
sourcePackage, sourceUserId, mInjector.getElapsedRealtime());
- if (mConstants.APP_STANDBY_QUOTAS_ENABLED) {
- // Quota deferring implementation:
- final int wakeupsInWindow = mAppWakeupHistory.getTotalWakeupsInWindow(sourcePackage,
- sourceUserId);
- final int quotaForBucket = getQuotaForBucketLocked(standbyBucket);
- boolean deferred = false;
- if (wakeupsInWindow >= quotaForBucket) {
- final long minElapsed;
- if (quotaForBucket <= 0) {
- // Just keep deferring for a day till the quota changes
- minElapsed = mInjector.getElapsedRealtime() + MILLIS_IN_DAY;
- } else {
- // Suppose the quota for window was q, and the qth last delivery time for this
- // package was t(q) then the next delivery must be after t(q) + <window_size>
- final long t = mAppWakeupHistory.getLastWakeupForPackage(sourcePackage,
- sourceUserId, quotaForBucket);
- minElapsed = t + 1 + mConstants.APP_STANDBY_WINDOW;
- }
- if (alarm.expectedWhenElapsed < minElapsed) {
- alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed;
- deferred = true;
- }
- }
- if (!deferred) {
- // Restore original requirements in case they were changed earlier.
- alarm.whenElapsed = alarm.expectedWhenElapsed;
- alarm.maxWhenElapsed = alarm.expectedMaxWhenElapsed;
+ // Quota deferring implementation:
+ final int wakeupsInWindow = mAppWakeupHistory.getTotalWakeupsInWindow(sourcePackage,
+ sourceUserId);
+ final int quotaForBucket = getQuotaForBucketLocked(standbyBucket);
+ boolean deferred = false;
+ if (wakeupsInWindow >= quotaForBucket) {
+ final long minElapsed;
+ if (quotaForBucket <= 0) {
+ // Just keep deferring for a day till the quota changes
+ minElapsed = mInjector.getElapsedRealtime() + MILLIS_IN_DAY;
+ } else {
+ // Suppose the quota for window was q, and the qth last delivery time for this
+ // package was t(q) then the next delivery must be after t(q) + <window_size>
+ final long t = mAppWakeupHistory.getLastWakeupForPackage(sourcePackage,
+ sourceUserId, quotaForBucket);
+ minElapsed = t + 1 + mConstants.APP_STANDBY_WINDOW;
}
- } else {
- // Minimum delay deferring implementation:
- final long lastElapsed = mAppWakeupHistory.getLastWakeupForPackage(sourcePackage,
- sourceUserId, 1);
- if (lastElapsed > 0) {
- final long minElapsed = lastElapsed + getMinDelayForBucketLocked(standbyBucket);
- if (alarm.expectedWhenElapsed < minElapsed) {
- alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed;
- } else {
- // app is now eligible to run alarms at the originally requested window.
- // Restore original requirements in case they were changed earlier.
- alarm.whenElapsed = alarm.expectedWhenElapsed;
- alarm.maxWhenElapsed = alarm.expectedMaxWhenElapsed;
- }
+ if (alarm.expectedWhenElapsed < minElapsed) {
+ alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed;
+ deferred = true;
}
}
+ if (!deferred) {
+ // Restore original requirements in case they were changed earlier.
+ alarm.whenElapsed = alarm.expectedWhenElapsed;
+ alarm.maxWhenElapsed = alarm.expectedMaxWhenElapsed;
+ }
+
return (oldWhenElapsed != alarm.whenElapsed || oldMaxWhenElapsed != alarm.maxWhenElapsed);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 9e7b80567263..485f436f7f65 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -38,7 +38,6 @@ import static com.android.server.AlarmManagerService.AlarmHandler.CHARGING_STATU
import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_LONG_TIME;
import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_SHORT_TIME;
import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION;
-import static com.android.server.AlarmManagerService.Constants.KEY_APP_STANDBY_QUOTAS_ENABLED;
import static com.android.server.AlarmManagerService.Constants.KEY_LISTENER_TIMEOUT;
import static com.android.server.AlarmManagerService.Constants.KEY_MAX_INTERVAL;
import static com.android.server.AlarmManagerService.Constants.KEY_MIN_FUTURITY;
@@ -305,6 +304,8 @@ public class AlarmManagerServiceTest {
argThat((filter) -> filter.hasAction(BatteryManager.ACTION_CHARGING)
&& filter.hasAction(BatteryManager.ACTION_DISCHARGING)));
mChargingReceiver = chargingReceiverCaptor.getValue();
+
+ setTestableQuotas();
}
private void setTestAlarm(int type, long triggerTime, PendingIntent operation) {
@@ -342,9 +343,10 @@ public class AlarmManagerServiceTest {
}
/**
+ * Lowers quotas to make testing feasible.
* Careful while calling as this will replace any existing settings for the calling test.
*/
- private void setQuotasEnabled(boolean enabled) {
+ private void setTestableQuotas() {
final StringBuilder constantsBuilder = new StringBuilder();
constantsBuilder.append(KEY_MIN_FUTURITY);
constantsBuilder.append("=0,");
@@ -353,14 +355,9 @@ public class AlarmManagerServiceTest {
constantsBuilder.append("=8,");
constantsBuilder.append(mService.mConstants.KEYS_APP_STANDBY_QUOTAS[WORKING_INDEX]);
constantsBuilder.append("=5,");
- if (!enabled) {
- constantsBuilder.append(KEY_APP_STANDBY_QUOTAS_ENABLED);
- constantsBuilder.append("=false,");
- }
doReturn(constantsBuilder.toString()).when(() -> Settings.Global.getString(mMockResolver,
Settings.Global.ALARM_MANAGER_CONSTANTS));
mService.mConstants.onChange(false, null);
- assertEquals(mService.mConstants.APP_STANDBY_QUOTAS_ENABLED, enabled);
}
@Test
@@ -481,67 +478,6 @@ public class AlarmManagerServiceTest {
assertEquals(mNowElapsedTest + 9, mTestTimer.getElapsed());
}
- @Test
- public void testStandbyBucketDelay_workingSet() throws Exception {
- setQuotasEnabled(false);
- setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, getNewMockPendingIntent());
- setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, getNewMockPendingIntent());
- assertEquals(mNowElapsedTest + 5, mTestTimer.getElapsed());
-
- when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
- anyLong())).thenReturn(STANDBY_BUCKET_WORKING_SET);
-
- mNowElapsedTest = mTestTimer.getElapsed();
- mTestTimer.expire();
-
- verify(mUsageStatsManagerInternal, atLeastOnce())
- .getAppStandbyBucket(eq(TEST_CALLING_PACKAGE),
- eq(UserHandle.getUserId(TEST_CALLING_UID)), anyLong());
- final long expectedNextTrigger = mNowElapsedTest
- + mService.getMinDelayForBucketLocked(STANDBY_BUCKET_WORKING_SET);
- assertEquals("Incorrect next alarm trigger", expectedNextTrigger, mTestTimer.getElapsed());
- }
-
- @Test
- public void testStandbyBucketDelay_frequent() throws Exception {
- setQuotasEnabled(false);
- setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, getNewMockPendingIntent());
- setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, getNewMockPendingIntent());
- assertEquals(mNowElapsedTest + 5, mTestTimer.getElapsed());
-
- when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
- anyLong())).thenReturn(STANDBY_BUCKET_FREQUENT);
- mNowElapsedTest = mTestTimer.getElapsed();
- mTestTimer.expire();
-
- verify(mUsageStatsManagerInternal, atLeastOnce())
- .getAppStandbyBucket(eq(TEST_CALLING_PACKAGE),
- eq(UserHandle.getUserId(TEST_CALLING_UID)), anyLong());
- final long expectedNextTrigger = mNowElapsedTest
- + mService.getMinDelayForBucketLocked(STANDBY_BUCKET_FREQUENT);
- assertEquals("Incorrect next alarm trigger.", expectedNextTrigger, mTestTimer.getElapsed());
- }
-
- @Test
- public void testStandbyBucketDelay_rare() throws Exception {
- setQuotasEnabled(false);
- setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, getNewMockPendingIntent());
- setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, getNewMockPendingIntent());
- assertEquals(mNowElapsedTest + 5, mTestTimer.getElapsed());
-
- when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
- anyLong())).thenReturn(STANDBY_BUCKET_RARE);
- mNowElapsedTest = mTestTimer.getElapsed();
- mTestTimer.expire();
-
- verify(mUsageStatsManagerInternal, atLeastOnce())
- .getAppStandbyBucket(eq(TEST_CALLING_PACKAGE),
- eq(UserHandle.getUserId(TEST_CALLING_UID)), anyLong());
- final long expectedNextTrigger = mNowElapsedTest
- + mService.getMinDelayForBucketLocked(STANDBY_BUCKET_RARE);
- assertEquals("Incorrect next alarm trigger.", expectedNextTrigger, mTestTimer.getElapsed());
- }
-
private void testQuotasDeferralOnSet(int standbyBucket) throws Exception {
final int quota = mService.getQuotaForBucketLocked(standbyBucket);
when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
@@ -601,73 +537,61 @@ public class AlarmManagerServiceTest {
@Test
public void testActiveQuota_deferredOnSet() throws Exception {
- setQuotasEnabled(true);
testQuotasDeferralOnSet(STANDBY_BUCKET_ACTIVE);
}
@Test
public void testActiveQuota_deferredOnExpiration() throws Exception {
- setQuotasEnabled(true);
testQuotasDeferralOnExpiration(STANDBY_BUCKET_ACTIVE);
}
@Test
public void testActiveQuota_notDeferred() throws Exception {
- setQuotasEnabled(true);
testQuotasNoDeferral(STANDBY_BUCKET_ACTIVE);
}
@Test
public void testWorkingQuota_deferredOnSet() throws Exception {
- setQuotasEnabled(true);
testQuotasDeferralOnSet(STANDBY_BUCKET_WORKING_SET);
}
@Test
public void testWorkingQuota_deferredOnExpiration() throws Exception {
- setQuotasEnabled(true);
testQuotasDeferralOnExpiration(STANDBY_BUCKET_WORKING_SET);
}
@Test
public void testWorkingQuota_notDeferred() throws Exception {
- setQuotasEnabled(true);
testQuotasNoDeferral(STANDBY_BUCKET_WORKING_SET);
}
@Test
public void testFrequentQuota_deferredOnSet() throws Exception {
- setQuotasEnabled(true);
testQuotasDeferralOnSet(STANDBY_BUCKET_FREQUENT);
}
@Test
public void testFrequentQuota_deferredOnExpiration() throws Exception {
- setQuotasEnabled(true);
testQuotasDeferralOnExpiration(STANDBY_BUCKET_FREQUENT);
}
@Test
public void testFrequentQuota_notDeferred() throws Exception {
- setQuotasEnabled(true);
testQuotasNoDeferral(STANDBY_BUCKET_FREQUENT);
}
@Test
public void testRareQuota_deferredOnSet() throws Exception {
- setQuotasEnabled(true);
testQuotasDeferralOnSet(STANDBY_BUCKET_RARE);
}
@Test
public void testRareQuota_deferredOnExpiration() throws Exception {
- setQuotasEnabled(true);
testQuotasDeferralOnExpiration(STANDBY_BUCKET_RARE);
}
@Test
public void testRareQuota_notDeferred() throws Exception {
- setQuotasEnabled(true);
testQuotasNoDeferral(STANDBY_BUCKET_RARE);
}
@@ -686,7 +610,6 @@ public class AlarmManagerServiceTest {
@Test
public void testQuotaDowngrade() throws Exception {
- setQuotasEnabled(true);
final int workingQuota = mService.getQuotaForBucketLocked(STANDBY_BUCKET_WORKING_SET);
when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
anyLong())).thenReturn(STANDBY_BUCKET_WORKING_SET);
@@ -714,7 +637,6 @@ public class AlarmManagerServiceTest {
@Test
public void testQuotaUpgrade() throws Exception {
- setQuotasEnabled(true);
final int frequentQuota = mService.getQuotaForBucketLocked(STANDBY_BUCKET_FREQUENT);
when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
anyLong())).thenReturn(STANDBY_BUCKET_FREQUENT);
@@ -752,7 +674,6 @@ public class AlarmManagerServiceTest {
@Test
public void testCharging() throws Exception {
- setQuotasEnabled(true);
final int workingQuota = mService.getQuotaForBucketLocked(STANDBY_BUCKET_WORKING_SET);
when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
anyLong())).thenReturn(STANDBY_BUCKET_WORKING_SET);