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
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 8b524dd..08c47dc 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -75,6 +75,12 @@
// 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 @@
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 @@
}
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;