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

Commit 93085216 authored by Julia Reynolds's avatar Julia Reynolds Committed by gitbuildkicker
Browse files

Clear calling identity before verifying listeners

Also don't throw when can't verify listener.

And update mocking in tests to clean state between tests.

Bug: 36783632
Fixes: 37263567
Test: runtest-systemui-notification, create a secondary user
Change-Id: I5ec95539c9859b67b8fbc7e6a85334e08e6b5a98
(cherry picked from commit da78147f)
parent bdb1bdd7
Loading
Loading
Loading
Loading
+46 −35
Original line number Diff line number Diff line
@@ -2695,7 +2695,9 @@ public class NotificationManagerService extends SystemService {
            Preconditions.checkNotNull(channel);

            ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
            checkHasCompanionDevice(info);
            if (!hasCompanionDevice(info)) {
                throw new SecurityException(info + " does not have access");
            }

            int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
            updateNotificationChannelInt(pkg, uid, channel, true);
@@ -2705,7 +2707,9 @@ public class NotificationManagerService extends SystemService {
        public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
                INotificationListener token, String pkg) throws RemoteException {
            ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
            checkHasCompanionDevice(info);
            if (!hasCompanionDevice(info)) {
                throw new SecurityException(info + " does not have access");
            }

            int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
            return mRankingHelper.getNotificationChannels(pkg, uid, false /* includeDeleted */);
@@ -2716,7 +2720,9 @@ public class NotificationManagerService extends SystemService {
                getNotificationChannelGroupsFromPrivilegedListener(
                INotificationListener token, String pkg) throws RemoteException {
            ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
            checkHasCompanionDevice(info);
            if (!hasCompanionDevice(info)) {
                throw new SecurityException(info + " does not have access");
            }

            List<NotificationChannelGroup> groups = new ArrayList<>();
            int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
@@ -4655,15 +4661,28 @@ public class NotificationManagerService extends SystemService {
                channels, overridePeople, snoozeCriteria, showBadge);
    }

    private void checkHasCompanionDevice(ManagedServiceInfo info) throws RemoteException {
    boolean hasCompanionDevice(ManagedServiceInfo info) {
        if (mCompanionManager == null) {
            mCompanionManager = ICompanionDeviceManager.Stub.asInterface(
                    ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
        }
        if (ArrayUtils.isEmpty(mCompanionManager.getAssociations(
                info.component.getPackageName(), info.userid))) {
            throw new SecurityException("Disallowed call from " + info.component);
        long identity = Binder.clearCallingIdentity();
        try {
            List<String> associations = mCompanionManager.getAssociations(
                    info.component.getPackageName(), info.userid);
            if (!ArrayUtils.isEmpty(associations)) {
                return true;
            }
        } catch (SecurityException se) {
            // Not a privileged listener
        } catch (RemoteException re) {
            Slog.e(TAG, "Cannot reach companion device service", re);
        } catch (Exception e) {
            Slog.e(TAG, "Cannot verify listener " + info, e);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
        return false;
    }

    private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
@@ -4996,11 +5015,12 @@ public class NotificationManagerService extends SystemService {
                return;
            }
            for (final ManagedServiceInfo serviceInfo : getServices()) {
                if (!serviceInfo.isEnabledForCurrentProfiles()) {
                if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
                    continue;
                }
                if (!hasCompanionDevice(serviceInfo)) {
                    continue;
                }
                try {
                    checkHasCompanionDevice(serviceInfo);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
@@ -5008,11 +5028,6 @@ public class NotificationManagerService extends SystemService {
                                modificationType);
                    }
                });
                } catch (SecurityException se) {
                    // Not a privileged listener; do not notify
                } catch (RemoteException e) {
                    Slog.e(TAG, "Cannot reach companion device service", e);
                }
            }
        }

@@ -5022,11 +5037,12 @@ public class NotificationManagerService extends SystemService {
                return;
            }
            for (final ManagedServiceInfo serviceInfo : getServices()) {
                if (!serviceInfo.isEnabledForCurrentProfiles()) {
                if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
                    continue;
                }
                if (!hasCompanionDevice(serviceInfo)) {
                    continue;
                }
                try {
                    checkHasCompanionDevice(serviceInfo);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
@@ -5034,11 +5050,6 @@ public class NotificationManagerService extends SystemService {
                                modificationType);
                    }
                });
                } catch (SecurityException se) {
                    // Not a privileged listener; do not notify
                } catch (RemoteException e) {
                    Slog.e(TAG, "Cannot reach companion device service", e);
                }
            }
        }

+24 −11
Original line number Diff line number Diff line
@@ -59,10 +59,11 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
@@ -74,20 +75,21 @@ public class NotificationManagerServiceTest {
    private NotificationManagerService mNotificationManagerService;
    private INotificationManager mBinderService;
    private NotificationManagerInternal mInternalService;
    private IPackageManager mPackageManager = mock(IPackageManager.class);
    private final PackageManager mPackageManagerClient = mock(PackageManager.class);
    @Mock
    private IPackageManager mPackageManager;
    @Mock
    private PackageManager mPackageManagerClient;
    private Context mContext = InstrumentationRegistry.getTargetContext();
    private final String PKG = mContext.getPackageName();
    private TestableLooper mTestableLooper;
    private final RankingHelper mRankingHelper = mock(RankingHelper.class);
    @Mock
    private RankingHelper mRankingHelper;
    private NotificationChannel mTestNotificationChannel = new NotificationChannel(
            TEST_CHANNEL_ID, TEST_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT);
    private NotificationManagerService.NotificationListeners mNotificationListeners =
            mock(NotificationManagerService.NotificationListeners.class);
    private ManagedServices.ManagedServiceInfo mListener =
            mNotificationListeners.new ManagedServiceInfo(
                    null, new ComponentName(PKG, "test_class"), uid, true, null, 0);
    private ICompanionDeviceManager mCompanionMgr = mock(ICompanionDeviceManager.class);
    @Mock
    private NotificationManagerService.NotificationListeners mNotificationListeners;
    private ManagedServices.ManagedServiceInfo mListener;
    @Mock private ICompanionDeviceManager mCompanionMgr;

    // Use a Testable subclass so we can simulate calls from the system without failing.
    private static class TestableNotificationManagerService extends NotificationManagerService {
@@ -102,6 +104,7 @@ public class NotificationManagerServiceTest {
    @Before
    @UiThreadTest
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        mNotificationManagerService = new TestableNotificationManagerService(mContext);

        // MockPackageManager - default returns ApplicationInfo with matching calling UID
@@ -116,6 +119,8 @@ public class NotificationManagerServiceTest {
        // Use this testable looper.
        mTestableLooper = new TestableLooper(false);

        mListener = mNotificationListeners.new ManagedServiceInfo(
                null, new ComponentName(PKG, "test_class"), uid, true, null, 0);
        when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
        mNotificationManagerService.init(mTestableLooper.getLooper(), mPackageManager,
                mPackageManagerClient, mockLightsManager, mNotificationListeners, mCompanionMgr);
@@ -631,4 +636,12 @@ public class NotificationManagerServiceTest {

        verify(mRankingHelper, never()).getNotificationChannelGroups(anyString(), anyInt());
    }

    @Test
    @UiThreadTest
    public void testHasCompanionDevice_failure() throws Exception {
        when(mCompanionMgr.getAssociations(anyString(), anyInt())).thenThrow(
                new IllegalArgumentException());
        mNotificationManagerService.hasCompanionDevice(mListener);
    }
}