summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeHugger Robot <treehugger-gerrit@google.com>2021-07-14 20:09:15 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2021-07-14 20:09:15 +0000
commit977e2adc143bbc0453a59c735631aa300f2d39bd (patch)
tree53d92164435cb8aebe3f0fb2fb3d9da9d2303cf4
parent65731d06cedc07501f7fb93411b01e678aeec364 (diff)
parent4e05326a55ce38e4f5ea4b2de263128c3bd05727 (diff)
downloadbase-977e2adc143bbc0453a59c735631aa300f2d39bd.tar.gz
Merge "Separating alarm history for lower quota" into sc-dev
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java33
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java157
2 files changed, 174 insertions, 16 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index ed80ddbd2cd7..9f529548833d 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -256,6 +256,7 @@ public class AlarmManagerService extends SystemService {
AlarmHandler mHandler;
AppWakeupHistory mAppWakeupHistory;
AppWakeupHistory mAllowWhileIdleHistory;
+ AppWakeupHistory mAllowWhileIdleCompatHistory;
private final SparseLongArray mLastPriorityAlarmDispatch = new SparseLongArray();
private final SparseArray<RingBuffer<RemovedAlarm>> mRemovalHistory = new SparseArray<>();
ClockReceiver mClockReceiver;
@@ -1633,6 +1634,7 @@ public class AlarmManagerService extends SystemService {
mAppWakeupHistory = new AppWakeupHistory(Constants.DEFAULT_APP_STANDBY_WINDOW);
mAllowWhileIdleHistory = new AppWakeupHistory(INTERVAL_HOUR);
+ mAllowWhileIdleCompatHistory = new AppWakeupHistory(INTERVAL_HOUR);
mNextWakeup = mNextNonWakeup = 0;
@@ -2142,20 +2144,23 @@ public class AlarmManagerService extends SystemService {
final int userId = UserHandle.getUserId(alarm.creatorUid);
final int quota;
final long window;
+ final AppWakeupHistory history;
if ((alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0) {
quota = mConstants.ALLOW_WHILE_IDLE_QUOTA;
window = mConstants.ALLOW_WHILE_IDLE_WINDOW;
+ history = mAllowWhileIdleHistory;
} else {
quota = mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
window = mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+ history = mAllowWhileIdleCompatHistory;
}
- final int dispatchesInWindow = mAllowWhileIdleHistory.getTotalWakeupsInWindow(
+ final int dispatchesInHistory = history.getTotalWakeupsInWindow(
alarm.sourcePackage, userId);
- if (dispatchesInWindow < quota) {
+ if (dispatchesInHistory < quota) {
// fine to go out immediately.
batterySaverPolicyElapsed = nowElapsed;
} else {
- batterySaverPolicyElapsed = mAllowWhileIdleHistory.getNthLastWakeupForPackage(
+ batterySaverPolicyElapsed = history.getNthLastWakeupForPackage(
alarm.sourcePackage, userId, quota) + window;
}
} else if ((alarm.flags & FLAG_PRIORITIZE) != 0) {
@@ -2201,20 +2206,23 @@ public class AlarmManagerService extends SystemService {
final int userId = UserHandle.getUserId(alarm.creatorUid);
final int quota;
final long window;
+ final AppWakeupHistory history;
if ((alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0) {
quota = mConstants.ALLOW_WHILE_IDLE_QUOTA;
window = mConstants.ALLOW_WHILE_IDLE_WINDOW;
+ history = mAllowWhileIdleHistory;
} else {
quota = mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
window = mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+ history = mAllowWhileIdleCompatHistory;
}
- final int dispatchesInWindow = mAllowWhileIdleHistory.getTotalWakeupsInWindow(
+ final int dispatchesInHistory = history.getTotalWakeupsInWindow(
alarm.sourcePackage, userId);
- if (dispatchesInWindow < quota) {
+ if (dispatchesInHistory < quota) {
// fine to go out immediately.
deviceIdlePolicyTime = nowElapsed;
} else {
- final long whenInQuota = mAllowWhileIdleHistory.getNthLastWakeupForPackage(
+ final long whenInQuota = history.getNthLastWakeupForPackage(
alarm.sourcePackage, userId, quota) + window;
deviceIdlePolicyTime = Math.min(whenInQuota, mPendingIdleUntil.getWhenElapsed());
}
@@ -2502,6 +2510,7 @@ public class AlarmManagerService extends SystemService {
Binder.getCallingPid(), callingUid, "AlarmManager.setPrioritized");
// The API doesn't allow using both together.
flags &= ~FLAG_ALLOW_WHILE_IDLE;
+ // Prioritized alarms don't need any extra permission to be exact.
} else if (exact || allowWhileIdle) {
final boolean needsPermission;
boolean lowerQuota;
@@ -2992,6 +3001,10 @@ public class AlarmManagerService extends SystemService {
mAllowWhileIdleHistory.dump(pw, nowELAPSED);
pw.println();
+ pw.println("Allow while idle compat history:");
+ mAllowWhileIdleCompatHistory.dump(pw, nowELAPSED);
+ pw.println();
+
if (mLastPriorityAlarmDispatch.size() > 0) {
pw.println("Last priority alarm dispatches:");
pw.increaseIndent();
@@ -4553,6 +4566,7 @@ public class AlarmManagerService extends SystemService {
removeUserLocked(userHandle);
mAppWakeupHistory.removeForUser(userHandle);
mAllowWhileIdleHistory.removeForUser(userHandle);
+ mAllowWhileIdleCompatHistory.removeForUser(userHandle);
}
return;
case Intent.ACTION_UID_REMOVED:
@@ -4588,6 +4602,8 @@ public class AlarmManagerService extends SystemService {
// package-removed and package-restarted case
mAppWakeupHistory.removeForPackage(pkg, UserHandle.getUserId(uid));
mAllowWhileIdleHistory.removeForPackage(pkg, UserHandle.getUserId(uid));
+ mAllowWhileIdleCompatHistory.removeForPackage(pkg,
+ UserHandle.getUserId(uid));
removeLocked(uid, REMOVE_REASON_UNDEFINED);
} else {
// external-applications-unavailable case
@@ -4965,7 +4981,10 @@ public class AlarmManagerService extends SystemService {
if (isAllowedWhileIdleRestricted(alarm)) {
// Record the last time this uid handled an ALLOW_WHILE_IDLE alarm while the
// device was in doze or battery saver.
- mAllowWhileIdleHistory.recordAlarmForPackage(alarm.sourcePackage,
+ final AppWakeupHistory history = ((alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0)
+ ? mAllowWhileIdleHistory
+ : mAllowWhileIdleCompatHistory;
+ history.recordAlarmForPackage(alarm.sourcePackage,
UserHandle.getUserId(alarm.creatorUid), nowELAPSED);
mAlarmStore.updateAlarmDeliveries(a -> {
if (a.creatorUid != alarm.creatorUid || !isAllowedWhileIdleRestricted(a)) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 583797e69995..a254f68e8bed 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -514,8 +514,16 @@ public class AlarmManagerServiceTest {
}
private void setAllowWhileIdleAlarm(int type, long triggerTime, PendingIntent pi,
- boolean unrestricted) {
- final int flags = unrestricted ? FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED : FLAG_ALLOW_WHILE_IDLE;
+ boolean unrestricted, boolean compat) {
+ assertFalse("Alarm cannot be compat and unrestricted", unrestricted && compat);
+ final int flags;
+ if (unrestricted) {
+ flags = FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
+ } else if (compat) {
+ flags = FLAG_ALLOW_WHILE_IDLE_COMPAT;
+ } else {
+ flags = FLAG_ALLOW_WHILE_IDLE;
+ }
setTestAlarm(type, triggerTime, pi, 0, flags, TEST_CALLING_UID);
}
@@ -1600,13 +1608,13 @@ public class AlarmManagerServiceTest {
final long firstTrigger = mNowElapsedTest + 10;
for (int i = 0; i < quota; i++) {
setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + i,
- getNewMockPendingIntent(), false);
+ getNewMockPendingIntent(), false, false);
mNowElapsedTest = mTestTimer.getElapsed();
mTestTimer.expire();
}
// This one should get deferred on set.
setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + quota,
- getNewMockPendingIntent(), false);
+ getNewMockPendingIntent(), false, false);
final long expectedNextTrigger = firstTrigger + mAllowWhileIdleWindow;
assertEquals("Incorrect trigger when no quota left", expectedNextTrigger,
mTestTimer.getElapsed());
@@ -1619,6 +1627,108 @@ public class AlarmManagerServiceTest {
}
@Test
+ public void allowWhileIdleCompatAlarmsWhileDeviceIdle() throws Exception {
+ setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 0);
+
+ final long window = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+ setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + window + 1000,
+ getNewMockPendingIntent());
+ assertNotNull(mService.mPendingIdleUntil);
+
+ final int quota = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
+ final long firstTrigger = mNowElapsedTest + 10;
+ for (int i = 0; i < quota; i++) {
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + i,
+ getNewMockPendingIntent(), false, true);
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ }
+ // This one should get deferred on set.
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + quota,
+ getNewMockPendingIntent(), false, true);
+ final long expectedNextTrigger = firstTrigger + window;
+ assertEquals("Incorrect trigger when no quota left", expectedNextTrigger,
+ mTestTimer.getElapsed());
+
+ // Bring the idle until alarm back.
+ setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, expectedNextTrigger - 50,
+ getNewMockPendingIntent());
+ assertEquals(expectedNextTrigger - 50, mService.mPendingIdleUntil.getWhenElapsed());
+ assertEquals(expectedNextTrigger - 50, mTestTimer.getElapsed());
+ }
+
+ @Test
+ public void allowWhileIdleCompatHistorySeparate() throws Exception {
+ when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID,
+ TEST_CALLING_PACKAGE)).thenReturn(true);
+ when(mAppStateTracker.isForceAllAppsStandbyEnabled()).thenReturn(true);
+
+ final int fullQuota = mService.mConstants.ALLOW_WHILE_IDLE_QUOTA;
+ final int compatQuota = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
+
+ final long fullWindow = mAllowWhileIdleWindow;
+ final long compatWindow = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+
+ final long firstFullTrigger = mNowElapsedTest + 10;
+ for (int i = 0; i < fullQuota; i++) {
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstFullTrigger + i,
+ getNewMockPendingIntent(), false, false);
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ }
+ // This one should get deferred on set, as full quota is not available.
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstFullTrigger + fullQuota,
+ getNewMockPendingIntent(), false, false);
+ final long expectedNextFullTrigger = firstFullTrigger + fullWindow;
+ assertEquals("Incorrect trigger when no quota left", expectedNextFullTrigger,
+ mTestTimer.getElapsed());
+ mService.removeLocked(TEST_CALLING_UID, REMOVE_REASON_UNDEFINED);
+
+ // The following should be allowed, as compat quota should be free.
+ for (int i = 0; i < compatQuota; i++) {
+ final long trigger = mNowElapsedTest + 1;
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger, getNewMockPendingIntent(),
+ false, true);
+ assertEquals(trigger, mTestTimer.getElapsed());
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ }
+
+ // Refresh the state
+ mService.removeLocked(TEST_CALLING_UID, REMOVE_REASON_UNDEFINED);
+ mService.mAllowWhileIdleHistory.removeForPackage(TEST_CALLING_PACKAGE, TEST_CALLING_USER);
+ mService.mAllowWhileIdleCompatHistory.removeForPackage(TEST_CALLING_PACKAGE,
+ TEST_CALLING_USER);
+
+ // Now test with flipped order
+
+ final long firstCompatTrigger = mNowElapsedTest + 10;
+ for (int i = 0; i < compatQuota; i++) {
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstCompatTrigger + i,
+ getNewMockPendingIntent(), false, true);
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ }
+ // This one should get deferred on set, as full quota is not available.
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstCompatTrigger + compatQuota,
+ getNewMockPendingIntent(), false, true);
+ final long expectedNextCompatTrigger = firstCompatTrigger + compatWindow;
+ assertEquals("Incorrect trigger when no quota left", expectedNextCompatTrigger,
+ mTestTimer.getElapsed());
+ mService.removeLocked(TEST_CALLING_UID, REMOVE_REASON_UNDEFINED);
+
+ // The following should be allowed, as full quota should be free.
+ for (int i = 0; i < fullQuota; i++) {
+ final long trigger = mNowElapsedTest + 1;
+ setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger, getNewMockPendingIntent(),
+ false, false);
+ assertEquals(trigger, mTestTimer.getElapsed());
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ }
+ }
+
+ @Test
public void allowWhileIdleUnrestricted() throws Exception {
setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 0);
@@ -1634,7 +1744,7 @@ public class AlarmManagerServiceTest {
final long firstTrigger = mNowElapsedTest + 10;
for (int i = 0; i < numAlarms; i++) {
setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + i,
- getNewMockPendingIntent(), true);
+ getNewMockPendingIntent(), true, false);
}
// All of them should fire as expected.
for (int i = 0; i < numAlarms; i++) {
@@ -1736,7 +1846,7 @@ public class AlarmManagerServiceTest {
final int quota = mService.mConstants.ALLOW_WHILE_IDLE_QUOTA;
testQuotasDeferralOnSet(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger,
- getNewMockPendingIntent(), false), quota, mAllowWhileIdleWindow);
+ getNewMockPendingIntent(), false, false), quota, mAllowWhileIdleWindow);
// Refresh the state
mService.removeLocked(TEST_CALLING_UID,
@@ -1744,7 +1854,7 @@ public class AlarmManagerServiceTest {
mService.mAllowWhileIdleHistory.removeForPackage(TEST_CALLING_PACKAGE, TEST_CALLING_USER);
testQuotasDeferralOnExpiration(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP,
- trigger, getNewMockPendingIntent(), false), quota, mAllowWhileIdleWindow);
+ trigger, getNewMockPendingIntent(), false, false), quota, mAllowWhileIdleWindow);
// Refresh the state
mService.removeLocked(TEST_CALLING_UID,
@@ -1752,7 +1862,36 @@ public class AlarmManagerServiceTest {
mService.mAllowWhileIdleHistory.removeForPackage(TEST_CALLING_PACKAGE, TEST_CALLING_USER);
testQuotasNoDeferral(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger,
- getNewMockPendingIntent(), false), quota, mAllowWhileIdleWindow);
+ getNewMockPendingIntent(), false, false), quota, mAllowWhileIdleWindow);
+ }
+
+ @Test
+ public void allowWhileIdleCompatAlarmsInBatterySaver() throws Exception {
+ when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID,
+ TEST_CALLING_PACKAGE)).thenReturn(true);
+ when(mAppStateTracker.isForceAllAppsStandbyEnabled()).thenReturn(true);
+
+ final int quota = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_QUOTA;
+ final long window = mService.mConstants.ALLOW_WHILE_IDLE_COMPAT_WINDOW;
+
+ testQuotasDeferralOnSet(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger,
+ getNewMockPendingIntent(), false, true), quota, window);
+
+ // Refresh the state
+ mService.removeLocked(TEST_CALLING_UID, REMOVE_REASON_UNDEFINED);
+ mService.mAllowWhileIdleCompatHistory.removeForPackage(TEST_CALLING_PACKAGE,
+ TEST_CALLING_USER);
+
+ testQuotasDeferralOnExpiration(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP,
+ trigger, getNewMockPendingIntent(), false, true), quota, window);
+
+ // Refresh the state
+ mService.removeLocked(TEST_CALLING_UID, REMOVE_REASON_UNDEFINED);
+ mService.mAllowWhileIdleCompatHistory.removeForPackage(TEST_CALLING_PACKAGE,
+ TEST_CALLING_USER);
+
+ testQuotasNoDeferral(trigger -> setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, trigger,
+ getNewMockPendingIntent(), false, true), quota, window);
}
@Test
@@ -2123,7 +2262,7 @@ public class AlarmManagerServiceTest {
final PendingIntent alarmPi = getNewMockPendingIntent();
final AlarmManager.AlarmClockInfo alarmClock = mock(AlarmManager.AlarmClockInfo.class);
mBinder.set(TEST_CALLING_PACKAGE, RTC_WAKEUP, 1234, WINDOW_EXACT, 0, 0,
- alarmPi, null, null, null, alarmClock);
+ alarmPi, null, null, null, alarmClock);
// Correct permission checks are invoked.
verify(mService).hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID);