摘要
1.发送广播(App喊话)
App喊话:你的App调用ContextImpl.sendBroadcast(),就像对着全校喊:“注意!有消息!”。
交给校长(AMS):消息通过Binder(类似对讲机)传给系统服务ActivityManagerService(AMS),校长负责管理全校广播。
2. 广播排队(校长整理消息)
分类处理:AMS检查广播类型(普通/有序)和权限,把广播塞进队列(BroadcastQueue)。
冷启动 vs 热启动:
冷启动:如果接收App没运行,校长先叫醒它(通过Zygote fork新进程,类似开学点名)。
热启动:如果App已经在后台,直接发消息。
3. 派送广播(班长传话)
找班长(ActivityThread):系统找到目标App的“班长”(主线程),让它通知具体的“同学”(BroadcastReceiver)。
主线程处理:班长通过ReceiverDispatcher把广播包装成Runnable,扔到主线程的“作业本”(消息队列)里,避免卡顿。
4. 接收广播(同学听讲)
执行onReceive():主线程执行BroadcastReceiver.onReceive(),就像同学听到广播后做作业。但作业不能拖堂(超过10秒会ANR)。
收尾:处理完通知校长(AMS),如果是有序广播还会告诉下一个同学
广播发送的架构图

阶段 |
步骤描述 |
关键方法/组件 |
冷/热启动区别 |
| 1. 广播发送 |
应用调用sendBroadcast()发起广播 |
ContextImpl.sendBroadcast()→AMS.broadcastIntentWithFeature() |
无区别 |
| 2. AMS处理广播 |
AMS验证广播合法性并分发给队列 |
AMS.broadcastIntentLocked()→BroadcastQueue.enqueueBroadcastLocked() |
无区别 |
| 3. 队列调度 |
广播队列根据接收进程状态选择冷启动或热启动路径 |
BroadcastQueueModernImpl.updateRunningListLocked() |
冷启动:进程不存在 → 触发进程创建 热启动:进程存在 → 直接分发 |
| 4. 进程启动(冷启动) |
通过Zygote fork新进程,并等待应用初始化完成 |
ProcessList.startProcessLocked()→ZygoteProcess.start() |
仅冷启动触发 |
| 5. 接收器绑定(冷启动) |
进程启动后,AMS重新将广播绑定到新进程的接收器 |
BroadcastQueueModernImpl.onApplicationAttachedLocked() |
仅冷启动触发 |
| 6. 广播分发(热启动) |
直接通过Binder调用将广播分发给已注册的接收器 |
ActivityThread.scheduleRegisteredReceiver() |
仅热启动触发 |
| 7. 主线程切换 |
接收器通过主线程Handler执行onReceive() |
LoadedApk.ReceiverDispatcher.Args.getRunnable() |
无区别(均需切换主线程) |
| 8. 结果回调 |
若为有序广播,接收器处理完成后通知AMS继续传递或终止广播 |
ActivityManagerService.finishReceiver() |
无区别 |
广播发送到接收的堆栈和时序图
ContextImpl. sendBroadcast(Intent intent)->ActivityManagerService.broadcastIntentWithFeature()→ActivityManagerService.broadcastIntentWithFeature()->ActivityManagerService.broadcastIntentLocked()→→ActivityManagerService.broadcastIntentLocked()->ActivityManagerService.broadcastIntentLockedTraced()→→→ActivityManagerService.broadcastIntentLockedTraced()->BroadcastQueue.enqueueBroadcastLocked()→→→→BroadcastQueue.enqueueBroadcastLocked()->BroadcastQueueModernImpl.enqueueBroadcastLocked()→→→→→BroadcastQueueModernImpl.enqueueBroadcastLocked()->BroadcastQueueModernImpl.updateRunningListLocked()→→→→→→BroadcastQueueModernImpl.scheduleReceiverColdLocked()->BroadcastQueueModernImpl.scheduleReceiverColdLocked() 冷启动后发广播→→→→→→→BroadcastQueueModernImpl.scheduleReceiverColdLocked()->ActivityManagerService.startProcessLocked()→→→→→→→→ActivityManagerService.startProcessLocked()->ProcessList.startProcessLocked()→→→→→→→→→ProcessList.startProcessLocked()->ZygoteProcess.start()// 最终通过Zygote fork进程→→→→→→→→→→ZygoteProcess.start()->BroadcastQueueModernImpl.onApplicationAttachedLocked()->BroadcastQueueModernImpl.updateRunningListLocked() 后面的流程和热启动发送广播一样了→→→→→BroadcastQueueModernImpl.updateRunningListLocked()->BroadcastQueueModernImpl.scheduleReceiverWarmLocked() 直接热启动发广播→→→→→→BroadcastQueueModernImpl.scheduleReceiverWarmLocked()->BroadcastQueueModernImpl.dispatchReceivers()→→→→→→→BroadcastQueueModernImpl.dispatchReceivers()->ActivityThread.scheduleRegisteredReceiver→→→→→→→→ActivityThread.scheduleRegisteredReceiver->LoadedApk.ReceiverDispatcher.InnerReceiver.performReceive()→→→→→→→→→LoadedApk.ReceiverDispatcher.InnerReceiver.performReceive()->LoadedApk.ReceiverDispatcher.Args.getRunnable()→→→→→→→→→→LoadedApk.ReceiverDispatcher.Args.getRunnable()->BroadcastReceiver.onReceive(mContext, intent):App就收到广播了哈

源码走读
一、调用ContextImpl.sendBroadcast发送广播
@Overridepublic void sendBroadcast(Intent intent) {// 1. 系统进程调用警告:防止系统进程误用普通API,Android框架的内部保护机制,防止系统进程错误使用普通API导致权限逃逸warnIfCallingFromSystemProcess();// 2. 解析Intent的MIME类型(如content:// URI对应的类型)String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());try {// 3. 准备跨进程传输:清理Intent中可能包含的进程内对象(如Parcelable),会清理Intent中不可序列化的对象,确保其能通过Binder传输。这是Android IPC的核心安全措施intent.prepareToLeaveProcess(this);// 4. 通过Binder调用AMS(ActivityManagerService)的广播发送接口ActivityManager.getService().broadcastIntentWithFeature(mMainThread.getApplicationThread(), // 调用方线程标识getAttributionTag(), // 调用方归属标签(用于权限追踪)intent, // 要发送的广播IntentresolvedType, // 已解析的MIME类型null, // 接收权限要求(null表示无限制)Activity.RESULT_OK, // 默认结果码null, // 结果数据(BroadcastResult)null, // 结果扩展数据null, // 排除的组件列表null /*excludedPermissions=*/, // 排除的权限列表null, // 广播选项(如延迟发送)AppOpsManager.OP_NONE, // 关联的AppOps操作null, // 目标用户ID(null表示当前用户)false, // 是否后台广播false, // 是否粘性广播getUserId()); // 发送方用户ID} catch (RemoteException e) {// 5. 处理系统服务通信异常(AMS运行在system_server进程)throw e.rethrowFromSystemServer();}}
二、调用AMS的broadcastIntentWithFeature方法:
核心逻辑:调用broadcastIntentLocked完成广播分发
@Overridepublic final int broadcastIntentWithFeature(IApplicationThread caller, // 调用方应用线程(Binder代理对象)String callingFeatureId, // 调用方特性标识(如Instant App ID)Intent intent, // 待发送的广播IntentString resolvedType, // Intent的MIME类型(已解析)IIntentReceiver resultTo, // 结果接收器(有序广播时使用)int resultCode, // 结果码String resultData, // 结果数据Bundle resultExtras, // 结果附加数据String[] requiredPermissions, // 接收方需具备的权限String[] excludedPermissions, // 排除的权限String[] excludedPackages, // 排除的包名int appOp, // 关联的AppOps操作Bundle bOptions, // 广播选项(如延迟、白名单等)boolean serialized, // 是否串行发送boolean sticky, // 是否粘性广播int userId) { // 目标用户ID// 1. 隔离进程检查:禁止isolated进程发送广播enforceNotIsolatedCaller("broadcastIntent");synchronized(this) {// 2. 校验Intent合法性(如action非空、组件权限等)intent = verifyBroadcastLocked(intent);// 3. 获取调用方进程信息final ProcessRecord callerApp = getRecordForAppLOSP(caller);final int callingPid = Binder.getCallingPid();final int callingUid = Binder.getCallingUid();// 4. 结果接收方默认为调用方进程(有序广播场景)final ProcessRecord resultToApp = callerApp;// 5. 检查广播选项权限(如后台启动白名单等)enforceBroadcastOptionPermissionsInternal(bOptions, callingUid);// 6. 清除调用方身份标识(切换为系统身份执行后续操作)final long origId = Binder.clearCallingIdentity();/// MTK扩展逻辑:DuraSpeed机制可能抑制广播发送String suppressAction = mAmsExt.onReadyToStartComponent(callerApp != null ? callerApp.info.packageName : null,callingUid, "broadcast", null);if ((suppressAction != null) && suppressAction.equals("skipped")) {Binder.restoreCallingIdentity(origId);Slog.d(TAG, "broadcastIntentWithFeature, suppress to broadcastIntent!");return ActivityManager.BROADCAST_SUCCESS; // 直接返回成功(被抑制)}try {// 7. 核心逻辑:调用broadcastIntentLocked完成广播分发return broadcastIntentLocked(callerApp,callerApp != null ? callerApp.info.packageName : null,callingFeatureId,intent, resolvedType, resultToApp, resultTo, resultCode,resultData, resultExtras, requiredPermissions,excludedPermissions, excludedPackages, appOp, bOptions,serialized, sticky, callingPid, callingUid, callingUid,callingPid, userId,BackgroundStartPrivileges.NONE, null, null);} finally {// 8. 恢复调用方身份Binder.restoreCallingIdentity(origId);}}}
继续分析 broadcastIntentLocked 函数,该函数是广播分发的核心逻辑
三、调用AMS的broadcastIntentLocked方法:
1、找出符合条件的静态接收器和动态接收器
2、若是无序广播,将动态接收器打包成一条广播记录,先进入无序广播队列,并行分发广播
3、按优先级将静态和动态接收器合并到一个接收器队列
4、将3中得到的接收器队列打包成一条广播记录,进入有序广播队列,串行分发广播
/*** 广播发送核心逻辑,处理权限校验、接收者匹配、队列分发等** @param callerApp 调用方进程记录(ProcessRecord)* @param callerPackage 调用方包名(用于权限校验)* @param intent 广播Intent(包含Action和附加数据)* @param resolvedType Intent的MIME类型(通过ContentResolver解析)* @param resultToApp 结果接收方进程(有序广播时使用)* @param brOptions 广播选项(延迟、白名单等,BroadcastOptions类型)* @param ordered 是否有序广播(true则按优先级顺序分发)* @param sticky 是否粘性广播(true则存入mStickyBroadcasts)* @param callingUid 调用方UID(用于跨进程身份校验)* @param userId 目标用户ID(USER_ALL表示所有用户)* @param backgroundStartPrivileges 后台启动权限控制(Android 15+限制)* @return 广播状态码(如BROADCAST_SUCCESS)*/final int broadcastIntentLockedTraced(...) {// 1. SDK沙箱进程检查(限制敏感广播发送)if (Process.isSdkSandboxUid(realCallingUid)) { ... }// 2. 系统启动状态处理:未完成启动时限制广播范围if (!mProcessesReady) {intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); // 仅动态接收器}// 3. 特殊广播处理(包管理、时间变更等)switch (intent.getAction()) {case Intent.ACTION_PACKAGE_REMOVED:forceStopPackageLocked(...); // 强制停止卸载的包case Intent.ACTION_TIME_CHANGED:mHandler.sendEmptyMessage(UPDATE_TIME_ZONE); // 异步更新时区}// 4. 粘性广播存储if (sticky) {synchronized (mStickyBroadcasts) {mStickyBroadcasts.put(userId, new Intent(intent)); // 按用户存储}}// 5. 接收者匹配:静态注册+动态注册List receivers = collectReceiverComponents(...); // 静态注册查询List<BroadcastFilter> registeredReceivers = mReceiverResolver.queryIntent(...); // 动态注册过滤// 6. 创建广播记录并加入队列BroadcastRecord r = new BroadcastRecord(...);mBroadcastQueue.enqueueBroadcastLocked(r); // 根据ordered选择并行或有序队列}
阶段 |
关键操作 |
涉及核心类/方法 |
| 1. 发送入口 |
Context.sendBroadcast()→ContextImpl.broadcastIntent() |
ContextWrapper→ContextImpl |
| 2. 跨进程通信 |
通过Binder调用AMS的broadcastIntentWithFeature() |
ActivityManagerService |
| 3. 权限与校验 |
- 检查调用方UID权限 - 验证Intent合法性(如非空Action) |
verifyBroadcastLocked() enforceBroadcastOptionPermissions() |
| 4. 接收者匹配 |
- 静态注册:PackageManagerService查询 - 动态注册:mReceiverResolver |
collectReceiverComponents() IntentResolver |
| 5. 队列分发 |
- 创建BroadcastRecord - 加入BroadcastQueue(前台/后台/离线队列) |
BroadcastQueue.enqueueBroadcastLocked() 接口定义 BroadcastQueueModernImpl.enqueueBroadcastLocked() 实现类 |
下一步:分析 enqueueBroadcastLocked() 的具体实现
四、调用BroadcastQueueModernImpl的enqueueBroadcastLocked方法
1、根据进程名和Uid找出或创建接收器进程记录(BroadcastProcessQueue)。
2、将接收器添加到接收器进程记录内的mPending、mPendingUrgent和mPendingOffload三个接收器队列中的一个
3、将接收器进程记录添加到进程队列(mRunnableHead),越早排队优先级越高
4、enqueueUpdateRunningList分发广播
/*** 将广播记录(BroadcastRecord)加入现代广播队列的核心逻辑** @param r 广播记录,包含Intent、接收者列表、发送方信息等** 关键流程:* 1. 对每个接收者,按进程分类管理(BroadcastProcessQueue)* 2. 根据策略决定接收者是否跳过(如静态接收者限制)* 3. 将接收者加入进程队列的优先级子队列(mPending/mPendingUrgent/mPendingOffload)* 4. 触发异步分发(enqueueUpdateRunningList)*/public void enqueueBroadcastLocked(@NonNull BroadcastRecord r) {// 调试日志:记录广播的发送方和接收者数量StringBuilder allReceivers = new StringBuilder();if (DEBUG_BROADCAST) {allReceivers.append(":").append(r.receivers);}logv("Enqueuing " + r + " from uid " + r.callingUid + " pid " + r.callingPid+ " for " + r.receivers.size() + " receivers" + allReceivers);final int cookie = traceBegin("enqueueBroadcast");// 应用单例广播策略(如系统广播的权限控制)r.applySingletonPolicy(mService);// 应用投递组策略(如后台广播的延迟处理)applyDeliveryGroupPolicy(r);// 记录入队时间(影响分发优先级,时间越早优先级越高)r.enqueueTime = SystemClock.uptimeMillis();r.enqueueRealTime = SystemClock.elapsedRealtime();r.enqueueClockTime = System.currentTimeMillis();mHistory.onBroadcastEnqueuedLocked(r); // 历史记录跟踪// 初始化被替换广播的缓存(用于FLAG_RECEIVER_REPLACE_PENDING逻辑)ArraySet<BroadcastRecord> replacedBroadcasts = mReplacedBroadcastsCache.getAndSet(null);if (replacedBroadcasts == null) {replacedBroadcasts = new ArraySet<>();}boolean enqueuedBroadcast = false;// 遍历所有接收者for (int i = 0; i < r.receivers.size(); i++) {final Object receiver = r.receivers.get(i);// 1. 获取或创建接收者所属进程的队列(BroadcastProcessQueue)final BroadcastProcessQueue queue = getOrCreateProcessQueue(getReceiverProcessName(receiver), // 进程名getReceiverUid(receiver) // UID);// 2. 检查接收者是否应跳过(如静态接收者只能接收显式广播)final String skipReason = mSkipPolicy.shouldSkipMessage(r, receiver);if (skipReason != null) {setDeliveryState(null, null, r, i, receiver, BroadcastRecord.DELIVERY_SKIPPED,"skipped by policy at enqueue: " + skipReason);continue; // 跳过无效接收者}enqueuedBroadcast = true;// 3. 将接收者加入进程队列的子队列(按优先级选择mPending/mPendingUrgent/mPendingOffload)final BroadcastRecord replacedBroadcast = queue.enqueueOrReplaceBroadcast(r, i, mBroadcastConsumerDeferApply);if (replacedBroadcast != null) {replacedBroadcasts.add(replacedBroadcast); // 记录被替换的旧广播}// 4. 更新可运行队列(mRunnableHead),越早加入优先级越高updateRunnableList(queue);// 5. 触发异步分发(通过Handler调度)enqueueUpdateRunningList();}// 清理被替换的广播(FLAG_RECEIVER_REPLACE_PENDING生效时)skipAndCancelReplacedBroadcasts(replacedBroadcasts);replacedBroadcasts.clear();mReplacedBroadcastsCache.compareAndSet(null, replacedBroadcasts);// 若广播无有效接收者,立即返回结果if (r.receivers.isEmpty() || !enqueuedBroadcast) {scheduleResultTo(r);notifyFinishBroadcast(r);}traceEnd(cookie);}
下一步:重点看下 触发异步分发 enqueueUpdateRunningList通过Handler调度到updateRunningListLocked函数
五、调用BroadcastQueueModernImpl的updateRunningListLocked方法
遍历mRunnableHead队列,接收器进程已启动则使用scheduleReceiverWarmLocked分发广播,否则使用scheduleReceiverColdLocked分发广播
/*** 更新"运行中"的进程队列列表,将符合条件的"可运行"队列提升为"运行中"状态** 核心逻辑:* 1. 遍历 mRunnableHead 队列,根据进程状态(冷启动/热启动)选择分发策略* 2. 热进程直接通过 scheduleReceiverWarmLocked 分发广播* 3. 冷进程通过 scheduleReceiverColdLocked 启动进程并分发** 限制条件:* - 最大并行运行队列数:MAX_RUNNING_PROCESS_QUEUES* - 同一时间仅允许一个冷启动进程(mRunningColdStart)*/@GuardedBy("mService")private void updateRunningListLocked() {// 计算可用运行槽位(考虑紧急广播的额外配额)final int usedExtra = Math.min(getRunningUrgentCount(),mConstants.EXTRA_RUNNING_URGENT_PROCESS_QUEUES);int avail = mRunning.length - getRunningSize() - usedExtra;if (avail == 0) return; // 无可用槽位时直接返回final int cookie = traceBegin("updateRunningList");final long now = SystemClock.uptimeMillis();// 检查是否有等待状态的队列(若有则忽略时间限制)final boolean waitingFor = !mWaitingFor.isEmpty();// 移除未处理的更新请求(避免重复调度)mLocalHandler.removeMessages(MSG_UPDATE_RUNNING_LIST);boolean updateOomAdj = false;BroadcastProcessQueue queue = mRunnableHead;while (queue != null && avail > 0) {BroadcastProcessQueue nextQueue = queue.runnableAtNext;final long runnableAt = queue.getRunnableAt();// 跳过非可运行状态的队列(如广播被跳过或失败)if (!queue.isRunnable()) {queue = nextQueue;continue;}// 若已达普通广播并行上限,仅处理紧急广播队列if (getRunningSize() >= mConstants.MAX_RUNNING_PROCESS_QUEUES) {if (!queue.isPendingUrgent()) {queue = nextQueue;continue;}}// 若队列未到可运行时间且无等待队列,延迟处理if (runnableAt > now && !waitingFor) {mLocalHandler.sendEmptyMessageAtTime(MSG_UPDATE_RUNNING_LIST, runnableAt);break;}// 清除队列的延迟状态(准备分发广播)queue.clearDeferredStates(mBroadcastConsumerDeferClear);// 更新进程温/冷状态updateWarmProcess(queue);final boolean processWarm = queue.isProcessWarm();if (processWarm) {// 热进程:临时解冻OOM调整并检查进程存活状态mService.mOomAdjuster.unfreezeTemporarily(queue.app,CachedAppOptimizer.UNFREEZE_REASON_START_RECEIVER);if (!queue.isProcessWarm()) { // 解冻后进程可能被杀死queue = nextQueue;enqueueUpdateRunningList();continue;}} else {// 冷进程:同一时间仅允许一个冷启动if (mRunningColdStart == null) {mRunningColdStart = queue;} else if (isPendingColdStartValid()) {queue = nextQueue;continue;} else {clearInvalidPendingColdStart();mRunningColdStart = queue;}}if (DEBUG_BROADCAST) logv("Promoting " + queue+ " from runnable to running; process is " + queue.app);// 将队列提升为运行状态promoteToRunningLocked(queue);boolean completed;/* 关键分发逻辑 */if (processWarm) {// 热进程分发:直接通过Binder调用进程的ReceiverupdateOomAdj |= queue.runningOomAdjusted;try {completed = scheduleReceiverWarmLocked(queue); // 同步分发广播} catch (BroadcastRetryException e) {finishOrReEnqueueActiveBroadcast(queue);completed = true;}} else {// 冷进程分发:先启动进程再分发completed = scheduleReceiverColdLocked(queue); // 异步启动进程}// 若广播分发完成,将队列降级为非运行状态if (completed) {demoteFromRunningLocked(queue);}avail--; // 占用一个可用槽位queue = nextQueue;}// 更新OOM调整状态(优化进程优先级)if (updateOomAdj) {mService.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_RECEIVER);}// 清理无效的冷启动状态checkPendingColdStartValidityLocked();checkAndRemoveWaitingFor();traceEnd(cookie);}
下一步:分别看下冷和热启动的流程
进程状态处理
热进程:通过 scheduleReceiverWarmLocked 直接分发广播(Binder调用已存在的进程)
冷进程:通过 scheduleReceiverColdLocked 启动新进程(仅允许一个冷启动 mRunningColdStart)
六、广播发送中涉及的冷和热启动的流程处理
先看冷启动,因为冷启动后的流程和热启动广播是一样的哈
6.1 冷启动通过 scheduleReceiverColdLocked 启动新进程
/*** 当目标进程未启动(冷状态)时调度广播分发的核心逻辑** @param queue 目标进程的广播队列(BroadcastProcessQueue)* @return true 表示广播分发已完成且队列可降级;false 表示需等待进程启动后继续处理** 关键流程:* 1. 验证队列状态并标记冷启动标志* 2. 检查接收者有效性(静态/动态注册、进程状态等)* 3. 通过AMS启动目标进程* 4. 记录进程启动信息用于后续热启动分发*/@CheckResult@GuardedBy("mService")private boolean scheduleReceiverColdLocked(@NonNull BroadcastProcessQueue queue) {// 1. 验证队列状态(必须处于活跃状态)checkState(queue.isActive(), "isActive");queue.setActiveViaColdStart(true); // 标记当前广播通过冷启动分发// 2. 获取当前待分发的广播和接收者信息final BroadcastRecord r = queue.getActive();final int index = queue.getActiveIndex();final Object receiver = r.receivers.get(index);// 3. 动态注册接收者(BroadcastFilter)不支持冷启动,直接跳过if (receiver instanceof BroadcastFilter) {mRunningColdStart = null;finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED,"BroadcastFilter for cold app");return true;}// 4. 检查接收者是否应跳过(如权限不足、进程已停止等)final String skipReason = shouldSkipReceiver(queue, r, index);if (skipReason != null) {mRunningColdStart = null;finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED, skipReason);return true;}// 5. 准备进程启动参数final ApplicationInfo info = ((ResolveInfo) receiver).activityInfo.applicationInfo;final ComponentName component = ((ResolveInfo) receiver).activityInfo.getComponentName();// 6. 处理应用停止状态(FLAG_STOPPED)和首次启动标志if ((info.flags & ApplicationInfo.FLAG_STOPPED) != 0) {queue.setActiveWasStopped(true); // 标记应用曾被用户强制停止}final int intentFlags = r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND;final boolean firstLaunch = !mService.wasPackageEverLaunched(info.packageName, r.userId);queue.setActiveFirstLaunch(firstLaunch); // 记录是否为首次启动// 7. 构建进程启动记录(HostingRecord)和性能策略final HostingRecord hostingRecord = new HostingRecord(HostingRecord.HOSTING_TYPE_BROADCAST,component,r.intent.getAction(),r.getHostingRecordTriggerType());final boolean isActivityCapable = (r.options != null&& r.options.getTemporaryAppAllowlistDuration() > 0);final int zygotePolicyFlags = isActivityCapable ?ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY;final boolean allowWhileBooting = (r.intent.getFlags()& Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0; // 允许在系统启动阶段运行// 8. 通过AMS启动目标进程long startTimeNs = SystemClock.uptimeNanos();if (DEBUG_BROADCAST) logv("Scheduling " + r + " to cold " + queue);queue.app = mService.startProcessLocked(queue.processName,info,true, // 允许冷启动intentFlags,hostingRecord,zygotePolicyFlags,allowWhileBooting,false // 非持久化进程);// 9. 进程启动失败处理if (queue.app == null) {mRunningColdStart = null;finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,"startProcessLocked failed");return true;}// 10. 记录进程启动信息(用于性能监控)mService.mProcessList.getAppStartInfoTracker().handleProcessBroadcastStart(startTimeNs,queue.app,r.getReceiverIntent(receiver),r.alarm /* isAlarm */);return false; // 返回false表示需等待进程启动完成后再触发热启动分发}
冷启动成功后,AMS会通过 attachApplicationLocked 回调重新触发 processNextBroadcast,最终由 scheduleReceiverWarmLocked 完成实际分发,故我们继续看热启动的分发广播流程
6.2 热启动通过 scheduleReceiverWarmLocked 直接分发广播
遍历接收器进程记录内的三个接收器队列,分发广播。
/*** 向已启动(热)进程分发当前活跃广播的核心逻辑** @param queue 目标进程的广播队列(BroadcastProcessQueue)* @return true 表示广播分发完成且队列可降级;false 表示需等待异步回调* @throws BroadcastRetryException 若需重试分发则抛出异常** 关键流程:* 1. 检查队列状态,确保当前有活跃广播待处理(queue.isActive())* 2. 记录广播分发的关键时间戳(dispatchTime/dispatchRealTime)* 3. 检查接收者是否需跳过(权限/进程状态等)* 4. 调用 dispatchReceivers 执行实际分发(跨进程Binder调用)* 5. 处理分发结果:若阻塞则返回false,否则继续处理下一个广播*/@CheckResult@GuardedBy("mService")private boolean scheduleReceiverWarmLocked(@NonNull BroadcastProcessQueue queue)throws BroadcastRetryException {checkState(queue.isActive(), "isActive"); // 断言队列处于活跃状态final int cookie = traceBegin("scheduleReceiverWarmLocked");while (queue.isActive()) { // 循环处理队列中的活跃广播final BroadcastRecord r = queue.getActive();final int index = queue.getActiveIndex();// 首次分发时记录时间戳(用于ANR计算)if (r.terminalCount == 0) {r.dispatchTime = SystemClock.uptimeMillis();r.dispatchRealTime = SystemClock.elapsedRealtime();r.dispatchClockTime = System.currentTimeMillis();}// 检查接收者是否需跳过(如静态接收者限制、进程死亡等)final String skipReason = shouldSkipReceiver(queue, r, index);if (skipReason == null) {// 执行实际分发(跨进程调用 onReceive)final boolean isBlockingDispatch = dispatchReceivers(queue, r, index);if (isBlockingDispatch) { // 若需等待异步回调(如有序广播)traceEnd(cookie);return false;}} else {// 标记跳过状态并清理资源finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED, skipReason);}// 检查队列是否需终止(如进程死亡或广播被取消)if (shouldRetire(queue)) {break;}// 处理下一个待分发的广播queue.makeActiveNextPending();}traceEnd(cookie);return true; // 当前批次分发完成}
下一步:重点关注dispatchReceivers跨进程回调 onReceive的逻辑
七、广播发送-dispatchReceivers函数
有序广播需要等待上一个接受器执行完才能执行下一个接受器。所以系统要求每个有序广播接收器需要在特定的时间内执行完(前台广播10S,后台广播60S),否则就会报ANR
/*** 分发广播到指定接收者,并启动ANR计时(针对有序广播的核心逻辑)** @param queue 目标进程的广播队列(BroadcastProcessQueue)* @param r 当前广播记录(BroadcastRecord)* @param index 接收者在r.receivers列表中的索引* @return true 表示有序广播需阻塞等待finishReceiver()回调;false 表示无序广播或假设已送达* @throws BroadcastRetryException 静态接收者分发失败时抛出以重试** 关键流程:* 1. 启动ANR超时监控(仅有序广播且非豁免场景)* 2. 处理后台启动权限和进程冷冻豁免* 3. 通过Binder跨进程调用触发接收者的onReceive()* 4. 若为有序广播,返回true以阻塞等待finishReceiver()*/@GuardedBy("mService")@CheckResultprivate boolean dispatchReceivers(@NonNull BroadcastProcessQueue queue,@NonNull BroadcastRecord r, int index) throws BroadcastRetryException {final ProcessRecord app = queue.app;final Object receiver = r.receivers.get(index);// --- ANR超时控制 ---// 仅在系统启动完成、非豁免广播且未假设送达时启动ANR计时final boolean assumeDelivered = r.isAssumedDelivered(index);if (mService.mProcessesReady && !r.timeoutExempt && !assumeDelivered) {queue.setTimeoutScheduled(true);// 前台广播10秒超时,后台广播60秒超时 [2,5](@ref)final int softTimeoutMillis = (int) (r.isForeground() ? mFgConstants.TIMEOUT: mBgConstants.TIMEOUT);startDeliveryTimeoutLocked(queue, softTimeoutMillis); // 启动ANR计时器} else {queue.setTimeoutScheduled(false);}// --- 后台启动权限管理 ---if (r.mBackgroundStartPrivileges.allowsAny()) {app.addOrUpdateBackgroundStartPrivileges(r, r.mBackgroundStartPrivileges);final long timeout = r.isForeground() ? mFgConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT: mBgConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT;// 延迟消息检查后台启动权限超时mLocalHandler.sendMessageDelayed(Message.obtain(mLocalHandler, MSG_BG_ACTIVITY_START_TIMEOUT, args), timeout);}// --- 进程冷冻豁免处理 ---if (r.options != null && r.options.getTemporaryAppAllowlistDuration() > 0) {if (r.options.getTemporaryAppAllowlistType()== PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_APP_FREEZING_DELAYED) {// 临时解冻进程以接收广播mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(app,CachedAppOptimizer.UNFREEZE_REASON_START_RECEIVER,r.options.getTemporaryAppAllowlistDuration());} else {mService.tempAllowlistUidLocked(queue.uid,r.options.getTemporaryAppAllowlistDuration(),r.options.getTemporaryAppAllowlistReasonCode(), r.toShortString(),r.options.getTemporaryAppAllowlistType(), r.callingUid);}}// --- 分发广播到接收者 ---final Intent receiverIntent = r.getReceiverIntent(receiver);final IApplicationThread thread = app.getOnewayThread();if (thread != null) {try {// 动态注册接收者(BroadcastFilter)if (receiver instanceof BroadcastFilter) {notifyScheduleRegisteredReceiver(app, r, (BroadcastFilter) receiver);thread.scheduleRegisteredReceiver(((BroadcastFilter) receiver).receiverList.receiver,receiverIntent, r.resultCode, r.resultData, r.resultExtras,r.ordered, r.initialSticky, assumeDelivered, r.userId,app.mState.getReportedProcState(),r.shareIdentity ? r.callingUid : Process.INVALID_UID,r.shareIdentity ? r.callerPackage : null);if (assumeDelivered) {finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_DELIVERED,"assuming delivered");return false; // 无序广播无需等待}}// 静态注册接收者(ResolveInfo)else {notifyScheduleReceiver(app, r, (ResolveInfo) receiver);thread.scheduleReceiver(receiverIntent, ((ResolveInfo) receiver).activityInfo,null, r.resultCode, r.resultData, r.resultExtras, r.ordered,assumeDelivered, r.userId,app.mState.getReportedProcState(),r.shareIdentity ? r.callingUid : Process.INVALID_UID,r.shareIdentity ? r.callerPackage : null);}return r.ordered; // 有序广播返回true,需阻塞等待finishReceiver()} catch (RemoteException e) {// 静态接收者分发失败时抛出异常以重试 [2](@ref)if (receiver instanceof ResolveInfo) {cancelDeliveryTimeoutLocked(queue);throw new BroadcastRetryException(e);}finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "remote app");return false;}} else {finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,"missing IApplicationThread");return false;}}
下一步:看ApplicationThread.scheduleReceiver
备注:有序广播必须等待前一个接收者的 finishReceiver() 回调后,才能分发到下一个接收者(通过 r.ordered 返回 true 实现)
八、广播发送-ApplicationThread.scheduleRegisteredReceiver函数
调度动态注册的广播接收器(跨进程调用入口)
/*** 调度动态注册的广播接收器(跨进程调用入口)** 核心作用:* 1. 确保动态注册的广播接收器按正确顺序分发(Binder单线程模型下保证有序性)* 2. 通过类型检查将调用路由到具体的 `InnerReceiver` 实现类* 3. 处理发送方身份信息(UID/Package)的传递校验** @param receiver 动态注册的接收器Binder代理(通常为InnerReceiver实例)* @param intent 广播Intent* @param assumeDelivered 是否假设广播已送达(避免ANR检查)* @param sendingUid 发送方UID(用于身份校验)* @param sendingPackage 发送方包名(用于身份校验)*/public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,int resultCode, String dataStr, Bundle extras, boolean ordered,boolean sticky, boolean assumeDelivered, int sendingUser, int processState,int sendingUid, String sendingPackage) throws RemoteException {// 更新进程状态(优化调度优先级)updateProcessState(processState, false);// --- 关键分发逻辑 ---if (receiver instanceof LoadedApk.ReceiverDispatcher.InnerReceiver) {// 标准路径:通过InnerReceiver触发接收逻辑((LoadedApk.ReceiverDispatcher.InnerReceiver) receiver).performReceive(intent,resultCode, dataStr, extras, ordered, sticky, assumeDelivered, sendingUser,sendingUid, sendingPackage); // [下一步分析点]} else {// 非标准路径:自定义IIntentReceiver的兼容性处理if (!assumeDelivered) {Log.wtf(TAG, "scheduleRegisteredReceiver() called for " + receiver+ " and " + intent + " without mechanism to finish delivery");}// 校验发送方身份信息传递完整性if (sendingUid != Process.INVALID_UID || sendingPackage != null) {Log.wtf(TAG, "scheduleRegisteredReceiver() called for " + receiver + " and " + intent+ " from " + sendingPackage + " (UID: " + sendingUid+ ") without mechanism to propagate the sender's identity");}// 降级处理:直接调用performReceive(无身份校验)receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky,sendingUser);}}
下一步:通过InnerReceiver触发接收逻辑,InnerReceiver.performReceive() → ReceiverDispatcher.performReceive() → 通过主线程Handler执行 Args.run() → 最终调用 BroadcastReceiver.onReceive()
九、广播发送-LoadedApk.ReceiverDispatcher.InnerReceiver.performReceive()函数
继续套娃哈
/*** 处理广播接收的核心方法(Binder服务端实现)** 核心职责:* 1. 校验Intent有效性并获取关联的ReceiverDispatcher* 2. 将广播分发给注册的BroadcastReceiver(通过rd.performReceive)* 3. 处理接收者已注销时的异常情况(通过AMS.finishReceiver回调)** @param assumeDelivered 是否假设广播已送达(跳过ANR检查)* @param sendingUid 发送方UID(用于权限校验)* @param sendingPackage 发送方包名(用于权限校验)*/public void performReceive(Intent intent, int resultCode, String data,Bundle extras, boolean ordered, boolean sticky, boolean assumeDelivered,int sendingUser, int sendingUid, String sendingPackage) {// 1. 获取ReceiverDispatcher弱引用(可能因进程回收或注销变为null)final LoadedApk.ReceiverDispatcher rd;if (intent == null) {Log.wtf(TAG, "Null intent received");rd = null;} else {rd = mDispatcher.get(); // 从WeakReference获取ReceiverDispatcher}// 2. 调试日志记录广播接收详情if (ActivityThread.DEBUG_BROADCAST) {int seq = intent.getIntExtra("seq", -1);Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction()+ " seq=" + seq + " to " + (rd != null ? rd.mReceiver : null));}// 3. 分两种情况处理广播if (rd != null) {// 正常路径:通过ReceiverDispatcher分发广播rd.performReceive(intent, resultCode, data, extras,ordered, sticky, assumeDelivered, sendingUser,sendingUid, sendingPackage); // [关键调用点]} else if (!assumeDelivered) {// 异常路径:接收者已注销但仍需通知AMS完成广播序列if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing broadcast to unregistered receiver");IActivityManager mgr = ActivityManager.getService();try {if (extras != null) {extras.setAllowFds(false); // 禁用文件描述符传递(安全措施)}// 强制通知AMS完成广播序列(避免阻塞后续广播)mgr.finishReceiver(mApplicationThread.asBinder(), resultCode, data,extras, false, intent.getFlags());} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}}/*** 处理广播分发的核心方法(通过主线程Handler调度)** 核心职责:* 1. 封装广播参数为Args对象(包含Intent、结果码、附加数据等)* 2. 通过主线程Handler异步执行广播处理(避免阻塞Binder线程)* 3. 处理分发失败或Intent为空的异常情况(强制通知AMS完成流程)** @param assumeDelivered 是否假设广播已送达(跳过ANR检查)* @param sendingUid 发送方UID(用于权限校验)* @param sendingPackage 发送方包名(用于身份校验)*/public void performReceive(Intent intent, int resultCode, String data,Bundle extras, boolean ordered, boolean sticky, boolean assumeDelivered,int sendingUser, int sendingUid, String sendingPackage) {// 1. 封装广播参数到Args对象(包含后续执行的Runnable逻辑)final Args args = new Args(intent, resultCode, data, extras, ordered,sticky, assumeDelivered, sendingUser, sendingUid, sendingPackage);// 2. 校验Intent有效性并记录调试日志if (intent == null) {Log.wtf(TAG, "Null intent received"); // 异常情况:Intent为空} else {if (ActivityThread.DEBUG_BROADCAST) {int seq = intent.getIntExtra("seq", -1);Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()+ " seq=" + seq + " to " + mReceiver); // 记录广播入队信息[3](@ref)}}// 3. 通过主线程Handler调度广播处理(关键异步化设计)if (intent == null || !mActivityThread.post(args.getRunnable())) {// 异常处理:Intent为空或主线程调度失败IActivityManager mgr = ActivityManager.getService();if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing sync broadcast to " + mReceiver);// 强制通知AMS完成广播流程(避免有序广播阻塞)[2,5](@ref)args.sendFinished(mgr);}}
下一步重点关注:LoadedApk.ReceiverDispatcher.Args.getRunnable()
十、广播发送-LoadedApk.ReceiverDispatcher.Args.getRunnable()函数
这个函数完成后,APP就
/*** 生成广播分发的Runnable任务(最终触发BroadcastReceiver.onReceive()的核心逻辑)** 核心职责:* 1. 封装广播分发逻辑为Lambda表达式(通过主线程Handler执行)* 2. 处理Intent和Receiver的异常情况(空值检查、重复分发等)* 3. 调用BroadcastReceiver.onReceive()并处理异常* 4. 通过sendFinished()通知AMS广播处理完成(避免ANR)** 调用链:* AMS -> InnerReceiver.performReceive() -> ReceiverDispatcher.getRunnable() -> onReceive()*/public final Runnable getRunnable() {return () -> {// 1. 获取广播接收器和Intent(通过成员变量传递)final BroadcastReceiver receiver = mReceiver;final Intent intent = mCurIntent;// 2. 调试日志记录广播分发信息if (ActivityThread.DEBUG_BROADCAST) {int seq = intent.getIntExtra("seq", -1);Slog.i(ActivityThread.TAG, "Dispatching broadcast " + intent.getAction()+ " seq=" + seq + " to " + receiver);}// 3. 异常检查:Intent为空或接收器已失效if (intent == null) {Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched+ (mRunCalled ? ", run() has already been called" : ""));}mCurIntent = null; // 清除Intent引用防止重复使用mDispatched = true; // 标记已分发mRunCalled = true; // 标记已执行// 4. 快速失败:接收器/Intent为空或已注销if (receiver == null || intent == null || mForgotten) {if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing null broadcast to " + receiver);sendFinished(ActivityManager.getService()); // 通知AMS结束流程return;}// 5. 开始性能追踪(用于Systrace工具分析)if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"broadcastReceiveReg: " + intent.getAction());}try {// 6. 准备Intent的ClassLoader(确保反序列化正确)ClassLoader cl = receiver.getClass().getClassLoader();intent.setExtrasClassLoader(cl);intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent),mContext.getAttributionSource());// 7. 关键调用:触发BroadcastReceiver.onReceive()receiver.setPendingResult(this); // 绑定结果回调receiver.onReceive(mContext, intent); // 实际业务逻辑执行点} catch (Exception e) {// 8. 异常处理:记录日志并通知AMSif (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing failed broadcast to " + receiver);sendFinished(ActivityManager.getService());if (mInstrumentation == null || !mInstrumentation.onException(receiver, e)) {Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);throw new RuntimeException("Error receiving broadcast " + intent + " in " + receiver, e);}}// 9. 检查未完成的广播结果(如有序广播未调用setResult)if (receiver.getPendingResult() != null) {finish(); // 强制结束广播流程}Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); // 结束性能追踪};}
Args.run,最终回调receiver.onReceive方法,至此,广播的发送和接收过程分析完毕。