AOSP Framework & Internals
3 min read

NotificationManagerService

Learn about NotificationManagerService.

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:

  1. Validation: NMS validates the Notification object, checking channel assignment, icon validity, and payload size limits.
  2. Enqueued: The notification is wrapped in a NotificationRecord and enqueued.
  3. Ranking: The RankingHelper evaluates the notification against others. Ranking determines the order of notifications in the shade. It uses an Extractor system (e.g., NotificationSignalExtractor) to parse signals like freshness, importance, contact affinity, and user overrides.
  4. Dispatch: NMS alerts active NotificationListenerService instances (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.