BroadcastReceiver机制-Android12

Posted xhBruce

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BroadcastReceiver机制-Android12相关的知识,希望对你有一定的参考价值。

BroadcastReceiver机制

android12-release
查看android developer 广播概览


1. 广播概览

  一般来说,广播可作为跨应用和普通用户流之外的消息传递系统。应用可以注册接收特定的广播。广播发出后,系统会自动将广播传送给同意接收这种广播的应用。
  广播(Broadcast)分为广播发送和广播接收两个过程,其中广播接收者BroadcastReceiver便是Android四大组件之一。

BroadcastReceiver注册方式分为两类:

  1. 静态广播接注册:通过AndroidManifest.xml的标签来申明的BroadcastReceiver。(受 Android 8.0(API 级别 26)后台执行限制的影响,以 API 级别 26 或更高级别为目标的应用无法再在其清单中注册用于隐式广播的广播接收器。

  2. 动态广播接注册:通过AMS.registerReceiver()方式注册的BroadcastReceiver,动态注册可在不需要时通过unregisterReceiver()取消注册。


广播发送方式可分为三类:

  1. 普通广播:sendBroadcast(Intent) 可并行处理,方法会按随机的顺序向所有接收器发送广播。这称为常规广播。这种方法效率更高,但也意味着接收器无法从其他接收器读取结果,无法传递从广播中收到的数据,也无法中止广播。

  2. 有序广播:sendOrderedBroadcast(Intent, String) 串行处理,一次向一个接收器发送广播。当接收器逐个顺序执行时,接收器可以向下传递结果,也可以完全中止广播,使其不再传递给其他接收器。接收器的运行顺序可以通过匹配的 intent-filter 的 android:priority 属性来控制;具有相同优先级的接收器将按随机顺序运行。

  3. Sticky广播:通过sendStickyBroadcast()发送

2. 注册广播

2.1 时序图

用户调用registerReceiver()方法,而Activity/Service都间接继承于Context抽象类,真正干活是交给ContextImpl类。

2.2 allSticky队列

  • allSticky.add(intent) 匹配成功,则将给intent添加到allSticky队列
  • 当IIntentReceiver为空,则直接返回第一个sticky Intent

2.3 创建BroadcastFilter对象,并添加到接收者队列ReceiverList

  • ReceiverList rl 接收者队列
  • mReceiverResolver.addFilter(bf) 添加ReceiverResolver队列,记录着所有已注册的广播

2.4 所有匹配该filter的sticky广播执行入队操作

  • broadcastQueueForIntent(intent) 获得mFgBroadcastQueuemBgBroadcastQueue
  • queue.enqueueParallelBroadcastLocked(r)将BroadcastRecord加入到并行广播队列mParallelBroadcasts
  • queue.scheduleBroadcastsLocked() 调度广播,发送BROADCAST_INTENT_MSG消息,触发处理下一个广播

3. 发送广播

3.1 三方方式发送参数

  • boolean serialized, boolean sticky 传递到broadcastIntentLocked中boolean ordered, boolean sticky
发送serialized/orderdedsticky
sendBroadcastfalsefalse
sendOrderedBroadcasttruefalse
sendStickyBroadcastfalsetrue

3.2 增加sticky广播

  • 增加sticky广播处理 mStickyBroadcastsstickieslist
// Add to the sticky list if requested.
if (sticky) 
    // ... ...
    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
    if (stickies == null) 
        stickies = new ArrayMap<>();
        mStickyBroadcasts.put(userId, stickies);
    
    ArrayList<Intent> list = stickies.get(intent.getAction());
    if (list == null) 
        list = new ArrayList<>();
        stickies.put(intent.getAction(), list);
    
    final int stickiesCount = list.size();
    int i;
    for (i = 0; i < stickiesCount; i++) 
        if (intent.filterEquals(list.get(i))) 
            // This sticky already exists, replace it.
            list.set(i, new Intent(intent));
            break;
        
    
    if (i >= stickiesCount) 
        list.add(new Intent(intent));
    

3.3 查询receivers和registeredReceivers

  • receivers:记录着匹配当前intent的所有静态注册广播接收者;receivers = collectReceiverComponents()通过PKMS根据Intent查询相应的静态receivers。
  • registeredReceivers:记录着匹配当前的所有动态注册的广播接收者;mReceiverResolver.queryIntent() 查询相应的动态注册的广播。
// Figure out who all will receive this broadcast.
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
// Need to resolve the intent to interested receivers...
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
         == 0) 
    receivers = collectReceiverComponents(
            intent, resolvedType, callingUid, users, broadcastAllowList);

if (intent.getComponent() == null) 
    if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) 
        // Query one target user at a time, excluding shell-restricted users
        for (int i = 0; i < users.length; i++) 
            if (mUserController.hasUserRestriction(
                    UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) 
                continue;
            
            List<BroadcastFilter> registeredReceiversForUser =
                    mReceiverResolver.queryIntent(intent,
                            resolvedType, false /*defaultOnly*/, users[i]);
            if (registeredReceivers == null) 
                registeredReceivers = registeredReceiversForUser;
             else if (registeredReceiversForUser != null) 
                registeredReceivers.addAll(registeredReceiversForUser);
            
        
     else 
        registeredReceivers = mReceiverResolver.queryIntent(intent,
                resolvedType, false /*defaultOnly*/, userId);
    

3.4 处理并序广播

  • broadcastQueueForIntent(intent) 根据intent的flag来判断前台队列或者后台队列
  • queue.enqueueParallelBroadcastLocked(r) 将BroadcastRecord加入到并行广播队列mParallelBroadcasts
  • queue.scheduleBroadcastsLocked() 处理广播
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) 
    // If we are not serializing this broadcast, then send the
    // registered receivers separately so they don't wait for the
    // components to be launched.
    if (isCallerSystem) 
        checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                isProtectedBroadcast, registeredReceivers);
    
    final BroadcastQueue queue = broadcastQueueForIntent(intent);
    BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
            callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
            requiredPermissions, excludedPermissions, appOp, brOptions, registeredReceivers,
            resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId,
            allowBackgroundActivityStarts, backgroundActivityStartsToken,
            timeoutExempt);
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
    final boolean replaced = replacePending
            && (queue.replaceParallelBroadcastLocked(r) != null);
    // Note: We assume resultTo is null for non-ordered broadcasts.
    if (!replaced) 
        queue.enqueueParallelBroadcastLocked(r);
        queue.scheduleBroadcastsLocked();
    
    registeredReceivers = null;
    NR = 0;

3.5 将registeredReceivers合并到receivers

3.6 处理串行广播

if ((receivers != null && receivers.size() > 0)
        || resultTo != null) 
    BroadcastQueue queue = broadcastQueueForIntent(intent);
    BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
            callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
            requiredPermissions, excludedPermissions, appOp, brOptions,
            receivers, resultTo, resultCode, resultData, resultExtras,
            ordered, sticky, false, userId, allowBackgroundActivityStarts,
            backgroundActivityStartsToken, timeoutExempt);

    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);

    final BroadcastRecord oldRecord =
            replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
    if (oldRecord != null) 
        // Replaced, fire the result-to receiver.
        if (oldRecord.resultTo != null) 
            final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);
            try 
                oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
                        oldRecord.intent,
                        Activity.RESULT_CANCELED, null, null,
                        false, false, oldRecord.userId);
             catch (RemoteException e) 
                Slog.w(TAG, "Failure ["
                        + queue.mQueueName + "] sending broadcast result of "
                        + intent, e);

            
        
     else 
        queue.enqueueOrderedBroadcastLocked(r);
        queue.scheduleBroadcastsLocked();
    

4. 发送广播小结

Sticky广播:

  1. 广播注册过程处理AMS.registerReceiver,开始处理粘性广播
  2. 创建BroadcastRecord对象
  3. 添加到mParallelBroadcasts队列
  4. 执行queue.scheduleBroadcastsLocked

并行广播:

  1. 广播发送过程处理
  2. 只有动态注册的mRegisteredReceivers才会并行处理
  3. 会创建BroadcastRecord对象
  4. 并添加到mParallelBroadcasts队列
  5. 然后执行queue.scheduleBroadcastsLocked

串行广播:

  1. 广播发送广播处理
  2. 所有静态注册的receivers以及动态注册mRegisteredReceivers合并到一张表处理
  3. 创建BroadcastRecord对象
  4. 并添加到mOrderedBroadcasts队列
  5. 然后执行queue.scheduleBroadcastsLocked

5. scheduleBroadcastsLocked处理

查看下图,不做代码展示说明:

  • scheduleBroadcastsLocked 执行 processNextBroadcast(true)
  • deliverToRegisteredReceiverLocked 通过IApplicationThread最终会调用注册的receiver.onReceive(mContext, intent)方法
  • 先处理并行广播mParallelBroadcasts,在处理串行广播,此时就广播超时监听处理broadcastTimeoutLocked
  • cancelBroadcastTimeoutLocked()取消广播耗时处理;广播ANR查看: ANR Broadcast TimeOut 超时判断
  • 动态注册广播BroadcastFilter处理deliverToRegisteredReceiverLocked
  • 静态广播处理processCurBroadcastLocked
  • 本次广播处理完成都会执行scheduleBroadcastsLocked进行下一条广播处理

以上是关于BroadcastReceiver机制-Android12的主要内容,如果未能解决你的问题,请参考以下文章

BroadcastReceiver机制-Android12

BroadcastReceiver--Android广播机制

Android——BroadcastReceiver广播机制(自定义广播)

Android——BroadcastReceiver广播机制(自定义广播)

Android——BroadcastReceiver广播机制(自定义广播)

BroadcastReceiver源码分析