Loading services/core/java/com/android/server/EventLogTags.logtags +2 −2 Original line number Original line Diff line number Diff line Loading @@ -51,8 +51,8 @@ option java_package com.android.server # --------------------------- # --------------------------- # NotificationManagerService.java # NotificationManagerService.java # --------------------------- # --------------------------- # when a NotificationManager.notify is called # when a NotificationManager.notify is called. status: 0=post, 1=update, 2=ignored 2750 notification_enqueue (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(notification|3),(update|1) 2750 notification_enqueue (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(notification|3),(status|1) # when someone tries to cancel a notification, the notification manager sometimes # when someone tries to cancel a notification, the notification manager sometimes # calls this with flags too # calls this with flags too 2751 notification_cancel (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(required_flags|1),(forbidden_flags|1),(reason|1|5),(listener|3) 2751 notification_cancel (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(required_flags|1),(forbidden_flags|1),(reason|1|5),(listener|3) Loading services/core/java/com/android/server/notification/NotificationManagerService.java +168 −20 Original line number Original line Diff line number Diff line Loading @@ -116,6 +116,7 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.ArrayList; import java.util.HashSet; import java.util.HashSet; import java.util.Iterator; import java.util.Iterator; import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Objects; Loading @@ -139,6 +140,7 @@ public class NotificationManagerService extends SystemService { static final int SHORT_DELAY = 2000; // 2 seconds static final int SHORT_DELAY = 2000; // 2 seconds static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; Loading Loading @@ -166,6 +168,15 @@ public class NotificationManagerService extends SystemService { static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY = static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY = ValidateNotificationPeople.STARRED_CONTACT; ValidateNotificationPeople.STARRED_CONTACT; /** notification_enqueue status value for a newly enqueued notification. */ private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0; /** notification_enqueue status value for an existing notification. */ private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1; /** notification_enqueue status value for an ignored notification. */ private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2; private IActivityManager mAm; private IActivityManager mAm; AudioManager mAudioManager; AudioManager mAudioManager; StatusBarManagerInternal mStatusBar; StatusBarManagerInternal mStatusBar; Loading Loading @@ -209,6 +220,7 @@ public class NotificationManagerService extends SystemService { final ArrayMap<String, NotificationRecord> mNotificationsByKey = final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<String, NotificationRecord>(); new ArrayMap<String, NotificationRecord>(); final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>(); final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>(); final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>(); ArrayList<String> mLights = new ArrayList<String>(); ArrayList<String> mLights = new ArrayList<String>(); NotificationRecord mLedNotification; NotificationRecord mLedNotification; Loading Loading @@ -251,6 +263,7 @@ public class NotificationManagerService extends SystemService { private static final int REASON_LISTENER_CANCEL = 10; private static final int REASON_LISTENER_CANCEL = 10; private static final int REASON_LISTENER_CANCEL_ALL = 11; private static final int REASON_LISTENER_CANCEL_ALL = 11; private static final int REASON_GROUP_SUMMARY_CANCELED = 12; private static final int REASON_GROUP_SUMMARY_CANCELED = 12; private static final int REASON_GROUP_OPTIMIZATION = 13; private static class Archive { private static class Archive { final int mBufferSize; final int mBufferSize; Loading Loading @@ -1658,6 +1671,16 @@ public class NotificationManagerService extends SystemService { pw.println("\n Condition providers:"); pw.println("\n Condition providers:"); mConditionProviders.dump(pw, filter); mConditionProviders.dump(pw, filter); pw.println("\n Group summaries:"); for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) { NotificationRecord r = entry.getValue(); pw.println(" " + entry.getKey() + " -> " + r.getKey()); if (mNotificationsByKey.get(r.getKey()) != r) { pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey."); r.dump(pw, " ", getContext()); } } } } } } Loading Loading @@ -1779,16 +1802,34 @@ public class NotificationManagerService extends SystemService { // Retain ranking information from previous record // Retain ranking information from previous record r.copyRankingInformation(old); r.copyRankingInformation(old); } } mRankingHelper.extractSignals(r); // Handle grouped notifications and bail out early if we // can to avoid extracting signals. handleGroupedNotificationLocked(r, old, callingUid, callingPid); boolean ignoreNotification = removeUnusedGroupedNotificationLocked(r, callingUid, callingPid); // This conditional is a dirty hack to limit the logging done on // This conditional is a dirty hack to limit the logging done on // behalf of the download manager without affecting other apps. // behalf of the download manager without affecting other apps. if (!pkg.equals("com.android.providers.downloads") if (!pkg.equals("com.android.providers.downloads") || Log.isLoggable("DownloadManager", Log.VERBOSE)) { || Log.isLoggable("DownloadManager", Log.VERBOSE)) { int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; if (ignoreNotification) { enqueueStatus = EVENTLOG_ENQUEUE_STATUS_IGNORED; } else if (old != null) { enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; } EventLogTags.writeNotificationEnqueue(callingUid, callingPid, EventLogTags.writeNotificationEnqueue(callingUid, callingPid, pkg, id, tag, userId, notification.toString(), pkg, id, tag, userId, notification.toString(), (old != null) ? 1 : 0); enqueueStatus); } if (ignoreNotification) { return; } } mRankingHelper.extractSignals(r); // 3. Apply local rules // 3. Apply local rules // blocked apps // blocked apps Loading @@ -1805,16 +1846,6 @@ public class NotificationManagerService extends SystemService { return; return; } } // Clear out group children of the old notification if the update causes the // group summary to go away. This happens when the old notification was a // summary and the new one isn't, or when the old notification was a summary // and its group key changed. if (old != null && old.getNotification().isGroupSummary() && (!notification.isGroupSummary() || !old.getGroupKey().equals(r.getGroupKey()))) { cancelGroupChildrenLocked(old, callingUid, callingPid, null); } int index = indexOfNotificationLocked(n.getKey()); int index = indexOfNotificationLocked(n.getKey()); if (index < 0) { if (index < 0) { mNotificationList.add(r); mNotificationList.add(r); Loading Loading @@ -1864,6 +1895,90 @@ public class NotificationManagerService extends SystemService { idOut[0] = id; idOut[0] = id; } } /** * Ensures that grouped notification receive their special treatment. * * <p>Cancels group children if the new notification causes a group to lose * its summary.</p> * * <p>Updates mSummaryByGroupKey.</p> */ private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old, int callingUid, int callingPid) { StatusBarNotification sbn = r.sbn; Notification n = sbn.getNotification(); String group = sbn.getGroupKey(); boolean isSummary = n.isGroupSummary(); Notification oldN = old != null ? old.sbn.getNotification() : null; String oldGroup = old != null ? old.sbn.getGroupKey() : null; boolean oldIsSummary = old != null && oldN.isGroupSummary(); if (oldIsSummary) { NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup); if (removedSummary != old) { String removedKey = removedSummary != null ? removedSummary.getKey() : "<null>"; Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() + ", removed=" + removedKey); } } if (isSummary) { mSummaryByGroupKey.put(group, r); } // Clear out group children of the old notification if the update // causes the group summary to go away. This happens when the old // notification was a summary and the new one isn't, or when the old // notification was a summary and its group key changed. if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) { cancelGroupChildrenLocked(old, callingUid, callingPid, null, REASON_GROUP_SUMMARY_CANCELED); } } /** * Performs group notification optimizations if SysUI is the only active * notification listener and returns whether the given notification should * be ignored. * * <p>Returns true if the given notification is a child of a group with a * summary, which means that SysUI will never show it, and hence the new * notification can be safely ignored.</p> * * <p>For summaries, cancels all children of that group, as SysUI will * never show them anymore.</p> * * @return true if the given notification can be ignored as an optimization */ private boolean removeUnusedGroupedNotificationLocked(NotificationRecord r, int callingUid, int callingPid) { // No optimizations are possible if listeners want groups. if (mListeners.notificationGroupsDesired()) { return false; } StatusBarNotification sbn = r.sbn; String group = sbn.getGroupKey(); boolean isSummary = sbn.getNotification().isGroupSummary(); boolean isChild = sbn.getNotification().isGroupChild(); NotificationRecord summary = mSummaryByGroupKey.get(group); if (isChild && summary != null) { // Child with an active summary -> ignore if (DBG) { Slog.d(TAG, "Ignoring group child " + sbn.getKey() + " due to existing summary " + summary.getKey()); } return true; } else if (isSummary) { // Summary -> cancel children cancelGroupChildrenLocked(r, callingUid, callingPid, null, REASON_GROUP_OPTIMIZATION); } return false; } private void buzzBeepBlinkLocked(NotificationRecord record) { private void buzzBeepBlinkLocked(NotificationRecord record) { boolean buzzBeepBlinked = false; boolean buzzBeepBlinked = false; final Notification notification = record.sbn.getNotification(); final Notification notification = record.sbn.getNotification(); Loading Loading @@ -2386,6 +2501,11 @@ public class NotificationManagerService extends SystemService { } } mNotificationsByKey.remove(r.sbn.getKey()); mNotificationsByKey.remove(r.sbn.getKey()); String groupKey = r.getGroupKey(); NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey); if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) { mSummaryByGroupKey.remove(groupKey); } // Save it for users of getHistoricalNotifications() // Save it for users of getHistoricalNotifications() mArchive.record(r.sbn); mArchive.record(r.sbn); Loading Loading @@ -2433,7 +2553,8 @@ public class NotificationManagerService extends SystemService { mNotificationList.remove(index); mNotificationList.remove(index); cancelNotificationLocked(r, sendDelete, reason); cancelNotificationLocked(r, sendDelete, reason); cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName); cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName, REASON_GROUP_SUMMARY_CANCELED); updateLightsLocked(); updateLightsLocked(); } } } } Loading Loading @@ -2512,7 +2633,7 @@ public class NotificationManagerService extends SystemService { final int M = canceledNotifications.size(); final int M = canceledNotifications.size(); for (int i = 0; i < M; i++) { for (int i = 0; i < M; i++) { cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, listenerName); listenerName, REASON_GROUP_SUMMARY_CANCELED); } } } } if (canceledNotifications != null) { if (canceledNotifications != null) { Loading Loading @@ -2556,14 +2677,14 @@ public class NotificationManagerService extends SystemService { int M = canceledNotifications != null ? canceledNotifications.size() : 0; int M = canceledNotifications != null ? canceledNotifications.size() : 0; for (int i = 0; i < M; i++) { for (int i = 0; i < M; i++) { cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, listenerName); listenerName, REASON_GROUP_SUMMARY_CANCELED); } } updateLightsLocked(); updateLightsLocked(); } } // Warning: The caller is responsible for invoking updateLightsLocked(). // Warning: The caller is responsible for invoking updateLightsLocked(). private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid, private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid, String listenerName) { String listenerName, int reason) { Notification n = r.getNotification(); Notification n = r.getNotification(); if (!n.isGroupSummary()) { if (!n.isGroupSummary()) { return; return; Loading @@ -2583,11 +2704,10 @@ public class NotificationManagerService extends SystemService { StatusBarNotification childSbn = childR.sbn; StatusBarNotification childSbn = childR.sbn; if (childR.getNotification().isGroupChild() && if (childR.getNotification().isGroupChild() && childR.getGroupKey().equals(r.getGroupKey())) { childR.getGroupKey().equals(r.getGroupKey())) { EventLogTags.writeNotificationCancel(callingUid, callingPid, EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(), pkg, childSbn.getId(), childSbn.getTag(), userId, 0, 0, childSbn.getTag(), userId, 0, 0, reason, listenerName); REASON_GROUP_SUMMARY_CANCELED, listenerName); mNotificationList.remove(i); mNotificationList.remove(i); cancelNotificationLocked(childR, false, REASON_GROUP_SUMMARY_CANCELED); cancelNotificationLocked(childR, false, reason); } } } } } } Loading Loading @@ -2783,6 +2903,7 @@ public class NotificationManagerService extends SystemService { public class NotificationListeners extends ManagedServices { public class NotificationListeners extends ManagedServices { private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); private boolean mNotificationGroupsDesired; public NotificationListeners() { public NotificationListeners() { super(getContext(), mHandler, mNotificationList, mUserProfiles); super(getContext(), mHandler, mNotificationList, mUserProfiles); Loading Loading @@ -2810,6 +2931,7 @@ public class NotificationManagerService extends SystemService { final INotificationListener listener = (INotificationListener) info.service; final INotificationListener listener = (INotificationListener) info.service; final NotificationRankingUpdate update; final NotificationRankingUpdate update; synchronized (mNotificationList) { synchronized (mNotificationList) { updateNotificationGroupsDesiredLocked(); update = makeRankingUpdateLocked(info); update = makeRankingUpdateLocked(info); } } try { try { Loading @@ -2825,6 +2947,7 @@ public class NotificationManagerService extends SystemService { updateListenerHintsLocked(); updateListenerHintsLocked(); } } mLightTrimListeners.remove(removed); mLightTrimListeners.remove(removed); updateNotificationGroupsDesiredLocked(); } } public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { Loading Loading @@ -3028,6 +3151,31 @@ public class NotificationManagerService extends SystemService { } } return false; return false; } } /** * Returns whether any of the currently registered listeners wants to receive notification * groups. * * <p>Currently we assume groups are desired by non-SystemUI listeners.</p> */ public boolean notificationGroupsDesired() { return mNotificationGroupsDesired; } private void updateNotificationGroupsDesiredLocked() { mNotificationGroupsDesired = true; // No listeners, no groups. if (mServices.isEmpty()) { mNotificationGroupsDesired = false; return; } // One listener: Check whether it's SysUI. if (mServices.size() == 1 && mServices.get(0).component.getPackageName().equals("com.android.systemui")) { mNotificationGroupsDesired = false; return; } } } } public static final class DumpFilter { public static final class DumpFilter { Loading Loading
services/core/java/com/android/server/EventLogTags.logtags +2 −2 Original line number Original line Diff line number Diff line Loading @@ -51,8 +51,8 @@ option java_package com.android.server # --------------------------- # --------------------------- # NotificationManagerService.java # NotificationManagerService.java # --------------------------- # --------------------------- # when a NotificationManager.notify is called # when a NotificationManager.notify is called. status: 0=post, 1=update, 2=ignored 2750 notification_enqueue (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(notification|3),(update|1) 2750 notification_enqueue (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(notification|3),(status|1) # when someone tries to cancel a notification, the notification manager sometimes # when someone tries to cancel a notification, the notification manager sometimes # calls this with flags too # calls this with flags too 2751 notification_cancel (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(required_flags|1),(forbidden_flags|1),(reason|1|5),(listener|3) 2751 notification_cancel (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(required_flags|1),(forbidden_flags|1),(reason|1|5),(listener|3) Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +168 −20 Original line number Original line Diff line number Diff line Loading @@ -116,6 +116,7 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.ArrayList; import java.util.HashSet; import java.util.HashSet; import java.util.Iterator; import java.util.Iterator; import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Objects; Loading @@ -139,6 +140,7 @@ public class NotificationManagerService extends SystemService { static final int SHORT_DELAY = 2000; // 2 seconds static final int SHORT_DELAY = 2000; // 2 seconds static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; Loading Loading @@ -166,6 +168,15 @@ public class NotificationManagerService extends SystemService { static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY = static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY = ValidateNotificationPeople.STARRED_CONTACT; ValidateNotificationPeople.STARRED_CONTACT; /** notification_enqueue status value for a newly enqueued notification. */ private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0; /** notification_enqueue status value for an existing notification. */ private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1; /** notification_enqueue status value for an ignored notification. */ private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2; private IActivityManager mAm; private IActivityManager mAm; AudioManager mAudioManager; AudioManager mAudioManager; StatusBarManagerInternal mStatusBar; StatusBarManagerInternal mStatusBar; Loading Loading @@ -209,6 +220,7 @@ public class NotificationManagerService extends SystemService { final ArrayMap<String, NotificationRecord> mNotificationsByKey = final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<String, NotificationRecord>(); new ArrayMap<String, NotificationRecord>(); final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>(); final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>(); final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>(); ArrayList<String> mLights = new ArrayList<String>(); ArrayList<String> mLights = new ArrayList<String>(); NotificationRecord mLedNotification; NotificationRecord mLedNotification; Loading Loading @@ -251,6 +263,7 @@ public class NotificationManagerService extends SystemService { private static final int REASON_LISTENER_CANCEL = 10; private static final int REASON_LISTENER_CANCEL = 10; private static final int REASON_LISTENER_CANCEL_ALL = 11; private static final int REASON_LISTENER_CANCEL_ALL = 11; private static final int REASON_GROUP_SUMMARY_CANCELED = 12; private static final int REASON_GROUP_SUMMARY_CANCELED = 12; private static final int REASON_GROUP_OPTIMIZATION = 13; private static class Archive { private static class Archive { final int mBufferSize; final int mBufferSize; Loading Loading @@ -1658,6 +1671,16 @@ public class NotificationManagerService extends SystemService { pw.println("\n Condition providers:"); pw.println("\n Condition providers:"); mConditionProviders.dump(pw, filter); mConditionProviders.dump(pw, filter); pw.println("\n Group summaries:"); for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) { NotificationRecord r = entry.getValue(); pw.println(" " + entry.getKey() + " -> " + r.getKey()); if (mNotificationsByKey.get(r.getKey()) != r) { pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey."); r.dump(pw, " ", getContext()); } } } } } } Loading Loading @@ -1779,16 +1802,34 @@ public class NotificationManagerService extends SystemService { // Retain ranking information from previous record // Retain ranking information from previous record r.copyRankingInformation(old); r.copyRankingInformation(old); } } mRankingHelper.extractSignals(r); // Handle grouped notifications and bail out early if we // can to avoid extracting signals. handleGroupedNotificationLocked(r, old, callingUid, callingPid); boolean ignoreNotification = removeUnusedGroupedNotificationLocked(r, callingUid, callingPid); // This conditional is a dirty hack to limit the logging done on // This conditional is a dirty hack to limit the logging done on // behalf of the download manager without affecting other apps. // behalf of the download manager without affecting other apps. if (!pkg.equals("com.android.providers.downloads") if (!pkg.equals("com.android.providers.downloads") || Log.isLoggable("DownloadManager", Log.VERBOSE)) { || Log.isLoggable("DownloadManager", Log.VERBOSE)) { int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; if (ignoreNotification) { enqueueStatus = EVENTLOG_ENQUEUE_STATUS_IGNORED; } else if (old != null) { enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; } EventLogTags.writeNotificationEnqueue(callingUid, callingPid, EventLogTags.writeNotificationEnqueue(callingUid, callingPid, pkg, id, tag, userId, notification.toString(), pkg, id, tag, userId, notification.toString(), (old != null) ? 1 : 0); enqueueStatus); } if (ignoreNotification) { return; } } mRankingHelper.extractSignals(r); // 3. Apply local rules // 3. Apply local rules // blocked apps // blocked apps Loading @@ -1805,16 +1846,6 @@ public class NotificationManagerService extends SystemService { return; return; } } // Clear out group children of the old notification if the update causes the // group summary to go away. This happens when the old notification was a // summary and the new one isn't, or when the old notification was a summary // and its group key changed. if (old != null && old.getNotification().isGroupSummary() && (!notification.isGroupSummary() || !old.getGroupKey().equals(r.getGroupKey()))) { cancelGroupChildrenLocked(old, callingUid, callingPid, null); } int index = indexOfNotificationLocked(n.getKey()); int index = indexOfNotificationLocked(n.getKey()); if (index < 0) { if (index < 0) { mNotificationList.add(r); mNotificationList.add(r); Loading Loading @@ -1864,6 +1895,90 @@ public class NotificationManagerService extends SystemService { idOut[0] = id; idOut[0] = id; } } /** * Ensures that grouped notification receive their special treatment. * * <p>Cancels group children if the new notification causes a group to lose * its summary.</p> * * <p>Updates mSummaryByGroupKey.</p> */ private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old, int callingUid, int callingPid) { StatusBarNotification sbn = r.sbn; Notification n = sbn.getNotification(); String group = sbn.getGroupKey(); boolean isSummary = n.isGroupSummary(); Notification oldN = old != null ? old.sbn.getNotification() : null; String oldGroup = old != null ? old.sbn.getGroupKey() : null; boolean oldIsSummary = old != null && oldN.isGroupSummary(); if (oldIsSummary) { NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup); if (removedSummary != old) { String removedKey = removedSummary != null ? removedSummary.getKey() : "<null>"; Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() + ", removed=" + removedKey); } } if (isSummary) { mSummaryByGroupKey.put(group, r); } // Clear out group children of the old notification if the update // causes the group summary to go away. This happens when the old // notification was a summary and the new one isn't, or when the old // notification was a summary and its group key changed. if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) { cancelGroupChildrenLocked(old, callingUid, callingPid, null, REASON_GROUP_SUMMARY_CANCELED); } } /** * Performs group notification optimizations if SysUI is the only active * notification listener and returns whether the given notification should * be ignored. * * <p>Returns true if the given notification is a child of a group with a * summary, which means that SysUI will never show it, and hence the new * notification can be safely ignored.</p> * * <p>For summaries, cancels all children of that group, as SysUI will * never show them anymore.</p> * * @return true if the given notification can be ignored as an optimization */ private boolean removeUnusedGroupedNotificationLocked(NotificationRecord r, int callingUid, int callingPid) { // No optimizations are possible if listeners want groups. if (mListeners.notificationGroupsDesired()) { return false; } StatusBarNotification sbn = r.sbn; String group = sbn.getGroupKey(); boolean isSummary = sbn.getNotification().isGroupSummary(); boolean isChild = sbn.getNotification().isGroupChild(); NotificationRecord summary = mSummaryByGroupKey.get(group); if (isChild && summary != null) { // Child with an active summary -> ignore if (DBG) { Slog.d(TAG, "Ignoring group child " + sbn.getKey() + " due to existing summary " + summary.getKey()); } return true; } else if (isSummary) { // Summary -> cancel children cancelGroupChildrenLocked(r, callingUid, callingPid, null, REASON_GROUP_OPTIMIZATION); } return false; } private void buzzBeepBlinkLocked(NotificationRecord record) { private void buzzBeepBlinkLocked(NotificationRecord record) { boolean buzzBeepBlinked = false; boolean buzzBeepBlinked = false; final Notification notification = record.sbn.getNotification(); final Notification notification = record.sbn.getNotification(); Loading Loading @@ -2386,6 +2501,11 @@ public class NotificationManagerService extends SystemService { } } mNotificationsByKey.remove(r.sbn.getKey()); mNotificationsByKey.remove(r.sbn.getKey()); String groupKey = r.getGroupKey(); NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey); if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) { mSummaryByGroupKey.remove(groupKey); } // Save it for users of getHistoricalNotifications() // Save it for users of getHistoricalNotifications() mArchive.record(r.sbn); mArchive.record(r.sbn); Loading Loading @@ -2433,7 +2553,8 @@ public class NotificationManagerService extends SystemService { mNotificationList.remove(index); mNotificationList.remove(index); cancelNotificationLocked(r, sendDelete, reason); cancelNotificationLocked(r, sendDelete, reason); cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName); cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName, REASON_GROUP_SUMMARY_CANCELED); updateLightsLocked(); updateLightsLocked(); } } } } Loading Loading @@ -2512,7 +2633,7 @@ public class NotificationManagerService extends SystemService { final int M = canceledNotifications.size(); final int M = canceledNotifications.size(); for (int i = 0; i < M; i++) { for (int i = 0; i < M; i++) { cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, listenerName); listenerName, REASON_GROUP_SUMMARY_CANCELED); } } } } if (canceledNotifications != null) { if (canceledNotifications != null) { Loading Loading @@ -2556,14 +2677,14 @@ public class NotificationManagerService extends SystemService { int M = canceledNotifications != null ? canceledNotifications.size() : 0; int M = canceledNotifications != null ? canceledNotifications.size() : 0; for (int i = 0; i < M; i++) { for (int i = 0; i < M; i++) { cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, listenerName); listenerName, REASON_GROUP_SUMMARY_CANCELED); } } updateLightsLocked(); updateLightsLocked(); } } // Warning: The caller is responsible for invoking updateLightsLocked(). // Warning: The caller is responsible for invoking updateLightsLocked(). private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid, private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid, String listenerName) { String listenerName, int reason) { Notification n = r.getNotification(); Notification n = r.getNotification(); if (!n.isGroupSummary()) { if (!n.isGroupSummary()) { return; return; Loading @@ -2583,11 +2704,10 @@ public class NotificationManagerService extends SystemService { StatusBarNotification childSbn = childR.sbn; StatusBarNotification childSbn = childR.sbn; if (childR.getNotification().isGroupChild() && if (childR.getNotification().isGroupChild() && childR.getGroupKey().equals(r.getGroupKey())) { childR.getGroupKey().equals(r.getGroupKey())) { EventLogTags.writeNotificationCancel(callingUid, callingPid, EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(), pkg, childSbn.getId(), childSbn.getTag(), userId, 0, 0, childSbn.getTag(), userId, 0, 0, reason, listenerName); REASON_GROUP_SUMMARY_CANCELED, listenerName); mNotificationList.remove(i); mNotificationList.remove(i); cancelNotificationLocked(childR, false, REASON_GROUP_SUMMARY_CANCELED); cancelNotificationLocked(childR, false, reason); } } } } } } Loading Loading @@ -2783,6 +2903,7 @@ public class NotificationManagerService extends SystemService { public class NotificationListeners extends ManagedServices { public class NotificationListeners extends ManagedServices { private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); private boolean mNotificationGroupsDesired; public NotificationListeners() { public NotificationListeners() { super(getContext(), mHandler, mNotificationList, mUserProfiles); super(getContext(), mHandler, mNotificationList, mUserProfiles); Loading Loading @@ -2810,6 +2931,7 @@ public class NotificationManagerService extends SystemService { final INotificationListener listener = (INotificationListener) info.service; final INotificationListener listener = (INotificationListener) info.service; final NotificationRankingUpdate update; final NotificationRankingUpdate update; synchronized (mNotificationList) { synchronized (mNotificationList) { updateNotificationGroupsDesiredLocked(); update = makeRankingUpdateLocked(info); update = makeRankingUpdateLocked(info); } } try { try { Loading @@ -2825,6 +2947,7 @@ public class NotificationManagerService extends SystemService { updateListenerHintsLocked(); updateListenerHintsLocked(); } } mLightTrimListeners.remove(removed); mLightTrimListeners.remove(removed); updateNotificationGroupsDesiredLocked(); } } public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { Loading Loading @@ -3028,6 +3151,31 @@ public class NotificationManagerService extends SystemService { } } return false; return false; } } /** * Returns whether any of the currently registered listeners wants to receive notification * groups. * * <p>Currently we assume groups are desired by non-SystemUI listeners.</p> */ public boolean notificationGroupsDesired() { return mNotificationGroupsDesired; } private void updateNotificationGroupsDesiredLocked() { mNotificationGroupsDesired = true; // No listeners, no groups. if (mServices.isEmpty()) { mNotificationGroupsDesired = false; return; } // One listener: Check whether it's SysUI. if (mServices.size() == 1 && mServices.get(0).component.getPackageName().equals("com.android.systemui")) { mNotificationGroupsDesired = false; return; } } } } public static final class DumpFilter { public static final class DumpFilter { Loading