Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 007b90ff authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Adding a normal permission for exact alarms"

parents 10740c41 be22a43c
Loading
Loading
Loading
Loading
+46 −6
Original line number Original line Diff line number Diff line
@@ -72,6 +72,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter;
import android.content.PermissionChecker;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal;
import android.database.ContentObserver;
import android.database.ContentObserver;
@@ -1839,6 +1840,9 @@ public class AlarmManagerService extends SystemService {
                    if (!isExactAlarmChangeEnabled(a.packageName, UserHandle.getUserId(a.uid))) {
                    if (!isExactAlarmChangeEnabled(a.packageName, UserHandle.getUserId(a.uid))) {
                        return false;
                        return false;
                    }
                    }
                    if (hasUseExactAlarmPermission(a.packageName, a.uid)) {
                        return false;
                    }
                    return !isExemptFromExactAlarmPermission(a.uid);
                    return !isExemptFromExactAlarmPermission(a.uid);
                };
                };
                removeAlarmsInternalLocked(whichAlarms, REMOVE_REASON_EXACT_PERMISSION_REVOKED);
                removeAlarmsInternalLocked(whichAlarms, REMOVE_REASON_EXACT_PERMISSION_REVOKED);
@@ -1900,6 +1904,9 @@ public class AlarmManagerService extends SystemService {
                                        || !isExactAlarmChangeEnabled(packageName, userId)) {
                                        || !isExactAlarmChangeEnabled(packageName, userId)) {
                                    return;
                                    return;
                                }
                                }
                                if (hasUseExactAlarmPermission(packageName, uid)) {
                                    return;
                                }


                                final boolean requested = mExactAlarmCandidates.contains(
                                final boolean requested = mExactAlarmCandidates.contains(
                                        UserHandle.getAppId(uid));
                                        UserHandle.getAppId(uid));
@@ -2534,6 +2541,8 @@ public class AlarmManagerService extends SystemService {


    private static boolean getScheduleExactAlarmState(boolean requested, boolean denyListed,
    private static boolean getScheduleExactAlarmState(boolean requested, boolean denyListed,
            int appOpMode) {
            int appOpMode) {
        // This does not account for the state of the USE_EXACT_ALARM permission.
        // The caller should do that separately.
        if (!requested) {
        if (!requested) {
            return false;
            return false;
        }
        }
@@ -2543,7 +2552,16 @@ public class AlarmManagerService extends SystemService {
        return appOpMode == AppOpsManager.MODE_ALLOWED;
        return appOpMode == AppOpsManager.MODE_ALLOWED;
    }
    }


    boolean hasUseExactAlarmPermission(String packageName, int uid) {
        return PermissionChecker.checkPermissionForPreflight(getContext(),
                Manifest.permission.USE_EXACT_ALARM, PermissionChecker.PID_UNKNOWN, uid,
                packageName) == PermissionChecker.PERMISSION_GRANTED;
    }

    boolean hasScheduleExactAlarmInternal(String packageName, int uid) {
    boolean hasScheduleExactAlarmInternal(String packageName, int uid) {
        if (hasUseExactAlarmPermission(packageName, uid)) {
            return true;
        }
        // Not using getScheduleExactAlarmState as this can avoid some calls to AppOpsService.
        // Not using getScheduleExactAlarmState as this can avoid some calls to AppOpsService.
        // Not using #mLastOpScheduleExactAlarm as it may contain stale values.
        // Not using #mLastOpScheduleExactAlarm as it may contain stale values.
        // No locking needed as all internal containers being queried are immutable.
        // No locking needed as all internal containers being queried are immutable.
@@ -3759,6 +3777,9 @@ public class AlarmManagerService extends SystemService {
                if (!isExactAlarmChangeEnabled(changedPackage, userId)) {
                if (!isExactAlarmChangeEnabled(changedPackage, userId)) {
                    continue;
                    continue;
                }
                }
                if (hasUseExactAlarmPermission(changedPackage, uid)) {
                    continue;
                }
                final int appOpMode;
                final int appOpMode;
                synchronized (mLock) {
                synchronized (mLock) {
                    appOpMode = mLastOpScheduleExactAlarm.get(uid,
                    appOpMode = mLastOpScheduleExactAlarm.get(uid,
@@ -3778,7 +3799,8 @@ public class AlarmManagerService extends SystemService {
                }
                }
                if (added) {
                if (added) {
                    synchronized (mLock) {
                    synchronized (mLock) {
                        removeExactAlarmsOnPermissionRevokedLocked(uid, changedPackage);
                        removeExactAlarmsOnPermissionRevokedLocked(uid,
                                changedPackage, /*killUid = */ true);
                    }
                    }
                } else {
                } else {
                    sendScheduleExactAlarmPermissionStateChangedBroadcast(changedPackage, userId);
                    sendScheduleExactAlarmPermissionStateChangedBroadcast(changedPackage, userId);
@@ -3794,7 +3816,7 @@ public class AlarmManagerService extends SystemService {
     * This is not expected to get called frequently.
     * This is not expected to get called frequently.
     */
     */
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    void removeExactAlarmsOnPermissionRevokedLocked(int uid, String packageName) {
    void removeExactAlarmsOnPermissionRevokedLocked(int uid, String packageName, boolean killUid) {
        if (isExemptFromExactAlarmPermission(uid)
        if (isExemptFromExactAlarmPermission(uid)
                || !isExactAlarmChangeEnabled(packageName, UserHandle.getUserId(uid))) {
                || !isExactAlarmChangeEnabled(packageName, UserHandle.getUserId(uid))) {
            return;
            return;
@@ -3805,7 +3827,7 @@ public class AlarmManagerService extends SystemService {
                && a.windowLength == 0);
                && a.windowLength == 0);
        removeAlarmsInternalLocked(whichAlarms, REMOVE_REASON_EXACT_PERMISSION_REVOKED);
        removeAlarmsInternalLocked(whichAlarms, REMOVE_REASON_EXACT_PERMISSION_REVOKED);


        if (mConstants.KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED) {
        if (killUid && mConstants.KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED) {
            PermissionManagerService.killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
            PermissionManagerService.killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
                    "schedule_exact_alarm revoked");
                    "schedule_exact_alarm revoked");
        }
        }
@@ -4617,6 +4639,7 @@ public class AlarmManagerService extends SystemService {
        public static final int EXACT_ALARM_DENY_LIST_PACKAGES_REMOVED = 10;
        public static final int EXACT_ALARM_DENY_LIST_PACKAGES_REMOVED = 10;
        public static final int REFRESH_EXACT_ALARM_CANDIDATES = 11;
        public static final int REFRESH_EXACT_ALARM_CANDIDATES = 11;
        public static final int TARE_AFFORDABILITY_CHANGED = 12;
        public static final int TARE_AFFORDABILITY_CHANGED = 12;
        public static final int CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE = 13;


        AlarmHandler() {
        AlarmHandler() {
            super(Looper.myLooper());
            super(Looper.myLooper());
@@ -4715,10 +4738,11 @@ public class AlarmManagerService extends SystemService {
                    break;
                    break;


                case REMOVE_EXACT_ALARMS:
                case REMOVE_EXACT_ALARMS:
                    final int uid = msg.arg1;
                    int uid = msg.arg1;
                    final String packageName = (String) msg.obj;
                    String packageName = (String) msg.obj;
                    synchronized (mLock) {
                    synchronized (mLock) {
                        removeExactAlarmsOnPermissionRevokedLocked(uid, packageName);
                        removeExactAlarmsOnPermissionRevokedLocked(uid, packageName, /*killUid = */
                                true);
                    }
                    }
                    break;
                    break;
                case EXACT_ALARM_DENY_LIST_PACKAGES_ADDED:
                case EXACT_ALARM_DENY_LIST_PACKAGES_ADDED:
@@ -4730,6 +4754,16 @@ public class AlarmManagerService extends SystemService {
                case REFRESH_EXACT_ALARM_CANDIDATES:
                case REFRESH_EXACT_ALARM_CANDIDATES:
                    refreshExactAlarmCandidates();
                    refreshExactAlarmCandidates();
                    break;
                    break;
                case CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE:
                    packageName = (String) msg.obj;
                    uid = msg.arg1;
                    if (!hasScheduleExactAlarmInternal(packageName, uid)) {
                        synchronized (mLock) {
                            removeExactAlarmsOnPermissionRevokedLocked(uid,
                                    packageName, /*killUid = */false);
                        }
                    }
                    break;
                default:
                default:
                    // nope, just ignore it
                    // nope, just ignore it
                    break;
                    break;
@@ -4914,6 +4948,12 @@ public class AlarmManagerService extends SystemService {
                        }
                        }
                        break;
                        break;
                    case Intent.ACTION_PACKAGE_ADDED:
                    case Intent.ACTION_PACKAGE_ADDED:
                        if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                            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);
                        mHandler.sendEmptyMessage(AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES);
                        return;
                        return;
                }
                }
+1 −0
Original line number Original line Diff line number Diff line
@@ -194,6 +194,7 @@ package android {
    field public static final String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
    field public static final String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
    field public static final String UPDATE_PACKAGES_WITHOUT_USER_ACTION = "android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION";
    field public static final String UPDATE_PACKAGES_WITHOUT_USER_ACTION = "android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION";
    field public static final String USE_BIOMETRIC = "android.permission.USE_BIOMETRIC";
    field public static final String USE_BIOMETRIC = "android.permission.USE_BIOMETRIC";
    field public static final String USE_EXACT_ALARM = "android.permission.USE_EXACT_ALARM";
    field @Deprecated public static final String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
    field @Deprecated public static final String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
    field public static final String USE_FULL_SCREEN_INTENT = "android.permission.USE_FULL_SCREEN_INTENT";
    field public static final String USE_FULL_SCREEN_INTENT = "android.permission.USE_FULL_SCREEN_INTENT";
    field public static final String USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER = "android.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER";
    field public static final String USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER = "android.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER";
+10 −0
Original line number Original line Diff line number Diff line
@@ -4403,6 +4403,16 @@
    <permission android:name="android.permission.SCHEDULE_EXACT_ALARM"
    <permission android:name="android.permission.SCHEDULE_EXACT_ALARM"
        android:protectionLevel="normal|appop"/>
        android:protectionLevel="normal|appop"/>


    <!-- Allows apps to use exact alarms just like with SCHEDULE_EXACT_ALARM but without needing
        to request this permission from the user.
        <p><b>This is only for apps that rely on exact alarms for their core functionality.</b>
        App stores may enforce policies to audit and review the use of this permission. Any app that
        requests this but is found to not require exact alarms for its primary function may be
        removed from the app store.
    -->
    <permission android:name="android.permission.USE_EXACT_ALARM"
                android:protectionLevel="normal"/>

    <!-- Allows an application to query tablet mode state and monitor changes
    <!-- Allows an application to query tablet mode state and monitor changes
         in it.
         in it.
         <p>Not for use by third-party applications.
         <p>Not for use by third-party applications.
+26 −8
Original line number Original line Diff line number Diff line
@@ -108,6 +108,7 @@ import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.times;


import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.ActivityOptions;
@@ -124,6 +125,7 @@ import android.app.usage.UsageStatsManagerInternal;
import android.content.ContentResolver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.PermissionChecker;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal;
import android.database.ContentObserver;
import android.database.ContentObserver;
import android.net.Uri;
import android.net.Uri;
@@ -389,6 +391,7 @@ public class AlarmManagerServiceTest {
                .mockStatic(LocalServices.class)
                .mockStatic(LocalServices.class)
                .spyStatic(Looper.class)
                .spyStatic(Looper.class)
                .mockStatic(MetricsHelper.class)
                .mockStatic(MetricsHelper.class)
                .mockStatic(PermissionChecker.class)
                .mockStatic(PermissionManagerService.class)
                .mockStatic(PermissionManagerService.class)
                .mockStatic(ServiceManager.class)
                .mockStatic(ServiceManager.class)
                .mockStatic(Settings.Global.class)
                .mockStatic(Settings.Global.class)
@@ -445,6 +448,10 @@ public class AlarmManagerServiceTest {
        doReturn(true)
        doReturn(true)
                .when(() -> DateFormat.is24HourFormat(eq(mMockContext), anyInt()));
                .when(() -> DateFormat.is24HourFormat(eq(mMockContext), anyInt()));


        doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
                () -> PermissionChecker.checkPermissionForPreflight(any(),
                        eq(Manifest.permission.USE_EXACT_ALARM), anyInt(), anyInt(), anyString()));

        when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
        when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);


        registerAppIds(new String[]{TEST_CALLING_PACKAGE},
        registerAppIds(new String[]{TEST_CALLING_PACKAGE},
@@ -2158,6 +2165,7 @@ public class AlarmManagerServiceTest {


    @Test
    @Test
    public void canScheduleExactAlarmsBinderCall() throws RemoteException {
    public void canScheduleExactAlarmsBinderCall() throws RemoteException {
        // Policy permission is denied in setUp().
        mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
        mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);


        // No permission, no exemption.
        // No permission, no exemption.
@@ -2168,6 +2176,14 @@ public class AlarmManagerServiceTest {
        mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
        mockExactAlarmPermissionGrant(true, false, MODE_ERRORED);
        assertFalse(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
        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)));
        assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));

        // Permission, no exemption.
        // Permission, no exemption.
        mockExactAlarmPermissionGrant(true, false, MODE_DEFAULT);
        mockExactAlarmPermissionGrant(true, false, MODE_DEFAULT);
        assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
        assertTrue(mBinder.canScheduleExactAlarms(TEST_CALLING_PACKAGE));
@@ -2699,7 +2715,8 @@ public class AlarmManagerServiceTest {
        mService.handleChangesToExactAlarmDenyList(new ArraySet<>(packages), false);
        mService.handleChangesToExactAlarmDenyList(new ArraySet<>(packages), false);


        // No permission revoked.
        // No permission revoked.
        verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(anyInt(), anyString());
        verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(anyInt(), anyString(),
                anyBoolean());


        // Permission got granted only for (appId1, userId2).
        // Permission got granted only for (appId1, userId2).
        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -2754,14 +2771,14 @@ public class AlarmManagerServiceTest {


        // Permission got revoked only for (appId1, userId2)
        // Permission got revoked only for (appId1, userId2)
        verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(
        verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(
                eq(UserHandle.getUid(userId1, appId1)), eq(packages[0]));
                eq(UserHandle.getUid(userId1, appId1)), eq(packages[0]), eq(true));
        verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(
        verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(
                eq(UserHandle.getUid(userId1, appId2)), eq(packages[1]));
                eq(UserHandle.getUid(userId1, appId2)), eq(packages[1]), eq(true));
        verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(
        verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(
                eq(UserHandle.getUid(userId2, appId2)), eq(packages[1]));
                eq(UserHandle.getUid(userId2, appId2)), eq(packages[1]), eq(true));


        verify(mService).removeExactAlarmsOnPermissionRevokedLocked(
        verify(mService).removeExactAlarmsOnPermissionRevokedLocked(
                eq(UserHandle.getUid(userId2, appId1)), eq(packages[0]));
                eq(UserHandle.getUid(userId2, appId1)), eq(packages[0]), eq(true));
    }
    }


    @Test
    @Test
@@ -2774,7 +2791,7 @@ public class AlarmManagerServiceTest {
        mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
        mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
        assertAndHandleMessageSync(REMOVE_EXACT_ALARMS);
        assertAndHandleMessageSync(REMOVE_EXACT_ALARMS);
        verify(mService).removeExactAlarmsOnPermissionRevokedLocked(TEST_CALLING_UID,
        verify(mService).removeExactAlarmsOnPermissionRevokedLocked(TEST_CALLING_UID,
                TEST_CALLING_PACKAGE);
                TEST_CALLING_PACKAGE, true);
    }
    }


    @Test
    @Test
@@ -2859,7 +2876,8 @@ public class AlarmManagerServiceTest {
                null);
                null);
        assertEquals(6, mService.mAlarmStore.size());
        assertEquals(6, mService.mAlarmStore.size());


        mService.removeExactAlarmsOnPermissionRevokedLocked(TEST_CALLING_UID, TEST_CALLING_PACKAGE);
        mService.removeExactAlarmsOnPermissionRevokedLocked(TEST_CALLING_UID, TEST_CALLING_PACKAGE,
                true);


        final ArrayList<Alarm> remaining = mService.mAlarmStore.asList();
        final ArrayList<Alarm> remaining = mService.mAlarmStore.asList();
        assertEquals(3, remaining.size());
        assertEquals(3, remaining.size());
@@ -3080,7 +3098,7 @@ public class AlarmManagerServiceTest {
                SCHEDULE_EXACT_ALARM)).thenReturn(exactAlarmRequesters);
                SCHEDULE_EXACT_ALARM)).thenReturn(exactAlarmRequesters);


        final Intent packageAdded = new Intent(Intent.ACTION_PACKAGE_ADDED)
        final Intent packageAdded = new Intent(Intent.ACTION_PACKAGE_ADDED)
                .setPackage(TEST_CALLING_PACKAGE)
                .setData(Uri.fromParts("package", TEST_CALLING_PACKAGE, null))
                .putExtra(Intent.EXTRA_REPLACING, true);
                .putExtra(Intent.EXTRA_REPLACING, true);
        mPackageChangesReceiver.onReceive(mMockContext, packageAdded);
        mPackageChangesReceiver.onReceive(mMockContext, packageAdded);