Merge "Remove exact listener alarms when uid gets cached"
This commit is contained in:
committed by
Android (Google) Code Review
commit
a84d1c11bc
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user