Android15或AndroidU广播的发送流程

发布于:2025-07-25 ⋅ 阅读:(14) ⋅ 点赞:(0)

摘要

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),如果是有序广播还会告诉下一个同学

广播发送的架构图

0

阶段

步骤描述

关键方法/组件

冷/热启动区别

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就收到广播了哈

0

源码走读

一、调用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,                             // 要发送的广播Intent                resolvedType,                       // 已解析的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,                      // 待发送的广播Intent        String 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调用进程的Receiver            updateOomAdj |= 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. 异常处理:记录日志并通知AMS            if (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方法,至此,广播的发送和接收过程分析完毕。


网站公告

今日签到

点亮在社区的每一天
去签到