Android 14 广播

目录

一、广播分类

1. 普通广播(Unordered Broadcast)

2. 有序广播(Ordered Broadcast)

3. 粘性广播(Sticky Broadcast)

二、动态广播接收器注册/注销(AMS 记录BroadcastReceiver)

三、发送/接收广播

broadcastIntentLocked

enqueueBroadcastLocked

updateRunningListLocked

scheduleReceiverWarmLocked

四、遇到一些的问题

Android 14之后,动态注册广播接收器需要显示标志能否接收应用外部的广播

广播接收器接收广播政策

Android 14 有序广播 ANR

在向特定package分发广播前,修改广播数据


一、广播分类

1. 普通广播(Unordered Broadcast)

普通广播是最简单的广播类型,一旦广播发出,所有的接收者都会收到这个广播,但接收的顺序是不确定的。
特点
* 无序性:接收者的接收顺序不确定。
* 不可拦截:广播发出后无法被任何接收者取消或拦截。
* 效率较高:因为不需要按顺序处理。
发送普通广播:sendBroadcast(intent);

2. 有序广播(Ordered Broadcast)

有序广播是按照优先级顺序依次传递给各个注册了该广播的接收者。每个接收者都可以选择是否继续传递广播,或者终止广播的传递。
特点
* 有序性:接收者按照优先级顺序接收广播。
* 可拦截:接收者可以选择终止广播,阻止后续的接收者接收到广播。
* 可以修改数据:接收者可以修改广播 Intent 中的数据,并传递给下一个接收者。
发送有序广播:sendOrderedBroadcast

3. 粘性广播(Sticky Broadcast)

粘性广播在发出后会被系统保留,直到被显式地清除。即使在广播发出后,没有接收者注册,稍后注册的接收者仍然可以接收到这个广播。
特点
* 持久性:广播发出后会被系统保留,直到被显式地清除。
* 可以被多次接收:即使没有接收者在广播发出时注册,稍后注册的接收者仍然可以接收到这个广播。
发送粘性广播:ActivityManager.broadcastStickyIntent(intent, AppOpsManager.OP_NONE,
                mBatteryChangedOptions, UserHandle.USER_ALL)
粘性广播的注意事项
由于粘性广播在发出后会被系统保留,因此需要谨慎使用,避免潜在的内存泄露问题。此外,从 Android 8.0(API 级别 26)开始,系统对粘性广播的支持有所限制,因此建议尽量避免使用粘性广播,改用其他机制(如 LocalBroadcastManager)来实现类似的功能。

二、动态广播接收器注册/注销(AMS 记录BroadcastReceiver)

    动态广播接收器打包成BroadcastFilter,记录在mReceiverResolver列表中
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
#registerReceiver
    //mRegisteredReceivers记录BroadcastReceiver
    rl = new ReceiverList(this, callerApp, callingPid, callingUid,
        userId, receiver);
    mRegisteredReceivers.put(receiver.asBinder(), rl);
    //mReceiverResolver记录IntentFilter
    roadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
        receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps,
                    exported);
    rl.add(bf);
    mReceiverResolver.addFilter(getPackageManagerInternal().snapshot(), bf);

#removeReceiverLocked
    void removeReceiverLocked(ReceiverList rl) {
        mRegisteredReceivers.remove(rl.receiver.asBinder());
        for (int i = rl.size() - 1; i >= 0; i--) {
            mReceiverResolver.removeFilter(rl.get(i));
        }
    }

三、发送/接收广播

broadcastIntentLocked

        1、找出符合条件的静态接收器和动态接收器
        2、若是无序广播,将动态接收器打包成一条广播记录,先进入无序广播队列,并行分发广播
        3、按优先级将静态和动态接收器合并到一个接收器队列
        4、将3中得到的接收器队列打包成一条广播记录,进入有序广播队列,串行分发广播
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
SparseArray<ArrayMap<String, ArrayList<StickyBroadcast>>> mStickyBroadcasts 粘性广播

#broadcastIntentLocked
//搜索AndroidManifest.xml中注册的Receiver
        if ((intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
            receivers = collectReceiverComponents(
                    intent, resolvedType, callingUid, users, broadcastAllowList);
        }
//获取代码动态注册的Receiver
        registeredReceivers = mReceiverResolver.queryIntent(snapshot, intent,
                        resolvedType, false /*defaultOnly*/, userId);

        //若是无序广播,则将符合条件的动态注册接收器和广播Intent打包成一条广播记录(BroadcastRecord),并进入并行队列{
        int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
        if (!ordered && NR > 0 && !mEnableModernQueue) { //若是无序广播
            final BroadcastQueue queue = broadcastQueueForIntent(intent);
            //将符合条件的动态注册接收器和广播Intent打包成一条广播记录(BroadcastRecord)
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
                    callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
                    registeredReceivers, resultToApp, resultTo, resultCode, resultData,
                    resultExtras, ordered, sticky, false, userId,
                    backgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver,
                    callerAppProcessState);
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
            queue.enqueueBroadcastLocked(r); //广播记录进入并行队列
            registeredReceivers = null;
            NR = 0;
        } //}若是无序广播,则将符合条件的动态注册接收器和广播Intent打包成一条广播记录(BroadcastRecord),并进入并行队列


        // Merge into one list. 当是有序广播时,将动态和静态接收器按优先级合并到一个队列{
        int ir = 0;
        // 比较优先级,先合并完静态接收器{
        if (receivers != null) {

            int NT = receivers != null ? receivers.size() : 0;
            int it = 0;
            ResolveInfo curt = null;    //当前静态接收器
            BroadcastFilter curr = null;//当前动态接收器
            while (it < NT && ir < NR) {//只有是有序广播才会执行,因为无序广播此时NR=0
                if (curt == null) {
                    curt = (ResolveInfo)receivers.get(it);
                }
                if (curr == null) {
                    curr = registeredReceivers.get(ir);
                }
                // 优先级高的(priority大的)靠前 {
                if (curr.getPriority() >= curt.priority) {
                    // 动态接收器优先级高,先进队列
                    receivers.add(it, curr);//这里插入到it位置,it之后的元素应该会整体在队列往后移一位
                    ir++;
                    curr = null;
                    it++;
                    NT++;
                } else {
                    // 静态接收器优先级高,先进队列
                    it++;
                    curt = null;
                }
                // }优先级高的(priority大的)靠前 
            }
        } // }比较优先级,先合并完静态广播

        //将剩下的动态接收器合并到队尾
        while (ir < NR) {//只有是有序广播才会执行,因为无序广播此时NR=0
            if (receivers == null) {
                receivers = new ArrayList();
            }
            receivers.add(registeredReceivers.get(ir));
            ir++;
        }//}将剩下的动态接收器合并到列表
        // }Merge into one list. 当是有序广播时,将动态和静态接收器按优先级合并到一个队列


        //有序广播进入队有序广播队列
        if ((receivers != null && receivers.size() > 0)
                || resultTo != null) {
            BroadcastQueue queue = broadcastQueueForIntent(intent);
            filterNonExportedComponents(intent, callingUid, callingPid, receivers,
                    mPlatformCompat, callerPackage, resolvedType);
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
                    callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
                    receivers, resultToApp, resultTo, resultCode, resultData, resultExtras,
                    ordered, sticky, false, userId,
                    backgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver,
                    callerAppProcessState);

            //即使是无序广播的静态接收器,在这里也是进入有序队列,并按顺序分发广播
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
            queue.enqueueBroadcastLocked(r);
        } else {
            //没有感兴趣的广播接收器
            // UNISOC: add log for debug broadcast skipped
            Slog.d(TAG, "Skip enqueue broadcast because no receiver with " + intent);
            // There was nobody interested in the broadcast, but we still want to record
            // that it happened.
            if (intent.getComponent() == null && intent.getPackage() == null
                    && (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
                // This was an implicit broadcast... let's record it for posterity.
                addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
            }
        }

enqueueBroadcastLocked

    1、根据进程名和Uid找出或创建接收器进程记录(BroadcastProcessQueue)。
    2、将接收器添加到接收器进程记录内的mPending、mPendingUrgent和mPendingOffload三个接收器队列中的一个
    3、将接收器进程记录添加到进程队列(mRunnableHead),越早排队优先级越高
    4、enqueueUpdateRunningList分发广播
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
#ActivityManagerService构造方中:
        if (mEnableModernQueue) { //14之后默认开启
            mBroadcastQueues = new BroadcastQueue[1];
            mBroadcastQueues[0] = new BroadcastQueueModernImpl(this, mHandler,
                    foreConstants, backConstants);
        } 


    BroadcastQueue broadcastQueueForFlags(int flags, Object cookie) {
        if (mEnableModernQueue) {//14之后默认开启
            return mBroadcastQueues[0];
        }
    }

frameworks/base/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
    public void enqueueBroadcastLocked(@NonNull BroadcastRecord r) {
        //UNISOC: remove DEBUG_BROADCAST switch for debug
        StringBuilder allReceivers = new StringBuilder();
        if (DEBUG_BROADCAST) {
            allReceivers.append(":");
            allReceivers.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);

        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),以进程名和Uid为主键。
            //2、在这里是根据接收器的进程名和Uid找出或常见接收器进程记录
            final BroadcastProcessQueue queue = getOrCreateProcessQueue(
                    getReceiverProcessName(receiver), getReceiverUid(receiver));

            // If this receiver is going to be skipped, skip it now itself and don't even enqueue
            // it.
            // 判断接收器是否跳过,如:静态接收器只能接收到显性广播
            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;
            // 每个接收器进程记录包含三个队列mPending、mPendingUrgent和mPendingOffload,这三个队列都是用来记录接收器信息,只是优先级不一样
            // 将接收器添加到广播进程队列内的三个队列中的一个
            final BroadcastRecord replacedBroadcast = queue.enqueueOrReplaceBroadcast(
                    r, i, mBroadcastConsumerDeferApply);
            if (replacedBroadcast != null) {
                replacedBroadcasts.add(replacedBroadcast);
            }
            // mRunnableHead是所有接收器进程记录的队列头,将接收器进程记录添加到mRunnableHead队列中
            updateRunnableList(queue); 
            // 在AMS的线程中执行,分发广播。
            enqueueUpdateRunningList();
        }

        // Skip any broadcasts that have been replaced by newer broadcasts with
        // FLAG_RECEIVER_REPLACE_PENDING.
        // TODO: Optimize and reuse mBroadcastConsumerSkipAndCanceled for the case of
        // cancelling all receivers for a broadcast.
        skipAndCancelReplacedBroadcasts(replacedBroadcasts);
        replacedBroadcasts.clear();
        mReplacedBroadcastsCache.compareAndSet(null, replacedBroadcasts);

        // If nothing to dispatch, send any pending result immediately
        if (r.receivers.isEmpty() || !enqueuedBroadcast) {
            scheduleResultTo(r);
            notifyFinishBroadcast(r);
        }

        traceEnd(cookie);
    }

updateRunningListLocked

    遍历mRunnableHead队列,接收器进程已启动则使用scheduleReceiverWarmLocked分发广播,否则使用scheduleReceiverColdLocked分发广播
    
private void updateRunningListLocked() {
        // Allocated size here implicitly includes the extra reservation for urgent
        // dispatches beyond the MAX_RUNNING_QUEUES soft limit for normal
        // parallelism.  If we're already dispatching some urgent broadcasts,
        // count that against the extra first - its role is to permit progress of
        // urgent broadcast traffic when the normal reservation is fully occupied
        // with less-urgent dispatches, not to generally expand parallelism.
        final int usedExtra = Math.min(getRunningUrgentCount(),
                mConstants.EXTRA_RUNNING_URGENT_PROCESS_QUEUES);
        int avail = mRunning.length - getRunningSize() - usedExtra;
        if (avail == 0) {
            Slog.d(TAG, "Skip update running list, mRunnableHead=" + mRunnableHead
                    + " Max running broadcast queue size is " + mRunning.length
                    + " current is " + getRunningSize() + " usedExtra is " + usedExtra);
            return;
        }

        final int cookie = traceBegin("updateRunningList");
        final long now = SystemClock.uptimeMillis();

        // If someone is waiting for a state, everything is runnable now
        final boolean waitingFor = !mWaitingFor.isEmpty();

        // We're doing an update now, so remove any future update requests;
        // we'll repost below if needed
        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();

            // When broadcasts are skipped or failed during list traversal, we
            // might encounter a queue that is no longer runnable; skip it
            if (!queue.isRunnable()) {
                queue = nextQueue;
                continue;
            }

            // If we've hit the soft limit for non-urgent dispatch parallelism,
            // only consider delivering from queues whose ready broadcast is urgent
            if (getRunningSize() >= mConstants.MAX_RUNNING_PROCESS_QUEUES) {
                if (!queue.isPendingUrgent()) {
                    queue = nextQueue;
                    continue;
                }
            }

            // If queues beyond this point aren't ready to run yet, schedule
            // another pass when they'll be runnable
            if (runnableAt > now && !waitingFor) {
                mLocalHandler.sendEmptyMessageAtTime(MSG_UPDATE_RUNNING_LIST, runnableAt);
                break;
            }

            // We might not have heard about a newly running process yet, so
            // consider refreshing if we think we're cold
            updateWarmProcess(queue);

            final boolean processWarm = queue.isProcessWarm();
            if (processWarm) {
                mService.mOomAdjuster.unfreezeTemporarily(queue.app,
                        CachedAppOptimizer.UNFREEZE_REASON_START_RECEIVER);
                // The process could be killed as part of unfreezing. So, check again if it
                // is still warm.
                if (!queue.isProcessWarm()) {
                    queue = nextQueue;
                    enqueueUpdateRunningList();
                    continue;
                }
            } else {
                // We only offer to run one cold-start at a time to preserve
                // system resources; below we either claim that single slot or
                // skip to look for another warm process
                if (mRunningColdStart == null) {
                    mRunningColdStart = queue;
                } else if (isPendingColdStartValid()) {
                    // Move to considering next runnable queue
                    queue = nextQueue;
                    continue;
                } else {
                    // Pending cold start is not valid, so clear it and move on.
                    clearInvalidPendingColdStart();
                    mRunningColdStart = queue;
                }
            }

            if (DEBUG_BROADCAST) logv("Promoting " + queue
                    + " from runnable to running; process is " + queue.app);
            promoteToRunningLocked(queue);
            boolean completed;
            if (processWarm) {
                updateOomAdj |= queue.runningOomAdjusted;
                try {
                    completed = scheduleReceiverWarmLocked(queue);
                } catch (BroadcastDeliveryFailedException e) {
                    reEnqueueActiveBroadcast(queue);
                    completed = true;
                }
            } else {
                completed = scheduleReceiverColdLocked(queue);
            }
            // If we are done with delivering the broadcasts to the process, we can demote it
            // from the "running" list.
            if (completed) {
                demoteFromRunningLocked(queue);
            }
            // TODO: If delivering broadcasts to a process is finished, we don't have to hold
            // a slot for it.
            avail--;

            // Move to considering next runnable queue
            queue = nextQueue;
        }

        // TODO: We need to update oomAdj early as this currently doesn't guarantee that the
        // procState is updated correctly when the app is handling a broadcast.
        if (updateOomAdj) {
            mService.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_RECEIVER);
        }

        checkPendingColdStartValidity();
        checkAndRemoveWaitingFor();

        traceEnd(cookie);
    }

scheduleReceiverWarmLocked

    遍历接收器进程记录内的三个接收器队列,分发广播。
    
private boolean scheduleReceiverWarmLocked(@NonNull BroadcastProcessQueue queue)
            throws BroadcastDeliveryFailedException {
        checkState(queue.isActive(), "isActive");

        final int cookie = traceBegin("scheduleReceiverWarmLocked");
        while (queue.isActive()) {
            final BroadcastRecord r = queue.getActive();
            final int index = queue.getActiveIndex();

            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) {
                final boolean isBlockingDispatch = dispatchReceivers(queue, r, index);
                if (isBlockingDispatch) {
                    traceEnd(cookie);
                    return false;
                }
            } else {
                finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED, skipReason);
            }

            if (shouldRetire(queue)) {
                break;
            }

            // We're on a roll; move onto the next broadcast for this process
            queue.makeActiveNextPending();
        }
        traceEnd(cookie);
        return true;
    }

四、遇到一些的问题

Android 14之后,动态注册广播接收器需要显示标志能否接收应用外部的广播

//RECEIVER_EXPORTED 表示可以接收应用外部广播,ContextRECEIVER_NOT_EXPORTED 应用内部广播
        registerReceiver(mReceiver2, intentFilter, Context.RECEIVER_EXPORTED);

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
#registerReceiver
            //动态广播接收器是否有标志RECEIVER_EXPORTED或RECEIVER_NOT_EXPORTED
            final boolean explicitExportStateDefined =
                    (flags & (Context.RECEIVER_EXPORTED | Context.RECEIVER_NOT_EXPORTED)) != 0;

            //动态广播接收器是否需要显式标志RECEIVER_EXPORTED或RECEIVER_NOT_EXPORTED
            boolean requireExplicitFlagForDynamicReceivers = CompatChanges.isChangeEnabled(
                    DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED, callingUid);

            //动态广播接收器没有显式标志RECEIVER_EXPORTED或RECEIVER_NOT_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");
                    // Assume default behavior-- flag check is not enforced
                }
        // Dynamic receivers are exported by default for versions prior to T
        final boolean exported = (flags & Context.RECEIVER_EXPORTED) != 0;

​

#broadcastIntentLocked
           //过滤RECEIVER_NOT_EXPORTED动态广播接收器
           filterNonExportedComponents(intent, callingUid, callingPid, registeredReceivers,
                mPlatformCompat, callerPackage, resolvedType);

广播接收器接收广播政策

    并不是每个广播接收器都能接收到广播,是在 BroadcastSkipPolicy#shouldSkipMessage有条件判断接收器收否能接受到广播
如静态接收器不能接收到隐式广播,log报: Background execution not allowed
frameworks/base/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
#enqueueBroadcastLocked
            for (int i = 0; i < r.receivers.size(); i++) {
            final Object receiver = r.receivers.get(i);
            final BroadcastProcessQueue queue = getOrCreateProcessQueue(
                    getReceiverProcessName(receiver), getReceiverUid(receiver));


            // If this receiver is going to be skipped, skip it now itself and don't even enqueue
            // it.
            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;
            }
        }

frameworks/base/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
#shouldSkipMessage
        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
            // (depending on how getAppStartModeLOSP has determined that).
            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();
            }
        }

Android 14 有序广播 ANR

    有序广播需要等待上一个接受器执行完才能执行下一个接受器。所以系统要求每个有序广播接收器需要在特定的时间内执行完(前台广播10S,后台广播60S),否则就会报ANR
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
    static final int BROADCAST_FG_TIMEOUT = (Build.isDebuggable()?40:10) * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
    static final int BROADCAST_BG_TIMEOUT = (Build.isDebuggable()?90:60) * 1000 * Build.HW_TIMEOUT_MULTIPLIER;

frameworks/base/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
    private boolean dispatchReceivers(@NonNull BroadcastProcessQueue queue,
            @NonNull BroadcastRecord r, int index) throws BroadcastDeliveryFailedException {
        final ProcessRecord app = queue.app;
        final Object receiver = r.receivers.get(index);

        // Skip ANR tracking early during boot, when requested, or when we
        // immediately assume delivery success
        final boolean assumeDelivered = r.isAssumedDelivered(index);   //是否是无序动态接收器
        if (mService.mProcessesReady && !r.timeoutExempt && !assumeDelivered) {
            queue.lastCpuDelayTime = queue.app.getCpuDelayTime();

            final int softTimeoutMillis = (int) (r.isForeground() ? mFgConstants.TIMEOUT
                    : mBgConstants.TIMEOUT);
            //当超时后,执行finishReceiverActiveLocked
            mLocalHandler.sendMessageDelayed(Message.obtain(mLocalHandler,
                    MSG_DELIVERY_TIMEOUT_SOFT, softTimeoutMillis, 0, queue), softTimeoutMillis);
        }

                    if (assumeDelivered) {
                        //无序动态接收器,标志为已分发完广播
                        finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_DELIVERED,
                                "assuming delivered");
                        return false;
                    }
    }

    private void finishReceiverActiveLocked(@NonNull BroadcastProcessQueue queue,
            @DeliveryState int deliveryState, @NonNull String reason) {
        //若是广播已经分发,则忽略
        if (!queue.isActive()) {
            logw("Ignoring finishReceiverActiveLocked; no active broadcast for " + queue);
            return;
        }
        if (deliveryState == BroadcastRecord.DELIVERY_TIMEOUT) {// 超时无响应,后台广播默认60s,前台广播默认10s
            r.anrCount++;
            if (app != null && !app.isDebugging()) {
                final String packageName = getReceiverPackageName(receiver);
                final String className = getReceiverClassName(receiver);
                mService.appNotResponding(queue.app,
                        TimeoutRecord.forBroadcastReceiver(r.intent, packageName, className));
            }
        } else {
            mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT_SOFT, queue);
            mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT_HARD, queue);
        }
    }

在向特定package分发广播前,修改广播数据

    private boolean dispatchReceivers(@NonNull BroadcastProcessQueue queue,
            @NonNull BroadcastRecord r, int index) throws BroadcastDeliveryFailedException {
                
        final Intent receiverIntent = r.getReceiverIntent(receiver);
        if("package"equals(queue.getPackageName()) && "action".equals(receiverIntent.getAction())){
           int temperature =receiverIntent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);
           receiverIntent.putExtra(BatteryManager.EXTRA_TEMPERATURE,temperature < 43 ? temperature:42.9);
        }
    }

dumpsys activity broadcasts

ACTIVITY MANAGER BROADCAST STATE (dumpsys activity broadcasts)
  
  📋 Per-process queues: //接收器进程记录
    a067f51 5587:com.sprd.engineermode/u0a108 not runnable because INFINITE_DEFER
      state:FRZ
      e:3 d:3 f:0 fd:0 o:0 a:0 p:3 pd:3 int:0 rt:0 ins:0 m:0 csi:0 adcsi:0 ccu:3 ccn:53
      -9s918ms 3be1f0 android.intent.action.BATTERY_CHANGED/u-1
          DEFERRED for registered 614d6a1
          blocked until 7, currently at 24 of 24
      -9s918ms 3be1f0 android.intent.action.BATTERY_CHANGED/u-1
          DEFERRED for registered ab9a91a
          blocked until 7, currently at 24 of 24
      -9s918ms 3be1f0 android.intent.action.BATTERY_CHANGED/u-1
          DEFERRED for registered 936b32f
          blocked until 7, currently at 24 of 24
    
    926a5c1 22881:com.google.android.apps.tachyon/u0a141 not runnable because INFINITE_DEFER
      state:FRZ
      runningOomAdjusted:true
      e:2 d:2 f:0 fd:0 o:0 a:0 p:1 pd:1 int:0 rt:0 ins:0 m:0 csi:0 adcsi:0 ccu:0 ccn:2
      -10s410ms 7597a9 android.intent.action.ACTION_POWER_CONNECTED/u-1
          DEFERRED for registered 5695093
      -9s918ms 3be1f0 android.intent.action.BATTERY_CHANGED/u-1
          DEFERRED for registered 5695093
          blocked until 7, currently at 24 of 24
    
  
  🧍 Runnable:
    (none)
  
  🏃 Running:
      (none)
      (none)
      (none)
      (none)
      (none)
  
  Broadcasts with ignored delivery group policies:
    {}
  
  Foreground UIDs:
    {10210=true}
  
  Broadcast parameters (key=bcast_fg_constants, observing=true):
    bcast_timeout=+40s0ms     //debug软件前台广播默认40s超时
    bcast_slow_time=+5s0ms
    bcast_deferral=+5s0ms
    bcast_deferral_decay_factor=0.75
    bcast_deferral_floor=0
    bcast_allow_bg_activity_start_timeout=+10s0ms
  
  Broadcast parameters (namespace=activity_manager_native_boot):
    modern_queue_enabled=true
    bcast_max_running_process_queues=4
    bcast_max_running_active_broadcasts=16
    bcast_max_core_running_blocking_broadcasts=16
    bcast_max_core_running_non_blocking_broadcasts=64
    bcast_max_pending_broadcasts=256
    bcast_delay_normal_millis=+500ms
    bcast_delay_cached_millis=+2m0s0ms
    bcast_delay_urgent_millis=-2m0s0ms
    bcast_delay_foreground_proc_millis=-2m0s0ms
    bcast_delay_persistent_proc_millis=-2m0s0ms
    bcast_max_history_complete_size=256
    bcast_max_history_summary_size=1024
    bcast_max_consecutive_urgent_dispatches=3
    bcast_max_consecutive_normal_dispatches=10
    bcast_core_defer_until_active=true
    pending_cold_start_check_interval_millis=30000
  
    Pending broadcasts:
    Broadcast #1:
      BroadcastRecord{3be1f0 android.intent.action.BATTERY_CHANGED/u-1} to user -1
      Intent { act=android.intent.action.BATTERY_CHANGED flg=0x60000010 (has extras) }
        extras: Bundle[{technology=Li-ion, icon-small=17303669, max_charging_voltage=5000000, health=2, max_charging_current=500000, status=2, plugged=2, present=true, android.os.extra.CHARGING_STATUS=0, seq=218, charge_counter=105032, level=100, scale=100, temperature=310, voltage=4391, android.os.extra.CYCLE_COUNT=2968, invalid_charger=0, battery_low=false}]
      caller=null null pid=1330 uid=1000
      options=Bundle[{android:broadcast.deferralPolicy=2, android:broadcast.deliveryGroupPolicy=1}]
      enqueueClockTime=2023-12-31 23:00:08.534 dispatchClockTime=2023-12-31 23:00:08.540
      dispatchTime=-9s914ms (+6ms since enq) receiverTime=--
      resultAbort=false ordered=false sticky=true initialSticky=false originalStickyCallingUid=-1
      terminalCount=20
      DELIVERED scheduled +7ms terminal 0 (0) #0: BroadcastFilter{d28a248 1000/u0 ReceiverList{7fc4eb 1330 system/1000/u0 local:77103a}}
        reason: assuming delivered
      DELIVERED scheduled +8ms terminal 0 (0) #1: BroadcastFilter{6c7aa69 1000/u0 ReceiverList{68d44f0 1330 system/1000/u0 local:1ec2933}}
        reason: assuming delivered
      DELIVERED scheduled +9ms terminal 0 (0) #2: BroadcastFilter{413a5f 1000/u0 ReceiverList{76fe2fe 1330 system/1000/u0 local:e895eb9}}
        reason: assuming delivered
      DELIVERED scheduled +10ms terminal +1ms (0) #3: BroadcastFilter{d0b673d 1000/u0 ReceiverList{ad16094 1330 system/1000/u0 local:7ae9ce7}}
        reason: assuming delivered
      DELIVERED scheduled +12ms terminal 0 (0) #4: BroadcastFilter{3d38cc5 1000/u0 ReceiverList{184073c 1330 system/1000/u0 local:a8e952f}}
        reason: assuming delivered
      DELIVERED scheduled +12ms terminal 0 (0) #5: BroadcastFilter{4ee9af5 1000/u0 ReceiverList{7e6b02c 1330 system/1000/u0 local:5ff8bdf}}
        reason: assuming delivered
      DELIVERED scheduled +13ms terminal 0 (0) #6: BroadcastFilter{272b94a 1000/u-1 ReceiverList{64baeb5 1330 system/1000/u-1 local:880baec}}
        reason: assuming delivered
      DELIVERED scheduled +15ms terminal 0 (7) #7: BroadcastFilter{10679e 1000/u0 ReceiverList{73c91d9 1330 system/1000/u0 local:5106420}}
        reason: assuming delivered
      DELIVERED scheduled +16ms terminal +1ms (7) #8: BroadcastFilter{c35db 1000/u0 ReceiverList{bfbeeea 1330 system/1000/u0 local:e47b6d5}}
        reason: assuming delivered
      DELIVERED scheduled +18ms terminal 0 (7) #9: BroadcastFilter{7031077 1000/u0 ReceiverList{8c96276 1330 system/1000/u0 local:c93d111}}
        reason: assuming delivered
      DELIVERED scheduled +19ms terminal 0 (7) #10: BroadcastFilter{6d0e5e9 1000/u0 ReceiverList{3503e70 1330 system/1000/u0 local:36118b3}}
        reason: assuming delivered
      DELIVERED scheduled +20ms terminal 0 (7) #11: BroadcastFilter{88d7e8a 1000/u0 ReceiverList{d2d40f5 1330 system/1000/u0 local:1002e2c}}
        reason: assuming delivered
      DELIVERED scheduled +22ms terminal 0 (7) #12: BroadcastFilter{4425832 10168/u0 ReceiverList{e1767a6 1981 com.android.systemui/10168/u0 remote:2ceed01}}
        reason: assuming delivered
      DELIVERED scheduled +24ms terminal +1ms (7) #13: BroadcastFilter{1d381a2 1001/u0 ReceiverList{6fb816d 1960 com.android.phone/1001/u0 remote:b45c584}}
        reason: assuming delivered
      DELIVERED scheduled +25ms terminal +1ms (7) #14: BroadcastFilter{34f93b6 1001/u0 ReceiverList{9faff51 1960 com.android.phone/1001/u0 remote:466bc78}}
        reason: assuming delivered
      DELIVERED scheduled +21ms terminal 0 (7) #15: BroadcastFilter{8f5c89c 1000/u-1 ReceiverList{553000f 1330 system/1000/u-1 local:41b716e}}
        reason: assuming delivered
      DELIVERED scheduled +23ms terminal 0 (7) #16: BroadcastFilter{6fb0907 10168/u0 ReceiverList{6daa346 1981 com.android.systemui/10168/u0 remote:6315321}}
        reason: assuming delivered
      DELIVERED scheduled +22ms terminal 0 (7) #17: BroadcastFilter{515841 1000/u0 ReceiverList{d8c2328 1330 system/1000/u0 local:ef3d4b}}
        reason: assuming delivered
      DELIVERED scheduled +28ms terminal 0 (7) #18: BroadcastFilter{bd2efd 10130/u0 ReceiverList{c126f54 3139 com.google.android.googlequicksearchbox:interactor/10130/u0 remote:7a3aea7}}
        reason: assuming delivered
      DELIVERED scheduled +24ms terminal 0 (7) #19: BroadcastFilter{60e1d52 10168/u0 ReceiverList{1357ddd 1981 com.android.systemui/10168/u0 remote:bd12db4}}
        reason: assuming delivered
      DEFERRED (7) #20: BroadcastFilter{614d6a1 10108/u0 ReceiverList{c0f1f08 5587 com.sprd.engineermode/10108/u0 remote:cb33cab}}
        reason: mBroadcastConsumerDeferApply
      DEFERRED (7) #21: BroadcastFilter{ab9a91a 10108/u0 ReceiverList{5bc3bc5 5587 com.sprd.engineermode/10108/u0 remote:1f6123c}}
        reason: mBroadcastConsumerDeferApply
      DEFERRED (7) #22: BroadcastFilter{936b32f 10108/u0 ReceiverList{47f7d0e 5587 com.sprd.engineermode/10108/u0 remote:dadd709}}
        reason: mBroadcastConsumerDeferApply
      DEFERRED (7) #23: BroadcastFilter{5695093 10141/u0 ReceiverList{366182 22881 com.google.android.apps.tachyon/10141/u0 remote:6074cd}}
        reason: mBroadcastConsumerDeferApply

log

2024-01-01 00:37:11.637 1330-3251/? V/ActivityManager: Broadcast: Intent { act=com.example.customview.MY_BROADCAST flg=0x10 } ordered=true userid=0 options=null
2024-01-01 00:37:11.638 1330-3251/? V/ActivityManager: Enqueueing broadcast: com.example.customview.MY_BROADCAST replacePending=false
2024-01-01 00:37:11.638 1330-3251/? V/ActivityManager: Enqueueing ordered broadcast BroadcastRecord{3a34b13 com.example.customview.MY_BROADCAST/u0}
2024-01-01 00:37:11.638 1330-3251/? V/BroadcastQueue: Enqueuing BroadcastRecord{3a34b13 com.example.customview.MY_BROADCAST/u0} from uid 10209 pid 11528 for 2 receivers:[BroadcastFilter{6bdd5af 10209/u0 ReceiverList{5fb998e 11528 com.example.customview/10209/u0 remote:a4e9589}}, ResolveInfo{118f150 com.example.customview/.MyReceiver m=0x108000 userHandle=UserHandle{0}}]
2024-01-01 00:37:11.639 1330-3251/? V/ActivityManager_MU: isSingleton(com.example.customview, ApplicationInfo{5054f49 com.example.customview}, com.example.customview.MyReceiver, 0x10000) = false
2024-01-01 00:37:11.639 1330-3251/? D/BroadcastQueue: com.example.customview:Intent { act=com.example.customview.MY_BROADCAST flg=0x10 } deferUntilActive=false RunnableAt=2194826 reason:FOREGROUND enqueueTime=2314826 app.isCached=false ProcessFreezable=false
2024-01-01 00:37:11.640 1330-3251/? D/BroadcastQueue: Delivery state of BroadcastRecord{3a34b13 com.example.customview.MY_BROADCAST/u0} to ResolveInfo{118f150 com.example.customview/.MyReceiver m=0x108000 userHandle=UserHandle{0}} via null changed from PENDING to SKIPPED because skipped by policy at enqueue: Background execution not allowed: receiving Intent { act=com.example.customview.MY_BROADCAST flg=0x10 } to com.example.customview/.MyReceiver
2024-01-01 00:37:11.640 1330-3251/? W/BroadcastQueue: Delivery state of BroadcastRecord{3a34b13 com.example.customview.MY_BROADCAST/u0} to ResolveInfo{118f150 com.example.customview/.MyReceiver m=0x108000 userHandle=UserHandle{0}} via null changed from PENDING to SKIPPED because skipped by policy at enqueue: Background execution not allowed: receiving Intent { act=com.example.customview.MY_BROADCAST flg=0x10 } to com.example.customview/.MyReceiver
2024-01-01 00:37:11.642 1330-1374/? V/BroadcastQueue: Scheduling BroadcastRecord{3a34b13 com.example.customview.MY_BROADCAST/u0} to warm ProcessRecord{66ca199 11528:com.example.customview/u0a209} receiver:com.example.customview.MainActivity$2 waited 3ms
2024-01-01 00:37:11.642 1330-1374/? D/BroadcastQueue: Delivery state of BroadcastRecord{3a34b13 com.example.customview.MY_BROADCAST/u0} to BroadcastFilter{6bdd5af 10209/u0 ReceiverList{5fb998e 11528 com.example.customview/10209/u0 remote:a4e9589}} via ProcessRecord{66ca199 11528:com.example.customview/u0a209} changed from PENDING to SCHEDULED because scheduleReceiverWarmLocked
2024-01-01 00:37:11.665 11528-11528/com.example.customview D/MyReceiver: 动态接收器 收到广播拉:2,执行前时间:1704040631665
2024-01-01 00:37:11.677 11528-11528/com.example.customview D/MyReceiver: 动态接收器 收到广播拉:2,执行完时间:1704040631677
2024-01-01 00:37:11.678 1330-3251/? D/BroadcastQueue: Delivery state of BroadcastRecord{3a34b13 com.example.customview.MY_BROADCAST/u0} to BroadcastFilter{6bdd5af 10209/u0 ReceiverList{5fb998e 11528 com.example.customview/10209/u0 remote:a4e9589}} via ProcessRecord{66ca199 11528:com.example.customview/u0a209} changed from SCHEDULED to DELIVERED because remote app
2024-01-01 00:37:11.679 1330-3251/? D/BroadcastQueue: Finished with ordered BroadcastRecord{3a34b13 com.example.customview.MY_BROADCAST/u0} took 39ms manifest receiver:1 manifest skipped: 1 total receiver:2
2024-01-01 00:37:11.679 1330-3251/? D/BroadcastQueue: Receiver BroadcastFilter{6bdd5af 10209/u0 ReceiverList{5fb998e 11528 com.example.customview/10209/u0 remote:a4e9589}} finished with BroadcastRecord{3a34b13 com.example.customview.MY_BROADCAST/u0} took 36ms

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值