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

Commit d60b6504 authored by Matías Hernández's avatar Matías Hernández Committed by mse1969
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 d89fe4bd
Loading
Loading
Loading
Loading
+45 −14
Original line number Diff line number Diff line
@@ -122,6 +122,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;
@@ -803,16 +810,22 @@ 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) {
        setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, true);
        return setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, true);
    }

    protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
    /**
     * Changes the enabled state of a managed service.
     *
     * @return true if the change (enabling or disabling) was applied; false otherwise
     */
    protected boolean setPackageOrComponentEnabled(String pkgOrComponent, int userId,
            boolean isPrimary, boolean enabled, boolean userSet) {
        Slog.i(TAG,
                (enabled ? " Allowing " : "Disallowing ") + mConfig.caption + " "
                        + pkgOrComponent + " (userSet: " + userSet + ")");
        boolean changed = false;
        synchronized (mApproved) {
            ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
            if (allowedByType == null) {
@@ -828,26 +841,44 @@ abstract public class ManagedServices {

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

            if (changed) {
                ArraySet<String> userSetServices = mUserSetServices.get(userId);
                if (userSetServices == null) {
                    userSetServices = new ArraySet<>();
                    mUserSetServices.put(userId, userSetServices);
                }
                if (userSet) {
                    if (userSetServices.size() < MAX_SERVICE_ENTRIES) {
                        userSetServices.add(pkgOrComponent);
                    }
                } else {
                    userSetServices.remove(pkgOrComponent);
                }

            }
        }

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

        return changed;
    }

    private String getApprovedValue(String pkgOrComponent) {
        if (mApprovalLevel == APPROVAL_BY_COMPONENT) {
            if(ComponentName.unflattenFromString(pkgOrComponent) != null) {
+24 −9
Original line number Diff line number Diff line
@@ -5368,8 +5368,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)
@@ -5571,10 +5574,15 @@ public class NotificationManagerService extends SystemService {
            try {
                if (mAllowedManagedServicePackages.test(
                        listener.getPackageName(), userId, mListeners.getRequiredPermission())) {
                    boolean changed = mListeners.setPackageOrComponentEnabled(
                            listener.flattenToString(), userId, /* isPrimary= */ true, granted,
                            userSet);
                    if (!changed) {
                        return;
                    }
                    mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
                            userId, false, granted, userSet);
                    mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
                            userId, true, granted, userSet);
                    getContext().sendBroadcastAsUser(new Intent(
                            ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
@@ -10767,19 +10775,20 @@ public class NotificationManagerService extends SystemService {
        }
        @Override
        protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
        protected boolean setPackageOrComponentEnabled(String pkgOrComponent, int userId,
                boolean isPrimary, boolean enabled, boolean userSet) {
            // 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, userSet);
                }
            }
            super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, userSet);
            return super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled,
                    userSet);
        }
        private boolean isVerboseLogEnabled() {
@@ -10818,14 +10827,20 @@ public class NotificationManagerService extends SystemService {
        }
        @Override
        protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
        protected boolean setPackageOrComponentEnabled(String pkgOrComponent, int userId,
                boolean isPrimary, boolean enabled, boolean userSet) {
            super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, userSet);
            boolean changed = super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary,
                    enabled, userSet);
            if (!changed) {
                return false;
            }
            mContext.sendBroadcastAsUser(
                    new Intent(ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED)
                            .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
                    UserHandle.of(userId), null);
            return true;
        }
        @Override
+20 −0
Original line number Diff line number Diff line
@@ -1872,6 +1872,26 @@ public class ManagedServicesTest extends UiServiceTestCase {
        assertFalse(info.isPermittedForProfile(0));
    }

    @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
    public void testUserProfiles_canProfileUseBoundServices_managedProfile() {
        List<UserInfo> users = new ArrayList<>();
+27 −0
Original line number Diff line number Diff line
@@ -493,6 +493,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);
        when(mNlf.isTypeAllowed(anyInt())).thenReturn(true);
        when(mNlf.isPackageAllowed(any())).thenReturn(true);
        when(mNlf.isPackageAllowed(null)).thenReturn(true);
@@ -4116,6 +4128,21 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                c.flattenToString(), user.getIdentifier(), true, /* enabled= */ false, true);
    }
    @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 {
        UserInfo ui = new UserInfo();