The Broadcast Dispatch Architecture
In the Android Open Source Project (AOSP), the broadcast mechanism is an essential IPC system allowing disparate components to respond to system-wide or application-specific events. A broadcast begins its journey when an application calls sendBroadcast(), sendOrderedBroadcast(), or sendStickyBroadcast().
The core routing is handled by the ActivityManagerService (AMS).
1. sendBroadcast() to AMS
When an app invokes Context.sendBroadcast(), the call traverses through the ContextImpl and executes an IPC call to the AMS via IActivityManager.broadcastIntent().
// ContextImpl.java
@Override
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null, null, AppOpsManager.OP_NONE,
null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
The AMS receives this intent and constructs a BroadcastRecord object. The AMS maintains separate queues for foreground and background broadcasts to ensure high-priority broadcasts are delivered promptly without being blocked by longer-running background tasks.
2. Resolving Receivers
Once the AMS has the BroadcastRecord, it must determine which applications have registered to receive this intent. It consults the PackageManagerService (PMS) using the resolveIntent() mechanism. Receivers can be:
- Dynamically Registered: Stored within the AMS's internal data structures (
mReceiverResolver). - Statically Registered: Declared in the
AndroidManifest.xmland parsed by the PMS.
3. Ordered vs Standard Dispatch
- Standard Broadcasts: AMS loops through all resolved receivers and dispatches the intent asynchronously. Order is not guaranteed.
- Ordered Broadcasts: AMS dispatches the intent to one receiver at a time, based on the
android:priorityattribute. The AMS waits for the receiver to finish (viafinishReceiver()) before moving to the next.
Sticky Broadcasts
Sticky broadcasts (e.g., ACTION_BATTERY_CHANGED) linger in the system after being sent. When a new receiver registers for a sticky intent, it immediately receives the last broadcasted value. Due to security and memory overhead concerns, custom sticky broadcasts are deprecated, but the system still utilizes them for critical continuous states.
System Broadcasts
System broadcasts are restricted to the OS. For example, ACTION_BOOT_COMPLETED is dispatched by the AMS after the SystemServer has finished booting all core services. ACTION_POWER_CONNECTED is dispatched by the BatteryService.
To debug broadcasts, you can use the following dumpsys command:
adb shell dumpsys activity broadcasts
This dumps the historical broadcast queue, active broadcasts, and registered receivers.
Broadcast Permission Enforcement
Permissions are enforced at two critical points:
- Sender-side: The sender can require receivers to hold a specific permission (e.g.,
sendBroadcast(intent, "com.example.PERMISSION")). The AMS checks if the resolved receiver holds this permission. - Receiver-side: The receiver can declare a permission requirement in its manifest or dynamic registration. The AMS verifies that the calling UID holds the required permission before dispatching.