Merge "Adding a policy mechanism to control alarms"
This commit is contained in:
committed by
Android (Google) Code Review
commit
4ed5b2bbeb
@@ -16,10 +16,13 @@
|
||||
|
||||
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.RTC;
|
||||
import static android.app.AlarmManager.RTC_WAKEUP;
|
||||
|
||||
import static com.android.server.alarm.AlarmManagerService.clampPositive;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.IAlarmListener;
|
||||
import android.app.PendingIntent;
|
||||
@@ -32,8 +35,28 @@ import java.io.PrintWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Class to describe an alarm that is used to the set the kernel timer that returns when the timer
|
||||
* expires. The timer will wake up the device if the alarm is a "wakeup" alarm.
|
||||
*/
|
||||
class Alarm {
|
||||
private static final int NUM_POLICIES = 2;
|
||||
/**
|
||||
* Index used to store the time the alarm was requested to expire. To be used with
|
||||
* {@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)}
|
||||
*/
|
||||
public static final int APP_STANDBY_POLICY_INDEX = 1;
|
||||
|
||||
public final int type;
|
||||
/**
|
||||
* The original trigger time supplied by the caller. This can be in the elapsed or rtc time base
|
||||
* depending on the type of this alarm
|
||||
*/
|
||||
public final long origWhen;
|
||||
public final boolean wakeup;
|
||||
public final PendingIntent operation;
|
||||
@@ -47,42 +70,40 @@ class Alarm {
|
||||
public final int creatorUid;
|
||||
public final String packageName;
|
||||
public final String sourcePackage;
|
||||
public final long windowLength;
|
||||
public final long repeatInterval;
|
||||
public int count;
|
||||
public long when;
|
||||
public long windowLength;
|
||||
public long whenElapsed; // 'when' in the elapsed time base
|
||||
public long maxWhenElapsed; // also in the elapsed time base
|
||||
// Expected alarm expiry time before app standby deferring is applied.
|
||||
public long expectedWhenElapsed;
|
||||
public long expectedMaxWhenElapsed;
|
||||
public long repeatInterval;
|
||||
/** The earliest time this alarm is eligible to fire according to each policy */
|
||||
private long[] mPolicyWhenElapsed;
|
||||
/** The ultimate delivery time to be used for this alarm */
|
||||
private long mWhenElapsed;
|
||||
private long mMaxWhenElapsed;
|
||||
public AlarmManagerService.PriorityClass priorityClass;
|
||||
|
||||
Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
|
||||
long _interval, PendingIntent _op, IAlarmListener _rec, String _listenerTag,
|
||||
WorkSource _ws, int _flags, AlarmManager.AlarmClockInfo _info,
|
||||
int _uid, String _pkgName) {
|
||||
type = _type;
|
||||
origWhen = _when;
|
||||
wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
|
||||
|| _type == AlarmManager.RTC_WAKEUP;
|
||||
when = _when;
|
||||
whenElapsed = _whenElapsed;
|
||||
expectedWhenElapsed = _whenElapsed;
|
||||
windowLength = _windowLength;
|
||||
maxWhenElapsed = expectedMaxWhenElapsed = AlarmManagerService.clampPositive(_maxWhen);
|
||||
repeatInterval = _interval;
|
||||
operation = _op;
|
||||
listener = _rec;
|
||||
listenerTag = _listenerTag;
|
||||
statsTag = makeTag(_op, _listenerTag, _type);
|
||||
workSource = _ws;
|
||||
flags = _flags;
|
||||
alarmClock = _info;
|
||||
uid = _uid;
|
||||
packageName = _pkgName;
|
||||
Alarm(int type, long when, long requestedWhenElapsed, long windowLength, long interval,
|
||||
PendingIntent op, IAlarmListener rec, String listenerTag, WorkSource ws, int flags,
|
||||
AlarmManager.AlarmClockInfo info, int uid, String pkgName) {
|
||||
this.type = type;
|
||||
origWhen = when;
|
||||
wakeup = type == AlarmManager.ELAPSED_REALTIME_WAKEUP
|
||||
|| type == AlarmManager.RTC_WAKEUP;
|
||||
mPolicyWhenElapsed = new long[NUM_POLICIES];
|
||||
mPolicyWhenElapsed[REQUESTER_POLICY_INDEX] = requestedWhenElapsed;
|
||||
mWhenElapsed = requestedWhenElapsed;
|
||||
this.windowLength = windowLength;
|
||||
mMaxWhenElapsed = clampPositive(requestedWhenElapsed + windowLength);
|
||||
repeatInterval = interval;
|
||||
operation = op;
|
||||
listener = rec;
|
||||
this.listenerTag = listenerTag;
|
||||
statsTag = makeTag(op, listenerTag, type);
|
||||
workSource = ws;
|
||||
this.flags = flags;
|
||||
alarmClock = info;
|
||||
this.uid = uid;
|
||||
packageName = pkgName;
|
||||
sourcePackage = (operation != null) ? operation.getCreatorPackage() : packageName;
|
||||
creatorUid = (operation != null) ? operation.getCreatorUid() : uid;
|
||||
creatorUid = (operation != null) ? operation.getCreatorUid() : this.uid;
|
||||
}
|
||||
|
||||
public static String makeTag(PendingIntent pi, String tag, int type) {
|
||||
@@ -91,13 +112,6 @@ class Alarm {
|
||||
return (pi != null) ? pi.getTag(alarmString) : (alarmString + tag);
|
||||
}
|
||||
|
||||
public AlarmManagerService.WakeupEvent makeWakeupEvent(long nowRTC) {
|
||||
return new AlarmManagerService.WakeupEvent(nowRTC, creatorUid,
|
||||
(operation != null)
|
||||
? operation.getIntent().getAction()
|
||||
: ("<listener>:" + listenerTag));
|
||||
}
|
||||
|
||||
// Returns true if either matches
|
||||
public boolean matches(PendingIntent pi, IAlarmListener rec) {
|
||||
return (operation != null)
|
||||
@@ -109,6 +123,65 @@ class Alarm {
|
||||
return packageName.equals(sourcePackage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the earliest time this alarm is allowed to expire based on the given policy.
|
||||
*
|
||||
* @param policyIndex The index of the policy. One of [{@link #REQUESTER_POLICY_INDEX},
|
||||
* {@link #APP_STANDBY_POLICY_INDEX}].
|
||||
*/
|
||||
public long getPolicyElapsed(int policyIndex) {
|
||||
return mPolicyWhenElapsed[policyIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the earliest time that this alarm should be delivered to the requesting app.
|
||||
*/
|
||||
public long getWhenElapsed() {
|
||||
return mWhenElapsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest time that this alarm should be delivered to the requesting app. Will be equal
|
||||
* to {@link #getWhenElapsed()} in case this is an exact alarm.
|
||||
*/
|
||||
public long getMaxWhenElapsed() {
|
||||
return mMaxWhenElapsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the earliest time this alarm can expire based on the passed policy index.
|
||||
*
|
||||
* @return {@code true} if this change resulted in a change in the ultimate delivery time (or
|
||||
* time window in the case of inexact alarms) of this alarm.
|
||||
* @see #getWhenElapsed()
|
||||
* @see #getMaxWhenElapsed()
|
||||
* @see #getPolicyElapsed(int)
|
||||
*/
|
||||
public boolean setPolicyElapsed(int policyIndex, long policyElapsed) {
|
||||
mPolicyWhenElapsed[policyIndex] = policyElapsed;
|
||||
return updateWhenElapsed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if either {@link #mWhenElapsed} or {@link #mMaxWhenElapsed} changes
|
||||
* due to this call.
|
||||
*/
|
||||
private boolean updateWhenElapsed() {
|
||||
final long oldWhenElapsed = mWhenElapsed;
|
||||
mWhenElapsed = 0;
|
||||
for (int i = 0; i < NUM_POLICIES; i++) {
|
||||
mWhenElapsed = Math.max(mWhenElapsed, mPolicyWhenElapsed[i]);
|
||||
}
|
||||
|
||||
final long oldMaxWhenElapsed = mMaxWhenElapsed;
|
||||
// windowLength should always be >= 0 here.
|
||||
final long maxRequestedElapsed = clampPositive(
|
||||
mPolicyWhenElapsed[REQUESTER_POLICY_INDEX] + windowLength);
|
||||
mMaxWhenElapsed = Math.max(maxRequestedElapsed, mWhenElapsed);
|
||||
|
||||
return (oldWhenElapsed != mWhenElapsed) || (oldMaxWhenElapsed != mMaxWhenElapsed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
@@ -116,11 +189,11 @@ class Alarm {
|
||||
sb.append(Integer.toHexString(System.identityHashCode(this)));
|
||||
sb.append(" type ");
|
||||
sb.append(type);
|
||||
sb.append(" when ");
|
||||
sb.append(when);
|
||||
sb.append(" origWhen ");
|
||||
sb.append(origWhen);
|
||||
sb.append(" ");
|
||||
sb.append(" whenElapsed ");
|
||||
sb.append(whenElapsed);
|
||||
sb.append(getWhenElapsed());
|
||||
sb.append(" ");
|
||||
sb.append(sourcePackage);
|
||||
sb.append('}');
|
||||
@@ -136,30 +209,46 @@ class Alarm {
|
||||
dump(ipw, nowELAPSED, sdf);
|
||||
}
|
||||
|
||||
private static String policyIndexToString(int index) {
|
||||
switch (index) {
|
||||
case REQUESTER_POLICY_INDEX:
|
||||
return "requester";
|
||||
case APP_STANDBY_POLICY_INDEX:
|
||||
return "app_standby";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
public static String typeToString(int type) {
|
||||
switch (type) {
|
||||
case RTC:
|
||||
return "RTC";
|
||||
case RTC_WAKEUP:
|
||||
return "RTC_WAKEUP";
|
||||
case ELAPSED_REALTIME:
|
||||
return "ELAPSED";
|
||||
case ELAPSED_REALTIME_WAKEUP:
|
||||
return "ELAPSED_WAKEUP";
|
||||
default:
|
||||
return "--unknown--";
|
||||
}
|
||||
}
|
||||
|
||||
public void dump(IndentingPrintWriter ipw, long nowELAPSED, SimpleDateFormat sdf) {
|
||||
final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
|
||||
ipw.print("tag=");
|
||||
ipw.println(statsTag);
|
||||
|
||||
ipw.print("type=");
|
||||
ipw.print(type);
|
||||
ipw.print(" expectedWhenElapsed=");
|
||||
TimeUtils.formatDuration(expectedWhenElapsed, nowELAPSED, ipw);
|
||||
ipw.print(" expectedMaxWhenElapsed=");
|
||||
TimeUtils.formatDuration(expectedMaxWhenElapsed, nowELAPSED, ipw);
|
||||
ipw.print(" whenElapsed=");
|
||||
TimeUtils.formatDuration(whenElapsed, nowELAPSED, ipw);
|
||||
ipw.print(" maxWhenElapsed=");
|
||||
TimeUtils.formatDuration(maxWhenElapsed, nowELAPSED, ipw);
|
||||
ipw.print(" when=");
|
||||
ipw.print(typeToString(type));
|
||||
ipw.print(" origWhen=");
|
||||
if (isRtc) {
|
||||
ipw.print(sdf.format(new Date(when)));
|
||||
ipw.print(sdf.format(new Date(origWhen)));
|
||||
} else {
|
||||
TimeUtils.formatDuration(when, nowELAPSED, ipw);
|
||||
TimeUtils.formatDuration(origWhen, nowELAPSED, ipw);
|
||||
}
|
||||
ipw.println();
|
||||
|
||||
ipw.print("window=");
|
||||
ipw.print(" window=");
|
||||
TimeUtils.formatDuration(windowLength, ipw);
|
||||
ipw.print(" repeatInterval=");
|
||||
ipw.print(repeatInterval);
|
||||
@@ -168,6 +257,19 @@ class Alarm {
|
||||
ipw.print(" flags=0x");
|
||||
ipw.println(Integer.toHexString(flags));
|
||||
|
||||
ipw.print("policyWhenElapsed:");
|
||||
for (int i = 0; i < NUM_POLICIES; i++) {
|
||||
ipw.print(" " + policyIndexToString(i) + "=");
|
||||
TimeUtils.formatDuration(mPolicyWhenElapsed[i], nowELAPSED, ipw);
|
||||
}
|
||||
ipw.println();
|
||||
|
||||
ipw.print("whenElapsed=");
|
||||
TimeUtils.formatDuration(getWhenElapsed(), nowELAPSED, ipw);
|
||||
ipw.print(" maxWhenElapsed=");
|
||||
TimeUtils.formatDuration(mMaxWhenElapsed, nowELAPSED, ipw);
|
||||
ipw.println();
|
||||
|
||||
if (alarmClock != null) {
|
||||
ipw.println("Alarm clock:");
|
||||
|
||||
@@ -177,9 +279,10 @@ class Alarm {
|
||||
ipw.print(" showIntent=");
|
||||
ipw.println(alarmClock.getShowIntent());
|
||||
}
|
||||
ipw.print("operation=");
|
||||
ipw.println(operation);
|
||||
|
||||
if (operation != null) {
|
||||
ipw.print("operation=");
|
||||
ipw.println(operation);
|
||||
}
|
||||
if (listener != null) {
|
||||
ipw.print("listener=");
|
||||
ipw.println(listener.asBinder());
|
||||
@@ -191,7 +294,7 @@ class Alarm {
|
||||
|
||||
proto.write(AlarmProto.TAG, statsTag);
|
||||
proto.write(AlarmProto.TYPE, type);
|
||||
proto.write(AlarmProto.TIME_UNTIL_WHEN_ELAPSED_MS, whenElapsed - nowElapsed);
|
||||
proto.write(AlarmProto.TIME_UNTIL_WHEN_ELAPSED_MS, getWhenElapsed() - nowElapsed);
|
||||
proto.write(AlarmProto.WINDOW_LENGTH_MS, windowLength);
|
||||
proto.write(AlarmProto.REPEAT_INTERVAL_MS, repeatInterval);
|
||||
proto.write(AlarmProto.COUNT, count);
|
||||
|
||||
@@ -26,6 +26,9 @@ 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.REQUESTER_POLICY_INDEX;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.Activity;
|
||||
@@ -727,9 +730,9 @@ public class AlarmManagerService extends SystemService {
|
||||
}
|
||||
|
||||
// within each class, sort by nominal delivery time
|
||||
if (lhs.whenElapsed < rhs.whenElapsed) {
|
||||
if (lhs.getWhenElapsed() < rhs.getWhenElapsed()) {
|
||||
return -1;
|
||||
} else if (lhs.whenElapsed > rhs.whenElapsed) {
|
||||
} else if (lhs.getWhenElapsed() > rhs.getWhenElapsed()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -798,9 +801,12 @@ public class AlarmManagerService extends SystemService {
|
||||
this(context, new Injector(context));
|
||||
}
|
||||
|
||||
private static boolean isRtc(int type) {
|
||||
return (type == RTC || type == RTC_WAKEUP);
|
||||
}
|
||||
|
||||
private long convertToElapsed(long when, int type) {
|
||||
final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
|
||||
if (isRtc) {
|
||||
if (isRtc(type)) {
|
||||
when -= mInjector.getCurrentTimeMillis() - mInjector.getElapsedRealtime();
|
||||
}
|
||||
return when;
|
||||
@@ -823,13 +829,29 @@ public class AlarmManagerService extends SystemService {
|
||||
}
|
||||
|
||||
// The RTC clock has moved arbitrarily, so we need to recalculate all the RTC alarm deliveries.
|
||||
void reevaluateRtcAlarms(final long nowElapsed) {
|
||||
void reevaluateRtcAlarms() {
|
||||
synchronized (mLock) {
|
||||
final ArrayList<Alarm> rtcAlarms = mAlarmStore.remove(a -> (a.type == RTC
|
||||
|| a.type == RTC_WAKEUP));
|
||||
for (final Alarm a : rtcAlarms) {
|
||||
restoreAlarmLocked(a, nowElapsed);
|
||||
setImplLocked(a);
|
||||
boolean changed = mAlarmStore.updateAlarmDeliveries(a -> {
|
||||
if (!isRtc(a.type)) {
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
return adjustIdleUntilTime(a);
|
||||
});
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
rescheduleKernelAlarmsLocked();
|
||||
// Only time shifted, so the next alarm clock will not change
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -844,7 +866,7 @@ public class AlarmManagerService extends SystemService {
|
||||
boolean reorderAlarmsBasedOnStandbyBuckets(ArraySet<Pair<String, Integer>> targetPackages) {
|
||||
final long start = mStatLogger.getTime();
|
||||
|
||||
final boolean changed = mAlarmStore.recalculateAlarmDeliveries(a -> {
|
||||
final boolean changed = mAlarmStore.updateAlarmDeliveries(a -> {
|
||||
final Pair<String, Integer> packageUser =
|
||||
Pair.create(a.sourcePackage, UserHandle.getUserId(a.creatorUid));
|
||||
if (targetPackages != null && !targetPackages.contains(packageUser)) {
|
||||
@@ -857,23 +879,8 @@ public class AlarmManagerService extends SystemService {
|
||||
return changed;
|
||||
}
|
||||
|
||||
private void restoreAlarmLocked(Alarm a, long nowElapsed) {
|
||||
a.when = a.origWhen;
|
||||
long whenElapsed = convertToElapsed(a.when, a.type);
|
||||
final long maxElapsed;
|
||||
if (a.windowLength == AlarmManager.WINDOW_EXACT) {
|
||||
// Exact
|
||||
maxElapsed = whenElapsed;
|
||||
} else {
|
||||
// Not exact. Preserve any explicit window, otherwise recalculate
|
||||
// the window based on the alarm's new futurity. Note that this
|
||||
// reflects a policy of preferring timely to deferred delivery.
|
||||
maxElapsed = (a.windowLength > 0)
|
||||
? clampPositive(whenElapsed + a.windowLength)
|
||||
: maxTriggerTime(nowElapsed, whenElapsed, a.repeatInterval);
|
||||
}
|
||||
a.expectedWhenElapsed = a.whenElapsed = whenElapsed;
|
||||
a.expectedMaxWhenElapsed = a.maxWhenElapsed = maxElapsed;
|
||||
private boolean restoreRequestedTime(Alarm a) {
|
||||
return a.setPolicyElapsed(REQUESTER_POLICY_INDEX, convertToElapsed(a.origWhen, a.type));
|
||||
}
|
||||
|
||||
static long clampPositive(long val) {
|
||||
@@ -973,14 +980,17 @@ 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.expectedWhenElapsed) / alarm.repeatInterval;
|
||||
alarm.count += (nowELAPSED - alarm.getPolicyElapsed(REQUESTER_POLICY_INDEX))
|
||||
/ alarm.repeatInterval;
|
||||
// Also schedule its next recurrence
|
||||
final long delta = alarm.count * alarm.repeatInterval;
|
||||
final long nextElapsed = alarm.expectedWhenElapsed + delta;
|
||||
setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
|
||||
maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
|
||||
alarm.repeatInterval, alarm.operation, null, null, alarm.flags,
|
||||
alarm.workSource, alarm.alarmClock, alarm.uid, alarm.packageName);
|
||||
final long nextElapsed = alarm.getPolicyElapsed(REQUESTER_POLICY_INDEX) + delta;
|
||||
final long nextMaxElapsed = maxTriggerTime(nowELAPSED, nextElapsed,
|
||||
alarm.repeatInterval);
|
||||
setImplLocked(alarm.type, alarm.origWhen + delta, nextElapsed,
|
||||
nextMaxElapsed - nextElapsed, alarm.repeatInterval, alarm.operation, null,
|
||||
null, alarm.flags, alarm.workSource, alarm.alarmClock, alarm.uid,
|
||||
alarm.packageName);
|
||||
// Kernel alarms will be rescheduled as needed in setImplLocked
|
||||
}
|
||||
}
|
||||
@@ -1026,18 +1036,10 @@ public class AlarmManagerService extends SystemService {
|
||||
if (mPendingWhileIdleAlarms.size() > 0) {
|
||||
ArrayList<Alarm> alarms = mPendingWhileIdleAlarms;
|
||||
mPendingWhileIdleAlarms = new ArrayList<>();
|
||||
final long nowElapsed = mInjector.getElapsedRealtime();
|
||||
for (int i = alarms.size() - 1; i >= 0; i--) {
|
||||
Alarm a = alarms.get(i);
|
||||
restoreAlarmLocked(a, nowElapsed);
|
||||
setImplLocked(a);
|
||||
setImplLocked(alarms.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
// Reschedule everything.
|
||||
rescheduleKernelAlarmsLocked();
|
||||
updateNextAlarmClockLocked();
|
||||
|
||||
}
|
||||
|
||||
static final class InFlight {
|
||||
@@ -1449,6 +1451,11 @@ public class AlarmManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & AlarmManager.FLAG_IDLE_UNTIL) != 0) {
|
||||
// Do not support windows for idle-until alarms.
|
||||
windowLength = AlarmManager.WINDOW_EXACT;
|
||||
}
|
||||
|
||||
// Sanity check the window length. This will catch people mistakenly
|
||||
// trying to pass an end-of-window timestamp rather than a duration.
|
||||
if (windowLength > AlarmManager.INTERVAL_HALF_DAY) {
|
||||
@@ -1515,17 +1522,17 @@ public class AlarmManagerService extends SystemService {
|
||||
Slog.w(TAG, errorMsg);
|
||||
throw new IllegalStateException(errorMsg);
|
||||
}
|
||||
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
|
||||
interval, operation, directReceiver, listenerTag, flags, workSource,
|
||||
alarmClock, callingUid, callingPackage);
|
||||
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, interval, operation,
|
||||
directReceiver, listenerTag, flags, workSource, alarmClock, callingUid,
|
||||
callingPackage);
|
||||
}
|
||||
}
|
||||
|
||||
private void setImplLocked(int type, long when, long whenElapsed, long windowLength,
|
||||
long maxWhen, long interval, PendingIntent operation, IAlarmListener directReceiver,
|
||||
long interval, PendingIntent operation, IAlarmListener directReceiver,
|
||||
String listenerTag, int flags, WorkSource workSource,
|
||||
AlarmManager.AlarmClockInfo alarmClock, int callingUid, String callingPackage) {
|
||||
Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval,
|
||||
final Alarm a = new Alarm(type, when, whenElapsed, windowLength, interval,
|
||||
operation, directReceiver, listenerTag, workSource, flags, alarmClock,
|
||||
callingUid, callingPackage);
|
||||
if (mActivityManagerInternal.isAppStartModeDisabled(callingUid, callingPackage)) {
|
||||
@@ -1560,72 +1567,55 @@ public class AlarmManagerService extends SystemService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the idle-until alarm delivery time based on the upcoming wake-from-idle alarm.
|
||||
* An alarm with {@link AlarmManager#FLAG_IDLE_UNTIL} is a special alarm that will put the
|
||||
* system into idle until it goes off. We need to pull it earlier if there are existing alarms
|
||||
* that have requested to bring us out of idle at an earlier time.
|
||||
*
|
||||
* @param alarm The alarm to adjust
|
||||
* @return true if the alarm delivery time was updated.
|
||||
*/
|
||||
private boolean adjustIdleUntilTime(Alarm alarm) {
|
||||
if ((alarm.flags & AlarmManager.FLAG_IDLE_UNTIL) != 0) {
|
||||
if ((alarm.flags & AlarmManager.FLAG_IDLE_UNTIL) == 0) {
|
||||
return false;
|
||||
}
|
||||
// This is a special alarm that will put the system into idle until it goes off.
|
||||
// The caller has given the time they want this to happen at, however we need
|
||||
// to pull that earlier if there are existing alarms that have requested to
|
||||
// bring us out of idle at an earlier time.
|
||||
if (mNextWakeFromIdle != null && alarm.whenElapsed > mNextWakeFromIdle.whenElapsed) {
|
||||
alarm.when = alarm.whenElapsed = alarm.maxWhenElapsed = mNextWakeFromIdle.whenElapsed;
|
||||
restoreRequestedTime(alarm);
|
||||
long triggerBeforeFuzz = alarm.getPolicyElapsed(REQUESTER_POLICY_INDEX);
|
||||
if (mNextWakeFromIdle != null && triggerBeforeFuzz > mNextWakeFromIdle.getWhenElapsed()) {
|
||||
triggerBeforeFuzz = mNextWakeFromIdle.getWhenElapsed();
|
||||
}
|
||||
// Add fuzz to make the alarm go off some time before the actual desired time.
|
||||
final long nowElapsed = mInjector.getElapsedRealtime();
|
||||
final int fuzz = fuzzForDuration(alarm.whenElapsed - nowElapsed);
|
||||
final int fuzz = fuzzForDuration(alarm.getWhenElapsed() - mInjector.getElapsedRealtime());
|
||||
final int delta;
|
||||
if (fuzz > 0) {
|
||||
if (mRandom == null) {
|
||||
mRandom = new Random();
|
||||
}
|
||||
final int delta = mRandom.nextInt(fuzz);
|
||||
alarm.whenElapsed -= delta;
|
||||
if (false) {
|
||||
Slog.d(TAG, "Alarm when: " + alarm.whenElapsed);
|
||||
Slog.d(TAG, "Delta until alarm: " + (alarm.whenElapsed - nowElapsed));
|
||||
Slog.d(TAG, "Applied fuzz: " + fuzz);
|
||||
Slog.d(TAG, "Final delta: " + delta);
|
||||
Slog.d(TAG, "Final when: " + alarm.whenElapsed);
|
||||
}
|
||||
alarm.when = alarm.maxWhenElapsed = alarm.whenElapsed;
|
||||
delta = mRandom.nextInt(fuzz);
|
||||
} else {
|
||||
delta = 0;
|
||||
}
|
||||
alarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, triggerBeforeFuzz - delta);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the alarm delivery time based on the current app standby bucket.
|
||||
* Adjusts the alarm's policy time for app_standby.
|
||||
*
|
||||
* @param alarm The alarm to adjust
|
||||
* @return true if the alarm delivery time was updated.
|
||||
* @param alarm The alarm to update.
|
||||
* @return {@code true} if the actual delivery time of the given alarm was updated due to
|
||||
* adjustments made in this call.
|
||||
*/
|
||||
private boolean adjustDeliveryTimeBasedOnBucketLocked(Alarm alarm) {
|
||||
if (isExemptFromAppStandby(alarm)) {
|
||||
return false;
|
||||
final long nowElapsed = mInjector.getElapsedRealtime();
|
||||
if (isExemptFromAppStandby(alarm) || mAppStandbyParole) {
|
||||
return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, nowElapsed);
|
||||
}
|
||||
if (mAppStandbyParole) {
|
||||
if (alarm.whenElapsed > alarm.expectedWhenElapsed) {
|
||||
// We did defer this alarm earlier, restore original requirements
|
||||
alarm.whenElapsed = alarm.expectedWhenElapsed;
|
||||
alarm.maxWhenElapsed = alarm.expectedMaxWhenElapsed;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
final long oldWhenElapsed = alarm.whenElapsed;
|
||||
final long oldMaxWhenElapsed = alarm.maxWhenElapsed;
|
||||
|
||||
final String sourcePackage = alarm.sourcePackage;
|
||||
final int sourceUserId = UserHandle.getUserId(alarm.creatorUid);
|
||||
final int standbyBucket = mUsageStatsManagerInternal.getAppStandbyBucket(
|
||||
sourcePackage, sourceUserId, mInjector.getElapsedRealtime());
|
||||
sourcePackage, sourceUserId, nowElapsed);
|
||||
|
||||
// Quota deferring implementation:
|
||||
boolean deferred = false;
|
||||
final int wakeupsInWindow = mAppWakeupHistory.getTotalWakeupsInWindow(sourcePackage,
|
||||
sourceUserId);
|
||||
if (standbyBucket == UsageStatsManager.STANDBY_BUCKET_RESTRICTED) {
|
||||
@@ -1635,14 +1625,9 @@ public class AlarmManagerService extends SystemService {
|
||||
if (wakeupsInWindow > 0) {
|
||||
final long lastWakeupTime = mAppWakeupHistory.getNthLastWakeupForPackage(
|
||||
sourcePackage, sourceUserId, mConstants.APP_STANDBY_RESTRICTED_QUOTA);
|
||||
if (mInjector.getElapsedRealtime() - lastWakeupTime
|
||||
< mConstants.APP_STANDBY_RESTRICTED_WINDOW) {
|
||||
final long minElapsed =
|
||||
lastWakeupTime + mConstants.APP_STANDBY_RESTRICTED_WINDOW;
|
||||
if (alarm.expectedWhenElapsed < minElapsed) {
|
||||
alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed;
|
||||
deferred = true;
|
||||
}
|
||||
if ((nowElapsed - lastWakeupTime) < mConstants.APP_STANDBY_RESTRICTED_WINDOW) {
|
||||
return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX,
|
||||
lastWakeupTime + mConstants.APP_STANDBY_RESTRICTED_WINDOW);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1651,7 +1636,7 @@ public class AlarmManagerService extends SystemService {
|
||||
final long minElapsed;
|
||||
if (quotaForBucket <= 0) {
|
||||
// Just keep deferring for a day till the quota changes
|
||||
minElapsed = mInjector.getElapsedRealtime() + MILLIS_IN_DAY;
|
||||
minElapsed = nowElapsed + MILLIS_IN_DAY;
|
||||
} else {
|
||||
// Suppose the quota for window was q, and the qth last delivery time for this
|
||||
// package was t(q) then the next delivery must be after t(q) + <window_size>
|
||||
@@ -1659,19 +1644,11 @@ public class AlarmManagerService extends SystemService {
|
||||
sourcePackage, sourceUserId, quotaForBucket);
|
||||
minElapsed = t + mConstants.APP_STANDBY_WINDOW;
|
||||
}
|
||||
if (alarm.expectedWhenElapsed < minElapsed) {
|
||||
alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed;
|
||||
deferred = true;
|
||||
}
|
||||
return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, minElapsed);
|
||||
}
|
||||
}
|
||||
if (!deferred) {
|
||||
// Restore original requirements in case they were changed earlier.
|
||||
alarm.whenElapsed = alarm.expectedWhenElapsed;
|
||||
alarm.maxWhenElapsed = alarm.expectedMaxWhenElapsed;
|
||||
}
|
||||
|
||||
return (oldWhenElapsed != alarm.whenElapsed || oldMaxWhenElapsed != alarm.maxWhenElapsed);
|
||||
// wakeupsInWindow are less than the permitted quota, hence no deferring is needed.
|
||||
return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, nowElapsed);
|
||||
}
|
||||
|
||||
private static boolean isAllowedWhileIdle(Alarm a) {
|
||||
@@ -1691,7 +1668,7 @@ public class AlarmManagerService extends SystemService {
|
||||
ent.tag = a.operation.getTag("");
|
||||
ent.op = "SET";
|
||||
ent.elapsedRealtime = mInjector.getElapsedRealtime();
|
||||
ent.argRealtime = a.whenElapsed;
|
||||
ent.argRealtime = a.getWhenElapsed();
|
||||
mAllowWhileIdleDispatches.add(ent);
|
||||
if (mPendingIdleUntil == null) {
|
||||
IdleDispatchEntry ent2 = new IdleDispatchEntry();
|
||||
@@ -1704,6 +1681,7 @@ public class AlarmManagerService extends SystemService {
|
||||
if ((mPendingIdleUntil != a) && (mPendingIdleUntil != null)) {
|
||||
Slog.wtfStack(TAG, "setImplLocked: idle until changed from " + mPendingIdleUntil
|
||||
+ " to " + a);
|
||||
mAlarmStore.remove(mPendingIdleUntil::equals);
|
||||
}
|
||||
mPendingIdleUntil = a;
|
||||
final ArrayList<Alarm> notAllowedWhileIdleAlarms = mAlarmStore.remove(
|
||||
@@ -1718,18 +1696,16 @@ public class AlarmManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
if ((a.flags & AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
|
||||
if (mNextWakeFromIdle == null || mNextWakeFromIdle.whenElapsed > a.whenElapsed) {
|
||||
if (mNextWakeFromIdle == null || mNextWakeFromIdle.getWhenElapsed()
|
||||
> a.getWhenElapsed()) {
|
||||
mNextWakeFromIdle = a;
|
||||
// If this wake from idle is earlier than whatever was previously scheduled,
|
||||
// and we are currently idling, then we need to rebatch alarms in case the idle
|
||||
// until time needs to be updated.
|
||||
// and we are currently idling, then the idle-until time needs to be updated.
|
||||
if (mPendingIdleUntil != null) {
|
||||
final long nowElapsed = mInjector.getElapsedRealtime();
|
||||
mAlarmStore.recalculateAlarmDeliveries(alarm -> {
|
||||
mAlarmStore.updateAlarmDeliveries(alarm -> {
|
||||
if (alarm != mPendingIdleUntil) {
|
||||
return false;
|
||||
}
|
||||
restoreAlarmLocked(alarm, nowElapsed);
|
||||
return adjustIdleUntilTime(alarm);
|
||||
});
|
||||
}
|
||||
@@ -2563,7 +2539,7 @@ public class AlarmManagerService extends SystemService {
|
||||
|
||||
long getNextWakeFromIdleTimeImpl() {
|
||||
synchronized (mLock) {
|
||||
return mNextWakeFromIdle != null ? mNextWakeFromIdle.whenElapsed : Long.MAX_VALUE;
|
||||
return mNextWakeFromIdle != null ? mNextWakeFromIdle.getWhenElapsed() : Long.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2784,12 +2760,11 @@ public class AlarmManagerService extends SystemService {
|
||||
restorePending = true;
|
||||
}
|
||||
if (mNextWakeFromIdle != null && mNextWakeFromIdle.matches(operation, directReceiver)) {
|
||||
mNextWakeFromIdle = null;
|
||||
mAlarmStore.recalculateAlarmDeliveries(alarm -> {
|
||||
mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
|
||||
mAlarmStore.updateAlarmDeliveries(alarm -> {
|
||||
if (alarm != mPendingIdleUntil) {
|
||||
return false;
|
||||
}
|
||||
restoreAlarmLocked(alarm, mInjector.getElapsedRealtime());
|
||||
return adjustIdleUntilTime(alarm);
|
||||
});
|
||||
}
|
||||
@@ -2834,15 +2809,14 @@ public class AlarmManagerService extends SystemService {
|
||||
mPendingBackgroundAlarms.removeAt(i);
|
||||
}
|
||||
}
|
||||
// If we're currently keying off of this app's alarms for doze transitions,
|
||||
// make sure to reset to other triggers.
|
||||
// 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 (mNextWakeFromIdle != null && mNextWakeFromIdle.uid == uid) {
|
||||
mNextWakeFromIdle = null;
|
||||
mAlarmStore.recalculateAlarmDeliveries(alarm -> {
|
||||
mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
|
||||
mAlarmStore.updateAlarmDeliveries(alarm -> {
|
||||
if (alarm != mPendingIdleUntil) {
|
||||
return false;
|
||||
}
|
||||
restoreAlarmLocked(alarm, mInjector.getElapsedRealtime());
|
||||
return adjustIdleUntilTime(alarm);
|
||||
});
|
||||
}
|
||||
@@ -2906,15 +2880,14 @@ public class AlarmManagerService extends SystemService {
|
||||
mPendingBackgroundAlarms.removeAt(i);
|
||||
}
|
||||
}
|
||||
// If we're currently keying off of this app's alarms for doze transitions,
|
||||
// make sure to reset to other triggers.
|
||||
// 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) {
|
||||
mNextWakeFromIdle = null;
|
||||
mAlarmStore.recalculateAlarmDeliveries(alarm -> {
|
||||
mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
|
||||
mAlarmStore.updateAlarmDeliveries(alarm -> {
|
||||
if (alarm != mPendingIdleUntil) {
|
||||
return false;
|
||||
}
|
||||
restoreAlarmLocked(alarm, mInjector.getElapsedRealtime());
|
||||
return adjustIdleUntilTime(alarm);
|
||||
});
|
||||
}
|
||||
@@ -3071,20 +3044,6 @@ public class AlarmManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
private static final String labelForType(int type) {
|
||||
switch (type) {
|
||||
case RTC:
|
||||
return "RTC";
|
||||
case RTC_WAKEUP:
|
||||
return "RTC_WAKEUP";
|
||||
case ELAPSED_REALTIME:
|
||||
return "ELAPSED";
|
||||
case ELAPSED_REALTIME_WAKEUP:
|
||||
return "ELAPSED_WAKEUP";
|
||||
}
|
||||
return "--unknown--";
|
||||
}
|
||||
|
||||
private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
|
||||
String prefix, long nowELAPSED, SimpleDateFormat sdf) {
|
||||
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, prefix, prefix);
|
||||
@@ -3095,7 +3054,7 @@ public class AlarmManagerService extends SystemService {
|
||||
long nowELAPSED, SimpleDateFormat sdf) {
|
||||
for (int i = list.size() - 1; i >= 0; i--) {
|
||||
final Alarm a = list.get(i);
|
||||
final String label = labelForType(a.type);
|
||||
final String label = Alarm.typeToString(a.type);
|
||||
ipw.print(label);
|
||||
ipw.print(" #");
|
||||
ipw.print(i);
|
||||
@@ -3125,6 +3084,9 @@ public class AlarmManagerService extends SystemService {
|
||||
}
|
||||
final String sourcePackage = alarm.sourcePackage;
|
||||
final int sourceUid = alarm.creatorUid;
|
||||
if (UserHandle.isCore(sourceUid)) {
|
||||
return false;
|
||||
}
|
||||
return (mAppStateTracker != null) &&
|
||||
mAppStateTracker.areAlarmsRestricted(sourceUid, sourcePackage,
|
||||
exemptOnBatterySaver);
|
||||
@@ -3169,11 +3131,7 @@ public class AlarmManagerService extends SystemService {
|
||||
// Whoops, it hasn't been long enough since the last ALLOW_WHILE_IDLE
|
||||
// alarm went off for this app. Reschedule the alarm to be in the
|
||||
// correct time period.
|
||||
alarm.expectedWhenElapsed = alarm.whenElapsed = minTime;
|
||||
if (alarm.maxWhenElapsed < minTime) {
|
||||
alarm.maxWhenElapsed = minTime;
|
||||
}
|
||||
alarm.expectedMaxWhenElapsed = alarm.maxWhenElapsed;
|
||||
alarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, minTime);
|
||||
if (RECORD_DEVICE_IDLE_ALARMS) {
|
||||
IdleDispatchEntry ent = new IdleDispatchEntry();
|
||||
ent.uid = alarm.uid;
|
||||
@@ -3213,12 +3171,11 @@ public class AlarmManagerService extends SystemService {
|
||||
restorePendingWhileIdleAlarmsLocked();
|
||||
}
|
||||
if (mNextWakeFromIdle == alarm) {
|
||||
mNextWakeFromIdle = null;
|
||||
mAlarmStore.recalculateAlarmDeliveries(a -> {
|
||||
mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
|
||||
mAlarmStore.updateAlarmDeliveries(a -> {
|
||||
if (a != mPendingIdleUntil) {
|
||||
return false;
|
||||
}
|
||||
restoreAlarmLocked(a, nowELAPSED);
|
||||
return adjustIdleUntilTime(a);
|
||||
});
|
||||
}
|
||||
@@ -3228,14 +3185,17 @@ 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.expectedWhenElapsed) / alarm.repeatInterval;
|
||||
alarm.count += (nowELAPSED - alarm.getPolicyElapsed(REQUESTER_POLICY_INDEX))
|
||||
/ alarm.repeatInterval;
|
||||
// Also schedule its next recurrence
|
||||
final long delta = alarm.count * alarm.repeatInterval;
|
||||
final long nextElapsed = alarm.expectedWhenElapsed + delta;
|
||||
setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
|
||||
maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
|
||||
alarm.repeatInterval, alarm.operation, null, null, alarm.flags,
|
||||
alarm.workSource, alarm.alarmClock, alarm.uid, alarm.packageName);
|
||||
final long nextElapsed = alarm.getPolicyElapsed(REQUESTER_POLICY_INDEX) + delta;
|
||||
final long nextMaxElapsed = maxTriggerTime(nowELAPSED, nextElapsed,
|
||||
alarm.repeatInterval);
|
||||
setImplLocked(alarm.type, alarm.origWhen + delta, nextElapsed,
|
||||
nextMaxElapsed - nextElapsed, alarm.repeatInterval, alarm.operation, null,
|
||||
null, alarm.flags, alarm.workSource, alarm.alarmClock, alarm.uid,
|
||||
alarm.packageName);
|
||||
}
|
||||
|
||||
if (alarm.wakeup) {
|
||||
@@ -3277,7 +3237,7 @@ public class AlarmManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
static int fuzzForDuration(long duration) {
|
||||
int fuzzForDuration(long duration) {
|
||||
if (duration < 15 * 60 * 1000) {
|
||||
// If the duration until the time is less than 15 minutes, the maximum fuzz
|
||||
// is the duration.
|
||||
@@ -3480,7 +3440,7 @@ public class AlarmManagerService extends SystemService {
|
||||
FrameworkStatsLog.write(FrameworkStatsLog.WALL_CLOCK_TIME_SHIFTED, nowRTC);
|
||||
removeImpl(null, mTimeTickTrigger);
|
||||
removeImpl(mDateChangeSender, null);
|
||||
reevaluateRtcAlarms(nowELAPSED);
|
||||
reevaluateRtcAlarms();
|
||||
mClockReceiver.scheduleTimeTickEvent();
|
||||
mClockReceiver.scheduleDateChangedEvent();
|
||||
synchronized (mLock) {
|
||||
|
||||
@@ -47,6 +47,15 @@ public interface AlarmStore {
|
||||
*/
|
||||
ArrayList<Alarm> remove(Predicate<Alarm> whichAlarms);
|
||||
|
||||
/**
|
||||
* Gets the earliest alarm with the flag {@link android.app.AlarmManager#FLAG_WAKE_FROM_IDLE}
|
||||
* based on {@link Alarm#getWhenElapsed()}.
|
||||
*
|
||||
* @return An alarm object matching the description above or {@code null} if no such alarm was
|
||||
* found.
|
||||
*/
|
||||
Alarm getNextWakeFromIdleAlarm();
|
||||
|
||||
/**
|
||||
* Returns the total number of alarms in this store.
|
||||
*/
|
||||
@@ -71,7 +80,7 @@ public interface AlarmStore {
|
||||
/**
|
||||
* Removes all alarms that are pending delivery at the given time.
|
||||
*
|
||||
* @param nowElapsed The time at which delivery eligibility is evaluated.
|
||||
* @param nowElapsed The time at which delivery eligibility is evaluated.
|
||||
* @return The list of alarms pending at the given time.
|
||||
*/
|
||||
ArrayList<Alarm> removePendingAlarms(long nowElapsed);
|
||||
@@ -82,7 +91,7 @@ public interface AlarmStore {
|
||||
*
|
||||
* @return {@code true} if any of the alarm deliveries changed due to this call.
|
||||
*/
|
||||
boolean recalculateAlarmDeliveries(AlarmDeliveryCalculator deliveryCalculator);
|
||||
boolean updateAlarmDeliveries(AlarmDeliveryCalculator deliveryCalculator);
|
||||
|
||||
/**
|
||||
* Returns all the alarms in the form of a list.
|
||||
@@ -97,6 +106,7 @@ public interface AlarmStore {
|
||||
* Primary useful for debugging. Can be called from the
|
||||
* {@link android.os.Binder#dump(FileDescriptor PrintWriter, String[]) dump} method of the
|
||||
* caller.
|
||||
*
|
||||
* @param ipw The {@link IndentingPrintWriter} to write to.
|
||||
* @param nowElapsed the time when the dump is requested in the
|
||||
* {@link SystemClock#elapsedRealtime()
|
||||
@@ -112,7 +122,7 @@ public interface AlarmStore {
|
||||
|
||||
/**
|
||||
* A functional interface used to update the alarm. Used to describe the update in
|
||||
* {@link #recalculateAlarmDeliveries(AlarmDeliveryCalculator)}
|
||||
* {@link #updateAlarmDeliveries(AlarmDeliveryCalculator)}
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface AlarmDeliveryCalculator {
|
||||
@@ -125,3 +135,4 @@ public interface AlarmStore {
|
||||
boolean updateAlarmDelivery(Alarm a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,8 +66,8 @@ public class BatchingAlarmStore implements AlarmStore {
|
||||
};
|
||||
|
||||
private static final Comparator<Alarm> sIncreasingTimeOrder = (a1, a2) -> {
|
||||
long when1 = a1.whenElapsed;
|
||||
long when2 = a2.whenElapsed;
|
||||
long when1 = a1.getWhenElapsed();
|
||||
long when2 = a2.getWhenElapsed();
|
||||
if (when1 > when2) {
|
||||
return 1;
|
||||
}
|
||||
@@ -99,11 +99,28 @@ public class BatchingAlarmStore implements AlarmStore {
|
||||
}
|
||||
if (!removed.isEmpty()) {
|
||||
mSize -= removed.size();
|
||||
// Not needed if only whole batches were removed, but keeping existing behavior.
|
||||
rebatchAllAlarms();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alarm getNextWakeFromIdleAlarm() {
|
||||
for (final Batch batch : mAlarmBatches) {
|
||||
if ((batch.mFlags & AlarmManager.FLAG_WAKE_FROM_IDLE) == 0) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < batch.size(); i++) {
|
||||
final Alarm a = batch.get(i);
|
||||
if ((a.flags & AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void rebatchAllAlarms() {
|
||||
final long start = mStatLogger.getTime();
|
||||
final ArrayList<Batch> oldBatches = (ArrayList<Batch>) mAlarmBatches.clone();
|
||||
@@ -157,7 +174,7 @@ public class BatchingAlarmStore implements AlarmStore {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean recalculateAlarmDeliveries(AlarmDeliveryCalculator deliveryCalculator) {
|
||||
public boolean updateAlarmDeliveries(AlarmDeliveryCalculator deliveryCalculator) {
|
||||
boolean changed = false;
|
||||
for (final Batch b : mAlarmBatches) {
|
||||
for (int i = 0; i < b.size(); i++) {
|
||||
@@ -204,7 +221,7 @@ public class BatchingAlarmStore implements AlarmStore {
|
||||
|
||||
private void insertAndBatchAlarm(Alarm alarm) {
|
||||
final int whichBatch = ((alarm.flags & AlarmManager.FLAG_STANDALONE) != 0) ? -1
|
||||
: attemptCoalesce(alarm.whenElapsed, alarm.maxWhenElapsed);
|
||||
: attemptCoalesce(alarm.getWhenElapsed(), alarm.getMaxWhenElapsed());
|
||||
|
||||
if (whichBatch < 0) {
|
||||
addBatch(mAlarmBatches, new Batch(alarm));
|
||||
@@ -247,8 +264,8 @@ public class BatchingAlarmStore implements AlarmStore {
|
||||
final ArrayList<Alarm> mAlarms = new ArrayList<>();
|
||||
|
||||
Batch(Alarm seed) {
|
||||
mStart = seed.whenElapsed;
|
||||
mEnd = clampPositive(seed.maxWhenElapsed);
|
||||
mStart = seed.getWhenElapsed();
|
||||
mEnd = clampPositive(seed.getMaxWhenElapsed());
|
||||
mFlags = seed.flags;
|
||||
mAlarms.add(seed);
|
||||
}
|
||||
@@ -276,12 +293,12 @@ public class BatchingAlarmStore implements AlarmStore {
|
||||
if (DEBUG_BATCH) {
|
||||
Slog.v(TAG, "Adding " + alarm + " to " + this);
|
||||
}
|
||||
if (alarm.whenElapsed > mStart) {
|
||||
mStart = alarm.whenElapsed;
|
||||
if (alarm.getWhenElapsed() > mStart) {
|
||||
mStart = alarm.getWhenElapsed();
|
||||
newStart = true;
|
||||
}
|
||||
if (alarm.maxWhenElapsed < mEnd) {
|
||||
mEnd = alarm.maxWhenElapsed;
|
||||
if (alarm.getMaxWhenElapsed() < mEnd) {
|
||||
mEnd = alarm.getMaxWhenElapsed();
|
||||
}
|
||||
mFlags |= alarm.flags;
|
||||
|
||||
@@ -309,11 +326,11 @@ public class BatchingAlarmStore implements AlarmStore {
|
||||
Slog.wtf(TAG, "Removed TIME_TICK alarm");
|
||||
}
|
||||
} else {
|
||||
if (alarm.whenElapsed > newStart) {
|
||||
newStart = alarm.whenElapsed;
|
||||
if (alarm.getWhenElapsed() > newStart) {
|
||||
newStart = alarm.getWhenElapsed();
|
||||
}
|
||||
if (alarm.maxWhenElapsed < newEnd) {
|
||||
newEnd = alarm.maxWhenElapsed;
|
||||
if (alarm.getMaxWhenElapsed() < newEnd) {
|
||||
newEnd = alarm.getMaxWhenElapsed();
|
||||
}
|
||||
newFlags |= alarm.flags;
|
||||
i++;
|
||||
|
||||
@@ -48,10 +48,13 @@ import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MIN_INT
|
||||
import static com.android.server.alarm.AlarmManagerService.IS_WAKEUP_MASK;
|
||||
import static com.android.server.alarm.AlarmManagerService.TIME_CHANGED_MASK;
|
||||
import static com.android.server.alarm.AlarmManagerService.WORKING_INDEX;
|
||||
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.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
@@ -82,6 +85,7 @@ 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;
|
||||
|
||||
@@ -108,6 +112,8 @@ 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;
|
||||
@@ -116,9 +122,7 @@ import java.util.concurrent.Executor;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AlarmManagerServiceTest {
|
||||
private static final String TAG = AlarmManagerServiceTest.class.getSimpleName();
|
||||
private static final String TEST_CALLING_PACKAGE = "com.android.framework.test-package";
|
||||
private static final int SYSTEM_UI_UID = 12345;
|
||||
private static final int TEST_CALLING_UID = 67890;
|
||||
private static final int TEST_CALLING_USER = UserHandle.getUserId(TEST_CALLING_UID);
|
||||
|
||||
private long mAppStandbyWindow;
|
||||
@@ -350,19 +354,31 @@ public class AlarmManagerServiceTest {
|
||||
}
|
||||
|
||||
private void setTestAlarm(int type, long triggerTime, PendingIntent operation) {
|
||||
setTestAlarm(type, triggerTime, operation, 0, TEST_CALLING_UID);
|
||||
setTestAlarm(type, triggerTime, operation, 0, AlarmManager.FLAG_STANDALONE,
|
||||
TEST_CALLING_UID);
|
||||
}
|
||||
|
||||
private void setRepeatingTestAlarm(int type, long firstTrigger, long interval,
|
||||
PendingIntent pi) {
|
||||
setTestAlarm(type, firstTrigger, pi, interval, TEST_CALLING_UID);
|
||||
setTestAlarm(type, firstTrigger, pi, interval, AlarmManager.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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private void setTestAlarm(int type, long triggerTime, PendingIntent operation, long interval,
|
||||
int callingUid) {
|
||||
mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, interval,
|
||||
operation, null, "test", AlarmManager.FLAG_STANDALONE, null, null,
|
||||
callingUid, TEST_CALLING_PACKAGE);
|
||||
int flags, int callingUid) {
|
||||
mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, interval, operation, null,
|
||||
"test", flags, null, null, callingUid, TEST_CALLING_PACKAGE);
|
||||
}
|
||||
|
||||
private void setTestAlarmWithListener(int type, long triggerTime, IAlarmListener listener) {
|
||||
@@ -1002,7 +1018,7 @@ 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, mockUid);
|
||||
getNewMockPendingIntent(mockUid), 0, AlarmManager.FLAG_STANDALONE, mockUid);
|
||||
}
|
||||
assertEquals(numAlarms, mService.mAlarmsPerUid.size());
|
||||
mService.removeUserLocked(mockUserId);
|
||||
@@ -1142,6 +1158,116 @@ public class AlarmManagerServiceTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleIdleUntil() {
|
||||
doReturn(0).when(mService).fuzzForDuration(anyLong());
|
||||
|
||||
final PendingIntent idleUntilPi6 = getNewMockPendingIntent();
|
||||
setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, idleUntilPi6);
|
||||
|
||||
assertTrue(mService.mPendingIdleUntil.matches(idleUntilPi6, null));
|
||||
assertEquals(mNowElapsedTest + 6, mTestTimer.getElapsed());
|
||||
assertEquals(mNowElapsedTest + 6, mService.mPendingIdleUntil.getWhenElapsed());
|
||||
|
||||
final PendingIntent idleUntilPi2 = getNewMockPendingIntent();
|
||||
setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 2, idleUntilPi2);
|
||||
|
||||
// The same mPendingIdleUntil should get updated, even with a different PendingIntent.
|
||||
assertTrue(mService.mPendingIdleUntil.matches(idleUntilPi2, null));
|
||||
assertEquals(mNowElapsedTest + 2, mTestTimer.getElapsed());
|
||||
assertEquals(1, mService.mAlarmStore.size());
|
||||
|
||||
final PendingIntent idleUntilPi10 = getNewMockPendingIntent();
|
||||
setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 10, idleUntilPi10);
|
||||
|
||||
// The same thing should happen even when the new alarm is in farther in the future.
|
||||
assertTrue(mService.mPendingIdleUntil.matches(idleUntilPi10, null));
|
||||
assertEquals(mNowElapsedTest + 10, mTestTimer.getElapsed());
|
||||
assertEquals(1, mService.mAlarmStore.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nextWakeFromIdle() throws Exception {
|
||||
assertNull(mService.mNextWakeFromIdle);
|
||||
|
||||
final PendingIntent wakeFromIdle6 = getNewMockPendingIntent();
|
||||
final long trigger6 = mNowElapsedTest + 6;
|
||||
setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, trigger6, wakeFromIdle6);
|
||||
|
||||
assertTrue(mService.mNextWakeFromIdle.matches(wakeFromIdle6, null));
|
||||
assertEquals(trigger6, mService.mNextWakeFromIdle.getWhenElapsed());
|
||||
assertEquals(trigger6, mTestTimer.getElapsed());
|
||||
|
||||
final PendingIntent wakeFromIdle10 = getNewMockPendingIntent();
|
||||
final long trigger10 = mNowElapsedTest + 10;
|
||||
setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, trigger10, wakeFromIdle10);
|
||||
|
||||
// mNextWakeFromIdle should not get updated.
|
||||
assertTrue(mService.mNextWakeFromIdle.matches(wakeFromIdle6, null));
|
||||
assertEquals(trigger6, mTestTimer.getElapsed());
|
||||
assertEquals(trigger6, mService.mNextWakeFromIdle.getWhenElapsed());
|
||||
|
||||
final PendingIntent wakeFromIdle3 = getNewMockPendingIntent();
|
||||
final long trigger3 = mNowElapsedTest + 3;
|
||||
setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, trigger3, wakeFromIdle3);
|
||||
|
||||
// mNextWakeFromIdle should always reflect the next earliest wake_from_idle alarm.
|
||||
assertTrue(mService.mNextWakeFromIdle.matches(wakeFromIdle3, null));
|
||||
assertEquals(trigger3, mTestTimer.getElapsed());
|
||||
assertEquals(trigger3, mService.mNextWakeFromIdle.getWhenElapsed());
|
||||
|
||||
mNowElapsedTest = trigger3;
|
||||
mTestTimer.expire();
|
||||
|
||||
assertTrue(mService.mNextWakeFromIdle.matches(wakeFromIdle6, null));
|
||||
assertEquals(trigger6, mTestTimer.getElapsed());
|
||||
assertEquals(trigger6, mService.mNextWakeFromIdle.getWhenElapsed());
|
||||
|
||||
mService.removeLocked(wakeFromIdle6, null);
|
||||
|
||||
assertTrue(mService.mNextWakeFromIdle.matches(wakeFromIdle10, null));
|
||||
assertEquals(trigger10, mTestTimer.getElapsed());
|
||||
assertEquals(trigger10, mService.mNextWakeFromIdle.getWhenElapsed());
|
||||
|
||||
mService.removeLocked(wakeFromIdle10, null);
|
||||
assertNull(mService.mNextWakeFromIdle);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void idleUntilBeforeWakeFromIdle() {
|
||||
doReturn(0).when(mService).fuzzForDuration(anyLong());
|
||||
|
||||
final PendingIntent idleUntilPi = getNewMockPendingIntent();
|
||||
final long requestedIdleUntil = mNowElapsedTest + 10;
|
||||
setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, requestedIdleUntil, idleUntilPi);
|
||||
|
||||
assertEquals(requestedIdleUntil, mService.mPendingIdleUntil.getWhenElapsed());
|
||||
|
||||
final PendingIntent wakeFromIdle5 = getNewMockPendingIntent();
|
||||
setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, wakeFromIdle5);
|
||||
assertEquals(mNowElapsedTest + 5, mService.mPendingIdleUntil.getWhenElapsed());
|
||||
|
||||
final PendingIntent wakeFromIdle8 = getNewMockPendingIntent();
|
||||
setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 8, wakeFromIdle8);
|
||||
assertEquals(mNowElapsedTest + 5, mService.mPendingIdleUntil.getWhenElapsed());
|
||||
|
||||
final PendingIntent wakeFromIdle12 = getNewMockPendingIntent();
|
||||
setWakeFromIdle(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 12, wakeFromIdle12);
|
||||
assertEquals(mNowElapsedTest + 5, mService.mPendingIdleUntil.getWhenElapsed());
|
||||
|
||||
mService.removeLocked(wakeFromIdle5, null);
|
||||
assertEquals(mNowElapsedTest + 8, mService.mPendingIdleUntil.getWhenElapsed());
|
||||
|
||||
mService.removeLocked(wakeFromIdle8, null);
|
||||
assertEquals(requestedIdleUntil, mService.mPendingIdleUntil.getWhenElapsed());
|
||||
|
||||
mService.removeLocked(idleUntilPi, null);
|
||||
assertNull(mService.mPendingIdleUntil);
|
||||
|
||||
setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 15, idleUntilPi);
|
||||
assertEquals(mNowElapsedTest + 12, mService.mPendingIdleUntil.getWhenElapsed());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mMockingSession != null) {
|
||||
@@ -1149,4 +1275,12 @@ 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.server.alarm;
|
||||
|
||||
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.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -35,9 +38,6 @@ import java.util.ArrayList;
|
||||
@Presubmit
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AlarmStoreTest {
|
||||
private static final int TEST_CALLING_UID = 12345;
|
||||
private static final String TEST_CALLING_PACKAGE = "android.alarm.unit.test";
|
||||
|
||||
private AlarmStore mAlarmStore;
|
||||
|
||||
@Before
|
||||
@@ -45,22 +45,22 @@ public class AlarmStoreTest {
|
||||
mAlarmStore = new BatchingAlarmStore(null);
|
||||
}
|
||||
|
||||
private static Alarm createAlarm(long whenElapsed, long windowLength, PendingIntent mockPi,
|
||||
private static Alarm createAlarm(long whenElapsed, long windowLength,
|
||||
AlarmManager.AlarmClockInfo alarmClock) {
|
||||
return createAlarm(AlarmManager.ELAPSED_REALTIME, whenElapsed, windowLength, mockPi,
|
||||
return createAlarm(AlarmManager.ELAPSED_REALTIME, whenElapsed, windowLength,
|
||||
alarmClock);
|
||||
}
|
||||
|
||||
private static Alarm createWakeupAlarm(long whenElapsed, long windowLength,
|
||||
PendingIntent mockPi, AlarmManager.AlarmClockInfo alarmClock) {
|
||||
return createAlarm(AlarmManager.ELAPSED_REALTIME_WAKEUP, whenElapsed, windowLength, mockPi,
|
||||
AlarmManager.AlarmClockInfo alarmClock) {
|
||||
return createAlarm(AlarmManager.ELAPSED_REALTIME_WAKEUP, whenElapsed, windowLength,
|
||||
alarmClock);
|
||||
}
|
||||
|
||||
private static Alarm createAlarm(int type, long whenElapsed, long windowLength,
|
||||
PendingIntent mockPi, AlarmManager.AlarmClockInfo alarmClock) {
|
||||
return new Alarm(type, whenElapsed, whenElapsed, windowLength, whenElapsed + windowLength,
|
||||
0, mockPi, null, null, null, 0, alarmClock, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
|
||||
AlarmManager.AlarmClockInfo alarmClock) {
|
||||
return new Alarm(type, whenElapsed, whenElapsed, windowLength, 0, mock(PendingIntent.class),
|
||||
null, null, null, 0, alarmClock, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
|
||||
}
|
||||
|
||||
private void addAlarmsToStore(Alarm... alarms) {
|
||||
@@ -71,11 +71,11 @@ public class AlarmStoreTest {
|
||||
|
||||
@Test
|
||||
public void add() {
|
||||
final Alarm a1 = createAlarm(1, 0, mock(PendingIntent.class), null);
|
||||
final Alarm a1 = createAlarm(1, 0, null);
|
||||
mAlarmStore.add(a1);
|
||||
assertEquals(1, mAlarmStore.size());
|
||||
|
||||
final Alarm a2 = createAlarm(2, 0, mock(PendingIntent.class), null);
|
||||
final Alarm a2 = createAlarm(2, 0, null);
|
||||
mAlarmStore.add(a2);
|
||||
assertEquals(2, mAlarmStore.size());
|
||||
|
||||
@@ -86,17 +86,17 @@ public class AlarmStoreTest {
|
||||
|
||||
@Test
|
||||
public void remove() {
|
||||
final Alarm a1 = createAlarm(1, 0, mock(PendingIntent.class), null);
|
||||
final Alarm a2 = createAlarm(2, 0, mock(PendingIntent.class), null);
|
||||
final Alarm a5 = createAlarm(5, 0, mock(PendingIntent.class), null);
|
||||
final Alarm a1 = createAlarm(1, 0, null);
|
||||
final Alarm a2 = createAlarm(2, 0, null);
|
||||
final Alarm a5 = createAlarm(5, 0, null);
|
||||
addAlarmsToStore(a1, a2, a5);
|
||||
|
||||
ArrayList<Alarm> removed = mAlarmStore.remove(a -> (a.whenElapsed < 4));
|
||||
ArrayList<Alarm> removed = mAlarmStore.remove(a -> (a.getWhenElapsed() < 4));
|
||||
assertEquals(2, removed.size());
|
||||
assertEquals(1, mAlarmStore.size());
|
||||
assertTrue(removed.contains(a1) && removed.contains(a2));
|
||||
|
||||
final Alarm a8 = createAlarm(8, 0, mock(PendingIntent.class), null);
|
||||
final Alarm a8 = createAlarm(8, 0, null);
|
||||
addAlarmsToStore(a8, a2, a1);
|
||||
|
||||
removed = mAlarmStore.remove(unused -> false);
|
||||
@@ -110,10 +110,10 @@ public class AlarmStoreTest {
|
||||
|
||||
@Test
|
||||
public void removePendingAlarms() {
|
||||
final Alarm a1_11 = createAlarm(1, 10, mock(PendingIntent.class), null);
|
||||
final Alarm a2_5 = createAlarm(2, 3, mock(PendingIntent.class), null);
|
||||
final Alarm a6_9 = createAlarm(6, 3, mock(PendingIntent.class), null);
|
||||
addAlarmsToStore(a2_5, a6_9, a1_11);
|
||||
final Alarm a1to11 = createAlarm(1, 10, null);
|
||||
final Alarm a2to5 = createAlarm(2, 3, null);
|
||||
final Alarm a6to9 = createAlarm(6, 3, null);
|
||||
addAlarmsToStore(a2to5, a6to9, a1to11);
|
||||
|
||||
final ArrayList<Alarm> pendingAt0 = mAlarmStore.removePendingAlarms(0);
|
||||
assertEquals(0, pendingAt0.size());
|
||||
@@ -121,24 +121,24 @@ public class AlarmStoreTest {
|
||||
|
||||
final ArrayList<Alarm> pendingAt3 = mAlarmStore.removePendingAlarms(3);
|
||||
assertEquals(2, pendingAt3.size());
|
||||
assertTrue(pendingAt3.contains(a1_11) && pendingAt3.contains(a2_5));
|
||||
assertTrue(pendingAt3.contains(a1to11) && pendingAt3.contains(a2to5));
|
||||
assertEquals(1, mAlarmStore.size());
|
||||
|
||||
addAlarmsToStore(a2_5, a1_11);
|
||||
addAlarmsToStore(a2to5, a1to11);
|
||||
final ArrayList<Alarm> pendingAt7 = mAlarmStore.removePendingAlarms(7);
|
||||
assertEquals(3, pendingAt7.size());
|
||||
assertTrue(pendingAt7.contains(a1_11) && pendingAt7.contains(a2_5) && pendingAt7.contains(
|
||||
a6_9));
|
||||
assertTrue(pendingAt7.contains(a1to11) && pendingAt7.contains(a2to5) && pendingAt7.contains(
|
||||
a6to9));
|
||||
assertEquals(0, mAlarmStore.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNextWakeupDeliveryTime() {
|
||||
final Alarm a1_10 = createAlarm(1, 9, mock(PendingIntent.class), null);
|
||||
final Alarm a3_8_wakeup = createWakeupAlarm(3, 5, mock(PendingIntent.class), null);
|
||||
final Alarm a6_wakeup = createWakeupAlarm(6, 0, mock(PendingIntent.class), null);
|
||||
final Alarm a5 = createAlarm(5, 0, mock(PendingIntent.class), null);
|
||||
addAlarmsToStore(a5, a6_wakeup, a3_8_wakeup, a1_10);
|
||||
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);
|
||||
addAlarmsToStore(a5, a6wakeup, a3to8wakeup, a1to10);
|
||||
|
||||
// The wakeup alarms are [6] and [3, 8], hence 6 is the latest time till when we can
|
||||
// defer delivering any wakeup alarm.
|
||||
@@ -155,11 +155,11 @@ public class AlarmStoreTest {
|
||||
|
||||
@Test
|
||||
public void getNextDeliveryTime() {
|
||||
final Alarm a1_10 = createAlarm(1, 9, mock(PendingIntent.class), null);
|
||||
final Alarm a3_8_wakeup = createWakeupAlarm(3, 5, mock(PendingIntent.class), null);
|
||||
final Alarm a6_wakeup = createWakeupAlarm(6, 0, mock(PendingIntent.class), null);
|
||||
final Alarm a5 = createAlarm(5, 0, mock(PendingIntent.class), null);
|
||||
addAlarmsToStore(a5, a6_wakeup, a3_8_wakeup, a1_10);
|
||||
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);
|
||||
addAlarmsToStore(a5, a6wakeup, a3to8wakeup, a1to10);
|
||||
|
||||
assertTrue(mAlarmStore.getNextDeliveryTime() <= 5);
|
||||
|
||||
@@ -168,24 +168,22 @@ public class AlarmStoreTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void recalculateAlarmDeliveries() {
|
||||
final Alarm a5 = createAlarm(5, 0, mock(PendingIntent.class), null);
|
||||
final Alarm a8 = createAlarm(8, 0, mock(PendingIntent.class), null);
|
||||
final Alarm a10 = createAlarm(10, 0, mock(PendingIntent.class), null);
|
||||
public void updateAlarmDeliveries() {
|
||||
final Alarm a5 = createAlarm(5, 0, null);
|
||||
final Alarm a8 = createAlarm(8, 0, null);
|
||||
final Alarm a10 = createAlarm(10, 0, null);
|
||||
addAlarmsToStore(a8, a10, a5);
|
||||
|
||||
assertEquals(5, mAlarmStore.getNextDeliveryTime());
|
||||
|
||||
mAlarmStore.recalculateAlarmDeliveries(a -> {
|
||||
a.whenElapsed += 3;
|
||||
a.maxWhenElapsed = a.whenElapsed;
|
||||
mAlarmStore.updateAlarmDeliveries(a -> {
|
||||
a.setPolicyElapsed(Alarm.REQUESTER_POLICY_INDEX, a.getWhenElapsed() + 3);
|
||||
return true;
|
||||
});
|
||||
assertEquals(8, mAlarmStore.getNextDeliveryTime());
|
||||
|
||||
mAlarmStore.recalculateAlarmDeliveries(a -> {
|
||||
a.whenElapsed = 20 - a.whenElapsed;
|
||||
a.maxWhenElapsed = a.whenElapsed;
|
||||
mAlarmStore.updateAlarmDeliveries(a -> {
|
||||
a.setPolicyElapsed(Alarm.REQUESTER_POLICY_INDEX, 20 - a.getWhenElapsed());
|
||||
return true;
|
||||
});
|
||||
assertEquals(7, mAlarmStore.getNextDeliveryTime());
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
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.REQUESTER_POLICY_INDEX;
|
||||
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.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@Presubmit
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AlarmTest {
|
||||
|
||||
private Alarm createDefaultAlarm(long requestedElapsed, long windowLength) {
|
||||
return new Alarm(ELAPSED_REALTIME, 0, requestedElapsed, windowLength, 0,
|
||||
mock(PendingIntent.class), null, null, null, 0, null, TEST_CALLING_UID,
|
||||
TEST_CALLING_PACKAGE);
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
|
||||
@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());
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void maxWhenElapsed() {
|
||||
final Alarm a = createDefaultAlarm(10, 12);
|
||||
assertEquals(22, a.getMaxWhenElapsed());
|
||||
|
||||
a.setPolicyElapsed(REQUESTER_POLICY_INDEX, 15);
|
||||
assertEquals(27, a.getMaxWhenElapsed());
|
||||
|
||||
a.setPolicyElapsed(REQUESTER_POLICY_INDEX, 2);
|
||||
assertEquals(14, a.getMaxWhenElapsed());
|
||||
|
||||
a.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 5);
|
||||
assertEquals(14, a.getMaxWhenElapsed());
|
||||
|
||||
a.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 16);
|
||||
assertEquals(16, a.getMaxWhenElapsed());
|
||||
|
||||
a.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 12);
|
||||
assertEquals(14, a.getMaxWhenElapsed());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPolicyElapsed() {
|
||||
final Alarm exactAlarm = createDefaultAlarm(10, 0);
|
||||
|
||||
assertTrue(exactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 4));
|
||||
assertTrue(exactAlarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 10));
|
||||
|
||||
assertFalse(exactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 8));
|
||||
assertFalse(exactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 10));
|
||||
assertFalse(exactAlarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 8));
|
||||
|
||||
assertTrue(exactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 7));
|
||||
|
||||
final Alarm inexactAlarm = createDefaultAlarm(10, 5);
|
||||
|
||||
assertTrue(inexactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 4));
|
||||
assertTrue(inexactAlarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 10));
|
||||
|
||||
// whenElapsed won't change, but maxWhenElapsed will.
|
||||
assertTrue(inexactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 8));
|
||||
assertTrue(inexactAlarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, 10));
|
||||
|
||||
assertFalse(inexactAlarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, 8));
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ public class BackgroundRestrictedAlarmsTest {
|
||||
}
|
||||
uidAlarms.add(new Alarm(
|
||||
removeIt ? RTC : RTC_WAKEUP,
|
||||
0, 0, 0, 0, 0, null, null, null, null, 0, null, uid, name));
|
||||
0, 0, 0, 0, null, null, null, null, 0, null, uid, name));
|
||||
return all;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.alarm;
|
||||
|
||||
public interface Constants {
|
||||
String TEST_CALLING_PACKAGE = "com.android.framework.test-package";
|
||||
int TEST_CALLING_UID = 67890;
|
||||
}
|
||||
Reference in New Issue
Block a user