type
status
date
slug
summary
tags
category
icon
password

广播实现机制

先思考几个问题:
  • 广播注册到了什么地方?
  • 当发送广播的时候,是谁在分发广播?
  • BroadcastReceiver是如何接收到广播的?

广播注册

从 Activity或者Context的registerReceiver()方法一路查看调用,可知最终注册实际上是在ActivityManagerService里进行的.
注册到了一个成员变量中:
final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();
这里的ReceiverList实际上就是BroadcastFilter(IntentFilter的继承类)的ArrayList封装.
而IBinder则是IItentReceiver,是一个AIDL定义的接口,在 LoadedApkReceiverDispatcher中有相应的代理实现类IntentReceiver.
BroadcastReceiver会被传递并封装到IItentReceiver中.
这样上面说的map其实也就清楚了: key ~= BroadcastReceiver, value ~= List<IntentFilter>

广播发送

sendBroadcast(Intent intent)出发,最终依然是由ActivityManagerService#broadcastIntent()方法处理的.
这里大概几个步骤:
  1. 检查Intent对象合法性,是否有问题,然后封装一些中间类传递数据
  1. 检查Intent是否为一些系统级的广播ACTION,然后发出Handler消息做对应的处理
  1. sticky广播相关的逻辑
  1. 查询处理静态注册可以接收的reciever
  1. 通过IntentResolver查询符合要求的BroadcastFilter
  1. 获取对应的BroadcastQueue对象(有三种,前台,后台,卸载),并将对应的Intent封装到BroadcastRecord中,并添加到BroadcastQueue中(queue.enqueueOrderedBroadcastLocked(r);)
  1. 开始BroadcastQueue的调度,这里需要注意的是分为两种调度:
      • 并行: enqueueParallelBroadcastLocked(r)
      • 串行: enqueueOrderedBroadcastLocked(r)

广播分发/调度

BroadcastReceiver中有:
public void scheduleBroadcastsLocked() { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts [" + mQueueName + "]: current=" + mBroadcastsScheduled); if (mBroadcastsScheduled) { return; } mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this)); mBroadcastsScheduled = true; } private final class BroadcastHandler extends Handler { public BroadcastHandler(Looper looper) { super(looper, null, true); } @Override public void handleMessage(Message msg) { switch (msg.what) { // 接收调度消息 case BROADCAST_INTENT_MSG: { if (DEBUG_BROADCAST) Slog.v( TAG_BROADCAST, "Received BROADCAST_INTENT_MSG [" + mQueueName + "]"); // 此处是关键 processNextBroadcast(true); } break; case BROADCAST_TIMEOUT_MSG: { synchronized (mService) { broadcastTimeoutLocked(true); } } break; } } }
可以看到这里其实就是通过Handler Message机制进行调度的.
调度的逻辑里会区分当前进程是否已经正在运行,广播是串行还是并行的,然后进入各自的调度逻辑.
这里挑一个串行的调度逻辑分析下,并行的逻辑也是大同小异的.
串行分发逻辑最终都会通过oneway binder调用IIntentReceiverperformReceive()方法去执行;
正如前面所说,在LoadedApk.ReceiverDispathcer  中有:
public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { final Args args = new Args(intent, resultCode, data, extras, ordered, sticky, sendingUser); if (intent == null) { Log.wtf(TAG, "Null intent received"); } else { if (ActivityThread.DEBUG_BROADCAST) { int seq = intent.getIntExtra("seq", -1); Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq + " to " + mReceiver); } } // intent一般不为null,因此会执行args中的runnbale if (intent == null || !mActivityThread.post(args.getRunnable())) { if (mRegistered && ordered) { IActivityManager mgr = ActivityManager.getService(); if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, "Finishing sync broadcast to " + mReceiver); args.sendFinished(mgr); } } }
getRunnable()方法中有:
ClassLoader cl = mReceiver.getClass().getClassLoader(); intent.setExtrasClassLoader(cl); intent.prepareToEnterProcess(); setExtrasClassLoader(cl); receiver.setPendingResult(this); receiver.onReceive(mContext, intent); ... if (receiver.getPendingResult() != null) { finish(); }
显而易见的,又是通过反射获取Receiver的对象并调用onReceive()方法.
执行完毕或者失败,发送执行完毕消息.

广播类型

  • 普通广播/有序广播/粘性广播
    • 普通广播随机顺序发送广播,有序广播串行发送数据,粘性广播不安全已被废弃
  • 串行/并行广播
    • 静态广播接收器不管广播是否为并行,都按照串行处理
      动态广播接收器遇到串行广播则按照串行处理,遇到并行广播则按照并行处理.

接收顺序问题

  • 广播发送时本身的优先级(比如有序广播)
  • 动态广播先于静态广播接收器收到广播

本地广播

主要是调用LocalBroadcastManager去使用,与系统广播的各种机制其实没什么关系,只是利用了一下BroadcastReceiver这个抽象类而已,其本质就是观察者模式 + Handler消息传递.因此在应用内传递效率颇高.
而且它的实现在支持包中,并不在源码中,目前是在androidx的支持包中.
看一段代码就明白了:
void executePendingBroadcasts() { while (true) { final BroadcastRecord[] brs; synchronized (mReceivers) { final int N = mPendingBroadcasts.size(); if (N <= 0) { return; } brs = new BroadcastRecord[N]; mPendingBroadcasts.toArray(brs); mPendingBroadcasts.clear(); } for (int i=0; i<brs.length; i++) { final BroadcastRecord br = brs[i]; final int nbr = br.receivers.size(); for (int j=0; j<nbr; j++) { final ReceiverRecord rec = br.receivers.get(j); if (!rec.dead) { rec.receiver.onReceive(mAppContext, br.intent); } } } } }

参考文章

  1. https://developer.android.com/guide/components/broadcasts
Android中的HandlerKotlin中的CoroutineScope
姜康
姜康
一个软件工程师
公告
type
status
date
slug
summary
tags
category
icon
password
🎉博客网站重新制作了🎉
👏欢迎更新体验👏