Loading apex/jobscheduler/framework/java/android/app/AlarmManager.java +13 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; Loading Loading @@ -280,6 +281,18 @@ public class AlarmManager { @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) public static final long ENABLE_USE_EXACT_ALARM = 218533173L; /** * For apps targeting {@link Build.VERSION_CODES#TIRAMISU} or above, the permission * {@link Manifest.permission#SCHEDULE_EXACT_ALARM} will be denied, unless the user explicitly * allows it from Settings. * * TODO (b/226439802): change to EnabledSince(T) after SDK finalization. * @hide */ @ChangeId @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2) public static final long SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = 226439802L; @UnsupportedAppUsage private final IAlarmManager mService; private final Context mContext; Loading apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +137 −34 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ 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.usage.UsageStatsManager; import android.app.usage.UsageStatsManagerInternal; import android.content.BroadcastReceiver; Loading Loading @@ -164,6 +165,7 @@ 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; Loading Loading @@ -224,6 +226,7 @@ public class AlarmManagerService extends SystemService { private ActivityManagerInternal mActivityManagerInternal; private final EconomyManagerInternal mEconomyManagerInternal; private PackageManagerInternal mPackageManagerInternal; private RoleManager mRoleManager; private volatile PermissionManagerServiceInternal mLocalPermissionManager; final Object mLock = new Object(); Loading Loading @@ -562,6 +565,9 @@ public class AlarmManagerService extends SystemService { @VisibleForTesting static final String KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED = "kill_on_schedule_exact_alarm_revoked"; @VisibleForTesting static final String KEY_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = "schedule_exact_alarm_denied_by_default"; private static final long DEFAULT_MIN_FUTURITY = 5 * 1000; private static final long DEFAULT_MIN_INTERVAL = 60 * 1000; Loading Loading @@ -606,6 +612,9 @@ public class AlarmManagerService extends SystemService { private static final boolean DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED = true; // TODO(b/226439802): Flip to true. private static final boolean DEFAULT_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = false; // Minimum futurity of a new alarm public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY; Loading Loading @@ -693,6 +702,14 @@ public class AlarmManagerService extends SystemService { public boolean KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED = DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED; /** * When this is {@code true}, apps with the change * {@link AlarmManager#SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT} enabled will not get * {@link Manifest.permission#SCHEDULE_EXACT_ALARM} unless the user grants it to them. */ public volatile boolean SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = DEFAULT_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT; public boolean USE_TARE_POLICY = Settings.Global.DEFAULT_ENABLE_TARE == 1; private long mLastAllowWhileIdleWhitelistDuration = -1; Loading Loading @@ -876,6 +893,15 @@ public class AlarmManagerService extends SystemService { KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED, DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED); break; case KEY_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT: final boolean oldValue = SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT; SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = properties.getBoolean( KEY_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, DEFAULT_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT); handleScheduleExactAlarmDeniedByDefaultChange(oldValue, SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT); break; default: if (name.startsWith(KEY_PREFIX_STANDBY_QUOTA) && !standbyQuotaUpdated) { // The quotas need to be updated in order, so we can't just rely Loading Loading @@ -946,6 +972,15 @@ public class AlarmManagerService extends SystemService { } } private void handleScheduleExactAlarmDeniedByDefaultChange(boolean oldValue, boolean newValue) { if (oldValue == newValue) { return; } mHandler.obtainMessage(AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_FEATURE_TOGGLE, newValue).sendToTarget(); } private void migrateAlarmsToNewStoreLocked() { final AlarmStore newStore = LAZY_BATCHING ? new LazyAlarmStore() : new BatchingAlarmStore(); Loading Loading @@ -1122,6 +1157,9 @@ public class AlarmManagerService extends SystemService { pw.print(KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED, KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED); pw.println(); pw.print(KEY_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT); pw.println(); pw.print(Settings.Global.ENABLE_TARE, USE_TARE_POLICY); pw.println(); Loading Loading @@ -1892,11 +1930,10 @@ public class AlarmManagerService extends SystemService { if (hasUseExactAlarmInternal(packageName, uid)) { return; } final boolean requested = mExactAlarmCandidates.contains( UserHandle.getAppId(uid)); final boolean denyListed = mConstants.EXACT_ALARM_DENY_LIST.contains(packageName); if (!mExactAlarmCandidates.contains(UserHandle.getAppId(uid))) { // Permission not requested, app op doesn't matter. return; } final int newMode = mAppOps.checkOpNoThrow( AppOpsManager.OP_SCHEDULE_EXACT_ALARM, uid, packageName); Loading @@ -1913,11 +1950,24 @@ public class AlarmManagerService extends SystemService { mLastOpScheduleExactAlarm.setValueAt(index, newMode); } } if (oldMode == newMode) { return; } final boolean allowedByDefault = isScheduleExactAlarmAllowedByDefault(packageName, uid); final boolean hadPermission = getScheduleExactAlarmState(requested, denyListed, oldMode); final boolean hasPermission = getScheduleExactAlarmState(requested, denyListed, newMode); 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); } else { hasPermission = allowedByDefault; } if (hadPermission && !hasPermission) { mHandler.obtainMessage(AlarmHandler.REMOVE_EXACT_ALARMS, Loading @@ -1939,6 +1989,8 @@ public class AlarmManagerService extends SystemService { LocalServices.getService(AppStandbyInternal.class); appStandbyInternal.addListener(new AppStandbyTracker()); mRoleManager = getContext().getSystemService(RoleManager.class); mMetricsHelper.registerPuller(() -> mAlarmStore); } } Loading Loading @@ -2525,19 +2577,6 @@ public class AlarmManagerService extends SystemService { } } private static boolean getScheduleExactAlarmState(boolean requested, boolean denyListed, int appOpMode) { // This does not account for the state of the USE_EXACT_ALARM permission. // The caller should do that separately. if (!requested) { return false; } if (appOpMode == AppOpsManager.MODE_DEFAULT) { return !denyListed; } return appOpMode == AppOpsManager.MODE_ALLOWED; } boolean hasUseExactAlarmInternal(String packageName, int uid) { return isUseExactAlarmEnabled(packageName, UserHandle.getUserId(uid)) && (PermissionChecker.checkPermissionForPreflight(getContext(), Loading @@ -2545,6 +2584,32 @@ public class AlarmManagerService extends SystemService { 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<String> 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); } boolean hasScheduleExactAlarmInternal(String packageName, int uid) { final long start = mStatLogger.getTime(); Loading @@ -2560,7 +2625,7 @@ public class AlarmManagerService extends SystemService { final int mode = mAppOps.checkOpNoThrow(AppOpsManager.OP_SCHEDULE_EXACT_ALARM, uid, packageName); if (mode == AppOpsManager.MODE_DEFAULT) { hasPermission = !mConstants.EXACT_ALARM_DENY_LIST.contains(packageName); hasPermission = isScheduleExactAlarmAllowedByDefault(packageName, uid); } else { hasPermission = (mode == AppOpsManager.MODE_ALLOWED); } Loading Loading @@ -2860,6 +2925,13 @@ public class AlarmManagerService extends SystemService { packageName, UserHandle.of(userId)); } private boolean isScheduleExactAlarmDeniedByDefault(String packageName, int userId) { return mConstants.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT && CompatChanges.isChangeEnabled( AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, packageName, UserHandle.of(userId)); } @NeverCompile // Avoid size overhead of debugging code. void dumpImpl(IndentingPrintWriter pw) { synchronized (mLock) { Loading Loading @@ -3769,26 +3841,27 @@ public class AlarmManagerService extends SystemService { if (!isExactAlarmChangeEnabled(changedPackage, userId)) { continue; } if (isScheduleExactAlarmDeniedByDefault(changedPackage, userId)) { continue; } if (hasUseExactAlarmInternal(changedPackage, uid)) { continue; } if (!mExactAlarmCandidates.contains(UserHandle.getAppId(uid))) { // Permission isn't requested, deny list doesn't matter. continue; } final int appOpMode; synchronized (mLock) { appOpMode = mLastOpScheduleExactAlarm.get(uid, AppOpsManager.opToDefaultMode(AppOpsManager.OP_SCHEDULE_EXACT_ALARM)); } final boolean requested = mExactAlarmCandidates.contains(UserHandle.getAppId(uid)); // added: true => package was added to the deny list // added: false => package was removed from the deny list final boolean hadPermission = getScheduleExactAlarmState(requested, !added, appOpMode); final boolean hasPermission = getScheduleExactAlarmState(requested, added, appOpMode); if (hadPermission == hasPermission) { if (appOpMode != AppOpsManager.MODE_DEFAULT) { // Deny list doesn't matter. continue; } // added: true => package was added to the deny list // added: false => package was removed from the deny list if (added) { synchronized (mLock) { removeExactAlarmsOnPermissionRevokedLocked(uid, Loading Loading @@ -4634,6 +4707,7 @@ public class AlarmManagerService extends SystemService { public static final int REFRESH_EXACT_ALARM_CANDIDATES = 11; public static final int TARE_AFFORDABILITY_CHANGED = 12; public static final int CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE = 13; public static final int CHECK_EXACT_ALARM_PERMISSION_ON_FEATURE_TOGGLE = 14; AlarmHandler() { super(Looper.myLooper()); Loading Loading @@ -4759,6 +4833,35 @@ public class AlarmManagerService extends SystemService { } } break; case CHECK_EXACT_ALARM_PERMISSION_ON_FEATURE_TOGGLE: final boolean defaultDenied = (Boolean) msg.obj; final int[] startedUserIds = mActivityManagerInternal.getStartedUserIds(); for (int appId : mExactAlarmCandidates) { for (int userId : startedUserIds) { uid = UserHandle.getUid(userId, appId); final AndroidPackage packageForUid = mPackageManagerInternal.getPackage(uid); if (packageForUid == null) { continue; } final String pkg = packageForUid.getPackageName(); if (defaultDenied) { if (!hasScheduleExactAlarmInternal(pkg, uid) && !hasUseExactAlarmInternal(pkg, uid)) { synchronized (mLock) { removeExactAlarmsOnPermissionRevokedLocked(uid, pkg, true); } } } else if (hasScheduleExactAlarmInternal(pkg, uid)) { sendScheduleExactAlarmPermissionStateChangedBroadcast(pkg, UserHandle.getUserId(uid)); } } } break; default: // nope, just ignore it break; Loading services/core/java/android/content/pm/PackageManagerInternal.java +5 −0 Original line number Diff line number Diff line Loading @@ -1207,6 +1207,11 @@ public abstract class PackageManagerInternal { @Nullable public abstract SharedUserApi getSharedUserApi(int sharedUserAppId); /** * Returns if the given uid is privileged or not. */ public abstract boolean isUidPrivileged(int uid); /** * Initiates a package state mutation request, returning the current state as known by * PackageManager. This allows the later commit request to compare the initial values and Loading services/core/java/com/android/server/pm/PackageManagerInternalBase.java +5 −0 Original line number Diff line number Diff line Loading @@ -722,6 +722,11 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { return snapshot().getSharedUser(sharedUserAppId); } @Override public boolean isUidPrivileged(int uid) { return snapshot().isUidPrivileged(uid); } @NonNull @Override @Deprecated Loading services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +70 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ 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; Loading Loading @@ -122,6 +123,7 @@ 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.usage.UsageStatsManagerInternal; import android.content.ContentResolver; import android.content.Context; Loading Loading @@ -184,6 +186,7 @@ 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; Loading Loading @@ -232,6 +235,8 @@ public class AlarmManagerServiceTest { @Mock private PackageManagerInternal mPackageManagerInternal; @Mock private RoleManager mRoleManager; @Mock private AppStateTrackerImpl mAppStateTracker; @Mock private AlarmManagerService.ClockReceiver mClockReceiver; Loading Loading @@ -457,6 +462,7 @@ public class AlarmManagerServiceTest { 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)}); Loading Loading @@ -3190,6 +3196,70 @@ public 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, true); mService.mConstants.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, false); mService.mConstants.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = true; mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[] { package1, package3, }); // Same as above, 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.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++) { Loading Loading
apex/jobscheduler/framework/java/android/app/AlarmManager.java +13 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; Loading Loading @@ -280,6 +281,18 @@ public class AlarmManager { @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) public static final long ENABLE_USE_EXACT_ALARM = 218533173L; /** * For apps targeting {@link Build.VERSION_CODES#TIRAMISU} or above, the permission * {@link Manifest.permission#SCHEDULE_EXACT_ALARM} will be denied, unless the user explicitly * allows it from Settings. * * TODO (b/226439802): change to EnabledSince(T) after SDK finalization. * @hide */ @ChangeId @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2) public static final long SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = 226439802L; @UnsupportedAppUsage private final IAlarmManager mService; private final Context mContext; Loading
apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +137 −34 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ 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.usage.UsageStatsManager; import android.app.usage.UsageStatsManagerInternal; import android.content.BroadcastReceiver; Loading Loading @@ -164,6 +165,7 @@ 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; Loading Loading @@ -224,6 +226,7 @@ public class AlarmManagerService extends SystemService { private ActivityManagerInternal mActivityManagerInternal; private final EconomyManagerInternal mEconomyManagerInternal; private PackageManagerInternal mPackageManagerInternal; private RoleManager mRoleManager; private volatile PermissionManagerServiceInternal mLocalPermissionManager; final Object mLock = new Object(); Loading Loading @@ -562,6 +565,9 @@ public class AlarmManagerService extends SystemService { @VisibleForTesting static final String KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED = "kill_on_schedule_exact_alarm_revoked"; @VisibleForTesting static final String KEY_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = "schedule_exact_alarm_denied_by_default"; private static final long DEFAULT_MIN_FUTURITY = 5 * 1000; private static final long DEFAULT_MIN_INTERVAL = 60 * 1000; Loading Loading @@ -606,6 +612,9 @@ public class AlarmManagerService extends SystemService { private static final boolean DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED = true; // TODO(b/226439802): Flip to true. private static final boolean DEFAULT_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = false; // Minimum futurity of a new alarm public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY; Loading Loading @@ -693,6 +702,14 @@ public class AlarmManagerService extends SystemService { public boolean KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED = DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED; /** * When this is {@code true}, apps with the change * {@link AlarmManager#SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT} enabled will not get * {@link Manifest.permission#SCHEDULE_EXACT_ALARM} unless the user grants it to them. */ public volatile boolean SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = DEFAULT_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT; public boolean USE_TARE_POLICY = Settings.Global.DEFAULT_ENABLE_TARE == 1; private long mLastAllowWhileIdleWhitelistDuration = -1; Loading Loading @@ -876,6 +893,15 @@ public class AlarmManagerService extends SystemService { KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED, DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED); break; case KEY_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT: final boolean oldValue = SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT; SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = properties.getBoolean( KEY_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, DEFAULT_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT); handleScheduleExactAlarmDeniedByDefaultChange(oldValue, SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT); break; default: if (name.startsWith(KEY_PREFIX_STANDBY_QUOTA) && !standbyQuotaUpdated) { // The quotas need to be updated in order, so we can't just rely Loading Loading @@ -946,6 +972,15 @@ public class AlarmManagerService extends SystemService { } } private void handleScheduleExactAlarmDeniedByDefaultChange(boolean oldValue, boolean newValue) { if (oldValue == newValue) { return; } mHandler.obtainMessage(AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_FEATURE_TOGGLE, newValue).sendToTarget(); } private void migrateAlarmsToNewStoreLocked() { final AlarmStore newStore = LAZY_BATCHING ? new LazyAlarmStore() : new BatchingAlarmStore(); Loading Loading @@ -1122,6 +1157,9 @@ public class AlarmManagerService extends SystemService { pw.print(KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED, KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED); pw.println(); pw.print(KEY_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT); pw.println(); pw.print(Settings.Global.ENABLE_TARE, USE_TARE_POLICY); pw.println(); Loading Loading @@ -1892,11 +1930,10 @@ public class AlarmManagerService extends SystemService { if (hasUseExactAlarmInternal(packageName, uid)) { return; } final boolean requested = mExactAlarmCandidates.contains( UserHandle.getAppId(uid)); final boolean denyListed = mConstants.EXACT_ALARM_DENY_LIST.contains(packageName); if (!mExactAlarmCandidates.contains(UserHandle.getAppId(uid))) { // Permission not requested, app op doesn't matter. return; } final int newMode = mAppOps.checkOpNoThrow( AppOpsManager.OP_SCHEDULE_EXACT_ALARM, uid, packageName); Loading @@ -1913,11 +1950,24 @@ public class AlarmManagerService extends SystemService { mLastOpScheduleExactAlarm.setValueAt(index, newMode); } } if (oldMode == newMode) { return; } final boolean allowedByDefault = isScheduleExactAlarmAllowedByDefault(packageName, uid); final boolean hadPermission = getScheduleExactAlarmState(requested, denyListed, oldMode); final boolean hasPermission = getScheduleExactAlarmState(requested, denyListed, newMode); 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); } else { hasPermission = allowedByDefault; } if (hadPermission && !hasPermission) { mHandler.obtainMessage(AlarmHandler.REMOVE_EXACT_ALARMS, Loading @@ -1939,6 +1989,8 @@ public class AlarmManagerService extends SystemService { LocalServices.getService(AppStandbyInternal.class); appStandbyInternal.addListener(new AppStandbyTracker()); mRoleManager = getContext().getSystemService(RoleManager.class); mMetricsHelper.registerPuller(() -> mAlarmStore); } } Loading Loading @@ -2525,19 +2577,6 @@ public class AlarmManagerService extends SystemService { } } private static boolean getScheduleExactAlarmState(boolean requested, boolean denyListed, int appOpMode) { // This does not account for the state of the USE_EXACT_ALARM permission. // The caller should do that separately. if (!requested) { return false; } if (appOpMode == AppOpsManager.MODE_DEFAULT) { return !denyListed; } return appOpMode == AppOpsManager.MODE_ALLOWED; } boolean hasUseExactAlarmInternal(String packageName, int uid) { return isUseExactAlarmEnabled(packageName, UserHandle.getUserId(uid)) && (PermissionChecker.checkPermissionForPreflight(getContext(), Loading @@ -2545,6 +2584,32 @@ public class AlarmManagerService extends SystemService { 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<String> 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); } boolean hasScheduleExactAlarmInternal(String packageName, int uid) { final long start = mStatLogger.getTime(); Loading @@ -2560,7 +2625,7 @@ public class AlarmManagerService extends SystemService { final int mode = mAppOps.checkOpNoThrow(AppOpsManager.OP_SCHEDULE_EXACT_ALARM, uid, packageName); if (mode == AppOpsManager.MODE_DEFAULT) { hasPermission = !mConstants.EXACT_ALARM_DENY_LIST.contains(packageName); hasPermission = isScheduleExactAlarmAllowedByDefault(packageName, uid); } else { hasPermission = (mode == AppOpsManager.MODE_ALLOWED); } Loading Loading @@ -2860,6 +2925,13 @@ public class AlarmManagerService extends SystemService { packageName, UserHandle.of(userId)); } private boolean isScheduleExactAlarmDeniedByDefault(String packageName, int userId) { return mConstants.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT && CompatChanges.isChangeEnabled( AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, packageName, UserHandle.of(userId)); } @NeverCompile // Avoid size overhead of debugging code. void dumpImpl(IndentingPrintWriter pw) { synchronized (mLock) { Loading Loading @@ -3769,26 +3841,27 @@ public class AlarmManagerService extends SystemService { if (!isExactAlarmChangeEnabled(changedPackage, userId)) { continue; } if (isScheduleExactAlarmDeniedByDefault(changedPackage, userId)) { continue; } if (hasUseExactAlarmInternal(changedPackage, uid)) { continue; } if (!mExactAlarmCandidates.contains(UserHandle.getAppId(uid))) { // Permission isn't requested, deny list doesn't matter. continue; } final int appOpMode; synchronized (mLock) { appOpMode = mLastOpScheduleExactAlarm.get(uid, AppOpsManager.opToDefaultMode(AppOpsManager.OP_SCHEDULE_EXACT_ALARM)); } final boolean requested = mExactAlarmCandidates.contains(UserHandle.getAppId(uid)); // added: true => package was added to the deny list // added: false => package was removed from the deny list final boolean hadPermission = getScheduleExactAlarmState(requested, !added, appOpMode); final boolean hasPermission = getScheduleExactAlarmState(requested, added, appOpMode); if (hadPermission == hasPermission) { if (appOpMode != AppOpsManager.MODE_DEFAULT) { // Deny list doesn't matter. continue; } // added: true => package was added to the deny list // added: false => package was removed from the deny list if (added) { synchronized (mLock) { removeExactAlarmsOnPermissionRevokedLocked(uid, Loading Loading @@ -4634,6 +4707,7 @@ public class AlarmManagerService extends SystemService { public static final int REFRESH_EXACT_ALARM_CANDIDATES = 11; public static final int TARE_AFFORDABILITY_CHANGED = 12; public static final int CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE = 13; public static final int CHECK_EXACT_ALARM_PERMISSION_ON_FEATURE_TOGGLE = 14; AlarmHandler() { super(Looper.myLooper()); Loading Loading @@ -4759,6 +4833,35 @@ public class AlarmManagerService extends SystemService { } } break; case CHECK_EXACT_ALARM_PERMISSION_ON_FEATURE_TOGGLE: final boolean defaultDenied = (Boolean) msg.obj; final int[] startedUserIds = mActivityManagerInternal.getStartedUserIds(); for (int appId : mExactAlarmCandidates) { for (int userId : startedUserIds) { uid = UserHandle.getUid(userId, appId); final AndroidPackage packageForUid = mPackageManagerInternal.getPackage(uid); if (packageForUid == null) { continue; } final String pkg = packageForUid.getPackageName(); if (defaultDenied) { if (!hasScheduleExactAlarmInternal(pkg, uid) && !hasUseExactAlarmInternal(pkg, uid)) { synchronized (mLock) { removeExactAlarmsOnPermissionRevokedLocked(uid, pkg, true); } } } else if (hasScheduleExactAlarmInternal(pkg, uid)) { sendScheduleExactAlarmPermissionStateChangedBroadcast(pkg, UserHandle.getUserId(uid)); } } } break; default: // nope, just ignore it break; Loading
services/core/java/android/content/pm/PackageManagerInternal.java +5 −0 Original line number Diff line number Diff line Loading @@ -1207,6 +1207,11 @@ public abstract class PackageManagerInternal { @Nullable public abstract SharedUserApi getSharedUserApi(int sharedUserAppId); /** * Returns if the given uid is privileged or not. */ public abstract boolean isUidPrivileged(int uid); /** * Initiates a package state mutation request, returning the current state as known by * PackageManager. This allows the later commit request to compare the initial values and Loading
services/core/java/com/android/server/pm/PackageManagerInternalBase.java +5 −0 Original line number Diff line number Diff line Loading @@ -722,6 +722,11 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { return snapshot().getSharedUser(sharedUserAppId); } @Override public boolean isUidPrivileged(int uid) { return snapshot().isUidPrivileged(uid); } @NonNull @Override @Deprecated Loading
services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +70 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ 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; Loading Loading @@ -122,6 +123,7 @@ 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.usage.UsageStatsManagerInternal; import android.content.ContentResolver; import android.content.Context; Loading Loading @@ -184,6 +186,7 @@ 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; Loading Loading @@ -232,6 +235,8 @@ public class AlarmManagerServiceTest { @Mock private PackageManagerInternal mPackageManagerInternal; @Mock private RoleManager mRoleManager; @Mock private AppStateTrackerImpl mAppStateTracker; @Mock private AlarmManagerService.ClockReceiver mClockReceiver; Loading Loading @@ -457,6 +462,7 @@ public class AlarmManagerServiceTest { 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)}); Loading Loading @@ -3190,6 +3196,70 @@ public 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, true); mService.mConstants.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, false); mService.mConstants.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = true; mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[] { package1, package3, }); // Same as above, 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.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++) { Loading