From ae9ea5f3d9f9a2193bba679dfd347191591e79f4 Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Tue, 13 Sep 2022 20:43:32 +0000 Subject: [PATCH] Add a way to disable non-wakeup alarm deferral. AlarmManager normally delays non-wakeup alarms when the screen is off. However, tests that depend on components that want to use non-wakeup alarms while the screen is off will be flaky with this deferral. Make it possible to disable the deferral for tests. We may also decide to disable this behavior altogether, so use DeviceConfig to allow experimentation. Also fix long comparison overflow issue in AlarmQueue. Bug: 245987711 Test: atest CtsJobSchedulerTestCases:FlexibilityConstraintTest Test: atest FrameworksMockingServicesTests:AlarmQueueTest Change-Id: I35f1299d551eb7099adfecd13449f53fef88de02 --- .../server/alarm/AlarmManagerService.java | 21 +++++++++++++++++++ .../controllers/FlexibilityController.java | 2 +- .../com/android/server/utils/AlarmQueue.java | 12 +++++++++-- .../android/server/utils/AlarmQueueTest.java | 21 +++++++++++++++++++ 4 files changed, 53 insertions(+), 3 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 b6d29aa5641a3..5b61f9abc357e 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -676,6 +676,9 @@ public class AlarmManagerService extends SystemService { private static final String KEY_TIME_TICK_ALLOWED_WHILE_IDLE = "time_tick_allowed_while_idle"; + private static final String KEY_DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF = + "delay_nonwakeup_alarms_while_screen_off"; + @VisibleForTesting static final String KEY_ALLOW_WHILE_IDLE_QUOTA = "allow_while_idle_quota"; @@ -743,6 +746,8 @@ public class AlarmManagerService extends SystemService { private static final int DEFAULT_TEMPORARY_QUOTA_BUMP = 0; + private static final boolean DEFAULT_DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF = true; + // Minimum futurity of a new alarm public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY; @@ -835,6 +840,9 @@ public class AlarmManagerService extends SystemService { */ public int TEMPORARY_QUOTA_BUMP = DEFAULT_TEMPORARY_QUOTA_BUMP; + public boolean DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF = + DEFAULT_DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF; + private long mLastAllowWhileIdleWhitelistDuration = -1; private int mVersion = 0; @@ -1011,6 +1019,11 @@ public class AlarmManagerService extends SystemService { TEMPORARY_QUOTA_BUMP = properties.getInt(KEY_TEMPORARY_QUOTA_BUMP, DEFAULT_TEMPORARY_QUOTA_BUMP); break; + case KEY_DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF: + DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF = properties.getBoolean( + KEY_DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF, + DEFAULT_DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF); + break; default: if (name.startsWith(KEY_PREFIX_STANDBY_QUOTA) && !standbyQuotaUpdated) { // The quotas need to be updated in order, so we can't just rely @@ -1249,6 +1262,10 @@ public class AlarmManagerService extends SystemService { pw.print(KEY_TEMPORARY_QUOTA_BUMP, TEMPORARY_QUOTA_BUMP); pw.println(); + pw.print(KEY_DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF, + DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF); + pw.println(); + pw.decreaseIndent(); } @@ -4360,7 +4377,11 @@ public class AlarmManagerService extends SystemService { } } + @GuardedBy("mLock") boolean checkAllowNonWakeupDelayLocked(long nowELAPSED) { + if (!mConstants.DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF) { + return false; + } if (mInteractive) { return false; } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java index f1e13dfcab5c1..9c167728cff94 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java @@ -644,7 +644,7 @@ public final class FlexibilityController extends StateController { static final String KEY_FALLBACK_FLEXIBILITY_DEADLINE = FC_CONFIG_PREFIX + "fallback_flexibility_deadline_ms"; static final String KEY_MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS = - FC_CONFIG_PREFIX + "min_alarm_time_flexibility_ms"; + FC_CONFIG_PREFIX + "min_time_between_flexibility_alarms_ms"; static final String KEY_PERCENTS_TO_DROP_NUM_FLEXIBLE_CONSTRAINTS = FC_CONFIG_PREFIX + "percents_to_drop_num_flexible_constraints"; static final String KEY_MAX_RESCHEDULED_DEADLINE_MS = diff --git a/services/core/java/com/android/server/utils/AlarmQueue.java b/services/core/java/com/android/server/utils/AlarmQueue.java index 3f4def6d60ab7..41373cd6bbe6b 100644 --- a/services/core/java/com/android/server/utils/AlarmQueue.java +++ b/services/core/java/com/android/server/utils/AlarmQueue.java @@ -34,6 +34,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import java.util.Comparator; import java.util.PriorityQueue; import java.util.function.Predicate; @@ -52,6 +53,11 @@ public abstract class AlarmQueue implements AlarmManager.OnAlarmListener { private static final boolean DEBUG = false; private static final long NOT_SCHEDULED = -1; + /** + * The threshold used to consider a new trigger time to be significantly different from the + * currently used trigger time. + */ + private static final long SIGNIFICANT_TRIGGER_TIME_CHANGE_THRESHOLD_MS = MINUTE_IN_MILLIS; /** * Internal priority queue for each key's alarm, ordered by the time the alarm should go off. @@ -59,7 +65,7 @@ public abstract class AlarmQueue implements AlarmManager.OnAlarmListener { */ private static class AlarmPriorityQueue extends PriorityQueue> { AlarmPriorityQueue() { - super(1, (o1, o2) -> (int) (o1.second - o2.second)); + super(1, Comparator.comparingLong(o -> o.second)); } /** @@ -306,8 +312,10 @@ public abstract class AlarmQueue implements AlarmManager.OnAlarmListener { // earlier but not significantly so, then we essentially delay the check for some // apps by up to a minute. // 3. The alarm is after the current alarm. + final long timeShiftThresholdMs = + Math.min(SIGNIFICANT_TRIGGER_TIME_CHANGE_THRESHOLD_MS, mMinTimeBetweenAlarmsMs); if (mTriggerTimeElapsed == NOT_SCHEDULED - || nextTriggerTimeElapsed < mTriggerTimeElapsed - MINUTE_IN_MILLIS + || nextTriggerTimeElapsed < mTriggerTimeElapsed - timeShiftThresholdMs || mTriggerTimeElapsed < nextTriggerTimeElapsed) { if (DEBUG) { Slog.d(TAG, "Scheduling alarm at " + nextTriggerTimeElapsed 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 849e6730ac116..00d7541a79dcf 100644 --- a/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java @@ -155,6 +155,27 @@ public class AlarmQueueTest { anyInt(), eq(nowElapsed + HOUR_IN_MILLIS), eq(ALARM_TAG), any(), any()); } + @Test + public void testAddingLargeAlarmTimes() { + final AlarmQueue alarmQueue = createAlarmQueue(true, 0); + final long nowElapsed = mInjector.getElapsedRealtime(); + + InOrder inOrder = inOrder(mAlarmManager); + + alarmQueue.addAlarm("com.android.test.1", Long.MAX_VALUE - 5); + inOrder.verify(mAlarmManager, timeout(1000).times(1)) + .setExact(anyInt(), eq(Long.MAX_VALUE - 5), eq(ALARM_TAG), any(), any()); + alarmQueue.addAlarm("com.android.test.2", Long.MAX_VALUE - 4); + inOrder.verify(mAlarmManager, never()) + .setExact(anyInt(), anyLong(), eq(ALARM_TAG), any(), any()); + alarmQueue.addAlarm("com.android.test.3", nowElapsed + 5); + inOrder.verify(mAlarmManager, timeout(1000).times(1)) + .setExact(anyInt(), eq(nowElapsed + 5), eq(ALARM_TAG), any(), any()); + alarmQueue.addAlarm("com.android.test.4", nowElapsed + 6); + inOrder.verify(mAlarmManager, never()) + .setExact(anyInt(), anyLong(), eq(ALARM_TAG), any(), any()); + } + /** * Verify that updating the alarm time for a key will result in the AlarmManager alarm changing, * if needed.