广播的发送和接受过程是怎样的

最近一直在研究学习Android broadcast 。这里就主要讲解一下广播的发送和接受过程

当通过send方法来发送广播时,AMS会查找出匹配的广播接收者并将广播发送给他们处理。广播的发送有几种类型:普通广播,有序广播和粘性广播。这里分析下普通广播的实现。

广播的发送和接收。其本质是一个过程的两个阶段。广播的发送仍然开始于ContextWrappersendBroadcast方法,之所以不是Context,那是因为ContextsendBroadcast是一个抽象方法。和广播的注册过程一样ContextWrappersendBroadcast方法仍然什么都不做,只是把事情交给ContextImpl去处理,ContextImplsendBroadcast方法源码如下:

public void sendBroadcast(Intent intent) {

  warnIfCallingFromSystemProcess();

  String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());

  try {

    intent.prepareToLeaveProcess();

    ActivityManagerNative.getDefault().broadcastIntent(

      mMainThread.getApplicationThread(), intent, resolvedType, null,

      Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false,

      getUserId());

  } catch (RemoteException e) {

  }

}

它直接向AMS发起了一个异步请求用于发送广播。那么AMSbroadcastIntent方法的源码如下:

public final int broadcastIntent(IApplicationThread caller,

            Intent intent, String resolvedType, IIntentReceiver resultTo,

            int resultCode, String resultData, Bundle map,

            String requiredPermission, boolean serialized, boolean sticky, int userId) {

        synchronized(this) {

            intent = verifyBroadcastLocked(intent);

            

            final ProcessRecord callerApp = getRecordForAppLocked(caller);

            final int callingPid = Binder.getCallingPid();

            final int callingUid = Binder.getCallingUid();

            final long origId = Binder.clearCallingIdentity();

            int res = broadcastIntentLocked(callerApp,

                    callerApp != null ? callerApp.info.packageName : null,

                    intent, resolvedType, resultTo,

                    resultCode, resultData, map, requiredPermission, serialized, sticky,

                    callingPid, callingUid, userId);

            Binder.restoreCallingIdentity(origId);

            return res;

        }

    }

从代码上看,broadcastIntent调用了broadcastIntentLocked方法,但在AMSbroadcastIntentLocked方法里有这么一句:

    // By default broadcasts do not go to stopped apps.

    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

这表示在Android5.0下,默认情况下广播不会发送给已经停止的应用。FLAG_EXCLUDE_STOPPED_PACKAGES的含义是表示 不包含已经停止的应用,这个时候广播不会发送给已经停止的应用。

broadcastIntentLocked的内部,会根据intent-filter查找出匹配的广播接收者并经过一系列的条件过滤,最终会将满足条件的广播接收者添加到BroadcastQueue中,接着BroadcastQueue将会广播发送给相应的广播接收者。

if ((receivers != null && receivers.size() > 0)

                || resultTo != null) {

            BroadcastQueue queue = broadcastQueueForIntent(intent);

            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,

                    callerPackage, callingPid, callingUid, requiredPermission,

                    receivers, resultTo, resultCode, resultData, map, ordered,

                    sticky, false);

            if (DEBUG_BROADCAST) Slog.v(

                    TAG, "Enqueueing ordered broadcast " + r

                    + ": prev had " + queue.mOrderedBroadcasts.size());

            if (DEBUG_BROADCAST) {

                int seq = r.intent.getIntExtra("seq", -1);

                Slog.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);

            }

            boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);

            if (!replaced) {

                queue.enqueueOrderedBroadcastLocked(r);

                queue.scheduleBroadcastsLocked();

            }

        }

下面看下BroadcastQueue中广播的发送过程的实现。如下所示:

 public void scheduleBroadcastsLocked() {

            if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["

                    + mQueueName + "]: current="

                    + mBroadcastsScheduled);

            if (mBroadcastsScheduled) {

                return;

            }

            mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));

            mBroadcastsScheduled = true;

        }

BroadcastQueuescheduleBroadcastsLocked方法并没有立即发送广播,而是发送了一个BROADCAST_INTENT_MSG类型的消息,BroadcastQueue收到消息后会调用processNextBroadcast方法,BroadcastQueueprocessNextBroadcast方法对普通广播的处理方式如下:

// First, deliver any non-serialized broadcasts right away.

                while (mParallelBroadcasts.size() > 0) {

                    r = mParallelBroadcasts.remove(0);

                    r.dispatchTime = SystemClock.uptimeMillis();

                    r.dispatchClockTime = System.currentTimeMillis();

                    final int N = r.receivers.size();

                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["

                            + mQueueName + "] " + r);

                    for (int i=0; i<N; i++) {

                        Object target = r.receivers.get(i);

                        if (DEBUG_BROADCAST)  Slog.v(TAG,

                                "Delivering non-ordered on [" + mQueueName + "] to registered "

                                + target + ": " + r);

                        deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);

                    }

                    addBroadcastToHistoryLocked(r);

                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["

                            + mQueueName + "] " + r);

                }

可以看到,无序广播存储在mParallelBroadcasts中,系统会遍历mParallelBroadcasts并将其中的广播发送给它们所有接收者,具体的发送过程是通过deliverToRegisteredReceiverLocked方法来实现的。

最终呢,会调用ApplicationThreadscheduleRegisteredReceiver的实现比较简单,它通过InnerReceiver来实现广播的接收。然后InnerReceiverperformReceive方法会调用LoadedApk.ReceiverDispatcherPerformReceive方法。最终会回调到receiver.onReceive()这个方法。

很显然,这个时候BroadcastReceiveronReceive方法被执行了,也就是说应用收到广播了,同时,onReceive方法是在广播接收者的主线程中被调用,所以不能做耗时操作,因为是在ApplicationThread的主线程上执行的。

 

 

 

 

文章来自:博客园/cryAllen

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值