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

Commit 92a0fe3d authored by Nate Myren's avatar Nate Myren Committed by Android (Google) Code Review
Browse files

Merge "Redact smart replies and actions from untrusted listeners" into main

parents 95722edc 1d37ad40
Loading
Loading
Loading
Loading
+24 −18
Original line number Diff line number Diff line
@@ -10754,6 +10754,14 @@ public class NotificationManagerService extends SystemService {
            final String key = record.getSbn().getKey();
            final NotificationListenerService.Ranking ranking =
                    new NotificationListenerService.Ranking();
            ArrayList<Notification.Action> smartActions = record.getSystemGeneratedSmartActions();
            ArrayList<CharSequence> smartReplies = record.getSmartReplies();
            if (redactSensitiveNotificationsFromUntrustedListeners()
                    && !mListeners.isUidTrusted(info.uid)
                    && mListeners.hasSensitiveContent(record)) {
                smartActions = null;
                smartReplies = null;
            }
            ranking.populate(
                    key,
                    rankings.size(),
@@ -10771,8 +10779,8 @@ public class NotificationManagerService extends SystemService {
                    record.isHidden(),
                    record.getLastAudiblyAlertedMs(),
                    record.getSound() != null || record.getVibration() != null,
                    record.getSystemGeneratedSmartActions(),
                    record.getSmartReplies(),
                    smartActions,
                    smartReplies,
                    record.canBubble(),
                    record.isTextChanged(),
                    record.isConversation(),
@@ -11522,21 +11530,17 @@ public class NotificationManagerService extends SystemService {
            super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, userSet);
            String pkgName = getPackageName(pkgOrComponent);
            if (redactSensitiveNotificationsFromUntrustedListeners()) {
                try {
                    int uid = mPackageManagerClient.getPackageUidAsUser(pkgName, userId);
                    if (!enabled) {
                int uid = mPackageManagerInternal.getPackageUid(pkgName, 0, userId);
                if (!enabled && uid >= 0) {
                    synchronized (mTrustedListenerUids) {
                        mTrustedListenerUids.remove(uid);
                    }
                }
                    if (enabled && isAppTrustedNotificationListenerService(uid, pkgName)) {
                if (enabled && uid >= 0 && isAppTrustedNotificationListenerService(uid, pkgName)) {
                    synchronized (mTrustedListenerUids) {
                        mTrustedListenerUids.add(uid);
                    }
                }
                } catch (NameNotFoundException e) {
                    Slog.e(TAG, "PackageManager could not find package " + pkgName, e);
                }
            }
            mContext.sendBroadcastAsUser(
@@ -11955,8 +11959,10 @@ public class NotificationManagerService extends SystemService {
                for (final ManagedServiceInfo info : getServices()) {
                    boolean isTrusted = isUidTrusted(info.uid);
                    boolean sendRedacted = isNewSensitive && !isTrusted;
                    boolean sendOldRedacted = isOldSensitive && !isTrusted;
                    boolean sendRedacted = redactSensitiveNotificationsFromUntrustedListeners()
                            && isNewSensitive && !isTrusted;
                    boolean sendOldRedacted = redactSensitiveNotificationsFromUntrustedListeners()
                            && isOldSensitive && !isTrusted;
                    boolean sbnVisible = isVisibleToListener(sbn, r.getNotificationType(), info);
                    boolean oldSbnVisible = (oldSbn != null)
                            && isVisibleToListener(oldSbn, old.getNotificationType(), info);
@@ -12055,7 +12061,7 @@ public class NotificationManagerService extends SystemService {
        StatusBarNotification redactStatusBarNotification(StatusBarNotification sbn) {
            if (!redactSensitiveNotificationsFromUntrustedListeners()) {
                return sbn;
                throw new RuntimeException("redactStatusBarNotification called while flag is off");
            }
            ApplicationInfo appInfo = sbn.getNotification().extras.getParcelable(
@@ -12227,6 +12233,7 @@ public class NotificationManagerService extends SystemService {
        public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
            boolean isHiddenRankingUpdate = changedHiddenNotifications != null
                    && changedHiddenNotifications.size() > 0;
            // TODO (b/73052211): if the ranking update changed the notification type,
            // cancel notifications for NLSes that can't see them anymore
            for (final ManagedServiceInfo serviceInfo : getServices()) {
@@ -12250,7 +12257,6 @@ public class NotificationManagerService extends SystemService {
                if (notifyThisListener || !isHiddenRankingUpdate) {
                    final NotificationRankingUpdate update = makeRankingUpdateLocked(
                            serviceInfo);
                    mHandler.post(() -> notifyRankingUpdate(serviceInfo, update));
                }
            }
+10 −15
Original line number Diff line number Diff line
@@ -68,10 +68,7 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.UserHandle;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.INotificationListener;
import android.service.notification.NotificationListenerFilter;
import android.service.notification.NotificationListenerService;
@@ -111,7 +108,7 @@ import java.util.concurrent.CountDownLatch;
public class NotificationListenersTest extends UiServiceTestCase {

    @Rule
    public CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
    public SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    @Mock
    private PackageManager mPm;
@@ -696,8 +693,8 @@ public class NotificationListenersTest extends UiServiceTestCase {
    }

    @Test
    @RequiresFlagsEnabled(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS)
    public void testListenerTrusted_withPermission() throws RemoteException {
        mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
        when(mNm.mPackageManager.checkUidPermission(RECEIVE_SENSITIVE_NOTIFICATIONS, mUid1))
                .thenReturn(PERMISSION_GRANTED);
        ManagedServices.ManagedServiceInfo info = getMockServiceInfo();
@@ -706,8 +703,8 @@ public class NotificationListenersTest extends UiServiceTestCase {
    }

    @Test
    @RequiresFlagsEnabled(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS)
    public void testListenerTrusted_withSystemSignature() {
        mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
        when(mNm.mPackageManagerInternal.isPlatformSigned(mCn1.getPackageName())).thenReturn(true);
        ManagedServices.ManagedServiceInfo info = getMockServiceInfo();
        mListeners.onServiceAdded(info);
@@ -715,8 +712,8 @@ public class NotificationListenersTest extends UiServiceTestCase {
    }

    @Test
    @RequiresFlagsEnabled(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS)
    public void testListenerTrusted_withCdmAssociation() throws Exception {
        mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
        mNm.mCompanionManager = mock(ICompanionDeviceManager.class);
        AssociationInfo assocInfo = mock(AssociationInfo.class);
        when(assocInfo.isRevoked()).thenReturn(false);
@@ -731,16 +728,16 @@ public class NotificationListenersTest extends UiServiceTestCase {
    }

    @Test
    @RequiresFlagsDisabled(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS)
    public void testListenerTrusted_ifFlagDisabled() {
        mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
        ManagedServices.ManagedServiceInfo info = getMockServiceInfo();
        mListeners.onServiceAdded(info);
        assertTrue(mListeners.isUidTrusted(mUid1));
    }

    @Test
    @RequiresFlagsEnabled(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS)
    public void testRedaction_whenPosted() {
        mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
        ArrayList<ManagedServices.ManagedServiceInfo> infos = new ArrayList<>();
        infos.add(getMockServiceInfo());
        doReturn(infos).when(mListeners).getServices();
@@ -762,13 +759,11 @@ public class NotificationListenersTest extends UiServiceTestCase {
        mListeners.notifyPostedLocked(r, old);
        verify(mListeners, atLeast(1)).redactStatusBarNotification(eq(sbn));
        verify(mListeners, never()).redactStatusBarNotification(eq(oldSbn));


    }

    @Test
    @RequiresFlagsEnabled(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS)
    public void testRedaction_whenPosted_oldRemoved() {
        mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
        ArrayList<ManagedServices.ManagedServiceInfo> infos = new ArrayList<>();
        infos.add(getMockServiceInfo());
        doReturn(infos).when(mListeners).getServices();
@@ -795,8 +790,8 @@ public class NotificationListenersTest extends UiServiceTestCase {
    }

    @Test
    @RequiresFlagsEnabled(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS)
    public void testRedaction_whenRemoved() {
        mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
        doReturn(mock(StatusBarNotification.class))
                .when(mListeners).redactStatusBarNotification(any());
        ArrayList<ManagedServices.ManagedServiceInfo> infos = new ArrayList<>();
@@ -816,8 +811,8 @@ public class NotificationListenersTest extends UiServiceTestCase {
    }

    @Test
    @RequiresFlagsDisabled(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS)
    public void testRedaction_noneIfFlagDisabled() {
        mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
        ArrayList<ManagedServices.ManagedServiceInfo> infos = new ArrayList<>();
        infos.add(getMockServiceInfo());
        doReturn(infos).when(mListeners).getServices();
+96 −10
Original line number Diff line number Diff line
@@ -77,7 +77,9 @@ import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
import static android.service.notification.Adjustment.KEY_CONTEXTUAL_ACTIONS;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
import static android.service.notification.Adjustment.KEY_TEXT_REPLIES;
import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
import static android.service.notification.Flags.FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS;
import static android.service.notification.Condition.SOURCE_CONTEXT;
@@ -216,9 +218,6 @@ import android.os.UserManager;
import android.os.WorkSource;
import android.permission.PermissionManager;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import android.platform.test.rule.DeniedDevices;
import android.platform.test.rule.DeviceProduct;
@@ -361,9 +360,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    @Rule
    public TestRule compatChangeRule = new PlatformCompatChangeRule();
    @Rule
    public CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
    private TestableNotificationManagerService mService;
    private INotificationManager mBinderService;
    private NotificationManagerInternal mInternalService;
@@ -11778,8 +11774,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    }
    @Test
    @RequiresFlagsEnabled(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS)
    public void testGetActiveNotificationsFromListener_redactNotification() throws Exception {
        mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
        NotificationRecord r =
                generateNotificationRecord(mTestNotificationChannel, 0, 0);
        mService.addNotification(r);
@@ -11808,12 +11804,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    }
    @Test
    @RequiresFlagsEnabled(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS)
    public void testGetSnoozedNotificationsFromListener_redactNotification() throws Exception {
        mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
        NotificationRecord r =
                generateNotificationRecord(mTestNotificationChannel, 0, 0);
        mService.addNotification(r);
        mService.snoozeNotificationInt(r.getKey(), 1000, null, mListener);
        when(mSnoozeHelper.getSnoozed()).thenReturn(List.of(r));
        when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
        when(mListeners.hasSensitiveContent(any())).thenReturn(true);
        StatusBarNotification redacted = generateRedactedSbn(mTestNotificationChannel, 1, 1);
@@ -11992,6 +11987,97 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(2, nru.getRankingMap().getOrderedKeys().length);
    }
    @Test
    public void testMakeRankingUpdate_redactsIfRecordSensitiveAndServiceUntrusted() {
        mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
        when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
        when(mListeners.hasSensitiveContent(any())).thenReturn(true);
        NotificationRecord pkgA = new NotificationRecord(mContext,
                generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
        addSmartActionsAndReplies(pkgA);
        mService.addNotification(pkgA);
        NotificationRecord pkgB = new NotificationRecord(mContext,
                generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
        addSmartActionsAndReplies(pkgB);
        mService.addNotification(pkgB);
        ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
        when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
        when(info.isSameUser(anyInt())).thenReturn(true);
        NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
        NotificationListenerService.Ranking ranking =
                nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
        assertEquals(0, ranking.getSmartActions().size());
        assertEquals(0, ranking.getSmartReplies().size());
        NotificationListenerService.Ranking ranking2 =
                nru.getRankingMap().getRawRankingObject(pkgB.getSbn().getKey());
        assertEquals(0, ranking2.getSmartActions().size());
        assertEquals(0, ranking2.getSmartReplies().size());
    }
    @Test
    public void testMakeRankingUpdate_doestntRedactIfFlagDisabled() {
        mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
        when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
        when(mListeners.hasSensitiveContent(any())).thenReturn(true);
        NotificationRecord pkgA = new NotificationRecord(mContext,
                generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
        addSmartActionsAndReplies(pkgA);
        mService.addNotification(pkgA);
        ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
        when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
        when(info.isSameUser(anyInt())).thenReturn(true);
        NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
        NotificationListenerService.Ranking ranking =
                nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
        assertEquals(1, ranking.getSmartActions().size());
        assertEquals(1, ranking.getSmartReplies().size());
    }
    @Test
    public void testMakeRankingUpdate_doesntRedactIfNotSensitiveOrServiceTrusted() {
        mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
        NotificationRecord pkgA = new NotificationRecord(mContext,
                generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
        addSmartActionsAndReplies(pkgA);
        mService.addNotification(pkgA);
        ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
        when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
        when(info.isSameUser(anyInt())).thenReturn(true);
        // No sensitive content, no redaction
        when(mListeners.isUidTrusted(eq(1000))).thenReturn(false);
        when(mListeners.hasSensitiveContent(any())).thenReturn(false);
        NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
        NotificationListenerService.Ranking ranking =
                nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
        assertEquals(1, ranking.getSmartActions().size());
        assertEquals(1, ranking.getSmartReplies().size());
        // trusted listener, no redaction
        when(mListeners.isUidTrusted(eq(1000))).thenReturn(true);
        when(mListeners.hasSensitiveContent(any())).thenReturn(true);
        nru = mService.makeRankingUpdateLocked(info);
        ranking = nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
        assertEquals(1, ranking.getSmartActions().size());
        assertEquals(1, ranking.getSmartReplies().size());
    }
    private void addSmartActionsAndReplies(NotificationRecord record) {
        Bundle b = new Bundle();
        ArrayList<Notification.Action> actions = new ArrayList<>();
        actions.add(new Notification.Action(0, "", null));
        b.putParcelableArrayList(KEY_CONTEXTUAL_ACTIONS, actions);
        ArrayList<CharSequence> replies = new ArrayList<>(List.of("test"));
        b.putCharSequenceArrayList(KEY_TEXT_REPLIES, replies);
        Adjustment a = new Adjustment(record.getSbn().getPackageName(), record.getSbn().getKey(),
                b, "", record.getUserId());
        record.addAdjustment(a);
        record.applyAdjustments();
    }
    @Test
    public void testMaybeShowReviewPermissionsNotification_flagOff() {
        mService.setShowReviewPermissionsNotification(false);