Skip to content

Commit b88ba91

Browse files
Christopher TateAndroid (Google) Code Review
authored andcommitted
Merge "Fix alarm delivery-order sorting" into lmp-dev
2 parents ba5df0d + 1590f1e commit b88ba91

1 file changed

Lines changed: 73 additions & 6 deletions

File tree

services/core/java/com/android/server/AlarmManagerService.java

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import java.util.Collections;
5959
import java.util.Comparator;
6060
import java.util.Date;
61+
import java.util.HashMap;
6162
import java.util.LinkedList;
6263
import java.util.Locale;
6364
import java.util.TimeZone;
@@ -141,6 +142,25 @@ class AlarmManagerService extends SystemService {
141142
private final SparseArray<AlarmManager.AlarmClockInfo> mHandlerSparseAlarmClockArray =
142143
new SparseArray<>();
143144

145+
// Alarm delivery ordering bookkeeping
146+
static final int PRIO_TICK = 0;
147+
static final int PRIO_WAKEUP = 1;
148+
static final int PRIO_NORMAL = 2;
149+
150+
class PriorityClass {
151+
int seq;
152+
int priority;
153+
154+
PriorityClass() {
155+
seq = mCurrentSeq - 1;
156+
priority = PRIO_NORMAL;
157+
}
158+
}
159+
160+
final HashMap<String, PriorityClass> mPriorities =
161+
new HashMap<String, PriorityClass>();
162+
int mCurrentSeq = 0;
163+
144164
class WakeupEvent {
145165
public long when;
146166
public int uid;
@@ -356,22 +376,62 @@ public int compare(Batch b1, Batch b2) {
356376
final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() {
357377
@Override
358378
public int compare(Alarm lhs, Alarm rhs) {
359-
if ((!lhs.operation.getCreatorPackage().equals(rhs.operation.getCreatorPackage()))
360-
&& lhs.wakeup != rhs.wakeup) {
361-
// We want to put wakeup alarms before non-wakeup alarms, since they are
362-
// the things that drive most activity in the alarm manager. However,
363-
// alarms from the same package should always be ordered strictly by time.
364-
return lhs.wakeup ? -1 : 1;
379+
// priority class trumps everything. TICK < WAKEUP < NORMAL
380+
if (lhs.priorityClass.priority < rhs.priorityClass.priority) {
381+
return -1;
382+
} else if (lhs.priorityClass.priority > rhs.priorityClass.priority) {
383+
return 1;
365384
}
385+
386+
// within each class, sort by nominal delivery time
366387
if (lhs.whenElapsed < rhs.whenElapsed) {
367388
return -1;
368389
} else if (lhs.whenElapsed > rhs.whenElapsed) {
369390
return 1;
370391
}
392+
393+
// same priority class + same target delivery time
371394
return 0;
372395
}
373396
};
374397

398+
void calculateDeliveryPriorities(ArrayList<Alarm> alarms) {
399+
final int N = alarms.size();
400+
for (int i = 0; i < N; i++) {
401+
Alarm a = alarms.get(i);
402+
403+
final int alarmPrio;
404+
if (Intent.ACTION_TIME_TICK.equals(a.operation.getIntent().getAction())) {
405+
alarmPrio = PRIO_TICK;
406+
} else if (a.wakeup) {
407+
alarmPrio = PRIO_WAKEUP;
408+
} else {
409+
alarmPrio = PRIO_NORMAL;
410+
}
411+
412+
PriorityClass packagePrio = a.priorityClass;
413+
if (packagePrio == null) packagePrio = mPriorities.get(a.operation.getCreatorPackage());
414+
if (packagePrio == null) {
415+
packagePrio = a.priorityClass = new PriorityClass(); // lowest prio & stale sequence
416+
mPriorities.put(a.operation.getCreatorPackage(), packagePrio);
417+
}
418+
a.priorityClass = packagePrio;
419+
420+
if (packagePrio.seq != mCurrentSeq) {
421+
// first alarm we've seen in the current delivery generation from this package
422+
packagePrio.priority = alarmPrio;
423+
packagePrio.seq = mCurrentSeq;
424+
} else {
425+
// Multiple alarms from this package being delivered in this generation;
426+
// bump the package's delivery class if it's warranted.
427+
// TICK < WAKEUP < NORMAL
428+
if (alarmPrio < packagePrio.priority) {
429+
packagePrio.priority = alarmPrio;
430+
}
431+
}
432+
}
433+
}
434+
375435
// minimum recurrence period or alarm futurity for us to be able to fuzz it
376436
static final long MIN_FUZZABLE_INTERVAL = 10000;
377437
static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
@@ -1381,6 +1441,10 @@ boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
13811441
}
13821442
}
13831443

1444+
// This is a new alarm delivery set; bump the sequence number to indicate that
1445+
// all apps' alarm delivery classes should be recalculated.
1446+
mCurrentSeq++;
1447+
calculateDeliveryPriorities(triggerList);
13841448
Collections.sort(triggerList, mAlarmDispatchComparator);
13851449

13861450
if (localLOGV) {
@@ -1423,6 +1487,7 @@ private static class Alarm {
14231487
public long repeatInterval;
14241488
public final AlarmManager.AlarmClockInfo alarmClock;
14251489
public final int userId;
1490+
public PriorityClass priorityClass;
14261491

14271492
public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
14281493
long _interval, PendingIntent _op, WorkSource _ws,
@@ -1676,6 +1741,7 @@ public void run()
16761741
rescheduleKernelAlarmsLocked();
16771742
updateNextAlarmClockLocked();
16781743
if (mPendingNonWakeupAlarms.size() > 0) {
1744+
calculateDeliveryPriorities(mPendingNonWakeupAlarms);
16791745
triggerList.addAll(mPendingNonWakeupAlarms);
16801746
Collections.sort(triggerList, mAlarmDispatchComparator);
16811747
final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
@@ -1889,6 +1955,7 @@ public void onReceive(Context context, Intent intent) {
18891955
if (pkgList != null && (pkgList.length > 0)) {
18901956
for (String pkg : pkgList) {
18911957
removeLocked(pkg);
1958+
mPriorities.remove(pkg);
18921959
for (int i=mBroadcastStats.size()-1; i>=0; i--) {
18931960
ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i);
18941961
if (uidStats.remove(pkg) != null) {

0 commit comments

Comments
 (0)