Loading services/core/java/com/android/server/AlarmManagerService.java +82 −20 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.SparseLongArray; import android.util.StatsLog; import android.util.TimeUtils; Loading Loading @@ -195,6 +196,7 @@ class AlarmManagerService extends SystemService { private final Injector mInjector; int mBroadcastRefCount = 0; PowerManager.WakeLock mWakeLock; SparseIntArray mAlarmsPerUid = new SparseIntArray(); ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<>(); ArrayList<InFlight> mInFlight = new ArrayList<>(); private final ArrayList<AlarmManagerInternal.InFlightListener> mInFlightListeners = Loading Loading @@ -393,6 +395,8 @@ class AlarmManagerService extends SystemService { @VisibleForTesting static final String KEY_LISTENER_TIMEOUT = "listener_timeout"; @VisibleForTesting static final String KEY_MAX_ALARMS_PER_UID = "max_alarms_per_uid"; @VisibleForTesting static final String KEY_APP_STANDBY_QUOTAS_ENABLED = "app_standby_quotas_enabled"; private static final String KEY_APP_STANDBY_WINDOW = "app_standby_window"; @VisibleForTesting Loading Loading @@ -420,6 +424,7 @@ class AlarmManagerService extends SystemService { private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9*60*1000; private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000; private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000; private static final int DEFAULT_MAX_ALARMS_PER_UID = 500; private static final boolean DEFAULT_APP_STANDBY_QUOTAS_ENABLED = true; private static final long DEFAULT_APP_STANDBY_WINDOW = 60 * 60 * 1000; // 1 hr /** Loading Loading @@ -461,6 +466,8 @@ class AlarmManagerService extends SystemService { // Direct alarm listener callback timeout public long LISTENER_TIMEOUT = DEFAULT_LISTENER_TIMEOUT; public int MAX_ALARMS_PER_UID = DEFAULT_MAX_ALARMS_PER_UID; public boolean APP_STANDBY_QUOTAS_ENABLED = DEFAULT_APP_STANDBY_QUOTAS_ENABLED; public long APP_STANDBY_WINDOW = DEFAULT_APP_STANDBY_WINDOW; Loading Loading @@ -549,6 +556,15 @@ class AlarmManagerService extends SystemService { APP_STANDBY_QUOTAS[i] = mParser.getInt(KEYS_APP_STANDBY_QUOTAS[i], Math.min(APP_STANDBY_QUOTAS[i - 1], DEFAULT_APP_STANDBY_QUOTAS[i])); } MAX_ALARMS_PER_UID = mParser.getInt(KEY_MAX_ALARMS_PER_UID, DEFAULT_MAX_ALARMS_PER_UID); if (MAX_ALARMS_PER_UID < DEFAULT_MAX_ALARMS_PER_UID) { Slog.w(TAG, "Cannot set " + KEY_MAX_ALARMS_PER_UID + " lower than " + DEFAULT_MAX_ALARMS_PER_UID); MAX_ALARMS_PER_UID = DEFAULT_MAX_ALARMS_PER_UID; } updateAllowWhileIdleWhitelistDurationLocked(); } } Loading Loading @@ -590,6 +606,9 @@ class AlarmManagerService extends SystemService { TimeUtils.formatDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION, pw); pw.println(); pw.print(KEY_MAX_ALARMS_PER_UID); pw.print("="); pw.println(MAX_ALARMS_PER_UID); for (int i = 0; i < KEYS_APP_STANDBY_DELAY.length; i++) { pw.print(KEYS_APP_STANDBY_DELAY[i]); pw.print("="); TimeUtils.formatDuration(APP_STANDBY_MIN_DELAYS[i], pw); Loading Loading @@ -671,12 +690,6 @@ class AlarmManagerService extends SystemService { final ArrayList<Alarm> alarms = new ArrayList<Alarm>(); Batch() { start = 0; end = Long.MAX_VALUE; flags = 0; } Batch(Alarm seed) { start = seed.whenElapsed; end = clampPositive(seed.maxWhenElapsed); Loading Loading @@ -728,11 +741,16 @@ class AlarmManagerService extends SystemService { return newStart; } /** * Remove an alarm from this batch. * <p> <b> Should be used only while re-ordering the alarm within the service </b> as it * does not update {@link #mAlarmsPerUid} */ boolean remove(Alarm alarm) { return remove(a -> (a == alarm)); return remove(a -> (a == alarm), true); } boolean remove(Predicate<Alarm> predicate) { boolean remove(Predicate<Alarm> predicate, boolean reOrdering) { boolean didRemove = false; long newStart = 0; // recalculate endpoints as we go long newEnd = Long.MAX_VALUE; Loading @@ -741,6 +759,9 @@ class AlarmManagerService extends SystemService { Alarm alarm = alarms.get(i); if (predicate.test(alarm)) { alarms.remove(i); if (!reOrdering) { decrementAlarmCount(alarm.uid); } didRemove = true; if (alarm.alarmClock != null) { mNextAlarmClockMayChange = true; Loading Loading @@ -1734,6 +1755,15 @@ class AlarmManagerService extends SystemService { + " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed + " interval=" + interval + " flags=0x" + Integer.toHexString(flags)); } if (mAlarmsPerUid.get(callingUid, 0) >= mConstants.MAX_ALARMS_PER_UID) { final String errorMsg = "Maximum limit of concurrent alarms " + mConstants.MAX_ALARMS_PER_UID + " reached for uid: " + UserHandle.formatUid(callingUid) + ", callingPackage: " + callingPackage; // STOPSHIP (b/128866264): Just to catch breakages. Remove before final release. Slog.wtf(TAG, errorMsg); throw new UnsupportedOperationException(errorMsg); } setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed, interval, operation, directReceiver, listenerTag, flags, true, workSource, alarmClock, callingUid, callingPackage); Loading @@ -1756,6 +1786,7 @@ class AlarmManagerService extends SystemService { } catch (RemoteException e) { } removeLocked(operation, directReceiver); incrementAlarmCount(a.uid); setImplLocked(a, false, doValidate); } Loading Loading @@ -2197,7 +2228,6 @@ class AlarmManagerService extends SystemService { ? sdf.format(new Date(nowRTC - (nowELAPSED - time))) : "-"); } while (i != mNextTickHistory); pw.println(); } SystemServiceManager ssm = LocalServices.getService(SystemServiceManager.class); Loading Loading @@ -2305,6 +2335,18 @@ class AlarmManagerService extends SystemService { if (!blocked) { pw.println(" none"); } pw.println(); pw.print(" Pending alarms per uid: ["); for (int i = 0; i < mAlarmsPerUid.size(); i++) { if (i > 0) { pw.print(", "); } UserHandle.formatUid(pw, mAlarmsPerUid.keyAt(i)); pw.print(":"); pw.print(mAlarmsPerUid.valueAt(i)); } pw.println("]"); pw.println(); mAppWakeupHistory.dump(pw, " ", nowELAPSED); Loading Loading @@ -3046,7 +3088,7 @@ class AlarmManagerService extends SystemService { final Predicate<Alarm> whichAlarms = (Alarm a) -> a.matches(operation, directReceiver); for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); didRemove |= b.remove(whichAlarms); didRemove |= b.remove(whichAlarms, false); if (b.size() == 0) { mAlarmBatches.remove(i); } Loading Loading @@ -3098,7 +3140,7 @@ class AlarmManagerService extends SystemService { final Predicate<Alarm> whichAlarms = (Alarm a) -> a.uid == uid; for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); didRemove |= b.remove(whichAlarms); didRemove |= b.remove(whichAlarms, false); if (b.size() == 0) { mAlarmBatches.remove(i); } Loading Loading @@ -3145,7 +3187,7 @@ class AlarmManagerService extends SystemService { final boolean oldHasTick = haveBatchesTimeTickAlarm(mAlarmBatches); for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); didRemove |= b.remove(whichAlarms); didRemove |= b.remove(whichAlarms, false); if (b.size() == 0) { mAlarmBatches.remove(i); } Loading Loading @@ -3183,6 +3225,7 @@ class AlarmManagerService extends SystemService { } } // Only called for ephemeral apps void removeForStoppedLocked(final int uid) { if (uid == Process.SYSTEM_UID) { Slog.wtf(TAG, "removeForStoppedLocked: Shouldn't for UID=" + uid); Loading @@ -3200,7 +3243,7 @@ class AlarmManagerService extends SystemService { }; for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); didRemove |= b.remove(whichAlarms); didRemove |= b.remove(whichAlarms, false); if (b.size() == 0) { mAlarmBatches.remove(i); } Loading Loading @@ -3237,7 +3280,7 @@ class AlarmManagerService extends SystemService { (Alarm a) -> UserHandle.getUserId(a.creatorUid) == userHandle; for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); didRemove |= b.remove(whichAlarms); didRemove |= b.remove(whichAlarms, false); if (b.size() == 0) { mAlarmBatches.remove(i); } Loading Loading @@ -3407,8 +3450,7 @@ class AlarmManagerService extends SystemService { return mConstants.ALLOW_WHILE_IDLE_LONG_TIME; } boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED, final long nowRTC) { boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED) { boolean hasWakeup = false; // batches are temporally sorted, so we need only pull from the // start of the list until we either empty it or hit a batch Loading Loading @@ -3984,7 +4026,7 @@ class AlarmManagerService extends SystemService { } mLastTrigger = nowELAPSED; boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED); if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) { // if there are no wakeup alarms and the screen is off, we can // delay what we have so far until the future. Loading Loading @@ -4108,9 +4150,8 @@ class AlarmManagerService extends SystemService { case ALARM_EVENT: { ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); synchronized (mLock) { final long nowRTC = mInjector.getCurrentTimeMillis(); final long nowELAPSED = mInjector.getElapsedRealtime(); triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); triggerAlarmsLocked(triggerList, nowELAPSED); updateNextAlarmClockLocked(); } Loading Loading @@ -4719,7 +4760,7 @@ class AlarmManagerService extends SystemService { mAppWakeupHistory.recordAlarmForPackage(alarm.sourcePackage, UserHandle.getUserId(alarm.creatorUid), nowELAPSED); } decrementAlarmCount(alarm.uid); final BroadcastStats bs = inflight.mBroadcastStats; bs.count++; if (bs.nesting == 0) { Loading Loading @@ -4747,6 +4788,27 @@ class AlarmManagerService extends SystemService { } } private void incrementAlarmCount(int uid) { final int uidIndex = mAlarmsPerUid.indexOfKey(uid); if (uidIndex >= 0) { mAlarmsPerUid.setValueAt(uidIndex, mAlarmsPerUid.valueAt(uidIndex) + 1); } else { mAlarmsPerUid.put(uid, 1); } } private void decrementAlarmCount(int uid) { final int uidIndex = mAlarmsPerUid.indexOfKey(uid); if (uidIndex >= 0) { final int newCount = mAlarmsPerUid.valueAt(uidIndex) - 1; if (newCount > 0) { mAlarmsPerUid.setValueAt(uidIndex, newCount); } else { mAlarmsPerUid.removeAt(uidIndex); } } } private class ShellCmd extends ShellCommand { IAlarmManager getBinderService() { Loading services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java +98 −2 Original line number Diff line number Diff line Loading @@ -15,7 +15,10 @@ */ package com.android.server; 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 android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; Loading Loading @@ -254,14 +257,22 @@ public class AlarmManagerServiceTest { } private void setTestAlarm(int type, long triggerTime, PendingIntent operation) { setTestAlarm(type, triggerTime, operation, TEST_CALLING_UID); } private void setTestAlarm(int type, long triggerTime, PendingIntent operation, int callingUid) { mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, 0, operation, null, "test", AlarmManager.FLAG_STANDALONE, null, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE); callingUid, TEST_CALLING_PACKAGE); } private PendingIntent getNewMockPendingIntent() { return getNewMockPendingIntent(TEST_CALLING_UID); } private PendingIntent getNewMockPendingIntent(int mockUid) { final PendingIntent mockPi = mock(PendingIntent.class, Answers.RETURNS_DEEP_STUBS); when(mockPi.getCreatorUid()).thenReturn(TEST_CALLING_UID); when(mockPi.getCreatorUid()).thenReturn(mockUid); when(mockPi.getCreatorPackage()).thenReturn(TEST_CALLING_PACKAGE); return mockPi; } Loading Loading @@ -724,6 +735,91 @@ public class AlarmManagerServiceTest { verify(mMockContext).sendBroadcastAsUser(mService.mTimeTickIntent, UserHandle.ALL); } @Test public void alarmCountKeyedOnCallingUid() { final int mockCreatorUid = 431412; final PendingIntent pi = getNewMockPendingIntent(mockCreatorUid); setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 5, pi); assertEquals(1, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); assertEquals(-1, mService.mAlarmsPerUid.get(mockCreatorUid, -1)); } @Test public void alarmCountOnSet() { final int numAlarms = 103; final int[] types = {RTC_WAKEUP, RTC, ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME}; for (int i = 1; i <= numAlarms; i++) { setTestAlarm(types[i % 4], mNowElapsedTest + i, getNewMockPendingIntent()); assertEquals(i, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); } } @Test public void alarmCountOnExpiration() throws InterruptedException { final int numAlarms = 8; // This test is slow for (int i = 0; i < numAlarms; i++) { setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent()); } int expired = 0; while (expired < numAlarms) { mNowElapsedTest = mTestTimer.getElapsed(); mTestTimer.expire(); expired++; assertEquals(numAlarms - expired, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0)); } } @Test public void alarmCountOnUidRemoved() { final int numAlarms = 10; for (int i = 0; i < numAlarms; i++) { setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent()); } assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); mService.removeLocked(TEST_CALLING_UID); assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0)); } @Test public void alarmCountOnPackageRemoved() { final int numAlarms = 10; for (int i = 0; i < numAlarms; i++) { setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent()); } assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); mService.removeLocked(TEST_CALLING_PACKAGE); assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0)); } @Test public void alarmCountOnUserRemoved() { final int mockUserId = 15; final int numAlarms = 10; for (int i = 0; i < numAlarms; i++) { int mockUid = UserHandle.getUid(mockUserId, 1234 + i); setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent(mockUid), mockUid); } assertEquals(numAlarms, mService.mAlarmsPerUid.size()); mService.removeUserLocked(mockUserId); assertEquals(0, mService.mAlarmsPerUid.size()); } @Test public void alarmCountOnAlarmRemoved() { final int numAlarms = 10; final PendingIntent[] pis = new PendingIntent[numAlarms]; for (int i = 0; i < numAlarms; i++) { pis[i] = getNewMockPendingIntent(); setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 5, pis[i]); } assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); for (int i = 0; i < numAlarms; i++) { mService.removeLocked(pis[i], null); assertEquals(numAlarms - i - 1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0)); } } @After public void tearDown() { if (mMockingSession != null) { Loading Loading
services/core/java/com/android/server/AlarmManagerService.java +82 −20 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.SparseLongArray; import android.util.StatsLog; import android.util.TimeUtils; Loading Loading @@ -195,6 +196,7 @@ class AlarmManagerService extends SystemService { private final Injector mInjector; int mBroadcastRefCount = 0; PowerManager.WakeLock mWakeLock; SparseIntArray mAlarmsPerUid = new SparseIntArray(); ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<>(); ArrayList<InFlight> mInFlight = new ArrayList<>(); private final ArrayList<AlarmManagerInternal.InFlightListener> mInFlightListeners = Loading Loading @@ -393,6 +395,8 @@ class AlarmManagerService extends SystemService { @VisibleForTesting static final String KEY_LISTENER_TIMEOUT = "listener_timeout"; @VisibleForTesting static final String KEY_MAX_ALARMS_PER_UID = "max_alarms_per_uid"; @VisibleForTesting static final String KEY_APP_STANDBY_QUOTAS_ENABLED = "app_standby_quotas_enabled"; private static final String KEY_APP_STANDBY_WINDOW = "app_standby_window"; @VisibleForTesting Loading Loading @@ -420,6 +424,7 @@ class AlarmManagerService extends SystemService { private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9*60*1000; private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000; private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000; private static final int DEFAULT_MAX_ALARMS_PER_UID = 500; private static final boolean DEFAULT_APP_STANDBY_QUOTAS_ENABLED = true; private static final long DEFAULT_APP_STANDBY_WINDOW = 60 * 60 * 1000; // 1 hr /** Loading Loading @@ -461,6 +466,8 @@ class AlarmManagerService extends SystemService { // Direct alarm listener callback timeout public long LISTENER_TIMEOUT = DEFAULT_LISTENER_TIMEOUT; public int MAX_ALARMS_PER_UID = DEFAULT_MAX_ALARMS_PER_UID; public boolean APP_STANDBY_QUOTAS_ENABLED = DEFAULT_APP_STANDBY_QUOTAS_ENABLED; public long APP_STANDBY_WINDOW = DEFAULT_APP_STANDBY_WINDOW; Loading Loading @@ -549,6 +556,15 @@ class AlarmManagerService extends SystemService { APP_STANDBY_QUOTAS[i] = mParser.getInt(KEYS_APP_STANDBY_QUOTAS[i], Math.min(APP_STANDBY_QUOTAS[i - 1], DEFAULT_APP_STANDBY_QUOTAS[i])); } MAX_ALARMS_PER_UID = mParser.getInt(KEY_MAX_ALARMS_PER_UID, DEFAULT_MAX_ALARMS_PER_UID); if (MAX_ALARMS_PER_UID < DEFAULT_MAX_ALARMS_PER_UID) { Slog.w(TAG, "Cannot set " + KEY_MAX_ALARMS_PER_UID + " lower than " + DEFAULT_MAX_ALARMS_PER_UID); MAX_ALARMS_PER_UID = DEFAULT_MAX_ALARMS_PER_UID; } updateAllowWhileIdleWhitelistDurationLocked(); } } Loading Loading @@ -590,6 +606,9 @@ class AlarmManagerService extends SystemService { TimeUtils.formatDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION, pw); pw.println(); pw.print(KEY_MAX_ALARMS_PER_UID); pw.print("="); pw.println(MAX_ALARMS_PER_UID); for (int i = 0; i < KEYS_APP_STANDBY_DELAY.length; i++) { pw.print(KEYS_APP_STANDBY_DELAY[i]); pw.print("="); TimeUtils.formatDuration(APP_STANDBY_MIN_DELAYS[i], pw); Loading Loading @@ -671,12 +690,6 @@ class AlarmManagerService extends SystemService { final ArrayList<Alarm> alarms = new ArrayList<Alarm>(); Batch() { start = 0; end = Long.MAX_VALUE; flags = 0; } Batch(Alarm seed) { start = seed.whenElapsed; end = clampPositive(seed.maxWhenElapsed); Loading Loading @@ -728,11 +741,16 @@ class AlarmManagerService extends SystemService { return newStart; } /** * Remove an alarm from this batch. * <p> <b> Should be used only while re-ordering the alarm within the service </b> as it * does not update {@link #mAlarmsPerUid} */ boolean remove(Alarm alarm) { return remove(a -> (a == alarm)); return remove(a -> (a == alarm), true); } boolean remove(Predicate<Alarm> predicate) { boolean remove(Predicate<Alarm> predicate, boolean reOrdering) { boolean didRemove = false; long newStart = 0; // recalculate endpoints as we go long newEnd = Long.MAX_VALUE; Loading @@ -741,6 +759,9 @@ class AlarmManagerService extends SystemService { Alarm alarm = alarms.get(i); if (predicate.test(alarm)) { alarms.remove(i); if (!reOrdering) { decrementAlarmCount(alarm.uid); } didRemove = true; if (alarm.alarmClock != null) { mNextAlarmClockMayChange = true; Loading Loading @@ -1734,6 +1755,15 @@ class AlarmManagerService extends SystemService { + " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed + " interval=" + interval + " flags=0x" + Integer.toHexString(flags)); } if (mAlarmsPerUid.get(callingUid, 0) >= mConstants.MAX_ALARMS_PER_UID) { final String errorMsg = "Maximum limit of concurrent alarms " + mConstants.MAX_ALARMS_PER_UID + " reached for uid: " + UserHandle.formatUid(callingUid) + ", callingPackage: " + callingPackage; // STOPSHIP (b/128866264): Just to catch breakages. Remove before final release. Slog.wtf(TAG, errorMsg); throw new UnsupportedOperationException(errorMsg); } setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed, interval, operation, directReceiver, listenerTag, flags, true, workSource, alarmClock, callingUid, callingPackage); Loading @@ -1756,6 +1786,7 @@ class AlarmManagerService extends SystemService { } catch (RemoteException e) { } removeLocked(operation, directReceiver); incrementAlarmCount(a.uid); setImplLocked(a, false, doValidate); } Loading Loading @@ -2197,7 +2228,6 @@ class AlarmManagerService extends SystemService { ? sdf.format(new Date(nowRTC - (nowELAPSED - time))) : "-"); } while (i != mNextTickHistory); pw.println(); } SystemServiceManager ssm = LocalServices.getService(SystemServiceManager.class); Loading Loading @@ -2305,6 +2335,18 @@ class AlarmManagerService extends SystemService { if (!blocked) { pw.println(" none"); } pw.println(); pw.print(" Pending alarms per uid: ["); for (int i = 0; i < mAlarmsPerUid.size(); i++) { if (i > 0) { pw.print(", "); } UserHandle.formatUid(pw, mAlarmsPerUid.keyAt(i)); pw.print(":"); pw.print(mAlarmsPerUid.valueAt(i)); } pw.println("]"); pw.println(); mAppWakeupHistory.dump(pw, " ", nowELAPSED); Loading Loading @@ -3046,7 +3088,7 @@ class AlarmManagerService extends SystemService { final Predicate<Alarm> whichAlarms = (Alarm a) -> a.matches(operation, directReceiver); for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); didRemove |= b.remove(whichAlarms); didRemove |= b.remove(whichAlarms, false); if (b.size() == 0) { mAlarmBatches.remove(i); } Loading Loading @@ -3098,7 +3140,7 @@ class AlarmManagerService extends SystemService { final Predicate<Alarm> whichAlarms = (Alarm a) -> a.uid == uid; for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); didRemove |= b.remove(whichAlarms); didRemove |= b.remove(whichAlarms, false); if (b.size() == 0) { mAlarmBatches.remove(i); } Loading Loading @@ -3145,7 +3187,7 @@ class AlarmManagerService extends SystemService { final boolean oldHasTick = haveBatchesTimeTickAlarm(mAlarmBatches); for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); didRemove |= b.remove(whichAlarms); didRemove |= b.remove(whichAlarms, false); if (b.size() == 0) { mAlarmBatches.remove(i); } Loading Loading @@ -3183,6 +3225,7 @@ class AlarmManagerService extends SystemService { } } // Only called for ephemeral apps void removeForStoppedLocked(final int uid) { if (uid == Process.SYSTEM_UID) { Slog.wtf(TAG, "removeForStoppedLocked: Shouldn't for UID=" + uid); Loading @@ -3200,7 +3243,7 @@ class AlarmManagerService extends SystemService { }; for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); didRemove |= b.remove(whichAlarms); didRemove |= b.remove(whichAlarms, false); if (b.size() == 0) { mAlarmBatches.remove(i); } Loading Loading @@ -3237,7 +3280,7 @@ class AlarmManagerService extends SystemService { (Alarm a) -> UserHandle.getUserId(a.creatorUid) == userHandle; for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); didRemove |= b.remove(whichAlarms); didRemove |= b.remove(whichAlarms, false); if (b.size() == 0) { mAlarmBatches.remove(i); } Loading Loading @@ -3407,8 +3450,7 @@ class AlarmManagerService extends SystemService { return mConstants.ALLOW_WHILE_IDLE_LONG_TIME; } boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED, final long nowRTC) { boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED) { boolean hasWakeup = false; // batches are temporally sorted, so we need only pull from the // start of the list until we either empty it or hit a batch Loading Loading @@ -3984,7 +4026,7 @@ class AlarmManagerService extends SystemService { } mLastTrigger = nowELAPSED; boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED); if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) { // if there are no wakeup alarms and the screen is off, we can // delay what we have so far until the future. Loading Loading @@ -4108,9 +4150,8 @@ class AlarmManagerService extends SystemService { case ALARM_EVENT: { ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); synchronized (mLock) { final long nowRTC = mInjector.getCurrentTimeMillis(); final long nowELAPSED = mInjector.getElapsedRealtime(); triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); triggerAlarmsLocked(triggerList, nowELAPSED); updateNextAlarmClockLocked(); } Loading Loading @@ -4719,7 +4760,7 @@ class AlarmManagerService extends SystemService { mAppWakeupHistory.recordAlarmForPackage(alarm.sourcePackage, UserHandle.getUserId(alarm.creatorUid), nowELAPSED); } decrementAlarmCount(alarm.uid); final BroadcastStats bs = inflight.mBroadcastStats; bs.count++; if (bs.nesting == 0) { Loading Loading @@ -4747,6 +4788,27 @@ class AlarmManagerService extends SystemService { } } private void incrementAlarmCount(int uid) { final int uidIndex = mAlarmsPerUid.indexOfKey(uid); if (uidIndex >= 0) { mAlarmsPerUid.setValueAt(uidIndex, mAlarmsPerUid.valueAt(uidIndex) + 1); } else { mAlarmsPerUid.put(uid, 1); } } private void decrementAlarmCount(int uid) { final int uidIndex = mAlarmsPerUid.indexOfKey(uid); if (uidIndex >= 0) { final int newCount = mAlarmsPerUid.valueAt(uidIndex) - 1; if (newCount > 0) { mAlarmsPerUid.setValueAt(uidIndex, newCount); } else { mAlarmsPerUid.removeAt(uidIndex); } } } private class ShellCmd extends ShellCommand { IAlarmManager getBinderService() { Loading
services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java +98 −2 Original line number Diff line number Diff line Loading @@ -15,7 +15,10 @@ */ package com.android.server; 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 android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; Loading Loading @@ -254,14 +257,22 @@ public class AlarmManagerServiceTest { } private void setTestAlarm(int type, long triggerTime, PendingIntent operation) { setTestAlarm(type, triggerTime, operation, TEST_CALLING_UID); } private void setTestAlarm(int type, long triggerTime, PendingIntent operation, int callingUid) { mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, 0, operation, null, "test", AlarmManager.FLAG_STANDALONE, null, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE); callingUid, TEST_CALLING_PACKAGE); } private PendingIntent getNewMockPendingIntent() { return getNewMockPendingIntent(TEST_CALLING_UID); } private PendingIntent getNewMockPendingIntent(int mockUid) { final PendingIntent mockPi = mock(PendingIntent.class, Answers.RETURNS_DEEP_STUBS); when(mockPi.getCreatorUid()).thenReturn(TEST_CALLING_UID); when(mockPi.getCreatorUid()).thenReturn(mockUid); when(mockPi.getCreatorPackage()).thenReturn(TEST_CALLING_PACKAGE); return mockPi; } Loading Loading @@ -724,6 +735,91 @@ public class AlarmManagerServiceTest { verify(mMockContext).sendBroadcastAsUser(mService.mTimeTickIntent, UserHandle.ALL); } @Test public void alarmCountKeyedOnCallingUid() { final int mockCreatorUid = 431412; final PendingIntent pi = getNewMockPendingIntent(mockCreatorUid); setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 5, pi); assertEquals(1, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); assertEquals(-1, mService.mAlarmsPerUid.get(mockCreatorUid, -1)); } @Test public void alarmCountOnSet() { final int numAlarms = 103; final int[] types = {RTC_WAKEUP, RTC, ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME}; for (int i = 1; i <= numAlarms; i++) { setTestAlarm(types[i % 4], mNowElapsedTest + i, getNewMockPendingIntent()); assertEquals(i, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); } } @Test public void alarmCountOnExpiration() throws InterruptedException { final int numAlarms = 8; // This test is slow for (int i = 0; i < numAlarms; i++) { setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent()); } int expired = 0; while (expired < numAlarms) { mNowElapsedTest = mTestTimer.getElapsed(); mTestTimer.expire(); expired++; assertEquals(numAlarms - expired, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0)); } } @Test public void alarmCountOnUidRemoved() { final int numAlarms = 10; for (int i = 0; i < numAlarms; i++) { setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent()); } assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); mService.removeLocked(TEST_CALLING_UID); assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0)); } @Test public void alarmCountOnPackageRemoved() { final int numAlarms = 10; for (int i = 0; i < numAlarms; i++) { setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent()); } assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); mService.removeLocked(TEST_CALLING_PACKAGE); assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0)); } @Test public void alarmCountOnUserRemoved() { final int mockUserId = 15; final int numAlarms = 10; for (int i = 0; i < numAlarms; i++) { int mockUid = UserHandle.getUid(mockUserId, 1234 + i); setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent(mockUid), mockUid); } assertEquals(numAlarms, mService.mAlarmsPerUid.size()); mService.removeUserLocked(mockUserId); assertEquals(0, mService.mAlarmsPerUid.size()); } @Test public void alarmCountOnAlarmRemoved() { final int numAlarms = 10; final PendingIntent[] pis = new PendingIntent[numAlarms]; for (int i = 0; i < numAlarms; i++) { pis[i] = getNewMockPendingIntent(); setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 5, pis[i]); } assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); for (int i = 0; i < numAlarms; i++) { mService.removeLocked(pis[i], null); assertEquals(numAlarms - i - 1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0)); } } @After public void tearDown() { if (mMockingSession != null) { Loading