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:
- Permission Grant: When a user grants notification
permissions to a website (e.g.,
https://example.com), Chromium triggers theSiteChannelsManager. - Channel Generation: The manager creates a new
Android
NotificationChannelspecifically for that origin. The website's domain is used as the user-visible channel name. - Grouping: To prevent the Android system settings
from becoming disorganized, the bridge assigns all website-specific
channels to a single
NotificationChannelGrouplabeled "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.permissionAPI) 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
SiteChannelsManagerqueries the AndroidNotificationManagerfor 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 aCONTENT_SETTING_BLOCKstate and passes it back to the C++ layer. If the importance is anything higher, it returnsCONTENT_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.