关于Android Broadcast 的一桩血案

1 案发现场

之前一直使用Broadcast都仅仅局限于简单调用,疑惑是根据需求选择发送方式,亦或是看心情决定是什么方式注册,直到今天,发生了一个关于广播的血案,事情的经过是这样:嫌疑人A发送了一个无序广播,通知各位听众某某事情,听众B举报别人听到了,它没听见,A大喊冤枉,我都广播了,并且是不分高低贵贱的无序广播,你没收到是你的问题,是不是你脑袋卡壳阻塞在哪里,B一听急了,我干其它事好好的,怎么就是没收到?看似一桩悬案就要诞生了!

2 案情分析

AB各有理,看似毫无头绪,A说它发了,B说它收不到,那问题只能是中间环节出了纰漏,不经纳闷了,中间能出什么纰漏?异步的基于消息机制的Android身上,什么都有可能。这个貌似一发一收的问题,归根于中间环节,那就一定是哪块阻塞了,无序广播怎么会阻塞?无序广播只是说平等对待,至于它背地里做了什么?所以指不定就是无序广播发送过程中阻塞在了哪里?不信,B可以多等等,如果是发送过程阻塞在哪里,那阻塞的地方肯定发生ANR,时间到了,B自然会收到,只是时间长短问题!!!

3 事发经过

1) A调用调用Context.sendBroadcast();进入Context类,发现它是个抽象类,实现位于ContextImpl

2) ContextImpl中的sendBroadcast()主要做了以下工作:

            ActivityManager.getService().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
                    options, false, false, getUserId());

可以看到ContextImpl把工作扔给AMS

3) AMS中的broadcastIntent()主要做了以下工作:

            int res = broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null,
                    intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                    requiredPermissions, appOp, bOptions, serialized, sticky,
                    callingPid, callingUid, userId);

4) AMS中的broadcastIntentLocked()主要做了以下工作

        // 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);
        }
        if (intent.getComponent() == null) {
            // 查询动态广播
            ...
        }

        ...

        int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
        if (!ordered && NR > 0) {
            ...
            //打包为BroadcastRecord
            BroadcastRecord r = new BroadcastRecord(...);
            ...
            if (!replaced) {
                //发送动态广播
                queue.enqueueParallelBroadcastLocked(r); 
                queue.scheduleBroadcastsLocked();
            }
            registeredReceivers = null;
            NR = 0;
        }

        ...

        if ((receivers != null && receivers.size() > 0)
                || resultTo != null) {
            BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(...);
                ...
            }  else {
                // 发送静态广播
                queue.enqueueOrderedBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }

貌似从上面代码中只能得到的信息是发送的动态广播比静态广播早!!!和案情也没什么关系,但是可以得到如下三个信息:

     //广播载体 BroadcastRecord

              //发送动态广播
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();

              // 发送静态广播
                queue.enqueueOrderedBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();

明显可以看到动态广播和静态广播走的不同分支:

动态广播 -> queue.enqueueParallelBroadcastLocked(r); // 直观看:Paralle是并发,不会阻塞

静态广播    -> queue.enqueueOrderedBroadcastLocked(r);  // 直观看.Ordered,串行,可能发生阻塞

之前一直认为有序、无序、粘性才会影响发送,有序由于等客户端响应,可能造成阻塞,现在看来注册方式也会导致发送广播时走到不同分支,有可能造成阻塞!!!

案件终于真想大白!!!小小嘚瑟下,NND!!!

4 案情总结

初入问题,先入为主,以为A发送的无序广播,不有由于听众某某某的阻塞造成B收不到广播!!!但忽略了一点,注册方式其实也是有可能对广播造成影响!!!

1)有序广播可能由于一个接收端的阻塞造成其它监听者没收到!

2)无序广播时,静态注册监听广播是串行的,由于广播Arraylist中BroadRecord的增多而导致发送阻塞,静态方式注册的该广播的接收者会都收不到广播。动态注册的接收者可以收到广播

a: 发送端串行广播太多

b:某个接收端阻塞

 动态静态
有序a、b
无序×a
粘性×a

******************************************************************************************************************************************

强列推荐:

不管发送方式、注册方式,尽量别用静态注册,接收的慢不说,还可能造成系统性能不足导致的发送端串行广播阻塞;

*******************************************************************************************************************************************

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值