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

Commit 6557fe4b authored by Valentin Iftime's avatar Valentin Iftime Committed by Iavor-Valentin Iftime
Browse files

Check for NLS service intent filter when rebinding services

 Also:
  - after updating packages with NLS components, check
 the approved services and remove from approved list if missing the NLS service intent filter.
  - check for services permission and intent when user enables NLS.

Flag: com.android.server.notification.notification_nls_rebind
Test: atest ManagedServicesTest
Bug: 347674739
Change-Id: I67089d910ca0cbcbfce4a0033badf280d3a0ac81
parent 60d45114
Loading
Loading
Loading
Loading
+54 −12
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@ import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
import static android.content.Context.BIND_AUTO_CREATE;
import static android.content.Context.BIND_FOREGROUND_SERVICE;
import static android.content.Context.DEVICE_POLICY_SERVICE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_INSTANT;
import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_AUTOBIND;
@@ -106,7 +109,8 @@ abstract public class ManagedServices {
    protected final String TAG = getClass().getSimpleName().replace('$', '.');
    protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    private static final int ON_BINDING_DIED_REBIND_DELAY_MS = 10000;
    protected static final int ON_BINDING_DIED_REBIND_DELAY_MS = 10000;
    protected static final int ON_BINDING_DIED_REBIND_MSG = 1234;
    protected static final String ENABLED_SERVICES_SEPARATOR = ":";
    private static final String DB_VERSION_1 = "1";
    private static final String DB_VERSION_2 = "2";
@@ -875,7 +879,21 @@ abstract public class ManagedServices {
            String approvedItem = getApprovedValue(pkgOrComponent);

            if (approvedItem != null) {
                final ComponentName component = ComponentName.unflattenFromString(approvedItem);
                if (enabled) {
                    if (Flags.notificationNlsRebind()) {
                        if (component != null && !isValidService(component, userId)) {
                            // Only fail if package is available
                            // If not, it will be validated again in onPackagesChanged
                            final PackageManager pm = mContext.getPackageManager();
                            if (pm.isPackageAvailable(component.getPackageName())) {
                                Slog.w(TAG, "Skip allowing " + mConfig.caption
                                        + " " + pkgOrComponent + " (userSet: " + userSet
                                        + ") for invalid service");
                                return;
                            }
                        }
                    }
                    approved.add(approvedItem);
                } else {
                    approved.remove(approvedItem);
@@ -973,7 +991,7 @@ abstract public class ManagedServices {
                || isPackageOrComponentAllowed(component.getPackageName(), userId))) {
            return false;
        }
        return componentHasBindPermission(component, userId);
        return isValidService(component, userId);
    }

    private boolean componentHasBindPermission(ComponentName component, int userId) {
@@ -1220,12 +1238,21 @@ abstract public class ManagedServices {
        if (!TextUtils.isEmpty(packageName)) {
            queryIntent.setPackage(packageName);
        }

        if (Flags.notificationNlsRebind()) {
            // Expand the package query
            extraFlags |= MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
            extraFlags |= MATCH_INSTANT;
        }

        List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
                queryIntent,
                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA | extraFlags,
                userId);
        if (DEBUG)
            Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
        if (DEBUG) {
            Slog.v(TAG, mConfig.serviceInterface + " pkg: " + packageName + " services: "
                    + installedServices);
        }
        if (installedServices != null) {
            for (int i = 0, count = installedServices.size(); i < count; i++) {
                ResolveInfo resolveInfo = installedServices.get(i);
@@ -1325,11 +1352,12 @@ abstract public class ManagedServices {
                    if (TextUtils.equals(getPackageName(approvedPackageOrComponent), packageName)) {
                        final ComponentName component = ComponentName.unflattenFromString(
                                approvedPackageOrComponent);
                        if (component != null && !componentHasBindPermission(component, userId)) {
                        if (component != null && !isValidService(component, userId)) {
                            approved.removeAt(j);
                            if (DEBUG) {
                                Slog.v(TAG, "Removing " + approvedPackageOrComponent
                                        + " from approved list; no bind permission found "
                                        + " from approved list; no bind permission or "
                                        + "service interface filter found "
                                        + mConfig.bindPermission);
                            }
                        }
@@ -1348,6 +1376,15 @@ abstract public class ManagedServices {
        }
    }

    protected boolean isValidService(ComponentName component, int userId) {
        if (Flags.notificationNlsRebind()) {
            return componentHasBindPermission(component, userId) && queryPackageForServices(
                    component.getPackageName(), userId).contains(component);
        } else {
            return componentHasBindPermission(component, userId);
        }
    }

    protected boolean isValidEntry(String packageOrComponent, int userId) {
        return hasMatchingServices(packageOrComponent, userId);
    }
@@ -1505,23 +1542,27 @@ abstract public class ManagedServices {
     * Called when user switched to unbind all services from other users.
     */
    @VisibleForTesting
    void unbindOtherUserServices(int currentUser) {
    void unbindOtherUserServices(int switchedToUser) {
        TimingsTraceAndSlog t = new TimingsTraceAndSlog();
        t.traceBegin("ManagedServices.unbindOtherUserServices_current" + currentUser);
        unbindServicesImpl(currentUser, true /* allExceptUser */);
        t.traceBegin("ManagedServices.unbindOtherUserServices_current" + switchedToUser);
        unbindServicesImpl(switchedToUser, true /* allExceptUser */);
        t.traceEnd();
    }

    void unbindUserServices(int user) {
    void unbindUserServices(int removedUser) {
        TimingsTraceAndSlog t = new TimingsTraceAndSlog();
        t.traceBegin("ManagedServices.unbindUserServices" + user);
        unbindServicesImpl(user, false /* allExceptUser */);
        t.traceBegin("ManagedServices.unbindUserServices" + removedUser);
        unbindServicesImpl(removedUser, false /* allExceptUser */);
        t.traceEnd();
    }

    void unbindServicesImpl(int user, boolean allExceptUser) {
        final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
        synchronized (mMutex) {
            if (Flags.notificationNlsRebind()) {
                // Remove enqueued rebinds to avoid rebinding services for a switched user
                mHandler.removeMessages(ON_BINDING_DIED_REBIND_MSG);
            }
            final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices();
            for (ManagedServiceInfo info : removableBoundServices) {
                if ((allExceptUser && (info.userid != user))
@@ -1716,6 +1757,7 @@ abstract public class ManagedServices {
                            mServicesRebinding.add(servicesBindingTag);
                            mHandler.postDelayed(() ->
                                    reregisterService(name, userid),
                                    ON_BINDING_DIED_REBIND_MSG,
                                    ON_BINDING_DIED_REBIND_DELAY_MS);
                        } else {
                            Slog.v(TAG, getCaption() + " not rebinding in user " + userid
+10 −0
Original line number Diff line number Diff line
@@ -187,3 +187,13 @@ flag {
  description: "Enables sound uri with vibration source in notification channel"
  bug: "351975435"
}

flag {
  name: "notification_nls_rebind"
  namespace: "systemui"
  description: "Check for NLS service intent filter when rebinding services"
  bug: "347674739"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}
+289 −9

File changed.

Preview size limit exceeded, changes collapsed.

+10 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;

import static org.junit.Assert.assertNull;

import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.any;
@@ -197,6 +198,8 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
    public void testWriteXml_userTurnedOffNAS() throws Exception {
        int userId = ActivityManager.getCurrentUser();

        doReturn(true).when(mAssistants).isValidService(eq(mCn), eq(userId));

        mAssistants.loadDefaultsFromConfig(true);

        mAssistants.setPackageOrComponentEnabled(mCn.flattenToString(), userId, true,
@@ -432,6 +435,10 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
    public void testSetPackageOrComponentEnabled_onlyOnePackage() throws Exception {
        ComponentName component1 = ComponentName.unflattenFromString("package/Component1");
        ComponentName component2 = ComponentName.unflattenFromString("package/Component2");

        doReturn(true).when(mAssistants).isValidService(eq(component1), eq(mZero.id));
        doReturn(true).when(mAssistants).isValidService(eq(component2), eq(mZero.id));

        mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true,
                true, true);
        verify(mNm, never()).setNotificationAssistantAccessGrantedForUserInternal(
@@ -577,6 +584,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
    public void testSetAdjustmentTypeSupportedState() throws Exception {
        int userId = ActivityManager.getCurrentUser();

        doReturn(true).when(mAssistants).isValidService(eq(mCn), eq(userId));
        mAssistants.loadDefaultsFromConfig(true);
        mAssistants.setPackageOrComponentEnabled(mCn.flattenToString(), userId, true,
                true, true);
@@ -600,6 +608,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
    public void testSetAdjustmentTypeSupportedState_readWriteXml_entries() throws Exception {
        int userId = ActivityManager.getCurrentUser();

        doReturn(true).when(mAssistants).isValidService(eq(mCn), eq(userId));
        mAssistants.loadDefaultsFromConfig(true);
        mAssistants.setPackageOrComponentEnabled(mCn.flattenToString(), userId, true,
                true, true);
@@ -623,6 +632,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
    public void testSetAdjustmentTypeSupportedState_readWriteXml_empty() throws Exception {
        int userId = ActivityManager.getCurrentUser();

        doReturn(true).when(mAssistants).isValidService(eq(mCn), eq(userId));
        mAssistants.loadDefaultsFromConfig(true);
        mAssistants.setPackageOrComponentEnabled(mCn.flattenToString(), userId, true,
                true, true);