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

Commit c858b578 authored by Matías Hernández's avatar Matías Hernández Committed by Nolen Johnson
Browse files

Limit the number of services (NLSes, etc) that can be approved per user

Trying to activate additional packages/components will be silently rejected.

Bug: 428701593
Test: atest ManagedServicesTest NotificationManagerServiceTest
Flag: com.android.server.notification.limit_managed_services_count
(cherry picked from commit a132684a)
Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:def30b58386ad8104aa6041952cacba473dc7ce2
Merged-In: Iddd8044997c41f97369b768f4da5e49efc43ad06
Change-Id: Iddd8044997c41f97369b768f4da5e49efc43ad06
parent f69eddc3
Loading
Loading
Loading
Loading
+22 −3
Original line number Diff line number Diff line
@@ -116,6 +116,13 @@ abstract public class ManagedServices {
    static final int APPROVAL_BY_PACKAGE = 0;
    static final int APPROVAL_BY_COMPONENT = 1;

    /**
     * Maximum number of entries allowed in the lists of packages/components contained in
     * {@link #mApproved} or {@link #mUserSetServices}. For the first, this effectively limits
     * the number of services (e.g. NLSes) that will be bound per user.
     */
    private static final int MAX_SERVICE_ENTRIES = 100;

    protected final Context mContext;
    protected final Object mMutex;
    private final UserProfiles mUserProfiles;
@@ -664,10 +671,11 @@ abstract public class ManagedServices {
        return mEnabledServicesPackageNames.contains(pkg);
    }

    protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
    protected boolean setPackageOrComponentEnabled(String pkgOrComponent, int userId,
            boolean isPrimary, boolean enabled) {
        Slog.i(TAG,
                (enabled ? " Allowing " : "Disallowing ") + mConfig.caption + " " + pkgOrComponent);
        boolean changed = false;
        synchronized (mApproved) {
            ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
            if (allowedByType == null) {
@@ -683,16 +691,27 @@ abstract public class ManagedServices {

            if (approvedItem != null) {
                if (enabled) {
                    if (approved.size() < MAX_SERVICE_ENTRIES) {
                        approved.add(approvedItem);
                        changed = true;
                    } else {
                        Slog.w(TAG, "Failed to allow" + mConfig.caption + pkgOrComponent
                            + "because there are too many already");
                    }
                } else {
                    approved.remove(approvedItem);
                    changed = true;
                }
            }
        }

        if (changed) {
            rebindServices(false, userId);
        }

        return changed;
    }

    private String getApprovedValue(String pkgOrComponent) {
        if (mApprovalLevel == APPROVAL_BY_COMPONENT) {
            if(ComponentName.unflattenFromString(pkgOrComponent) != null) {
+14 −7
Original line number Diff line number Diff line
@@ -4851,8 +4851,11 @@ public class NotificationManagerService extends SystemService {
            try {
                if (mAllowedManagedServicePackages.test(
                        pkg, userId, mConditionProviders.getRequiredPermission())) {
                    mConditionProviders.setPackageOrComponentEnabled(
                            pkg, userId, true, granted);
                    boolean changed = mConditionProviders.setPackageOrComponentEnabled(pkg, userId,
                            /* isPrimary= */ true, granted);
                    if (!changed) {
                        return;
                    }

                    getContext().sendBroadcastAsUser(new Intent(
                            ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
@@ -5025,10 +5028,14 @@ public class NotificationManagerService extends SystemService {
            try {
                if (mAllowedManagedServicePackages.test(
                        listener.getPackageName(), userId, mListeners.getRequiredPermission())) {
                    boolean changed = mListeners.setPackageOrComponentEnabled(
                            listener.flattenToString(), userId, /* isPrimary= */ true, granted);
                    if (!changed) {
                        return;
                    }

                    mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
                            userId, false, granted);
                    mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
                            userId, true, granted);

                    getContext().sendBroadcastAsUser(new Intent(
                            ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
@@ -9610,19 +9617,19 @@ public class NotificationManagerService extends SystemService {
        }

        @Override
        protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
        protected boolean setPackageOrComponentEnabled(String pkgOrComponent, int userId,
                boolean isPrimary, boolean enabled) {
            // Ensures that only one component is enabled at a time
            if (enabled) {
                List<ComponentName> allowedComponents = getAllowedComponents(userId);
                if (!allowedComponents.isEmpty()) {
                    ComponentName currentComponent = CollectionUtils.firstOrNull(allowedComponents);
                    if (currentComponent.flattenToString().equals(pkgOrComponent)) return;
                    if (currentComponent.flattenToString().equals(pkgOrComponent)) return false;
                    setNotificationAssistantAccessGrantedForUserInternal(
                            currentComponent, userId, false);
                }
            }
            super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled);
            return super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled);
        }

        @Override
+17 −0
Original line number Diff line number Diff line
@@ -484,6 +484,23 @@ public class ManagedServicesTest extends UiServiceTestCase {
        assertTrue(components.contains(new ComponentName("package", "default")));
    }

    @Test
    public void testPackageUninstall_componentNoLongerUserSetList() throws Exception {
        final String pkg = "this.is.a.package.name";
        final String component = pkg + "/Ba";
        for (int approvalLevel : new int[] { APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                    mIpm, approvalLevel);
            writeExpectedValuesToSettings(approvalLevel);
            service.migrateToXml();
            final String verifyValue = (approvalLevel == APPROVAL_BY_COMPONENT) ? component : pkg;
            assertThat(service.isPackageOrComponentAllowed(verifyValue, 0)).isTrue();
            assertThat(service.isPackageOrComponentUserSet(verifyValue, 0)).isTrue();
            service.onPackagesChanged(true, new String[]{pkg}, new int[]{103});
            assertThat(service.isPackageOrComponentUserSet(verifyValue, 0)).isFalse();
        }
    }

    /** Test that backup only writes packages/components that belong to the target user. */
    @Test
    public void testWriteXml_onlyBackupsForTargetUser() throws Exception {
+25 −0
Original line number Diff line number Diff line
@@ -545,6 +545,18 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        mPolicyFile.finishWrite(fos);

        // Setup managed services
        when(mListeners.setPackageOrComponentEnabled(any(), anyInt(), anyBoolean(), anyBoolean()))
                .thenReturn(true);
        when(mListeners.setPackageOrComponentEnabled(any(), anyInt(), anyBoolean(), anyBoolean(),
                anyBoolean())).thenReturn(true);
        when(mAssistants.setPackageOrComponentEnabled(any(), anyInt(), anyBoolean(), anyBoolean()))
                .thenReturn(true);
        when(mAssistants.setPackageOrComponentEnabled(any(), anyInt(), anyBoolean(), anyBoolean(),
                anyBoolean())).thenReturn(true);
        when(mConditionProviders.setPackageOrComponentEnabled(any(), anyInt(), anyBoolean(),
                anyBoolean())).thenReturn(true);
        when(mConditionProviders.setPackageOrComponentEnabled(any(), anyInt(), anyBoolean(),
                anyBoolean(), anyBoolean())).thenReturn(true);
        mListener = mListeners.new ManagedServiceInfo(
                null, new ComponentName(PKG, "test_class"),
                UserHandle.getUserId(mUid), true, null, 0);
@@ -3442,6 +3454,19 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                c.flattenToString(), user.getIdentifier(), true, /* enabled= */ false);
    }

    @Test
    public void testSetListenerAccessForUser_tooManyListeners_skipsFollowups() throws Exception {
        UserHandle user = UserHandle.of(mContext.getUserId() + 10);
        ComponentName c = ComponentName.unflattenFromString("package/Component");
        when(mListeners.setPackageOrComponentEnabled(any(), anyInt(), anyBoolean(), anyBoolean(),
                anyBoolean())).thenReturn(false);
        mBinderService.setNotificationListenerAccessGrantedForUser(
                c, user.getIdentifier(), /* enabled= */ true, true);
        verify(mConditionProviders, never()).setPackageOrComponentEnabled(any(), anyInt(),
                anyBoolean(), anyBoolean(), anyBoolean());
        verify(mContext, never()).sendBroadcastAsUser(any(), any(), any());
    }

    @Test
    public void testSetAssistantAccessForUser() throws Exception {
        UserHandle user = UserHandle.of(10);