Merge "Tune delivery and batching of alarms" into lmp-dev

automerge: 3ec6a91

* commit '3ec6a91204ffac6e81eaad7ca29e817e9502f856':
  Tune delivery and batching of alarms
This commit is contained in:
Bart Sears
2014-12-12 13:15:38 +00:00
committed by android-build-merger

View File

@@ -61,6 +61,7 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Locale; import java.util.Locale;
import java.util.Random;
import java.util.TimeZone; import java.util.TimeZone;
import static android.app.AlarmManager.RTC_WAKEUP; import static android.app.AlarmManager.RTC_WAKEUP;
@@ -108,8 +109,12 @@ class AlarmManagerService extends SystemService {
final Object mLock = new Object(); final Object mLock = new Object();
long mNativeData; 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; private long mNextNonWakeup;
int mBroadcastRefCount = 0; int mBroadcastRefCount = 0;
PowerManager.WakeLock mWakeLock; PowerManager.WakeLock mWakeLock;
boolean mLastWakeLockUnimportantForLogging; boolean mLastWakeLockUnimportantForLogging;
@@ -361,14 +366,27 @@ class AlarmManagerService extends SystemService {
static class BatchTimeOrder implements Comparator<Batch> { static class BatchTimeOrder implements Comparator<Batch> {
public int compare(Batch b1, Batch b2) { public int compare(Batch b1, Batch b2) {
long when1 = b1.start; final long start1 = b1.start;
long when2 = b2.start; final long start2 = b2.start;
if (when1 - when2 > 0) { if (start1 > start2) {
return 1; return 1;
} }
if (when1 - when2 < 0) { if (start1 < start2) {
return -1; 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; return 0;
} }
} }
@@ -591,7 +609,7 @@ class AlarmManagerService extends SystemService {
@Override @Override
public void onStart() { public void onStart() {
mNativeData = init(); mNativeData = init();
mNextWakeup = mNextNonWakeup = 0; mNextWakeup = mNextWakeupBatchStart = mNextNonWakeup = 0;
// We have to set current TimeZone info to kernel // We have to set current TimeZone info to kernel
// because kernel doesn't keep this after reboot // because kernel doesn't keep this after reboot
@@ -786,8 +804,9 @@ class AlarmManagerService extends SystemService {
"AlarmManager.set"); "AlarmManager.set");
} }
// Exact alarms are standalone; inexact get batched together
setImpl(type, triggerAtTime, windowLength, interval, operation, setImpl(type, triggerAtTime, windowLength, interval, operation,
false, workSource, alarmClock); windowLength == AlarmManager.WINDOW_EXACT, workSource, alarmClock);
} }
@Override @Override
@@ -858,7 +877,7 @@ class AlarmManagerService extends SystemService {
pw.print("nowRTC="); pw.print(nowRTC); pw.print("nowRTC="); pw.print(nowRTC);
pw.print("="); pw.print(sdf.format(new Date(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(); pw.println();
if (!mInteractive) { if (!mInteractive) {
pw.print("Time since non-interactive: "); pw.print("Time since non-interactive: ");
@@ -1064,17 +1083,6 @@ class AlarmManagerService extends SystemService {
return true; 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) { private AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) {
synchronized (mLock) { synchronized (mLock) {
return mNextAlarmClockForUser.get(userId); return mNextAlarmClockForUser.get(userId);
@@ -1208,16 +1216,48 @@ class AlarmManagerService extends SystemService {
// prior to that which contains no wakeups, we schedule that as well. // prior to that which contains no wakeups, we schedule that as well.
long nextNonWakeup = 0; long nextNonWakeup = 0;
if (mAlarmBatches.size() > 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); final Batch firstBatch = mAlarmBatches.get(0);
if (firstWakeup != null && mNextWakeup != firstWakeup.start) { if (firstWakeup != null && mNextWakeupBatchStart != firstWakeup.start) {
mNextWakeup = firstWakeup.start; mNextWakeupBatchStart = mNextWakeup = firstWakeup.start;
setLocked(ELAPSED_REALTIME_WAKEUP, 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) { if (firstBatch != firstWakeup) {
nextNonWakeup = firstBatch.start; nextNonWakeup = firstBatch.start;
} }
} }
if (mPendingNonWakeupAlarms.size() > 0) { if (mPendingNonWakeupAlarms.size() > 0) {
if (nextNonWakeup == 0 || mNextNonWakeupDeliveryTime < nextNonWakeup) { if (nextNonWakeup == 0 || mNextNonWakeupDeliveryTime < nextNonWakeup) {
nextNonWakeup = mNextNonWakeupDeliveryTime; nextNonWakeup = mNextNonWakeupDeliveryTime;