Loading services/core/java/com/android/server/notification/NotificationListenerStats.java 0 → 100644 +134 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.notification; import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; import com.android.server.notification.ManagedServices.ManagedServiceInfo; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.io.PrintWriter; class NotificationListenerStats { /** * Maximum number of channels that a single NLS is allowed to create for <em>all</em> installed * packages. Should be much higher than reasonably necessary, but still prevent runaway channel * creation abuse. * * @see PreferencesHelper#NOTIFICATION_CHANNEL_COUNT_LIMIT */ private static final int MAX_CHANNELS = 5_000; private static final String TAG_STATS = "nlsStats"; private static final String TAG_NLS = "nls"; private static final String ATT_UID = "uid"; private static final String ATT_OWNED_CHANNEL_COUNT = "channelCount"; private final Object mLock = new Object(); // nlsUid => count of channels created by that (privileged) NLS. @GuardedBy("mLock") private final SparseIntArray mChannelsCreated = new SparseIntArray(); private final int mMaxChannelsAllowed; NotificationListenerStats() { this(MAX_CHANNELS); } @VisibleForTesting NotificationListenerStats(int maxChannelsAllowed) { mMaxChannelsAllowed = maxChannelsAllowed; } boolean isAllowedToCreateChannel(ManagedServiceInfo nls) { synchronized (mLock) { int numCreated = mChannelsCreated.get(nls.uid); return numCreated < mMaxChannelsAllowed; } } void logCreatedChannels(ManagedServiceInfo nls, int increase) { synchronized (mLock) { int prevCreated = mChannelsCreated.get(nls.uid); mChannelsCreated.put(nls.uid, prevCreated + increase); } } void onPackageRemoved(int uid, String packageName) { // If the uninstalled package was an NLS, drop its stats. synchronized (mLock) { mChannelsCreated.delete(uid); } } static boolean isXmlTag(String tag) { return TAG_STATS.equals(tag); } void writeXml(TypedXmlSerializer out) throws IOException { out.startTag(null, TAG_STATS); synchronized (mLock) { for (int i = 0; i < mChannelsCreated.size(); i++) { out.startTag(null, TAG_NLS); out.attributeInt(null, ATT_UID, mChannelsCreated.keyAt(i)); out.attributeInt(null, ATT_OWNED_CHANNEL_COUNT, mChannelsCreated.valueAt(i)); out.endTag(null, TAG_NLS); } } out.endTag(null, TAG_STATS); } void readXml(TypedXmlPullParser parser) throws XmlPullParserException, IOException { int type = parser.getEventType(); if (type != XmlPullParser.START_TAG) return; String tag = parser.getName(); if (!TAG_STATS.equals(tag)) return; synchronized (mLock) { while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { tag = parser.getName(); if (type == XmlPullParser.END_TAG && TAG_STATS.equals(tag)) { break; } if (type == XmlPullParser.START_TAG) { if (TAG_NLS.equals(tag)) { int uid = parser.getAttributeInt(null, ATT_UID, 0); int channelCount = parser.getAttributeInt(null, ATT_OWNED_CHANNEL_COUNT, 0); mChannelsCreated.put(uid, channelCount); } } } } } void dump(PrintWriter pw, String prefix) { synchronized (mLock) { for (int i = 0; i < mChannelsCreated.size(); i++) { pw.println(prefix + "NLS with uid " + mChannelsCreated.keyAt(i)); pw.println(prefix + " created channel count: " + mChannelsCreated.valueAt(i)); } } } } services/core/java/com/android/server/notification/NotificationManagerService.java +63 −16 Original line number Diff line number Diff line Loading @@ -787,6 +787,7 @@ public class NotificationManagerService extends SystemService { @VisibleForTesting NotificationAssistants mAssistants; private ConditionProviders mConditionProviders; private NotificationListenerStats mNotificationListenerStats; private NotificationUsageStats mUsageStats; private boolean mLockScreenAllowSecureNotifications = true; final ArrayMap<String, ArrayMap<Integer, Loading Loading @@ -1239,6 +1240,9 @@ public class NotificationManagerService extends SystemService { mLockScreenAllowSecureNotifications = parser.getAttributeBoolean(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE, true); } if (NotificationListenerStats.isXmlTag(parser.getName())) { mNotificationListenerStats.readXml(parser); } } if (!migratedManagedServices) { Loading Loading @@ -1359,6 +1363,9 @@ public class NotificationManagerService extends SystemService { if (!forBackup || userId == USER_SYSTEM) { writeSecureNotificationsPolicy(out); } if (!forBackup) { mNotificationListenerStats.writeXml(out); } out.endTag(null, TAG_NOTIFICATION_POLICY); out.endDocument(); } Loading Loading @@ -2796,7 +2803,8 @@ public class NotificationManagerService extends SystemService { SystemUiSystemPropertiesFlags.FlagResolver flagResolver, PermissionManager permissionManager, PowerManager powerManager, PostNotificationTrackerFactory postNotificationTrackerFactory, UiEventLogger uiEventLogger, BitmapOffloadInternal bitmapOffloader) { UiEventLogger uiEventLogger, BitmapOffloadInternal bitmapOffloader, NotificationListenerStats notificationListenerStats) { mHandler = handler; if (Flags.nmBinderPerfThrottleEffectsSuppressorBroadcast()) { mBroadcastsHandler = broadcastsHandler; Loading Loading @@ -2847,6 +2855,7 @@ public class NotificationManagerService extends SystemService { mMetricsLogger = new MetricsLogger(); mRankingHandler = rankingHandler; mConditionProviders = conditionProviders; mNotificationListenerStats = notificationListenerStats; mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), Clock.systemUTC(), mConditionProviders, flagResolver, new ZenModeEventLogger(mPackageManagerClient)); mZenModeHelper.addCallback(new ZenModeHelper.Callback() { Loading Loading @@ -3170,7 +3179,7 @@ public class NotificationManagerService extends SystemService { getContext().getSystemService(PermissionManager.class), getContext().getSystemService(PowerManager.class), new PostNotificationTrackerFactory() {}, new UiEventLoggerImpl(), bitmapOffloader); bitmapOffloader, new NotificationListenerStats()); publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL); Loading Loading @@ -7377,7 +7386,15 @@ public class NotificationManagerService extends SystemService { Objects.requireNonNull(user); Objects.requireNonNull(parentId); Objects.requireNonNull(conversationId); verifyPrivilegedListener(token, user, true); ManagedServiceInfo nlsInfo = verifyPrivilegedListener(token, user, true); if (!nlsInfo.isSystemUi() && !isNotificationAssistant(nlsInfo.service) && !mNotificationListenerStats.isAllowedToCreateChannel(nlsInfo)) { Slog.e(TAG, "NLS " + nlsInfo + " has created too many channels already! " + "Rejecting " + pkg + "/" + user + "/" + parentId + "/" + conversationId); return null; } if (notificationClassification()) { if (SYSTEM_RESERVED_IDS.contains(parentId)) { Loading @@ -7388,18 +7405,39 @@ public class NotificationManagerService extends SystemService { } } int uid = getUidForPackageAndUser(pkg, user); NotificationChannel conversationChannel = mPreferencesHelper.getNotificationChannel(pkg, uid, parentId, false).copy(); String conversationChannelId = String.format( CONVERSATION_CHANNEL_ID_FORMAT, parentId, conversationId); if (uid == INVALID_UID) { return null; } NotificationChannel parentChannel = mPreferencesHelper.getNotificationChannel(pkg, uid, parentId, false); if (parentChannel == null) { return null; } NotificationChannel previous = mPreferencesHelper.getConversationNotificationChannel( pkg, uid, parentId, conversationId, false, false); if (previous != null) { // If the conversation already exists, we're done. Continuing is worse since // it would override any conversation customizations with the parent's values. return previous; } String conversationChannelId = String.format(CONVERSATION_CHANNEL_ID_FORMAT, parentId, conversationId); NotificationChannel conversationChannel = parentChannel.copy(); conversationChannel.setId(conversationChannelId); conversationChannel.setConversationId(parentId, conversationId); createNotificationChannelsImpl( pkg, uid, new ParceledListSlice(Arrays.asList(conversationChannel))); pkg, uid, new ParceledListSlice<>(Arrays.asList(conversationChannel))); NotificationChannel created = mPreferencesHelper.getConversationNotificationChannel( pkg, uid, parentId, conversationId, false, false); if (created != null) { mNotificationListenerStats.logCreatedChannels(nlsInfo, /* increase= */ 1); handleSavePolicyFile(); } return mPreferencesHelper.getConversationNotificationChannel( pkg, uid, parentId, conversationId, false, false).copy(); return created; } @Override Loading Loading @@ -7491,8 +7529,9 @@ public class NotificationManagerService extends SystemService { return mPermissionHelper.isPermissionFixed(pkg, userId); } private void verifyPrivilegedListener(INotificationListener token, UserHandle user, boolean assistantAllowed) { @NonNull private ManagedServiceInfo verifyPrivilegedListener(INotificationListener token, UserHandle user, boolean assistantAllowed) { ManagedServiceInfo info; synchronized (mNotificationLock) { info = mListeners.checkServiceTokenLocked(token); Loading @@ -7507,6 +7546,7 @@ public class NotificationManagerService extends SystemService { if (!info.enabledAndUserMatches(user.getIdentifier())) { throw new SecurityException(info + " does not have access"); } return info; } private void verifyPrivilegedListenerUriPermission(int sourceUid, Loading Loading @@ -8218,6 +8258,7 @@ public class NotificationManagerService extends SystemService { pw.println("\n Notification listeners:"); mListeners.dump(pw, filter); pw.print(" mListenerHints: "); pw.println(mListenerHints); pw.print(" mListenersDisablingEffects: ("); N = mListenersDisablingEffects.size(); for (int i = 0; i < N; i++) { Loading @@ -8237,6 +8278,10 @@ public class NotificationManagerService extends SystemService { } } pw.println(')'); pw.println("\n NotificationListenerStats:"); mNotificationListenerStats.dump(pw, " "); pw.println("\n Notification assistant services:"); mAssistants.dump(pw, filter); } Loading Loading @@ -11072,6 +11117,8 @@ public class NotificationManagerService extends SystemService { // (recently dismissed notifications) and notification history. mArchive.removePackageNotifications(pkg, userHandle); mHistoryManager.onPackageRemoved(userHandle, pkg); // Remove from NLS Stats (in case the package included an NLS). mNotificationListenerStats.onPackageRemoved(uid, pkg); } } if (preferencesChanged) { Loading Loading @@ -12419,11 +12466,11 @@ public class NotificationManagerService extends SystemService { */ @VisibleForTesting boolean isInteractionVisibleToListener(ManagedServiceInfo info, int userId) { boolean isAssistantService = isServiceTokenValid(info.getService()); boolean isAssistantService = isNotificationAssistant(info.getService()); return !isAssistantService || info.isSameUser(userId); } private boolean isServiceTokenValid(IInterface service) { private boolean isNotificationAssistant(IInterface service) { synchronized (mNotificationLock) { return mAssistants.isServiceTokenValidLocked(service); } Loading Loading @@ -14671,7 +14718,7 @@ public class NotificationManagerService extends SystemService { BackgroundThread.getHandler().post(() -> { if (info.isSystem || hasCompanionDevice(info) || isServiceTokenValid(info.service)) { || isNotificationAssistant(info.service)) { notifyNotificationChannelChanged( info, pkg, user, channel, modificationType); } services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +105 −121 File changed.Preview size limit exceeded, changes collapsed. Show changes services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -175,7 +175,7 @@ public class RoleObserverTest extends UiServiceTestCase { mock(PowerManager.class), new NotificationManagerService.PostNotificationTrackerFactory() {}, mock(UiEventLogger.class), mock(BitmapOffloadInternal.class)); mock(BitmapOffloadInternal.class), new NotificationListenerStats()); } catch (SecurityException e) { if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) { throw e; Loading Loading
services/core/java/com/android/server/notification/NotificationListenerStats.java 0 → 100644 +134 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.notification; import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; import com.android.server.notification.ManagedServices.ManagedServiceInfo; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.io.PrintWriter; class NotificationListenerStats { /** * Maximum number of channels that a single NLS is allowed to create for <em>all</em> installed * packages. Should be much higher than reasonably necessary, but still prevent runaway channel * creation abuse. * * @see PreferencesHelper#NOTIFICATION_CHANNEL_COUNT_LIMIT */ private static final int MAX_CHANNELS = 5_000; private static final String TAG_STATS = "nlsStats"; private static final String TAG_NLS = "nls"; private static final String ATT_UID = "uid"; private static final String ATT_OWNED_CHANNEL_COUNT = "channelCount"; private final Object mLock = new Object(); // nlsUid => count of channels created by that (privileged) NLS. @GuardedBy("mLock") private final SparseIntArray mChannelsCreated = new SparseIntArray(); private final int mMaxChannelsAllowed; NotificationListenerStats() { this(MAX_CHANNELS); } @VisibleForTesting NotificationListenerStats(int maxChannelsAllowed) { mMaxChannelsAllowed = maxChannelsAllowed; } boolean isAllowedToCreateChannel(ManagedServiceInfo nls) { synchronized (mLock) { int numCreated = mChannelsCreated.get(nls.uid); return numCreated < mMaxChannelsAllowed; } } void logCreatedChannels(ManagedServiceInfo nls, int increase) { synchronized (mLock) { int prevCreated = mChannelsCreated.get(nls.uid); mChannelsCreated.put(nls.uid, prevCreated + increase); } } void onPackageRemoved(int uid, String packageName) { // If the uninstalled package was an NLS, drop its stats. synchronized (mLock) { mChannelsCreated.delete(uid); } } static boolean isXmlTag(String tag) { return TAG_STATS.equals(tag); } void writeXml(TypedXmlSerializer out) throws IOException { out.startTag(null, TAG_STATS); synchronized (mLock) { for (int i = 0; i < mChannelsCreated.size(); i++) { out.startTag(null, TAG_NLS); out.attributeInt(null, ATT_UID, mChannelsCreated.keyAt(i)); out.attributeInt(null, ATT_OWNED_CHANNEL_COUNT, mChannelsCreated.valueAt(i)); out.endTag(null, TAG_NLS); } } out.endTag(null, TAG_STATS); } void readXml(TypedXmlPullParser parser) throws XmlPullParserException, IOException { int type = parser.getEventType(); if (type != XmlPullParser.START_TAG) return; String tag = parser.getName(); if (!TAG_STATS.equals(tag)) return; synchronized (mLock) { while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { tag = parser.getName(); if (type == XmlPullParser.END_TAG && TAG_STATS.equals(tag)) { break; } if (type == XmlPullParser.START_TAG) { if (TAG_NLS.equals(tag)) { int uid = parser.getAttributeInt(null, ATT_UID, 0); int channelCount = parser.getAttributeInt(null, ATT_OWNED_CHANNEL_COUNT, 0); mChannelsCreated.put(uid, channelCount); } } } } } void dump(PrintWriter pw, String prefix) { synchronized (mLock) { for (int i = 0; i < mChannelsCreated.size(); i++) { pw.println(prefix + "NLS with uid " + mChannelsCreated.keyAt(i)); pw.println(prefix + " created channel count: " + mChannelsCreated.valueAt(i)); } } } }
services/core/java/com/android/server/notification/NotificationManagerService.java +63 −16 Original line number Diff line number Diff line Loading @@ -787,6 +787,7 @@ public class NotificationManagerService extends SystemService { @VisibleForTesting NotificationAssistants mAssistants; private ConditionProviders mConditionProviders; private NotificationListenerStats mNotificationListenerStats; private NotificationUsageStats mUsageStats; private boolean mLockScreenAllowSecureNotifications = true; final ArrayMap<String, ArrayMap<Integer, Loading Loading @@ -1239,6 +1240,9 @@ public class NotificationManagerService extends SystemService { mLockScreenAllowSecureNotifications = parser.getAttributeBoolean(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE, true); } if (NotificationListenerStats.isXmlTag(parser.getName())) { mNotificationListenerStats.readXml(parser); } } if (!migratedManagedServices) { Loading Loading @@ -1359,6 +1363,9 @@ public class NotificationManagerService extends SystemService { if (!forBackup || userId == USER_SYSTEM) { writeSecureNotificationsPolicy(out); } if (!forBackup) { mNotificationListenerStats.writeXml(out); } out.endTag(null, TAG_NOTIFICATION_POLICY); out.endDocument(); } Loading Loading @@ -2796,7 +2803,8 @@ public class NotificationManagerService extends SystemService { SystemUiSystemPropertiesFlags.FlagResolver flagResolver, PermissionManager permissionManager, PowerManager powerManager, PostNotificationTrackerFactory postNotificationTrackerFactory, UiEventLogger uiEventLogger, BitmapOffloadInternal bitmapOffloader) { UiEventLogger uiEventLogger, BitmapOffloadInternal bitmapOffloader, NotificationListenerStats notificationListenerStats) { mHandler = handler; if (Flags.nmBinderPerfThrottleEffectsSuppressorBroadcast()) { mBroadcastsHandler = broadcastsHandler; Loading Loading @@ -2847,6 +2855,7 @@ public class NotificationManagerService extends SystemService { mMetricsLogger = new MetricsLogger(); mRankingHandler = rankingHandler; mConditionProviders = conditionProviders; mNotificationListenerStats = notificationListenerStats; mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), Clock.systemUTC(), mConditionProviders, flagResolver, new ZenModeEventLogger(mPackageManagerClient)); mZenModeHelper.addCallback(new ZenModeHelper.Callback() { Loading Loading @@ -3170,7 +3179,7 @@ public class NotificationManagerService extends SystemService { getContext().getSystemService(PermissionManager.class), getContext().getSystemService(PowerManager.class), new PostNotificationTrackerFactory() {}, new UiEventLoggerImpl(), bitmapOffloader); bitmapOffloader, new NotificationListenerStats()); publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL); Loading Loading @@ -7377,7 +7386,15 @@ public class NotificationManagerService extends SystemService { Objects.requireNonNull(user); Objects.requireNonNull(parentId); Objects.requireNonNull(conversationId); verifyPrivilegedListener(token, user, true); ManagedServiceInfo nlsInfo = verifyPrivilegedListener(token, user, true); if (!nlsInfo.isSystemUi() && !isNotificationAssistant(nlsInfo.service) && !mNotificationListenerStats.isAllowedToCreateChannel(nlsInfo)) { Slog.e(TAG, "NLS " + nlsInfo + " has created too many channels already! " + "Rejecting " + pkg + "/" + user + "/" + parentId + "/" + conversationId); return null; } if (notificationClassification()) { if (SYSTEM_RESERVED_IDS.contains(parentId)) { Loading @@ -7388,18 +7405,39 @@ public class NotificationManagerService extends SystemService { } } int uid = getUidForPackageAndUser(pkg, user); NotificationChannel conversationChannel = mPreferencesHelper.getNotificationChannel(pkg, uid, parentId, false).copy(); String conversationChannelId = String.format( CONVERSATION_CHANNEL_ID_FORMAT, parentId, conversationId); if (uid == INVALID_UID) { return null; } NotificationChannel parentChannel = mPreferencesHelper.getNotificationChannel(pkg, uid, parentId, false); if (parentChannel == null) { return null; } NotificationChannel previous = mPreferencesHelper.getConversationNotificationChannel( pkg, uid, parentId, conversationId, false, false); if (previous != null) { // If the conversation already exists, we're done. Continuing is worse since // it would override any conversation customizations with the parent's values. return previous; } String conversationChannelId = String.format(CONVERSATION_CHANNEL_ID_FORMAT, parentId, conversationId); NotificationChannel conversationChannel = parentChannel.copy(); conversationChannel.setId(conversationChannelId); conversationChannel.setConversationId(parentId, conversationId); createNotificationChannelsImpl( pkg, uid, new ParceledListSlice(Arrays.asList(conversationChannel))); pkg, uid, new ParceledListSlice<>(Arrays.asList(conversationChannel))); NotificationChannel created = mPreferencesHelper.getConversationNotificationChannel( pkg, uid, parentId, conversationId, false, false); if (created != null) { mNotificationListenerStats.logCreatedChannels(nlsInfo, /* increase= */ 1); handleSavePolicyFile(); } return mPreferencesHelper.getConversationNotificationChannel( pkg, uid, parentId, conversationId, false, false).copy(); return created; } @Override Loading Loading @@ -7491,8 +7529,9 @@ public class NotificationManagerService extends SystemService { return mPermissionHelper.isPermissionFixed(pkg, userId); } private void verifyPrivilegedListener(INotificationListener token, UserHandle user, boolean assistantAllowed) { @NonNull private ManagedServiceInfo verifyPrivilegedListener(INotificationListener token, UserHandle user, boolean assistantAllowed) { ManagedServiceInfo info; synchronized (mNotificationLock) { info = mListeners.checkServiceTokenLocked(token); Loading @@ -7507,6 +7546,7 @@ public class NotificationManagerService extends SystemService { if (!info.enabledAndUserMatches(user.getIdentifier())) { throw new SecurityException(info + " does not have access"); } return info; } private void verifyPrivilegedListenerUriPermission(int sourceUid, Loading Loading @@ -8218,6 +8258,7 @@ public class NotificationManagerService extends SystemService { pw.println("\n Notification listeners:"); mListeners.dump(pw, filter); pw.print(" mListenerHints: "); pw.println(mListenerHints); pw.print(" mListenersDisablingEffects: ("); N = mListenersDisablingEffects.size(); for (int i = 0; i < N; i++) { Loading @@ -8237,6 +8278,10 @@ public class NotificationManagerService extends SystemService { } } pw.println(')'); pw.println("\n NotificationListenerStats:"); mNotificationListenerStats.dump(pw, " "); pw.println("\n Notification assistant services:"); mAssistants.dump(pw, filter); } Loading Loading @@ -11072,6 +11117,8 @@ public class NotificationManagerService extends SystemService { // (recently dismissed notifications) and notification history. mArchive.removePackageNotifications(pkg, userHandle); mHistoryManager.onPackageRemoved(userHandle, pkg); // Remove from NLS Stats (in case the package included an NLS). mNotificationListenerStats.onPackageRemoved(uid, pkg); } } if (preferencesChanged) { Loading Loading @@ -12419,11 +12466,11 @@ public class NotificationManagerService extends SystemService { */ @VisibleForTesting boolean isInteractionVisibleToListener(ManagedServiceInfo info, int userId) { boolean isAssistantService = isServiceTokenValid(info.getService()); boolean isAssistantService = isNotificationAssistant(info.getService()); return !isAssistantService || info.isSameUser(userId); } private boolean isServiceTokenValid(IInterface service) { private boolean isNotificationAssistant(IInterface service) { synchronized (mNotificationLock) { return mAssistants.isServiceTokenValidLocked(service); } Loading Loading @@ -14671,7 +14718,7 @@ public class NotificationManagerService extends SystemService { BackgroundThread.getHandler().post(() -> { if (info.isSystem || hasCompanionDevice(info) || isServiceTokenValid(info.service)) { || isNotificationAssistant(info.service)) { notifyNotificationChannelChanged( info, pkg, user, channel, modificationType); }
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +105 −121 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -175,7 +175,7 @@ public class RoleObserverTest extends UiServiceTestCase { mock(PowerManager.class), new NotificationManagerService.PostNotificationTrackerFactory() {}, mock(UiEventLogger.class), mock(BitmapOffloadInternal.class)); mock(BitmapOffloadInternal.class), new NotificationListenerStats()); } catch (SecurityException e) { if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) { throw e; Loading