[toc]
基于 Android 7.1.1 源码,分析 BroadcastReceiver 动态注册 的过程,转载请说明出处!
0 综述
BroadcastReceiver 动态注册,就是应用程序在运行过程中,调用 registerReceiver 方法注册:1
2
3
4
5
6
7
8
9
10
11
12
13
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter);
@Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler);
@Override
public Intent registerReceiverAsUser(
BroadcastReceiver receiver, UserHandle user, IntentFilter filter,
String broadcastPermission, Handler scheduler);
可以看到,动态注册广播接收者者时,我们需要创建一个 IntentFilter 过滤器对象,我们还可以指定广播发送者的权限,除此之外,我们还可以通过传入 Handler 来指定 onReceive 方法执行的线程(默认是主线程)。
当应用不再需要这个广播接收者后,需要动态取消注册:
1 | public void unregisterReceiver(BroadcastReceiver receiver); |
下面,我们来进入源码,分析动态注册的流程!
1 应用进程
1.1 ContextWapper.registerReceiver
1 |
|
这里的 mBase 是 ContextImpl 对象!
1.2 ContextImpl.registerReceiver
进入 ContextImpl 继续看:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
return registerReceiver(receiver, filter, null, null);
}
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext());
}
public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
IntentFilter filter, String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, user.getIdentifier(),
filter, broadcastPermission, scheduler, getOuterContext());
}
我们可以看到,虽然是不同的注册方法,最后都调用了 registerReceiverInternal 方法!getOuterContext() 方法用于获得注册时的上下文运行环境!也就是代表注册时所属的组件!!
1.3 ContextImpl.registerReceiverInternal - 核心入口
1 | private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, |
IIntentReceiver 类实例 rd 用来在应用进程和系统进程中进行 Binder 通信!
Handler 类对象 scheduler 用来设置接受到广播后 onReceive 执行的线程,如果传入 null,默认就在主线程!
这里涉及到一个 mPackageInfo,他是 LoadedApk 类的实例。每一个进程在创建时,都会有一个 LoadedApk 对象。用来分装一个应用程序的信息!
我们去 LoadedApk 目录去看看:
1.3.1 LoadedApk.getReceiverDispatcher
这里的 boolean registered 为 true:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39public getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
synchronized (mReceivers) {
//【1】尝试获得对应的 ReceiverDispatcher,如果没有就重新创建!
LoadedApk.ReceiverDispatcher rd = null;
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
if (registered) {
map = mReceivers.get(context);
if (map != null) {
rd = map.get(r);
}
}
//【*1.3.2】第一次注册,创建全新的 ReceiverDispatcher 对象!
if (rd == null) {
rd = new ReceiverDispatcher(r, context, handler,
instrumentation, registered);
if (registered) {
if (map == null) {
map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
mReceivers.put(context, map);
}
map.put(r, rd);
}
} else {
//【2】校验一下 context 和 handler 是否和之前注册的一样,不一样会抛出异常!
rd.validate(context, handler);
}
rd.mForgotten = false;
//【3】返回内部的 InnerReceiver 对象!
return rd.getIIntentReceiver();
}
}
LoadedApk 有一个 ArrayMap 集合 mReceivers:1
2private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
= new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
用来保存当前进程下,每个上下文运行环境 Context 中,对应的 BroadcastReceiver 和 ReceiverDispatcher 的映射关系!
1.3.2 new LoadedApk.ReceiverDispatcher
我们再去看看 ReceiverDispatcher 对象:
1 | ReceiverDispatcher(BroadcastReceiver receiver, Context context, |
这里的 IntentReceiverLeaked,我们不过多分析,很简单!1
2
3
4
5final class IntentReceiverLeaked extends AndroidRuntimeException {
public IntentReceiverLeaked(String msg) {
super(msg);
}
}
ReceiverDispatcher 用于保存 BroadcastReceiver 和 InnerReceiver 映射关系,我们继续看:
1.3.2.1 new ReceiverDispatcher.InnerReceiver
1 | final static class InnerReceiver extends IIntentReceiver.Stub { |
我们可以看到 InnerReceiver 继承了 IIntentReceiver.Stub,他是作为 Binder 通信的服务端,其实,这种架构,我们在 Service 的创建和启动中,也同样看到过!!
1.4 ActivityManagerP.registerReceiver
接着调用 AMP 代理对象的 registerReceiver 方法,进入系统进程,注册 BroadcastReceiver!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29public Intent registerReceiver(IApplicationThread caller, String packageName,
IIntentReceiver receiver,
IntentFilter filter, String perm, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
//【1】处理 ApplicationThread 对象!
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(packageName);
//【2】处理 IIntentReceiver 对象!
data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
filter.writeToParcel(data, 0);
data.writeString(perm);
data.writeInt(userId);
mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
reply.readException();
Intent intent = null;
int haveIntent = reply.readInt();
if (haveIntent != 0) {
intent = Intent.CREATOR.createFromParcel(reply);
}
reply.recycle();
data.recycle();
return intent;
}
下面,进入系统进程!
2 系统进程
首先,进入 ActivityManagerN.onTransact 方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
... ... ...
case REGISTER_RECEIVER_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
//【1】获得 ApplicationThreadProxy 对象!
IBinder b = data.readStrongBinder();
IApplicationThread app =
b != null ? ApplicationThreadNative.asInterface(b) : null;
String packageName = data.readString();
b = data.readStrongBinder();
//【2】获得 IIntentReceiver.proxy 对象!
IIntentReceiver rec
= b != null ? IIntentReceiver.Stub.asInterface(b) : null;
//【3】获得 IntentFilter 对象!
IntentFilter filter = IntentFilter.CREATOR.createFromParcel(data);
String perm = data.readString();
int userId = data.readInt();
//【*2.1】继续调用 AMS.registerReceiver 方法,注册广播接收者!
Intent intent = registerReceiver(app, packageName, rec, filter, perm, userId);
reply.writeNoException();
if (intent != null) {
reply.writeInt(1);
intent.writeToParcel(reply, 0);
} else {
reply.writeInt(0);
}
return true;
}
... ... ...
}
2.1 ActivityManagerS.registerReceiver
参数分析:
- IApplicationThread caller:注册操作所属的应用进程的 ApplicationThreadProxy 对象
- String callerPackage:注册者所属的应用程序包名;
- IIntentReceiver receiver:IIntentReceiver.Proxy 对象,映射注册者进程中的 InnerReceiver 对象;
- IntentFilter filter:Intent 过滤器;
- String permission:需要的权限!
- int userId:当前设备用户 id
1 | public Intent registerReceiver(IApplicationThread caller, String callerPackage, |
下面我们来分析下这个方法中的一些重要步骤:
2.1.1 ActivityManagerS.getRecordForAppLocked
获得注册者进程的 ProcessRecord 对象,传入参数:
- IApplicationThread thread:注册者进程在系统进程中的 ApplicationThreadProxy 对象!
1 | final ProcessRecord getRecordForAppLocked( |
这里调用了 getLRURecordIndexForAppLocked 方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
IBinder threadBinder = thread.asBinder();
// Find the application record.
for (int i=mLruProcesses.size()-1; i>=0; i--) {
ProcessRecord rec = mLruProcesses.get(i);
// 找到正在运行,并且 IApplicationThread 对象可以匹配的进程!
if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
return i;
}
}
return -1;
}
mLruProcesses 是一个 ArrayList 集合,用来保存正在运行中的应用程序进程,这里我们先不看!
2.1.2 IntentFilter.match
主要代码段:1
2
3
4
5
6if (filter.match(resolver, intent, true, TAG) >= 0) {
if (allSticky == null) {
allSticky = new ArrayList<Intent>();
}
allSticky.add(intent);
}
当前要注册的广播接收者只能接收到能够和 IntentFilter 匹配的广播,所以对于“粘性广播”,我们还需要再进行一次匹配操作,找到能够匹配 IntentFilter 的粘性广播,保存到 allSticky 列表中,我们来看看匹配过程:
1 | public final int match(ContentResolver resolver, Intent intent, |
2.1.3 ActivityManagerS.broadcastQueueForIntent
该方法的作用是为广播选择合适的队列:1
2
3
4
5
6
7
8
9BroadcastQueue broadcastQueueForIntent(Intent intent) {
final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
if (DEBUG_BROADCAST_BACKGROUND) Slog.i(TAG_BROADCAST,
"Broadcast intent " + intent + " on "
+ (isFg ? "foreground" : "background") + " queue");
return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
}
如果 Intent 设置了 Intent.FLAG_RECEIVER_FOREGROUND 标志位,那该广播就是一个前台广播,应该被加入 mFgBroadcastQueue 队列;否则,这是一个后台广播,就应该被添加到 mBgBroadcastQueue 队列中;
2.1.4 new BroadcastRecord
创建广播管理对象 BroadcastRecord,参数传递:
- BroadcastQueue _queue:表示广播所在的队列,传入 queue
- Intent _intent:传入 intent
- ProcessRecord _callerApp:传入 null
- String _callerPackage:传入 null
- int _callingPid:传入 -1
- int _callingUid:传入 -1
- String _resolvedType:传入 null
- String[] _requiredPermissions:传入 null
- int _appOp:传入 AppOpsManager.OP_NONE
- BroadcastOptions _options:传入 null
- List _receivers:传入 receivers,这里是
- IIntentReceiver _resultTo:传入 null
- int _resultCode:传入 0
- String _resultData:传入 null
- Bundle _resultExtras:传入 null
- boolean _serialized:传入 false
- boolean _sticky:传入 true
- boolean _initialSticky:传入 true
- int _userId:传入 -1
1 | BroadcastRecord(BroadcastQueue _queue, |
这里是对“粘性”广播创建对应的 BroadcastRecord 管理对象!
2.1.5 BroadcastQueue.enqueueParallelBroadcastLocked
将“粘性”广播 BroadcastRecord 添加到 BroadcastQueue 对象内部的 mParallelBroadcasts 列表中,并初始化 r.enqueueClockTime 为当前系统时间,表示广播进入队列的时间;1
2
3
4public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
mParallelBroadcasts.add(r);
r.enqueueClockTime = System.currentTimeMillis();
}
可以看出,粘性广播属于并发的广播!
2.1.6 BroadcastQueue.scheduleBroadcastsLocked
开始处理广播,mBroadcastsScheduled 表示是否开始广播处理任务!1
2
3
4
5
6
7
8
9
10
11
12
13public void scheduleBroadcastsLocked() {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
if (mBroadcastsScheduled) {
return;
}
//【1】发送 BROADCAST_INTENT_MSG 消息!
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
收集了粘性广播,把粘性广播添加到了指定的广播队列中,然后就是要处理广播了!mHandler 是 BroadcastHandler 对象,这里是向 BroadcastHandler 发送 BROADCAST_INTENT_MSG 消息,开始分发广播!!
2.2 BroadcastQueue.scheduleBroadcastsLocked
1 | public void scheduleBroadcastsLocked() { |
2.3 BroadcastQueue.BroadcastHandler
1 | private final class BroadcastHandler extends Handler { |
接着,调用 processNextBroadcast 方法,分发队列中的广播,分发的具体流程,我们会在 sendBroadcast 流程分析那篇博文中详细解析,这里先不看!
3 总结
3.1 数据结构分析
以上过程涉及到了一些重要的数据结构!
3.1.1 BroadcastRecevier
1 | public abstract class BroadcastReceiver { |
BroadcastReceiver 是一个抽象类,我们在开发时,需要继承 BroadcastReceiver 来实现自己的广播接收者!
3.1.2 mStickyBroadcasts
1 | final SparseArray<ArrayMap<String, ArrayList<Intent>>> mStickyBroadcasts = |
mStickyBroadcasts 用来保存每个设备用户下活跃的粘性广播!
这里来解释下粘性广播,粘性广播是可以发送给以后注册的接受者的广播,意思是系统会将前面的粘性广播保存在 AMS 中,一旦注册了能够接受对应粘性广播的 BroadcastReceiver,在注册结束后,BroadcastReceiver 会立即收到粘性广播!
mStickyBroadcasts 是一个稀疏数组,数组下标为设备用户ID:userId,对应的数组元素是设备用户 ID 下所有活跃的粘性广播:ArrayMap<String, ArrayList<Intent>>
;
ArrayMap<String, ArrayList<Intent>>
的 key 是粘性广播 Intent 的 action,value 是一个 ArrayList:是所有设置了同一个 action 的粘性广播 Intent;
3.1.3 mRegisteredReceivers
1 | final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>(); |
用来保存动态注册的广播接收者,是一个 HashMap,key 是广播接收者的 IInnerReceiver 对象,value 是 ReceiverList 对象,是一个 ArrayList 集合,用来封装该广播接收者的信息!
3.1.4 ReceiverList
ReceiverList 用于封装每一个动态创建
1 | final class ReceiverList extends ArrayList<BroadcastFilter> |
ReceiverList 继承了 ArrayList
3.1.5 BroadcastFilter
BroadcastFilter 表示的动态设定的
1 | final class BroadcastFilter extends IntentFilter { |
BroadcastFilter 继承了 IntentFilter,其本身是一个 IntentFilter 扩展类,出了有 IntentFilter 的属性和方法之外,他还封装了一些其他的属性,我们可以把 BroadcastFilter 理解为注册广播是传入的 IntentFilter!
3.1.6 mReceiverResolver
mReceiverResolver 是模板类 IntentResolver 的子类,用于解析 Intent 对象!
1 | final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver |
mReceiverResolver 持有所有动态注册的广播接受者的 BroadcastFilter 对象,也就是 IntentFilter,当广播没有设置组件信息时,会通过 mReceiverResolver 查询接收者的信息!
3.1.7 BroadcastQueue
BroadcastQueue 表示的是广播队列,任何一个广播都需要被添加到这个队列才能被分发!Android 系统提供了两个队列:1
2
3
4
5
6
7
8BroadcastQueue mFgBroadcastQueue;
BroadcastQueue mBgBroadcastQueue;
final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[2];
// 广播接收者运行超时时间
static final int BROADCAST_FG_TIMEOUT = 10*1000;
static final int BROADCAST_BG_TIMEOUT = 60*1000;
他们是在 AMS 的启动时候初始化的:1
2
3
4
5
6
7mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
"foreground", BROADCAST_FG_TIMEOUT, false);
mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
"background", BROADCAST_BG_TIMEOUT, true);
mBroadcastQueues[0] = mFgBroadcastQueue;
mBroadcastQueues[1] = mBgBroadcastQueue;
一个是前台队列,一个是后台队列!一个广播会根据是否设置了 Intent.FLAG_RECEIVER_FOREGROUND 标志位,会被放到 mFgBroadcastQueue 或者 mBgBroadcastQueue 队列中进行分发,我们去看看 BroadcastQueue 类的一些重要的成员变量:
1 | public final class BroadcastQueue { |
BroadcastQueue 里面还有很多的方法,用于处理广播的分发,超时等等,这个我们后面再看!!
3.1.8 BroadcastRecord
在应用端,广播的表现形式是一个个 Intent 对象,但是在系统进程中,AMS 会将 Intent 封装成 BroadcastRecord 对象:
1 | final class BroadcastRecord extends Binder { |
3.2 结构关系图
结构关系图我们从 2 个方面来说明!
3.2.1 注册者进程关系图
处理广播的类是 BroadcastReceiver,InnerReceiver 用于实现注册者进程和系统进程的跨进程通信,ReceiverDispatcher 实现了二者的低耦合,用于管理二者的映射关系!
系统进程通过 InnerReceiver.Proxy 代理对象,通过 Binder 通信将广播传递给注册者进程的 BroadcastReceiver!performReceive 方法最终会创建一个 Args 对象,用于拉起 BroadcastReceiver 的 onReceive 方法!