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

Commit d6e679f4 authored by Yuri Lin's avatar Yuri Lin
Browse files

Add user-set boolean to notification permission values.

This change allows for logs and dumps to collect whether any package bans were set by the user or not, and adds that info to the string (logcat) dump. This is also in preparation for adding this field to the PackageNotificationPreferences pulled atom (will be in a future CL).

Bug: 194833441
Test: NotificationmanagerServiceTest, NotificationPermissionMigrationTest, PermissionHelperTest, PreferencesHelperTest
Change-Id: Ic119522a7fedd1869697f320e57813292f4115ce
parent ff92c7eb
Loading
Loading
Loading
Loading
+8 −7
Original line number Diff line number Diff line
@@ -5073,7 +5073,7 @@ public class NotificationManagerService extends SystemService {
            final DumpFilter filter = DumpFilter.parseFromArguments(args);
            final long token = Binder.clearCallingIdentity();
            try {
                final ArrayMap<Pair<Integer, String>, Boolean> pkgPermissions =
                final ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions =
                        getAllUsersNotificationPermissions();
                if (filter.stats) {
                    dumpJson(pw, filter, pkgPermissions);
@@ -5911,17 +5911,18 @@ public class NotificationManagerService extends SystemService {
    // Returns a single map containing that info keyed by (uid, package name) for all users.
    // Because this calls into mPermissionHelper, this method must never be called with a lock held.
    @VisibleForTesting
    protected ArrayMap<Pair<Integer, String>, Boolean> getAllUsersNotificationPermissions() {
    protected ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>>
            getAllUsersNotificationPermissions() {
        // don't bother if migration is not enabled
        if (!mEnableAppSettingMigration) {
            return null;
        }
        ArrayMap<Pair<Integer, String>, Boolean> allPermissions = new ArrayMap<>();
        ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> allPermissions = new ArrayMap<>();
        final List<UserInfo> allUsers = mUm.getUsers();
        // for each of these, get the package notification permissions that are associated
        // with this user and add it to the map
        for (UserInfo ui : allUsers) {
            ArrayMap<Pair<Integer, String>, Boolean> userPermissions =
            ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> userPermissions =
                    mPermissionHelper.getNotificationPermissionValues(
                            ui.getUserHandle().getIdentifier());
            for (Pair<Integer, String> pair : userPermissions.keySet()) {
@@ -5932,7 +5933,7 @@ public class NotificationManagerService extends SystemService {
    }

    private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter,
            ArrayMap<Pair<Integer, String>, Boolean> pkgPermissions) {
            ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
        JSONObject dump = new JSONObject();
        try {
            dump.put("service", "Notification Manager");
@@ -5956,7 +5957,7 @@ public class NotificationManagerService extends SystemService {
    }

    private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter,
            ArrayMap<Pair<Integer, String>, Boolean> pkgPermissions) {
            ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
        final ProtoOutputStream proto = new ProtoOutputStream(fd);
        synchronized (mNotificationLock) {
            int N = mNotificationList.size();
@@ -6047,7 +6048,7 @@ public class NotificationManagerService extends SystemService {
    }

    void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter,
            ArrayMap<Pair<Integer, String>, Boolean> pkgPermissions) {
            ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
        pw.print("Current Notification Manager state");
        if (filter.filtered) {
            pw.print(" (filtered to "); pw.print(filter); pw.print(")");
+18 −6
Original line number Diff line number Diff line
@@ -36,10 +36,8 @@ import android.util.Slog;
import com.android.server.pm.permission.PermissionManagerServiceInternal;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

@@ -139,15 +137,17 @@ public final class PermissionHelper {
        return granted;
    }

    // Key: (uid, package name); Value: (granted, user set)
    public @NonNull
    ArrayMap<Pair<Integer, String>, Boolean> getNotificationPermissionValues(
            int userId) {
            ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>>
                    getNotificationPermissionValues(int userId) {
        assertFlag();
        ArrayMap<Pair<Integer, String>, Boolean> notifPermissions = new ArrayMap<>();
        ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> notifPermissions = new ArrayMap<>();
        Set<Pair<Integer, String>> allRequestingUids = getAppsRequestingPermission(userId);
        Set<Pair<Integer, String>> allApprovedUids = getAppsGrantedPermission(userId);
        for (Pair<Integer, String> pair : allRequestingUids) {
            notifPermissions.put(pair, allApprovedUids.contains(pair));
            notifPermissions.put(pair, new Pair(allApprovedUids.contains(pair),
                    isPermissionUserSet(pair.second /* package name */, userId)));
        }
        return notifPermissions;
    }
@@ -196,6 +196,18 @@ public final class PermissionHelper {
        return false;
    }

    boolean isPermissionUserSet(String packageName, @UserIdInt int userId) {
        assertFlag();
        try {
            int flags = mPermManager.getPermissionFlags(packageName, NOTIFICATION_PERMISSION,
                    userId);
            return (flags & PackageManager.FLAG_PERMISSION_USER_SET) != 0;
        } catch (RemoteException e) {
            Slog.e(TAG, "Could not reach system server", e);
        }
        return false;
    }

    private void assertFlag() {
        if (!mMigrationEnabled) {
            throw new IllegalStateException("Method called without checking flag value");
+29 −22
Original line number Diff line number Diff line
@@ -557,7 +557,7 @@ public class PreferencesHelper implements RankingConfig {
            out.attributeBoolean(null, ATT_HIDE_SILENT, mHideSilentStatusBarIcons);
            out.endTag(null, TAG_STATUS_ICONS);
        }
        ArrayMap<Pair<Integer, String>, Boolean> notifPermissions = new ArrayMap<>();
        ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> notifPermissions = new ArrayMap<>();
        if (mPermissionHelper.isMigrationEnabled() && forBackup) {
            notifPermissions = mPermissionHelper.getNotificationPermissionValues(userId);
        }
@@ -573,9 +573,8 @@ public class PreferencesHelper implements RankingConfig {
                out.attribute(null, ATT_NAME, r.pkg);
                if (!notifPermissions.isEmpty()) {
                    Pair<Integer, String> app = new Pair(r.uid, r.pkg);
                    out.attributeInt(null, ATT_IMPORTANCE, notifPermissions.get(app)
                            ? IMPORTANCE_DEFAULT
                            : IMPORTANCE_NONE);
                    out.attributeInt(null, ATT_IMPORTANCE,
                            notifPermissions.get(app).first ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE);
                    notifPermissions.remove(app);
                } else {
                    if (r.importance != DEFAULT_IMPORTANCE) {
@@ -642,7 +641,7 @@ public class PreferencesHelper implements RankingConfig {
                out.startTag(null, TAG_PACKAGE);
                out.attribute(null, ATT_NAME, app.second);
                out.attributeInt(null, ATT_IMPORTANCE,
                        notifPermissions.get(app) ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE);
                        notifPermissions.get(app).first ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE);
                out.endTag(null, TAG_PACKAGE);
            }
        }
@@ -1932,7 +1931,7 @@ public class PreferencesHelper implements RankingConfig {

    public void dump(PrintWriter pw, String prefix,
            @NonNull NotificationManagerService.DumpFilter filter,
            ArrayMap<Pair<Integer, String>, Boolean> pkgPermissions) {
            ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
        pw.print(prefix);
        pw.println("per-package config version: " + XML_VERSION);

@@ -1946,7 +1945,7 @@ public class PreferencesHelper implements RankingConfig {

    public void dump(ProtoOutputStream proto,
            @NonNull NotificationManagerService.DumpFilter filter,
            ArrayMap<Pair<Integer, String>, Boolean> pkgPermissions) {
            ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
        synchronized (mPackagePreferences) {
            dumpPackagePreferencesLocked(proto, RankingHelperProto.RECORDS, filter,
                    mPackagePreferences, pkgPermissions);
@@ -1958,7 +1957,7 @@ public class PreferencesHelper implements RankingConfig {
    private void dumpPackagePreferencesLocked(PrintWriter pw, String prefix,
            @NonNull NotificationManagerService.DumpFilter filter,
            ArrayMap<String, PackagePreferences> packagePreferences,
            ArrayMap<Pair<Integer, String>, Boolean> packagePermissions) {
            ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> packagePermissions) {
        // Used for tracking which package preferences we've seen already for notification
        // permission reasons; after handling packages with local preferences, we'll want to dump
        // the ones with notification permissions set but not local prefs.
@@ -1987,8 +1986,10 @@ public class PreferencesHelper implements RankingConfig {
                    if (packagePermissions != null && pkgsWithPermissionsToHandle.contains(key)) {
                        pw.print(" importance=");
                        pw.print(NotificationListenerService.Ranking.importanceToString(
                                packagePermissions.get(key)
                                packagePermissions.get(key).first
                                        ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE));
                        pw.print(" userSet=");
                        pw.print(packagePermissions.get(key).second);
                        pkgsWithPermissionsToHandle.remove(key);
                    }
                }
@@ -2042,7 +2043,10 @@ public class PreferencesHelper implements RankingConfig {
                    pw.print(')');
                    pw.print(" importance=");
                    pw.print(NotificationListenerService.Ranking.importanceToString(
                            packagePermissions.get(p) ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE));
                            packagePermissions.get(p).first
                                    ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE));
                    pw.print(" userSet=");
                    pw.print(packagePermissions.get(p).second);
                    pw.println();
                }
            }
@@ -2052,7 +2056,7 @@ public class PreferencesHelper implements RankingConfig {
    private void dumpPackagePreferencesLocked(ProtoOutputStream proto, long fieldId,
            @NonNull NotificationManagerService.DumpFilter filter,
            ArrayMap<String, PackagePreferences> packagePreferences,
            ArrayMap<Pair<Integer, String>, Boolean> packagePermissions) {
            ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> packagePermissions) {
        Set<Pair<Integer, String>> pkgsWithPermissionsToHandle = null;
        if (packagePermissions != null) {
            pkgsWithPermissionsToHandle = packagePermissions.keySet();
@@ -2071,7 +2075,8 @@ public class PreferencesHelper implements RankingConfig {
                    Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
                    if (packagePermissions != null && pkgsWithPermissionsToHandle.contains(key)) {
                        proto.write(RankingHelperProto.RecordProto.IMPORTANCE,
                                packagePermissions.get(key) ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE);
                                packagePermissions.get(key).first
                                        ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE);
                        pkgsWithPermissionsToHandle.remove(key);
                    }
                } else {
@@ -2099,7 +2104,8 @@ public class PreferencesHelper implements RankingConfig {
                    proto.write(RankingHelperProto.RecordProto.PACKAGE, p.second);
                    proto.write(RankingHelperProto.RecordProto.UID, p.first);
                    proto.write(RankingHelperProto.RecordProto.IMPORTANCE,
                            packagePermissions.get(p) ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE);
                            packagePermissions.get(p).first
                                    ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE);
                    proto.end(fToken);
                }
            }
@@ -2110,7 +2116,7 @@ public class PreferencesHelper implements RankingConfig {
     * Fills out {@link PackageNotificationPreferences} proto and wraps it in a {@link StatsEvent}.
     */
    public void pullPackagePreferencesStats(List<StatsEvent> events,
            ArrayMap<Pair<Integer, String>, Boolean> pkgPermissions) {
            ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
        Set<Pair<Integer, String>> pkgsWithPermissionsToHandle = null;
        if (pkgPermissions != null) {
            pkgsWithPermissionsToHandle = pkgPermissions.keySet();
@@ -2134,7 +2140,8 @@ public class PreferencesHelper implements RankingConfig {
                    int importance = IMPORTANCE_NONE;
                    Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
                    if (pkgPermissions != null && pkgsWithPermissionsToHandle.contains(key)) {
                        importance = pkgPermissions.get(key) ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE;
                        importance = pkgPermissions.get(key).first
                                ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE;
                        pkgsWithPermissionsToHandle.remove(key);
                    }
                    event.writeInt(importance);
@@ -2158,7 +2165,7 @@ public class PreferencesHelper implements RankingConfig {
                        .setAtomId(PACKAGE_NOTIFICATION_PREFERENCES);
                event.writeInt(p.first);
                event.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
                event.writeInt(pkgPermissions.get(p) ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE);
                event.writeInt(pkgPermissions.get(p).first ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE);

                // fill out the rest of the fields with default values so as not to confuse the
                // builder
@@ -2236,7 +2243,7 @@ public class PreferencesHelper implements RankingConfig {
    }

    public JSONObject dumpJson(NotificationManagerService.DumpFilter filter,
            ArrayMap<Pair<Integer, String>, Boolean> pkgPermissions) {
            ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
        JSONObject ranking = new JSONObject();
        JSONArray PackagePreferencess = new JSONArray();
        try {
@@ -2266,7 +2273,7 @@ public class PreferencesHelper implements RankingConfig {
                                    && pkgsWithPermissionsToHandle.contains(key)) {
                                PackagePreferences.put("importance",
                                        NotificationListenerService.Ranking.importanceToString(
                                                pkgPermissions.get(key)
                                                pkgPermissions.get(key).first
                                                        ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE));
                                pkgsWithPermissionsToHandle.remove(key);
                            }
@@ -2316,7 +2323,7 @@ public class PreferencesHelper implements RankingConfig {
                        PackagePreferences.put("packageName", p.second);
                        PackagePreferences.put("importance",
                                NotificationListenerService.Ranking.importanceToString(
                                        pkgPermissions.get(p)
                                        pkgPermissions.get(p).first
                                                ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE));
                    } catch (JSONException e) {
                        // pass
@@ -2344,7 +2351,7 @@ public class PreferencesHelper implements RankingConfig {
     * @return
     */
    public JSONArray dumpBansJson(NotificationManagerService.DumpFilter filter,
            ArrayMap<Pair<Integer, String>, Boolean> pkgPermissions) {
            ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
        JSONArray bans = new JSONArray();
        Map<Integer, String> packageBans = mPermissionHelper.isMigrationEnabled()
                ? getPermissionBasedPackageBans(pkgPermissions) : getPackageBans();
@@ -2383,11 +2390,11 @@ public class PreferencesHelper implements RankingConfig {
    // Same functionality as getPackageBans by extracting the set of packages from the provided
    // map that are disallowed from sending notifications.
    protected Map<Integer, String> getPermissionBasedPackageBans(
            ArrayMap<Pair<Integer, String>, Boolean> pkgPermissions) {
            ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
        ArrayMap<Integer, String> packageBans = new ArrayMap<>();
        if (pkgPermissions != null) {
            for (Pair<Integer, String> p : pkgPermissions.keySet()) {
                if (!pkgPermissions.get(p)) {
                if (!pkgPermissions.get(p).first) {
                    packageBans.put(p.first, p.second);
                }
            }
+14 −10
Original line number Diff line number Diff line
@@ -839,21 +839,25 @@ public class NotificationPermissionMigrationTest extends UiServiceTestCase {
        when(mUm.getUsers()).thenReturn(userInfos);

        // construct the permissions for each of them
        ArrayMap<Pair<Integer, String>, Boolean> permissions0 = new ArrayMap<>(),
        ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> permissions0 = new ArrayMap<>(),
                permissions1 = new ArrayMap<>();
        permissions0.put(new Pair<>(10, "package1"), true);
        permissions0.put(new Pair<>(20, "package2"), false);
        permissions1.put(new Pair<>(11, "package1"), false);
        permissions1.put(new Pair<>(21, "package2"), true);
        permissions0.put(new Pair<>(10, "package1"), new Pair<>(true, false));
        permissions0.put(new Pair<>(20, "package2"), new Pair<>(false, true));
        permissions1.put(new Pair<>(11, "package1"), new Pair<>(false, false));
        permissions1.put(new Pair<>(21, "package2"), new Pair<>(true, true));
        when(mPermissionHelper.getNotificationPermissionValues(0)).thenReturn(permissions0);
        when(mPermissionHelper.getNotificationPermissionValues(1)).thenReturn(permissions1);
        when(mPermissionHelper.getNotificationPermissionValues(2)).thenReturn(new ArrayMap<>());

        ArrayMap<Pair<Integer, String>, Boolean> combinedPermissions =
        ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> combinedPermissions =
                mService.getAllUsersNotificationPermissions();
        assertTrue(combinedPermissions.get(new Pair<>(10, "package1")));
        assertFalse(combinedPermissions.get(new Pair<>(20, "package2")));
        assertFalse(combinedPermissions.get(new Pair<>(11, "package1")));
        assertTrue(combinedPermissions.get(new Pair<>(21, "package2")));
        assertTrue(combinedPermissions.get(new Pair<>(10, "package1")).first);
        assertFalse(combinedPermissions.get(new Pair<>(10, "package1")).second);
        assertFalse(combinedPermissions.get(new Pair<>(20, "package2")).first);
        assertTrue(combinedPermissions.get(new Pair<>(20, "package2")).second);
        assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).first);
        assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).second);
        assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).first);
        assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).second);
    }
}
+16 −6
Original line number Diff line number Diff line
@@ -42,7 +42,6 @@ import android.content.pm.ParceledListSlice;
import android.permission.IPermissionManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Pair;
import android.util.Slog;

import androidx.test.runner.AndroidJUnit4;

@@ -312,11 +311,22 @@ public class PermissionHelperTest extends UiServiceTestCase {
        when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS), anyInt()))
                .thenReturn(requesting);

        Map<Pair<Integer, String>, Boolean> expected = ImmutableMap.of(new Pair(1, "first"), true,
                new Pair(2, "second"), true,
                new Pair(3, "third"), false);

        Map<Pair<Integer, String>, Boolean> actual =
        // 2 and 3 are user-set permissions
        when(mPermManager.getPermissionFlags(
                "first", Manifest.permission.POST_NOTIFICATIONS, userId)).thenReturn(0);
        when(mPermManager.getPermissionFlags(
                "second", Manifest.permission.POST_NOTIFICATIONS, userId))
                .thenReturn(FLAG_PERMISSION_USER_SET);
        when(mPermManager.getPermissionFlags(
                "third", Manifest.permission.POST_NOTIFICATIONS, userId))
                .thenReturn(FLAG_PERMISSION_USER_SET);

        Map<Pair<Integer, String>, Pair<Boolean, Boolean>> expected =
                ImmutableMap.of(new Pair(1, "first"), new Pair(true, false),
                    new Pair(2, "second"), new Pair(true, true),
                    new Pair(3, "third"), new Pair(false, true));

        Map<Pair<Integer, String>, Pair<Boolean, Boolean>> actual =
                mPermissionHelper.getNotificationPermissionValues(userId);

        assertThat(actual).containsExactlyEntriesIn(expected);
Loading