summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Tate <ctate@google.com>2014-12-04 18:27:16 -0800
committerThe Android Automerger <android-build@google.com>2014-12-11 18:03:20 -0800
commita6e7e6bf5923f427785d6946ac050ba4e4052dc5 (patch)
treeed21fc9037c93c289fdbd4c9227201c843c7cb46
parent5a995f968ca0e5c9701e36f0240b4708ea69c78d (diff)
downloadbase-a6e7e6bf5923f427785d6946ac050ba4e4052dc5.tar.gz
Tune delivery and batching of alarms
cherry-pick from lmp-mr1-dev * Inexact alarms no longer coalesce with exact alarms. The motivation here is that exact alarms are far more likely to be wall-clock aligned, and in general pulling all alarms toward wall-clock alignment is a bad idea. * Wakeup times are now fuzzed within the target batch's allowed window rather than being hard pinned at the start of the window. Bug 18631821 Change-Id: Iefaf34eee3f2a6546abefc27e177ee2fdcff935f (cherry picked from commit 81f9882b5aadd6a2289c9f521a06a7af5f35ebf0)
-rw-r--r--services/core/java/com/android/server/AlarmManagerService.java86
1 files changed, 63 insertions, 23 deletions
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 9d6ccfb03882..ed8bc51f0de9 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -61,6 +61,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Locale;
+import java.util.Random;
import java.util.TimeZone;
import static android.app.AlarmManager.RTC_WAKEUP;
@@ -108,8 +109,12 @@ class AlarmManagerService extends SystemService {
final Object mLock = new Object();
long mNativeData;
- private long mNextWakeup;
+
+ private final Random mFuzzer = new Random();
+ private long mNextWakeupBatchStart; // nominal start of next wakeup's delivery window
+ private long mNextWakeup; // actual scheduled next wakeup within that window
private long mNextNonWakeup;
+
int mBroadcastRefCount = 0;
PowerManager.WakeLock mWakeLock;
boolean mLastWakeLockUnimportantForLogging;
@@ -361,14 +366,27 @@ class AlarmManagerService extends SystemService {
static class BatchTimeOrder implements Comparator<Batch> {
public int compare(Batch b1, Batch b2) {
- long when1 = b1.start;
- long when2 = b2.start;
- if (when1 - when2 > 0) {
+ final long start1 = b1.start;
+ final long start2 = b2.start;
+ if (start1 > start2) {
return 1;
}
- if (when1 - when2 < 0) {
+ if (start1 < start2) {
return -1;
}
+
+ // Identical trigger times. As a secondary ordering, require that
+ // the batch with the shorter allowable delivery window sorts first.
+ final long interval1 = b1.end - b1.start;
+ final long interval2 = b2.end - b2.start;
+ if (interval1 > interval2) {
+ return 1;
+ }
+ if (interval2 < interval1) {
+ return -1;
+ }
+
+ // equal start + delivery window => they're identical
return 0;
}
}
@@ -591,7 +609,7 @@ class AlarmManagerService extends SystemService {
@Override
public void onStart() {
mNativeData = init();
- mNextWakeup = mNextNonWakeup = 0;
+ mNextWakeup = mNextWakeupBatchStart = mNextNonWakeup = 0;
// We have to set current TimeZone info to kernel
// because kernel doesn't keep this after reboot
@@ -786,8 +804,9 @@ class AlarmManagerService extends SystemService {
"AlarmManager.set");
}
+ // Exact alarms are standalone; inexact get batched together
setImpl(type, triggerAtTime, windowLength, interval, operation,
- false, workSource, alarmClock);
+ windowLength == AlarmManager.WINDOW_EXACT, workSource, alarmClock);
}
@Override
@@ -858,7 +877,7 @@ class AlarmManagerService extends SystemService {
pw.print("nowRTC="); pw.print(nowRTC);
pw.print("="); pw.print(sdf.format(new Date(nowRTC)));
- pw.print(" nowELAPSED="); TimeUtils.formatDuration(nowELAPSED, pw);
+ pw.print(" nowELAPSED="); pw.print(nowELAPSED);
pw.println();
if (!mInteractive) {
pw.print("Time since non-interactive: ");
@@ -1064,17 +1083,6 @@ class AlarmManagerService extends SystemService {
return true;
}
- private Batch findFirstWakeupBatchLocked() {
- final int N = mAlarmBatches.size();
- for (int i = 0; i < N; i++) {
- Batch b = mAlarmBatches.get(i);
- if (b.hasWakeups()) {
- return b;
- }
- }
- return null;
- }
-
private AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) {
synchronized (mLock) {
return mNextAlarmClockForUser.get(userId);
@@ -1208,16 +1216,48 @@ class AlarmManagerService extends SystemService {
// prior to that which contains no wakeups, we schedule that as well.
long nextNonWakeup = 0;
if (mAlarmBatches.size() > 0) {
- final Batch firstWakeup = findFirstWakeupBatchLocked();
+ // Find the first wakeup alarm and note the following batch as well. We'll be
+ // choosing a fuzzed delivery time within the first's allowable interval but
+ // ensuring that it does not encroach on the second's start time, to minimize
+ // alarm reordering.
+ Batch firstWakeup = null, nextAfterWakeup = null;
+ final int N = mAlarmBatches.size();
+ for (int i = 0; i < N; i++) {
+ Batch b = mAlarmBatches.get(i);
+ if (b.hasWakeups()) {
+ firstWakeup = b;
+ if (i < N-1) {
+ nextAfterWakeup = mAlarmBatches.get(i+1);
+ }
+ break;
+ }
+ }
+
+ // There's a subtlety here: we depend on the invariant that if two batches
+ // exist with the same start time, the one with the shorter delivery window
+ // is sorted before the other. This guarantees us that we need only look
+ // at the first [relevant] batch in the queue in order to schedule an alarm
+ // appropriately.
final Batch firstBatch = mAlarmBatches.get(0);
- if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
- mNextWakeup = firstWakeup.start;
- setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
+ if (firstWakeup != null && mNextWakeupBatchStart != firstWakeup.start) {
+ mNextWakeupBatchStart = mNextWakeup = firstWakeup.start;
+ final long windowEnd = (nextAfterWakeup == null)
+ ? firstWakeup.end
+ : Math.min(firstWakeup.end, nextAfterWakeup.start);
+ final long interval = windowEnd - firstWakeup.start;
+ // if the interval is over maxint we're into crazy land anyway, but
+ // just in case we check and don't fuzz if the conversion to int for
+ // random-number purposes would blow up
+ if (interval > 0 && interval < Integer.MAX_VALUE) {
+ mNextWakeup += mFuzzer.nextInt((int) interval);
+ }
+ setLocked(ELAPSED_REALTIME_WAKEUP, mNextWakeup);
}
if (firstBatch != firstWakeup) {
nextNonWakeup = firstBatch.start;
}
}
+
if (mPendingNonWakeupAlarms.size() > 0) {
if (nextNonWakeup == 0 || mNextNonWakeupDeliveryTime < nextNonWakeup) {
nextNonWakeup = mNextNonWakeupDeliveryTime;