diff options
| author | 2021-05-03 19:46:34 -0700 | |
|---|---|---|
| committer | 2021-05-04 19:37:40 -0700 | |
| commit | 74b85211fa12e3e0585fb538f313c234c3e0c27b (patch) | |
| tree | d3caa73bc6175756b01bf665fe8cbf221dc668dd | |
| parent | 54df750079167360102da81ab7b77582a67190e9 (diff) | |
Hold wakeup alarms for as long as possible
If the screen is off, but the CPU is awake and epoll_wait returns for a
non-wakeup alarm, sending any wakeup alarm within its eligibility window
would cause all the held non-wakeup alarms to also fire, which could:
1. Elongate the length of the time the CPU is awake.
2. Cause apps to wake up and perform work.
This change defers sending any wakeup alarm as long as it is possible to
defer all such eligible alarms to later.
Also, fixed a bug in sorting after adding multiple alarms to the store.
Test: atest CtsAlarmManagerTestCases
atest FrameworksMockingServicesTests:com.android.server.alarm
Bug: 161497385
Change-Id: I01f98255091baddf4e7529f88733776e27d090d7
| -rw-r--r-- | apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java | 41 |
1 files changed, 32 insertions, 9 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java index 2e12e2f34ea0..0073335a1332 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java @@ -40,6 +40,7 @@ import java.util.function.Predicate; public class LazyAlarmStore implements AlarmStore { @VisibleForTesting static final String TAG = LazyAlarmStore.class.getSimpleName(); + private static final long ALARM_DEADLINE_SLOP = 500; private final ArrayList<Alarm> mAlarms = new ArrayList<>(); private Runnable mOnAlarmClockRemoved; @@ -75,7 +76,7 @@ public class LazyAlarmStore implements AlarmStore { return; } mAlarms.addAll(alarms); - Collections.sort(alarms, sDecreasingTimeOrder); + Collections.sort(mAlarms, sDecreasingTimeOrder); } @Override @@ -163,25 +164,47 @@ public class LazyAlarmStore implements AlarmStore { @Override public ArrayList<Alarm> removePendingAlarms(long nowElapsed) { final ArrayList<Alarm> pending = new ArrayList<>(); - final ArrayList<Alarm> standAlones = new ArrayList<>(); + + // Only send wake-up alarms if this is the absolutely latest time we can evaluate + // for at least one wakeup alarm. This prevents sending other non-wakeup alarms when the + // screen is off but the CPU is awake for some reason. + boolean sendWakeups = false; + + // If any alarm with FLAG_STANDALONE is present, we cannot send any alarms without that flag + // in the present batch. + boolean standalonesOnly = false; for (int i = mAlarms.size() - 1; i >= 0; i--) { final Alarm alarm = mAlarms.get(i); if (alarm.getWhenElapsed() > nowElapsed) { break; } + mAlarms.remove(i); pending.add(alarm); + if (alarm.wakeup && alarm.getMaxWhenElapsed() <= nowElapsed + ALARM_DEADLINE_SLOP) { + // Using some slop as it is better to send the wakeup alarm now, rather than + // waking up again a short time later, just to send it. + sendWakeups = true; + } if ((alarm.flags & AlarmManager.FLAG_STANDALONE) != 0) { - standAlones.add(alarm); + standalonesOnly = true; } } - if (!standAlones.isEmpty()) { - // If there are deliverable standalone alarms, others must not go out yet. - mAlarms.removeAll(standAlones); - return standAlones; + final ArrayList<Alarm> toSend = new ArrayList<>(); + for (int i = pending.size() - 1; i >= 0; i--) { + final Alarm pendingAlarm = pending.get(i); + if (!sendWakeups && pendingAlarm.wakeup) { + continue; + } + if (standalonesOnly && (pendingAlarm.flags & AlarmManager.FLAG_STANDALONE) == 0) { + continue; + } + pending.remove(i); + toSend.add(pendingAlarm); } - mAlarms.removeAll(pending); - return pending; + // Perhaps some alarms could not be sent right now. Adding them back for later. + addAll(pending); + return toSend; } @Override |