注册
调用者进程
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
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,代表一个进程信息,存放在ArrayListmLruProcesses
中。如果没缓存,则会通过以下方法去创建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
:有序广播队列,同一时间只允许执行一个广播,该队列顶部的广播便是活动广播,其他广播必须等待该广播结束才能运行,也是独立区别前台的和后台的广播
小结
传递的参数为广播接收者BroadcastReceiver和Intent过滤条件IntentFilter,也就是
BroadcastFilter
;创建对象LoadedApk.ReceiverDispatcher.InnerReceiver,该对象继承于IIntentReceiver.Stub;
通过AMS把当前进程的ApplicationThread和InnerReceiver对象的代理类,注册登记到system_server进程;
当广播receiver没有注册过,则创建广播接收者队列ReceiverList,该对象继承于ArrayList, 并添加到AMS.mRegisteredReceivers(已注册广播队列);
创建BroadcastFilter,并添加到AMS.mReceiverResolver;
将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"/>
Sticky广播: 广播注册过程处理AMS.registerReceiver,开始处理粘性广播,见小节[2.5];
创建BroadcastRecord对象;
并添加到mParallelBroadcasts队列;
然后执行queue.scheduleBroadcastsLocked;
并行广播: 广播发送过程处理,见小节[3.4.6]
只有动态注册的mRegisteredReceivers才会并行处理;
会创建BroadcastRecord对象;
并添加到mParallelBroadcasts队列;
然后执行queue.scheduleBroadcastsLocked;
串行广播: 广播发送广播处理,见小节[3.4.8]
所有静态注册的receivers以及动态注册mRegisteredReceivers合并到一张表处理;
创建BroadcastRecord对象;
并添加到mOrderedBroadcasts队列;
然后执行queue.scheduleBroadcastsLocked;