Merge "Adding device-idle policy time to alarms"

This commit is contained in:
TreeHugger Robot
2020-10-29 20:38:03 +00:00
committed by Android (Google) Code Review
5 changed files with 427 additions and 285 deletions

View File

@@ -31,6 +31,8 @@ import android.util.IndentingPrintWriter;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -39,17 +41,23 @@ import java.util.Date;
* expires. The timer will wake up the device if the alarm is a "wakeup" alarm.
*/
class Alarm {
private static final int NUM_POLICIES = 2;
@VisibleForTesting
public static final int NUM_POLICIES = 3;
/**
* Index used to store the time the alarm was requested to expire. To be used with
* {@link #setPolicyElapsed(int, long)}
* {@link #setPolicyElapsed(int, long)}.
*/
public static final int REQUESTER_POLICY_INDEX = 0;
/**
* Index used to store the earliest time the alarm can expire based on app-standby policy.
* To be used with {@link #setPolicyElapsed(int, long)}
* To be used with {@link #setPolicyElapsed(int, long)}.
*/
public static final int APP_STANDBY_POLICY_INDEX = 1;
/**
* Index used to store the earliest time the alarm can expire based on the device's doze policy.
* To be used with {@link #setPolicyElapsed(int, long)}.
*/
public static final int DEVICE_IDLE_POLICY_INDEX = 2;
public final int type;
/**
@@ -128,10 +136,18 @@ class Alarm {
* @param policyIndex The index of the policy. One of [{@link #REQUESTER_POLICY_INDEX},
* {@link #APP_STANDBY_POLICY_INDEX}].
*/
public long getPolicyElapsed(int policyIndex) {
@VisibleForTesting
long getPolicyElapsed(int policyIndex) {
return mPolicyWhenElapsed[policyIndex];
}
/**
* @return the time this alarm was requested to go off in the elapsed time base.
*/
public long getRequestedElapsed() {
return mPolicyWhenElapsed[REQUESTER_POLICY_INDEX];
}
/**
* Get the earliest time that this alarm should be delivered to the requesting app.
*/
@@ -205,8 +221,10 @@ class Alarm {
return "requester";
case APP_STANDBY_POLICY_INDEX:
return "app_standby";
case DEVICE_IDLE_POLICY_INDEX:
return "device_idle";
default:
return "unknown";
return "--unknown--";
}
}

View File

@@ -21,12 +21,14 @@ import static android.app.AlarmManager.ELAPSED_REALTIME;
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE;
import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
import static android.app.AlarmManager.FLAG_IDLE_UNTIL;
import static android.app.AlarmManager.RTC;
import static android.app.AlarmManager.RTC_WAKEUP;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.os.UserHandle.USER_SYSTEM;
import static com.android.server.alarm.Alarm.APP_STANDBY_POLICY_INDEX;
import static com.android.server.alarm.Alarm.DEVICE_IDLE_POLICY_INDEX;
import static com.android.server.alarm.Alarm.REQUESTER_POLICY_INDEX;
import android.annotation.NonNull;
@@ -81,7 +83,6 @@ import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.LongArrayQueue;
import android.util.MutableBoolean;
import android.util.NtpTrustedTime;
import android.util.Pair;
import android.util.Slog;
@@ -699,36 +700,31 @@ public class AlarmManagerService extends SystemService {
final HashMap<String, PriorityClass> mPriorities = new HashMap<>();
int mCurrentSeq = 0;
static final class WakeupEvent {
public long when;
public int uid;
public String action;
public WakeupEvent(long theTime, int theUid, String theAction) {
when = theTime;
uid = theUid;
action = theAction;
}
}
final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() {
@Override
public int compare(Alarm lhs, Alarm rhs) {
// priority class trumps everything. TICK < WAKEUP < NORMAL
// Alarm to exit device_idle should go out first.
final boolean lhsIdleUntil = (lhs.flags & FLAG_IDLE_UNTIL) != 0;
final boolean rhsIdleUntil = (rhs.flags & FLAG_IDLE_UNTIL) != 0;
if (lhsIdleUntil != rhsIdleUntil) {
return lhsIdleUntil ? -1 : 1;
}
// Then, priority class trumps everything. TICK < WAKEUP < NORMAL
if (lhs.priorityClass.priority < rhs.priorityClass.priority) {
return -1;
} else if (lhs.priorityClass.priority > rhs.priorityClass.priority) {
return 1;
}
// within each class, sort by nominal delivery time
if (lhs.getWhenElapsed() < rhs.getWhenElapsed()) {
// within each class, sort by requested delivery time
if (lhs.getRequestedElapsed() < rhs.getRequestedElapsed()) {
return -1;
} else if (lhs.getWhenElapsed() > rhs.getWhenElapsed()) {
} else if (lhs.getRequestedElapsed() > rhs.getRequestedElapsed()) {
return 1;
}
// same priority class + same target delivery time
return 0;
}
};
@@ -777,10 +773,9 @@ public class AlarmManagerService extends SystemService {
final AlarmStore mAlarmStore;
// set to non-null if in idle mode; while in this mode, any alarms we don't want
// to run during this time are placed in mPendingWhileIdleAlarms
// to run during this time are rescehduled to go off after this alarm.
Alarm mPendingIdleUntil = null;
Alarm mNextWakeFromIdle = null;
ArrayList<Alarm> mPendingWhileIdleAlarms = new ArrayList<>();
@VisibleForTesting
AlarmManagerService(Context context, Injector injector) {
@@ -830,15 +825,21 @@ public class AlarmManagerService extends SystemService {
return restoreRequestedTime(a);
});
if (mNextWakeFromIdle != null && isRtc(mNextWakeFromIdle.type)) {
// The next wake from idle got updated due to the rtc time change, implying we need
// to update the time we have to come out of idle too.
changed |= mAlarmStore.updateAlarmDeliveries(a -> {
if (a != mPendingIdleUntil) {
return false;
if (changed && mPendingIdleUntil != null) {
if (mNextWakeFromIdle != null && isRtc(mNextWakeFromIdle.type)) {
// The next wake from idle got updated due to the rtc time change, so we need
// to update the time we have to come out of idle too.
final boolean idleUntilUpdated = mAlarmStore.updateAlarmDeliveries(a -> {
if (a != mPendingIdleUntil) {
return false;
}
return adjustIdleUntilTime(a);
});
if (idleUntilUpdated) {
mAlarmStore.updateAlarmDeliveries(
alarm -> adjustDeliveryTimeBasedOnDeviceIdle(alarm));
}
return adjustIdleUntilTime(a);
});
}
}
if (changed) {
@@ -972,11 +973,10 @@ public class AlarmManagerService extends SystemService {
// Recurring alarms may have passed several alarm intervals while the
// alarm was kept pending. Send the appropriate trigger count.
if (alarm.repeatInterval > 0) {
alarm.count += (nowELAPSED - alarm.getPolicyElapsed(REQUESTER_POLICY_INDEX))
/ alarm.repeatInterval;
alarm.count += (nowELAPSED - alarm.getRequestedElapsed()) / alarm.repeatInterval;
// Also schedule its next recurrence
final long delta = alarm.count * alarm.repeatInterval;
final long nextElapsed = alarm.getPolicyElapsed(REQUESTER_POLICY_INDEX) + delta;
final long nextElapsed = alarm.getRequestedElapsed() + delta;
final long nextMaxElapsed = maxTriggerTime(nowELAPSED, nextElapsed,
alarm.repeatInterval);
setImplLocked(alarm.type, alarm.origWhen + delta, nextElapsed,
@@ -1015,25 +1015,6 @@ public class AlarmManagerService extends SystemService {
}
}
void restorePendingWhileIdleAlarmsLocked() {
if (RECORD_DEVICE_IDLE_ALARMS) {
IdleDispatchEntry ent = new IdleDispatchEntry();
ent.uid = 0;
ent.pkg = "FINISH IDLE";
ent.elapsedRealtime = mInjector.getElapsedRealtime();
mAllowWhileIdleDispatches.add(ent);
}
// Bring pending alarms back into the main list.
if (mPendingWhileIdleAlarms.size() > 0) {
ArrayList<Alarm> alarms = mPendingWhileIdleAlarms;
mPendingWhileIdleAlarms = new ArrayList<>();
for (int i = alarms.size() - 1; i >= 0; i--) {
setImplLocked(alarms.get(i));
}
}
}
static final class InFlight {
final PendingIntent mPendingIntent;
final long mWhenElapsed;
@@ -1571,7 +1552,7 @@ public class AlarmManagerService extends SystemService {
return false;
}
restoreRequestedTime(alarm);
long triggerBeforeFuzz = alarm.getPolicyElapsed(REQUESTER_POLICY_INDEX);
long triggerBeforeFuzz = alarm.getRequestedElapsed();
if (mNextWakeFromIdle != null && triggerBeforeFuzz > mNextWakeFromIdle.getWhenElapsed()) {
triggerBeforeFuzz = mNextWakeFromIdle.getWhenElapsed();
}
@@ -1590,6 +1571,35 @@ public class AlarmManagerService extends SystemService {
return true;
}
/**
* Adjusts the delivery time of the alarm based on device_idle (doze) rules.
*
* @param alarm The alarm to adjust
* @return {@code true} if the alarm delivery time was updated.
*/
private boolean adjustDeliveryTimeBasedOnDeviceIdle(Alarm alarm) {
final long nowElapsed = mInjector.getElapsedRealtime();
if (mPendingIdleUntil == null || mPendingIdleUntil == alarm) {
return alarm.setPolicyElapsed(DEVICE_IDLE_POLICY_INDEX, nowElapsed);
}
final long deviceIdlePolicyTime;
if ((alarm.flags & (AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED
| AlarmManager.FLAG_WAKE_FROM_IDLE)) != 0) {
// Unrestricted.
deviceIdlePolicyTime = nowElapsed;
} else if ((alarm.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0) {
// Allowed but limited.
final long lastDispatch = mLastAllowWhileIdleDispatch.get(alarm.creatorUid, 0);
deviceIdlePolicyTime = (lastDispatch == 0) ? nowElapsed
: lastDispatch + mConstants.ALLOW_WHILE_IDLE_LONG_TIME;
} else {
// Not allowed.
deviceIdlePolicyTime = mPendingIdleUntil.getWhenElapsed();
}
return alarm.setPolicyElapsed(DEVICE_IDLE_POLICY_INDEX, deviceIdlePolicyTime);
}
/**
* Adjusts the alarm's policy time for app_standby.
*
@@ -1643,12 +1653,6 @@ public class AlarmManagerService extends SystemService {
return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, nowElapsed);
}
private static boolean isAllowedWhileIdle(Alarm a) {
return ((a.flags & (AlarmManager.FLAG_ALLOW_WHILE_IDLE
| AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED
| AlarmManager.FLAG_WAKE_FROM_IDLE)) != 0);
}
private void setImplLocked(Alarm a) {
if ((a.flags & AlarmManager.FLAG_IDLE_UNTIL) != 0) {
adjustIdleUntilTime(a);
@@ -1676,16 +1680,9 @@ public class AlarmManagerService extends SystemService {
mAlarmStore.remove(mPendingIdleUntil::equals);
}
mPendingIdleUntil = a;
final ArrayList<Alarm> notAllowedWhileIdleAlarms = mAlarmStore.remove(
alarm -> !isAllowedWhileIdle(alarm));
mPendingWhileIdleAlarms.addAll(notAllowedWhileIdleAlarms);
mAlarmStore.updateAlarmDeliveries(alarm -> adjustDeliveryTimeBasedOnDeviceIdle(alarm));
} else if (mPendingIdleUntil != null) {
// We currently have an idle until alarm scheduled; if the new alarm has
// not explicitly stated it wants to run while idle, then put it on hold.
if (!isAllowedWhileIdle(a)) {
mPendingWhileIdleAlarms.add(a);
return;
}
adjustDeliveryTimeBasedOnDeviceIdle(a);
}
if ((a.flags & AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
if (mNextWakeFromIdle == null || mNextWakeFromIdle.getWhenElapsed()
@@ -1694,12 +1691,17 @@ public class AlarmManagerService extends SystemService {
// If this wake from idle is earlier than whatever was previously scheduled,
// and we are currently idling, then the idle-until time needs to be updated.
if (mPendingIdleUntil != null) {
mAlarmStore.updateAlarmDeliveries(alarm -> {
final boolean updated = mAlarmStore.updateAlarmDeliveries(alarm -> {
if (alarm != mPendingIdleUntil) {
return false;
}
return adjustIdleUntilTime(alarm);
});
if (updated) {
// idle-until got updated, so also update all alarms not allowed while idle.
mAlarmStore.updateAlarmDeliveries(
alarm -> adjustDeliveryTimeBasedOnDeviceIdle(alarm));
}
}
}
}
@@ -2095,7 +2097,7 @@ public class AlarmManagerService extends SystemService {
mAppWakeupHistory.dump(pw, nowELAPSED);
if (mPendingIdleUntil != null || mPendingWhileIdleAlarms.size() > 0) {
if (mPendingIdleUntil != null) {
pw.println();
pw.println("Idle mode state:");
@@ -2107,8 +2109,6 @@ public class AlarmManagerService extends SystemService {
} else {
pw.println("null");
}
pw.println("Pending alarms:");
dumpAlarmList(pw, mPendingWhileIdleAlarms, nowELAPSED, sdf);
pw.decreaseIndent();
}
if (mNextWakeFromIdle != null) {
@@ -2428,10 +2428,6 @@ public class AlarmManagerService extends SystemService {
mPendingIdleUntil.dumpDebug(
proto, AlarmManagerServiceDumpProto.PENDING_IDLE_UNTIL, nowElapsed);
}
for (Alarm a : mPendingWhileIdleAlarms) {
a.dumpDebug(proto, AlarmManagerServiceDumpProto.PENDING_WHILE_IDLE_ALARMS,
nowElapsed);
}
if (mNextWakeFromIdle != null) {
mNextWakeFromIdle.dumpDebug(proto, AlarmManagerServiceDumpProto.NEXT_WAKE_FROM_IDLE,
nowElapsed);
@@ -2752,21 +2748,13 @@ public class AlarmManagerService extends SystemService {
return;
}
final Predicate<Alarm> whichAlarms = (Alarm a) -> a.matches(operation, directReceiver);
final ArrayList<Alarm> removedAlarms = mAlarmStore.remove(whichAlarms);
final ArrayList<Alarm> removedAlarms = mAlarmStore.remove(
a -> a.matches(operation, directReceiver));
for (final Alarm removed : removedAlarms) {
decrementAlarmCount(removed.uid, 1);
}
final boolean didRemove = !removedAlarms.isEmpty();
for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
final Alarm alarm = mPendingWhileIdleAlarms.get(i);
if (alarm.matches(operation, directReceiver)) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
mPendingWhileIdleAlarms.remove(i);
decrementAlarmCount(alarm.uid, 1);
}
}
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i);
for (int j = alarmsForUid.size() - 1; j >= 0; j--) {
@@ -2793,22 +2781,25 @@ public class AlarmManagerService extends SystemService {
if (DEBUG_BATCH) {
Slog.v(TAG, "remove(operation) changed bounds; rebatching");
}
boolean restorePending = false;
boolean idleUntilUpdated = false;
if (mPendingIdleUntil != null && mPendingIdleUntil.matches(operation, directReceiver)) {
mPendingIdleUntil = null;
restorePending = true;
idleUntilUpdated = true;
}
if (mNextWakeFromIdle != null && mNextWakeFromIdle.matches(operation, directReceiver)) {
mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
mAlarmStore.updateAlarmDeliveries(alarm -> {
if (alarm != mPendingIdleUntil) {
return false;
}
return adjustIdleUntilTime(alarm);
});
if (mPendingIdleUntil != null) {
idleUntilUpdated |= mAlarmStore.updateAlarmDeliveries(alarm -> {
if (alarm != mPendingIdleUntil) {
return false;
}
return adjustIdleUntilTime(alarm);
});
}
}
if (restorePending) {
restorePendingWhileIdleAlarmsLocked();
if (idleUntilUpdated) {
mAlarmStore.updateAlarmDeliveries(
alarm -> adjustDeliveryTimeBasedOnDeviceIdle(alarm));
}
rescheduleKernelAlarmsLocked();
updateNextAlarmClockLocked();
@@ -2821,21 +2812,12 @@ public class AlarmManagerService extends SystemService {
return;
}
final Predicate<Alarm> whichAlarms = (Alarm a) -> a.uid == uid;
final ArrayList<Alarm> removed = mAlarmStore.remove(whichAlarms);
final ArrayList<Alarm> removed = mAlarmStore.remove(a -> a.uid == uid);
final boolean didRemove = !removed.isEmpty();
if (didRemove) {
decrementAlarmCount(uid, removed.size());
}
for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
final Alarm a = mPendingWhileIdleAlarms.get(i);
if (a.uid == uid) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
mPendingWhileIdleAlarms.remove(i);
decrementAlarmCount(uid, 1);
}
}
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i);
for (int j = alarmsForUid.size() - 1; j >= 0; j--) {
@@ -2850,20 +2832,26 @@ public class AlarmManagerService extends SystemService {
}
// If we're currently using this app's alarms to come out of doze,
// make sure to reset to any remaining WAKE_FROM_IDLE alarms.
boolean idleUntilUpdated = false;
if (mNextWakeFromIdle != null && mNextWakeFromIdle.uid == uid) {
mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
mAlarmStore.updateAlarmDeliveries(alarm -> {
if (alarm != mPendingIdleUntil) {
return false;
}
return adjustIdleUntilTime(alarm);
});
if (mPendingIdleUntil != null) {
idleUntilUpdated |= mAlarmStore.updateAlarmDeliveries(alarm -> {
if (alarm != mPendingIdleUntil) {
return false;
}
return adjustIdleUntilTime(alarm);
});
}
}
if (mPendingIdleUntil != null && mPendingIdleUntil.uid == uid) {
// Should never happen - only the system uid is allowed to set idle-until alarms
Slog.wtf(TAG, "Removed app uid " + uid + " set idle-until alarm!");
mPendingIdleUntil = null;
restorePendingWhileIdleAlarmsLocked();
idleUntilUpdated = true;
}
if (idleUntilUpdated) {
mAlarmStore.updateAlarmDeliveries(alarm -> adjustDeliveryTimeBasedOnDeviceIdle(alarm));
}
if (didRemove) {
if (DEBUG_BATCH) {
@@ -2883,29 +2871,12 @@ public class AlarmManagerService extends SystemService {
return;
}
final MutableBoolean removedNextWakeFromIdle = new MutableBoolean(false);
final Predicate<Alarm> whichAlarms = (Alarm a) -> {
final boolean didMatch = a.matches(packageName);
if (didMatch && a == mNextWakeFromIdle) {
removedNextWakeFromIdle.value = true;
}
return didMatch;
};
final ArrayList<Alarm> removed = mAlarmStore.remove(whichAlarms);
final ArrayList<Alarm> removed = mAlarmStore.remove(a -> a.matches(packageName));
final boolean didRemove = !removed.isEmpty();
if (didRemove) {
decrementAlarmCount(removed.get(0).uid, removed.size());
}
for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
final Alarm a = mPendingWhileIdleAlarms.get(i);
if (a.matches(packageName)) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
mPendingWhileIdleAlarms.remove(i);
decrementAlarmCount(a.uid, 1);
}
}
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i);
for (int j = alarmsForUid.size() - 1; j >= 0; j--) {
@@ -2921,14 +2892,20 @@ public class AlarmManagerService extends SystemService {
}
// If we're currently using this app's alarms to come out of doze,
// make sure to reset to any remaining WAKE_FROM_IDLE alarms.
if (removedNextWakeFromIdle.value) {
if (mNextWakeFromIdle != null && mNextWakeFromIdle.matches(packageName)) {
mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
mAlarmStore.updateAlarmDeliveries(alarm -> {
if (alarm != mPendingIdleUntil) {
return false;
if (mPendingIdleUntil != null) {
final boolean updated = mAlarmStore.updateAlarmDeliveries(alarm -> {
if (alarm != mPendingIdleUntil) {
return false;
}
return adjustIdleUntilTime(alarm);
});
if (updated) {
mAlarmStore.updateAlarmDeliveries(
alarm -> adjustDeliveryTimeBasedOnDeviceIdle(alarm));
}
return adjustIdleUntilTime(alarm);
});
}
}
if (didRemove) {
if (DEBUG_BATCH) {
@@ -2953,14 +2930,6 @@ public class AlarmManagerService extends SystemService {
decrementAlarmCount(uid, removed.size());
}
for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
final Alarm a = mPendingWhileIdleAlarms.get(i);
if (a.uid == uid) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
mPendingWhileIdleAlarms.remove(i);
decrementAlarmCount(uid, 1);
}
}
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
if (mPendingBackgroundAlarms.keyAt(i) == uid) {
final ArrayList<Alarm> toRemove = mPendingBackgroundAlarms.valueAt(i);
@@ -2992,14 +2961,6 @@ public class AlarmManagerService extends SystemService {
}
final boolean didRemove = !removedAlarms.isEmpty();
for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
if (UserHandle.getUserId(mPendingWhileIdleAlarms.get(i).creatorUid)
== userHandle) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
final Alarm removed = mPendingWhileIdleAlarms.remove(i);
decrementAlarmCount(removed.uid, 1);
}
}
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
if (UserHandle.getUserId(mPendingBackgroundAlarms.keyAt(i)) == userHandle) {
final ArrayList<Alarm> toRemove = mPendingBackgroundAlarms.valueAt(i);
@@ -3016,6 +2977,21 @@ public class AlarmManagerService extends SystemService {
mLastAllowWhileIdleDispatch.removeAt(i);
}
}
if (mNextWakeFromIdle != null && whichAlarms.test(mNextWakeFromIdle)) {
mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
if (mPendingIdleUntil != null) {
final boolean updated = mAlarmStore.updateAlarmDeliveries(alarm -> {
if (alarm != mPendingIdleUntil) {
return false;
}
return adjustIdleUntilTime(alarm);
});
if (updated) {
mAlarmStore.updateAlarmDeliveries(
alarm -> adjustDeliveryTimeBasedOnDeviceIdle(alarm));
}
}
}
if (didRemove) {
if (DEBUG_BATCH) {
@@ -3062,12 +3038,6 @@ public class AlarmManagerService extends SystemService {
return true;
}
}
for (int i = 0; i < mPendingWhileIdleAlarms.size(); i++) {
final Alarm a = mPendingWhileIdleAlarms.get(i);
if (a.matches(packageName)) {
return true;
}
}
return false;
}
@@ -3134,16 +3104,10 @@ public class AlarmManagerService extends SystemService {
private static native long getNextAlarm(long nativeData, int type);
private long getWhileIdleMinIntervalLocked(int uid) {
final boolean dozing = mPendingIdleUntil != null;
final boolean ebs = (mAppStateTracker != null)
&& mAppStateTracker.isForceAllAppsStandbyEnabled();
if (!dozing && !ebs) {
return mConstants.ALLOW_WHILE_IDLE_SHORT_TIME;
}
if (dozing) {
return mConstants.ALLOW_WHILE_IDLE_LONG_TIME;
}
if (mUseAllowWhileIdleShortTime.get(uid)) {
if (!ebs || mUseAllowWhileIdleShortTime.get(uid)) {
// if the last allow-while-idle went off while uid was fg, or the uid
// recently came into fg, don't block the alarm for long.
return mConstants.ALLOW_WHILE_IDLE_SHORT_TIME;
@@ -3201,16 +3165,12 @@ public class AlarmManagerService extends SystemService {
}
if (mPendingIdleUntil == alarm) {
mPendingIdleUntil = null;
restorePendingWhileIdleAlarmsLocked();
mAlarmStore.updateAlarmDeliveries(a -> adjustDeliveryTimeBasedOnDeviceIdle(a));
}
if (mNextWakeFromIdle == alarm) {
mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
mAlarmStore.updateAlarmDeliveries(a -> {
if (a != mPendingIdleUntil) {
return false;
}
return adjustIdleUntilTime(a);
});
// Note that we don't need to update mPendingIdleUntil because it should already
// be removed from the alarm store.
}
// Recurring alarms may have passed several alarm intervals while the
@@ -3218,11 +3178,10 @@ public class AlarmManagerService extends SystemService {
if (alarm.repeatInterval > 0) {
// this adjustment will be zero if we're late by
// less than one full repeat interval
alarm.count += (nowELAPSED - alarm.getPolicyElapsed(REQUESTER_POLICY_INDEX))
/ alarm.repeatInterval;
alarm.count += (nowELAPSED - alarm.getRequestedElapsed()) / alarm.repeatInterval;
// Also schedule its next recurrence
final long delta = alarm.count * alarm.repeatInterval;
final long nextElapsed = alarm.getPolicyElapsed(REQUESTER_POLICY_INDEX) + delta;
final long nextElapsed = alarm.getRequestedElapsed() + delta;
final long nextMaxElapsed = maxTriggerTime(nowELAPSED, nextElapsed,
alarm.repeatInterval);
setImplLocked(alarm.type, alarm.origWhen + delta, nextElapsed,
@@ -4222,6 +4181,12 @@ public class AlarmManagerService extends SystemService {
if (allowWhileIdle) {
// Record the last time this uid handled an ALLOW_WHILE_IDLE alarm.
mLastAllowWhileIdleDispatch.put(alarm.creatorUid, nowELAPSED);
mAlarmStore.updateAlarmDeliveries(a -> {
if (a.creatorUid != alarm.creatorUid) {
return false;
}
return adjustDeliveryTimeBasedOnDeviceIdle(a);
});
if ((mAppStateTracker == null)
|| mAppStateTracker.isUidInForeground(alarm.creatorUid)) {
mUseAllowWhileIdleShortTime.put(alarm.creatorUid, true);

View File

@@ -17,8 +17,14 @@ package com.android.server.alarm;
import static android.app.AlarmManager.ELAPSED_REALTIME;
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE;
import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
import static android.app.AlarmManager.FLAG_IDLE_UNTIL;
import static android.app.AlarmManager.FLAG_STANDALONE;
import static android.app.AlarmManager.FLAG_WAKE_FROM_IDLE;
import static android.app.AlarmManager.RTC;
import static android.app.AlarmManager.RTC_WAKEUP;
import static android.app.AlarmManager.WINDOW_EXACT;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
@@ -66,7 +72,6 @@ import static org.mockito.Mockito.atLeastOnce;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
import android.app.IActivityManager;
import android.app.IAlarmCompleteListener;
import android.app.IAlarmListener;
@@ -85,7 +90,6 @@ import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.SparseArray;
@@ -112,8 +116,6 @@ import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.concurrent.Executor;
@@ -354,48 +356,51 @@ public class AlarmManagerServiceTest {
}
private void setTestAlarm(int type, long triggerTime, PendingIntent operation) {
setTestAlarm(type, triggerTime, operation, 0, AlarmManager.FLAG_STANDALONE,
TEST_CALLING_UID);
setTestAlarm(type, triggerTime, operation, 0, FLAG_STANDALONE, TEST_CALLING_UID);
}
private void setRepeatingTestAlarm(int type, long firstTrigger, long interval,
PendingIntent pi) {
setTestAlarm(type, firstTrigger, pi, interval, AlarmManager.FLAG_STANDALONE,
TEST_CALLING_UID);
setTestAlarm(type, firstTrigger, pi, interval, FLAG_STANDALONE, TEST_CALLING_UID);
}
private void setIdleUntilAlarm(int type, long triggerTime, PendingIntent pi) {
setTestAlarm(type, triggerTime, pi, 0, AlarmManager.FLAG_IDLE_UNTIL, TEST_CALLING_UID);
setTestAlarm(type, triggerTime, pi, 0, FLAG_IDLE_UNTIL, TEST_CALLING_UID);
}
private void setWakeFromIdle(int type, long triggerTime, PendingIntent pi) {
// Note: Only alarm clock alarms are allowed to include this flag in the actual service.
// But this is a unit test so we'll only test the flag for granularity and convenience.
setTestAlarm(type, triggerTime, pi, 0,
AlarmManager.FLAG_WAKE_FROM_IDLE | AlarmManager.FLAG_STANDALONE, TEST_CALLING_UID);
setTestAlarm(type, triggerTime, pi, 0, FLAG_WAKE_FROM_IDLE | FLAG_STANDALONE,
TEST_CALLING_UID);
}
private void setAllowWhileIdleAlarm(int type, long triggerTime, PendingIntent pi,
boolean unrestricted) {
final int flags = unrestricted ? FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED : FLAG_ALLOW_WHILE_IDLE;
setTestAlarm(type, triggerTime, pi, 0, flags, TEST_CALLING_UID);
}
private void setTestAlarm(int type, long triggerTime, PendingIntent operation, long interval,
int flags, int callingUid) {
mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, interval, operation, null,
"test", flags, null, null, callingUid, TEST_CALLING_PACKAGE);
mService.setImpl(type, triggerTime, WINDOW_EXACT, interval, operation, null, "test", flags,
null, null, callingUid, TEST_CALLING_PACKAGE);
}
private void setTestAlarmWithListener(int type, long triggerTime, IAlarmListener listener) {
mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, 0,
null, listener, "test", AlarmManager.FLAG_STANDALONE, null, null,
TEST_CALLING_UID, TEST_CALLING_PACKAGE);
mService.setImpl(type, triggerTime, WINDOW_EXACT, 0, null, listener, "test",
FLAG_STANDALONE, null, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
}
private PendingIntent getNewMockPendingIntent() {
return getNewMockPendingIntent(TEST_CALLING_UID);
return getNewMockPendingIntent(TEST_CALLING_UID, TEST_CALLING_PACKAGE);
}
private PendingIntent getNewMockPendingIntent(int mockUid) {
private PendingIntent getNewMockPendingIntent(int creatorUid, String creatorPackage) {
final PendingIntent mockPi = mock(PendingIntent.class, Answers.RETURNS_DEEP_STUBS);
when(mockPi.getCreatorUid()).thenReturn(mockUid);
when(mockPi.getCreatorPackage()).thenReturn(TEST_CALLING_PACKAGE);
when(mockPi.getCreatorUid()).thenReturn(creatorUid);
when(mockPi.getCreatorPackage()).thenReturn(creatorPackage);
return mockPi;
}
@@ -865,7 +870,7 @@ public class AlarmManagerServiceTest {
public void alarmCountKeyedOnCallingUid() {
final int mockCreatorUid = 431412;
setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 5,
getNewMockPendingIntent(mockCreatorUid));
getNewMockPendingIntent(mockCreatorUid, TEST_CALLING_PACKAGE));
assertEquals(1, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
assertEquals(-1, mService.mAlarmsPerUid.get(mockCreatorUid, -1));
}
@@ -1018,33 +1023,14 @@ public class AlarmManagerServiceTest {
for (int i = 0; i < numAlarms; i++) {
int mockUid = UserHandle.getUid(mockUserId, 1234 + i);
setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10,
getNewMockPendingIntent(mockUid), 0, AlarmManager.FLAG_STANDALONE, mockUid);
getNewMockPendingIntent(mockUid, TEST_CALLING_PACKAGE), 0, FLAG_STANDALONE,
mockUid);
}
assertEquals(numAlarms, mService.mAlarmsPerUid.size());
mService.removeUserLocked(mockUserId);
assertEquals(0, mService.mAlarmsPerUid.size());
}
@Test
public void alarmCountOnRemoveFromPendingWhileIdle() {
mService.mPendingIdleUntil = mock(Alarm.class);
final int numAlarms = 15;
final PendingIntent[] pis = new PendingIntent[numAlarms];
for (int i = 0; i < numAlarms; i++) {
pis[i] = getNewMockPendingIntent();
setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 5, pis[i]);
}
assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
assertEquals(numAlarms, mService.mPendingWhileIdleAlarms.size());
final int toRemove = 8;
for (int i = 0; i < toRemove; i++) {
mService.removeLocked(pis[i], null);
assertEquals(numAlarms - i - 1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
}
mService.removeLocked(TEST_CALLING_UID);
assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
}
@Test
public void alarmCountOnAlarmRemoved() {
final int numAlarms = 10;
@@ -1268,6 +1254,134 @@ public class AlarmManagerServiceTest {
assertEquals(mNowElapsedTest + 12, mService.mPendingIdleUntil.getWhenElapsed());
}
@Test
public void allowWhileIdleAlarmsWhileDeviceIdle() throws Exception {
doReturn(0).when(mService).fuzzForDuration(anyLong());
final long awiDelayForTest = 23;
setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_LONG_TIME, awiDelayForTest);
setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_SHORT_TIME, 0);
setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 1000,
getNewMockPendingIntent());
assertNotNull(mService.mPendingIdleUntil);
final long seedTrigger = mNowElapsedTest + 3;
final int numAlarms = 10;
final PendingIntent[] pis = new PendingIntent[numAlarms];
for (int i = 0; i < numAlarms; i++) {
pis[i] = getNewMockPendingIntent();
setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, seedTrigger + i * i, pis[i], false);
}
long lastAwiDispatch = -1;
int i = 0;
while (i < numAlarms) {
final long nextDispatch = (lastAwiDispatch >= 0) ? (lastAwiDispatch + awiDelayForTest)
: (seedTrigger + i * i);
assertEquals("Wrong allow-while-idle dispatch", nextDispatch, mTestTimer.getElapsed());
mNowElapsedTest = nextDispatch;
mTestTimer.expire();
while (i < numAlarms && (seedTrigger + i * i) <= nextDispatch) {
verify(pis[i]).send(eq(mMockContext), eq(0), any(Intent.class), any(),
any(Handler.class), isNull(), any());
i++;
}
Log.d(TAG, "Dispatched alarms upto " + i + " at " + nextDispatch);
lastAwiDispatch = nextDispatch;
}
}
@Test
public void allowWhileIdleUnrestricted() throws Exception {
doReturn(0).when(mService).fuzzForDuration(anyLong());
final long awiDelayForTest = 127;
setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_LONG_TIME, awiDelayForTest);
setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_SHORT_TIME, 0);
setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 1000,
getNewMockPendingIntent());
assertNotNull(mService.mPendingIdleUntil);
final long seedTrigger = mNowElapsedTest + 3;
for (int i = 1; i <= 5; i++) {
setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, seedTrigger + i * i,
getNewMockPendingIntent(), true);
}
for (int i = 1; i <= 5; i++) {
final long nextTrigger = mTestTimer.getElapsed();
assertEquals("Wrong trigger for alarm " + i, seedTrigger + i * i, nextTrigger);
mNowElapsedTest = nextTrigger;
mTestTimer.expire();
}
}
@Test
public void deviceIdleThrottling() throws Exception {
doReturn(0).when(mService).fuzzForDuration(anyLong());
final long deviceIdleUntil = mNowElapsedTest + 1234;
setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, deviceIdleUntil, getNewMockPendingIntent());
assertEquals(deviceIdleUntil, mTestTimer.getElapsed());
final int numAlarms = 10;
final PendingIntent[] pis = new PendingIntent[numAlarms];
for (int i = 0; i < numAlarms; i++) {
setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + i + 1,
pis[i] = getNewMockPendingIntent());
assertEquals(deviceIdleUntil, mTestTimer.getElapsed());
}
mNowElapsedTest = mTestTimer.getElapsed();
mTestTimer.expire();
for (int i = 0; i < numAlarms; i++) {
verify(pis[i]).send(eq(mMockContext), eq(0), any(Intent.class), any(),
any(Handler.class), isNull(), any());
}
}
@Test
public void dispatchOrder() throws Exception {
doReturn(0).when(mService).fuzzForDuration(anyLong());
final long deviceIdleUntil = mNowElapsedTest + 1234;
final PendingIntent idleUntilPi = getNewMockPendingIntent();
setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, deviceIdleUntil, idleUntilPi);
assertEquals(deviceIdleUntil, mTestTimer.getElapsed());
final PendingIntent pi5wakeup = getNewMockPendingIntent();
final PendingIntent pi4wakeupPackage = getNewMockPendingIntent();
final PendingIntent pi2nonWakeup = getNewMockPendingIntent(57, "test.different.package");
setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, pi5wakeup);
setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 4, pi4wakeupPackage);
setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 2, pi2nonWakeup);
mNowElapsedTest = deviceIdleUntil;
mTestTimer.expire();
// The order of the alarms in delivery list should be:
// IdleUntil, all alarms of a package with any wakeup alarms, then the rest.
// Within a package, alarms should be ordered by requested delivery time.
final PendingIntent[] expectedOrder = new PendingIntent[]{
idleUntilPi, pi4wakeupPackage, pi5wakeup, pi2nonWakeup};
ArgumentCaptor<ArrayList<Alarm>> listCaptor = ArgumentCaptor.forClass(ArrayList.class);
verify(mService).deliverAlarmsLocked(listCaptor.capture(), anyLong());
final ArrayList<Alarm> deliveryList = listCaptor.getValue();
assertEquals(expectedOrder.length, deliveryList.size());
for (int i = 0; i < expectedOrder.length; i++) {
assertTrue("Unexpected alarm: " + deliveryList.get(i) + " at pos: " + i,
deliveryList.get(i).matches(expectedOrder[i], null));
}
}
@After
public void tearDown() {
if (mMockingSession != null) {
@@ -1275,12 +1389,4 @@ public class AlarmManagerServiceTest {
}
LocalServices.removeServiceForTest(AlarmManagerInternal.class);
}
private void dumpAllAlarms(String tag, ArrayList<Alarm> alarms) {
System.out.println(tag + ": ");
IndentingPrintWriter ipw = new IndentingPrintWriter(new PrintWriter(System.out));
AlarmManagerService.dumpAlarmList(ipw, alarms, mNowElapsedTest,
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"));
ipw.close();
}
}

View File

@@ -20,6 +20,7 @@ import static com.android.server.alarm.Constants.TEST_CALLING_PACKAGE;
import static com.android.server.alarm.Constants.TEST_CALLING_UID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
@@ -45,22 +46,17 @@ public class AlarmStoreTest {
mAlarmStore = new BatchingAlarmStore(null);
}
private static Alarm createAlarm(long whenElapsed, long windowLength,
AlarmManager.AlarmClockInfo alarmClock) {
return createAlarm(AlarmManager.ELAPSED_REALTIME, whenElapsed, windowLength,
alarmClock);
private static Alarm createAlarm(long whenElapsed, long windowLength) {
return createAlarm(AlarmManager.ELAPSED_REALTIME, whenElapsed, windowLength, 0);
}
private static Alarm createWakeupAlarm(long whenElapsed, long windowLength,
AlarmManager.AlarmClockInfo alarmClock) {
return createAlarm(AlarmManager.ELAPSED_REALTIME_WAKEUP, whenElapsed, windowLength,
alarmClock);
private static Alarm createWakeupAlarm(long whenElapsed, long windowLength, int flags) {
return createAlarm(AlarmManager.ELAPSED_REALTIME_WAKEUP, whenElapsed, windowLength, flags);
}
private static Alarm createAlarm(int type, long whenElapsed, long windowLength,
AlarmManager.AlarmClockInfo alarmClock) {
private static Alarm createAlarm(int type, long whenElapsed, long windowLength, int flags) {
return new Alarm(type, whenElapsed, whenElapsed, windowLength, 0, mock(PendingIntent.class),
null, null, null, 0, alarmClock, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
null, null, null, flags, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
}
private void addAlarmsToStore(Alarm... alarms) {
@@ -71,11 +67,11 @@ public class AlarmStoreTest {
@Test
public void add() {
final Alarm a1 = createAlarm(1, 0, null);
final Alarm a1 = createAlarm(1, 0);
mAlarmStore.add(a1);
assertEquals(1, mAlarmStore.size());
final Alarm a2 = createAlarm(2, 0, null);
final Alarm a2 = createAlarm(2, 0);
mAlarmStore.add(a2);
assertEquals(2, mAlarmStore.size());
@@ -86,9 +82,9 @@ public class AlarmStoreTest {
@Test
public void remove() {
final Alarm a1 = createAlarm(1, 0, null);
final Alarm a2 = createAlarm(2, 0, null);
final Alarm a5 = createAlarm(5, 0, null);
final Alarm a1 = createAlarm(1, 0);
final Alarm a2 = createAlarm(2, 0);
final Alarm a5 = createAlarm(5, 0);
addAlarmsToStore(a1, a2, a5);
ArrayList<Alarm> removed = mAlarmStore.remove(a -> (a.getWhenElapsed() < 4));
@@ -96,7 +92,7 @@ public class AlarmStoreTest {
assertEquals(1, mAlarmStore.size());
assertTrue(removed.contains(a1) && removed.contains(a2));
final Alarm a8 = createAlarm(8, 0, null);
final Alarm a8 = createAlarm(8, 0);
addAlarmsToStore(a8, a2, a1);
removed = mAlarmStore.remove(unused -> false);
@@ -110,9 +106,9 @@ public class AlarmStoreTest {
@Test
public void removePendingAlarms() {
final Alarm a1to11 = createAlarm(1, 10, null);
final Alarm a2to5 = createAlarm(2, 3, null);
final Alarm a6to9 = createAlarm(6, 3, null);
final Alarm a1to11 = createAlarm(1, 10);
final Alarm a2to5 = createAlarm(2, 3);
final Alarm a6to9 = createAlarm(6, 3);
addAlarmsToStore(a2to5, a6to9, a1to11);
final ArrayList<Alarm> pendingAt0 = mAlarmStore.removePendingAlarms(0);
@@ -134,10 +130,10 @@ public class AlarmStoreTest {
@Test
public void getNextWakeupDeliveryTime() {
final Alarm a1to10 = createAlarm(1, 9, null);
final Alarm a3to8wakeup = createWakeupAlarm(3, 5, null);
final Alarm a6wakeup = createWakeupAlarm(6, 0, null);
final Alarm a5 = createAlarm(5, 0, null);
final Alarm a1to10 = createAlarm(1, 9);
final Alarm a3to8wakeup = createWakeupAlarm(3, 5, 0);
final Alarm a6wakeup = createWakeupAlarm(6, 0, 0);
final Alarm a5 = createAlarm(5, 0);
addAlarmsToStore(a5, a6wakeup, a3to8wakeup, a1to10);
// The wakeup alarms are [6] and [3, 8], hence 6 is the latest time till when we can
@@ -155,10 +151,10 @@ public class AlarmStoreTest {
@Test
public void getNextDeliveryTime() {
final Alarm a1to10 = createAlarm(1, 9, null);
final Alarm a3to8wakeup = createWakeupAlarm(3, 5, null);
final Alarm a6wakeup = createWakeupAlarm(6, 0, null);
final Alarm a5 = createAlarm(5, 0, null);
final Alarm a1to10 = createAlarm(1, 9);
final Alarm a3to8wakeup = createWakeupAlarm(3, 5, 0);
final Alarm a6wakeup = createWakeupAlarm(6, 0, 0);
final Alarm a5 = createAlarm(5, 0);
addAlarmsToStore(a5, a6wakeup, a3to8wakeup, a1to10);
assertTrue(mAlarmStore.getNextDeliveryTime() <= 5);
@@ -167,11 +163,33 @@ public class AlarmStoreTest {
assertEquals(0, mAlarmStore.getNextWakeupDeliveryTime());
}
@Test
public void getNextWakeFromIdle() {
final Alarm a3 = createWakeupAlarm(3, 0, AlarmManager.FLAG_WAKE_FROM_IDLE);
final Alarm a5 = createWakeupAlarm(5, 0, AlarmManager.FLAG_WAKE_FROM_IDLE);
final Alarm a7 = createWakeupAlarm(7, 0, AlarmManager.FLAG_WAKE_FROM_IDLE);
mAlarmStore.add(a5);
assertEquals(a5, mAlarmStore.getNextWakeFromIdleAlarm());
mAlarmStore.add(a7);
assertEquals(a5, mAlarmStore.getNextWakeFromIdleAlarm());
mAlarmStore.add(a3);
assertEquals(a3, mAlarmStore.getNextWakeFromIdleAlarm());
mAlarmStore.remove(a -> (a == a3) || (a == a5));
assertEquals(a7, mAlarmStore.getNextWakeFromIdleAlarm());
mAlarmStore.remove(a -> (a == a7));
assertNull(mAlarmStore.getNextWakeFromIdleAlarm());
}
@Test
public void updateAlarmDeliveries() {
final Alarm a5 = createAlarm(5, 0, null);
final Alarm a8 = createAlarm(8, 0, null);
final Alarm a10 = createAlarm(10, 0, null);
final Alarm a5 = createAlarm(5, 0);
final Alarm a8 = createAlarm(8, 0);
final Alarm a10 = createAlarm(10, 0);
addAlarmsToStore(a8, a10, a5);
assertEquals(5, mAlarmStore.getNextDeliveryTime());

View File

@@ -19,6 +19,7 @@ package com.android.server.alarm;
import static android.app.AlarmManager.ELAPSED_REALTIME;
import static com.android.server.alarm.Alarm.APP_STANDBY_POLICY_INDEX;
import static com.android.server.alarm.Alarm.NUM_POLICIES;
import static com.android.server.alarm.Alarm.REQUESTER_POLICY_INDEX;
import static com.android.server.alarm.Constants.TEST_CALLING_PACKAGE;
import static com.android.server.alarm.Constants.TEST_CALLING_UID;
@@ -36,6 +37,8 @@ import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Random;
@Presubmit
@RunWith(AndroidJUnit4.class)
public class AlarmTest {
@@ -49,29 +52,54 @@ public class AlarmTest {
@Test
public void initSetsOnlyRequesterPolicy() {
final Alarm a = createDefaultAlarm(4567, 2);
assertEquals(4567, a.getPolicyElapsed(REQUESTER_POLICY_INDEX));
assertEquals(0, a.getPolicyElapsed(APP_STANDBY_POLICY_INDEX));
for (int i = 0; i < NUM_POLICIES; i++) {
if (i == REQUESTER_POLICY_INDEX) {
assertEquals(4567, a.getPolicyElapsed(i));
} else {
assertEquals(0, a.getPolicyElapsed(i));
}
}
}
/**
* Generates a long matrix {@code A} of size {@code NxN}, with the property that the {@code i}th
* row will have the {@code i}th element largest in that row.
*
* In other words, {@code A[i][i]} will be the maximum of {@code A[i][j]} over all {@code j},
* {@code 0<=j<N}.
*/
private static long[][] generatePolicyTestMatrix(int n) {
final long[][] data = new long[n][n];
final Random random = new Random(971);
for (int i = 0; i < n; i++) {
data[i][i] = 1;
for (int j = 0; j < n; j++) {
if (i != j) {
data[i][j] = random.nextInt(1 << 20);
data[i][i] += data[i][j];
}
}
}
return data;
}
@Test
public void whenElapsed() {
final Alarm a = createDefaultAlarm(0, 0);
a.setPolicyElapsed(REQUESTER_POLICY_INDEX, 4);
a.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 10);
assertEquals(10, a.getWhenElapsed());
final long[][] uniqueData = generatePolicyTestMatrix(NUM_POLICIES);
for (int i = 0; i < NUM_POLICIES; i++) {
for (int j = 0; j < NUM_POLICIES; j++) {
a.setPolicyElapsed(j, uniqueData[i][j]);
}
assertEquals(uniqueData[i][i], a.getWhenElapsed());
}
a.setPolicyElapsed(REQUESTER_POLICY_INDEX, 12);
assertEquals(12, a.getWhenElapsed());
a.setPolicyElapsed(REQUESTER_POLICY_INDEX, 7);
assertEquals(10, a.getWhenElapsed());
a.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 2);
assertEquals(7, a.getWhenElapsed());
a.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 7);
assertEquals(7, a.getWhenElapsed());
for (int i = 0; i < NUM_POLICIES; i++) {
a.setPolicyElapsed(i, 3);
}
assertEquals(3, a.getWhenElapsed());
}
@Test
@@ -85,18 +113,21 @@ public class AlarmTest {
a.setPolicyElapsed(REQUESTER_POLICY_INDEX, 2);
assertEquals(14, a.getMaxWhenElapsed());
a.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 5);
assertEquals(14, a.getMaxWhenElapsed());
for (int i = 0; i < NUM_POLICIES; i++) {
if (i == REQUESTER_POLICY_INDEX) {
continue;
}
a.setPolicyElapsed(i, 17);
// getWhenElapsed is 17, so getMaxWhenElapsed will return 17 too.
assertEquals(17, a.getMaxWhenElapsed());
a.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 16);
assertEquals(16, a.getMaxWhenElapsed());
a.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 12);
assertEquals(14, a.getMaxWhenElapsed());
a.setPolicyElapsed(i, 5);
assertEquals(14, a.getMaxWhenElapsed());
}
}
@Test
public void setPolicyElapsed() {
public void setPolicyElapsedExact() {
final Alarm exactAlarm = createDefaultAlarm(10, 0);
assertTrue(exactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 4));
@@ -108,6 +139,10 @@ public class AlarmTest {
assertTrue(exactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 7));
}
@Test
public void setPolicyElapsedInexact() {
final Alarm inexactAlarm = createDefaultAlarm(10, 5);
assertTrue(inexactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 4));