Merge "Gating USE_EXACT_ALARM by target sdk T" into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d03d400d8f
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user