Loading apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java +164 −61 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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) { Loading @@ -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) Loading @@ -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); Loading @@ -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('}'); Loading @@ -136,29 +209,45 @@ 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="); TimeUtils.formatDuration(windowLength, ipw); ipw.print(" repeatInterval="); Loading @@ -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:"); Loading @@ -177,9 +279,10 @@ class Alarm { ipw.print(" showIntent="); ipw.println(alarmClock.getShowIntent()); } if (operation != null) { ipw.print("operation="); ipw.println(operation); } if (listener != null) { ipw.print("listener="); ipw.println(listener.asBinder()); Loading @@ -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); Loading apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +119 −159 File changed.Preview size limit exceeded, changes collapsed. Show changes apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java +14 −3 Original line number Diff line number Diff line Loading @@ -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. */ Loading Loading @@ -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. Loading @@ -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() Loading @@ -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 { Loading @@ -125,3 +135,4 @@ public interface AlarmStore { boolean updateAlarmDelivery(Alarm a); } } apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java +31 −14 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading @@ -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(); Loading Loading @@ -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++) { Loading Loading @@ -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)); Loading Loading @@ -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); } Loading Loading @@ -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; Loading Loading @@ -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++; Loading services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +143 −9 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -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) { Loading @@ -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(); } } Loading
apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java +164 −61 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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) { Loading @@ -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) Loading @@ -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); Loading @@ -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('}'); Loading @@ -136,29 +209,45 @@ 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="); TimeUtils.formatDuration(windowLength, ipw); ipw.print(" repeatInterval="); Loading @@ -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:"); Loading @@ -177,9 +279,10 @@ class Alarm { ipw.print(" showIntent="); ipw.println(alarmClock.getShowIntent()); } if (operation != null) { ipw.print("operation="); ipw.println(operation); } if (listener != null) { ipw.print("listener="); ipw.println(listener.asBinder()); Loading @@ -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); Loading
apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +119 −159 File changed.Preview size limit exceeded, changes collapsed. Show changes
apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java +14 −3 Original line number Diff line number Diff line Loading @@ -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. */ Loading Loading @@ -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. Loading @@ -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() Loading @@ -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 { Loading @@ -125,3 +135,4 @@ public interface AlarmStore { boolean updateAlarmDelivery(Alarm a); } }
apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java +31 −14 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading @@ -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(); Loading Loading @@ -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++) { Loading Loading @@ -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)); Loading Loading @@ -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); } Loading Loading @@ -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; Loading Loading @@ -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++; Loading
services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +143 −9 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -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) { Loading @@ -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(); } }