From 498c6cbd78f42d4f6d2568ead6c2697fcfaa326e Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Mon, 17 Nov 2014 16:09:27 -0800 Subject: [PATCH] Prevent some alarm pathologies * Sanity-check the recurrence interval. Some buggy apps pass seconds where the API expects milliseconds, with the result that the device pins the CPU at 100% trying to deliver alarm broadcasts every 60 ms or what have you. The minimum recurrence is now 1 minute. * Sanity-check alarms being scheduled for the immediate future. As with the above this will catch people trying to schedule alarms in a spammy way that keeps the device from entering low-power state. The minimum futurity of a new alarm is now 5 seconds. Bug 17495168 Change-Id: If8ff7d88da48960532ac21a0ba20094af9912603 --- .../android/server/AlarmManagerService.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 8b524ddab458c..08c47dcaa9b79 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -75,6 +75,12 @@ class AlarmManagerService extends SystemService { // warning message. The time duration is in milliseconds. private static final long LATE_ALARM_THRESHOLD = 10 * 1000; + // Minimum futurity of a new alarm + private static final long MIN_FUTURITY = 5 * 1000; // 5 seconds, in millis + + // Minimum alarm recurrence interval + private static final long MIN_INTERVAL = 60 * 1000; // one minute, in millis + private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP; private static final int RTC_MASK = 1 << RTC; private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP; @@ -696,6 +702,15 @@ class AlarmManagerService extends SystemService { windowLength = AlarmManager.INTERVAL_HOUR; } + // Sanity check the recurrence interval. This will catch people who supply + // seconds when the API expects milliseconds. + if (interval > 0 && interval < MIN_INTERVAL) { + Slog.w(TAG, "Suspiciously short interval " + interval + + " millis; expanding to " + (int)(MIN_INTERVAL/1000) + + " seconds"); + interval = MIN_INTERVAL; + } + if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) { throw new IllegalArgumentException("Invalid alarm type " + type); } @@ -709,7 +724,11 @@ class AlarmManagerService extends SystemService { } final long nowElapsed = SystemClock.elapsedRealtime(); - final long triggerElapsed = convertToElapsed(triggerAtTime, type); + final long nominalTrigger = convertToElapsed(triggerAtTime, type); + // Try to prevent spamming by making sure we aren't firing alarms in the immediate future + final long minTrigger = nowElapsed + MIN_FUTURITY; + final long triggerElapsed = (nominalTrigger > minTrigger) ? nominalTrigger : minTrigger; + final long maxElapsed; if (windowLength == AlarmManager.WINDOW_EXACT) { maxElapsed = triggerElapsed;