Loading apex/jobscheduler/service/aconfig/alarm.aconfig +0 −10 Original line number Diff line number Diff line package: "com.android.server.alarm" container: "system" flag { name: "use_frozen_state_to_drop_listener_alarms" namespace: "backstage_power" description: "Use frozen state callback to drop listener alarms for cached apps" bug: "324470945" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "start_user_before_scheduled_alarms" namespace: "multiuser" Loading apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +24 −63 Original line number Diff line number Diff line Loading @@ -282,7 +282,6 @@ public class AlarmManagerService extends SystemService { private final Injector mInjector; int mBroadcastRefCount = 0; boolean mUseFrozenStateToDropListenerAlarms; MetricsHelper mMetricsHelper; PowerManager.WakeLock mWakeLock; SparseIntArray mAlarmsPerUid = new SparseIntArray(); Loading Loading @@ -1784,14 +1783,12 @@ public class AlarmManagerService extends SystemService { mMetricsHelper = new MetricsHelper(getContext(), mLock); mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mUseFrozenStateToDropListenerAlarms = Flags.useFrozenStateToDropListenerAlarms(); mStartUserBeforeScheduledAlarms = Flags.startUserBeforeScheduledAlarms() && UserManager.supportsMultipleUsers(); if (mStartUserBeforeScheduledAlarms) { mUserWakeupStore = new UserWakeupStore(); mUserWakeupStore.init(); } if (mUseFrozenStateToDropListenerAlarms) { final ActivityManager.UidFrozenStateChangedCallback callback = (uids, frozenStates) -> { final int size = frozenStates.length; if (uids.length != size) { Loading @@ -1817,7 +1814,6 @@ public class AlarmManagerService extends SystemService { }; final ActivityManager am = getContext().getSystemService(ActivityManager.class); am.registerUidFrozenStateChangedCallback(new HandlerExecutor(mHandler), callback); } mListenerDeathRecipient = new IBinder.DeathRecipient() { @Override Loading Loading @@ -2994,13 +2990,10 @@ public class AlarmManagerService extends SystemService { pw.println("Feature Flags:"); pw.increaseIndent(); pw.print(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS, mUseFrozenStateToDropListenerAlarms); pw.println(); pw.print(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS, Flags.startUserBeforeScheduledAlarms()); pw.decreaseIndent(); pw.println(); pw.decreaseIndent(); pw.println(); pw.println("App Standby Parole: " + mAppStandbyParole); Loading Loading @@ -5146,38 +5139,6 @@ public class AlarmManagerService extends SystemService { removeForStoppedLocked(uid); } } @Override public void handleUidCachedChanged(int uid, boolean cached) { if (mUseFrozenStateToDropListenerAlarms) { // Use ActivityManager#UidFrozenStateChangedCallback instead. return; } if (!CompatChanges.isChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, uid)) { return; } // Apps can quickly get frozen after being cached, breaking the exactness guarantee on // listener alarms. So going forward, the contract of exact listener alarms explicitly // states that they will be removed as soon as the app goes out of lifecycle. We still // allow a short grace period for quick shuffling of proc-states that may happen // unexpectedly when switching between different lifecycles and is generally hard for // apps to avoid. final long delay; synchronized (mLock) { delay = mConstants.CACHED_LISTENER_REMOVAL_DELAY; } final Integer uidObj = uid; if (cached && !mHandler.hasEqualMessages(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED, uidObj)) { mHandler.sendMessageDelayed( mHandler.obtainMessage(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED, uidObj), delay); } else { mHandler.removeEqualMessages(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED, uidObj); } } }; private final BroadcastStats getStatsLocked(PendingIntent pi) { Loading services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +6 −80 Original line number Diff line number Diff line Loading @@ -67,7 +67,6 @@ import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHARGING import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_ALARMS; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_FOR_CANCELED; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.TEMPORARY_QUOTA_CHANGED; import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA; Loading Loading @@ -152,7 +151,6 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import android.platform.test.flag.util.FlagSetException; Loading Loading @@ -436,8 +434,7 @@ public final class AlarmManagerServiceTest { */ private void disableFlagsNotSetByAnnotation() { try { mSetFlagsRule.disableFlags(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS, Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS); mSetFlagsRule.disableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS); } catch (FlagSetException fse) { // Expected if the test about to be run requires this enabled. } Loading Loading @@ -523,13 +520,11 @@ public final class AlarmManagerServiceTest { mService.onStart(); if (Flags.useFrozenStateToDropListenerAlarms()) { final ArgumentCaptor<ActivityManager.UidFrozenStateChangedCallback> frozenCaptor = ArgumentCaptor.forClass(ActivityManager.UidFrozenStateChangedCallback.class); verify(mActivityManager).registerUidFrozenStateChangedCallback( any(HandlerExecutor.class), frozenCaptor.capture()); mUidFrozenStateCallback = frozenCaptor.getValue(); } // Unable to mock mMockContext to return a mock stats manager. // So just mocking the whole MetricsHelper instance. Loading Loading @@ -3744,79 +3739,11 @@ public final class AlarmManagerServiceTest { testTemporaryQuota_bumpedBeforeDeferral(STANDBY_BUCKET_RARE); } @Test public void exactListenerAlarmsRemovedOnCached() { mockChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, true); setTestAlarmWithListener(ELAPSED_REALTIME, 31, getNewListener(() -> {}), WINDOW_EXACT, TEST_CALLING_UID); setTestAlarmWithListener(RTC, 42, getNewListener(() -> {}), 56, TEST_CALLING_UID); setTestAlarm(ELAPSED_REALTIME, 54, WINDOW_EXACT, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID, null); setTestAlarm(RTC, 49, 154, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID, null); setTestAlarmWithListener(ELAPSED_REALTIME, 21, getNewListener(() -> {}), WINDOW_EXACT, TEST_CALLING_UID_2); setTestAlarmWithListener(RTC, 412, getNewListener(() -> {}), 561, TEST_CALLING_UID_2); setTestAlarm(ELAPSED_REALTIME, 26, WINDOW_EXACT, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID_2, null); setTestAlarm(RTC, 549, 234, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID_2, null); assertEquals(8, mService.mAlarmStore.size()); mListener.handleUidCachedChanged(TEST_CALLING_UID, true); assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED); assertEquals(7, mService.mAlarmStore.size()); mListener.handleUidCachedChanged(TEST_CALLING_UID_2, true); assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED); assertEquals(6, mService.mAlarmStore.size()); } @Test public void alarmCountOnListenerCached() { mockChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, true); // Set some alarms for TEST_CALLING_UID. final int numExactListenerUid1 = 14; for (int i = 0; i < numExactListenerUid1; i++) { setTestAlarmWithListener(ALARM_TYPES[i % 4], mNowElapsedTest + i, getNewListener(() -> {})); } setTestAlarmWithListener(RTC, 42, getNewListener(() -> {}), 56, TEST_CALLING_UID); setTestAlarm(ELAPSED_REALTIME, 54, getNewMockPendingIntent()); setTestAlarm(RTC, 49, 154, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID, null); // Set some alarms for TEST_CALLING_UID_2. final int numExactListenerUid2 = 9; for (int i = 0; i < numExactListenerUid2; i++) { setTestAlarmWithListener(ALARM_TYPES[i % 4], mNowElapsedTest + i, getNewListener(() -> {}), WINDOW_EXACT, TEST_CALLING_UID_2); } setTestAlarmWithListener(RTC, 412, getNewListener(() -> {}), 561, TEST_CALLING_UID_2); setTestAlarm(RTC_WAKEUP, 26, WINDOW_EXACT, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID_2, null); assertEquals(numExactListenerUid1 + 3, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); assertEquals(numExactListenerUid2 + 2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2)); mListener.handleUidCachedChanged(TEST_CALLING_UID, true); assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED); assertEquals(3, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); assertEquals(numExactListenerUid2 + 2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2)); mListener.handleUidCachedChanged(TEST_CALLING_UID_2, true); assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED); assertEquals(3, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); assertEquals(2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2)); } private void executeUidFrozenStateCallback(int[] uids, int[] frozenStates) { assertNotNull(mUidFrozenStateCallback); mUidFrozenStateCallback.onUidFrozenStateChanged(uids, frozenStates); } @EnableFlags(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS) @DisableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS) @Test public void exactListenerAlarmsRemovedOnFrozen() { Loading Loading @@ -3848,7 +3775,6 @@ public final class AlarmManagerServiceTest { assertEquals(6, mService.mAlarmStore.size()); } @EnableFlags(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS) @DisableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS) @Test public void alarmCountOnListenerFrozen() { Loading Loading
apex/jobscheduler/service/aconfig/alarm.aconfig +0 −10 Original line number Diff line number Diff line package: "com.android.server.alarm" container: "system" flag { name: "use_frozen_state_to_drop_listener_alarms" namespace: "backstage_power" description: "Use frozen state callback to drop listener alarms for cached apps" bug: "324470945" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "start_user_before_scheduled_alarms" namespace: "multiuser" Loading
apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +24 −63 Original line number Diff line number Diff line Loading @@ -282,7 +282,6 @@ public class AlarmManagerService extends SystemService { private final Injector mInjector; int mBroadcastRefCount = 0; boolean mUseFrozenStateToDropListenerAlarms; MetricsHelper mMetricsHelper; PowerManager.WakeLock mWakeLock; SparseIntArray mAlarmsPerUid = new SparseIntArray(); Loading Loading @@ -1784,14 +1783,12 @@ public class AlarmManagerService extends SystemService { mMetricsHelper = new MetricsHelper(getContext(), mLock); mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mUseFrozenStateToDropListenerAlarms = Flags.useFrozenStateToDropListenerAlarms(); mStartUserBeforeScheduledAlarms = Flags.startUserBeforeScheduledAlarms() && UserManager.supportsMultipleUsers(); if (mStartUserBeforeScheduledAlarms) { mUserWakeupStore = new UserWakeupStore(); mUserWakeupStore.init(); } if (mUseFrozenStateToDropListenerAlarms) { final ActivityManager.UidFrozenStateChangedCallback callback = (uids, frozenStates) -> { final int size = frozenStates.length; if (uids.length != size) { Loading @@ -1817,7 +1814,6 @@ public class AlarmManagerService extends SystemService { }; final ActivityManager am = getContext().getSystemService(ActivityManager.class); am.registerUidFrozenStateChangedCallback(new HandlerExecutor(mHandler), callback); } mListenerDeathRecipient = new IBinder.DeathRecipient() { @Override Loading Loading @@ -2994,13 +2990,10 @@ public class AlarmManagerService extends SystemService { pw.println("Feature Flags:"); pw.increaseIndent(); pw.print(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS, mUseFrozenStateToDropListenerAlarms); pw.println(); pw.print(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS, Flags.startUserBeforeScheduledAlarms()); pw.decreaseIndent(); pw.println(); pw.decreaseIndent(); pw.println(); pw.println("App Standby Parole: " + mAppStandbyParole); Loading Loading @@ -5146,38 +5139,6 @@ public class AlarmManagerService extends SystemService { removeForStoppedLocked(uid); } } @Override public void handleUidCachedChanged(int uid, boolean cached) { if (mUseFrozenStateToDropListenerAlarms) { // Use ActivityManager#UidFrozenStateChangedCallback instead. return; } if (!CompatChanges.isChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, uid)) { return; } // Apps can quickly get frozen after being cached, breaking the exactness guarantee on // listener alarms. So going forward, the contract of exact listener alarms explicitly // states that they will be removed as soon as the app goes out of lifecycle. We still // allow a short grace period for quick shuffling of proc-states that may happen // unexpectedly when switching between different lifecycles and is generally hard for // apps to avoid. final long delay; synchronized (mLock) { delay = mConstants.CACHED_LISTENER_REMOVAL_DELAY; } final Integer uidObj = uid; if (cached && !mHandler.hasEqualMessages(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED, uidObj)) { mHandler.sendMessageDelayed( mHandler.obtainMessage(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED, uidObj), delay); } else { mHandler.removeEqualMessages(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED, uidObj); } } }; private final BroadcastStats getStatsLocked(PendingIntent pi) { Loading
services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +6 −80 Original line number Diff line number Diff line Loading @@ -67,7 +67,6 @@ import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHARGING import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_ALARMS; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_FOR_CANCELED; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.TEMPORARY_QUOTA_CHANGED; import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA; Loading Loading @@ -152,7 +151,6 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import android.platform.test.flag.util.FlagSetException; Loading Loading @@ -436,8 +434,7 @@ public final class AlarmManagerServiceTest { */ private void disableFlagsNotSetByAnnotation() { try { mSetFlagsRule.disableFlags(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS, Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS); mSetFlagsRule.disableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS); } catch (FlagSetException fse) { // Expected if the test about to be run requires this enabled. } Loading Loading @@ -523,13 +520,11 @@ public final class AlarmManagerServiceTest { mService.onStart(); if (Flags.useFrozenStateToDropListenerAlarms()) { final ArgumentCaptor<ActivityManager.UidFrozenStateChangedCallback> frozenCaptor = ArgumentCaptor.forClass(ActivityManager.UidFrozenStateChangedCallback.class); verify(mActivityManager).registerUidFrozenStateChangedCallback( any(HandlerExecutor.class), frozenCaptor.capture()); mUidFrozenStateCallback = frozenCaptor.getValue(); } // Unable to mock mMockContext to return a mock stats manager. // So just mocking the whole MetricsHelper instance. Loading Loading @@ -3744,79 +3739,11 @@ public final class AlarmManagerServiceTest { testTemporaryQuota_bumpedBeforeDeferral(STANDBY_BUCKET_RARE); } @Test public void exactListenerAlarmsRemovedOnCached() { mockChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, true); setTestAlarmWithListener(ELAPSED_REALTIME, 31, getNewListener(() -> {}), WINDOW_EXACT, TEST_CALLING_UID); setTestAlarmWithListener(RTC, 42, getNewListener(() -> {}), 56, TEST_CALLING_UID); setTestAlarm(ELAPSED_REALTIME, 54, WINDOW_EXACT, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID, null); setTestAlarm(RTC, 49, 154, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID, null); setTestAlarmWithListener(ELAPSED_REALTIME, 21, getNewListener(() -> {}), WINDOW_EXACT, TEST_CALLING_UID_2); setTestAlarmWithListener(RTC, 412, getNewListener(() -> {}), 561, TEST_CALLING_UID_2); setTestAlarm(ELAPSED_REALTIME, 26, WINDOW_EXACT, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID_2, null); setTestAlarm(RTC, 549, 234, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID_2, null); assertEquals(8, mService.mAlarmStore.size()); mListener.handleUidCachedChanged(TEST_CALLING_UID, true); assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED); assertEquals(7, mService.mAlarmStore.size()); mListener.handleUidCachedChanged(TEST_CALLING_UID_2, true); assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED); assertEquals(6, mService.mAlarmStore.size()); } @Test public void alarmCountOnListenerCached() { mockChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, true); // Set some alarms for TEST_CALLING_UID. final int numExactListenerUid1 = 14; for (int i = 0; i < numExactListenerUid1; i++) { setTestAlarmWithListener(ALARM_TYPES[i % 4], mNowElapsedTest + i, getNewListener(() -> {})); } setTestAlarmWithListener(RTC, 42, getNewListener(() -> {}), 56, TEST_CALLING_UID); setTestAlarm(ELAPSED_REALTIME, 54, getNewMockPendingIntent()); setTestAlarm(RTC, 49, 154, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID, null); // Set some alarms for TEST_CALLING_UID_2. final int numExactListenerUid2 = 9; for (int i = 0; i < numExactListenerUid2; i++) { setTestAlarmWithListener(ALARM_TYPES[i % 4], mNowElapsedTest + i, getNewListener(() -> {}), WINDOW_EXACT, TEST_CALLING_UID_2); } setTestAlarmWithListener(RTC, 412, getNewListener(() -> {}), 561, TEST_CALLING_UID_2); setTestAlarm(RTC_WAKEUP, 26, WINDOW_EXACT, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID_2, null); assertEquals(numExactListenerUid1 + 3, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); assertEquals(numExactListenerUid2 + 2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2)); mListener.handleUidCachedChanged(TEST_CALLING_UID, true); assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED); assertEquals(3, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); assertEquals(numExactListenerUid2 + 2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2)); mListener.handleUidCachedChanged(TEST_CALLING_UID_2, true); assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED); assertEquals(3, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); assertEquals(2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2)); } private void executeUidFrozenStateCallback(int[] uids, int[] frozenStates) { assertNotNull(mUidFrozenStateCallback); mUidFrozenStateCallback.onUidFrozenStateChanged(uids, frozenStates); } @EnableFlags(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS) @DisableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS) @Test public void exactListenerAlarmsRemovedOnFrozen() { Loading Loading @@ -3848,7 +3775,6 @@ public final class AlarmManagerServiceTest { assertEquals(6, mService.mAlarmStore.size()); } @EnableFlags(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS) @DisableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS) @Test public void alarmCountOnListenerFrozen() { Loading