AOSP Broadcast 广播机制源码分析
目录
1. 广播的设计和实现原理
1.1 广播架构概述
Android广播(Broadcast)是一种基于发布-订阅(Publish-Subscribe)模式的组件间通信机制。它允许应用程序或系统组件向其他组件发送异步消息,实现松耦合的组件间通信。
核心设计思想
+------------------+
| BroadcastQueue |
| (Abstract) |
+--------+---------+
|
v
+--------------------------------+
| BroadcastQueueModernImpl |
| (Modern Queue Implementation)|
+--------------------------------+
|
+----------------------+----------------------+
| | |
v v v
+---------------+ +----------------+ +--------------+
| BroadcastRecord| |BroadcastProcess| |BroadcastFilter|
| (广播记录) | | Queue | | (动态注册) |
+---------------+ +----------------+ +--------------+
1.2 核心类和组件分析
1.2.1 BroadcastQueue (抽象基类)
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
java
// BroadcastQueue.java:44-62
public abstract class BroadcastQueue {
public static final String TAG = "BroadcastQueue";
public static final String TAG_DUMP = "broadcast_queue_dump";
final @NonNull ActivityManagerService mService;
final @NonNull Handler mHandler;
final @NonNull BroadcastSkipPolicy mSkipPolicy;
final @NonNull BroadcastHistory mHistory;
final @NonNull String mQueueName;
BroadcastQueue(@NonNull ActivityManagerService service, @NonNull Handler handler,
@NonNull String name, @NonNull BroadcastSkipPolicy skipPolicy,
@NonNull BroadcastHistory history) {
mService = Objects.requireNonNull(service);
mHandler = Objects.requireNonNull(handler);
mQueueName = Objects.requireNonNull(name);
mSkipPolicy = Objects.requireNonNull(skipPolicy);
mHistory = Objects.requireNonNull(history);
}
// ...
}
核心方法:
enqueueBroadcastLocked(): 将广播加入队列finishReceiverLocked(): 接收器处理完成的信号onApplicationAttachedLocked(): 进程启动后的回调isIdleLocked(): 判断队列是否空闲
1.2.2 BroadcastQueueModernImpl (现代队列实现)
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
这是Android 14+中使用的现代广播队列实现,采用按进程调度的方式。
java
// BroadcastQueueModernImpl.java:116-140
/**
* Alternative {@link BroadcastQueue} implementation which pivots broadcasts to
* be dispatched on a per-process basis.
* <p>
* Each process now has its own broadcast queue represented by a
* {@link BroadcastProcessQueue} instance. Each queue has a concept of being
* "runnable at" a particular time in the future, which supports arbitrarily
* pausing or delaying delivery on a per-process basis.
*/
class BroadcastQueueModernImpl extends BroadcastQueue {
// 进程队列映射: UID -> BroadcastProcessQueue
@GuardedBy("mService")
private final SparseArray<BroadcastProcessQueue> mProcessQueues = new SparseArray<>();
// 可运行队列链表头
private BroadcastProcessQueue mRunnableHead = null;
// 正在运行的队列数组
@GuardedBy("mService")
private final BroadcastProcessQueue[] mRunning;
// 等待冷启动的队列
@GuardedBy("mService")
private @Nullable BroadcastProcessQueue mRunningColdStart;
}
1.2.3 BroadcastRecord (广播记录)
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastRecord.java
java
// BroadcastRecord.java:79-144
final class BroadcastRecord extends Binder {
final @NonNull Intent intent; // 原始Intent
final @Nullable ComponentName targetComp; // 目标组件
final @Nullable ProcessRecord callerApp; // 发送者进程
final @Nullable String callerPackage; // 发送者包名
final int callingPid; // 发送者PID
final int callingUid; // 发送者UID
final boolean ordered; // 是否有序广播
final boolean sticky; // 是否粘性广播
final boolean alarm; // 是否闹钟触发
final boolean pushMessage; // 是否推送消息
final boolean interactive; // 是否交互式
final boolean initialSticky; // 是否初始粘性
final boolean prioritized; // 是否优先级分层
final boolean deferUntilActive; // 延迟至活跃
final int userId; // 用户ID
final @NonNull List<Object> receivers; // 接收者列表 (BroadcastFilter 或 ResolveInfo)
final @DeliveryState int[] delivery; // 每个接收者的投递状态
// 投递状态定义
static final int DELIVERY_PENDING = 0; // 等待投递
static final int DELIVERY_DELIVERED = 1; // 投递成功
static final int DELIVERY_SKIPPED = 2; // 跳过
static final int DELIVERY_TIMEOUT = 3; // 超时
static final int DELIVERY_SCHEDULED = 4; // 已调度
static final int DELIVERY_FAILURE = 5; // 失败
static final int DELIVERY_DEFERRED = 6; // 延迟
}
1.2.4 BroadcastFilter (动态注册的接收器)
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastFilter.java
java
// BroadcastFilter.java:29-57
public final class BroadcastFilter extends IntentFilter {
final ReceiverList receiverList; // 关联的接收器列表
final String packageName; // 包名
final String featureId; // 特性ID
final String receiverId; // 接收器ID
final String requiredPermission; // 所需权限
final int owningUid; // 所属UID
final int owningUserId; // 所属用户ID
final boolean instantApp; // 是否即时应用
final boolean visibleToInstantApp;// 对即时应用可见
public final boolean exported; // 是否导出
}
1.2.5 BroadcastProcessQueue (进程广播队列)
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastProcessQueue.java
java
// BroadcastProcessQueue.java:51-65
/**
* Queue of pending {@link BroadcastRecord} entries intended for delivery to a
* specific process.
* <p>
* Each queue has a concept of being "runnable at" a particular time in the
* future, which supports arbitrarily pausing or delaying delivery on a
* per-process basis.
*/
class BroadcastProcessQueue {
final @NonNull BroadcastConstants constants;
final @NonNull String processName;
final int uid;
// 等待投递的广播队列
private final ArrayDeque<SomeArgs> mPending = new ArrayDeque<>();
// 紧急广播队列
private final ArrayDeque<SomeArgs> mPendingUrgent = new ArrayDeque<>(4);
// 卸载广播队列
private final ArrayDeque<SomeArgs> mPendingOffload = new ArrayDeque<>(4);
// 当前活跃的广播
private @Nullable BroadcastRecord mActive;
}
1.2.6 BroadcastConstants (广播常量配置)
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastConstants.java
java
// BroadcastConstants.java:48-112
public class BroadcastConstants {
// 默认超时时间 10秒
private static final long DEFAULT_TIMEOUT = 10_000 * Build.HW_TIMEOUT_MULTIPLIER;
// 超时时间配置
public long TIMEOUT = DEFAULT_TIMEOUT;
// 并行运行的进程队列数
public int MAX_RUNNING_PROCESS_QUEUES = DEFAULT_MAX_RUNNING_PROCESS_QUEUES;
private static final int DEFAULT_MAX_RUNNING_PROCESS_QUEUES =
ActivityManager.isLowRamDeviceStatic() ? 2 : 4;
// 紧急广播额外的并行队列
public int EXTRA_RUNNING_URGENT_PROCESS_QUEUES = DEFAULT_EXTRA_RUNNING_URGENT_PROCESS_QUEUES;
// 普通广播延迟 500ms
public long DELAY_NORMAL_MILLIS = DEFAULT_DELAY_NORMAL_MILLIS;
private static final long DEFAULT_DELAY_NORMAL_MILLIS = +500;
// 缓存应用广播延迟 120秒
public long DELAY_CACHED_MILLIS = DEFAULT_DELAY_CACHED_MILLIS;
private static final long DEFAULT_DELAY_CACHED_MILLIS = +120_000;
// 紧急广播延迟 -120秒 (优先处理)
public long DELAY_URGENT_MILLIS = DEFAULT_DELAY_URGENT_MILLIS;
private static final long DEFAULT_DELAY_URGENT_MILLIS = -120_000;
}
1.3 广播系统架构图
数据结构
广播队列层
Framework层
应用层 Application Layer
App 1
sendBroadcast
App 2
BroadcastReceiver
App 3
BroadcastReceiver
ContextImpl
broadcastIntent
ActivityManagerService
broadcastIntentWithFeature
BroadcastController
broadcastIntentLocked
BroadcastQueue
Abstract
BroadcastQueueModernImpl
Modern Implementation
BroadcastProcessQueue
Process 1
BroadcastProcessQueue
Process 2
BroadcastRecord
广播记录
BroadcastFilter
动态注册
ResolveInfo
静态注册
2. 广播的使用和整体调用流程
2.1 发送广播API
2.1.1 ContextImpl中的发送方法
文件路径 : frameworks/base/core/java/android/app/ContextImpl.java
| API | 描述 | 是否有序 | 是否粘性 |
|---|---|---|---|
sendBroadcast(Intent) |
发送普通广播 | 否 | 否 |
sendBroadcast(Intent, String) |
发送带权限的广播 | 否 | 否 |
sendOrderedBroadcast(Intent, String) |
发送有序广播 | 是 | 否 |
sendStickyBroadcast(Intent) |
发送粘性广播(已废弃) | 否 | 是 |
sendBroadcastAsUser(Intent, UserHandle) |
向指定用户发送广播 | 否 | 否 |
java
// ContextImpl.java:1500-1511 - sendBroadcastAsUser示例
@Override
public void sendBroadcastAsUser(Intent intent, UserHandle user) {
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 /*excludedPermissions=*/,
null, AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
2.2 注册广播接收器
2.2.1 动态注册
文件路径 : frameworks/base/core/java/android/app/ContextImpl.java:1851-1948
java
// ContextImpl.java:1903-1948 - registerReceiverInternal
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
IIntentReceiver rd = null;
if (receiver != null) {
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
}
// ...
}
try {
final Intent intent;
intent = ActivityManager.getService().registerReceiverWithFeature(
mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(),
AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission,
userId, flags);
// ...
return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
2.2.2 静态注册(Manifest方式)
在AndroidManifest.xml中声明:
xml
<receiver android:name=".MyReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.example.MY_ACTION" />
</intent-filter>
</receiver>
2.3 完整调用链时序图
Receiver Process BroadcastProcessQueue BroadcastQueueModernImpl BroadcastController ActivityManagerService ContextImpl Application Receiver Process BroadcastProcessQueue BroadcastQueueModernImpl BroadcastController ActivityManagerService ContextImpl Application 1. 验证Intent合法性 2. 检查权限 3. 处理受保护广播 4. 收集接收者 loop [每个接收者] alt [进程已启动(Warm)] [进程未启动(Cold)] sendBroadcast(intent) prepareToLeaveProcess(intent) broadcastIntentWithFeature() broadcastIntentLocked() collectReceivers() enqueueBroadcastLocked(record) enqueueOrReplaceBroadcast() updateRunnableList(queue) updateRunningListLocked() scheduleReceiverWarmLocked() scheduleReceiver() / scheduleRegisteredReceiver() scheduleReceiverColdLocked() startProcessLocked() onApplicationAttachedLocked() scheduleReceiver() onReceive() finishReceiver() finishReceiverLocked()
2.4 广播发送核心流程代码
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastController.java
java
// BroadcastController.java:760-788 - broadcastIntentLocked
@GuardedBy("mService")
final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,
@Nullable String callerFeatureId, Intent intent, String resolvedType,
ProcessRecord resultToApp, IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions,
String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid,
int realCallingUid, int realCallingPid, int userId,
BackgroundStartPrivileges backgroundStartPrivileges,
@Nullable int[] broadcastAllowList,
@Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
final int cookie = traceBroadcastIntentBegin(intent, resultTo, ordered, sticky,
callingUid, realCallingUid, userId);
try {
final BroadcastSentEventRecord broadcastSentEventRecord =
new BroadcastSentEventRecord();
final int res = broadcastIntentLockedTraced(callerApp, callerPackage,
callerFeatureId, intent, resolvedType, resultToApp, resultTo,
resultCode, resultData, resultExtras, requiredPermissions,
excludedPermissions, excludedPackages, appOp,
BroadcastOptions.fromBundleNullable(bOptions), ordered, sticky,
callingPid, callingUid, realCallingUid, realCallingPid, userId,
backgroundStartPrivileges, broadcastAllowList, filterExtrasForReceiver,
broadcastSentEventRecord);
// ...
return res;
} finally {
traceBroadcastIntentEnd(cookie);
}
}
3. 广播的派发流程
3.1 BroadcastQueue实现机制
3.1.1 队列入队流程
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java:782-867
java
// BroadcastQueueModernImpl.java:782-867 - enqueueBroadcastLocked
@GuardedBy("mService")
@Override
public void enqueueBroadcastLocked(@NonNull BroadcastRecord r) {
// 检查发送者是否可冻结,如果是则暂存
if (Flags.deferOutgoingBroadcasts() && isProcessFreezable(r.callerApp)) {
final BroadcastProcessQueue queue = getOrCreateProcessQueue(
r.callerApp.processName, r.callerApp.uid);
if (queue.getOutgoingBroadcastCount() >= mConstants.MAX_FROZEN_OUTGOING_BROADCASTS) {
r.callerApp.killLocked("Too many outgoing broadcasts in cached state", ...);
return;
}
queue.enqueueOutgoingBroadcast(r);
return;
}
// 应用单例策略
r.applySingletonPolicy(mService);
// 应用投递组策略
applyDeliveryGroupPolicy(r);
// 记录入队时间
r.enqueueTime = SystemClock.uptimeMillis();
r.enqueueRealTime = SystemClock.elapsedRealtime();
r.enqueueClockTime = System.currentTimeMillis();
// 为每个接收者创建进程队列并入队
for (int i = 0; i < r.receivers.size(); i++) {
final Object receiver = r.receivers.get(i);
final BroadcastProcessQueue queue = getOrCreateProcessQueue(
getReceiverProcessName(receiver), getReceiverUid(receiver));
// 检查是否应该跳过
final String skipReason = mSkipPolicy.shouldSkipMessage(r, receiver);
if (skipReason != null) {
setDeliveryState(null, null, r, i, receiver,
BroadcastRecord.DELIVERY_SKIPPED, "skipped by policy: " + skipReason);
continue;
}
// 入队或替换
final BroadcastRecord replacedBroadcast = queue.enqueueOrReplaceBroadcast(
r, i, mBroadcastConsumerDeferApply);
updateRunnableList(queue);
enqueueUpdateRunningList();
}
}
3.2 有序广播和无序广播的派发机制
3.2.1 有序广播(Ordered Broadcast)
有序广播按优先级顺序逐个投递,前一个接收者处理完成后才投递给下一个。
java
// BroadcastRecord.java:756-786 - calculateBlockedUntilBeyondCount
@VisibleForTesting
static @NonNull int[] calculateBlockedUntilBeyondCount(
@NonNull List<Object> receivers, boolean ordered) {
final int N = receivers.size();
final int[] blockedUntilBeyondCount = new int[N];
int lastPriority = 0;
int lastPriorityIndex = 0;
for (int i = 0; i < N; i++) {
if (ordered) {
// 有序广播: 每个接收者需要等待前一个完成
blockedUntilBeyondCount[i] = i;
} else {
// 优先级广播: 只需等待前一个优先级档次完成
final int thisPriority = getReceiverPriority(receivers.get(i));
if ((i == 0) || (thisPriority != lastPriority)) {
lastPriority = thisPriority;
lastPriorityIndex = i;
blockedUntilBeyondCount[i] = i;
} else {
blockedUntilBeyondCount[i] = lastPriorityIndex;
}
}
}
// ...
return blockedUntilBeyondCount;
}
有序广播特点:
- 按优先级顺序逐个投递
- 可以通过
abortBroadcast()终止传递 - 可以设置结果数据传递给下一个接收者
- 投递超时会触发ANR
3.2.2 无序广播(Normal Broadcast)
无序广播可以并行投递给多个接收者。
无序广播
Broadcast
Receiver 1
Receiver 2
Receiver 3
有序广播
Receiver 1
Priority: 100
Receiver 2
Priority: 50
Receiver 3
Priority: 0
3.3 广播匹配和过滤机制
3.3.1 BroadcastSkipPolicy (跳过策略)
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
java
// BroadcastSkipPolicy.java:74-80 - shouldSkipMessage
public @Nullable String shouldSkipMessage(@NonNull BroadcastRecord r,
@NonNull Object target) {
if (target instanceof BroadcastFilter) {
return shouldSkipMessage(r, (BroadcastFilter) target);
} else {
return shouldSkipMessage(r, (ResolveInfo) target);
}
}
跳过条件:
- Target SDK版本不匹配 :
BroadcastOptions指定的API级别范围 - 兼容性变更过滤 :
requireCompatChange检查 - 关联不允许 :
validateAssociationAllowedLocked - 防火墙阻止 :
IntentFirewall.checkBroadcast - 权限检查失败: 组件权限、AppOps权限
- 包不可用: 包已禁用或不存在
- 用户未运行: 目标用户不在运行状态
- 排除权限/包 :
excludedPermissions/excludedPackages
3.3.2 接收者解析流程
java
// BroadcastController.java - 收集接收者
// 1. 收集静态注册的接收者(Manifest)
List<ResolveInfo> receivers = collectReceiverComponents(intent, resolvedType,
callingUid, userIds, flags);
// 2. 收集动态注册的接收者
List<BroadcastFilter> registeredReceivers =
mReceiverResolver.queryIntent(snapshot, intent, resolvedType, false, userId);
// 3. 合并并按优先级排序
3.4 投递状态机
入队
调度投递
策略跳过
延迟投递
投递成功
超时
失败
进程激活
直接投递
PENDING
SCHEDULED
SKIPPED
DEFERRED
DELIVERED
TIMEOUT
FAILURE
4. 广播ANR机制
4.1 ANR触发条件
广播ANR(Application Not Responding)在以下情况触发:
- 前台广播超时: 默认10秒
- 后台广播超时: 默认10秒(可配置延长)
- 有序广播接收者未完成 : 超过超时时间未调用
finishReceiver()
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastConstants.java:60-62
java
// BroadcastConstants.java:60-62
// 默认超时时间 10秒
private static final long DEFAULT_TIMEOUT = 10_000 * Build.HW_TIMEOUT_MULTIPLIER;
public long TIMEOUT = DEFAULT_TIMEOUT;
4.2 ANR检测和处理流程
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
java
// BroadcastQueueModernImpl.java:1127-1150 - dispatchReceivers (启动ANR计时器)
@GuardedBy("mService")
@CheckResult
private boolean dispatchReceivers(@NonNull BroadcastProcessQueue queue,
@NonNull BroadcastRecord r, int index) throws BroadcastRetryException {
// ...
// 跳过ANR追踪的条件: 启动早期、请求豁免、假定投递成功
final boolean assumeDelivered = r.isAssumedDelivered(index);
if (mService.mProcessesReady && !r.timeoutExempt && !assumeDelivered) {
queue.setTimeoutScheduled(true);
final int softTimeoutMillis = (int) (r.isForeground() ? mFgConstants.TIMEOUT
: mBgConstants.TIMEOUT);
startDeliveryTimeoutLocked(queue, softTimeoutMillis);
} else {
queue.setTimeoutScheduled(false);
}
// ...
}
java
// BroadcastQueueModernImpl.java:1326-1331 - deliveryTimeoutLocked (处理超时)
@GuardedBy("mService")
private void deliveryTimeoutLocked(@NonNull BroadcastProcessQueue queue) {
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_TIMEOUT,
"deliveryTimeoutLocked");
demoteFromRunningLocked(queue);
}
java
// BroadcastQueueModernImpl.java:1437-1472 - finishReceiverActiveLocked (触发ANR)
@GuardedBy("mService")
private void finishReceiverActiveLocked(@NonNull BroadcastProcessQueue queue,
@DeliveryState int deliveryState, @NonNull String reason) {
// ...
if (deliveryState == BroadcastRecord.DELIVERY_TIMEOUT) {
r.anrCount++;
if (app != null && !app.isDebugging()) {
final AutoCloseable timer = mAnrTimer.accept(queue);
final String packageName = getReceiverPackageName(receiver);
final String className = getReceiverClassName(receiver);
TimeoutRecord tr = TimeoutRecord.forBroadcastReceiver(r.intent, packageName,
className).setExpiredTimer(timer);
mService.appNotResponding(queue.app, tr); // 触发ANR
} else {
mAnrTimer.discard(queue);
}
}
// ...
}
4.3 前台广播和后台广播的超时时间
| 广播类型 | 超时时间 | 说明 |
|---|---|---|
| 前台广播 | 10秒 | FLAG_RECEIVER_FOREGROUND |
| 后台广播 | 10秒 (可延长) | 普通广播 |
| ANR软超时 | 10秒 | 考虑CPU延迟后可能延长 |
java
// BroadcastQueueModernImpl.java:1304-1316 - 软超时扩展逻辑
@GuardedBy("mService")
private void deliveryTimeoutSoftLocked(@NonNull BroadcastProcessQueue queue,
int softTimeoutMillis) {
if (queue.app != null) {
// 根据进程CPU延迟扩展超时时间
final long cpuDelayTime = queue.app.getCpuDelayTime() - queue.lastCpuDelayTime;
final long hardTimeoutMillis = MathUtils.constrain(cpuDelayTime, 0, softTimeoutMillis);
mAnrTimer.start(queue, hardTimeoutMillis);
} else {
deliveryTimeoutLocked(queue);
}
}
4.4 ANR处理流程图
App Process ActivityManagerService AnrTimer BroadcastQueue App Process ActivityManagerService AnrTimer BroadcastQueue 检查CPU延迟时间 显示ANR对话框 alt [CPU延迟较大] [无延迟] alt [正常完成] [超时] startDeliveryTimeoutLocked(10s) scheduleReceiver() finishReceiver() finishReceiverLocked() cancelDeliveryTimeoutLocked() MSG_DELIVERY_TIMEOUT_SOFT 延长超时(硬超时) deliveryTimeoutLocked() appNotResponding()
5. 本地广播和全局广播
5.1 全局广播
全局广播通过ActivityManagerService进行系统级跨进程通信:
java
// 发送全局广播
context.sendBroadcast(intent);
context.sendOrderedBroadcast(intent, permission);
特点:
- 通过Binder IPC跨进程通信
- 所有匹配的接收者都能收到
- 需要权限控制确保安全
- 效率相对较低
5.2 LocalBroadcastManager (本地广播)
注意 :
LocalBroadcastManager已被官方标记为废弃(Deprecated),推荐使用LiveData、Flow或其他响应式方案。
LocalBroadcastManager位于AndroidX库中,不在AOSP核心代码中。它是一个进程内的广播机制:
java
// 使用示例(已废弃)
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
lbm.registerReceiver(receiver, filter);
lbm.sendBroadcast(intent);
实现原理:
- 使用
Handler在进程内分发消息 - 维护一个接收者列表和待处理广播队列
- 不经过
ActivityManagerService - 完全在进程内完成
5.3 两者对比
| 特性 | 全局广播 | 本地广播 |
|---|---|---|
| 作用范围 | 系统级跨进程 | 进程内 |
| 效率 | 较低(Binder IPC) | 高(Handler) |
| 安全性 | 需权限控制 | 天然安全 |
| ANR风险 | 有 | 无 |
| 是否废弃 | 否 | 是(推荐LiveData) |
6. 系统广播
6.1 常见系统广播类型
文件路径 : frameworks/base/core/res/AndroidManifest.xml
| 广播Action | 触发时机 | 是否受保护 |
|---|---|---|
ACTION_BOOT_COMPLETED |
系统启动完成 | 是 |
ACTION_SCREEN_ON/OFF |
屏幕开关 | 是 |
ACTION_BATTERY_LOW |
电量低 | 是 |
ACTION_PACKAGE_ADDED |
安装应用 | 是 |
ACTION_PACKAGE_REMOVED |
卸载应用 | 是 |
ACTION_USER_PRESENT |
用户解锁 | 是 |
ACTION_TIME_CHANGED |
时间变化 | 是 |
ACTION_LOCALE_CHANGED |
语言变化 | 是 |
6.2 受保护广播机制(Protected Broadcast)
文件路径 : frameworks/base/core/res/AndroidManifest.xml:29-67
xml
<!-- AndroidManifest.xml 受保护广播声明 -->
<protected-broadcast android:name="android.intent.action.SCREEN_OFF" />
<protected-broadcast android:name="android.intent.action.SCREEN_ON" />
<protected-broadcast android:name="android.intent.action.USER_PRESENT" />
<protected-broadcast android:name="android.intent.action.TIME_SET" />
<protected-broadcast android:name="android.intent.action.BOOT_COMPLETED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_ADDED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_REMOVED" />
<!-- ... 更多受保护广播 -->
保护检查代码:
java
// BroadcastController.java:992-1028 - 受保护广播检查
// 验证受保护广播只能由系统代码发送
final boolean isProtectedBroadcast;
try {
isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception", e);
return ActivityManager.BROADCAST_SUCCESS;
}
// 检查是否是系统调用者
final boolean isCallerSystem;
switch (UserHandle.getAppId(callingUid)) {
case ROOT_UID:
case SYSTEM_UID:
case PHONE_UID:
case BLUETOOTH_UID:
case NFC_UID:
case SE_UID:
case NETWORK_STACK_UID:
isCallerSystem = true;
break;
default:
isCallerSystem = (callerApp != null) && callerApp.isPersistent();
break;
}
// 非系统应用发送受保护广播会抛出SecurityException
if (!isCallerSystem) {
if (isProtectedBroadcast) {
String msg = "Permission Denial: not allowed to send broadcast "
+ action + " from pid=" + callingPid + ", uid=" + callingUid;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
}
6.3 系统广播处理流程
投递
受保护检查
系统广播发送
Yes
No
Yes
No
System Event
System Service
BroadcastController
isProtectedBroadcast?
isCallerSystem?
SecurityException
入队
Static Receivers
Manifest
Dynamic Receivers
Runtime
7. 广播优先级
7.1 优先级设置
7.1.1 静态注册设置优先级
xml
<receiver android:name=".MyReceiver">
<intent-filter android:priority="100">
<action android:name="com.example.MY_ACTION" />
</intent-filter>
</receiver>
7.1.2 动态注册设置优先级
java
IntentFilter filter = new IntentFilter("com.example.MY_ACTION");
filter.setPriority(100); // 设置优先级
context.registerReceiver(receiver, filter);
7.2 优先级范围
文件路径 : frameworks/base/core/java/android/content/IntentFilter.java
| 优先级 | 值 | 说明 |
|---|---|---|
| SYSTEM_HIGH_PRIORITY | 1000 | 系统最高优先级 |
| SYSTEM_LOW_PRIORITY | -1000 | 系统最低优先级 |
| 普通应用范围 | -1000 ~ 1000 | 应用可设置范围 |
7.3 优先级对派发顺序的影响
java
// BroadcastRecord.java:820-826 - 获取接收者优先级
static int getReceiverPriority(@NonNull Object receiver) {
if (receiver instanceof BroadcastFilter) {
return ((BroadcastFilter) receiver).getPriority();
} else /* if (receiver instanceof ResolveInfo) */ {
return ((ResolveInfo) receiver).priority;
}
}
派发策略:
- 有序广播: 严格按优先级从高到低顺序投递
- 无序广播: 同一优先级档次可并行投递,不同档次顺序投递
- 系统优先级 : 系统组件使用
SYSTEM_HIGH_PRIORITY确保优先处理
java
// BroadcastController.java:321-349 - 系统组件自动提升优先级
if (UserHandle.isCore(callingUid)) {
final int priority = filter.getPriority();
final boolean systemPriority = (priority >= IntentFilter.SYSTEM_HIGH_PRIORITY)
|| (priority <= IntentFilter.SYSTEM_LOW_PRIORITY);
if (!systemPriority) {
// 检查是否是重要广播
final String action = filter.getAction(i);
if (action.startsWith("android.intent.action.USER_")
|| action.startsWith("android.intent.action.PACKAGE_")
|| action.equals(Intent.ACTION_SHUTDOWN)) {
// 自动提升到系统优先级
if (priority == 0) {
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
}
}
}
}
7.4 优先级分层投递示意
优先级分层(无序广播)
完成
完成
Broadcast
Tier 1: Priority 1000
Tier 2: Priority 500
Tier 3: Priority 0
Receiver A
Receiver B
Receiver C
Receiver D
Receiver E
有序广播投递
完成
完成
完成
Broadcast
Receiver
Priority: 1000
Receiver
Priority: 500
Receiver
Priority: 0
Receiver
Priority: -500
8. 广播的优化
8.1 性能优化建议
8.1.1 避免在广播接收器中执行耗时操作
java
// 错误示例
public void onReceive(Context context, Intent intent) {
// 耗时操作会阻塞主线程并可能导致ANR
performHeavyWork(); // 不要这样做!
}
// 正确示例
public void onReceive(Context context, Intent intent) {
// 使用goAsync()异步处理
final PendingResult pendingResult = goAsync();
new Thread(() -> {
try {
performHeavyWork();
} finally {
pendingResult.finish();
}
}).start();
}
8.1.2 使用BroadcastOptions优化
java
// 设置广播延迟策略
BroadcastOptions options = BroadcastOptions.makeBasic();
options.setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE);
context.sendBroadcast(intent, null, options.toBundle());
// 设置投递组策略(避免重复广播)
options.setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT);
8.1.3 合理使用FLAG_RECEIVER_REPLACE_PENDING
java
// 频繁发送的广播使用REPLACE_PENDING避免队列积压
Intent intent = new Intent("com.example.FREQUENT_UPDATE");
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
context.sendBroadcast(intent);
8.2 安全优化
8.2.1 权限控制
java
// 发送时指定权限
context.sendBroadcast(intent, "com.example.RECEIVE_PERMISSION");
// 注册时指定权限
context.registerReceiver(receiver, filter, "com.example.SEND_PERMISSION", null);
8.2.2 使用RECEIVER_EXPORTED/NOT_EXPORTED
java
// Android 12+必须显式声明导出状态
IntentFilter filter = new IntentFilter("com.example.ACTION");
context.registerReceiver(receiver, filter, Context.RECEIVER_NOT_EXPORTED);
8.2.3 防止广播被截取
java
// 发送时设置包名限定
Intent intent = new Intent("com.example.SENSITIVE_ACTION");
intent.setPackage("com.example.targetapp");
context.sendBroadcast(intent);
8.3 Android版本演进中的优化
| Android版本 | 优化内容 |
|---|---|
| Android 7.0 | 移除CONNECTIVITY_ACTION的隐式广播 |
| Android 8.0 | 限制后台应用接收隐式广播 |
| Android 9.0 | 引入FOREGROUND_SERVICE权限要求 |
| Android 12 | 要求显式声明RECEIVER_EXPORTED |
| Android 13 | 运行时权限用于POST_NOTIFICATIONS广播 |
| Android 14+ | 引入BroadcastQueueModernImpl按进程调度 |
8.3.1 Android 14+ Modern Queue 优化
java
// BroadcastConstants.java - 新的队列参数
// 最大并行进程队列数
public int MAX_RUNNING_PROCESS_QUEUES = 4; // 低内存设备为2
// 紧急广播额外并行数
public int EXTRA_RUNNING_URGENT_PROCESS_QUEUES = 1;
// 普通广播延迟(用于防抖)
public long DELAY_NORMAL_MILLIS = 500;
// 缓存应用广播延迟
public long DELAY_CACHED_MILLIS = 120_000;
// 紧急广播优先处理(负值表示提前)
public long DELAY_URGENT_MILLIS = -120_000;
8.4 最佳实践总结
- 优先使用显式广播 : 指定
ComponentName或Package - 避免隐式广播: Android 8.0+限制后台隐式广播
- 使用LocalBroadcast替代方案 :
LiveData、Flow、EventBus - 合理设置优先级: 不要滥用高优先级
- 及时取消注册: 避免内存泄漏
- 使用goAsync(): 处理耗时操作
- 权限保护敏感广播: 发送和接收都要设置权限
- 利用BroadcastOptions: 使用延迟策略和投递组策略
9. 广播安全设计
Android广播机制包含多层安全防护,从发送、传输到接收的全流程都有相应的安全检查机制。本章详细分析广播系统中的各项安全设计。
9.1 受保护广播(Protected Broadcast)
9.1.1 概述
受保护广播(Protected Broadcast)是Android系统用于保护敏感系统广播的机制。只有系统级进程(如system_server、Phone、Bluetooth等)才能发送受保护广播,普通应用尝试发送会抛出SecurityException。
9.1.2 在AndroidManifest.xml中声明
文件路径 : frameworks/base/core/res/AndroidManifest.xml
xml
<!-- 系统框架声明受保护广播 -->
<protected-broadcast android:name="android.intent.action.SCREEN_OFF" />
<protected-broadcast android:name="android.intent.action.SCREEN_ON" />
<protected-broadcast android:name="android.intent.action.USER_PRESENT" />
<protected-broadcast android:name="android.intent.action.TIME_SET" />
<protected-broadcast android:name="android.intent.action.TIME_TICK" />
<protected-broadcast android:name="android.intent.action.TIMEZONE_CHANGED" />
<protected-broadcast android:name="android.intent.action.BOOT_COMPLETED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_ADDED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_REMOVED" />
<protected-broadcast android:name="android.intent.action.BATTERY_CHANGED" />
<protected-broadcast android:name="android.intent.action.BATTERY_LOW" />
<protected-broadcast android:name="android.intent.action.ACTION_SHUTDOWN" />
<protected-broadcast android:name="android.intent.action.USER_ADDED" />
<protected-broadcast android:name="android.intent.action.USER_REMOVED" />
<!-- 更多受保护广播... -->
系统应用也可以在自己的AndroidManifest.xml中声明受保护广播:
xml
<!-- 系统应用(平台签名)可以声明自己的受保护广播 -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.systemservice">
<protected-broadcast android:name="com.android.systemservice.CUSTOM_ACTION" />
</manifest>
9.1.3 源码中的保护机制分析
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastController.java
java
// BroadcastController.java:992-1058 - 受保护广播安全检查
// 1. 首先检查广播action是否为受保护广播
final boolean isProtectedBroadcast;
try {
isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception", e);
return ActivityManager.BROADCAST_SUCCESS;
}
// 2. 判断调用者是否为系统级进程
final boolean isCallerSystem;
switch (UserHandle.getAppId(callingUid)) {
case ROOT_UID: // 0
case SYSTEM_UID: // 1000
case PHONE_UID: // 1001
case BLUETOOTH_UID: // 1002
case NFC_UID: // 1027
case SE_UID: // 1068
case NETWORK_STACK_UID: // 1073
isCallerSystem = true;
break;
default:
// 持久化系统应用也被视为系统调用者
isCallerSystem = (callerApp != null) && callerApp.isPersistent();
break;
}
// 3. 非系统应用发送受保护广播直接抛出SecurityException
if (!isCallerSystem) {
if (isProtectedBroadcast) {
String msg = "Permission Denial: not allowed to send broadcast "
+ action + " from pid=" + callingPid + ", uid=" + callingUid;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
}
9.1.4 常见受保护广播列表
| 广播Action | 用途 | 安全原因 |
|---|---|---|
ACTION_BOOT_COMPLETED |
系统启动完成 | 防止伪造启动事件 |
ACTION_SCREEN_ON/OFF |
屏幕状态变化 | 防止伪造屏幕事件 |
ACTION_BATTERY_CHANGED |
电池状态变化 | 防止伪造电池信息 |
ACTION_PACKAGE_ADDED/REMOVED |
应用安装/卸载 | 防止伪造应用事件 |
ACTION_USER_ADDED/REMOVED |
用户添加/删除 | 防止伪造用户事件 |
ACTION_TIME_SET |
时间设置 | 防止伪造时间变更 |
ACTION_SHUTDOWN |
系统关机 | 防止伪造关机事件 |
CONNECTIVITY_ACTION |
网络连接变化 | 防止伪造网络状态 |
9.2 权限保护机制
Android广播支持双向权限保护:发送方可以要求接收方具有特定权限,接收方也可以要求发送方具有特定权限。
9.2.1 发送广播时的权限要求
java
// 发送带权限要求的广播 - 只有具有该权限的接收者才能收到
context.sendBroadcast(intent, "com.example.RECEIVE_MY_BROADCAST");
// 发送带多个权限要求的广播
String[] permissions = {"android.permission.ACCESS_FINE_LOCATION",
"android.permission.ACCESS_COARSE_LOCATION"};
context.sendBroadcast(intent, permissions);
9.2.2 接收广播时的权限声明
动态注册时指定权限:
java
// 只有具有SEND_PERMISSION权限的发送者发出的广播才会被接收
IntentFilter filter = new IntentFilter("com.example.MY_ACTION");
context.registerReceiver(receiver, filter,
"com.example.SEND_PERMISSION", // 发送者需要的权限
null, // Handler
Context.RECEIVER_EXPORTED); // 导出标志
静态注册时指定权限:
xml
<!-- AndroidManifest.xml -->
<receiver android:name=".MyReceiver"
android:permission="com.example.SEND_PERMISSION"
android:exported="true">
<intent-filter>
<action android:name="com.example.MY_ACTION" />
</intent-filter>
</receiver>
9.2.3 双向权限保护机制
接收方
权限检查
发送方
sendBroadcast with permission
pass
fail
pass
fail
Sender App
Broadcast
发送方权限检查
接收方权限检查
拒绝投递
Receiver
拒绝投递
Receiver App
9.2.4 源码中的权限校验流程
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
java
// BroadcastSkipPolicy.java:391-416 - 检查发送者是否有权限发送给该接收者
// Check that the sender has permission to send to this receiver
if (filter.requiredPermission != null) {
int perm = checkComponentPermission(filter.requiredPermission,
r.callingPid, r.callingUid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
return "Permission Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid="
+ r.callingPid + ", uid=" + r.callingUid + ")"
+ " requires " + filter.requiredPermission
+ " due to registered receiver " + filter;
} else {
// 检查AppOps权限
final int opCode = AppOpsManager.permissionToOpCode(filter.requiredPermission);
if (opCode != AppOpsManager.OP_NONE
&& mService.getAppOpsManager().noteOpNoThrow(opCode, r.callingUid,
r.callerPackage, r.callerFeatureId, "Broadcast sent to protected receiver")
!= AppOpsManager.MODE_ALLOWED) {
return "Appop Denial: broadcasting "
+ r.intent.toString()
+ " requires appop " + AppOpsManager.permissionToOp(
filter.requiredPermission);
}
}
}
java
// BroadcastSkipPolicy.java:453-513 - 检查接收者是否有发送方要求的权限
// Check that the receiver has the required permission(s) to receive this broadcast.
if (r.requiredPermissions != null && r.requiredPermissions.length > 0) {
for (int i = 0; i < r.requiredPermissions.length; i++) {
String requiredPermission = r.requiredPermissions[i];
final int perm = checkComponentPermission(
requiredPermission,
filter.receiverList.pid,
filter.receiverList.uid,
-1 /* owningUid */,
true /* exported */);
if (perm != PackageManager.PERMISSION_GRANTED) {
return "Permission Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " requires " + requiredPermission
+ " due to sender " + r.callerPackage;
}
// 检查AppOps
int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
&& mService.getAppOpsManager().noteOpNoThrow(appOp,
filter.receiverList.uid, filter.packageName, filter.featureId,
"Broadcast delivered to registered receiver")
!= AppOpsManager.MODE_ALLOWED) {
return "Appop Denial: receiving "
+ r.intent.toString()
+ " requires appop " + AppOpsManager.permissionToOp(requiredPermission);
}
}
}
9.2.5 权限保护对比表
| 保护方向 | API方法 | 效果 |
|---|---|---|
| 发送方保护接收方 | sendBroadcast(intent, permission) |
只有具有指定权限的接收者才能收到 |
| 接收方保护自己 | registerReceiver(..., permission, ...) |
只接收具有指定权限的发送者的广播 |
| 静态声明接收权限 | android:permission |
静态注册的接收器要求发送者权限 |
| 排除特定权限 | excludedPermissions |
排除具有特定权限的接收者 |
9.3 包可见性和导出控制
9.3.1 android:exported属性
从Android 12(API 31)开始,所有包含Intent Filter的组件必须显式声明exported属性。
静态注册:
xml
<!-- 允许其他应用发送广播给此接收器 -->
<receiver android:name=".PublicReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.example.PUBLIC_ACTION" />
</intent-filter>
</receiver>
<!-- 仅接收同一应用内部广播 -->
<receiver android:name=".PrivateReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.example.PRIVATE_ACTION" />
</intent-filter>
</receiver>
9.3.2 RECEIVER_EXPORTED和RECEIVER_NOT_EXPORTED标志
文件路径 : frameworks/base/core/java/android/content/Context.java
java
// Context.java:769-783 - 动态注册的导出标志
/**
* Flag for registerReceiver: The receiver can receive broadcasts from other Apps.
* Has the same behavior as marking a statically registered receiver with "exported=true"
*/
public static final int RECEIVER_EXPORTED = 0x2;
/**
* Flag for registerReceiver: The receiver cannot receive broadcasts from other Apps.
* Has the same behavior as marking a statically registered receiver with "exported=false"
*/
public static final int RECEIVER_NOT_EXPORTED = 0x4;
动态注册示例:
java
// Android 14+必须显式指定导出状态
IntentFilter filter = new IntentFilter("com.example.MY_ACTION");
// 允许接收其他应用的广播
context.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
// 仅接收同应用广播
context.registerReceiver(receiver, filter, Context.RECEIVER_NOT_EXPORTED);
// 同时指定会抛出异常
// context.registerReceiver(receiver, filter,
// Context.RECEIVER_EXPORTED | Context.RECEIVER_NOT_EXPORTED); // IllegalArgumentException!
9.3.3 导出检查机制源码
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastController.java
java
// BroadcastController.java:136-144 - 强制要求显式导出声明
/**
* It is now required for apps to explicitly set either
* {@link android.content.Context#RECEIVER_EXPORTED} or
* {@link android.content.Context#RECEIVER_NOT_EXPORTED} when registering a receiver for an
* unprotected broadcast in code.
*/
@ChangeId
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
private static final long DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED = 161145287L;
java
// BroadcastController.java:437-454 - 导出状态检查
if (!onlyProtectedBroadcasts) {
if (receiver == null && !explicitExportStateDefined) {
// sticky broadcast, no flag specified (flag isn't required)
flags |= Context.RECEIVER_EXPORTED;
} else if (requireExplicitFlagForDynamicReceivers && !explicitExportStateDefined) {
throw new SecurityException(
callerPackage + ": One of RECEIVER_EXPORTED or "
+ "RECEIVER_NOT_EXPORTED should be specified when a receiver "
+ "isn't being registered exclusively for system broadcasts");
} else if (!requireExplicitFlagForDynamicReceivers && (
(flags & Context.RECEIVER_NOT_EXPORTED) == 0)) {
// Change is not enabled, assume exported unless otherwise specified.
flags |= Context.RECEIVER_EXPORTED;
}
}
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
java
// BroadcastSkipPolicy.java:601-615 - 投递时的导出检查
// Ensure that broadcasts are only sent to other apps if they are explicitly marked as
// exported, or are System level broadcasts
final int originalCallingUid = r.sticky ? r.originalStickyCallingUid : r.callingUid;
if (!filter.exported && checkComponentPermission(null, r.callingPid,
originalCallingUid, filter.receiverList.uid, filter.exported)
!= PackageManager.PERMISSION_GRANTED) {
return "Exported Denial: sending "
+ r.intent.toString()
+ ", action: " + r.intent.getAction()
+ " from " + r.callerPackage
+ " (uid=" + originalCallingUid + ")"
+ " due to receiver " + filter.receiverList.app
+ " (uid " + filter.receiverList.uid + ")"
+ " not specifying RECEIVER_EXPORTED";
}
9.3.4 隐式广播限制(Android 8.0+)
从Android 8.0开始,后台应用无法通过Manifest静态注册接收大多数隐式广播。
java
// BroadcastSkipPolicy.java:351-358 - 后台启动限制检查
public boolean disallowBackgroundStart(@NonNull BroadcastRecord r) {
return ((r.intent.getFlags() & Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
|| (r.intent.getComponent() == null
&& r.intent.getPackage() == null
&& ((r.intent.getFlags()
& Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0)
&& !isSignaturePerm(r.requiredPermissions));
}
白名单豁免的系统广播:
文件路径 : frameworks/base/services/core/java/com/android/server/SystemConfig.java
java
// SystemConfig.java:1143-1152 - 允许隐式广播配置
case "allow-implicit-broadcast": {
if (allowImplicitBroadcasts) {
String action = parser.getAttributeValue(null, "action");
if (action == null) {
Slog.w(TAG, "<" + name + "> without action in "
+ permFile + " at " + parser.getPositionDescription());
} else {
mAllowImplicitBroadcasts.add(action);
}
}
XmlUtils.skipCurrentTag(parser);
} break;
9.4 后台广播限制
9.4.1 Android 8.0+后台应用的广播接收限制
从Android 8.0开始,系统对后台应用接收广播施加了严格限制:
- 隐式广播限制: 后台应用无法通过Manifest接收大多数隐式广播
- 动态注册不受限 : 通过
registerReceiver()动态注册的接收器不受此限制 - 显式广播不受限: 指定了Component或Package的显式广播不受限制
java
// BroadcastSkipPolicy.java:212-231 - 后台启动模式检查
final int allowed = mService.getAppStartModeLOSP(
info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
// We won't allow this receiver to be launched if the app has been
// completely disabled from launches, or it was not explicitly sent
// to it and the app is in a state that should not receive it
if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
return "Background execution disabled: receiving "
+ r.intent + " to "
+ component.flattenToShortString();
} else if (disallowBackgroundStart(r)) {
mService.addBackgroundCheckViolationLocked(r.intent.getAction(),
component.getPackageName());
return "Background execution not allowed: receiving "
+ r.intent + " to "
+ component.flattenToShortString();
}
}
9.4.2 白名单豁免的系统广播
以下是部分允许后台应用接收的隐式广播(定义在/data/system/etc/sysconfig/目录下的xml文件中):
| 广播Action | 豁免原因 |
|---|---|
ACTION_BOOT_COMPLETED |
应用初始化需要 |
ACTION_LOCALE_CHANGED |
语言变化需要响应 |
ACTION_USB_ACCESSORY_ATTACHED |
USB设备交互 |
ACTION_CONNECTION_STATE_CHANGED |
蓝牙连接状态 |
ACTION_PHONE_STATE_CHANGED |
电话状态变化 |
9.4.3 BroadcastOptions安全考虑
文件路径 : frameworks/base/core/java/android/app/BroadcastOptions.java
java
// BroadcastOptions使用示例 - 控制后台活动启动权限
BroadcastOptions options = BroadcastOptions.makeBasic();
// 允许接收者启动后台Activity(需要特殊权限)
// 只有系统应用才能设置此选项
options.setBackgroundActivityStartsAllowed(true);
// 设置临时白名单,允许接收者短暂在前台运行
options.setTemporaryAppAllowlist(duration,
TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
REASON_SHELL, "");
权限检查:
java
// BroadcastController.java:964-983 - BroadcastOptions权限检查
if (brOptions != null && brOptions.allowsBackgroundActivityStarts()) {
// See if the caller is allowed to do this.
if (checkComponentPermission(
android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
realCallingPid, realCallingUid, -1, true)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: " + intent.getAction()
+ " broadcast from " + callerPackage + " (pid=" + callingPid
+ ", uid=" + callingUid + ")"
+ " requires "
+ android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
}
9.5 粘性广播的安全问题
9.5.1 Sticky Broadcast已废弃的原因
粘性广播(sendStickyBroadcast())已在Android 5.0(API 21)被标记为废弃,主要安全隐患包括:
- 信息泄露: 粘性广播会被缓存,任何后续注册的接收器都能获取最后一次发送的内容
- 权限绕过: 无法对粘性广播设置接收权限
- 数据篡改: 恶意应用可以发送相同Action的粘性广播覆盖系统广播
- 资源占用: 粘性广播会一直占用系统内存直到被移除
9.5.2 源码中的限制
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastController.java
java
// BroadcastController.java:1376-1402 - 粘性广播的安全限制
if (sticky) {
// 1. 需要BROADCAST_STICKY权限
if (mService.checkPermission(android.Manifest.permission.BROADCAST_STICKY,
callingPid, callingUid)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast"
+ " requires " + android.Manifest.permission.BROADCAST_STICKY;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
// 2. 粘性广播不能附带权限要求
if (requiredPermissions != null && requiredPermissions.length > 0) {
Slog.w(TAG, "Can't broadcast sticky intent " + intent
+ " and enforce permissions " + Arrays.toString(requiredPermissions));
return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
}
// 3. 粘性广播不能指定目标组件
if (intent.getComponent() != null) {
throw new SecurityException(
"Sticky broadcasts can't target a specific component");
}
}
9.5.3 替代方案推荐
| 原用途 | 推荐替代方案 |
|---|---|
| 缓存最新状态 | LiveData / StateFlow |
| 进程间状态共享 | ContentProvider |
| 系统状态查询 | 直接调用系统API(如BatteryManager) |
| 事件通知 | 普通广播 + 启动时主动查询 |
9.6 跨用户广播的安全隔离
9.6.1 sendBroadcastAsUser的权限要求
文件路径 : frameworks/base/core/java/android/app/ContextImpl.java
java
// 跨用户发送广播需要特殊权限
context.sendBroadcastAsUser(intent, UserHandle.ALL); // 发送给所有用户
context.sendBroadcastAsUser(intent, new UserHandle(userId)); // 发送给指定用户
所需权限:
INTERACT_ACROSS_USERS: 基本跨用户交互权限INTERACT_ACROSS_USERS_FULL: 完全跨用户交互权限
9.6.2 多用户场景下的广播隔离机制
java
// BroadcastController.java:913-929 - 用户隔离检查
userId = mService.mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
ALLOW_NON_FULL, "broadcast", callerPackage);
// Make sure that the user who is receiving this broadcast or its parent is running.
if (userId != UserHandle.USER_ALL && !mService.mUserController.isUserOrItsParentRunning(
userId)) {
if ((callingUid != SYSTEM_UID
|| (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
&& !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
Slog.w(TAG, "Skipping broadcast of " + intent
+ ": user " + userId + " and its parent (if any) are stopped");
return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
}
}
9.6.3 USER_ALL的使用限制
java
// 只有系统进程可以使用USER_ALL发送广播
if (userId == UserHandle.USER_ALL && broadcastAllowList != null) {
Slog.e(TAG, "broadcastAllowList only applies when sending to individual users. "
+ "Assuming restrictive whitelist.");
broadcastAllowList = new int[]{};
}
9.6.4 Work Profile的广播隔离
java
// BroadcastSkipPolicy.java:150-159 - FLAG_SINGLE_USER检查
if ((info.activityInfo.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) {
if (ActivityManager.checkUidPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS,
info.activityInfo.applicationInfo.uid)
!= PackageManager.PERMISSION_GRANTED) {
return "Permission Denial: Receiver " + component.flattenToShortString()
+ " requests FLAG_SINGLE_USER, but app does not hold "
+ android.Manifest.permission.INTERACT_ACROSS_USERS;
}
}
9.7 Intent安全设计
9.7.1 显式Intent vs 隐式Intent的安全差异
| 特性 | 显式Intent | 隐式Intent |
|---|---|---|
| 目标确定性 | 明确指定组件 | 系统解析匹配 |
| 安全风险 | 低 | 可能被劫持 |
| Android 8.0+后台限制 | 不受限 | Manifest接收器受限 |
| 建议使用场景 | 敏感广播 | 系统广播、公开API |
9.7.2 Component指定防止Intent劫持
java
// 安全发送: 指定目标组件
Intent intent = new Intent("com.example.SENSITIVE_ACTION");
intent.setComponent(new ComponentName("com.example.targetapp",
"com.example.targetapp.MyReceiver"));
context.sendBroadcast(intent);
// 或者指定目标包名
intent.setPackage("com.example.targetapp");
context.sendBroadcast(intent);
9.7.3 Intent Flags的安全使用
文件路径 : frameworks/base/core/java/android/content/Intent.java
| Flag | 值 | 用途 |
|---|---|---|
FLAG_RECEIVER_REGISTERED_ONLY |
0x40000000 | 只发送给动态注册的接收器 |
FLAG_RECEIVER_REPLACE_PENDING |
0x20000000 | 替换队列中相同的广播 |
FLAG_RECEIVER_FOREGROUND |
0x10000000 | 以前台优先级发送 |
FLAG_RECEIVER_NO_ABORT |
0x08000000 | 有序广播不可中止 |
FLAG_RECEIVER_INCLUDE_BACKGROUND |
0x01000000 | 包含后台应用(系统使用) |
FLAG_RECEIVER_EXCLUDE_BACKGROUND |
0x00800000 | 排除后台应用 |
FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS |
0x00200000 | 对即时应用可见 |
java
// 安全使用示例
Intent intent = new Intent("com.example.ACTION");
// 只发送给已运行的动态注册接收器
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
// 有序广播不可被中止
intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
context.sendOrderedBroadcast(intent, null);
9.7.4 防止Intent数据注入攻击
java
// 验证Intent数据
@Override
public void onReceive(Context context, Intent intent) {
// 1. 验证Action
if (!"com.example.EXPECTED_ACTION".equals(intent.getAction())) {
return;
}
// 2. 验证数据类型和范围
String data = intent.getStringExtra("key");
if (data == null || data.length() > MAX_LENGTH) {
return;
}
// 3. 验证URI来源
Uri uri = intent.getData();
if (uri != null && !"content".equals(uri.getScheme())) {
return;
}
// 4. 避免直接使用Intent中的ComponentName启动组件
// 恶意应用可能注入恶意组件名
}
9.8 系统级广播的安全机制
9.8.1 系统进程发送广播的特权
系统进程(UID 0-1999)发送广播时享有以下特权:
- 可以发送受保护广播
- 可以使用
FLAG_RECEIVER_FROM_SHELL - 可以设置
BroadcastOptions中的特殊选项 - 不受后台限制影响
9.8.2 UID校验机制
java
// BroadcastController.java:1004-1018 - 系统UID识别
final boolean isCallerSystem;
switch (UserHandle.getAppId(callingUid)) {
case ROOT_UID: // 0 - root
case SYSTEM_UID: // 1000 - system
case PHONE_UID: // 1001 - phone/radio
case BLUETOOTH_UID: // 1002 - bluetooth
case NFC_UID: // 1027 - nfc
case SE_UID: // 1068 - secure element
case NETWORK_STACK_UID: // 1073 - network stack
isCallerSystem = true;
break;
default:
// 持久化应用也被视为系统
isCallerSystem = (callerApp != null) && callerApp.isPersistent();
break;
}
9.8.3 Signature级别权限的使用
xml
<!-- 定义平台签名权限 -->
<permission android:name="com.example.PLATFORM_PERMISSION"
android:protectionLevel="signature" />
<!-- 只有平台签名应用才能发送此广播 -->
<receiver android:name=".SecureReceiver"
android:permission="com.example.PLATFORM_PERMISSION"
android:exported="true">
<intent-filter>
<action android:name="com.example.SECURE_ACTION" />
</intent-filter>
</receiver>
9.8.4 checkBroadcastFromSystem检查
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastController.java
java
// BroadcastController.java:2018-2096 - 系统广播合规性检查
private void checkBroadcastFromSystem(Intent intent, ProcessRecord callerApp,
String callerPackage, int callingUid, boolean isProtectedBroadcast, List receivers) {
// 跳过shell发送的广播
if ((intent.getFlags() & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {
return;
}
final String action = intent.getAction();
// 已知安全的系统广播直接放行
if (isProtectedBroadcast
|| Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
|| Intent.ACTION_MEDIA_BUTTON.equals(action)
// ... 其他白名单action
) {
return;
}
// 显式广播检查目标是否受保护
if (intent.getPackage() != null || intent.getComponent() != null) {
boolean allProtected = true;
for (Object target : receivers) {
if (target instanceof ResolveInfo) {
ResolveInfo ri = (ResolveInfo) target;
if (ri.activityInfo.exported && ri.activityInfo.permission == null) {
allProtected = false;
break;
}
}
// ...
}
if (allProtected) {
return;
}
}
// 记录非保护广播的发送(用于审计)
Log.wtf(TAG, "Sending non-protected broadcast " + action
+ " from system " + callerApp.toShortString());
}
9.9 广播队列的安全考虑
9.9.1 防止广播队列溢出攻击
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastController.java
java
// BroadcastController.java:146-147 - 每个应用的接收器数量限制
// Maximum number of receivers an app can register.
private static final int MAX_RECEIVERS_ALLOWED_PER_APP = 1000;
java
// BroadcastController.java:521-526 - 接收器数量检查
if (rl.app != null) {
final int totalReceiversForApp = rl.app.mReceivers.numberOfReceivers();
if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {
throw new IllegalStateException("Too many receivers, total of "
+ totalReceiversForApp + ", registered for pid: "
+ rl.pid + ", callerPackage: " + callerPackage);
}
}
9.9.2 冻结进程的广播限制
文件路径 : frameworks/base/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
java
// BroadcastQueueModernImpl.java:782-795 - 冻结进程的广播限制
if (Flags.deferOutgoingBroadcasts() && isProcessFreezable(r.callerApp)) {
final BroadcastProcessQueue queue = getOrCreateProcessQueue(
r.callerApp.processName, r.callerApp.uid);
// 限制冻结进程的待发广播数量
if (queue.getOutgoingBroadcastCount() >= mConstants.MAX_FROZEN_OUTGOING_BROADCASTS) {
r.callerApp.killLocked("Too many outgoing broadcasts in cached state",
ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_TOO_MANY_CACHED_BCAST,
true);
return;
}
queue.enqueueOutgoingBroadcast(r);
return;
}
9.9.3 恶意广播的检测和丢弃
java
// BroadcastSkipPolicy中的多层检查
// 1. IntentFirewall检查
if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid)) {
return "Firewall blocked: broadcasting " + broadcastDescription(r, component);
}
// 2. Association检查
if (!mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
component.getPackageName(), info.activityInfo.applicationInfo.uid)) {
return "Association not allowed: broadcasting " + broadcastDescription(r, component);
}
// 3. 包可用性检查
boolean isAvailable = AppGlobals.getPackageManager().isPackageAvailable(
info.activityInfo.packageName,
UserHandle.getUserId(info.activityInfo.applicationInfo.uid));
if (!isAvailable) {
return "Skipping delivery: package no longer available";
}
9.10 源码安全检查点总结
9.10.1 关键安全检查点位置
| 检查点 | 源码位置 | 检查内容 |
|---|---|---|
| 受保护广播检查 | BroadcastController.broadcastIntentLockedTraced() |
只有系统进程可发送 |
| 权限检查 | BroadcastSkipPolicy.shouldSkipMessage() |
双向权限验证 |
| 导出检查 | BroadcastSkipPolicy.shouldSkipMessage() |
exported属性验证 |
| 用户隔离 | BroadcastController.broadcastIntentLockedTraced() |
跨用户权限检查 |
| 后台限制 | BroadcastSkipPolicy.disallowBackgroundStart() |
后台应用限制 |
| IntentFirewall | BroadcastSkipPolicy.shouldSkipMessage() |
防火墙规则检查 |
| 接收器数量限制 | BroadcastController.registerReceiverWithFeatureTraced() |
防止DoS攻击 |
9.10.2 安全检查流程图
Invalid
Valid
Yes
No
Yes
No
Permission Denied
OK
Permission Denied
Firewall Blocked
Not Exported
Background Blocked
Pass
Done
sendBroadcast
verifyBroadcastLocked
Exception
isProtectedBroadcast?
isCallerSystem?
SecurityException
Continue
Check BroadcastOptions
SecurityException
Collect Receivers
For Each Receiver
shouldSkipMessage?
Skip Receiver
Deliver Broadcast
Broadcast Complete
9.11 安全最佳实践
9.11.1 发送广播时的安全准则
java
// 1. 使用显式Intent发送敏感广播
Intent intent = new Intent("com.example.SENSITIVE_ACTION");
intent.setPackage("com.example.targetapp"); // 限定包名
context.sendBroadcast(intent);
// 2. 指定接收者需要的权限
context.sendBroadcast(intent, "com.example.RECEIVE_PERMISSION");
// 3. 对于有序广播,使用NO_ABORT防止中断
intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
context.sendOrderedBroadcast(intent, null);
// 4. 敏感数据不要放在广播中传输
// 错误: intent.putExtra("password", userPassword);
// 正确: 使用其他安全IPC机制
9.11.2 接收广播时的安全准则
java
// 1. 显式声明导出状态
context.registerReceiver(receiver, filter, Context.RECEIVER_NOT_EXPORTED);
// 2. 设置发送者权限要求
context.registerReceiver(receiver, filter,
"com.example.SEND_PERMISSION", null, Context.RECEIVER_EXPORTED);
// 3. 在onReceive中验证发送者
@Override
public void onReceive(Context context, Intent intent) {
// 获取发送者信息(Android 13+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
String senderPackage = getSenderPackage();
int senderUid = getSenderUid();
// 验证发送者身份
}
// 验证Intent数据
validateIntentData(intent);
}
// 4. 及时取消注册,避免泄露
@Override
protected void onDestroy() {
context.unregisterReceiver(receiver);
super.onDestroy();
}
9.11.3 权限配置的最佳实践
| 场景 | 推荐做法 |
|---|---|
| 应用内部广播 | RECEIVER_NOT_EXPORTED + 显式Intent |
| 与特定应用通信 | setPackage() + 自定义signature权限 |
| 公开API广播 | RECEIVER_EXPORTED + 权限保护 |
| 接收系统广播 | 按需注册,避免Manifest静态注册 |
| 敏感数据传输 | 避免广播,使用ContentProvider或Binder |
9.11.4 安全审计要点
-
检查Manifest中的receiver声明:
- 是否有不必要的
exported="true" - 是否缺少权限保护
- 是否有不必要的
-
检查动态注册:
- 是否显式指定了
RECEIVER_EXPORTED/NOT_EXPORTED - 是否在适当时机取消注册
- 是否显式指定了
-
检查广播发送:
- 敏感广播是否使用显式Intent
- 是否正确设置权限要求
-
检查onReceive实现:
- 是否验证Intent数据
- 是否有信息泄露风险
- 是否在主线程执行耗时操作
附录: 核心源码文件索引
| 类名 | 文件路径 | 描述 |
|---|---|---|
| BroadcastQueue | frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java |
广播队列抽象基类 |
| BroadcastQueueModernImpl | frameworks/base/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java |
现代广播队列实现 |
| BroadcastRecord | frameworks/base/services/core/java/com/android/server/am/BroadcastRecord.java |
广播记录 |
| BroadcastFilter | frameworks/base/services/core/java/com/android/server/am/BroadcastFilter.java |
动态注册过滤器 |
| BroadcastProcessQueue | frameworks/base/services/core/java/com/android/server/am/BroadcastProcessQueue.java |
进程广播队列 |
| BroadcastConstants | frameworks/base/services/core/java/com/android/server/am/BroadcastConstants.java |
广播常量配置 |
| BroadcastController | frameworks/base/services/core/java/com/android/server/am/BroadcastController.java |
广播控制器 |
| BroadcastSkipPolicy | frameworks/base/services/core/java/com/android/server/am/BroadcastSkipPolicy.java |
广播跳过策略 |
| ReceiverList | frameworks/base/services/core/java/com/android/server/am/ReceiverList.java |
接收者列表 |
| BroadcastReceiver | frameworks/base/core/java/android/content/BroadcastReceiver.java |
广播接收器基类 |
| BroadcastOptions | frameworks/base/core/java/android/app/BroadcastOptions.java |
广播选项 |
| ContextImpl | frameworks/base/core/java/android/app/ContextImpl.java |
Context实现类 |
| ActivityManagerService | frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java |
AMS服务 |
| Intent | frameworks/base/core/java/android/content/Intent.java |
Intent类(包含FLAG定义) |
| Context | frameworks/base/core/java/android/content/Context.java |
Context类(包含RECEIVER_*标志) |
| IntentFirewall | frameworks/base/services/core/java/com/android/server/firewall/IntentFirewall.java |
Intent防火墙 |
| SystemConfig | frameworks/base/services/core/java/com/android/server/SystemConfig.java |
系统配置(隐式广播白名单) |
参考资料
- Android Source Code: https://android.googlesource.com/
- Android Developer Documentation: https://developer.android.com/guide/components/broadcasts
- AOSP Architecture: https://source.android.com/docs/core/architecture
- Android Security Best Practices: https://developer.android.com/topic/security/best-practices
致敬前辈,砥砺前行!