diff options
| author | 2014-12-12 01:52:29 +0000 | |
|---|---|---|
| committer | 2014-12-12 01:52:31 +0000 | |
| commit | 3ec6a91204ffac6e81eaad7ca29e817e9502f856 (patch) | |
| tree | 99e2cb495b471811e5d931aadcc87c93fedf3903 | |
| parent | 8965a8da5513cf31a313ecdac3506718c2813932 (diff) | |
| parent | b62aa5530ef2ec17177bb54018c5cda3080c94bc (diff) | |
Merge "Tune delivery and batching of alarms" into lmp-dev
| -rw-r--r-- | services/core/java/com/android/server/AlarmManagerService.java | 86 |
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; |