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

Commit 24b5dfbe authored by Matías Hernández's avatar Matías Hernández Committed by mse1969
Browse files

[BACKPORT] Prevent accidental creation of PackagePreferences for non-existing packages

This could be caused by (indirectly) invoking PreferencesHelper.getOrCreatePackagePreferences
with an INVALID_UID (e.g. as the result of NMS passing along the result of
getUidForPackageAndUser for a missing package). This was never intended -- API calls can
result in the creation of PackagePreferences (since the structure is lazily initialized) but
only for present packages.
In most cases this was prevented by other checks (e.g. canNotifyAsPackage, which fails if
missing) but specifically for the "fromPrivilegedListener" methods there was no similar
enforcement.

Switch the PreferencesHelper usage so that:
* setters (e.g. create/updateChannel, groups) throw if supplied an invalid uid.
* getters that should have PackagePreferences creation as a side effect (e.g. getChannel)
  early exit if supplied an invalid uid.
* most getters don't actually create PackagePreferences and just return default values
  (e.g. canShowBadge) if they don't exist yet.

(Also, unify constants for representing a missing package into Process.INVALID_UID, and
fix several tests that were impropely set up).

Bug: 426207912
Test: atest NotificationManagerServiceTest PreferencesHelperTest
(cherry picked from commit 236cff68)
Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:a629bb1b5e87dbcd82a0ab85c681f443b606ce10
Merged-In: I7d0717aed9fb26490f68801c9220833f2bed8e23
Change-Id: I7d0717aed9fb26490f68801c9220833f2bed8e23
parent 8c505fdd
Loading
Loading
Loading
Loading
+25 −12
Original line number Diff line number Diff line
@@ -326,6 +326,8 @@ public class NotificationManagerService extends SystemService {

    static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps

    static final int INVALID_UID = -1;

    static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;

    static final boolean ENABLE_BLOCKED_TOASTS = true;
@@ -2916,7 +2918,7 @@ public class NotificationManagerService extends SystemService {
                String targetPkg, String channelId) {
            if (canNotifyAsPackage(callingPkg, targetPkg, userId)
                    || isCallingUidSystem()) {
                int targetUid = -1;
                int targetUid = INVALID_UID;
                try {
                    targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
                } catch (NameNotFoundException e) {
@@ -3090,7 +3092,7 @@ public class NotificationManagerService extends SystemService {
                String callingPkg, String targetPkg, int userId) {
            if (canNotifyAsPackage(callingPkg, targetPkg, userId)
                || isCallingUidSystem()) {
                int targetUid = -1;
                int targetUid = INVALID_UID;
                try {
                    targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
                } catch (NameNotFoundException e) {
@@ -4422,11 +4424,10 @@ public class NotificationManagerService extends SystemService {
            int uid = 0;
            long identity = Binder.clearCallingIdentity();
            try {
                uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
                return mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
            return uid;
        }

        @Override
@@ -5394,7 +5395,7 @@ public class NotificationManagerService extends SystemService {
            return callingUid;
        }

        int targetUid = -1;
        int targetUid = INVALID_UID;
        try {
            targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
        } catch (NameNotFoundException e) {
@@ -8925,15 +8926,22 @@ public class NotificationManagerService extends SystemService {
            List<UserInfo> users = mUm.getUsers();
            mNonBlockableDefaultApps = new ArrayMap<>();
            for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {
                String role = NON_BLOCKABLE_DEFAULT_ROLES[i];
                final ArrayMap<Integer, ArraySet<String>> userToApprovedList = new ArrayMap<>();
                mNonBlockableDefaultApps.put(NON_BLOCKABLE_DEFAULT_ROLES[i], userToApprovedList);
                mNonBlockableDefaultApps.put(role, userToApprovedList);
                for (int j = 0; j < users.size(); j++) {
                    Integer userId = users.get(j).getUserHandle().getIdentifier();
                    int userId = users.get(j).getUserHandle().getIdentifier();
                    ArraySet<String> approvedForUserId = new ArraySet<>(mRm.getRoleHoldersAsUser(
                            NON_BLOCKABLE_DEFAULT_ROLES[i], UserHandle.of(userId)));
                            role, UserHandle.of(userId)));
                    ArraySet<Pair<String, Integer>> approvedAppUids = new ArraySet<>();
                    for (String pkg : approvedForUserId) {
                        approvedAppUids.add(new Pair(pkg, getUidForPackage(pkg, userId)));
                        int uid = getUidForPackage(pkg, userId);
                        if (uid != INVALID_UID) {
                            approvedAppUids.add(new Pair<>(pkg, uid));
                        } else {
                            Slog.e(TAG, "init: Invalid package for role " + role
                                    + " (user " + userId + "): " + pkg);
                        }
                    }
                    userToApprovedList.put(userId, approvedForUserId);
                    mPreferencesHelper.updateDefaultApps(userId, null, approvedAppUids);
@@ -8988,8 +8996,13 @@ public class NotificationManagerService extends SystemService {
            }
            for (String nowApproved : roleHolders) {
                if (!previouslyApproved.contains(nowApproved)) {
                    toAdd.add(new Pair(nowApproved,
                            getUidForPackage(nowApproved, user.getIdentifier())));
                    int uid = getUidForPackage(nowApproved, user.getIdentifier());
                    if (uid != INVALID_UID) {
                        toAdd.add(new Pair<>(nowApproved, uid));
                    } else {
                        Slog.e(TAG, "onRoleHoldersChanged: Invalid package for role " + roleName
                                + " (user " + user.getIdentifier() + "): " + nowApproved);
                    }
                }
            }

@@ -9010,7 +9023,7 @@ public class NotificationManagerService extends SystemService {
            } catch (RemoteException e) {
                Slog.e(TAG, "role manager has bad default " + pkg + " " + userId);
            }
            return -1;
            return INVALID_UID;
        }
    }

+71 −31
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.Preconditions;
@@ -70,7 +71,7 @@ import java.util.concurrent.ConcurrentHashMap;
public class PreferencesHelper implements RankingConfig {
    private static final String TAG = "NotificationPrefHelper";
    private static final int XML_VERSION = 1;
    private static final int UNKNOWN_UID = UserHandle.USER_NULL;
    private static final int INVALID_UID = -1;
    private static final String NON_BLOCKABLE_CHANNEL_DELIM = ":";

    @VisibleForTesting
@@ -178,7 +179,7 @@ public class PreferencesHelper implements RankingConfig {
                        mHideSilentStatusBarIcons = XmlUtils.readBooleanAttribute(
                                parser, ATT_HIDE_SILENT, DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
                    } else if (TAG_PACKAGE.equals(tag)) {
                        int uid = XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
                        int uid = XmlUtils.readIntAttribute(parser, ATT_UID, INVALID_UID);
                        String name = parser.getAttributeValue(null, ATT_NAME);
                        if (!TextUtils.isEmpty(name)) {
                            if (forRestore) {
@@ -191,7 +192,8 @@ public class PreferencesHelper implements RankingConfig {
                            boolean skipWarningLogged = false;
                            boolean skipGroupWarningLogged = false;

                            PackagePreferences r = getOrCreatePackagePreferencesLocked(name, uid,
                            PackagePreferences r = getOrCreatePackagePreferencesSupportingInvalidUidLocked(
                                    name, uid,
                                    XmlUtils.readIntAttribute(
                                            parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE),
                                    XmlUtils.readIntAttribute(parser, ATT_PRIORITY,
@@ -274,7 +276,7 @@ public class PreferencesHelper implements RankingConfig {
                                // Delegate
                                if (TAG_DELEGATE.equals(tagName)) {
                                    int delegateId =
                                            XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
                                            XmlUtils.readIntAttribute(parser, ATT_UID, INVALID_UID);
                                    String delegateName =
                                            XmlUtils.readStringAttribute(parser, ATT_NAME);
                                    boolean delegateEnabled = XmlUtils.readBooleanAttribute(
@@ -283,7 +285,7 @@ public class PreferencesHelper implements RankingConfig {
                                            parser, ATT_USER_ALLOWED,
                                            Delegate.DEFAULT_USER_ALLOWED);
                                    Delegate d = null;
                                    if (delegateId != UNKNOWN_UID && !TextUtils.isEmpty(
                                    if (delegateId != INVALID_UID && !TextUtils.isEmpty(
                                            delegateName)) {
                                        d = new Delegate(
                                                delegateName, delegateId, delegateEnabled,
@@ -307,22 +309,54 @@ public class PreferencesHelper implements RankingConfig {
        throw new IllegalStateException("Failed to reach END_DOCUMENT");
    }

    /**
     * Returns the {@link PackagePreferences} object associated to the pkg/uid pair. If it doesn't
     * exist, return {@code null}.
     */
    @GuardedBy("mPackagePreferences")
    @Nullable
    private PackagePreferences getPackagePreferencesLocked(String pkg, int uid) {
        final String key = packagePreferencesKey(pkg, uid);
        return mPackagePreferences.get(key);
    }

    /**
     * Returns the {@link PackagePreferences} object associated to the pkg/uid pair. If it doesn't
     * exist, a new one is initialized (with appropriate defaults, e.g. default channel if pre-O)
     * and stored in {@link #mPackagePreferences}.
     *
     * @throws IllegalArgumentException if the supplied uid is not valid (i.e. {@code INVALID_UID}).
     */
    @GuardedBy("mPackagePreferences")
    @NonNull
    private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, int uid) {
        return getOrCreatePackagePreferencesLocked(pkg, uid,
                DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE,
                DEFAULT_ALLOW_BUBBLE);
        Objects.requireNonNull(pkg);
        Preconditions.checkArgument(uid != INVALID_UID,
                "Valid uid required to get settings of %s", pkg);
        // TODO (b/194833441): use permissionhelper instead of DEFAULT_IMPORTANCE
        return getOrCreatePackagePreferencesSupportingInvalidUidLocked(pkg,
                uid, DEFAULT_IMPORTANCE, DEFAULT_PRIORITY,
                DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE, DEFAULT_ALLOW_BUBBLE);
    }

    private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, int uid,

    /**
     * Returns the {@link PackagePreferences} object associated to the pkg/uid pair, and initializes
     * a new one (with appropriate defaults, e.g. default channel if pre-O) if it doesn't exist.
     *
     * <p>This method accepts {@link android.os.Process#INVALID_UID} as the {@code uid}
     * parameter, and in that case will create a (time-limited) entry in
     * {@link #mRestoredWithoutUids} instead of {@link #mPackagePreferences}. As such, should only
     * be used that way by the {@code readXml()} path, to support restoring NMS backups before all
     * packages have been reinstalled -- for API calls, we shouldn't create entries for
     * non-existing packages.
     */
    @GuardedBy("mPackagePreferences")
    private PackagePreferences getOrCreatePackagePreferencesSupportingInvalidUidLocked(String pkg, int uid,
            int importance, int priority, int visibility, boolean showBadge, boolean allowBubble) {
        final String key = packagePreferencesKey(pkg, uid);
        PackagePreferences
                r = (uid == UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg)
                r = (uid == INVALID_UID) ? mRestoredWithoutUids.get(pkg)
                : mPackagePreferences.get(key);
        if (r == null) {
            r = new PackagePreferences();
@@ -340,7 +374,7 @@ public class PreferencesHelper implements RankingConfig {
                Slog.e(TAG, "createDefaultChannelIfNeededLocked - Exception: " + e);
            }

            if (r.uid == UNKNOWN_UID) {
            if (r.uid == INVALID_UID) {
                mRestoredWithoutUids.put(pkg, r);
            } else {
                mPackagePreferences.put(key, r);
@@ -536,13 +570,15 @@ public class PreferencesHelper implements RankingConfig {
    @Override
    public boolean areBubblesAllowed(String pkg, int uid) {
        synchronized (mPackagePreferences) {
            return getOrCreatePackagePreferencesLocked(pkg, uid).allowBubble;
            PackagePreferences p = getPackagePreferencesLocked(pkg, uid);
            return p != null ? p.allowBubble : DEFAULT_ALLOW_BUBBLE;
        }
    }

    public int getAppLockedFields(String pkg, int uid) {
        synchronized (mPackagePreferences) {
            return getOrCreatePackagePreferencesLocked(pkg, uid).lockedAppFields;
            PackagePreferences p = getPackagePreferencesLocked(pkg, uid);
            return p != null ? p.lockedAppFields : DEFAULT_LOCKED_APP_FIELDS;
        }
    }

@@ -571,7 +607,8 @@ public class PreferencesHelper implements RankingConfig {
    @Override
    public boolean canShowBadge(String packageName, int uid) {
        synchronized (mPackagePreferences) {
            return getOrCreatePackagePreferencesLocked(packageName, uid).showBadge;
            PackagePreferences p = getPackagePreferencesLocked(packageName, uid);
            return p != null ? p.showBadge : DEFAULT_SHOW_BADGE;
        }
    }

@@ -589,7 +626,10 @@ public class PreferencesHelper implements RankingConfig {
            return false;
        }
        synchronized (mPackagePreferences) {
            PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
            PackagePreferences r = getPackagePreferencesLocked(packageName, uid);
            if (r == null) {
                return false;
            }
            NotificationChannelGroup group = r.groups.get(groupId);
            if (group == null) {
                return false;
@@ -600,13 +640,15 @@ public class PreferencesHelper implements RankingConfig {

    int getPackagePriority(String pkg, int uid) {
        synchronized (mPackagePreferences) {
            return getOrCreatePackagePreferencesLocked(pkg, uid).priority;
            PackagePreferences p = getPackagePreferencesLocked(pkg, uid);
            return p != null ? p.priority : DEFAULT_PRIORITY;
        }
    }

    int getPackageVisibility(String pkg, int uid) {
        synchronized (mPackagePreferences) {
            return getOrCreatePackagePreferencesLocked(pkg, uid).visibility;
            PackagePreferences p = getPackagePreferencesLocked(pkg, uid);
            return p != null ? p.visibility : DEFAULT_VISIBILITY;
        }
    }

@@ -619,9 +661,6 @@ public class PreferencesHelper implements RankingConfig {
        Preconditions.checkNotNull(!TextUtils.isEmpty(group.getName()));
        synchronized (mPackagePreferences) {
            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
            if (r == null) {
                throw new IllegalArgumentException("Invalid package");
            }
            if (fromTargetApp) {
                group.setBlocked(false);
                if (r.groups.size() >= NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT) {
@@ -663,9 +702,6 @@ public class PreferencesHelper implements RankingConfig {
        boolean needsPolicyFileChange = false;
        synchronized (mPackagePreferences) {
            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
            if (r == null) {
                throw new IllegalArgumentException("Invalid package");
            }
            if (channel.getGroup() != null && !r.groups.containsKey(channel.getGroup())) {
                throw new IllegalArgumentException("NotificationChannelGroup doesn't exist");
            }
@@ -797,9 +833,6 @@ public class PreferencesHelper implements RankingConfig {
        Preconditions.checkNotNull(updatedChannel.getId());
        synchronized (mPackagePreferences) {
            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
            if (r == null) {
                throw new IllegalArgumentException("Invalid package");
            }
            NotificationChannel channel = r.channels.get(updatedChannel.getId());
            if (channel == null || channel.isDeleted()) {
                throw new IllegalArgumentException("Channel does not exist");
@@ -856,6 +889,9 @@ public class PreferencesHelper implements RankingConfig {
    public NotificationChannel getNotificationChannel(String pkg, int uid, String channelId,
            boolean includeDeleted) {
        Preconditions.checkNotNull(pkg);
        if (uid == INVALID_UID) {
            return null;
        }
        synchronized (mPackagePreferences) {
            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
            if (r == null) {
@@ -1118,6 +1154,9 @@ public class PreferencesHelper implements RankingConfig {
    public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid,
            boolean includeDeleted) {
        Preconditions.checkNotNull(pkg);
        if (uid == INVALID_UID) {
            return ParceledListSlice.emptyList();
        }
        List<NotificationChannel> channels = new ArrayList<>();
        synchronized (mPackagePreferences) {
            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
@@ -1350,7 +1389,8 @@ public class PreferencesHelper implements RankingConfig {
     * {@code uid}, have their importance locked by the user. Locked notifications don't get
     * considered for sentiment adjustments (and thus never show a blocking helper).
     */
    public void setAppImportanceLocked(String packageName, int uid) {
    @VisibleForTesting
    void setAppImportanceLocked(String packageName, int uid) {
        synchronized (mPackagePreferences) {
            PackagePreferences prefs = getOrCreatePackagePreferencesLocked(packageName, uid);
            if ((prefs.lockedAppFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0) {
@@ -1522,7 +1562,7 @@ public class PreferencesHelper implements RankingConfig {
                pw.print("  AppSettings: ");
                pw.print(r.pkg);
                pw.print(" (");
                pw.print(r.uid == UNKNOWN_UID ? "UNKNOWN_UID" : Integer.toString(r.uid));
                pw.print(r.uid == INVALID_UID ? "INVALID_UID" : Integer.toString(r.uid));
                pw.print(')');
                if (r.importance != DEFAULT_IMPORTANCE) {
                    pw.print(" importance=");
@@ -1949,7 +1989,7 @@ public class PreferencesHelper implements RankingConfig {

    private static class PackagePreferences {
        String pkg;
        int uid = UNKNOWN_UID;
        int uid = INVALID_UID;
        int importance = DEFAULT_IMPORTANCE;
        int priority = DEFAULT_PRIORITY;
        int visibility = DEFAULT_VISIBILITY;
@@ -1976,7 +2016,7 @@ public class PreferencesHelper implements RankingConfig {
        static final boolean DEFAULT_ENABLED = true;
        static final boolean DEFAULT_USER_ALLOWED = true;
        String mPkg;
        int mUid = UNKNOWN_UID;
        int mUid = INVALID_UID;
        boolean mEnabled = DEFAULT_ENABLED;
        boolean mUserAllowed = DEFAULT_USER_ALLOWED;

@@ -1988,7 +2028,7 @@ public class PreferencesHelper implements RankingConfig {
        }

        public boolean isAllowed(String pkg, int uid) {
            if (pkg == null || uid == UNKNOWN_UID) {
            if (pkg == null || uid == INVALID_UID) {
                return false;
            }
            return pkg.equals(mPkg)
+53 −0
Original line number Diff line number Diff line
@@ -126,6 +126,7 @@ import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings;
import android.service.notification.Adjustment;
import android.service.notification.INotificationListener;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationRankingUpdate;
import android.service.notification.NotificationStats;
@@ -190,6 +191,7 @@ import java.util.function.Consumer;
@RunWithLooper
public class NotificationManagerServiceTest extends UiServiceTestCase {
    private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
    private static final String MISSING_PACKAGE = "MISSING!";
    private static final String CLEAR_DEVICE_CONFIG_KEY_CMD =
            "device_config delete " + DeviceConfig.NAMESPACE_SYSTEMUI + " "
                    + SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE;
@@ -197,6 +199,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
            "device_config put " + DeviceConfig.NAMESPACE_SYSTEMUI + " "
                    + SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE;

    private static final int INVALID_UID = -1;
    private TestableContext mContext = spy(getContext());
    private final int mUid = Binder.getCallingUid();
    private final @UserIdInt int mUserId = UserHandle.getUserId(mUid);
@@ -413,11 +416,17 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        mContext.setMockPackageManager(mPackageManagerClient);
        final ApplicationInfo applicationInfo = new ApplicationInfo();
        applicationInfo.uid = mUid;

        when(mPackageManager.getPackageUid(eq(mPkg), anyLong(), eq(mUserId))).thenReturn(mUid);
        when(mPackageManager.getPackageUid(eq(MISSING_PACKAGE), anyLong(), anyInt()))
                .thenReturn(INVALID_UID);
        when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt()))
                .thenReturn(applicationInfo);
        when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
                .thenReturn(applicationInfo);
        when(mPackageManagerClient.getPackageUidAsUser(any(), anyInt())).thenReturn(mUid);
        when(mPackageManagerClient.getPackageUidAsUser(eq(MISSING_PACKAGE), anyInt()))
                .thenThrow(new PackageManager.NameNotFoundException("Missing package!"));
        final LightsManager mockLightsManager = mock(LightsManager.class);
        when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class));
        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
@@ -2283,6 +2292,50 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        verify(mPreferencesHelper, never()).getNotificationChannelGroups(anyString(), anyInt());
    }

    @Test
    public void getNotificationChannelsFromPrivilegedListener_invalidPackage_returnsNull()
            throws Exception {
        when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
        when(mCompanionMgr.getAssociations(mPkg, mUserId))
                .thenReturn(singletonList(mock(AssociationInfo.class)));

        ParceledListSlice<?> channels =
                mBinderService.getNotificationChannelsFromPrivilegedListener(
                        mock(INotificationListener.class), MISSING_PACKAGE, mUser);

        assertThat(channels.getList()).isEmpty();
    }

    @Test
    public void getNotificationChannelGroupsFromPrivilegedListener_invalidPackage_returnsEmpty()
            throws Exception {
        when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
        when(mCompanionMgr.getAssociations(mPkg, mUserId))
                .thenReturn(singletonList(mock(AssociationInfo.class)));

        ParceledListSlice<?> groups =
                mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
                        mock(INotificationListener.class), MISSING_PACKAGE, mUser);

        assertThat(groups.getList()).isEmpty();
    }

    @Test
    public void updateNotificationChannelFromPrivilegedListener_invalidPackage_throws()
            throws Exception {
        when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
        when(mCompanionMgr.getAssociations(mPkg, mUserId))
                .thenReturn(singletonList(mock(AssociationInfo.class)));

        Exception e = assertThrows(IllegalArgumentException.class,
                () -> mBinderService.updateNotificationChannelFromPrivilegedListener(
                        mock(INotificationListener.class), MISSING_PACKAGE, mUser,
                        mTestNotificationChannel));

        assertThat(e).hasMessageThat().isEqualTo(
                "Valid uid required to get settings of " + MISSING_PACKAGE);
    }

    @Test
    public void testHasCompanionDevice_failure() throws Exception {
        when(mCompanionMgr.getAssociations(anyString(), anyInt())).thenThrow(