diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java index 394be6ef11ca2..26c0eef5542dc 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -30,6 +30,9 @@ import static android.app.AlarmManager.INTERVAL_DAY; import static android.app.AlarmManager.INTERVAL_HOUR; import static android.app.AlarmManager.RTC; import static android.app.AlarmManager.RTC_WAKEUP; +import static android.content.PermissionChecker.PERMISSION_GRANTED; +import static android.content.PermissionChecker.PID_UNKNOWN; +import static android.content.PermissionChecker.checkPermissionForPreflight; import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import static android.os.PowerExemptionManager.REASON_ALARM_MANAGER_ALARM_CLOCK; import static android.os.PowerExemptionManager.REASON_DENIED; @@ -87,11 +90,9 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.PermissionChecker; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.UserPackage; -import android.database.ContentObserver; import android.net.Uri; import android.os.BatteryManager; import android.os.BatteryStatsInternal; @@ -182,7 +183,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; -import java.util.List; import java.util.Locale; import java.util.Set; import java.util.TimeZone; @@ -269,7 +269,8 @@ public class AlarmManagerService extends SystemService { /** * A map from uid to the last op-mode we have seen for - * {@link AppOpsManager#OP_SCHEDULE_EXACT_ALARM} + * {@link AppOpsManager#OP_SCHEDULE_EXACT_ALARM}. Used for evaluating permission state change + * when the denylist changes. */ @VisibleForTesting @GuardedBy("mLock") @@ -2097,20 +2098,31 @@ public class AlarmManagerService extends SystemService { if (oldMode == newMode) { return; } - final boolean allowedByDefault = - isScheduleExactAlarmAllowedByDefault(packageName, uid); + final boolean deniedByDefault = isScheduleExactAlarmDeniedByDefault( + packageName, UserHandle.getUserId(uid)); final boolean hadPermission; - if (oldMode != AppOpsManager.MODE_DEFAULT) { - hadPermission = (oldMode == AppOpsManager.MODE_ALLOWED); - } else { - hadPermission = allowedByDefault; - } final boolean hasPermission; - if (newMode != AppOpsManager.MODE_DEFAULT) { - hasPermission = (newMode == AppOpsManager.MODE_ALLOWED); + + if (deniedByDefault) { + final boolean permissionState = getContext().checkPermission( + Manifest.permission.SCHEDULE_EXACT_ALARM, PID_UNKNOWN, + uid) == PackageManager.PERMISSION_GRANTED; + hadPermission = (oldMode == AppOpsManager.MODE_DEFAULT) + ? permissionState + : (oldMode == AppOpsManager.MODE_ALLOWED); + hasPermission = (newMode == AppOpsManager.MODE_DEFAULT) + ? permissionState + : (newMode == AppOpsManager.MODE_ALLOWED); } else { - hasPermission = allowedByDefault; + final boolean allowedByDefault = + !mConstants.EXACT_ALARM_DENY_LIST.contains(packageName); + hadPermission = (oldMode == AppOpsManager.MODE_DEFAULT) + ? allowedByDefault + : (oldMode == AppOpsManager.MODE_ALLOWED); + hasPermission = (newMode == AppOpsManager.MODE_DEFAULT) + ? allowedByDefault + : (newMode == AppOpsManager.MODE_ALLOWED); } if (hadPermission && !hasPermission) { @@ -2754,41 +2766,13 @@ public class AlarmManagerService extends SystemService { 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); - } - - /** - * Returns whether SCHEDULE_EXACT_ALARM is allowed by default. - */ - boolean isScheduleExactAlarmAllowedByDefault(String packageName, int uid) { - if (isScheduleExactAlarmDeniedByDefault(packageName, UserHandle.getUserId(uid))) { - - // This is essentially like changing the protection level of the permission to - // (privileged|signature|role|appop), but have to implement this logic to maintain - // compatibility for older apps. - if (mPackageManagerInternal.isPlatformSigned(packageName) - || mPackageManagerInternal.isUidPrivileged(uid)) { - return true; - } - final long token = Binder.clearCallingIdentity(); - try { - final List wellbeingHolders = (mRoleManager != null) - ? mRoleManager.getRoleHolders(RoleManager.ROLE_SYSTEM_WELLBEING) - : Collections.emptyList(); - return wellbeingHolders.contains(packageName); - } finally { - Binder.restoreCallingIdentity(token); - } - } - return !mConstants.EXACT_ALARM_DENY_LIST.contains(packageName); + && (checkPermissionForPreflight(getContext(), Manifest.permission.USE_EXACT_ALARM, + PID_UNKNOWN, uid, packageName) == PERMISSION_GRANTED); } boolean hasScheduleExactAlarmInternal(String packageName, int uid) { 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 boolean hasPermission; @@ -2796,11 +2780,16 @@ public class AlarmManagerService extends SystemService { hasPermission = false; } else if (!isExactAlarmChangeEnabled(packageName, UserHandle.getUserId(uid))) { hasPermission = false; + } else if (isScheduleExactAlarmDeniedByDefault(packageName, UserHandle.getUserId(uid))) { + hasPermission = (checkPermissionForPreflight(getContext(), + Manifest.permission.SCHEDULE_EXACT_ALARM, PID_UNKNOWN, uid, packageName) + == PERMISSION_GRANTED); } else { + // Compatibility permission check for older apps. final int mode = mAppOps.checkOpNoThrow(AppOpsManager.OP_SCHEDULE_EXACT_ALARM, uid, packageName); if (mode == AppOpsManager.MODE_DEFAULT) { - hasPermission = isScheduleExactAlarmAllowedByDefault(packageName, uid); + hasPermission = !mConstants.EXACT_ALARM_DENY_LIST.contains(packageName); } else { hasPermission = (mode == AppOpsManager.MODE_ALLOWED); } @@ -4685,10 +4674,6 @@ public class AlarmManagerService extends SystemService { return service.new ClockReceiver(); } - void registerContentObserver(ContentObserver contentObserver, Uri uri) { - mContext.getContentResolver().registerContentObserver(uri, false, contentObserver); - } - void registerDeviceConfigListener(DeviceConfig.OnPropertiesChangedListener listener) { DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ALARM_MANAGER, AppSchedulingModuleThread.getExecutor(), listener); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 479ea4e7b46ba..70a1354e3046c 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -5303,12 +5303,12 @@ {@link android.Manifest.permission#USE_EXACT_ALARM} once it targets API {@link android.os.Build.VERSION_CODES#TIRAMISU}. All apps using exact alarms for secondary features (which should still be user facing) should continue using this permission. -

Protection level: appop +

Protection level: signature|privileged|appop --> + android:protectionLevel="signature|privileged|appop"/> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 5d303cfb2a85e..0faf62e03b145 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -321,6 +321,7 @@ applications that come with the platform + diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java index e7e26a1268e06..174141101dfc2 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java @@ -28,7 +28,6 @@ import static android.app.AlarmManager.FLAG_STANDALONE; import static android.app.AlarmManager.FLAG_WAKE_FROM_IDLE; import static android.app.AlarmManager.RTC; import static android.app.AlarmManager.RTC_WAKEUP; -import static android.app.AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT; import static android.app.AlarmManager.WINDOW_EXACT; import static android.app.AlarmManager.WINDOW_HEURISTIC; import static android.app.AppOpsManager.MODE_ALLOWED; @@ -126,7 +125,6 @@ import android.app.IAlarmListener; import android.app.IAlarmManager; import android.app.PendingIntent; import android.app.compat.CompatChanges; -import android.app.role.RoleManager; import android.app.tare.EconomyManager; import android.app.usage.UsageStatsManagerInternal; import android.content.ContentResolver; @@ -134,7 +132,6 @@ import android.content.Context; import android.content.Intent; import android.content.PermissionChecker; import android.content.pm.PackageManagerInternal; -import android.database.ContentObserver; import android.net.Uri; import android.os.BatteryManager; import android.os.Bundle; @@ -192,7 +189,6 @@ import org.mockito.quality.Strictness; import org.mockito.stubbing.Answer; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -246,8 +242,6 @@ public final class AlarmManagerServiceTest { @Mock private PackageManagerInternal mPackageManagerInternal; @Mock - private RoleManager mRoleManager; - @Mock private AppStateTrackerImpl mAppStateTracker; @Mock private AlarmManagerService.ClockReceiver mClockReceiver; @@ -392,11 +386,6 @@ public final class AlarmManagerServiceTest { return mWakeLock; } - @Override - void registerContentObserver(ContentObserver observer, Uri uri) { - // Do nothing. - } - @Override void registerDeviceConfigListener(DeviceConfig.OnPropertiesChangedListener listener) { // Do nothing. @@ -484,10 +473,12 @@ public final class AlarmManagerServiceTest { doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when( () -> PermissionChecker.checkPermissionForPreflight(any(), eq(Manifest.permission.USE_EXACT_ALARM), anyInt(), anyInt(), anyString())); + doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when( + () -> PermissionChecker.checkPermissionForPreflight(any(), eq(SCHEDULE_EXACT_ALARM), + anyInt(), anyInt(), anyString())); when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager); when(mMockContext.getSystemService(BatteryManager.class)).thenReturn(mBatteryManager); - when(mMockContext.getSystemService(RoleManager.class)).thenReturn(mRoleManager); registerAppIds(new String[]{TEST_CALLING_PACKAGE}, new Integer[]{UserHandle.getAppId(TEST_CALLING_UID)}); @@ -2181,40 +2172,6 @@ public final class AlarmManagerServiceTest { } } - @Test - public void hasScheduleExactAlarmBinderCallNotDenyListed() throws RemoteException { - mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - - mockScheduleExactAlarmState(true, false, MODE_DEFAULT); - assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - - mockScheduleExactAlarmState(true, false, MODE_ALLOWED); - assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - - mockScheduleExactAlarmState(true, false, MODE_ERRORED); - assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - - mockScheduleExactAlarmState(true, false, MODE_IGNORED); - assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - } - - @Test - public void hasScheduleExactAlarmBinderCallDenyListed() throws RemoteException { - mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - - mockScheduleExactAlarmState(true, true, MODE_ERRORED); - assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - - mockScheduleExactAlarmState(true, true, MODE_DEFAULT); - assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - - mockScheduleExactAlarmState(true, true, MODE_IGNORED); - assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - - mockScheduleExactAlarmState(true, true, MODE_ALLOWED); - assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - } - private void mockChangeEnabled(long changeId, boolean enabled) { doReturn(enabled).when(() -> CompatChanges.isChangeEnabled(eq(changeId), anyString(), any(UserHandle.class))); @@ -2222,16 +2179,62 @@ public final class AlarmManagerServiceTest { } @Test - public void hasScheduleExactAlarmBinderCallNotDeclared() throws RemoteException { + public void hasScheduleExactAlarmBinderCall() throws RemoteException { + mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); + mockChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true); + + mockScheduleExactAlarmState(true); + assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); + + mockScheduleExactAlarmState(false); + assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); + } + + @Test + public void hasScheduleExactAlarmBinderCallNotDenyListedPreT() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - mockScheduleExactAlarmState(false, false, MODE_DEFAULT); + mockScheduleExactAlarmStatePreT(true, false, MODE_DEFAULT); + assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); + + mockScheduleExactAlarmStatePreT(true, false, MODE_ALLOWED); + assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); + + mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED); assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - mockScheduleExactAlarmState(false, false, MODE_ALLOWED); + mockScheduleExactAlarmStatePreT(true, false, MODE_IGNORED); + assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); + } + + @Test + public void hasScheduleExactAlarmBinderCallDenyListedPreT() throws RemoteException { + mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); + + mockScheduleExactAlarmStatePreT(true, true, MODE_ERRORED); assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); - mockScheduleExactAlarmState(false, true, MODE_ALLOWED); + mockScheduleExactAlarmStatePreT(true, true, MODE_DEFAULT); + assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); + + mockScheduleExactAlarmStatePreT(true, true, MODE_IGNORED); + assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); + + mockScheduleExactAlarmStatePreT(true, true, MODE_ALLOWED); + assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); + } + + @Test + public void hasScheduleExactAlarmBinderCallNotDeclaredPreT() throws RemoteException { + mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); + + mockScheduleExactAlarmStatePreT(false, false, MODE_DEFAULT); + assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); + + mockScheduleExactAlarmStatePreT(false, false, MODE_ALLOWED); + assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); + + mockScheduleExactAlarmStatePreT(false, true, MODE_ALLOWED); assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER)); } @@ -2240,61 +2243,94 @@ public final class AlarmManagerServiceTest { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false); // canScheduleExactAlarms should be true regardless of any permission state. - mockUseExactAlarmState(true); + // Both SEA and UEA are denied in setUp. assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); mockUseExactAlarmState(false); assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); - mockScheduleExactAlarmState(false, true, MODE_DEFAULT); - assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); - - mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mockScheduleExactAlarmState(false); assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); } @Test - public void canScheduleExactAlarmsBinderCall() throws RemoteException { + public void canScheduleExactAlarmsBinderCallPreT() 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. - mockScheduleExactAlarmState(true, true, MODE_DEFAULT); + mockScheduleExactAlarmStatePreT(true, true, MODE_DEFAULT); assertFalse(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); // No permission, no exemption. - mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED); assertFalse(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); // Policy permission only, no exemption. - mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED); mockUseExactAlarmState(true); assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); mockUseExactAlarmState(false); // User permission only, no exemption. - mockScheduleExactAlarmState(true, false, MODE_DEFAULT); + mockScheduleExactAlarmStatePreT(true, false, MODE_DEFAULT); assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); // User permission only, no exemption. - mockScheduleExactAlarmState(true, true, MODE_ALLOWED); + mockScheduleExactAlarmStatePreT(true, true, MODE_ALLOWED); assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); // No permission, exemption. - mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED); when(mDeviceIdleInternal.isAppOnWhitelist(TEST_CALLING_UID)).thenReturn(true); assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); // No permission, exemption. - mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mockScheduleExactAlarmStatePreT(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 permissions and exemption. - mockScheduleExactAlarmState(true, false, MODE_ALLOWED); + mockScheduleExactAlarmStatePreT(true, false, MODE_ALLOWED); + mockUseExactAlarmState(true); + assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); + } + + @Test + public void canScheduleExactAlarmsBinderCall() throws RemoteException { + // Both permissions are denied in setUp(). + mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); + mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true); + mockChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true); + + // No permission, no exemption. + assertFalse(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); + + // Policy permission only, no exemption. + mockUseExactAlarmState(true); + assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); + + mockUseExactAlarmState(false); + + // User permission only, no exemption. + mockScheduleExactAlarmState(true); + assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); + + // No permission, exemption. + mockScheduleExactAlarmState(false); + when(mDeviceIdleInternal.isAppOnWhitelist(TEST_CALLING_UID)).thenReturn(true); + assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); + + // No permission, core uid exemption. + when(mDeviceIdleInternal.isAppOnWhitelist(TEST_CALLING_UID)).thenReturn(false); + doReturn(true).when(() -> UserHandle.isCore(TEST_CALLING_UID)); + assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); + + // Both permissions and core uid exemption. + mockScheduleExactAlarmState(true); mockUseExactAlarmState(true); assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE)); } @@ -2404,8 +2440,9 @@ public final class AlarmManagerServiceTest { @Test public void alarmClockBinderCallWithSEAPermission() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); + mockChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true); - mockScheduleExactAlarmState(true, false, MODE_ALLOWED); + mockScheduleExactAlarmState(true); final PendingIntent alarmPi = getNewMockPendingIntent(); final AlarmManager.AlarmClockInfo alarmClock = mock(AlarmManager.AlarmClockInfo.class); @@ -2431,9 +2468,10 @@ public final class AlarmManagerServiceTest { public void alarmClockBinderCallWithUEAPermission() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true); + mockChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true); mockUseExactAlarmState(true); - mockScheduleExactAlarmState(false, false, MODE_ERRORED); + mockScheduleExactAlarmState(false); final PendingIntent alarmPi = getNewMockPendingIntent(); final AlarmManager.AlarmClockInfo alarmClock = mock(AlarmManager.AlarmClockInfo.class); @@ -2455,7 +2493,7 @@ public final class AlarmManagerServiceTest { assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type); } - private void mockScheduleExactAlarmState(boolean declared, boolean denyList, int mode) { + private void mockScheduleExactAlarmStatePreT(boolean declared, boolean denyList, int mode) { String[] requesters = declared ? new String[]{TEST_CALLING_PACKAGE} : EmptyArray.STRING; when(mPermissionManagerInternal.getAppOpPermissionPackages(SCHEDULE_EXACT_ALARM)) .thenReturn(requesters); @@ -2470,6 +2508,20 @@ public final class AlarmManagerServiceTest { TEST_CALLING_PACKAGE)).thenReturn(mode); } + private void mockScheduleExactAlarmState(boolean granted) { + String[] requesters = granted ? new String[]{TEST_CALLING_PACKAGE} : EmptyArray.STRING; + when(mPermissionManagerInternal.getAppOpPermissionPackages(SCHEDULE_EXACT_ALARM)) + .thenReturn(requesters); + mService.refreshExactAlarmCandidates(); + + final int result = granted ? PermissionChecker.PERMISSION_GRANTED + : PermissionChecker.PERMISSION_HARD_DENIED; + doReturn(result).when( + () -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext), + eq(SCHEDULE_EXACT_ALARM), anyInt(), eq(TEST_CALLING_UID), + eq(TEST_CALLING_PACKAGE))); + } + private void mockUseExactAlarmState(boolean granted) { final int result = granted ? PermissionChecker.PERMISSION_GRANTED : PermissionChecker.PERMISSION_HARD_DENIED; @@ -2483,7 +2535,7 @@ public final class AlarmManagerServiceTest { public void alarmClockBinderCallWithoutPermission() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED); when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true); final PendingIntent alarmPi = getNewMockPendingIntent(); @@ -2504,8 +2556,9 @@ public final class AlarmManagerServiceTest { @Test public void exactBinderCallWithSEAPermission() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); + mockChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true); - mockScheduleExactAlarmState(true, false, MODE_ALLOWED); + mockScheduleExactAlarmState(true); final PendingIntent alarmPi = getNewMockPendingIntent(); mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0, 0, alarmPi, null, null, null, null); @@ -2529,9 +2582,10 @@ public final class AlarmManagerServiceTest { public void exactBinderCallWithUEAPermission() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true); + mockChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true); mockUseExactAlarmState(true); - mockScheduleExactAlarmState(false, false, MODE_ERRORED); + mockScheduleExactAlarmState(false); final PendingIntent alarmPi = getNewMockPendingIntent(); mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0, 0, alarmPi, null, null, null, null); @@ -2555,7 +2609,7 @@ public final class AlarmManagerServiceTest { public void exactBinderCallWithAllowlist() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); // If permission is denied, only then allowlist will be checked. - mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED); when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true); final PendingIntent alarmPi = getNewMockPendingIntent(); @@ -2575,7 +2629,7 @@ public final class AlarmManagerServiceTest { public void exactAllowWhileIdleBinderCallWithSEAPermission() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - mockScheduleExactAlarmState(true, false, MODE_ALLOWED); + mockScheduleExactAlarmStatePreT(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); @@ -2601,7 +2655,7 @@ public final class AlarmManagerServiceTest { mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true); mockUseExactAlarmState(true); - mockScheduleExactAlarmState(false, false, MODE_ERRORED); + mockScheduleExactAlarmStatePreT(false, false, MODE_ERRORED); 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); @@ -2625,7 +2679,7 @@ public final class AlarmManagerServiceTest { public void exactAllowWhileIdleBinderCallWithAllowlist() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); // If permission is denied, only then allowlist will be checked. - mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED); when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true); final PendingIntent alarmPi = getNewMockPendingIntent(); @@ -2651,7 +2705,7 @@ public final class AlarmManagerServiceTest { public void exactBinderCallsWithoutPermissionWithoutAllowlist() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED); when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(false); final PendingIntent alarmPi = getNewMockPendingIntent(); @@ -2701,7 +2755,7 @@ public final class AlarmManagerServiceTest { public void binderCallWithUserAllowlist() throws RemoteException { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); - mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED); when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true); when(mAppStateTracker.isUidPowerSaveUserExempt(TEST_CALLING_UID)).thenReturn(true); @@ -3026,7 +3080,7 @@ public final class AlarmManagerServiceTest { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ALLOWED); - mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED); mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE); assertAndHandleMessageSync(REMOVE_EXACT_ALARMS); @@ -3039,7 +3093,7 @@ public final class AlarmManagerServiceTest { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false); mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ALLOWED); - mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED); mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE); @@ -3052,7 +3106,7 @@ public final class AlarmManagerServiceTest { mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false); mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ERRORED); - mockScheduleExactAlarmState(true, true, MODE_DEFAULT); + mockScheduleExactAlarmStatePreT(true, true, MODE_DEFAULT); mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE); @@ -3068,7 +3122,7 @@ public final class AlarmManagerServiceTest { when(mActivityManagerInternal.getBootTimeTempAllowListDuration()).thenReturn(durationMs); mService.mLastOpScheduleExactAlarm.put(TEST_CALLING_UID, MODE_ERRORED); - mockScheduleExactAlarmState(true, false, MODE_ALLOWED); + mockScheduleExactAlarmStatePreT(true, false, MODE_ALLOWED); mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE); final ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); @@ -3328,7 +3382,7 @@ public final class AlarmManagerServiceTest { .putExtra(Intent.EXTRA_REPLACING, true); mockUseExactAlarmState(false); - mockScheduleExactAlarmState(true, false, MODE_ALLOWED); + mockScheduleExactAlarmStatePreT(true, false, MODE_ALLOWED); mPackageChangesReceiver.onReceive(mMockContext, packageReplacedIntent); assertAndHandleMessageSync(CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE); @@ -3336,7 +3390,7 @@ public final class AlarmManagerServiceTest { assertEquals(5, mService.mAlarmStore.size()); mockUseExactAlarmState(true); - mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED); mPackageChangesReceiver.onReceive(mMockContext, packageReplacedIntent); assertAndHandleMessageSync(CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE); @@ -3344,7 +3398,7 @@ public final class AlarmManagerServiceTest { assertEquals(5, mService.mAlarmStore.size()); mockUseExactAlarmState(false); - mockScheduleExactAlarmState(true, false, MODE_ERRORED); + mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED); mPackageChangesReceiver.onReceive(mMockContext, packageReplacedIntent); assertAndHandleMessageSync(CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE); @@ -3362,55 +3416,6 @@ public final class AlarmManagerServiceTest { assertEquals(0, remaining.size()); } - @Test - public void isScheduleExactAlarmAllowedByDefault() { - final String package1 = "priv"; - final String package2 = "signed"; - final String package3 = "normal"; - final String package4 = "wellbeing"; - final int uid1 = 1294; - final int uid2 = 8321; - final int uid3 = 3412; - final int uid4 = 4591; - - when(mPackageManagerInternal.isUidPrivileged(uid1)).thenReturn(true); - when(mPackageManagerInternal.isUidPrivileged(uid2)).thenReturn(false); - when(mPackageManagerInternal.isUidPrivileged(uid3)).thenReturn(false); - when(mPackageManagerInternal.isUidPrivileged(uid4)).thenReturn(false); - - when(mPackageManagerInternal.isPlatformSigned(package1)).thenReturn(false); - when(mPackageManagerInternal.isPlatformSigned(package2)).thenReturn(true); - when(mPackageManagerInternal.isPlatformSigned(package3)).thenReturn(false); - when(mPackageManagerInternal.isPlatformSigned(package4)).thenReturn(false); - - when(mRoleManager.getRoleHolders(RoleManager.ROLE_SYSTEM_WELLBEING)).thenReturn( - Arrays.asList(package4)); - - mockChangeEnabled(SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, false); - mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[]{ - package1, - package3, - }); - - // Deny listed packages will be false. - assertFalse(mService.isScheduleExactAlarmAllowedByDefault(package1, uid1)); - assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package2, uid2)); - assertFalse(mService.isScheduleExactAlarmAllowedByDefault(package3, uid3)); - assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package4, uid4)); - - mockChangeEnabled(SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true); - mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[]{ - package1, - package3, - }); - - // Deny list doesn't matter now, only exemptions should be true. - assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package1, uid1)); - assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package2, uid2)); - assertFalse(mService.isScheduleExactAlarmAllowedByDefault(package3, uid3)); - assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package4, uid4)); - } - @Test public void alarmScheduledAtomPushed() { for (int i = 0; i < 10; i++) { @@ -3510,7 +3515,7 @@ public final class AlarmManagerServiceTest { } @Test - public void hasUseExactAlarmPermission() { + public void hasUseExactAlarmInternal() { mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true); mockUseExactAlarmState(true); @@ -3521,7 +3526,7 @@ public final class AlarmManagerServiceTest { } @Test - public void hasUseExactAlarmPermissionChangeDisabled() { + public void hasUseExactAlarmInternalChangeDisabled() { mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, false); mockUseExactAlarmState(true); @@ -3531,6 +3536,49 @@ public final class AlarmManagerServiceTest { assertFalse(mService.hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID)); } + @Test + public void hasScheduleExactAlarmInternal() { + mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); + mockChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true); + + mockScheduleExactAlarmState(false); + assertFalse(mService.hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID)); + + mockScheduleExactAlarmState(true); + assertTrue(mService.hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID)); + } + + @Test + public void hasScheduleExactAlarmInternalPreT() { + mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true); + mockChangeEnabled(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, false); + + mockScheduleExactAlarmStatePreT(true, true, MODE_DEFAULT); + assertFalse(mService.hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID)); + + mockScheduleExactAlarmStatePreT(false, false, MODE_ALLOWED); + assertFalse(mService.hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID)); + + mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED); + assertFalse(mService.hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID)); + + mockScheduleExactAlarmStatePreT(true, false, MODE_ALLOWED); + assertTrue(mService.hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID)); + } + + @Test + public void hasScheduleExactAlarmInternalPreS() { + mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, false); + + mockScheduleExactAlarmState(true); + mockScheduleExactAlarmStatePreT(true, false, MODE_ALLOWED); + assertFalse(mService.hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID)); + + mockScheduleExactAlarmState(false); + mockScheduleExactAlarmStatePreT(true, false, MODE_ERRORED); + assertFalse(mService.hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID)); + } + @Test public void temporaryQuotaReserve_hasQuota() { final int quotaToFill = 5;