Merge "Remove exact listener alarms when uid gets cached"

This commit is contained in:
Suprabh Shukla
2023-02-11 06:40:21 +00:00
committed by Android (Google) Code Review
5 changed files with 290 additions and 60 deletions

View File

@@ -311,6 +311,15 @@ public class AlarmManager {
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public static final long SCHEDULE_EXACT_ALARM_DOES_NOT_ELEVATE_BUCKET = 262645982L;
/**
* Exact alarms expecting a {@link OnAlarmListener} callback will be dropped when the calling
* app goes into cached state.
*
* @hide
*/
@ChangeId
public static final long EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED = 265195908L;
@UnsupportedAppUsage
private final IAlarmManager mService;
private final Context mContext;
@@ -808,13 +817,24 @@ public class AlarmManager {
* The OnAlarmListener's {@link OnAlarmListener#onAlarm() onAlarm()} method will be
* invoked via the specified target Handler, or on the application's main looper
* if {@code null} is passed as the {@code targetHandler} parameter.
* <p>
* This API should only be used to set alarms that are relevant in the context of the app's
* current lifecycle, as the {@link OnAlarmListener} instance supplied is only valid as long as
* the process is alive, and the system can clean up the app process as soon as it is out of
* lifecycle. To schedule alarms that fire reliably even after the current lifecycle completes,
* and wakes up the app if required, use any of the other scheduling APIs that accept a
* {@link PendingIntent} instance.
*
* <p class="note"><strong>Note:</strong>
* <p>
* On previous android versions {@link Build.VERSION_CODES#S} and
* {@link Build.VERSION_CODES#TIRAMISU}, apps targeting SDK level 31 or higher needed to hold
* the {@link Manifest.permission#SCHEDULE_EXACT_ALARM SCHEDULE_EXACT_ALARM} permission to use
* this API, unless the app was exempt from battery restrictions.
*
* <p class="note"><strong>Note:</strong>
* Starting with android version {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, the system will
* explicitly drop any alarms set via this API when the calling app goes out of lifecycle.
*
*/
public void setExact(@AlarmType int type, long triggerAtMillis, @Nullable String tag,
@NonNull OnAlarmListener listener, @Nullable Handler targetHandler) {
@@ -984,6 +1004,10 @@ public class AlarmManager {
* allowlist. This can be set, for example, by marking the app as {@code <allow-in-power-save>}
* within the system config.
*
* <p class="note"><strong>Note:</strong>
* Starting with android version {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, the system will
* explicitly drop any alarms set via this API when the calling app goes out of lifecycle.
*
* @param type type of alarm
* @param triggerAtMillis The exact time in milliseconds, that the alarm should be delivered,
* expressed in the appropriate clock's units (depending on the alarm
@@ -1295,6 +1319,10 @@ public class AlarmManager {
*
* <p> See {@link #setExactAndAllowWhileIdle(int, long, PendingIntent)} for more details.
*
* <p class="note"><strong>Note:</strong>
* Starting with android version {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, the system will
* explicitly drop any alarms set via this API when the calling app goes out of lifecycle.
*
* @param type type of alarm
* @param triggerAtMillis The exact time in milliseconds, that the alarm should be delivered,
* expressed in the appropriate clock's units (depending on the alarm

View File

@@ -425,6 +425,12 @@ public class AppStateTrackerImpl implements AppStateTracker {
*/
public void removeAlarmsForUid(int uid) {
}
/**
* Called when a uid goes into cached, so its alarms using a listener should be removed.
*/
public void removeListenerAlarmsForCachedUid(int uid) {
}
}
public AppStateTrackerImpl(Context context, Looper looper) {
@@ -496,7 +502,8 @@ public class AppStateTrackerImpl implements AppStateTracker {
mIActivityManager.registerUidObserver(new UidObserver(),
ActivityManager.UID_OBSERVER_GONE
| ActivityManager.UID_OBSERVER_IDLE
| ActivityManager.UID_OBSERVER_ACTIVE,
| ActivityManager.UID_OBSERVER_ACTIVE
| ActivityManager.UID_OBSERVER_CACHED,
ActivityManager.PROCESS_STATE_UNKNOWN, null);
mAppOpsService.startWatchingMode(TARGET_OP, null,
new AppOpsWatcher());
@@ -731,6 +738,7 @@ public class AppStateTrackerImpl implements AppStateTracker {
@Override
public void onUidCachedChanged(int uid, boolean cached) {
mHandler.onUidCachedChanged(uid, cached);
}
@Override
@@ -800,6 +808,7 @@ public class AppStateTrackerImpl implements AppStateTracker {
private static final int MSG_ON_UID_ACTIVE = 12;
private static final int MSG_ON_UID_GONE = 13;
private static final int MSG_ON_UID_IDLE = 14;
private static final int MSG_ON_UID_CACHED = 15;
MyHandler(Looper looper) {
super(looper);
@@ -860,6 +869,12 @@ public class AppStateTrackerImpl implements AppStateTracker {
obtainMessage(MSG_ON_UID_IDLE, uid, disabled ? 1 : 0).sendToTarget();
}
public void onUidCachedChanged(int uid, boolean cached) {
if (cached) {
obtainMessage(MSG_ON_UID_CACHED, uid, 0).sendToTarget();
}
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -953,6 +968,15 @@ public class AppStateTrackerImpl implements AppStateTracker {
handleUidDisabled(msg.arg1);
}
return;
case MSG_ON_UID_CACHED:
handleUidCached(msg.arg1);
return;
}
}
private void handleUidCached(int uid) {
for (Listener l : cloneListeners()) {
l.removeListenerAlarmsForCachedUid(uid);
}
}

View File

@@ -19,6 +19,7 @@ package com.android.server.alarm;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.AlarmManager.ELAPSED_REALTIME;
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
import static android.app.AlarmManager.EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED;
import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE;
import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_COMPAT;
import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
@@ -57,6 +58,8 @@ import static com.android.server.alarm.Alarm.TARE_POLICY_INDEX;
import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_ALARM_CANCELLED;
import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_DATA_CLEARED;
import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_EXACT_PERMISSION_REVOKED;
import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_LISTENER_BINDER_DIED;
import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_LISTENER_CACHED;
import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_PI_CANCELLED;
import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_UNDEFINED;
@@ -610,6 +613,8 @@ public class AlarmManagerService extends SystemService {
static final int REMOVE_REASON_EXACT_PERMISSION_REVOKED = 2;
static final int REMOVE_REASON_DATA_CLEARED = 3;
static final int REMOVE_REASON_PI_CANCELLED = 4;
static final int REMOVE_REASON_LISTENER_BINDER_DIED = 5;
static final int REMOVE_REASON_LISTENER_CACHED = 6;
final String mTag;
final long mWhenRemovedElapsed;
@@ -639,6 +644,10 @@ public class AlarmManagerService extends SystemService {
return "data_cleared";
case REMOVE_REASON_PI_CANCELLED:
return "pi_cancelled";
case REMOVE_REASON_LISTENER_BINDER_DIED:
return "listener_binder_died";
case REMOVE_REASON_LISTENER_CACHED:
return "listener_cached";
default:
return "unknown:" + reason;
}
@@ -1892,7 +1901,9 @@ public class AlarmManagerService extends SystemService {
@Override
public void binderDied(IBinder who) {
final IAlarmListener listener = IAlarmListener.Stub.asInterface(who);
removeImpl(null, listener);
synchronized (mLock) {
removeLocked(null, listener, REMOVE_REASON_LISTENER_BINDER_DIED);
}
}
};
@@ -5444,6 +5455,24 @@ public class AlarmManagerService extends SystemService {
removeForStoppedLocked(uid);
}
}
@Override
public void removeListenerAlarmsForCachedUid(int uid) {
if (!CompatChanges.isChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, uid)) {
return;
}
synchronized (mLock) {
removeAlarmsInternalLocked(a -> {
if (a.uid != uid || a.listener == null || a.windowLength != 0) {
return false;
}
// TODO (b/265195908): Change to a .w once we have some data on breakages.
Slog.wtf(TAG, "Alarm " + a.listenerTag + " being removed for " + a.packageName
+ " because the app went into cached state");
return true;
}, REMOVE_REASON_LISTENER_CACHED);
}
}
};
private final BroadcastStats getStatsLocked(PendingIntent pi) {

View File

@@ -271,7 +271,8 @@ public class AppStateTrackerTest {
verify(mMockIActivityManager).registerUidObserver(
uidObserverArgumentCaptor.capture(),
eq(ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE
| ActivityManager.UID_OBSERVER_ACTIVE),
| ActivityManager.UID_OBSERVER_ACTIVE
| ActivityManager.UID_OBSERVER_CACHED),
eq(ActivityManager.PROCESS_STATE_UNKNOWN),
isNull());
verify(mMockIAppOpsService).startWatchingMode(
@@ -1364,6 +1365,8 @@ public class AppStateTrackerTest {
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1));
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
verify(l, times(0)).removeAlarmsForUid(UID_10_1);
verify(l, times(0)).removeListenerAlarmsForCachedUid(UID_10_1);
reset(l);
mIUidObserver.onUidGone(UID_10_1, true);
@@ -1381,6 +1384,8 @@ public class AppStateTrackerTest {
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
verify(l, times(1)).removeAlarmsForUid(UID_10_1);
verify(l, times(0)).removeListenerAlarmsForCachedUid(UID_10_1);
reset(l);
mIUidObserver.onUidActive(UID_10_1);
@@ -1398,6 +1403,8 @@ public class AppStateTrackerTest {
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1));
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
verify(l, times(0)).removeAlarmsForUid(UID_10_1);
verify(l, times(0)).removeListenerAlarmsForCachedUid(UID_10_1);
reset(l);
mIUidObserver.onUidIdle(UID_10_1, true);
@@ -1415,8 +1422,49 @@ public class AppStateTrackerTest {
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
verify(l, times(1)).removeAlarmsForUid(UID_10_1);
verify(l, times(0)).removeListenerAlarmsForCachedUid(UID_10_1);
reset(l);
mIUidObserver.onUidCachedChanged(UID_10_1, true);
waitUntilMainHandlerDrain();
waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(eq(UID_10_1));
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
verify(l, times(0)).removeAlarmsForUid(UID_10_1);
verify(l, times(1)).removeListenerAlarmsForCachedUid(UID_10_1);
reset(l);
mIUidObserver.onUidCachedChanged(UID_10_1, false);
waitUntilMainHandlerDrain();
waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(eq(UID_10_1));
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
verify(l, times(0)).removeAlarmsForUid(UID_10_1);
verify(l, times(0)).removeListenerAlarmsForCachedUid(UID_10_1);
reset(l);
// Without battery saver.
mPowerSaveMode = false;
mPowerSaveObserver.accept(getPowerSaveState());
@@ -1433,6 +1481,8 @@ public class AppStateTrackerTest {
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
verify(l, times(0)).removeAlarmsForUid(UID_10_1);
verify(l, times(0)).removeListenerAlarmsForCachedUid(UID_10_1);
reset(l);
mIUidObserver.onUidActive(UID_10_1);
@@ -1450,6 +1500,8 @@ public class AppStateTrackerTest {
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1));
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
verify(l, times(0)).removeAlarmsForUid(UID_10_1);
verify(l, times(0)).removeListenerAlarmsForCachedUid(UID_10_1);
reset(l);
mIUidObserver.onUidGone(UID_10_1, true);
@@ -1467,6 +1519,8 @@ public class AppStateTrackerTest {
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
verify(l, times(1)).removeAlarmsForUid(UID_10_1);
verify(l, times(0)).removeListenerAlarmsForCachedUid(UID_10_1);
reset(l);
mIUidObserver.onUidActive(UID_10_1);
@@ -1484,6 +1538,8 @@ public class AppStateTrackerTest {
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1));
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
verify(l, times(0)).removeAlarmsForUid(UID_10_1);
verify(l, times(0)).removeListenerAlarmsForCachedUid(UID_10_1);
reset(l);
mIUidObserver.onUidIdle(UID_10_1, true);
@@ -1501,6 +1557,46 @@ public class AppStateTrackerTest {
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
verify(l, times(1)).removeAlarmsForUid(UID_10_1);
verify(l, times(0)).removeListenerAlarmsForCachedUid(UID_10_1);
reset(l);
mIUidObserver.onUidCachedChanged(UID_10_1, true);
waitUntilMainHandlerDrain();
waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(eq(UID_10_1));
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
verify(l, times(0)).removeAlarmsForUid(UID_10_1);
verify(l, times(1)).removeListenerAlarmsForCachedUid(UID_10_1);
reset(l);
mIUidObserver.onUidCachedChanged(UID_10_1, false);
waitUntilMainHandlerDrain();
waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(eq(UID_10_1));
verify(l, times(0)).unblockAllUnrestrictedAlarms();
verify(l, times(0)).unblockAlarmsForUid(anyInt());
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
verify(l, times(0)).removeAlarmsForUid(UID_10_1);
verify(l, times(0)).removeListenerAlarmsForCachedUid(UID_10_1);
reset(l);
}

View File

@@ -18,6 +18,7 @@ package com.android.server.alarm;
import static android.Manifest.permission.SCHEDULE_EXACT_ALARM;
import static android.app.AlarmManager.ELAPSED_REALTIME;
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
import static android.app.AlarmManager.EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED;
import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE;
import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_COMPAT;
import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
@@ -201,17 +202,21 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.LongConsumer;
@Presubmit
@SuppressWarnings("GuardedBy") // This test enforces synchronous behavior.
@RunWith(AndroidJUnit4.class)
public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
private static final String TAG = AlarmManagerServiceTest.class.getSimpleName();
private static final int SYSTEM_UI_UID = 12345;
private static final int TEST_CALLING_USER = UserHandle.getUserId(TEST_CALLING_UID);
private static final int TEST_CALLING_UID_2 = TEST_CALLING_UID + 1;
private static final int[] ALARM_TYPES =
{RTC_WAKEUP, RTC, ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME};
private long mAppStandbyWindow;
private long mAllowWhileIdleWindow;
private AlarmManagerService mService;
private AppStandbyInternal.AppIdleStateChangeListener mAppStandbyListener;
private AppStateTrackerImpl.Listener mListener;
private AlarmManagerService.UninstallReceiver mPackageChangesReceiver;
private AlarmManagerService.ChargingReceiver mChargingReceiver;
private IAppOpsCallback mIAppOpsCallback;
@@ -515,10 +520,16 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
setTareEnabled(EconomyManager.ENABLED_MODE_OFF);
mAppStandbyWindow = mService.mConstants.APP_STANDBY_WINDOW;
mAllowWhileIdleWindow = mService.mConstants.ALLOW_WHILE_IDLE_WINDOW;
ArgumentCaptor<AppStandbyInternal.AppIdleStateChangeListener> captor =
ArgumentCaptor<AppStandbyInternal.AppIdleStateChangeListener> idleListenerCaptor =
ArgumentCaptor.forClass(AppStandbyInternal.AppIdleStateChangeListener.class);
verify(mAppStandbyInternal).addListener(captor.capture());
mAppStandbyListener = captor.getValue();
verify(mAppStandbyInternal).addListener(idleListenerCaptor.capture());
mAppStandbyListener = idleListenerCaptor.getValue();
final ArgumentCaptor<AppStateTrackerImpl.Listener> trackerListenerCaptor =
ArgumentCaptor.forClass(AppStateTrackerImpl.Listener.class);
verify(mAppStateTracker).addListener(trackerListenerCaptor.capture());
mListener = trackerListenerCaptor.getValue();
final ArgumentCaptor<AlarmManagerService.ChargingReceiver> chargingReceiverCaptor =
ArgumentCaptor.forClass(AlarmManagerService.ChargingReceiver.class);
@@ -613,8 +624,13 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
}
private void setTestAlarmWithListener(int type, long triggerTime, IAlarmListener listener) {
mService.setImpl(type, triggerTime, WINDOW_EXACT, 0, null, listener, "test",
FLAG_STANDALONE, null, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE, null, 0);
setTestAlarmWithListener(type, triggerTime, listener, WINDOW_EXACT, TEST_CALLING_UID);
}
private void setTestAlarmWithListener(int type, long triggerTime, IAlarmListener listener,
long windowLength, int callingUid) {
mService.setImpl(type, triggerTime, windowLength, 0, null, listener, "test",
FLAG_STANDALONE, null, null, callingUid, TEST_CALLING_PACKAGE, null, 0);
}
private PendingIntent getNewMockPendingIntent() {
@@ -638,6 +654,15 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
return mockPi;
}
private IAlarmListener getNewListener(Runnable onAlarm) {
return new IAlarmListener.Stub() {
@Override
public void doAlarm(IAlarmCompleteListener callback) throws RemoteException {
onAlarm.run();
}
};
}
private void setDeviceConfigInt(String key, int val) {
mDeviceConfigKeys.add(key);
doReturn(val).when(mDeviceConfigProperties).getInt(eq(key), anyInt());
@@ -1213,10 +1238,6 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
@Test
public void testAlarmRestrictedByFAS() throws Exception {
final ArgumentCaptor<AppStateTrackerImpl.Listener> listenerArgumentCaptor =
ArgumentCaptor.forClass(AppStateTrackerImpl.Listener.class);
verify(mAppStateTracker).addListener(listenerArgumentCaptor.capture());
final PendingIntent alarmPi = getNewMockPendingIntent();
when(mAppStateTracker.areAlarmsRestricted(TEST_CALLING_UID,
TEST_CALLING_PACKAGE)).thenReturn(true);
@@ -1231,7 +1252,7 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
mTestTimer.expire();
assertNotNull(restrictedAlarms.get(TEST_CALLING_UID));
listenerArgumentCaptor.getValue().unblockAlarmsForUid(TEST_CALLING_UID);
mListener.unblockAlarmsForUid(TEST_CALLING_UID);
verify(alarmPi).send(eq(mMockContext), eq(0), any(Intent.class), any(),
any(Handler.class), isNull(), any());
assertNull(restrictedAlarms.get(TEST_CALLING_UID));
@@ -1239,11 +1260,6 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
@Test
public void alarmsRemovedOnAppStartModeDisabled() {
final ArgumentCaptor<AppStateTrackerImpl.Listener> listenerArgumentCaptor =
ArgumentCaptor.forClass(AppStateTrackerImpl.Listener.class);
verify(mAppStateTracker).addListener(listenerArgumentCaptor.capture());
final AppStateTrackerImpl.Listener listener = listenerArgumentCaptor.getValue();
final PendingIntent alarmPi1 = getNewMockPendingIntent();
final PendingIntent alarmPi2 = getNewMockPendingIntent();
@@ -1254,7 +1270,7 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
when(mActivityManagerInternal.isAppStartModeDisabled(TEST_CALLING_UID,
TEST_CALLING_PACKAGE)).thenReturn(true);
listener.removeAlarmsForUid(TEST_CALLING_UID);
mListener.removeAlarmsForUid(TEST_CALLING_UID);
assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
}
@@ -1305,9 +1321,8 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
@Test
public void alarmCountOnSetPi() {
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());
setTestAlarm(ALARM_TYPES[i % 4], mNowElapsedTest + i, getNewMockPendingIntent());
assertEquals(i, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
}
}
@@ -1315,13 +1330,9 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
@Test
public void alarmCountOnSetListener() {
final int numAlarms = 103;
final int[] types = {RTC_WAKEUP, RTC, ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME};
for (int i = 1; i <= numAlarms; i++) {
setTestAlarmWithListener(types[i % 4], mNowElapsedTest + i, new IAlarmListener.Stub() {
@Override
public void doAlarm(IAlarmCompleteListener callback) throws RemoteException {
}
});
setTestAlarmWithListener(ALARM_TYPES[i % 4], mNowElapsedTest + i,
getNewListener(() -> {}));
assertEquals(i, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
}
}
@@ -1346,12 +1357,7 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
final int numAlarms = 8; // This test is slow
for (int i = 0; i < numAlarms; i++) {
setTestAlarmWithListener(ELAPSED_REALTIME, mNowElapsedTest + i + 10,
new IAlarmListener.Stub() {
@Override
public void doAlarm(IAlarmCompleteListener callback)
throws RemoteException {
}
});
getNewListener(() -> {}));
}
int expired = 0;
while (expired < numAlarms) {
@@ -1384,12 +1390,9 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
public void alarmCountOnExceptionWhileCallingListener() throws Exception {
final int numAlarms = 5; // This test is slow
for (int i = 0; i < numAlarms; i++) {
final IAlarmListener listener = new IAlarmListener.Stub() {
@Override
public void doAlarm(IAlarmCompleteListener callback) throws RemoteException {
throw new RemoteException("For testing behavior on exception");
}
};
final IAlarmListener listener = getNewListener(() -> {
throw new RuntimeException("For testing behavior on exception");
});
setTestAlarmWithListener(ELAPSED_REALTIME, mNowElapsedTest + i + 10, listener);
}
int expired = 0;
@@ -1476,7 +1479,7 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
@Test
public void alarmTypes() throws Exception {
final int[] typesToSet = {ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME, RTC_WAKEUP, RTC};
final int[] typesToSet = ALARM_TYPES;
final int[] typesExpected = {ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME,
ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME};
assertAlarmTypeConversion(typesToSet, typesExpected);
@@ -1515,11 +1518,7 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
final int numAlarms = 10;
final IAlarmListener[] listeners = new IAlarmListener[numAlarms];
for (int i = 0; i < numAlarms; i++) {
listeners[i] = new IAlarmListener.Stub() {
@Override
public void doAlarm(IAlarmCompleteListener callback) throws RemoteException {
}
};
listeners[i] = getNewListener(() -> {});
setTestAlarmWithListener(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + i, listeners[i]);
}
assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
@@ -1562,13 +1561,10 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
final int numAlarms = 5;
final AtomicInteger alarmsFired = new AtomicInteger(0);
for (int i = 0; i < numAlarms; i++) {
final IAlarmListener listener = new IAlarmListener.Stub() {
@Override
public void doAlarm(IAlarmCompleteListener callback) throws RemoteException {
alarmsFired.incrementAndGet();
mService.mPendingNonWakeupAlarms.clear();
}
};
final IAlarmListener listener = getNewListener(() -> {
alarmsFired.incrementAndGet();
mService.mPendingNonWakeupAlarms.clear();
});
setTestAlarmWithListener(ELAPSED_REALTIME, mNowElapsedTest + i + 5, listener);
}
doReturn(true).when(mService).checkAllowNonWakeupDelayLocked(anyLong());
@@ -1956,11 +1952,6 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
@Test
public void batterySaverThrottling() {
final ArgumentCaptor<AppStateTrackerImpl.Listener> listenerArgumentCaptor =
ArgumentCaptor.forClass(AppStateTrackerImpl.Listener.class);
verify(mAppStateTracker).addListener(listenerArgumentCaptor.capture());
final AppStateTrackerImpl.Listener listener = listenerArgumentCaptor.getValue();
when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID,
TEST_CALLING_PACKAGE)).thenReturn(true);
@@ -1970,12 +1961,12 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID,
TEST_CALLING_PACKAGE)).thenReturn(false);
listener.updateAllAlarms();
mListener.updateAllAlarms();
assertEquals(mNowElapsedTest + 7, mTestTimer.getElapsed());
when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID,
TEST_CALLING_PACKAGE)).thenReturn(true);
listener.updateAlarmsForUid(TEST_CALLING_UID);
mListener.updateAlarmsForUid(TEST_CALLING_UID);
assertEquals(mNowElapsedTest + INDEFINITE_DELAY, mTestTimer.getElapsed());
}
@@ -2229,6 +2220,7 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
private void mockChangeEnabled(long changeId, boolean enabled) {
doReturn(enabled).when(() -> CompatChanges.isChangeEnabled(eq(changeId), anyString(),
any(UserHandle.class)));
doReturn(enabled).when(() -> CompatChanges.isChangeEnabled(eq(changeId), anyInt()));
}
@Test
@@ -3753,6 +3745,67 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase {
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.removeListenerAlarmsForCachedUid(TEST_CALLING_UID);
assertEquals(7, mService.mAlarmStore.size());
mListener.removeListenerAlarmsForCachedUid(TEST_CALLING_UID_2);
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.removeListenerAlarmsForCachedUid(TEST_CALLING_UID);
assertEquals(3, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
mListener.removeListenerAlarmsForCachedUid(TEST_CALLING_UID_2);
assertEquals(2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2));
}
@Override
public void afterSessionFinished() {
LocalServices.removeServiceForTest(AlarmManagerInternal.class);