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

Commit 2686322e authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fix backup and restore of package blocks" into oc-dev

parents d63b77c6 5fe2eae6
Loading
Loading
Loading
Loading
+11 −75
Original line number Diff line number Diff line
@@ -90,7 +90,6 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.media.AudioManager;
@@ -114,7 +113,6 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
import android.os.VibrationEffect;
import android.provider.Settings;
@@ -473,19 +471,6 @@ public class NotificationManagerService extends SystemService {
        out.endDocument();
    }

    /** Use this when you actually want to post a notification or toast.
     *
     * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
     */
    private boolean noteNotificationOp(String pkg, int uid) {
        if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
                != AppOpsManager.MODE_ALLOWED) {
            Slog.v(TAG, "notifications are disabled by AppOps for " + pkg);
            return false;
        }
        return true;
    }

    /** Use this to check if a package can post a notification or toast. */
    private boolean checkNotificationOp(String pkg, int uid) {
        return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
@@ -1154,7 +1139,7 @@ public class NotificationManagerService extends SystemService {
        final File systemDir = new File(Environment.getDataDirectory(), "system");
        mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));

        syncBlockDb();
        loadPolicyFile();

        // This is a ManagedServices object that keeps track of the listeners.
        mListeners = notificationListeners;
@@ -1267,46 +1252,6 @@ public class NotificationManagerService extends SystemService {
                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
    }

    /**
     * Make sure the XML config and the the AppOps system agree about blocks.
     */
    private void syncBlockDb() {
        loadPolicyFile();

        // sync bans from ranker into app opps
        Map<Integer, String> packageBans = mRankingHelper.getPackageBans();
        for(Entry<Integer, String> ban : packageBans.entrySet()) {
            final int uid = ban.getKey();
            final String packageName = ban.getValue();
            setNotificationsEnabledForPackageImpl(packageName, uid, false);
        }

        // sync bans from app opps into ranker
        packageBans.clear();
        for (UserInfo user : UserManager.get(getContext()).getUsers()) {
            final int userId = user.getUserHandle().getIdentifier();
            final PackageManager packageManager = getContext().getPackageManager();
            List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
            final int packageCount = packages.size();
            for (int p = 0; p < packageCount; p++) {
                final String packageName = packages.get(p).packageName;
                try {
                    final int uid = packageManager.getPackageUidAsUser(packageName, userId);
                    if (!checkNotificationOp(packageName, uid)) {
                        packageBans.put(uid, packageName);
                    }
                } catch (NameNotFoundException e) {
                    // forget you
                }
            }
        }
        for (Entry<Integer, String> ban : packageBans.entrySet()) {
            mRankingHelper.setImportance(ban.getValue(), ban.getKey(), IMPORTANCE_NONE);
        }

        savePolicyFile();
    }

    @Override
    public void onBootPhase(int phase) {
        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
@@ -1328,19 +1273,6 @@ public class NotificationManagerService extends SystemService {
        }
    }

    void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
        Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);

        mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
                enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);

        // Now, cancel any outstanding notifications that are part of a just-disabled app
        if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
            cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
                    UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
        }
    }

    private void updateListenerHintsLocked() {
        final int hints = calculateHints();
        if (hints == mListenerHints) return;
@@ -1522,7 +1454,8 @@ public class NotificationManagerService extends SystemService {
                    isPackageSuspendedForUser(pkg, Binder.getCallingUid());

            if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
                    (!noteNotificationOp(pkg, Binder.getCallingUid()) || isPackageSuspended)) {
                    (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
                            || isPackageSuspended)) {
                Slog.e(TAG, "Suppressing toast from package " + pkg
                        + (isPackageSuspended
                                ? " due to package suspended by administrator."
@@ -1643,8 +1576,12 @@ public class NotificationManagerService extends SystemService {
        public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
            checkCallerIsSystem();

            setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
            mRankingHelper.setEnabled(pkg, uid, enabled);
            // Now, cancel any outstanding notifications that are part of a just-disabled app
            if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
                cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
                        UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
            }
            savePolicyFile();
        }

@@ -1662,8 +1599,8 @@ public class NotificationManagerService extends SystemService {
        @Override
        public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
            checkCallerIsSystemOrSameApp(pkg);
            return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
                    == AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid);

            return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
        }

        @Override
@@ -3400,8 +3337,7 @@ public class NotificationManagerService extends SystemService {
        }

        final boolean isBlocked = r.getImportance() == NotificationManager.IMPORTANCE_NONE
                || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE
                || !noteNotificationOp(pkg, callingUid);
                || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
        if (isBlocked) {
            Slog.e(TAG, "Suppressing notification from package by user request.");
            usageStats.registerBlocked(r);
+4 −4
Original line number Diff line number Diff line
@@ -21,8 +21,6 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.util.Preconditions;

import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -35,8 +33,6 @@ import android.content.pm.ParceledListSlice;
import android.metrics.LogMaker;
import android.os.Build;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.service.notification.NotificationListenerService.Ranking;
import android.text.TextUtils;
@@ -189,6 +185,10 @@ public class RankingHelper implements RankingConfig {
                                safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY),
                                safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY),
                                safeBool(parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE));
                        r.importance = safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
                        r.priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY);
                        r.visibility = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
                        r.showBadge = safeBool(parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE);

                        final int innerDepth = parser.getDepth();
                        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+76 −19
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static junit.framework.Assert.fail;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;

@@ -50,15 +51,11 @@ import android.net.Uri;
import android.os.Build;
import android.os.UserHandle;
import android.provider.Settings.Secure;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.TestableContext;
import android.testing.TestableSettingsProvider;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.Xml;

import java.io.BufferedInputStream;
@@ -87,10 +84,10 @@ import static org.mockito.Mockito.when;
public class RankingHelperTest extends NotificationTestCase {
    private static final String PKG = "com.android.server.notification";
    private static final int UID = 0;
    private static final UserHandle USER = UserHandle.getUserHandleForUid(UID);
    private static final UserHandle USER = UserHandle.of(0);
    private static final String UPDATED_PKG = "updatedPkg";
    private static final int UID2 = 1111111;
    private static final UserHandle USER2 = UserHandle.getUserHandleForUid(UID2);
    private static final int UID2 = 1111;
    private static final UserHandle USER2 = UserHandle.of(10);
    private static final String TEST_CHANNEL_ID = "test_channel_id";

    @Mock NotificationUsageStats mUsageStats;
@@ -199,24 +196,21 @@ public class RankingHelperTest extends NotificationTestCase {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
        serializer.startDocument(null, true);
        serializer.startTag(null, "ranking");
        mHelper.writeXml(serializer, forBackup);
        serializer.endTag(null, "ranking");
        serializer.endDocument();
        serializer.flush();

        for (String channelId : channelIds) {
            mHelper.permanentlyDeleteNotificationChannel(pkg, uid, channelId);
        }
        return baos;
    }

    private void loadStreamXml(ByteArrayOutputStream stream) throws Exception {
    private void loadStreamXml(ByteArrayOutputStream stream, boolean forRestore) throws Exception {
        XmlPullParser parser = Xml.newPullParser();
        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(stream.toByteArray())),
                null);
        parser.nextTag();
        mHelper.readXml(parser, false);
        mHelper.readXml(parser, forRestore);
    }

    private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
@@ -323,8 +317,72 @@ public class RankingHelperTest extends NotificationTestCase {
                channel2.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
        mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG}, new int[]{UID});

        loadStreamXml(baos);
        loadStreamXml(baos, false);

        assertTrue(mHelper.canShowBadge(PKG, UID));
        assertEquals(channel1, mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
        compareChannels(channel2,
                mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));

        List<NotificationChannelGroup> actualGroups =
                mHelper.getNotificationChannelGroups(PKG, UID, false).getList();
        boolean foundNcg = false;
        for (NotificationChannelGroup actual : actualGroups) {
            if (ncg.getId().equals(actual.getId())) {
                foundNcg = true;
                compareGroups(ncg, actual);
            } else if (ncg2.getId().equals(actual.getId())) {
                compareGroups(ncg2, actual);
            }
        }
        assertTrue(foundNcg);

        boolean foundChannel2Group = false;
        for (NotificationChannelGroup actual : actualGroups) {
            if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) {
                foundChannel2Group = true;
                break;
            }
        }
        assertTrue(foundChannel2Group);
    }

    @Test
    public void testChannelXmlForBackup() throws Exception {
        NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
        NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
        NotificationChannel channel1 =
                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
        NotificationChannel channel2 =
                new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
        channel2.setDescription("descriptions for all");
        channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
        channel2.enableLights(true);
        channel2.setBypassDnd(true);
        channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
        channel2.enableVibration(false);
        channel2.setGroup(ncg.getId());
        channel2.setLightColor(Color.BLUE);

        mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
        mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
        mHelper.createNotificationChannel(PKG, UID, channel1, true);
        mHelper.createNotificationChannel(PKG, UID, channel2, false);
        mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true);

        mHelper.setShowBadge(PKG, UID, true);

        mHelper.setImportance(UPDATED_PKG, UID2, IMPORTANCE_NONE);

        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel1.getId(),
                channel2.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
        mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG, UPDATED_PKG}, new int[]{UID, UID2});

        mHelper.setShowBadge(UPDATED_PKG, UID2, true);

        loadStreamXml(baos, true);

        assertEquals(IMPORTANCE_NONE, mHelper.getImportance(UPDATED_PKG, UID2));
        assertTrue(mHelper.canShowBadge(PKG, UID));
        assertEquals(channel1, mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
        compareChannels(channel2,
@@ -397,7 +455,7 @@ public class RankingHelperTest extends NotificationTestCase {
        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
                NotificationChannel.DEFAULT_CHANNEL_ID);

        loadStreamXml(baos);
        loadStreamXml(baos, false);

        final NotificationChannel updated = mHelper.getNotificationChannel(PKG, UID,
                NotificationChannel.DEFAULT_CHANNEL_ID, false);
@@ -417,7 +475,7 @@ public class RankingHelperTest extends NotificationTestCase {
        ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
                NotificationChannel.DEFAULT_CHANNEL_ID);

        loadStreamXml(baos);
        loadStreamXml(baos, false);

        assertEquals(NotificationManager.IMPORTANCE_LOW, mHelper.getNotificationChannel(
                PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false).getImportance());
@@ -465,7 +523,7 @@ public class RankingHelperTest extends NotificationTestCase {
        final ApplicationInfo upgraded = new ApplicationInfo();
        upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
        when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(upgraded);
        loadStreamXml(baos);
        loadStreamXml(baos, false);

        // Default Channel should be gone.
        assertEquals(null, mHelper.getNotificationChannel(PKG, UID,
@@ -483,7 +541,7 @@ public class RankingHelperTest extends NotificationTestCase {
        final ApplicationInfo upgraded = new ApplicationInfo();
        upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
        when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(upgraded);
        loadStreamXml(baos);
        loadStreamXml(baos, false);

        // Default Channel should be gone.
        assertEquals(null, mHelper.getNotificationChannel(PKG, UID,
@@ -497,7 +555,7 @@ public class RankingHelperTest extends NotificationTestCase {
        mHelper.createNotificationChannel(PKG, UID,
                new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true);

        loadStreamXml(baos);
        loadStreamXml(baos, false);

        // Should still have the newly created channel that wasn't in the xml.
        assertTrue(mHelper.getNotificationChannel(PKG, UID, "bananas", false) != null);
@@ -1271,5 +1329,4 @@ public class RankingHelperTest extends NotificationTestCase {
        assertFalse(mHelper.badgingEnabled(USER));
        assertTrue(mHelper.badgingEnabled(USER2));
    }

}