How Chromium Manages Android Web Push Notification Channels

This article explores the architecture behind the Chromium web browser's native notification bridge on Android and how it manages user-configurable web push notification channels. It covers the communication between C++ and Java via the Java Native Interface (JNI), the dynamic creation of site-specific notification channels, how notifications are routed, and how Android OS-level user preferences are synchronized with the browser's internal permission engine.

The Architecture of the Notification Bridge

Chromium’s core logic, including the handling of Service Workers and the Web Push protocol, is written in C++. However, the Android operating system requires interactions with its system services, such as the NotificationManager, to be executed in Java.

To connect these two environments, Chromium uses a native notification bridge split into two primary components:

  • NotificationPlatformBridgeAndroid (C++): Resides in the browser process and receives requests from the Blink rendering engine to display or close a notification.
  • NotificationPlatformBridge (Java): Receives data from the C++ layer via the Java Native Interface (JNI) and communicates directly with the Android OS APIs.

When a web push notification is triggered, the C++ layer packages the notification data (title, body, icon, and origin URL) and passes it across the JNI boundary to the Java bridge for native rendering.

Dynamic Channel Creation per Origin

Starting with Android 8.0 (API level 26), all notifications must be assigned to a specific Notification Channel. This allows users to control notification behavior—such as sound, vibration, and visual priority—at the operating system level.

If Chromium used a single channel for all web notifications, muting one annoying website would mute every website. To solve this, the Java bridge uses a component called SiteChannelsManager to dynamically manage channels on a per-origin basis:

  1. Permission Grant: When a user grants notification permissions to a website (e.g., https://example.com), Chromium triggers the SiteChannelsManager.
  2. Channel Generation: The manager creates a new Android NotificationChannel specifically for that origin. The website's domain is used as the user-visible channel name.
  3. Grouping: To prevent the Android system settings from becoming disorganized, the bridge assigns all website-specific channels to a single NotificationChannelGroup labeled "Sites."

Routing Web Push Notifications

Once a channel exists, routing incoming web push messages becomes a matter of matching origins to channel IDs.

When the Java NotificationPlatformBridge receives a notification payload from the C++ layer, it extracts the origin URL of the sending website. It queries the SiteChannelsManager to retrieve the unique channel ID associated with that origin. The bridge then constructs the native Android notification using NotificationCompat.Builder, attaches the specific channel ID, and hands it off to the Android NotificationManager for display. The Android OS then automatically applies whatever custom sound, vibration, or DND (Do Not Disturb) override rules the user has configured for that specific channel.

Synchronizing User Configurations and Permissions

A major challenge for Chromium is that users can modify notification channels directly inside the Android OS settings app, completely bypassing the browser's user interface. A user might go into the Android settings and toggle off the channel for a specific website.

Chromium must ensure its internal permission state—managed by the HostContentSettingsMap in C++—matches the Android OS state. The bridge handles this synchronization through a state-querying mechanism:

  • Checking Channel Status: Whenever a website checks its notification permission status (via the JavaScript Notification.permission API) or when Chromium loads its site settings UI, the C++ layer asks the Java bridge for the current status of the origin's channel.
  • Evaluating Importance: The SiteChannelsManager queries the Android NotificationManager for the channel's importance level.
  • Translating States: If the user has turned off the channel in Android settings, the OS returns IMPORTANCE_NONE. The Java bridge translates this into a CONTENT_SETTING_BLOCK state and passes it back to the C++ layer. If the importance is anything higher, it returns CONTENT_SETTING_ALLOW.

Because Android does not allow apps to programmatically change a channel's settings once it is created, the user's OS-level configuration acts as the ultimate source of truth.

Channel Deletion and Cleanup

To prevent thousands of unused channels from accumulating in the Android OS settings, the native bridge also manages channel destruction.

If a user revokes a website's notification permission through Chromium's internal site settings, or if the user clears their browsing data and site permissions, the C++ layer instructs the Java bridge to clean up. The SiteChannelsManager locates the channel ID mapped to that origin and calls the Android deleteNotificationChannel API, completely removing the website's entry from the Android system menus.