注册

调用者进程

  1. public Intent registerReceiver(IApplicationThread caller, String callerPackage,
  2. IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
  3. int flags)
  • caller — 调用者进程的ApplicationThread, 在ActivityThread被创建时创建, 继承 IApplicationThread.Stub

    • ActivityThread#ApplicationThread
  • receiver — 广播接收者的回调接口,也是binder通信的关键回调接口, 位于LoadedApk#ReceiverDispatcher#InnerReceiver , 继承于 InnerReceiver#Stub

    • ContextImpl#registerReceiverInternal

    • new LoadedApk.ReceiverDispatcher()

    • mIIntentReceiver = new InnerReceiver(…);

system_server进程

ActivityManager.getService().registerReceiver(
        mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
        broadcastPermission, userId, flags)

中间的调度过程可以参见此链接

ProcessRecord

每个app进程创建时,都会在AMS中存储,且存储的实体就是 ProcessRecord,代表一个进程信息,存放在ArrayList mLruProcesses 中。如果没缓存,则会通过以下方法去创建AMS#getRecordForAppLocked

final IBinder threadBinder = thread.asBinder();
final ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();
for (int i = pmap.size()-1; i >= 0; i--) {
    final SparseArray<ProcessRecord> procs = pmap.valueAt(i);
    for (int j = procs.size()-1; j >= 0; j--) {
        final ProcessRecord proc = procs.valueAt(j);
        if (proc.thread != null && proc.thread.asBinder() == threadBinder) {
            Slog.wtf(TAG, "getRecordForApp: exists in name list but not in LRU list: "
                    + proc);
            return proc;
        }
    }
}

�mRegisteredReceivers

final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();

存放该IIntentReceiver 对应的广播接受者列表

ReceiverList 本身是一个ArrayList,存储 �BroadcastFilter 对象

ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
    rl = new ReceiverList(this, callerApp, callingPid, callingUid,
            userId, receiver);
    if (rl.app != null) {
        rl.app.receivers.add(rl);
    } else {
。。    
            receiver.asBinder().linkToDeath(rl, 0);
        } catch (RemoteException e) {
            return sticky;
        }
        rl.linkedToDeath = true;
    }
    mRegisteredReceivers.put(receiver.asBinder(), rl);
} 
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
        permission, callingUid, userId, instantApp, visibleToInstantApps);
rl.add(bf);

�在BroadcastQueue中有两个广播队列mParallelBroadcasts,mOrderedBroadcasts,数据类型都为ArrayList:

 //所有匹配该filter的sticky广播执行入队操作
        //如果没有使用sendStickyBroadcast,则allSticky=null。
        if (allSticky != null) {
            ArrayList receivers = new ArrayList();
            receivers.add(bf);

            final int stickyCount = allSticky.size();
            for (int i = 0; i < stickyCount; i++) {
                Intent intent = allSticky.get(i);
                //根据intent返回前台或后台广播队列【见2.5.3】
                BroadcastQueue queue = broadcastQueueForIntent(intent);
                //创建BroadcastRecord
                BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                        null, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers,
                        null, 0, null, null, false, true, true, -1);
                //该广播加入到并行广播队列
                queue.enqueueParallelBroadcastLocked(r);
                //调度广播,发送BROADCAST_INTENT_MSG消息,触发处理下一个广播。
                queue.scheduleBroadcastsLocked();
            }
        }

mParallelBroadcasts:并行广播队列,可以立刻执行,而无需等待另一个广播运行完成,该队列只允许动态已注册的广播,从而避免发生同时拉起大量进程来执行广播,前台的和后台的广播分别位于独立的队列。
mOrderedBroadcasts:有序广播队列,同一时间只允许执行一个广播,该队列顶部的广播便是活动广播,其他广播必须等待该广播结束才能运行,也是独立区别前台的和后台的广播

小结

  1. 传递的参数为广播接收者BroadcastReceiver和Intent过滤条件IntentFilter,也就是BroadcastFilter

  2. 创建对象LoadedApk.ReceiverDispatcher.InnerReceiver,该对象继承于IIntentReceiver.Stub;

  3. 通过AMS把当前进程的ApplicationThread和InnerReceiver对象的代理类,注册登记到system_server进程;

  4. 当广播receiver没有注册过,则创建广播接收者队列ReceiverList,该对象继承于ArrayList, 并添加到AMS.mRegisteredReceivers(已注册广播队列);

  5. 创建BroadcastFilter,并添加到AMS.mReceiverResolver;

  6. 将BroadcastFilter添加到该广播接收者的ReceiverList

另外,当注册的是Sticky广播:

  • 创建BroadcastRecord,并添加到BroadcastQueue的mParallelBroadcasts(并行广播队列),注册后调用AMS来尽快处理该广播。

  • 根据注册广播的Intent是否包含FLAG_RECEIVER_FOREGROUND,则mFgBroadcastQueue

发送

public final int broadcastIntent(IApplicationThread caller,
        Intent intent, String resolvedType, IIntentReceiver resultTo,
        int resultCode, String resultData, Bundle resultExtras,
        String[] requiredPermissions, int appOp, Bundle bOptions,
        boolean serialized, boolean sticky, int userId)

BroadcastIntent()方法有两个布尔参数serialized和sticky来共同决定是普通广播,有序广播,还是Sticky广播,参数如下:

类型 serialized sticky
sendBroadcast false false
sendOrderedBroadcast true false
sendStickyBroadcast false true

有序广播 - 可操作!可以通过 priority来指定优先级,A -> B -> C 优先级高的先获取广播,并且可以通过 setResult***() 等方法来修改广播内容,下一个广播B可以通过getResult***() 获取修改的内容。A可以通过
abortBroadcast() 终止广播,这样B,C就无法获取此广播

Sticky广播 - 会一直滞留,当有匹配此广播的广播接收器被注册后,该广播接收器就会收到此条信息。使用此函数需要发送广播时,需要获得BROADCAST_STICKY权限. 即使已经有广播接收器处理了该广播,当再有匹配的广播接收器被注册时,此广播仍会被接收。如果你只想处理一遍该广播,可以通过removeStickyBroadcast()函数来实现

<uses-permission android:name="android.permission.BROADCAST_STICKY"/>

处理各种广播的细节

  1. Sticky广播: 广播注册过程处理AMS.registerReceiver,开始处理粘性广播,见小节[2.5];

    • 创建BroadcastRecord对象;

    • 并添加到mParallelBroadcasts队列;

    • 然后执行queue.scheduleBroadcastsLocked;

  2. 并行广播: 广播发送过程处理,见小节[3.4.6]

    • 只有动态注册的mRegisteredReceivers才会并行处理;

    • 会创建BroadcastRecord对象;

    • 并添加到mParallelBroadcasts队列;

    • 然后执行queue.scheduleBroadcastsLocked;

  3. 串行广播: 广播发送广播处理,见小节[3.4.8]

    • 所有静态注册的receivers以及动态注册mRegisteredReceivers合并到一张表处理;

    • 创建BroadcastRecord对象;

    • 并添加到mOrderedBroadcasts队列;

    • 然后执行queue.scheduleBroadcastsLocked;

BroadcastReceiver - 图1