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

Commit 3c6bc4d5 authored by Yuri Lin's avatar Yuri Lin Committed by Android (Google) Code Review
Browse files

Merge "Add packages with denied adjustments to PackageNotificationPreferences" into main

parents 19b9004b 4259fa31
Loading
Loading
Loading
Loading
+25 −2
Original line number Diff line number Diff line
@@ -3171,7 +3171,7 @@ public class NotificationManagerService extends SystemService {
                if (notificationClassificationUi()) {
                    mPreferencesHelper.pullPackagePreferencesStats(data,
                            getAllUsersNotificationPermissions(),
                            new ArrayMap<>());
                            mAssistants.getDeniedKeysForUsersAndPackages());
                } else {
                    mPreferencesHelper.pullPackagePreferencesStats(data,
                            getAllUsersNotificationPermissions());
@@ -3184,7 +3184,8 @@ public class NotificationManagerService extends SystemService {
                mPreferencesHelper.pullPackageChannelGroupPreferencesStats(data);
                break;
            case NOTIFICATION_ADJUSTMENT_PREFERENCES:
                if (notificationClassification() && notificationClassificationUi()) {
                if ((notificationClassification() && notificationClassificationUi())
                        || nmSummarization() || nmSummarizationUi()) {
                    mAssistants.pullAdjustmentPreferencesStats(data);
                }
                break;
@@ -12459,6 +12460,28 @@ public class NotificationManagerService extends SystemService {
            }
        }
        // For logging preferences: get a map of user id -> package name -> list of denied keys
        // This is essentially a reconfiguration of the contents of mAdjustmentKeyDeniedPackages.
        @NonNull Map<Integer, Map<String, List<String>>> getDeniedKeysForUsersAndPackages() {
            Map<Integer, Map<String, List<String>>> out = new ArrayMap<>();
            synchronized (mLock) {
                for (int userId : mAdjustmentKeyDeniedPackages.keySet()) {
                    Map<String, Set<String>> pkgsByType = mAdjustmentKeyDeniedPackages.get(userId);
                    if (!pkgsByType.isEmpty()) {
                        out.putIfAbsent(userId, new ArrayMap<>());
                        Map<String, List<String>> pkgMapForUser = out.get(userId);
                        for (String keyType : pkgsByType.keySet()) {
                            for (String pkgName : pkgsByType.get(keyType)) {
                                pkgMapForUser.putIfAbsent(pkgName, new ArrayList<>());
                                pkgMapForUser.get(pkgName).add(keyType);
                            }
                        }
                    }
                }
            }
            return out;
        }
        protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
            for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
                ArrayList<String> keys = new ArrayList<>(records.size());
+29 −29
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package com.android.server.notification;

import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.Flags.nmSummarization;
import static android.app.Flags.nmSummarizationUi;
import static android.app.Flags.notificationClassificationUi;
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
import static android.app.NotificationChannel.NEWS_ID;
@@ -99,6 +101,7 @@ import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.notification.NotificationRecordLogger.NotificationPullStatsEvent;
import com.android.server.notification.PermissionHelper.PackagePermission;
import com.android.server.uri.UriGrantsManagerInternal;

@@ -115,6 +118,7 @@ import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -2581,7 +2585,7 @@ public class PreferencesHelper implements RankingConfig {
     */
    public void pullPackagePreferencesStats(List<StatsEvent> events,
            ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
        pullPackagePreferencesStats(events, pkgPermissions, new ArrayMap<String, Set<Integer>>());
        pullPackagePreferencesStats(events, pkgPermissions, new ArrayMap<>());
    }


@@ -2592,14 +2596,12 @@ public class PreferencesHelper implements RankingConfig {
     *                       where the first represents whether the notification permission was
     *                       granted to that package, and the second represents whether the
     *                       permission was user-set.
     * @param pkgAdjustmentKeyTypes A map of package names that are not allowed to have their
     *                                 notifications classified into differently typed notification
     *                                 channels, and the channels that they're allowed to be
     *                                 classified into.
     * @param adjustmentDeniedPackages A map of user id -> package name -> the set of adjustments
     *                                 that are not allowed for that package/user.
     */
    public void pullPackagePreferencesStats(List<StatsEvent> events,
            ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions,
            @NonNull Map<String, Set<Integer>> pkgAdjustmentKeyTypes) {
            @NonNull Map<Integer, Map<String, List<String>>> adjustmentDeniedPackages) {
        Set<Pair<Integer, String>> pkgsWithPermissionsToHandle = null;
        if (pkgPermissions != null) {
            pkgsWithPermissionsToHandle = pkgPermissions.keySet();
@@ -2645,13 +2647,14 @@ public class PreferencesHelper implements RankingConfig {
                        isFsiPermissionUserSet(r.pkg, r.uid, fsiState,
                                currentPermissionFlags);

                if (!notificationClassificationUi()
                        && pkgAdjustmentKeyTypes.keySet().size() > 0) {
                if (!(notificationClassificationUi() || nmSummarization() || nmSummarizationUi())
                        && adjustmentDeniedPackages.keySet().size() > 0) {
                    Slog.w(TAG, "Pkg adjustment types improperly allowed without flag set");
                }

                int[] allowedBundleTypes =
                        getAllowedTypesForPackage(pkgAdjustmentKeyTypes, r.pkg);
                int[] deniedAdjustmentsForPackage =
                        getDeniedAdjustmentsForPackage(adjustmentDeniedPackages,
                                UserHandle.getUserId(r.uid), r.pkg);

                events.add(FrameworkStatsLog.buildStatsEvent(
                        PACKAGE_NOTIFICATION_PREFERENCES,
@@ -2662,8 +2665,9 @@ public class PreferencesHelper implements RankingConfig {
                        /* optional bool user_set_importance = 5 */ importanceIsUserSet,
                        /* optional FsiState fsi_state = 6 */ fsiState,
                        /* optional bool is_fsi_permission_user_set = 7 */ fsiIsUserSet,
                        /* repeated int32 allowed_bundle_types = 8 */ allowedBundleTypes
                ));
                        /* repeated int32 allowed_bundle_types = 8 */ new int[]{},
                        /* repeated AdjustmentKey denied_adjustments = 9 */
                        deniedAdjustmentsForPackage));
            }
        }

@@ -2675,9 +2679,6 @@ public class PreferencesHelper implements RankingConfig {
                }
                pulledEvents++;

                int[] allowedBundleTypes =
                        getAllowedTypesForPackage(pkgAdjustmentKeyTypes, p.second);

                // Because all fields are required in FrameworkStatsLog.buildStatsEvent, we have
                // to fill in default values for all the unspecified fields.
                events.add(FrameworkStatsLog.buildStatsEvent(
@@ -2690,28 +2691,27 @@ public class PreferencesHelper implements RankingConfig {
                        /* optional bool user_set_importance = 5 */ pkgPermissions.get(p).second,
                        /* optional FsiState fsi_state = 6 */ 0,
                        /* optional bool is_fsi_permission_user_set = 7 */ false,
                        /* repeated BundleTypes allowed_bundle_types = 8 */ allowedBundleTypes));
                        /* repeated BundleTypes allowed_bundle_types = 8 */ new int[]{},
                        /* repeated AdjustmentKey denied_adjustments = 9 */ new int[]{}));
            }
        }
    }

    private int[] getAllowedTypesForPackage(@NonNull
                                            Map<String, Set<Integer>> pkgAdjustmentKeyTypes,
                                            String pkg) {
        int[] allowedBundleTypes = new int[]{};
    private int[] getDeniedAdjustmentsForPackage(
            @NonNull Map<Integer, Map<String, List<String>>> adjustmentDeniedPackages,
            @UserIdInt int userId, String pkg) {
        if (notificationClassificationUi()) {
            if (pkgAdjustmentKeyTypes.containsKey(pkg)) {
                // Convert from set to int[]
                Set<Integer> types = pkgAdjustmentKeyTypes.get(pkg);
                allowedBundleTypes = new int[types.size()];
                int i = 0;
                for (int val : types) {
                    allowedBundleTypes[i] = val;
                    i++;
            if (adjustmentDeniedPackages.containsKey(userId)) {
                List<String> deniedKeys = adjustmentDeniedPackages.get(userId).getOrDefault(pkg,
                        Collections.EMPTY_LIST);
                int[] out = new int[deniedKeys.size()];
                for (int i = 0; i < deniedKeys.size(); i++) {
                    out[i] = NotificationPullStatsEvent.adjustmentKeyEnum(deniedKeys.get(i));
                }
                return out;
            }
        }
        return allowedBundleTypes;
        return new int[]{};
    }

    /**
+62 −32
Original line number Diff line number Diff line
@@ -138,6 +138,7 @@ import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.service.notification.Adjustment;
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.nano.RankingHelperProto;
import android.testing.TestableContentResolver;
@@ -6290,8 +6291,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {

        ArrayList<StatsEvent> events = new ArrayList<>();

        mHelper.pullPackagePreferencesStats(events, appPermissions,
                new ArrayMap<String, Set<Integer>>());
        mHelper.pullPackagePreferencesStats(events, appPermissions, new ArrayMap<>());

        // expected output. format: uid -> importance, as only uid (and not package name)
        // is in PackageNotificationPreferences
@@ -6327,6 +6327,13 @@ public class PreferencesHelperTest extends UiServiceTestCase {
        NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
        mHelper.createNotificationChannel(PKG_P, UID_P, channelC, true, false, UID_P, false);

        // one app for a different user + one channel
        int otherUserId = UserHandle.getUserId(UID_P) + 1;
        int otherUid = UserHandle.getUid(otherUserId, UserHandle.getAppId(UID_P));
        NotificationChannel channelOther = new NotificationChannel("d", "d", IMPORTANCE_DEFAULT);
        mHelper.createNotificationChannel(PKG_P, otherUid, channelOther, true, false, otherUid,
                false);

        // build a collection of app permissions that should be passed in and used
        ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions = new ArrayMap<>();
        pkgPermissions.put(new Pair<>(UID_N_MR1, PKG_N_MR1), new Pair<>(true, false));
@@ -6336,50 +6343,73 @@ public class PreferencesHelperTest extends UiServiceTestCase {
        mHelper.canShowBadge(PKG_O, UID_O);
        mHelper.canShowBadge(PKG_P, UID_P);

        // Sets bundles_allowed to true for these packages.
        ArrayMap<String, Set<Integer>> packageSpecificAdjustmentKeyTypes = new ArrayMap<>();
        Set<Integer> nMr1BundlesSet = new ArraySet<Integer>();
        nMr1BundlesSet.add(TYPE_NEWS);
        nMr1BundlesSet.add(TYPE_SOCIAL_MEDIA);
        packageSpecificAdjustmentKeyTypes.put(PKG_N_MR1, nMr1BundlesSet);
        Set<Integer> pBundlesSet = new ArraySet<Integer>();
        packageSpecificAdjustmentKeyTypes.put(PKG_P, pBundlesSet);
        // Sets denied types for packages.
        ArrayMap<Integer, Map<String, List<String>>> deniedAdjustments = new ArrayMap<>();
        ArrayMap<String, List<String>> deniedByPkg = new ArrayMap<>();
        List<String> nMr1DeniedAdjustments = new ArrayList<>();
        nMr1DeniedAdjustments.add(Adjustment.KEY_TYPE);
        deniedByPkg.put(PKG_N_MR1, nMr1DeniedAdjustments);
        List<String> pDeniedAdjustments = new ArrayList<>();
        pDeniedAdjustments.add(Adjustment.KEY_SUMMARIZATION);
        deniedByPkg.put(PKG_P, pDeniedAdjustments);
        deniedAdjustments.put(UserHandle.getUserId(UID_O), deniedByPkg);

        List<String> otherDeniedAdjustments = new ArrayList<>();
        otherDeniedAdjustments.add(Adjustment.KEY_TYPE);
        otherDeniedAdjustments.add(Adjustment.KEY_SUMMARIZATION);
        ArrayMap<String, List<String>> otherUserPackage = new ArrayMap<>();
        otherUserPackage.put(PKG_P, otherDeniedAdjustments);
        deniedAdjustments.put(otherUserId, otherUserPackage);

        ArrayList<StatsEvent> events = new ArrayList<>();

        mHelper.pullPackagePreferencesStats(events, pkgPermissions,
                packageSpecificAdjustmentKeyTypes);
                deniedAdjustments);

        assertEquals("total number of packages", 3, events.size());
        assertEquals("total number of packages", 4, events.size());

        // Convert resulting atoms into a map to confirm existence of logs independent of order,
        // verifying their type along the way.
        // Map is of uid -> associated atom
        Map<Integer, PackageNotificationPreferences> results = new ArrayMap<>();
        for (int i = 0; i < 4; i++) {
            AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(events.get(i));
            assertTrue(atom.hasPackageNotificationPreferences());
            PackageNotificationPreferences p = atom.getPackageNotificationPreferences();
            results.put(p.getUid(), p);
        }

        AtomsProto.Atom atom0 = StatsEventTestUtils.convertToAtom(events.get(0));
        assertTrue(atom0.hasPackageNotificationPreferences());
        PackageNotificationPreferences p0 = atom0.getPackageNotificationPreferences();
        assertThat(p0.getUid()).isEqualTo(UID_O);
        assertThat(results.containsKey(UID_O)).isTrue();
        PackageNotificationPreferences p0 = results.get(UID_O);
        assertThat(p0.getImportance()).isEqualTo(IMPORTANCE_NONE); // banned by permissions
        assertThat(p0.getUserSetImportance()).isTrue();
        assertThat(p0.getAllowedBundleTypesList()).hasSize(0);
        assertThat(p0.getDeniedAdjustmentsList()).hasSize(0);

        AtomsProto.Atom atom1 = StatsEventTestUtils.convertToAtom(events.get(1));
        assertTrue(atom1.hasPackageNotificationPreferences());
        PackageNotificationPreferences p1 = atom1.getPackageNotificationPreferences();
        assertThat(p1.getUid()).isEqualTo(UID_N_MR1);
        assertThat(results.containsKey(UID_N_MR1)).isTrue();
        PackageNotificationPreferences p1 = results.get(UID_N_MR1);
        assertThat(p1.getImportance()).isEqualTo(IMPORTANCE_DEFAULT);
        assertThat(p1.getUserSetImportance()).isFalse();
        assertThat(p1.getAllowedBundleTypesList()).hasSize(2);

        assertThat(p1.getAllowedBundleTypes(0).getNumber())
                .isEqualTo(NotificationProtoEnums.TYPE_SOCIAL_MEDIA);
        assertThat(p1.getAllowedBundleTypes(1).getNumber())
                .isEqualTo(NotificationProtoEnums.TYPE_NEWS);
        assertThat(p1.getDeniedAdjustmentsList()).hasSize(1);
        assertThat(p1.getDeniedAdjustments(0).getNumber()).isEqualTo(
                NotificationProtoEnums.KEY_TYPE);

        AtomsProto.Atom atom2 = StatsEventTestUtils.convertToAtom(events.get(2));
        assertTrue(atom2.hasPackageNotificationPreferences());
        PackageNotificationPreferences p2 = atom2.getPackageNotificationPreferences();
        assertThat(p2.getUid()).isEqualTo(UID_P);
        assertThat(results.containsKey(UID_P)).isTrue();
        PackageNotificationPreferences p2 = results.get(UID_P);
        assertThat(p2.getImportance()).isEqualTo(IMPORTANCE_UNSPECIFIED); // default: unspecified
        assertThat(p2.getUserSetImportance()).isFalse();
        assertThat(p2.getAllowedBundleTypesList()).hasSize(0);
        assertThat(p2.getDeniedAdjustmentsList()).hasSize(1);
        assertThat(p2.getDeniedAdjustments(0).getNumber()).isEqualTo(
                NotificationProtoEnums.KEY_SUMMARIZATION);

        assertThat(results.containsKey(otherUid)).isTrue();
        PackageNotificationPreferences p3 = results.get(otherUid);
        assertThat(p3.getImportance()).isEqualTo(IMPORTANCE_UNSPECIFIED); // default: unspecified
        assertThat(p3.getUserSetImportance()).isFalse();
        assertThat(p3.getDeniedAdjustmentsList()).hasSize(2);
        assertThat(p3.getDeniedAdjustments(0).getNumber()).isEqualTo(
                NotificationProtoEnums.KEY_TYPE);
        assertThat(p3.getDeniedAdjustments(1).getNumber()).isEqualTo(
                NotificationProtoEnums.KEY_SUMMARIZATION);
    }

    @Test