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

Commit 6676dab3 authored by Chris Wren's avatar Chris Wren
Browse files

fix race in getAppActiveNotifications

Bug: 32642818
Test: cts-tradefed run cts -m CtsAppTestCases -t android.app.cts.NotificationManagerTest
Change-Id: I3fe8cd1147b03c3d9b6a9461088785c0d9321768
parent 3070dbfa
Loading
Loading
Loading
Loading
+147 −113
Original line number Diff line number Diff line
@@ -270,6 +270,7 @@ public class NotificationManagerService extends SystemService {
            new ArrayList<NotificationRecord>();
    final ArrayMap<String, NotificationRecord> mNotificationsByKey =
            new ArrayMap<String, NotificationRecord>();
    final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
    final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
    final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
    final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
@@ -1613,33 +1614,58 @@ public class NotificationManagerService extends SystemService {
            int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
                    Binder.getCallingUid(), incomingUserId, true, false,
                    "getAppActiveNotifications", pkg);

            final ArrayList<StatusBarNotification> list
                    = new ArrayList<StatusBarNotification>(mNotificationList.size());
            final ArrayMap<String, StatusBarNotification> map
                    = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());

            synchronized (mNotificationList) {
                final int N = mNotificationList.size();
                for (int i = 0; i < N; i++) {
                    final StatusBarNotification sbn = mNotificationList.get(i).sbn;
                    StatusBarNotification sbn = sanitizeSbn(pkg, userId,
                            mNotificationList.get(i).sbn);
                    if (sbn != null) {
                        map.put(sbn.getKey(), sbn);
                    }
                }
                for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
                    StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
                    if (sbn != null) {
                        map.put(sbn.getKey(), sbn);
                    }
                }
            }
            synchronized (mEnqueuedNotifications) {
                final int N = mEnqueuedNotifications.size();
                for (int i = 0; i < N; i++) {
                    StatusBarNotification sbn = sanitizeSbn(pkg, userId,
                            mEnqueuedNotifications.get(i).sbn);
                    if (sbn != null) {
                        map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
                    }
                }
            }

            final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
            list.addAll(map.values());
            return new ParceledListSlice<StatusBarNotification>(list);
        }

        private StatusBarNotification sanitizeSbn(String pkg, int userId,
                StatusBarNotification sbn) {
            if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
                    && (sbn.getNotification().flags
                    & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
                // We could pass back a cloneLight() but clients might get confused and
                // try to send this thing back to notify() again, which would not work
                // very well.
                        final StatusBarNotification sbnOut = new StatusBarNotification(
                return new StatusBarNotification(
                        sbn.getPackageName(),
                        sbn.getOpPkg(),
                        sbn.getNotificationChannel(),
                        sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
                        sbn.getNotification().clone(),
                        sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
                        list.add(sbnOut);
                    }
                }
            }

            return new ParceledListSlice<StatusBarNotification>(list);
            return null;
        }

        /**
@@ -2834,6 +2860,9 @@ public class NotificationManagerService extends SystemService {

        // setup local book-keeping
        final NotificationRecord r = new NotificationRecord(getContext(), n);
        synchronized (mEnqueuedNotifications) {
            mEnqueuedNotifications.add(r);
        }
        mHandler.post(new EnqueueNotificationRunnable(userId, r));

        idOut[0] = id;
@@ -2850,7 +2879,7 @@ public class NotificationManagerService extends SystemService {

        @Override
        public void run() {

            try {
                synchronized (mNotificationList) {
                    if (mSnoozeHelper.isSnoozed(userId, r.sbn.getPackageName(), r.getKey())) {
                        // TODO: log to event log
@@ -2966,6 +2995,11 @@ public class NotificationManagerService extends SystemService {

                    buzzBeepBlinkLocked(r);
                }
            } finally {
                synchronized (mEnqueuedNotifications) {
                    mEnqueuedNotifications.remove(r);
                }
            }
        }

        protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
+11 −0
Original line number Diff line number Diff line
@@ -36,6 +36,9 @@ import android.util.Slog;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
@@ -84,6 +87,14 @@ public class SnoozeHelper {
                && mSnoozedNotifications.get(userId).get(pkg).containsKey(key);
    }

    protected Collection<NotificationRecord> getSnoozed(int userId, String pkg) {
        if (mSnoozedNotifications.containsKey(userId)
                && mSnoozedNotifications.get(userId).containsKey(pkg)) {
            mSnoozedNotifications.get(userId).get(pkg).values();
        }
        return Collections.EMPTY_LIST;
    }

    /**
     * Snoozes a notification and schedules an alarm to repost at that time.
     */