From ef46dcbc567938823b600eca5d3349d661a5aeaf Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Wed, 28 Jun 2023 19:21:04 +0000 Subject: [PATCH] Fix alarm throttling. Alarm throttling wasn't happening if the queue became empty before a new alarm was scheduled. This fixes that so the min time between alarms is always enforced. Bug: 288975061 Test: atest FrameworksMockingServicesTests:AlarmQueueTest Change-Id: Id01bcf4e7d53ae7d89c99cb7f97b86163c43ea88 --- .../com/android/server/utils/AlarmQueue.java | 7 +++++- .../android/server/utils/AlarmQueueTest.java | 23 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/utils/AlarmQueue.java b/services/core/java/com/android/server/utils/AlarmQueue.java index 09ba19508476e..83605ae09e97f 100644 --- a/services/core/java/com/android/server/utils/AlarmQueue.java +++ b/services/core/java/com/android/server/utils/AlarmQueue.java @@ -151,6 +151,10 @@ public abstract class AlarmQueue implements AlarmManager.OnAlarmListener { @GuardedBy("mLock") @ElapsedRealtimeLong private long mTriggerTimeElapsed = NOT_SCHEDULED; + /** The last time an alarm went off (ie. the last time {@link #onAlarm()} was called}). */ + @GuardedBy("mLock") + @ElapsedRealtimeLong + private long mLastFireTimeElapsed; /** * @param alarmTag The tag to use when scheduling the alarm with AlarmManager. @@ -284,7 +288,7 @@ public abstract class AlarmQueue implements AlarmManager.OnAlarmListener { /** Sets an alarm with {@link AlarmManager} for the earliest alarm in the queue after now. */ @GuardedBy("mLock") private void setNextAlarmLocked() { - setNextAlarmLocked(mInjector.getElapsedRealtime()); + setNextAlarmLocked(mLastFireTimeElapsed + mMinTimeBetweenAlarmsMs); } /** @@ -334,6 +338,7 @@ public abstract class AlarmQueue implements AlarmManager.OnAlarmListener { final ArraySet expired = new ArraySet<>(); synchronized (mLock) { final long nowElapsed = mInjector.getElapsedRealtime(); + mLastFireTimeElapsed = nowElapsed; while (mAlarmPriorityQueue.size() > 0) { final Pair alarm = mAlarmPriorityQueue.peek(); if (alarm.second <= nowElapsed) { diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java index a3a49d7035d94..f3aa4274b3cda 100644 --- a/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java @@ -258,6 +258,29 @@ public class AlarmQueueTest { anyInt(), eq(nowElapsed + 5 * HOUR_IN_MILLIS), eq(ALARM_TAG), any(), any()); } + @Test + public void testMinTimeBetweenAlarms_freshAlarm() { + final AlarmQueue alarmQueue = createAlarmQueue(true, 5 * MINUTE_IN_MILLIS); + final long fixedTimeElapsed = mInjector.getElapsedRealtime(); + + InOrder inOrder = inOrder(mAlarmManager); + + final String pkg1 = "com.android.test.1"; + final String pkg2 = "com.android.test.2"; + alarmQueue.addAlarm(pkg1, fixedTimeElapsed + MINUTE_IN_MILLIS); + inOrder.verify(mAlarmManager, timeout(1000).times(1)).setExact( + anyInt(), eq(fixedTimeElapsed + MINUTE_IN_MILLIS), eq(ALARM_TAG), any(), any()); + + advanceElapsedClock(MINUTE_IN_MILLIS); + + alarmQueue.onAlarm(); + // Minimum of 5 minutes between alarms, so the next alarm should be 5 minutes after the + // first. + alarmQueue.addAlarm(pkg2, fixedTimeElapsed + 2 * MINUTE_IN_MILLIS); + inOrder.verify(mAlarmManager, timeout(1000).times(1)).setExact( + anyInt(), eq(fixedTimeElapsed + 6 * MINUTE_IN_MILLIS), eq(ALARM_TAG), any(), any()); + } + @Test public void testOnAlarm() { final AlarmQueue alarmQueue = createAlarmQueue(true, 0);