android U广播详解(二)

news/2024/10/17 20:28:20/

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,表明其他事件可能会被解除阻塞。@CheckResultboolean 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的状态变化可能会让我们达到一个新的beyondCountfinal 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} 的结果是否对接收方进行了优先排序。@VisibleForTestingstatic 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.javaprivate @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所在队列的runnablepublic 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() {// 普通优先级大于负载,但是限制为10final ArrayDeque<SomeArgs> nextNormal = queueForNextBroadcast(mPending, mPendingOffload,mActiveCountConsecutiveNormal, constants.MAX_CONSECUTIVE_NORMAL_DISPATCHES); //10// 紧急优先级大于普通,限制为3final ArrayDeque<SomeArgs> nextBroadcastQueue = queueForNextBroadcast(mPendingUrgent, nextNormal,mActiveCountConsecutiveUrgent, constants.MAX_CONSECUTIVE_URGENT_DISPATCHES); //3return 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@Overridepublic 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 immediatelyif (r.receivers.isEmpty()) {scheduleResultTo(r);notifyFinishBroadcast(r);}traceEnd(cookie);}
应用对应的传递组策略
 // BroadcastQueueModernImpl.javaprivate 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.javapublic 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.javaprivate 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.javaprivate 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; //-120smRunnableAtReason = REASON_CONTAINS_FOREGROUND;// 源于用户交互广播数量 > 0} else if (mCountInteractive > 0) {mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS; //-120smRunnableAtReason = REASON_CONTAINS_INTERACTIVE;// 广播由root/shell/active instrument发送数量  > 0} else if (mCountInstrumented > 0) {mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS; //-120smRunnableAtReason = REASON_CONTAINS_INSTRUMENTED;// 当前进程处于instrumented} else if (mProcessInstrumented) {mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS; //-120smRunnableAtReason = REASON_INSTRUMENTED;// PROCESS_STATE_TOP top app} else if (mUidForeground) {mRunnableAt = runnableAt + constants.DELAY_FOREGROUND_PROC_MILLIS; //-120smRunnableAtReason = 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) {// 广播有设置deferUntilActiveif (r.deferUntilActive) {// 所有排队的广播都是可推迟的,deferif (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; //120smRunnableAtReason = REASON_CACHED;}}} else {// This record isn't deferrablemRunnableAt = runnableAt + constants.DELAY_CACHED_MILLIS;// 120smRunnableAtReason = REASON_CACHED;}} else if (mCountResultTo > 0) {mRunnableAt = runnableAt;mRunnableAtReason = REASON_CONTAINS_RESULT_TO;// 当前进程的为manifest的receiver数量 > 0} else {mRunnableAt = runnableAt + constants.DELAY_NORMAL_MILLIS; // +500msmRunnableAtReason = 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);}// 可运行数量-1avail--;// Move to considering next runnable queuequeue = nextQueue;}// 更新adjif (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提升到11if (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 {// 检查状态是否是activecheckState(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_SKIPPEDfinishReceiverActiveLocked(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@Overridepublic 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,后台60sfinal 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 testmService.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);// 设置传递状态为SCHEDULEDsetDeliveryState(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// 如果无序广播,直接标记分发状态为DELIVEREDif (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@Overridepublic 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.javaprivate 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.javaprivate 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()) {// 已经派发完成,则回调最终receiverscheduleResultTo(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.ppmy.cn/news/1158596.html

相关文章

Constitutional AI

用中文以结构树的方式列出这篇讲稿的知识点&#xff1a; Although you can use a reward model to eliminate the need for human evaluation during RLHF fine tuning, the human effort required to produce the trained reward model in the first place is huge. The label…

短视频剪辑矩阵系统开发解决的市场工具难点?

短视频剪辑矩阵系统开发源码----源头搭建 一、源码技术构建源码部署搭建交付之---- 1.需要协助系统完成部署、接口全部正常接入、系统正常运行多久&#xff1f;7个工作日 2.需要准备好服务器以及备案域名 3.短视频SEO模块一年项目带宽&#xff0c;带宽最低要求10M&#xff0c;…

ts使用记录

1、安装&#xff1a;通过管理员权权限使用cmd或者终端全局安装 npm install -g typescript2、运行&#xff1a; 可以通过tsc命令运行hello.ts文件 tsc hello.ts3、通过vscode的run code插件去右键运行 1.先安装插件run code 2.全局安装ts-node&#xff0c;npm install -g ts-n…

基于 Debian 稳定分支发行版的Zephix 7 发布

导读Zephix 是一个基于 Debian 稳定版的实时 Linux 操作系统。它可以完全从可移动媒介上运行&#xff0c;而不触及用户系统磁盘上存储的任何文件。 Zephix 是一个基于 Debian 稳定版的实时 Linux 操作系统。它可以完全从可移动媒介上运行&#xff0c;而不触及用户系统磁盘上存…

【Vue】vue在Windows平台IIS的部署

系列文章 【C#】IIS平台下&#xff0c;WebAPI发布及异常处理 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/126539836 【Vue】vue2与WebApi跨域CORS问题 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/133808959 文章目…

python find函数

一、 find函数作用&#xff1a; 用于判断字符串是否含有子串&#xff1b; 若包含子串&#xff0c;则返回所在字符串第一次出现的位置索引 若不包含子串&#xff0c;则返回-1 二、find函数语法&#xff1a; 字符串.find(self, sub, startNone, endNone) 源码&#xff1a; sub&a…

Debian衍生桌面项目SpiralLinux12.231001发布

导读SpiralLinux 是一个从 Debian 衍生出来的桌面项目&#xff0c;其重点是在所有主要桌面环境中实现简洁性和开箱即用的可用性。 spiral Linux 是为刚接触 Linux 世界的人们量身定制的发行版。这是 GeckoLinux 开发人员的创意&#xff0c;他更喜欢保持匿名。尽管他不愿透露姓…

机器学习——学习路线

一、Pytorch Pytorch安装Pytorch基础Pytorch项目实践 二、机器学习 1、监督学习 线性回归 均方差损失推导梯度下降法归一化正则化Lasso回归&岭回归多项式回归 线性分类 逻辑回归多标签分类交叉熵损失Softmax回归SVM支持向量机 决策树 剪枝与后剪枝随机森林Adaboost…