NotificationManagerService (NMS) handles the lifecycle, ranking, and display of system and application notifications. It bridges the gap between applications requesting to show a notification and SystemUI which actually renders it on the screen.
Notification Posting and Ranking
When an application posts a notification, it makes a Binder transaction to INotificationManager.aidl. The core logic resides in NotificationManagerService.java.
The posting flow involves several checks:
- Validation: NMS validates the
Notificationobject, checking channel assignment, icon validity, and payload size limits. - Enqueued: The notification is wrapped in a
NotificationRecordand enqueued. - Ranking: The
RankingHelperevaluates the notification against others. Ranking determines the order of notifications in the shade. It uses anExtractorsystem (e.g.,NotificationSignalExtractor) to parse signals like freshness, importance, contact affinity, and user overrides. - Dispatch: NMS alerts active
NotificationListenerServiceinstances (like SystemUI) about the new or updated notification.
Notification Channels
Introduced in Android 8.0 (Oreo), Notification Channels (NotificationChannel) mandate that apps group their notifications. This shifted control from developers to users, allowing users to block or mute specific categories rather than the entire app.
Channels are persisted by NMS using an XML file typically found at /data/system/notification_policy.xml. When a notification is posted, NMS verifies if the specified channel ID exists and applies the channel's properties (vibration, sound, importance) to the notification record.
// Simplified snippet of NMS validating a channel
NotificationChannel channel = mPreferencesHelper.getNotificationChannel(
pkg, uid, notification.getChannelId(), false);
if (channel == null) {
throw new IllegalArgumentException("Channel not found");
}
if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
// Drop notification early if blocked by user
return;
}
NotificationListenerService
SystemUI and third-party apps (like smartwatches or Android Auto) consume notifications by implementing NotificationListenerService. This component binds to NMS and receives callbacks like onNotificationPosted() and onNotificationRemoved().
Because this allows access to sensitive user data, binding a NotificationListenerService requires the user to explicitly grant permission via Settings. Internally, NMS tracks allowed listeners using ManagedServices and restricts binding exclusively to approved components.
You can inspect active listeners via adb:
adb shell dumpsys notification --nls
DND (Do Not Disturb) Policy
Do Not Disturb, managed by ZenModeHelper within NMS, dictates whether a notification is allowed to interrupt the user (e.g., make sound, vibrate, or turn on the screen).
The Zen policy consists of rules (e.g., "Priority Only", "Alarms Only", "Total Silence"). When a notification reaches the ranking phase, the ZenModeFiltering system intercepts it. If the notification does not match the criteria of the active Zen mode (for instance, a message from an unstarred contact during "Priority Only" mode), NMS sets the NotificationRecord.setIntercepted(true) flag.
SystemUI observes this flag and suppresses the auditory and visual interruptions, though the notification may still appear silently in the notification shade.