diff options
21 files changed, 824 insertions, 302 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java index f672e4b711c4..45ea23321d15 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java @@ -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); diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java index 05910a5b171e..82819dab0f69 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -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; - } - 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 nowElapsed = mInjector.getElapsedRealtime(); + if (isExemptFromAppStandby(alarm) || mAppStandbyParole) { + return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, nowElapsed); } - 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) { diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java index 9fdbb8bbffc7..7a846b9b82db 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java @@ -48,6 +48,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. */ int size(); @@ -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); } } + diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java index 91c0c0579c69..cbfe80bdce24 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java @@ -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++; diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 90401ad53a93..b020c7044a00 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -81,6 +81,7 @@ import android.hardware.SystemSensorManager; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.IAuthService; import android.hardware.camera2.CameraManager; +import android.hardware.devicestate.DeviceStateManager; import android.hardware.display.ColorDisplayManager; import android.hardware.display.DisplayManager; import android.hardware.face.FaceManager; @@ -1348,6 +1349,12 @@ public final class SystemServiceRegistry { throws ServiceNotFoundException { return new DreamManager(ctx); }}); + registerService(Context.DEVICE_STATE_SERVICE, DeviceStateManager.class, + new CachedServiceFetcher<DeviceStateManager>() { + @Override + public DeviceStateManager createService(ContextImpl ctx) { + return new DeviceStateManager(); + }}); sInitializing = true; try { @@ -1404,6 +1411,7 @@ public final class SystemServiceRegistry { case Context.CONTENT_CAPTURE_MANAGER_SERVICE: case Context.APP_PREDICTION_SERVICE: case Context.INCREMENTAL_SERVICE: + case Context.ETHERNET_SERVICE: return null; } Slog.wtf(TAG, "Manager wrapper not available: " + name); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 9c216a3ffd47..c4157cfe09ad 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3508,6 +3508,7 @@ public abstract class Context { PERMISSION_SERVICE, LIGHTS_SERVICE, //@hide: PEOPLE_SERVICE, + //@hide: DEVICE_STATE_SERVICE, }) @Retention(RetentionPolicy.SOURCE) public @interface ServiceName {} @@ -5246,6 +5247,14 @@ public abstract class Context { public static final String PEOPLE_SERVICE = "people"; /** + * Use with {@link #getSystemService(String)} to access device state service. + * + * @see #getSystemService(String) + * @hide + */ + public static final String DEVICE_STATE_SERVICE = "device_state"; + + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. * diff --git a/core/java/android/hardware/devicestate/DeviceStateManager.java b/core/java/android/hardware/devicestate/DeviceStateManager.java new file mode 100644 index 000000000000..a52f983ff2a7 --- /dev/null +++ b/core/java/android/hardware/devicestate/DeviceStateManager.java @@ -0,0 +1,38 @@ +/* + * 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 android.hardware.devicestate; + +import android.annotation.SystemService; +import android.content.Context; + +/** + * Manages the state of the system for devices with user-configurable hardware like a foldable + * phone. + * + * @hide + */ +@SystemService(Context.DEVICE_STATE_SERVICE) +public final class DeviceStateManager { + /** Invalid device state. */ + public static final int INVALID_DEVICE_STATE = -1; + + private DeviceStateManagerGlobal mGlobal; + + public DeviceStateManager() { + mGlobal = DeviceStateManagerGlobal.getInstance(); + } +} diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java new file mode 100644 index 000000000000..4e7cf4af118d --- /dev/null +++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java @@ -0,0 +1,58 @@ +/* + * 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 android.hardware.devicestate; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.os.IBinder; +import android.os.ServiceManager; + +/** + * Provides communication with the device state system service on behalf of applications. + * + * @see DeviceStateManager + * @hide + */ +final class DeviceStateManagerGlobal { + private static DeviceStateManagerGlobal sInstance; + + /** + * Returns an instance of {@link DeviceStateManagerGlobal}. May return {@code null} if a + * connection with the device state service couldn't be established. + */ + @Nullable + static DeviceStateManagerGlobal getInstance() { + synchronized (DeviceStateManagerGlobal.class) { + if (sInstance == null) { + IBinder b = ServiceManager.getService(Context.DEVICE_STATE_SERVICE); + if (b != null) { + sInstance = new DeviceStateManagerGlobal(IDeviceStateManager + .Stub.asInterface(b)); + } + } + return sInstance; + } + } + + @NonNull + private final IDeviceStateManager mDeviceStateManager; + + private DeviceStateManagerGlobal(@NonNull IDeviceStateManager deviceStateManager) { + mDeviceStateManager = deviceStateManager; + } +} diff --git a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl new file mode 100644 index 000000000000..24913e9b2d23 --- /dev/null +++ b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl @@ -0,0 +1,20 @@ +/** + * 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 android.hardware.devicestate; + +/** @hide */ +interface IDeviceStateManager {} diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index 7fac615aa88d..32ce5e26e929 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -2751,4 +2751,9 @@ enum PageId { // OS: R QPR2 BLUETOOTH_PAIRING_RECEIVER = 1851; + + // OPEN: Settings > Display > Screen timeout + // CATEGORY: SETTINGS + // OS: S + SCREEN_TIMEOUT = 1852; } diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index eb2e23e1b5e1..4a095c9be053 100644 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -28,7 +28,6 @@ import android.location.LocationManager; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; -import android.telephony.PhoneNumberUtils; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.Log; @@ -161,7 +160,7 @@ public class GpsNetInitiatedHandler { be set to true when the phone is having emergency call, and then will be set to false by mPhoneStateListener when the emergency call ends. */ - mIsInEmergencyCall = PhoneNumberUtils.isEmergencyNumber(phoneNumber); + mIsInEmergencyCall = mTelephonyManager.isEmergencyNumber(phoneNumber); if (DEBUG) Log.v(TAG, "ACTION_NEW_OUTGOING_CALL - " + getInEmergency()); } else if (action.equals(LocationManager.MODE_CHANGED_ACTION)) { updateLocationMode(); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 9ddf7a4fb79b..d71b919818ea 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -941,10 +941,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (resolvedUserId != mCurrentUserId) { return null; } - if (mA11yWindowManager.findA11yWindowInfoByIdLocked(windowId) == null) { + final AccessibilityWindowInfo accessibilityWindowInfo = mA11yWindowManager + .findA11yWindowInfoByIdLocked(windowId); + if (accessibilityWindowInfo == null) { return null; } - return mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(userId, windowId); + // We use AccessibilityWindowInfo#getId instead of windowId. When the windowId comes + // from an embedded hierarchy, the system can't find correct window token because + // embedded hierarchy doesn't have windowInfo. Calling + // AccessibilityWindowManager#findA11yWindowInfoByIdLocked can look for its parent's + // windowInfo, so it is safer to use AccessibilityWindowInfo#getId + // to get window token to find real window. + return mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(userId, + accessibilityWindowInfo.getId()); } } diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java index 4cff5c013bda..7e3c1ab50ad5 100644 --- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java +++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java @@ -16,8 +16,11 @@ package com.android.server.devicestate; +import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE; + import android.annotation.NonNull; import android.content.Context; +import android.hardware.devicestate.IDeviceStateManager; import android.util.IntArray; import android.util.Slog; @@ -49,9 +52,6 @@ import java.util.Arrays; * @see DeviceStatePolicy */ public final class DeviceStateManagerService extends SystemService { - /** Invalid device state. */ - public static final int INVALID_DEVICE_STATE = -1; - private static final String TAG = "DeviceStateManagerService"; private static final boolean DEBUG = false; @@ -88,6 +88,7 @@ public final class DeviceStateManagerService extends SystemService { @Override public void onStart() { mDeviceStatePolicy.getDeviceStateProvider().setListener(new DeviceStateProviderListener()); + publishBinderService(Context.DEVICE_STATE_SERVICE, new BinderService()); } /** @@ -267,4 +268,9 @@ public final class DeviceStateManagerService extends SystemService { requestState(state); } } + + /** Implementation of {@link IDeviceStateManager} published as a binder service. */ + private final class BinderService extends IDeviceStateManager.Stub { + + } } diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java index d61783ef59d2..a5f083477863 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java @@ -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(); + } } diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java index 9e43b4ab9b5a..f0490ce469dd 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java @@ -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()); diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java new file mode 100644 index 000000000000..efcfae38c3d3 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java @@ -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)); + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java index 6465739f6822..5bb6a42b2604 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java @@ -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; } diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/Constants.java b/services/tests/mockingservicestests/src/com/android/server/alarm/Constants.java new file mode 100644 index 000000000000..2552db8a310a --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/Constants.java @@ -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; +} diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java index 59d4e2ae6ae4..058794a3b9e9 100644 --- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java @@ -16,7 +16,7 @@ package com.android.server.devicestate; -import static com.android.server.devicestate.DeviceStateManagerService.INVALID_DEVICE_STATE; +import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertThrows; diff --git a/telecomm/java/android/telecom/CallerInfo.java b/telecomm/java/android/telecom/CallerInfo.java index fb6f99405759..aff2f0183a3b 100644 --- a/telecomm/java/android/telecom/CallerInfo.java +++ b/telecomm/java/android/telecom/CallerInfo.java @@ -405,7 +405,8 @@ public class CallerInfo { // Change the callerInfo number ONLY if it is an emergency number // or if it is the voicemail number. If it is either, take a // shortcut and skip the query. - if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) { + TelephonyManager tm = context.getSystemService(TelephonyManager.class); + if (tm.isEmergencyNumber(number)) { return new CallerInfo().markAsEmergency(context); } else if (PhoneNumberUtils.isVoiceMailNumber(null, subId, number)) { return new CallerInfo().markAsVoiceMail(context, subId); diff --git a/telecomm/java/android/telecom/CallerInfoAsyncQuery.java b/telecomm/java/android/telecom/CallerInfoAsyncQuery.java index 4a81a8eea5cf..a9e1a8fc1952 100644 --- a/telecomm/java/android/telecom/CallerInfoAsyncQuery.java +++ b/telecomm/java/android/telecom/CallerInfoAsyncQuery.java @@ -34,6 +34,7 @@ import android.os.UserManager; import android.provider.ContactsContract.PhoneLookup; import android.telephony.PhoneNumberUtils; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.text.TextUtils; import java.util.ArrayList; @@ -481,7 +482,8 @@ public class CallerInfoAsyncQuery { cw.subId = subId; // check to see if these are recognized numbers, and use shortcuts if we can. - if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) { + TelephonyManager tm = context.getSystemService(TelephonyManager.class); + if (tm.isEmergencyNumber(number)) { cw.event = EVENT_EMERGENCY_NUMBER; } else if (PhoneNumberUtils.isVoiceMailNumber(context, subId, number)) { cw.event = EVENT_VOICEMAIL_NUMBER; |