summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Suprabh Shukla <suprabh@google.com> 2020-09-03 12:54:39 -0700
committer Suprabh Shukla <suprabh@google.com> 2020-09-08 20:40:37 +0000
commit951fa94b6a7f9a41d38faa759148db2e8e7da7ce (patch)
tree8aa8ec680bcee642da0069505513c6f6f09c4548
parentbe69e09c86085c9c6c61ba0d077efc445a254d2f (diff)
RESTRICT AUTOMERGE Remove alarms from mPendingNonWakeupAlarms
While setting an alarm, we should remove any existing occurrences of the same, but we were skipping on removing any past due non-wakeup alarms. In rare cases when a caller is spamming the alarm manager, we might end up accumulating alarms inside mPendingNonWakeupAlarms that count towards the per-uid limit of the caller, and may result in an exception. Test: atest FrameworksMockingServicesTests:AlarmManagerServiceTest atest CtsAlarmManagerTestCases Bug: 167645096 Bug: 130444055 Change-Id: I2d2b08019a3b3a1e63b60d3a6e2909db7b1a1864
-rw-r--r--services/core/java/com/android/server/AlarmManagerService.java8
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java43
2 files changed, 51 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 4fab067d1d3b..651f941be0b1 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -3109,6 +3109,14 @@ class AlarmManagerService extends SystemService {
mPendingBackgroundAlarms.removeAt(i);
}
}
+ for (int i = mPendingNonWakeupAlarms.size() - 1; i >= 0; i--) {
+ final Alarm a = mPendingNonWakeupAlarms.get(i);
+ if (a.matches(operation, directReceiver)) {
+ // Don't set didRemove, since this doesn't impact the scheduled alarms.
+ mPendingNonWakeupAlarms.remove(i);
+ decrementAlarmCount(a.uid, 1);
+ }
+ }
if (didRemove) {
if (DEBUG_BATCH) {
Slog.v(TAG, "remove(operation) changed bounds; rebatching");
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index ca8e50aa19c9..7bd0201b997a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -1053,6 +1053,49 @@ public class AlarmManagerServiceTest {
}
}
+ @Test
+ public void nonWakeupAlarmsDeferred() throws Exception {
+ final int numAlarms = 10;
+ final PendingIntent[] pis = new PendingIntent[numAlarms];
+ for (int i = 0; i < numAlarms; i++) {
+ pis[i] = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 5, pis[i]);
+ }
+ doReturn(true).when(mService).checkAllowNonWakeupDelayLocked(anyLong());
+ // Advance time past all expirations.
+ mNowElapsedTest += numAlarms + 5;
+ mTestTimer.expire();
+ assertEquals(numAlarms, mService.mPendingNonWakeupAlarms.size());
+
+ // These alarms should be sent on interactive state change to true
+ mService.interactiveStateChangedLocked(false);
+ mService.interactiveStateChangedLocked(true);
+
+ for (int i = 0; i < numAlarms; i++) {
+ verify(pis[i]).send(eq(mMockContext), eq(0), any(Intent.class), any(),
+ any(Handler.class), isNull(), any());
+ }
+ }
+
+ @Test
+ public void alarmCountOnPendingNonWakeupAlarmsRemoved() throws Exception {
+ final int numAlarms = 10;
+ final PendingIntent[] pis = new PendingIntent[numAlarms];
+ for (int i = 0; i < numAlarms; i++) {
+ pis[i] = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 5, pis[i]);
+ }
+ doReturn(true).when(mService).checkAllowNonWakeupDelayLocked(anyLong());
+ // Advance time past all expirations.
+ mNowElapsedTest += numAlarms + 5;
+ mTestTimer.expire();
+ assertEquals(numAlarms, mService.mPendingNonWakeupAlarms.size());
+ for (int i = 0; i < numAlarms; i++) {
+ mService.removeLocked(pis[i], null);
+ assertEquals(numAlarms - i - 1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+ }
+ }
+
@After
public void tearDown() {
if (mMockingSession != null) {