android U广播详解(二)

news2024/11/18 12:47:50

android U广播详解(一)

基础代码介绍

广播相关

// 用作单个进程批量分发receivers,已被丢弃
frameworks/base/services/core/java/com/android/server/am/BroadcastReceiverBatch.java
// 主要逻辑所在类,包括入队、分发、结束等
frameworks/base/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
// 进程队列,分发广播时的单位
frameworks/base/services/core/java/com/android/server/am/BroadcastProcessQueue.java
// 之前的BroadcastQueue
frameworks/base/services/core/java/com/android/server/am/BroadcastQueueImpl.java
// 决定是否跳过分发当前receiver
frameworks/base/services/core/java/com/android/server/am/BroadcastSkipPolicy.java

默认使用BroadcastQueueModernImpl类来处理广播相关逻辑:

// 默认使用modern Queue
if (mEnableModernQueue) {
    mBroadcastQueues = new BroadcastQueue[1];
    mBroadcastQueues[0] = new BroadcastQueueModernImpl(this, mHandler,
            foreConstants, backConstants);
} else {
   ......
}
每个接收者的交付状态
// BroadcastRecord.java
    @IntDef(flag = false, prefix = { "DELIVERY_" }, value = {
            DELIVERY_PENDING, // 初始状态:等待未来运行
            DELIVERY_DELIVERED, // 终端状态:成功完成
            DELIVERY_SKIPPED, // 终端状态:由于内部政策而跳过
            DELIVERY_TIMEOUT, // 终端状态:尝试投递时超时
            DELIVERY_SCHEDULED, // 中间状态:当前正在执行
            DELIVERY_FAILURE, // 终端状态:派送失败
    })

    final @DeliveryState int[] delivery;   // 每个接受者的交付状态

    // 获取指定index对应receiver的交付状态
    @DeliveryState int getDeliveryState(int index) {
        return delivery[index];
    }

    // 如果给定的交付状态为“终端”,则返回,其中不会进行额外的交付状态更改。
    static boolean isDeliveryStateTerminal(@DeliveryState int deliveryState) {
        switch (deliveryState) {
            case DELIVERY_DELIVERED:
            case DELIVERY_SKIPPED:
            case DELIVERY_TIMEOUT:
            case DELIVERY_FAILURE:
                return true;
            default:
                return false;
        }
    }
    
    // 如果给定的传递状态为“超出”,则返回,这意味着我们已经超出了该接收器,并且未来的接收器现在已解锁。
    static boolean isDeliveryStateBeyond(@DeliveryState int deliveryState) {
        switch (deliveryState) {
            case DELIVERY_DELIVERED:
            case DELIVERY_SKIPPED:
            case DELIVERY_TIMEOUT:
            case DELIVERY_FAILURE:
            case DELIVERY_DEFERRED:
                return true;
            default:
                return false;
    }
    
    // 更新给定索引的{@link #receivers}传递状态。,自动更新与状态变化相关的任何时间测量
    // 如果由于此状态转换{@link #beyondCount}而发生变化则返回true,表明其他事件可能会被解除阻塞。
    @CheckResult
    boolean setDeliveryState(int index, @DeliveryState int newDeliveryState,
            @NonNull String reason) {
        final int oldDeliveryState = delivery[index];
        if (isDeliveryStateTerminal(oldDeliveryState)
                || newDeliveryState == oldDeliveryState) {
            // 我们已经到达终端或请求状态,因此请保留第一次转换时的所有统计数据和原因完整无缺
            return false;
        }

        switch (oldDeliveryState) {
            case DELIVERY_DEFERRED:
                deferredCount--;
                break;
        }
        switch (newDeliveryState) {
            case DELIVERY_PENDING:
                scheduledTime[index] = 0;
                break;
            case DELIVERY_SCHEDULED:
                scheduledTime[index] = SystemClock.uptimeMillis();
                break;
            case DELIVERY_DEFERRED:
                deferredCount++;
                break;
            case DELIVERY_DELIVERED:
            case DELIVERY_SKIPPED:
            case DELIVERY_TIMEOUT:
            case DELIVERY_FAILURE:
                terminalTime[index] = SystemClock.uptimeMillis();
                terminalCount++;
                break;
        }

        delivery[index] = newDeliveryState;
        deliveryReasons[index] = reason;

        // 如果当前receiver的状态变化可能会让我们达到一个新的beyondCount
        final int oldBeyondCount = beyondCount;
        if (index >= beyondCount) {
            for (int i = beyondCount; i < delivery.length; i++) {
                if (isDeliveryStateBeyond(getDeliveryState(i))) {
                    beyondCount = i + 1;
                } else {
                    break;
                }
            }
        }
        return (beyondCount != oldBeyondCount);
    }
广播种类
  // BroadcastRecord.java
    // 紧急广播,关于此广播传送优先级的核心策略确定,前台、用户交互触发、闹钟触发
    boolean isUrgent() {
        return (isForeground()
                || interactive
                || alarm);
    }
    // 负载广播
    boolean isOffload() {
        return (intent.getFlags() & Intent.FLAG_RECEIVER_OFFLOAD) != 0;
    }

    // 确定 {@link #calculateBlockedUntilTerminalCount} 的结果是否对接收方进行了优先排序。
    @VisibleForTesting
    static boolean isPrioritized(@NonNull int[] blockedUntilBeyondCount,
        boolean ordered) {
        return !ordered && (blockedUntilBeyondCount.length > 0)
            && (blockedUntilBeyondCount[0] != -1);
    }
// BroadcastProcessQueue.java
// 等待发送到此进程的广播的有序集合,作为一对 {@link BroadcastRecord} 和代表接收者的 {@link BroadcastRecord#receivers} 的索引。
private final ArrayDeque<SomeArgs> mPending = new ArrayDeque<>();

// 等待分派到此进程的“紧急”广播的有序集合,与 {@link #mPending} 的表示相同。
private final ArrayDeque<SomeArgs> mPendingUrgent = new ArrayDeque<>(4);

// 等待分派到此进程的“卸载”广播的有序集合,与{@link #mPending} 的表示相同。
private final ArrayDeque<SomeArgs> mPendingOffload = new ArrayDeque<>(4);
// 持有等待调度的广播的所有队列的列表
private final List<ArrayDeque<SomeArgs>> mPendingQueues = List.of(
        mPendingUrgent, mPending, mPendingOffload);

进程队列状态

在这里插入图片描述

可运行状态
 // BroadcastProcessQueue.java
    private @UptimeMillisLong long mRunnableAt = Long.MAX_VALUE;
    private @Reason int mRunnableAtReason = REASON_EMPTY;
    private boolean mRunnableAtInvalidated;

    // 未处于Blocked状态,且队列不为空
    public boolean isRunnable() {
        if (mRunnableAtInvalidated) updateRunnableAt();
        return mRunnableAt != Long.MAX_VALUE;
    }

    // 返回此进程被视为可运行的时间,通常是下一个pending广播的首次入队时间,也有可能是暂停或延迟时间
    public @UptimeMillisLong long getRunnableAt() {
        if (mRunnableAtInvalidated) updateRunnableAt();
        return mRunnableAt;
    }

    // 返回当前 {@link #getRunnableAt()} 值背后的“原因”,例如表明队列延迟或暂停的原因。
    public @Reason int getRunnableAtReason() {
        if (mRunnableAtInvalidated) updateRunnableAt();
        return mRunnableAtReason;
    }

    // 前一个receiver分发完,则应刷新下一个receiver所在队列的runnable
    public void invalidateRunnableAt() {
        mRunnableAtInvalidated = true;
    }

    // 快速确定此队列是否有等待传递给清单接收者的广播,这表明我们应该请求 OOM 调整。
    public boolean isPendingManifest() {
        return mCountManifest > 0;
    }
    // BroadcastQueueModernImpl.java
    // 从 UID 映射到每个进程的广播队列。 如果一个 UID 托管多个进程,则每个额外的进程都使用 {@link BroadcastProcessQueue#next} 存储为链表。
    @GuardedBy("mService")
    private final SparseArray<BroadcastProcessQueue> mProcessQueues = new SparseArray<>();

    // 包含“可运行”队列的链表头。 它们按 {@link BroadcastProcessQueue#getRunnableAt()} 排序,因此我们更喜欢首先调度等待时间较长的广播。
    private BroadcastProcessQueue mRunnableHead = null;
运行中状态
   // BroadcastProcessQueue.java
    // 正在调度的活动广播
    private @Nullable BroadcastRecord mActive;
        
    // 这是 {@link #mActive} 的 {@link BroadcastRecord#receivers} 列表的索引。
    private int mActiveIndex;

    public boolean isActive() {
        return mActive != null;
    }

    // 将当前活动的广播设置为下一个待处理的广播。
    public void makeActiveNextPending() {
        // TODO: what if the next broadcast isn't runnable yet?
        final SomeArgs next = removeNextBroadcast();
        mActive = (BroadcastRecord) next.arg1;
        mActiveIndex = next.argi1;
        mActiveCountSinceIdle++;
        mActiveViaColdStart = false;
        next.recycle();
        onBroadcastDequeued(mActive, mActiveIndex);
    }
// BroadcastQueueModernImpl.java
   // 当前正在“运行”的队列数组,可能有 {@code null} 的间隙。
    @GuardedBy("mService")
    private final BroadcastProcessQueue[] mRunning;

    // 正在“运行”但正在等待通过 {@link #onApplicationAttachedLocked} 完成冷启动的单个队列。 为了优化系统健康,我们一次只请求一个冷启动。
    @GuardedBy("mService")
    private @Nullable BroadcastProcessQueue mRunningColdStart;

    // 返回 {@link #mRunning} 中包含的活动队列总数。
    private int getRunningSize() {
        int size = 0;
        for (int i = 0; i < mRunning.length; i++) {
            if (mRunning[i] != null) size++;
        }
        return size;
    }
idle状态
// BroadcastProcessQueue.java   
    // 快速确定此队列是否有仍在等待在未来某个时间点传送的广播。
    public boolean isIdle() {
        return !isActive() && isEmpty();
    }

    // 将当前运行的广播设置为空闲。
    public void makeActiveIdle() {
        mActive = null;
        mActiveIndex = 0;
        mActiveCountSinceIdle = 0;
        mActiveViaColdStart = false;
        invalidateRunnableAt();
    }

分发相关

有序广播分发阻塞
// BroadcastRecord.java

// 已经接收完成/失败/Defer状态的receiver数量,即receiver状态不会影响后续receiver接收的数量
int beyondCount;

// 根据整体广播的当前状态,是否应将给定的 {@link #receivers} 索引视为已Blocked。
boolean isBlocked(int index) {
    return (beyondCount < blockedUntilBeyondCount[index]);
}

计算每个接收器应被视为阻塞的 {@link #beyondCount} 。
例如,在有序广播中,接收器 {@code N} 被阻塞,直到接收器 {@code N-1} 达到终止状态。
同样,在一个优先级广播,接收者 {@code N} 被阻塞,直到所有更高优先级的接收者达到终止状态。
当没有终端计数约束时,每个接收者的阻塞值为 {@code -1}。

// BroadcastRecord.java
@VisibleForTesting
static @NonNull int[] calculateBlockedUntilBeyondCount(
        @NonNull List<Object> receivers, boolean ordered) {
    final int N = receivers.size();
    final int[] blockedUntilBeyondCount = new int[N];
    int lastPriority = 0;
    int lastPriorityIndex = 0;
    for (int i = 0; i < N; i++) {
        if (ordered) {
            // 当发送有序广播时,我们需要阻塞这个接收者,直到所有之前的接收者都终止
            blockedUntilBeyondCount[i] = i;
        } else {
            // 发送优先级广播时,我们只需要等待前一批接收者终止
            final int thisPriority = getReceiverPriority(receivers.get(i));
            if ((i == 0) || (thisPriority != lastPriority)) {
                lastPriority = thisPriority;
                lastPriorityIndex = i;
                blockedUntilBeyondCount[i] = i;
            } else {
                blockedUntilBeyondCount[i] = lastPriorityIndex;
            }
        }
    }
    // 如果整个列表都在同一个优先级中,标记为-1表示它们都不需要等待
    if (N > 0 && blockedUntilBeyondCount[N - 1] == 0) {
        Arrays.fill(blockedUntilBeyondCount, -1);
    }
    return blockedUntilBeyondCount;
}
选取队列中下一个待执行广播
// BroadcastProcessQueue.java

// 自上次非紧急调度以来已调度的连续紧急广播数。
private int mActiveCountConsecutiveUrgent;

// 自上次负载调度以来已调度的连续正常广播数。
private int mActiveCountConsecutiveNormal;
 // BroadcastProcessQueue.java
    
    // 将当前活动的广播设置为下一个待处理的广播。
    public void makeActiveNextPending() {
        // TODO: what if the next broadcast isn't runnable yet?
        final SomeArgs next = removeNextBroadcast();
        mActive = (BroadcastRecord) next.arg1;
        mActiveIndex = next.argi1;
        mActiveCountSinceIdle++;
        mActiveAssumedDeliveryCountSinceIdle +=
                (mActive.isAssumedDelivered(mActiveIndex) ? 1 : 0);
        mActiveViaColdStart = false;
        mActiveWasStopped = false;
        next.recycle();
        onBroadcastDequeued(mActive, mActiveIndex);
    }

    @Nullable ArrayDeque<SomeArgs> queueForNextBroadcast() {
        // 普通优先级大于负载,但是限制为10
        final ArrayDeque<SomeArgs> nextNormal = queueForNextBroadcast(
                mPending, mPendingOffload,
                mActiveCountConsecutiveNormal, constants.MAX_CONSECUTIVE_NORMAL_DISPATCHES); //10
        // 紧急优先级大于普通,限制为3
        final ArrayDeque<SomeArgs> nextBroadcastQueue = queueForNextBroadcast(
                mPendingUrgent, nextNormal,
                mActiveCountConsecutiveUrgent, constants.MAX_CONSECUTIVE_URGENT_DISPATCHES); //3
        return nextBroadcastQueue;
    }

    private @Nullable ArrayDeque<SomeArgs> queueForNextBroadcast(
            @Nullable ArrayDeque<SomeArgs> highPriorityQueue,
            @Nullable ArrayDeque<SomeArgs> lowPriorityQueue,
            int consecutiveHighPriorityCount,  // 连续高优先级计数
            int maxHighPriorityDispatchLimit) { // 最大高优先级调度限制 10 or 3
        // 没有高优先级pending,没有进一步的决策
        if (isQueueEmpty(highPriorityQueue)) {
            return lowPriorityQueue;
        }
        // 只有高优先级pending,也没有进一步的决策
        if (isQueueEmpty(lowPriorityQueue)) {
            return highPriorityQueue;
        }

        // 缓解饥饿:虽然我们默认优先考虑高优先级队列,但我们允许低优先级队列稳定前进,即使高优先级队列中的广播到达速度快于它们的调度速度。
                  // 我们不会尝试推迟到低优先级队列中的下一个广播,如果该广播是有序的并且在传递给其他receiver时仍然被阻止。
        final SomeArgs nextLPArgs = lowPriorityQueue.peekFirst();
        final BroadcastRecord nextLPRecord = (BroadcastRecord) nextLPArgs.arg1;
        final int nextLPRecordIndex = nextLPArgs.argi1;
        final BroadcastRecord nextHPRecord = (BroadcastRecord) highPriorityQueue.peekFirst().arg1;
        final boolean shouldConsiderLPQueue = (mCountPrioritizeEarliestRequests // 最早优先,waitFor
                  // 连续高优先级处理达到阈值3 or 10
                || consecutiveHighPriorityCount >= maxHighPriorityDispatchLimit);
        // 低优先级队列符合条件
        final boolean isLPQueueEligible = shouldConsiderLPQueue
            // 低优先级队列入队时间更早
                && nextLPRecord.enqueueTime <= nextHPRecord.enqueueTime
            // 低优先级队列未处于有序广播分发的阻塞状态
                && !nextLPRecord.isBlocked(nextLPRecordIndex);
        return isLPQueueEligible ? lowPriorityQueue : highPriorityQueue;
    }
队列是否继续调度
 // BroadcastProcessQueue.java
     
    // 自此队列上次空闲以来已分派的 {@link #mActive} 广播计数,会在shouldContinueScheduling被使用,一个进程一次最多可分发8 or 16个广播
    private int mActiveCountSinceIdle;
    public int getActiveCountSinceIdle() {
        return mActiveCountSinceIdle;
    }

    // 如果我们知道此队列正在运行的“热”进程,则返回。
    public boolean isProcessWarm() {
        return (app != null) && (app.getOnewayThread() != null) && !app.isKilled();
    }
// BroadcastQueueModernImpl.java
    
    // 如果队列中不再有广播或者队列不可运行,则返回 true。
    private boolean shouldRetire(@NonNull BroadcastProcessQueue queue) {
        // 如果我们已经取得了合理的进展,请定期退出,以避免其他进程饥饿和广播立即完成而无需等待时堆栈溢出
        final boolean shouldRetire;
        if (UserHandle.isCore(queue.uid)) {
            // 动态注册的无序广播数量
            final int nonBlockingDeliveryCount = queue.getActiveAssumedDeliveryCountSinceIdle();
            // 有序广播 & 清单注册的广播数量
            final int blockingDeliveryCount = (queue.getActiveCountSinceIdle()
                    - queue.getActiveAssumedDeliveryCountSinceIdle());
            shouldRetire = (blockingDeliveryCount
                    // 16(低内存8)
                    >= mConstants.MAX_CORE_RUNNING_BLOCKING_BROADCASTS) || (nonBlockingDeliveryCount
                    // 64 (低内存32)
                    >= mConstants.MAX_CORE_RUNNING_NON_BLOCKING_BROADCASTS);
        } else {
            // 默认16(低内存8),系统可配置
            shouldRetire =
                    (queue.getActiveCountSinceIdle() >= mConstants.MAX_RUNNING_ACTIVE_BROADCASTS);
        }

        return !queue.isRunnable() || !queue.isProcessWarm() || shouldRetire;
    }

整体流程

入队流程:
在这里插入图片描述
冷启会多如下流程:
在这里插入图片描述
分发流程:
在这里插入图片描述
静态注册或有序广播结束分发后回调到AMS的流程:
在这里插入图片描述

入队

// BroadcastQueueModernImpl.java
    @Override
    public void enqueueBroadcastLocked(@NonNull BroadcastRecord r) {
        if (DEBUG_BROADCAST) logv("Enqueuing " + r + " for " + r.receivers.size() + " receivers");

        final int cookie = traceBegin("enqueueBroadcast");
        // 通过将它们重新定位到 {@link UserHandle#USER_SYSTEM},对单例进程托管的清单接收器进行特殊处理。
        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);
            final BroadcastProcessQueue queue = getOrCreateProcessQueue(
                    getReceiverProcessName(receiver), getReceiverUid(receiver));
            // 如果要跳过此接收器,请立即跳过它,甚至不要将其加入队列。
            // 诸如一些权限校验等
            final String skipReason = mSkipPolicy.shouldSkipMessage(r, receiver);
            if (skipReason != null) {
                setDeliveryState(null, null, r, i, receiver, BroadcastRecord.DELIVERY_SKIPPED,
                        "skipped by policy at enqueue: " + skipReason);
                continue;
            }
            // 入队对应的进程队列
            enqueuedBroadcast = true;
            final BroadcastRecord replacedBroadcast = queue.enqueueOrReplaceBroadcast(
                    r, i, mBroadcastConsumerDeferApply);
            if (replacedBroadcast != null) {
                replacedBroadcasts.add(replacedBroadcast);
            }
            // 更新可运行时间
            updateRunnableList(queue);
            // schedule 运行队列
            enqueueUpdateRunningList();
        }

        // 跳过任何已被带有 FLAG_RECEIVER_REPLACE_PENDING 的新广播取代的广播。
        skipAndCancelReplacedBroadcasts(replacedBroadcasts);
        replacedBroadcasts.clear();
        // If nothing to dispatch, send any pending result immediately
        if (r.receivers.isEmpty()) {
            scheduleResultTo(r);
            notifyFinishBroadcast(r);
        }

        traceEnd(cookie);
    }
应用对应的传递组策略
 // BroadcastQueueModernImpl.java
    private void applyDeliveryGroupPolicy(@NonNull BroadcastRecord r) {
        if (mService.shouldIgnoreDeliveryGroupPolicy(r.intent.getAction())) {
            return;
        }
        // 发送广播时可以指定下发策略
        final int policy = (r.options != null)
                ? r.options.getDeliveryGroupPolicy() : BroadcastOptions.DELIVERY_GROUP_POLICY_ALL;
        final BroadcastConsumer broadcastConsumer;
        switch (policy) {
            case BroadcastOptions.DELIVERY_GROUP_POLICY_ALL:
                // 在这种情况下,需要保留较旧的广播,因此无事可做。
                return;
            case BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT:
                // 匹配上则直接skip当前派发
                broadcastConsumer = mBroadcastConsumerSkipAndCanceled;
                break;
            case BroadcastOptions.DELIVERY_GROUP_POLICY_MERGED:
                final BundleMerger extrasMerger = r.options.getDeliveryGroupExtrasMerger();
                if (extrasMerger == null) {
                    // Extras合并需要能够合并extras。 因此,如果未提供,则忽略交付组策略。
                    return;
                }
                // 先合并额外的数据,再跳过分发
                broadcastConsumer = (record, recordIndex) -> {
                    r.intent.mergeExtras(record.intent, extrasMerger);
                    mBroadcastConsumerSkipAndCanceled.accept(record, recordIndex);
                };
                break;
            default:
                logw("Unknown delivery group policy: " + policy);
                return;
        }
        final ArrayMap<BroadcastRecord, Boolean> recordsLookupCache = getRecordsLookupCache();
        forEachMatchingBroadcast(QUEUE_PREDICATE_ANY, (testRecord, testIndex) -> {
            // 如果接收方已经处于终端状态,则忽略它。
            if (isDeliveryStateTerminal(testRecord.getDeliveryState(testIndex))) {
                return false;
            }
            // 我们只允许调用者删除他们排队的广播
            if ((r.callingUid != testRecord.callingUid)
                    || (r.userId != testRecord.userId)
                    || !r.matchesDeliveryGroup(testRecord)) {
                return false;
            }

            // 对于有序广播,请检查新广播的接收器是否是前一个广播的接收器的超集,
            // 因为跳过和仅删除其中一个可能会导致不一致的状态。
            if (testRecord.ordered || testRecord.prioritized) {
                return containsAllReceivers(r, testRecord, recordsLookupCache);
            } else if (testRecord.resultTo != null) {
                return testRecord.getDeliveryState(testIndex) == DELIVERY_DEFERRED
                        ? r.containsReceiver(testRecord.receivers.get(testIndex))
                        : containsAllReceivers(r, testRecord, recordsLookupCache);
            } else {
                return r.containsReceiver(testRecord.receivers.get(testIndex));
            }
        }, broadcastConsumer, true);
        recordsLookupCache.clear();
        mRecordsLookupCache.compareAndSet(null, recordsLookupCache);
    }

    // 典型的消费者会跳过给定的广播并将其标记为已取消,通常是因为它与predicate匹配。
    private final BroadcastConsumer mBroadcastConsumerSkipAndCanceled = (r, i) -> {
        setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_SKIPPED,
                "mBroadcastConsumerSkipAndCanceled");
        r.resultCode = Activity.RESULT_CANCELED;
        r.resultData = null;
        r.resultExtras = null;
    };
添加广播到对应的进程队列

将给定的广播排队,以便在未来的某个时间点发送到此进程。 目标接收器由 {@link BroadcastRecord#receivers} 中的给定索引指示。
如果广播被标记为 {@link BroadcastRecord#isReplacePending()},则此调用将替换任何待处理的调度; 否则它将作为普通广播排队。
定义后,此接收器被视为“阻塞”,直到至少给定计数的其他接收器达到终止状态; 通常用于有序广播和优先级广播。

// BroadcastProcessQueue.java
    public BroadcastRecord enqueueOrReplaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
            @NonNull BroadcastConsumer replacedBroadcastConsumer) {
        // 当 updateDeferredStates() 已将延迟状态应用于所有待处理项目时,也应用于此新广播
        if (mLastDeferredStates && record.deferUntilActive
                && (record.getDeliveryState(recordIndex) == BroadcastRecord.DELIVERY_PENDING)) {
            deferredStatesApplyConsumer.accept(record, recordIndex);
        }
        
        // 如果发件人使用 BroadcastOptions 交付组 API 指定了策略,则忽略 FLAG_RECEIVER_REPLACE_PENDING。
        if (record.isReplacePending()
                && record.getDeliveryGroupPolicy() == BroadcastOptions.DELIVERY_GROUP_POLICY_ALL) {
            final BroadcastRecord replacedBroadcastRecord = replaceBroadcast(record, recordIndex);
            if (replacedBroadcastRecord != null) {
                return replacedBroadcastRecord;
            }
        }

        // 调用者对替换不感兴趣,或者我们没有在上面找到任何待替换的项目,因此作为新广播排队
        SomeArgs newBroadcastArgs = SomeArgs.obtain();
        newBroadcastArgs.arg1 = record;
        newBroadcastArgs.argi1 = recordIndex;

        // 交叉广播优先级策略:一些广播可能保证在其他已经pending的广播之前发布,例如,如果这个新广播处于不同的交付类别或与具有隐式响应期望的直接用户交互相关联。
        getQueueForBroadcast(record).addLast(newBroadcastArgs);
        onBroadcastEnqueued(record, recordIndex);
        return null;
    }

    // 判断广播类别,紧急、负载、普通
    private @NonNull ArrayDeque<SomeArgs> getQueueForBroadcast(@NonNull BroadcastRecord record) {
        // 前台、用户交互、闹钟
        if (record.isUrgent()) {
            return mPendingUrgent;
        } else if (record.isOffload()) {
            return mPendingOffload;
        } else {
            return mPending;
        }
    }

当给定的记录已入队时更新摘要统计信息,跟onBroadcastDequeued对应。

// BroadcastProcessQueue.java
    private void onBroadcastEnqueued(@NonNull BroadcastRecord record, int recordIndex) {
        if (record.deferUntilActive) {
            mCountDeferred++;
        }
        if (record.isForeground()) {
            if (record.deferUntilActive) {
                mCountForegroundDeferred++;
            }
            mCountForeground++;
        }
        if (record.ordered) {
            mCountOrdered++;
        }
        if (record.alarm) {
            mCountAlarm++;
        }
        if (record.prioritized) {
            if (record.deferUntilActive) {
                mCountPrioritizedDeferred++;
            }
            mCountPrioritized++;
        }
        if (record.interactive) {
            mCountInteractive++;
        }
        if (record.resultTo != null) {
            mCountResultTo++;
        }
        if (record.callerInstrumented) {
            mCountInstrumented++;
        }
        if (record.receivers.get(recordIndex) instanceof ResolveInfo) {
            mCountManifest++;
        }
        invalidateRunnableAt();
    }
更新当前队列的RunnbaleAt
  • 默认mRunnableAt时间为广播的入队时间+500ms
  • 当前队列中有有序、闹钟、优先级、receiver为manifest或当前是persistent进程等,mRunnableAt时间为广播的入队时间。
  • 当前进程队列有前台广播、源于用户交互广播、由由root/shell/active instrument发送广播或当前进程为instrumented或当前app为top app,则mRunnableAt为入队时间-120s
  • 当前进程处于冻结状态,mRunnableAt为入队时间+120s或者defer
// BroadcastProcessQueue.java
    private void updateRunnableAt() {
        if (!mRunnableAtInvalidated) return;
        mRunnableAtInvalidated = false;
        // 获取下一个待处理的广播
        final SomeArgs next = peekNextBroadcast();
        if (next != null) {
            final BroadcastRecord r = (BroadcastRecord) next.arg1;
            final int index = next.argi1;
            final long runnableAt = r.enqueueTime;

            // 如果我们特别排在其他有序调度活动之后,我们还不能运行
            if (r.isBlocked(index)) {
                mRunnableAt = Long.MAX_VALUE;
                mRunnableAtReason = REASON_BLOCKED;
                return;
            }
            // 对此进程的任何广播需要延迟的持续时间
            if (mForcedDelayedDurationMs > 0) {
                mRunnableAt = runnableAt + mForcedDelayedDurationMs;
                mRunnableAtReason = REASON_FORCE_DELAYED;
                // 前台广播数量 > mCountForegroundDeferred
            } else if (mCountForeground > mCountForegroundDeferred) {
                mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS; //-120s
                mRunnableAtReason = REASON_CONTAINS_FOREGROUND;
                // 源于用户交互广播数量 > 0
            } else if (mCountInteractive > 0) {
                mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS; //-120s
                mRunnableAtReason = REASON_CONTAINS_INTERACTIVE;
                // 广播由root/shell/active instrument发送数量  > 0
            } else if (mCountInstrumented > 0) {
                mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS; //-120s
                mRunnableAtReason = REASON_CONTAINS_INSTRUMENTED;
                // 当前进程处于instrumented
            } else if (mProcessInstrumented) {
                mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS; //-120s
                mRunnableAtReason = REASON_INSTRUMENTED;
            // PROCESS_STATE_TOP top app
            } else if (mUidForeground) {
                mRunnableAt = runnableAt + constants.DELAY_FOREGROUND_PROC_MILLIS; //-120s
                mRunnableAtReason = REASON_FOREGROUND;
            } else if (app != null && app.getSetProcState() == ActivityManager.PROCESS_STATE_TOP) {
                // TODO (b/287676625): Use a callback to check when a process goes in and out of
                // the TOP state.
                mRunnableAt = runnableAt + constants.DELAY_FOREGROUND_PROC_MILLIS;
                mRunnableAtReason = REASON_TOP_PROCESS;
            } else if (mProcessPersistent) {
                mRunnableAt = runnableAt + constants.DELAY_PERSISTENT_PROC_MILLIS;
                mRunnableAtReason = REASON_PERSISTENT;
            } else if (UserHandle.isCore(uid)) {
                mRunnableAt = runnableAt;
                mRunnableAtReason = REASON_CORE_UID;
                // 有序广播数量  > 0 
            else if (mCountOrdered > 0) {
                mRunnableAt = runnableAt;
                mRunnableAtReason = REASON_CONTAINS_ORDERED;
                // 闹钟触发的广播  > 0
            } else if (mCountAlarm > 0) {
                mRunnableAt = runnableAt;
                mRunnableAtReason = REASON_CONTAINS_ALARM;
                // 优先级广播数量 > mCountPrioritizedDeferred
            } else if (mCountPrioritized > mCountPrioritizedDeferred) {
                mRunnableAt = runnableAt;
                mRunnableAtReason = REASON_CONTAINS_PRIORITIZED;
                // 有final receiver的广播 > mCountPrioritizedDeferred
            } else if (mCountManifest > 0) {
                mRunnableAt = runnableAt;
                mRunnableAtReason = REASON_CONTAINS_MANIFEST;
                // 进程冻结
            } else if (mProcessFreezable) {
                // 广播有设置deferUntilActive
                if (r.deferUntilActive) {
                    // 所有排队的广播都是可推迟的,defer
                    if (mCountDeferred == mCountEnqueued) {
                        mRunnableAt = Long.MAX_VALUE;
                        mRunnableAtReason = REASON_CACHED_INFINITE_DEFER;
                    } else {
                        // 至少有一个排队的广播不可推迟,请重新选择此记录的时间和原因。 
                        // 如果后来的记录不可推迟并且是这些特殊情况之一,则上述情况之一已经捕获了这一点。
                        if (r.isForeground()) {
                            mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS;
                            mRunnableAtReason = REASON_CONTAINS_FOREGROUND;
                        } else if (r.prioritized) {
                            mRunnableAt = runnableAt;
                            mRunnableAtReason = REASON_CONTAINS_PRIORITIZED;
                        } else if (r.resultTo != null) {
                            mRunnableAt = runnableAt;
                            mRunnableAtReason = REASON_CONTAINS_RESULT_TO;
                        } else {
                            
                            mRunnableAt = runnableAt + constants.DELAY_CACHED_MILLIS; //120s
                            mRunnableAtReason = REASON_CACHED;
                        }
                    }
                } else {
                    // This record isn't deferrable
                    mRunnableAt = runnableAt + constants.DELAY_CACHED_MILLIS;// 120s
                    mRunnableAtReason = REASON_CACHED;
                }
            } else if (mCountResultTo > 0) {
                mRunnableAt = runnableAt;
                mRunnableAtReason = REASON_CONTAINS_RESULT_TO;
                // 当前进程的为manifest的receiver数量 > 0
            } else {
                mRunnableAt = runnableAt + constants.DELAY_NORMAL_MILLIS; // +500ms
                mRunnableAtReason = REASON_NORMAL;
            }

            // 如果我们有太多待处理的广播,绕过上面可能应用的任何延迟以帮助耗尽
            if (mPending.size() + mPendingUrgent.size()
                    + mPendingOffload.size() >= constants.MAX_PENDING_BROADCASTS) {
                mRunnableAt = Math.min(mRunnableAt, runnableAt);
                mRunnableAtReason = REASON_MAX_PENDING;
            }
        } else {
            mRunnableAt = Long.MAX_VALUE;
            mRunnableAtReason = REASON_EMPTY;
        }
    }
更新可运行队列

考虑更新“可运行”队列的列表,特别是与给定队列相关的列表。
通常在 {@link BroadcastProcessQueue#getRunnableAt()} 可能已更改时调用,因为这会影响我们将“可运行”队列提升为“正在运行”的顺序。

 // BroadcastQueueModernImpl.java
    @GuardedBy("mService")
    private void updateRunnableList(@NonNull BroadcastProcessQueue queue) {
        if (getRunningIndexOf(queue) >= 0) {
            // 已经运行; 一旦它们运行完毕,它们将被重新插入到可运行列表中,所以现在不需要更新它们
            return;
        }
        // 为了将自己正确地放入可运行列表中,我们可能需要更新可能已失效的内部结构; 
        // 我们在最后一刻才等到,以避免重复工作
        queue.updateDeferredStates(mBroadcastConsumerDeferApply, mBroadcastConsumerDeferClear);
        queue.updateRunnableAt();
        // 是可运行状态
        final boolean wantQueue = queue.isRunnable();
        // 已在队列中
        final boolean inQueue = (queue == mRunnableHead) || (queue.runnableAtPrev != null)
                || (queue.runnableAtNext != null);
        if (wantQueue) {
            if (inQueue) {
                // 我们处于队列中,但我们在链表中的位置可能需要根据 
                // runnableAt 更改进行移动,链表前面的额队列总是应先被分发
                final boolean prevLower = (queue.runnableAtPrev != null)
                        ? queue.runnableAtPrev.getRunnableAt() <= queue.getRunnableAt() : true;
                final boolean nextHigher = (queue.runnableAtNext != null)
                        ? queue.runnableAtNext.getRunnableAt() >= queue.getRunnableAt() : true;
                if (!prevLower || !nextHigher) {
                    mRunnableHead = removeFromRunnableList(mRunnableHead, queue);
                    mRunnableHead = insertIntoRunnableList(mRunnableHead, queue);
                }
            } else {
                mRunnableHead = insertIntoRunnableList(mRunnableHead, queue);
            }
            // 从队列中移除
        } else if (inQueue) {
            mRunnableHead = removeFromRunnableList(mRunnableHead, queue);
        }

        // 当前队列为空、不是正在调度、进程不存活等,移除该队列
        if (queue.isEmpty() && !queue.isActive() && !queue.isProcessWarm()) {
            removeProcessQueue(queue.processName, queue.uid);
        }
    }

分发

更新正在运行队列

考虑更新“正在运行”队列的列表。 此方法可以将“可运行”队列提升为“正在运行”,受限于最多 {@link BroadcastConstants#MAX_RUNNING_PROCESS_QUEUES}(2 or 4) 热进程和只有一个挂起的冷启动。

一次可运行的队列数量为MAX_RUNNING_PROCESS_QUEUES(低内存2个,否则4个)+EXTRA_RUNNING_URGENT_PROCESS_QUEUES(1个)

  • 如果当前正在运行的列表>= (2 or 4),则取紧急的队列
  • 当前队列未到执行时间,则在指定时间再次执行更新
  • 当前队列的进程是冷启动,但是已经有一个需要冷启动的队列正在运行,则取下一个队列
 // BroadcastQueueModernImpl.java
    @GuardedBy("mService")
    private void updateRunningListLocked() {
         // 此处分配的大小隐含地包括超出正常并行性的 MAX_RUNNING_QUEUES 软限制的紧急调度的额外预留。
        // 如果我们已经在调度一些紧急广播,请先将其与额外广播放在一起 - 它的作用是在正常预留完全被不太紧急的调度占用时允许紧急广播流量的进展,而不是通常扩展并行性。
        final int usedExtra = Math.min(getRunningUrgentCount(),
                mConstants.EXTRA_RUNNING_URGENT_PROCESS_QUEUES); //1 
        // 空闲数量
        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) { // 2 or 4                        // 则只考虑从就绪广播为紧急的队列进行交付
                if (!queue.isPendingUrgent()) {
                    queue = nextQueue;
                    continue;
                }
            }

            // 最早的一个队列运行时间超出当前时间,跳出循环,并post 延时消息以便及时分发
            if (runnableAt > now && !waitingFor) {
                mLocalHandler.sendEmptyMessageAtTime(MSG_UPDATE_RUNNING_LIST, runnableAt);
                break;
            }

            // 我们可能还没有听说过新运行的进程,所以如果我们是冷启,请考虑刷新
            updateWarmProcess(queue);

            final boolean processWarm = queue.isProcessWarm();
            if (processWarm) {
                mService.mOomAdjuster.unfreezeTemporarily(queue.app,
                        CachedAppOptimizer.UNFREEZE_REASON_START_RECEIVER);
                // 该进程可能会作为解冻的一部分被终止。 所以,再检查一下是否仍然存在。
                if (!queue.isProcessWarm()) {
                    queue = nextQueue;
                    enqueueUpdateRunningList();
                    continue;
                }
            } else {
                // 我们只提供一次运行一个冷启动以节省系统资源;
                // 下面我们要么声明单个插槽,要么跳到寻找另一个warm进程
                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) {
                updateOomAdj |= queue.runningOomAdjusted;
                try {
                    completed = scheduleReceiverWarmLocked(queue);
                } catch (BroadcastDeliveryFailedException e) {
                    reEnqueueActiveBroadcast(queue);
                    completed = true;
                }
            } else {
                completed = scheduleReceiverColdLocked(queue);
            }
            // 如果我们完成了向进程传递广播,我们可以将其从“运行”列表中降级。
            if (completed) {
                demoteFromRunningLocked(queue);
            }
            // 可运行数量-1
            avail--;

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

        // 更新adj
        if (updateOomAdj) {
            mService.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_RECEIVER);
        }

        checkPendingColdStartValidity();
        checkAndRemoveWaitingFor();
        traceEnd(cookie);
    } 

将进程提升到“正在运行”列表

 // BroadcastQueueModernImpl.java
    @GuardedBy("mService")
    private void promoteToRunningLocked(@NonNull BroadcastProcessQueue queue) {
        // 分配此可用许可证并开始运行!
        final int queueIndex = getRunningIndexOf(null);
        // 将当前队列放在可运行数组中
        mRunning[queueIndex] = queue;

        // 从可运行链表中删除当前队列
        mRunnableHead = removeFromRunnableList(mRunnableHead, queue);

        // 将此进程的所有跟踪事件发送到一致的轨道中
        queue.runningTraceTrackName = TAG + ".mRunning[" + queueIndex + "]";
        // 指示此过程是否应进行 OOM 调整的标志,定义为升级到正在运行的插槽的一部分
        queue.runningOomAdjusted = queue.isPendingManifest()
                || queue.isPendingOrdered()
                || queue.isPendingResultTo();

        // 如果已经处于热启动,我们可以立即提出OOM调整请求; 否则我们需要等到进程变暖
        final boolean processWarm = queue.isProcessWarm();
        if (processWarm) {
            notifyStartedRunning(queue);
        }

        // 如果我们已经暖和了,现在就安排下一个待定的广播; 否则我们将等待冷启动回来
        // 设置队列的下一个active广播
        queue.makeActiveNextPending();
        if (processWarm) {
            queue.traceProcessRunningBegin();
        } else {
            queue.traceProcessStartingBegin();
        }
    }
    
   // 通知操作系统的其他部分给定的广播队列已开始运行,通常用于内部簿记。
   private void notifyStartedRunning(@NonNull BroadcastProcessQueue queue) {
        if (queue.app != null) {
            // 当前进程的ProcessReceiverRecord计数++
            queue.app.mReceivers.incrementCurReceivers();

            // 如果它在后台受限,不要改变它的 LRU 位置。.
            if (mService.mInternal.getRestrictionLevel(
                    queue.uid) < ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET) {
                mService.updateLruProcessLocked(queue.app, false, null);
            }

            mService.mOomAdjuster.unfreezeTemporarily(queue.app,
                    CachedAppOptimizer.UNFREEZE_REASON_START_RECEIVER);
             // manifest receiver/有序/有最终接受者所在进程需要将procState提升到11
            if (queue.runningOomAdjusted) {
                queue.app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
                mService.enqueueOomAdjTargetLocked(queue.app);
            }
        }
    }

将进程从“正在运行”列表中降级

// BroadcastQueueModernImpl.java
    @GuardedBy("mService")
    private void demoteFromRunningLocked(@NonNull BroadcastProcessQueue queue) {
        if (!queue.isActive()) {
            logw("Ignoring demoteFromRunning; no active broadcast for " + queue);
            return;
        }

        final int cookie = traceBegin("demoteFromRunning");
        // 我们已经耗尽了正在运行的广播; 也许回到可运行状态
        queue.makeActiveIdle();
        queue.traceProcessEnd();

        final int queueIndex = getRunningIndexOf(queue);
        mRunning[queueIndex] = null;
        // 更新可运行列表和Running列表,尝试进行下一个进程队列的分发
        updateRunnableList(queue);
        enqueueUpdateRunningList();

        // 告诉其他操作系统组件应用程序没有主动运行,从而有机会更新 OOM 调整
        notifyStoppedRunning(queue);
        traceEnd(cookie);
    }
热启分发

当我们知道进程处于热状态时,在给定队列上安排当前活动的广播。
无论是在远程应用程序处理广播的情况下,还是在没有远程应用程序的情况下在本地完成广播的情况下,都强烈希望通过调用 {@link #finishReceiverLocked} 来始终如一地处理所有涉及结果 。

    @CheckResult
    @GuardedBy("mService")
    private boolean scheduleReceiverWarmLocked(@NonNull BroadcastProcessQueue queue)
            throws BroadcastDeliveryFailedException {
        // 检查状态是否是active
        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 {
                // 跳过则标记结束,状态为DELIVERY_SKIPPED
                finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED, skipReason);
            }
            // 是否应该退出分发循环,达到数量限制会退出
            if (shouldRetire(queue)) {
                break;
            }

            // 标记下一个活动广播
            queue.makeActiveNextPending();
        }
        traceEnd(cookie);
        return true;
    }
冷启分发

当我们知道进程处于冷状态时,在给定队列上安排当前活动的广播。 这将导致冷启动,并最终会在准备就绪后调用 {@link #scheduleReceiverWarmLocked}。

 // BroadcastQueueModernImpl.java
    @CheckResult
    @GuardedBy("mService")
    private boolean scheduleReceiverColdLocked(@NonNull BroadcastProcessQueue queue) {
        checkState(queue.isActive(), "isActive");

        // 标记活动广播是通过冷启动安排的
        queue.setActiveViaColdStart(true);

        final BroadcastRecord r = queue.getActive();
        final int index = queue.getActiveIndex();
        final Object receiver = r.receivers.get(index);

        // 忽略通过动态注册的receiver来冷启动
        if (receiver instanceof BroadcastFilter) {
            mRunningColdStart = null;
            finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED,
                    "BroadcastFilter for cold app");
            return true;
        }
        // 判断是否需要跳过此次分发
        final String skipReason = shouldSkipReceiver(queue, r, index);
        if (skipReason != null) {
            mRunningColdStart = null;
            finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED, skipReason);
            return true;
        }

        final ApplicationInfo info = ((ResolveInfo) receiver).activityInfo.applicationInfo;
        final ComponentName component = ((ResolveInfo) receiver).activityInfo.getComponentName();

        if ((info.flags & ApplicationInfo.FLAG_STOPPED) != 0) {
            queue.setActiveWasStopped(true);
        }
        final int intentFlags = r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND;
        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;

        if (DEBUG_BROADCAST) logv("Scheduling " + r + " to cold " + queue);
        queue.app = mService.startProcessLocked(queue.processName, info, true, intentFlags,
                        hostingRecord, zygotePolicyFlags, allowWhileBooting, false);
        // 启动进程失败
        if (queue.app == null) {
            mRunningColdStart = null;
            finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
                    "startProcessLocked failed");
            return true;
        }
        return false;
    }

冷启进程启动后走跟热启一样的流程

    // BroadcastQueueModernImpl.java
    @Override
    public boolean onApplicationAttachedLocked(@NonNull ProcessRecord app)
            throws BroadcastDeliveryFailedException {
        if (DEBUG_BROADCAST) {
            logv("Process " + app + " is attached");
        }
        // 进程记录可以被回收,所以总是从查找相关的每个进程队列开始
        final BroadcastProcessQueue queue = getProcessQueue(app);
        if (queue != null) {
            setQueueProcess(queue, app);
        }

        boolean didSomething = false;
        if ((mRunningColdStart != null) && (mRunningColdStart == queue)) {
            // 我们一直在等待这个应用程序冷启动,现在已经准备好了; 调度它的下一个广播并清除插槽
            mRunningColdStart = null;

            // 现在我们已经启动,我们终于可以请求我们一直在等待的 OOM 调整
            notifyStartedRunning(queue);
            mService.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_RECEIVER);

            queue.traceProcessEnd();
            queue.traceProcessRunningBegin();
            try {
                // 跟热启流程一样了
                if (scheduleReceiverWarmLocked(queue)) {
                    // 当前进程分发完成,从可运行列表中移除
                    demoteFromRunningLocked(queue);
                }
            } catch (BroadcastDeliveryFailedException e) {
                reEnqueueActiveBroadcast(queue);
                demoteFromRunningLocked(queue);
                throw e;
            }

            // 我们可能愿意开始另一个冷启动,在ActivityManager线程中触发
            enqueueUpdateRunningList();
            didSomething = true;
        }
        return didSomething;
    }
分发到App进程

接收者即将被发送。 如有必要,启动 ANR 计时器。
如果需要等待finishReceiver回调,则返回true

// BroadcastQueueModernImpl.java
@CheckResult
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);

    // 当有请求时或当我们立即假设交付成功时,在启动期间尽早跳过 ANR 跟踪
    final boolean assumeDelivered = r.isAssumedDelivered(index);
    if (mService.mProcessesReady && !r.timeoutExempt && !assumeDelivered) {
        queue.lastCpuDelayTime = queue.app.getCpuDelayTime();
        // 前台10s,后台60s
        final int softTimeoutMillis = (int) (r.isForeground() ? mFgConstants.TIMEOUT
                : mBgConstants.TIMEOUT);
        mLocalHandler.sendMessageDelayed(Message.obtain(mLocalHandler,
                MSG_DELIVERY_TIMEOUT_SOFT, softTimeoutMillis, 0, queue), softTimeoutMillis);
    }

    // 添加或更新后台启动权限
    if (r.mBackgroundStartPrivileges.allowsAny()) {
        app.addOrUpdateBackgroundStartPrivileges(r, r.mBackgroundStartPrivileges);
        // 10s豁免
        final long timeout = r.isForeground() ? mFgConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT
                : mBgConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT;
        final SomeArgs args = SomeArgs.obtain();
        args.arg1 = app;
        args.arg2 = r;
        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) {
            // Only delay freezer, don't add to any temp allowlist
            // TODO: Add a unit test
            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);
        }
    }

    if (DEBUG_BROADCAST) logv("Scheduling " + r + " to warm " + app);
    // 设置传递状态为SCHEDULED
    setDeliveryState(queue, app, r, index, receiver, BroadcastRecord.DELIVERY_SCHEDULED,
            "scheduleReceiverWarmLocked");

    final Intent receiverIntent = r.getReceiverIntent(receiver);
    final IApplicationThread thread = app.getOnewayThread();
    if (thread != null) {
        try {
            if (r.shareIdentity) {
                mService.mPackageManagerInt.grantImplicitAccess(r.userId, r.intent,
                        UserHandle.getAppId(app.uid), r.callingUid, true);
            }
            queue.lastProcessState = app.mState.getCurProcState();
            // 动态分发
            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);
                // TODO: consider making registered receivers of unordered
                // broadcasts report results to detect ANRs
                // 如果无序广播,直接标记分发状态为DELIVERED
                if (assumeDelivered) {
                    finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_DELIVERED,
                            "assuming delivered");
                    return false;
                }
            } 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);
            }
            // 有序或静态则block下个广播的分发
            return true;
        } catch (RemoteException e) {
            final String msg = "Failed to schedule " + r + " to " + receiver
                    + " via " + app + ": " + e;
            logw(msg);
            app.killLocked("Can't deliver broadcast", ApplicationExitInfo.REASON_OTHER,
                    ApplicationExitInfo.SUBREASON_UNDELIVERED_BROADCAST, true);
            // If we were trying to deliver a manifest broadcast, throw the error as we need
            // to try redelivering the broadcast to this receiver.
            if (receiver instanceof ResolveInfo) {
                mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT_SOFT, queue);
                throw new BroadcastDeliveryFailedException(e);
            }
            finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
                    "remote app");
            return false;
        }
    } else {
    // 进程不存在
        finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
                "missing IApplicationThread");
        return false;
    }
}

如果应假定此接收者已交付,则返回 true。

// BroadcastRecord.java
boolean isAssumedDelivered(int index) {
    return (receivers.get(index) instanceof BroadcastFilter) && !ordered
            && (resultTo == null);
}
结束分发

有序广播或静态注册需要等待app执行完后binder回调finishReceiverLocked方法结束分发,运行在binder线程。

    // BroadcastQueueModernImpl.java
    @Override
    public boolean finishReceiverLocked(@NonNull ProcessRecord app, int resultCode,
            @Nullable String resultData, @Nullable Bundle resultExtras, boolean resultAbort,
            boolean waitForServices) {
        final BroadcastProcessQueue queue = getProcessQueue(app);
        if ((queue == null) || !queue.isActive()) {
            logw("Ignoring finishReceiverLocked; no active broadcast for " + queue);
            return false;
        }

        final BroadcastRecord r = queue.getActive();
        final int index = queue.getActiveIndex();
        // 有序广播相关属性赋值
        if (r.ordered) {
            r.resultCode = resultCode;
            r.resultData = resultData;
            r.resultExtras = resultExtras;
            if (!r.isNoAbort()) {
                r.resultAbort = resultAbort;
            }
        }
        
        // 为了确保以单调方式更新“超出”高水位线,我们在可能跳过任何剩余的中止接收器之前完成此接收器
        finishReceiverActiveLocked(queue,
                BroadcastRecord.DELIVERY_DELIVERED, "remote app");

        // 当调用者中止有序广播时,我们将所有剩余的接收者标记为已跳过
        if (r.resultAbort) {
            for (int i = index + 1; i < r.receivers.size(); i++) {
                setDeliveryState(null, null, r, i, r.receivers.get(i),
                        BroadcastRecord.DELIVERY_SKIPPED, "resultAbort");
            }
        }
        // 如果当前分发的广播达到限制,则从可运行列表中移除
        if (shouldRetire(queue)) {
            demoteFromRunningLocked(queue);
            return true;
        }

        // 我们进展顺利; 进入该过程的下一个广播
        queue.makeActiveNextPending();
        try {
            // 如果执行广播流程已达到限制,则从可运行列表中移除当前进程队列
            if (scheduleReceiverWarmLocked(queue)) {
                demoteFromRunningLocked(queue);
                return true;
            }
        } catch (BroadcastDeliveryFailedException e) {
            reEnqueueActiveBroadcast(queue);
            demoteFromRunningLocked(queue);
            return true;
        }

        return false;
    }

终止队列中所有活动的广播。

    // BroadcastQueueModernImpl.java
    private void finishReceiverActiveLocked(@NonNull BroadcastProcessQueue queue,
            @DeliveryState int deliveryState, @NonNull String reason) {
        if (!queue.isActive()) {
            logw("Ignoring finishReceiverActiveLocked; no active broadcast for " + queue);
            return;
        }

        final int cookie = traceBegin("finishReceiver");
        final ProcessRecord app = queue.app;
        final BroadcastRecord r = queue.getActive();
        final int index = queue.getActiveIndex();
        final Object receiver = r.receivers.get(index);
        // 标记终端传递状态
        setDeliveryState(queue, app, r, index, receiver, deliveryState, reason);
        // 处理anr超时
        if (deliveryState == BroadcastRecord.DELIVERY_TIMEOUT) {
            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);
        }

        // 假设接收方刚刚完成,检查是否满足“waitingFor”条件。
        checkAndRemoveWaitingFor();

        traceEnd(cookie);
    }

设置给定广播的传递状态,然后应用与有序广播相关的任何额外簿记。

    // BroadcastQueueModernImpl.java
    private void setDeliveryState(@Nullable BroadcastProcessQueue queue,
            @Nullable ProcessRecord app, @NonNull BroadcastRecord r, int index,
            @NonNull Object receiver, @DeliveryState int newDeliveryState,
            @NonNull String reason) {
        final int cookie = traceBegin("setDeliveryState");

        // 记住旧状态并应用新状态
        final int oldDeliveryState = getDeliveryState(r, index);
        final boolean beyondCountChanged = r.setDeliveryState(index, newDeliveryState, reason);

        // 当我们改变交付状态作为从队列运行的一部分时,发出任何相关的跟踪结果
        if (queue != null) {
            if (newDeliveryState == BroadcastRecord.DELIVERY_SCHEDULED) {
                queue.traceActiveBegin();
            } else if ((oldDeliveryState == BroadcastRecord.DELIVERY_SCHEDULED)
                    && isDeliveryStateTerminal(newDeliveryState)) {
                queue.traceActiveEnd();
            }
        }

        // 如果我们进入最终状态,我们可能会有内部簿记来更新有序广播
        if (!isDeliveryStateTerminal(oldDeliveryState)
                && isDeliveryStateTerminal(newDeliveryState)) {
            if (DEBUG_BROADCAST
                    && newDeliveryState != BroadcastRecord.DELIVERY_DELIVERED) {
                logw("Delivery state of " + r + " to " + receiver
                        + " via " + app + " changed from "
                        + deliveryStateToString(oldDeliveryState) + " to "
                        + deliveryStateToString(newDeliveryState) + " because " + reason);
            }

            notifyFinishReceiver(queue, app, r, index, receiver);
        }

        //当我们达到新的高水位线时,我们可能能够解锁其他接收者或最终结果
        if (beyondCountChanged) {
            if (r.beyondCount == r.receivers.size()) {
                // 已经派发完成,则回调最终receiver
                scheduleResultTo(r);
            }

            // 我们这里的终端状态可能足以让我们阻塞的另一个进程现在可以运行
            if (r.ordered || r.prioritized) {
                for (int i = 0; i < r.receivers.size(); i++) {
                    if (!isDeliveryStateTerminal(getDeliveryState(r, i)) || (i == index)) {
                        final Object otherReceiver = r.receivers.get(i);
                        final BroadcastProcessQueue otherQueue = getProcessQueue(
                                getReceiverProcessName(otherReceiver),
                                getReceiverUid(otherReceiver));
                        if (otherQueue != null) {
                            otherQueue.invalidateRunnableAt();
                            updateRunnableList(otherQueue);
                        }
                    }
                }
                enqueueUpdateRunningList();
            }
        }

        traceEnd(cookie);
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1099601.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spacedrive:开源跨平台文件管理 | 开源日报 No.57

denoland/deno Stars: 91.2k License: MIT Deno 是一个简单、现代和安全的 JavaScript 和 TypeScript 运行时&#xff0c;使用 V8 引擎并用 Rust 构建。其主要功能包括&#xff1a; 默认情况下具有高度安全性&#xff0c;除非显式启用&#xff0c;否则无法访问文件、网络或环…

docker入门加实战—网络

docker入门加实战—网络 我们运行了一些容器&#xff0c;但是这些容器是否能够进行连通呢&#xff1f;那我们就来试一下。 我们查看一下MySQL容器的详细信息&#xff1a; 主要关注&#xff0c;Networks.bridge.IPAddress属性信息&#xff1a; docker inspect mysql # 或者过…

RT-Thread学习笔记(二):RT-Thread内核

RT-Thread内核 什么是RTOS&#xff1f;RTOS内核包含哪些内容&#xff1f;RT-Thread内核架构RT-Thread系统架构 RT-Thread内核文件RT-Thread系统启动流程RT-Thread 内核配置文件 什么是RTOS&#xff1f;RTOS内核包含哪些内容&#xff1f; RTOS(Real Time Operating System)指的…

PyTorch 深度学习之循环神经网络(基础篇)Basic RNN(十一)

0.Revision: DNN dense 重义层 全连接 RNN处理带有序列的数据 1. What is RNNs? linear layer 1.1 What is RNN? tanh (-1, 1) 1.2 RNN Cell in PyTorch 1.3 How to use RNNCell *先把维度搞清楚 多了一个序列的维度 2. How to use RNN 2.1 How to use RNN - numLayers…

nginx正反向代理,负载均衡

Nginx 正向代理&#xff0c;反向代理 &#xff0c;负载均衡 Nginx有两种代理协议 七层代理&#xff08;http协议&#xff09; 四层代理&#xff08;tcp/udp流量转发&#xff09; 四层代理七层代理概念 四层代理 四层代理&#xff1a;基于tcp/ip协议层的转发代理方式&#…

grid网格布局,比flex方便太多了,介绍几种常用的grid布局属性

使用flex布局的痛点 如果使用justify-content: space-between;让子元素两端对齐&#xff0c;自动分配中间间距&#xff0c;假设一行4个&#xff0c;如果每一行都是4的倍数那没任何问题&#xff0c;但如果最后一行是2、3个的时候就会出现下面的状况&#xff1a; /* flex布局 两…

Android versionCode会变成指定数值加001、002、003等后缀

“活久见”—今天遇到个奇怪的问题&#xff0c;指定的versionCode最终在打包出来的apk中,versionCode变成&#xff08;指定数值 00X的形式&#xff09; 如下所示&#xff1a; 注&#xff1a;当前build.gradle中的versionCode为26 后来搜索代码&#xff0c;发现原来是这个配置导…

系统架构与Tomcat的安装和配置

2023.10.16 今天是学习javaweb的第一天&#xff0c;主要学习了系统架构的相关知识和原理&#xff0c;下载了web服务器软件&#xff1a;Tomcat&#xff0c;并对其进行了配置。 系统架构包括&#xff1a;C/S架构 和 B/S架构。 C/S架构&#xff1a; Client / Server&#xff08;…

052:mapboxGL同一个图层,设置每个feature不同的颜色

第052个 点击查看专栏目录 本示例是介绍演示如何在vue+mapbox中同一个图层,设置每个feature不同的颜色。 这里的数据都是点,通过每个geojson数据的属性中color的值,来同通过get的方式将颜色值挂在到circle-color上。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实…

JavaFX:控件边框设置

JavaFX中控件的边框也可以进行设置。主要有两种方式&#xff0c;一种是Java方式&#xff0c;一种是CSS方式。 JavaFX中控件继承自Region类。setBorder方法用来设置边框属性。 // The border of the Region, which is made up of zero or more BorderStrokes, and zero // or …

Python制作PDF转Word工具(Tkinter+pdf2docx)

一、效果样式 二、核心点 1. 使用pdf2docx完成PDF转换Word 安装pdf2docx可能会报错&#xff0c;安装完成引入from pdf2docx import Converter运行也可能报错&#xff0c;可以根据报错提示看缺少那些库&#xff0c;先卸载pip uninstall xxx,使用pip install python-docx -i htt…

[架构之路-238]:目标系统 - 纵向分层 - 网络通信 - 网络规划与设计框架

目录 一、需求分析 二、网络规划与设计 三、逻辑网络设计 四、物理设计 五、分层网络设计 5.1 接入层交换机 5.2 汇聚层交换机 5.3 核心层交换机 六、网络存储技术 七、IPV6 八、综合布线系统 九、物联网 十、云计算 十一、云存储 一、需求分析 二、网络规划与设…

Hadoop3教程(十五):MapReduce中的Combiner

文章目录 &#xff08;103&#xff09;Combiner概述什么是CombinerCombiner有什么用处Combiner有什么特点如何自定义Combiner &#xff08;104&#xff09;Combiner合并案例实操如何从日志里查看Combiner如果不存在Reduce阶段&#xff0c;会发生什么自定义Combiner的两种方式 参…

error=‘Cannot allocate memory‘ (errno=12)

Bug信息 OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x0000000080000000, 716177408, 0) failed; error=Cannot allocate memory (errno=12)Bug本质原因 服务器内存不足,Java程序无法启动 查看服务器剩余内存 free -h常用的解决思路 减小服务中对JVM的…

基于vue实现滑块动画效果

主要实现&#xff1a;通过鼠标移移动、触摸元素、鼠标释放、离开元素事件来进行触发 创建了一个滑动盒子&#xff0c;其中包含一个滑块图片。通过鼠标按下或触摸开始事件&#xff0c;开始跟踪滑块的位置和鼠标/触摸位置之间的偏移量。然后&#xff0c;通过计算偏移量和起始时的…

2023年10月工作经验及问题整理总结

目录 1.window自带的base64加密解密 2.ElementUI修改鼠标移动到表格的背景色 3.vscode保存时几万个eslint错误 4.Git 拉取Gitee仓库报错&#xff1a;“fatal: unable to access ": Failed to connect to 127.0.0.1 port 1080: Connection r... 4.1本地查看Git是否使用…

Python爬虫-雪球网

前言 本文是该专栏的第8篇,后面会持续分享python爬虫案例干货,记得关注。 地址:aHR0cHM6Ly94dWVxaXUuY29tLw== 需求:根据目标搜索词,获取搜索结果数据 废话不多说,跟着笔者直接往下看详细内容。(附带完整代码) 正文 1. 请求方式和参数分析 使用浏览器打开链接之后,…

【深度学习实验】循环神经网络(四):基于 LSTM 的语言模型训练

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入必要的工具包 1. RNN与梯度裁剪 2. LSTM模型 3. 训练函数 a. train_epoch b. train 4. 文本预测 5. GPU判断函数 6. 训练与测试 7. 代码整合 经验是智慧之父&#xff0c;记忆…

详解 ElasticSearch 集群搭建

&#x1f339; 以上分享 ElasticSearch 安装部署&#xff0c;如有问题请指教写。&#x1f339;&#x1f339; 如你对技术也感兴趣&#xff0c;欢迎交流。&#x1f339;&#x1f339;&#x1f339; 如有需要&#xff0c;请&#x1f44d;点赞&#x1f496;收藏&#x1f431;‍&a…

【微信小程序】6天精准入门(第2天:小程序的视图层、逻辑层、事件系统及页面生命周期)

一、视图层 View 1、什么是视图层 框架的视图层由 WXML 与 WXSS 编写&#xff0c;由组件来进行展示。将逻辑层的数据反映成视图&#xff0c;同时将视图层的事件发送给逻辑层。WXML(WeiXin Markup language) 用于描述页面的结构。WXS(WeiXin Script) 是小程序的一套脚本语言&am…