Merge "Gating USE_EXACT_ALARM by target sdk T" into tm-dev

This commit is contained in:
Suprabh Shukla
2022-03-30 22:08:03 +00:00
committed by Android (Google) Code Review
6 changed files with 218 additions and 134 deletions

View File

@@ -270,6 +270,16 @@ public class AlarmManager {
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
public static final long ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS = 185199076L;
/**
* For apps targeting {@link Build.VERSION_CODES#TIRAMISU} or above, certain kinds of apps can
* use {@link Manifest.permission#USE_EXACT_ALARM} to schedule exact alarms.
*
* @hide
*/
@ChangeId
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
public static final long ENABLE_USE_EXACT_ALARM = 218533173L;
@UnsupportedAppUsage
private final IAlarmManager mService;
private final Context mContext;

View File

@@ -1827,30 +1827,9 @@ public class AlarmManagerService extends SystemService {
newAppIds.add(UserHandle.getAppId(uid));
}
}
final ArraySet<Integer> removed = new ArraySet<>(mExactAlarmCandidates);
removed.removeAll(newAppIds);
// This code is only called on package_added and boot. The set {removed} is only expected to
// be non-empty when a package was updated and it removed the permission from its manifest.
for (int i = 0; i < removed.size(); i++) {
final int removedAppId = removed.valueAt(i);
synchronized (mLock) {
Slog.i(TAG, "App id " + removedAppId + " lost SCHEDULE_EXACT_ALARM on update");
// Some packages may have lost permission to schedule exact alarms on update, their alarms
// will be removed while handling CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE after this.
final Predicate<Alarm> whichAlarms = a -> {
if (UserHandle.getAppId(a.uid) != removedAppId || a.windowLength != 0) {
return false;
}
if (!isExactAlarmChangeEnabled(a.packageName, UserHandle.getUserId(a.uid))) {
return false;
}
if (hasUseExactAlarmPermission(a.packageName, a.uid)) {
return false;
}
return !isExemptFromExactAlarmPermission(a.uid);
};
removeAlarmsInternalLocked(whichAlarms, REMOVE_REASON_EXACT_PERMISSION_REVOKED);
}
}
// No need to lock. Assignment is always atomic.
mExactAlarmCandidates = Collections.unmodifiableSet(newAppIds);
}
@@ -1910,7 +1889,7 @@ public class AlarmManagerService extends SystemService {
|| !isExactAlarmChangeEnabled(packageName, userId)) {
return;
}
if (hasUseExactAlarmPermission(packageName, uid)) {
if (hasUseExactAlarmInternal(packageName, uid)) {
return;
}
@@ -2533,8 +2512,9 @@ public class AlarmManagerService extends SystemService {
}
@Override
public boolean hasScheduleExactAlarm(String packageName, int uid) {
return hasScheduleExactAlarmInternal(packageName, uid);
public boolean hasExactAlarmPermission(String packageName, int uid) {
return hasScheduleExactAlarmInternal(packageName, uid)
|| hasUseExactAlarmInternal(packageName, uid);
}
@Override
@@ -2558,21 +2538,19 @@ public class AlarmManagerService extends SystemService {
return appOpMode == AppOpsManager.MODE_ALLOWED;
}
boolean hasUseExactAlarmPermission(String packageName, int uid) {
return PermissionChecker.checkPermissionForPreflight(getContext(),
boolean hasUseExactAlarmInternal(String packageName, int uid) {
return isUseExactAlarmEnabled(packageName, UserHandle.getUserId(uid))
&& (PermissionChecker.checkPermissionForPreflight(getContext(),
Manifest.permission.USE_EXACT_ALARM, PermissionChecker.PID_UNKNOWN, uid,
packageName) == PermissionChecker.PERMISSION_GRANTED;
packageName) == PermissionChecker.PERMISSION_GRANTED);
}
boolean hasScheduleExactAlarmInternal(String packageName, int uid) {
if (hasUseExactAlarmPermission(packageName, uid)) {
return true;
}
final long start = mStatLogger.getTime();
// Not using getScheduleExactAlarmState as this can avoid some calls to AppOpsService.
// Not using #mLastOpScheduleExactAlarm as it may contain stale values.
// No locking needed as all internal containers being queried are immutable.
final long start = mStatLogger.getTime();
final boolean hasPermission;
if (!mExactAlarmCandidates.contains(UserHandle.getAppId(uid))) {
hasPermission = false;
@@ -2703,7 +2681,8 @@ public class AlarmManagerService extends SystemService {
lowerQuota = allowWhileIdle;
idleOptions = allowWhileIdle ? mOptsWithFgs.toBundle() : null;
}
if (needsPermission && !hasScheduleExactAlarmInternal(callingPackage, callingUid)) {
if (needsPermission && !hasScheduleExactAlarmInternal(callingPackage, callingUid)
&& !hasUseExactAlarmInternal(callingPackage, callingUid)) {
if (!isExemptFromExactAlarmPermission(callingUid)) {
final String errorMessage = "Caller " + callingPackage + " needs to hold "
+ Manifest.permission.SCHEDULE_EXACT_ALARM + " to set "
@@ -2768,7 +2747,8 @@ public class AlarmManagerService extends SystemService {
return true;
}
return isExemptFromExactAlarmPermission(packageUid)
|| hasScheduleExactAlarmInternal(packageName, packageUid);
|| hasScheduleExactAlarmInternal(packageName, packageUid)
|| hasUseExactAlarmInternal(packageName, packageUid);
}
@Override
@@ -2875,6 +2855,11 @@ public class AlarmManagerService extends SystemService {
packageName, UserHandle.of(userId));
}
private static boolean isUseExactAlarmEnabled(String packageName, int userId) {
return CompatChanges.isChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM,
packageName, UserHandle.of(userId));
}
@NeverCompile // Avoid size overhead of debugging code.
void dumpImpl(IndentingPrintWriter pw) {
synchronized (mLock) {
@@ -3784,7 +3769,7 @@ public class AlarmManagerService extends SystemService {
if (!isExactAlarmChangeEnabled(changedPackage, userId)) {
continue;
}
if (hasUseExactAlarmPermission(changedPackage, uid)) {
if (hasUseExactAlarmInternal(changedPackage, uid)) {
continue;
}
final int appOpMode;
@@ -3817,8 +3802,9 @@ public class AlarmManagerService extends SystemService {
}
/**
* Called when an app loses {@link Manifest.permission#SCHEDULE_EXACT_ALARM} to remove alarms
* that the app is no longer eligible to use.
* Called when an app loses the permission to use exact alarms. This will happen when the app
* no longer has either {@link Manifest.permission#SCHEDULE_EXACT_ALARM} or
* {@link Manifest.permission#USE_EXACT_ALARM}.
*
* This is not expected to get called frequently.
*/
@@ -3828,7 +3814,8 @@ public class AlarmManagerService extends SystemService {
|| !isExactAlarmChangeEnabled(packageName, UserHandle.getUserId(uid))) {
return;
}
Slog.w(TAG, "Package " + packageName + ", uid " + uid + " lost SCHEDULE_EXACT_ALARM!");
Slog.w(TAG, "Package " + packageName + ", uid " + uid
+ " lost permission to set exact alarms!");
final Predicate<Alarm> whichAlarms = a -> (a.uid == uid && a.packageName.equals(packageName)
&& a.windowLength == 0);
@@ -4764,7 +4751,8 @@ public class AlarmManagerService extends SystemService {
case CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE:
packageName = (String) msg.obj;
uid = msg.arg1;
if (!hasScheduleExactAlarmInternal(packageName, uid)) {
if (!hasScheduleExactAlarmInternal(packageName, uid)
&& !hasUseExactAlarmInternal(packageName, uid)) {
synchronized (mLock) {
removeExactAlarmsOnPermissionRevokedLocked(uid,
packageName, /*killUid = */false);
@@ -4936,13 +4924,15 @@ public class AlarmManagerService extends SystemService {
mLastOpScheduleExactAlarm.delete(uid);
return;
case Intent.ACTION_PACKAGE_ADDED:
mHandler.sendEmptyMessage(AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES);
if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
// Some apps may lose permission to set exact alarms on update.
// We need to remove their exact alarms.
final String packageUpdated = intent.getData().getSchemeSpecificPart();
mHandler.obtainMessage(
AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE, uid, -1,
packageUpdated).sendToTarget();
}
mHandler.sendEmptyMessage(AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES);
return;
case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);

View File

@@ -1309,7 +1309,7 @@ public class AppStandbyController
return STANDBY_BUCKET_WORKING_SET;
}
if (mInjector.hasScheduleExactAlarm(packageName, UserHandle.getUid(userId, appId))) {
if (mInjector.hasExactAlarmPermission(packageName, UserHandle.getUid(userId, appId))) {
return STANDBY_BUCKET_WORKING_SET;
}
}
@@ -2326,8 +2326,8 @@ public class AppStandbyController
return mWellbeingApp != null && mWellbeingApp.equals(packageName);
}
boolean hasScheduleExactAlarm(String packageName, int uid) {
return mAlarmManagerInternal.hasScheduleExactAlarm(packageName, uid);
boolean hasExactAlarmPermission(String packageName, int uid) {
return mAlarmManagerInternal.hasExactAlarmPermission(packageName, uid);
}
void updatePowerWhitelistCache() {

View File

@@ -44,7 +44,8 @@ public interface AlarmManagerInternal {
/**
* Returns if the given package in the given user holds
* {@link android.Manifest.permission#SCHEDULE_EXACT_ALARM}
* {@link android.Manifest.permission#SCHEDULE_EXACT_ALARM} or
* {@link android.Manifest.permission#USE_EXACT_ALARM}.
*/
boolean hasScheduleExactAlarm(String packageName, int uid);
boolean hasExactAlarmPermission(String packageName, int uid);
}

View File

@@ -58,6 +58,7 @@ import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PERMISSION;
import static com.android.server.alarm.AlarmManagerService.ACTIVE_INDEX;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.APP_STANDBY_BUCKET_CHANGED;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHARGING_STATUS_CHANGED;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.EXACT_ALARM_DENY_LIST_PACKAGES_ADDED;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.EXACT_ALARM_DENY_LIST_PACKAGES_REMOVED;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES;
@@ -1044,9 +1045,19 @@ public class AlarmManagerServiceTest {
final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
verify(mService.mHandler, atLeastOnce()).sendMessageAtTime(messageCaptor.capture(),
anyLong());
final Message lastMessage = messageCaptor.getValue();
assertEquals("Unexpected message send to handler", what, lastMessage.what);
mService.mHandler.handleMessage(lastMessage);
Message expectedMessage = null;
final ArrayList<Integer> sentMessages = new ArrayList<>();
for (Message sentMessage : messageCaptor.getAllValues()) {
if (sentMessage.what == what) {
expectedMessage = sentMessage;
}
sentMessages.add(sentMessage.what);
}
assertNotNull("Unexpected messages sent to handler. Expected: " + what + ", sent: "
+ sentMessages, expectedMessage);
mService.mHandler.handleMessage(expectedMessage);
}
@Test
@@ -2109,16 +2120,16 @@ public class AlarmManagerServiceTest {
public void hasScheduleExactAlarmBinderCallNotDenyListed() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockExactAlarmPermissionGrant(true, false, MODE_DEFAULT);
mockScheduleExactAlarmState(true, false, MODE_DEFAULT);
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED);
mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockExactAlarmPermissionGrant(true, false, MODE_IGNORED);
mockScheduleExactAlarmState(true, false, MODE_IGNORED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
}
@@ -2126,16 +2137,16 @@ public class AlarmManagerServiceTest {
public void hasScheduleExactAlarmBinderCallDenyListed() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockExactAlarmPermissionGrant(true, true, MODE_ERRORED);
mockScheduleExactAlarmState(true, true, MODE_ERRORED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockExactAlarmPermissionGrant(true, true, MODE_DEFAULT);
mockScheduleExactAlarmState(true, true, MODE_DEFAULT);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockExactAlarmPermissionGrant(true, true, MODE_IGNORED);
mockScheduleExactAlarmState(true, true, MODE_IGNORED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockExactAlarmPermissionGrant(true, true, MODE_ALLOWED);
mockScheduleExactAlarmState(true, true, MODE_ALLOWED);
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
}
@@ -2148,13 +2159,13 @@ public class AlarmManagerServiceTest {
public void hasScheduleExactAlarmBinderCallNotDeclared() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockExactAlarmPermissionGrant(false, false, MODE_DEFAULT);
mockScheduleExactAlarmState(false, false, MODE_DEFAULT);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockExactAlarmPermissionGrant(false, false, MODE_ALLOWED);
mockScheduleExactAlarmState(false, false, MODE_ALLOWED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
mockExactAlarmPermissionGrant(false, true, MODE_ALLOWED);
mockScheduleExactAlarmState(false, true, MODE_ALLOWED);
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
}
@@ -2162,10 +2173,17 @@ public class AlarmManagerServiceTest {
public void canScheduleExactAlarmsBinderCallChangeDisabled() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false);
mockExactAlarmPermissionGrant(false, true, MODE_DEFAULT);
// canScheduleExactAlarms should be true regardless of any permission state.
mockUseExactAlarmState(true);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
mockUseExactAlarmState(false);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
mockScheduleExactAlarmState(false, true, MODE_DEFAULT);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
}
@@ -2173,44 +2191,45 @@ public class AlarmManagerServiceTest {
public void canScheduleExactAlarmsBinderCall() throws RemoteException {
// Policy permission is denied in setUp().
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true);
// No permission, no exemption.
mockExactAlarmPermissionGrant(true, true, MODE_DEFAULT);
mockScheduleExactAlarmState(true, true, MODE_DEFAULT);
assertFalse(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// No permission, no exemption.
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
assertFalse(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// Policy permission only, no exemption.
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
doReturn(PermissionChecker.PERMISSION_GRANTED).when(
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
eq(Manifest.permission.USE_EXACT_ALARM), anyInt(), eq(TEST_CALLING_UID),
eq(TEST_CALLING_PACKAGE)));
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mockUseExactAlarmState(true);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// Permission, no exemption.
mockExactAlarmPermissionGrant(true, false, MODE_DEFAULT);
mockUseExactAlarmState(false);
// User permission only, no exemption.
mockScheduleExactAlarmState(true, false, MODE_DEFAULT);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// Permission, no exemption.
mockExactAlarmPermissionGrant(true, true, MODE_ALLOWED);
// User permission only, no exemption.
mockScheduleExactAlarmState(true, true, MODE_ALLOWED);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// No permission, exemption.
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(TEST_CALLING_UID)).thenReturn(true);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// No permission, exemption.
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(TEST_CALLING_UID)).thenReturn(false);
doReturn(true).when(() -> UserHandle.isCore(TEST_CALLING_UID));
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
// Both permission and exemption.
mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED);
// Both permissions and exemption.
mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
mockUseExactAlarmState(true);
assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
}
@@ -2237,6 +2256,8 @@ public class AlarmManagerServiceTest {
verify(mService, never()).hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE,
TEST_CALLING_UID);
verify(mService, never()).hasUseExactAlarmInternal(TEST_CALLING_PACKAGE,
TEST_CALLING_UID);
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
}
@@ -2313,7 +2334,7 @@ public class AlarmManagerServiceTest {
public void alarmClockBinderCall() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED);
mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
final PendingIntent alarmPi = getNewMockPendingIntent();
final AlarmManager.AlarmClockInfo alarmClock = mock(AlarmManager.AlarmClockInfo.class);
@@ -2335,7 +2356,7 @@ public class AlarmManagerServiceTest {
assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
}
private void mockExactAlarmPermissionGrant(boolean declared, boolean denyList, int mode) {
private void mockScheduleExactAlarmState(boolean declared, boolean denyList, int mode) {
String[] requesters = declared ? new String[]{TEST_CALLING_PACKAGE} : EmptyArray.STRING;
when(mPermissionManagerInternal.getAppOpPermissionPackages(SCHEDULE_EXACT_ALARM))
.thenReturn(requesters);
@@ -2350,12 +2371,21 @@ public class AlarmManagerServiceTest {
TEST_CALLING_PACKAGE)).thenReturn(mode);
}
private void mockUseExactAlarmState(boolean granted) {
final int result = granted ? PermissionChecker.PERMISSION_GRANTED
: PermissionChecker.PERMISSION_HARD_DENIED;
doReturn(result).when(
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
eq(Manifest.permission.USE_EXACT_ALARM), anyInt(), eq(TEST_CALLING_UID),
eq(TEST_CALLING_PACKAGE)));
}
@Test
public void alarmClockBinderCallWithoutPermission() throws RemoteException {
setDeviceConfigBoolean(KEY_CRASH_NON_CLOCK_APPS, true);
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
final PendingIntent alarmPi = getNewMockPendingIntent();
@@ -2377,7 +2407,7 @@ public class AlarmManagerServiceTest {
public void exactBinderCallWithPermission() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED);
mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
final PendingIntent alarmPi = getNewMockPendingIntent();
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
0, alarmPi, null, null, null, null);
@@ -2401,7 +2431,7 @@ public class AlarmManagerServiceTest {
public void exactBinderCallWithAllowlist() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
// If permission is denied, only then allowlist will be checked.
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
final PendingIntent alarmPi = getNewMockPendingIntent();
@@ -2421,7 +2451,7 @@ public class AlarmManagerServiceTest {
public void exactAllowWhileIdleBinderCallWithPermission() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED);
mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
final PendingIntent alarmPi = getNewMockPendingIntent();
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
FLAG_ALLOW_WHILE_IDLE, alarmPi, null, null, null, null);
@@ -2444,7 +2474,7 @@ public class AlarmManagerServiceTest {
public void exactAllowWhileIdleBinderCallWithAllowlist() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
// If permission is denied, only then allowlist will be checked.
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
final PendingIntent alarmPi = getNewMockPendingIntent();
@@ -2471,7 +2501,7 @@ public class AlarmManagerServiceTest {
setDeviceConfigBoolean(KEY_CRASH_NON_CLOCK_APPS, true);
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(false);
final PendingIntent alarmPi = getNewMockPendingIntent();
@@ -2503,6 +2533,7 @@ public class AlarmManagerServiceTest {
FLAG_ALLOW_WHILE_IDLE, alarmPi, null, null, null, null);
verify(mService, never()).hasScheduleExactAlarmInternal(anyString(), anyInt());
verify(mService, never()).hasUseExactAlarmInternal(anyString(), anyInt());
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -2520,7 +2551,7 @@ public class AlarmManagerServiceTest {
public void binderCallWithUserAllowlist() throws RemoteException {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
when(mAppStateTracker.isUidPowerSaveUserExempt(TEST_CALLING_UID)).thenReturn(true);
@@ -2792,7 +2823,7 @@ public class AlarmManagerServiceTest {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ALLOWED);
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
assertAndHandleMessageSync(REMOVE_EXACT_ALARMS);
@@ -2805,7 +2836,7 @@ public class AlarmManagerServiceTest {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false);
mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ALLOWED);
mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
@@ -2818,7 +2849,7 @@ public class AlarmManagerServiceTest {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false);
mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ERRORED);
mockExactAlarmPermissionGrant(true, true, MODE_DEFAULT);
mockScheduleExactAlarmState(true, true, MODE_DEFAULT);
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
@@ -2834,7 +2865,7 @@ public class AlarmManagerServiceTest {
when(mActivityManagerInternal.getBootTimeTempAllowListDuration()).thenReturn(durationMs);
mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ERRORED);
mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED);
mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -3035,48 +3066,6 @@ public class AlarmManagerServiceTest {
UserHandle.getUid(userId, unknownAppId)) < 0);
}
@Test
public void refreshExactAlarmCandidatesRemovesExactAlarmsIfNeeded() {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mService.mExactAlarmCandidates = new ArraySet<>(new Integer[]{1, 2, 5});
final String[] updatedRequesters = new String[]{"p11", "p2", "p9"};
final Integer[] appIds = new Integer[]{11, 2, 9};
registerAppIds(updatedRequesters, appIds);
when(mPermissionManagerInternal.getAppOpPermissionPackages(
SCHEDULE_EXACT_ALARM)).thenReturn(updatedRequesters);
final PendingIntent exactAppId1 = getNewMockPendingIntent();
setTestAlarm(ELAPSED_REALTIME, 0, 0, exactAppId1, 0, 0,
UserHandle.getUid(TEST_CALLING_USER, 1), null);
final PendingIntent exactAppId2 = getNewMockPendingIntent();
setTestAlarm(ELAPSED_REALTIME, 0, 0, exactAppId2, 0, 0,
UserHandle.getUid(TEST_CALLING_USER, 2), null);
final PendingIntent exactAppId5 = getNewMockPendingIntent();
setTestAlarm(ELAPSED_REALTIME, 0, 0, exactAppId5, 0, 0,
UserHandle.getUid(TEST_CALLING_USER, 5), null);
final PendingIntent inexactAppId5 = getNewMockPendingIntent();
setTestAlarm(ELAPSED_REALTIME, 0, 23, inexactAppId5, 0, 0,
UserHandle.getUid(TEST_CALLING_USER, 5), null);
assertEquals(4, mService.mAlarmStore.size());
mService.refreshExactAlarmCandidates();
// App ids 1 and 5 lost the permission, so there alarms should be removed.
final ArrayList<Alarm> remaining = mService.mAlarmStore.asList();
assertEquals(2, remaining.size());
assertTrue("Inexact alarm removed",
remaining.removeIf(a -> a.matches(inexactAppId5, null)));
assertTrue("Alarm from app id 2 removed",
remaining.removeIf(a -> a.matches(exactAppId2, null)));
}
@Test
public void refreshExactAlarmCandidatesOnPackageAdded() {
final String[] exactAlarmRequesters = new String[]{"p11", "p2", "p9"};
@@ -3129,6 +3118,78 @@ public class AlarmManagerServiceTest {
assertEquals(new ArraySet<>(appIds), mService.mExactAlarmCandidates);
}
@Test
public void exactAlarmsRemovedIfNeededOnPackageReplaced() {
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true);
final int otherUid = 2313;
final String otherPackage = "p1";
final PendingIntent exactAlarm1 = getNewMockPendingIntent();
setTestAlarm(ELAPSED_REALTIME, 1, 0, exactAlarm1, 0, 0, TEST_CALLING_UID,
TEST_CALLING_PACKAGE, null);
final PendingIntent exactAlarm2 = getNewMockPendingIntent();
setTestAlarm(ELAPSED_REALTIME, 2, 0, exactAlarm2, 0, 0, TEST_CALLING_UID,
TEST_CALLING_PACKAGE, null);
final PendingIntent otherPackageExactAlarm = getNewMockPendingIntent(otherUid,
otherPackage);
setTestAlarm(ELAPSED_REALTIME, 0, 0, otherPackageExactAlarm, 0, 0, otherUid, otherPackage,
null);
final PendingIntent inexactAlarm = getNewMockPendingIntent();
setTestAlarm(ELAPSED_REALTIME, 0, 23, inexactAlarm, 0, 0, TEST_CALLING_UID,
TEST_CALLING_PACKAGE, null);
final PendingIntent otherPackageInexactAlarm = getNewMockPendingIntent(otherUid,
otherPackage);
setTestAlarm(ELAPSED_REALTIME, 0, 23, otherPackageInexactAlarm, 0, 0, otherUid,
otherPackage, null);
assertEquals(5, mService.mAlarmStore.size());
final Intent packageReplacedIntent = new Intent(Intent.ACTION_PACKAGE_ADDED)
.setData(Uri.fromParts("package", TEST_CALLING_PACKAGE, null))
.putExtra(Intent.EXTRA_UID, TEST_CALLING_UID)
.putExtra(Intent.EXTRA_REPLACING, true);
mockUseExactAlarmState(false);
mockScheduleExactAlarmState(true, false, MODE_ALLOWED);
mPackageChangesReceiver.onReceive(mMockContext, packageReplacedIntent);
assertAndHandleMessageSync(CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE);
// user permission is granted, no alarms should be removed
assertEquals(5, mService.mAlarmStore.size());
mockUseExactAlarmState(true);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mPackageChangesReceiver.onReceive(mMockContext, packageReplacedIntent);
assertAndHandleMessageSync(CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE);
// policy permission is granted, no alarms should be removed
assertEquals(5, mService.mAlarmStore.size());
mockUseExactAlarmState(false);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
mPackageChangesReceiver.onReceive(mMockContext, packageReplacedIntent);
assertAndHandleMessageSync(CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE);
// no permission is granted, exact alarms should be removed
assertEquals(3, mService.mAlarmStore.size());
List<Alarm> remaining = mService.mAlarmStore.asList();
assertTrue("Inexact alarm removed", remaining.removeIf(a -> a.matches(inexactAlarm, null)));
assertEquals(2, remaining.size());
assertTrue("Alarms from other package removed",
remaining.removeIf(a -> a.matches(otherPackageExactAlarm, null)
|| a.matches(otherPackageInexactAlarm, null)));
assertEquals(0, remaining.size());
}
@Test
public void alarmScheduledAtomPushed() {
for (int i = 0; i < 10; i++) {
@@ -3187,6 +3248,28 @@ public class AlarmManagerServiceTest {
bOptions.getTemporaryAppAllowlistReasonCode());
}
@Test
public void hasUseExactAlarmPermission() {
mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true);
mockUseExactAlarmState(true);
assertTrue(mService.hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
mockUseExactAlarmState(false);
assertFalse(mService.hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
}
@Test
public void hasUseExactAlarmPermissionChangeDisabled() {
mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, false);
mockUseExactAlarmState(true);
assertFalse(mService.hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
mockUseExactAlarmState(false);
assertFalse(mService.hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID));
}
@After
public void tearDown() {
if (mMockingSession != null) {

View File

@@ -283,7 +283,7 @@ public class AppStandbyControllerTests {
}
@Override
boolean hasScheduleExactAlarm(String packageName, int uid) {
boolean hasExactAlarmPermission(String packageName, int uid) {
return mClockApps.contains(Pair.create(packageName, uid));
}