Android系统源码分析-Broadcast注册和注销
距离上一篇博客进程的加载过了很久的时间,这中间换了一份工作,加入了新的团队,也开始了新的项目,比较忙,所以最近才有时间将四大组件之一的广播原理看完,最近一段时间会相继把四大组件分析写完,让我们对四大组件有更深的了解。本来想一篇把广播的内容写完,但是发现要解释的代码比较多,所以还是分开来讲,那么这篇先分析广播的注册和注销,下一篇再分析广播的发送。
Broadcast的注册
注册广播时序图Step-1:注册广播入口ContextImpl.registerReceiver:
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
return registerReceiver(receiver, filter, null, null);
}
然后调用registerReceiver复写方法:
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext());
}
Step-2:调用registerReceiverInternal方法:
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context) {
IIntentReceiver rd = null;
// 需要注册的广播接收器不为null
if (receiver != null) {
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
// 获取主线程的Handler,mMainThread是描述当前应用程序进程的
scheduler = mMainThread.getHandler();
}
// 将广播接收者receiver封装成一个实现了IIntentReceiver接口的Binder对象rd(ReceiverDispatcher)
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
// 获取主线程的Handler
scheduler = mMainThread.getHandler();
}
// 将广播接收者receiver封装成一个实现了IIntentReceiver接口的Binder对象rd(ReceiverDispatcher)
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
try {
// 调用ActivityManagerProxy的registerReceiver,最终通过mRemote.transact方法传递到
// ActivityManagerService中的registerReceiver方法
final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
...
return intent;
} catch (RemoteException e) {
...
}
}
mPackageInfo是LoadedApk类型对象,这个对象是在一个应用启动的时候创建的。
Step-3:LoadedApk.getReceiverDispatcher方法:
// 每一个注册过广播接收者的Activity组件在LaodApk类中都有一个对应的ReceiverDispatcher对象,它负责
// 将这个被注册的广播接收者与注册它的Activity组件关联在一起。这些ReceiverDispatcher对象保存在一个
// HashMap中,并且以它们所关联的广播接收者为关键字。最后用来保存这些ReceiverDispatcher对象的HashMap
// 又以它们所关联的Activity组件的Context接口为关键字保存在LoadApk类的成员变量mReceivers中
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
synchronized (mReceivers) {
LoadedApk.ReceiverDispatcher rd = null;
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
// 是不是注册广播
if (registered) {
// 查找有没有对应的广播接收者对象列表
map = mReceivers.get(context);
if (map != null) {
// 查找是否存在该广播接收者对应的ReceiverDispatcher对象
rd = map.get(r);
}
}
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);
}
// 缓存ReceiverDispatcher
map.put(r, rd);
}
} else {
// 验证广播分发者的Context和Handler是否一致。
rd.validate(context, handler);
}
rd.mForgotten = false;
return rd.getIIntentReceiver();
}
}
这里主要是将广播接收者receiver封装成一个实现了IIntentReceiver接口的Binder对象rd,然后将其放置到LoadedApk对象中的mReceivers中保存起来。
再回到上面代码中,将生成的实现了IIntentReceiver接口的Binder对象rd通过mRemote.transact方法传递到ActivityManagerService中的registerReceiver方法,因为四大组件的消息传递都是通过这种方式实现的。
Step-7:ActivityManagerProxy.registerReceiver
public Intent registerReceiver(IApplicationThread caller, String packageName,
IIntentReceiver receiver,
IntentFilter filter, String perm, int userId) throws RemoteException {
...
// 通过内部的一个Binder代理对象mRemote向AMS发送一个类型为REGISTER_RECEIVER_TRANSACTION的进程
// 间通信请求
mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
...
return intent;
}
Step-8:ActivityManagerService.registerReceiver
通过上面的mRemote.transact方法传递到ActivityManagerService中对应的方法:
/**
* 粘性广播(Sticky):一个粘性广播被发送到AMS后,就会一直保存在AMS中,直到AMS下次再接收到另外一个
* 同类型的粘性广播为止。一个Activity组件在向AMS注册接收某一种烈性的广播时,如果AMS内部切好保存这个
* 这种类型的粘性广播,那么AMS就会将这个粘性广播返回给Activity组件,以便它可以知道系统上一次发出的它
* 所感兴趣的广播内容。我们可以通过sendStrickyBroadcast向AMS发送粘性广播
*/
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
...
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
int callingUid;
int callingPid;
synchronized (this) {
if (caller != null) {
// 根据caller从ProcessRecord缓存列表中查询ProcessRecord对象caller,用来描述正在请求
// AMS注册广播接收者的一个Activity组件所运行在的应用程序进程
callerApp = getRecordForAppLocked(caller);
if (callerApp == null) {// 没有对应进程,不能注册广播
...//抛出异常
}
...
} else {
...
}
// 获取注册广播的用户的userId(UserController是多用户功能的用户管理,一些系统包含访客模式,或者多用户,每个用户就会有一个id)
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
// 获取需要注册广播的IntentFilter中所有的action
Iterator<String> actions = filter.actionsIterator();
// 如果注册广播没有Action则添加一个null
if (actions == null) {
ArrayList<String> noAction = new ArrayList<String>(1);
noAction.add(null);
actions = noAction.iterator();
}
// Activity组件在注册一个广播接收者时,并不是直接将这个广播接收者注册到了AMS中,而是将与它关联
// 的一个InnerReceiver对象注册到了AMS中。当AMS接收到一个广播时,它就会根据这个广播的类型在内
// 部知道对应的InnerReceiver对象,然后再通过这个对象将这个广播发送给对应的广播接收者。AMS中每
// 一个广播接收者都是使用一个BroadcastFilter对象来描述的,而每一个BroadcastFilter对象又是根
// 据它所描述的广播接收者所关联的一个BroadcastFilter对象,以及所要接受的广播类型来创建。由于在
// 一个应用程序中,不同的Activity组件可能会使用同一个BroadcastFilter对象来注册不同的广播接收
// 者,因此AMS会使用一个ReceiverList列表来保存这些使用了相同InnerReceiver对象来注册的广播接
// 收者,并且以它们所使用的InnerReceiver对象为关键字。
// Collect stickies of users
// 收集与注册用户userId相关的所有已经被广播过的Intent,存储在stickyIntents中
// 包含所有用户以及注册广播进程对应的用户
// 第一个UserHandle.USER_ALL表示设备上所有的用户,
// 第二个是callingUid对应用户的userId(当前用户的userId)
int[] userIds = {UserHandle.USER_ALL, UserHandle.getUserId(callingUid)};
// 这里只通过action进行过滤
while (actions.hasNext()) {
String action = actions.next();
// 遍历与调度进程相关的用户id
for (int id : userIds) {
// 根据userId查询已经发送过的对应的Intent列表
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
// 如果已经发送的Intent里包含上面要注册的广播的action的Intent,将其保存到stickyIntents中
if (stickies != null) {
// 根据action查询Intent列表
ArrayList<Intent> intents = stickies.get(action);
if (intents != null) {
if (stickyIntents == null) {
stickyIntents = new ArrayList<Intent>();
}
stickyIntents.addAll(intents);
}
}
}
}
}
// 下面对通过action过滤出来粘性广播的Intent列表,包括:action,type,scheme,data,categories
ArrayList<Intent> allSticky = null;
if (stickyIntents != null) {
final ContentResolver resolver = mContext.getContentResolver();
// Look for any matching sticky broadcasts...
for (int i = 0, N = stickyIntents.size(); i < N; i++) {
Intent intent = stickyIntents.get(i);
// 查找与IntentFilter匹配的Intent
if (filter.match(resolver, intent, true, TAG) >= 0) {
if (allSticky == null) {
allSticky = new ArrayList<Intent>();
}
allSticky.add(intent);
}
}
}
...
if (receiver == null) {// 如果广播接收器为null,则直接返回第一个Intent结束注册
return sticky;
}
synchronized (this) {
// 首先判断当前进程是否还活着
if (callerApp != null && (callerApp.thread == null
|| callerApp.thread.asBinder() != caller.asBinder())) {
// Original caller already died(注册失败)
return null;
}
// 首先从缓存中查找注册的receiver对应的ReceiverList(ArrayList<BroadcastFilter>),
// 第一次注册为null,receiver对应的是一个BroadcastFilter列表,也就是说可以通过调用
// registerReceiver来为receiver注册不同的广播条件。
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以及对应的ReceiverList列表放到mRegisteredReceivers中
mRegisteredReceivers.put(receiver.asBinder(), rl);
}
...
// 创建BroadcastFilter对象bf,用来描述正在注册的广播接收者,并添加到ReceiverList队列rl中
// 以及mReceiverResolver中
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId);
rl.add(bf);
...
// 添加到已注册接收器的广播解析器中,注册完成
mReceiverResolver.addFilter(bf);
// Enqueue broadcasts for all existing stickies that match
// this filter.
// 上面注册结束以后,如果筛选出了与当前注册的IntentFilter匹配的sticky广播的Intent列表,
// 就将所有匹配的Intent逐条发送广播给当前的注册者receiver,可以看到这里的接受者receivers
// 里面就只有当前创建的一个BroadcastFilter,也就是当前的注册者。
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返回时前台广播队列还是后台广播队列
BroadcastQueue queue = broadcastQueueForIntent(intent);
// 需要发送的一条广播记录,receivers包含了所有能接收该条广播的接收器
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();
}
}
return sticky;
}
}
上面时注册广播的核心代码,主要是先判断注册的广播的Action是不是已经存在AMS(ActivityManagerService)中的粘性广播中,如果存在就将这些Intent单独保存到一个列表中,然后处理广播接收器,上面代码和注释写的很清楚了,广播注册不是直接将receiver保存在AMS中,而是先将其封装到实现IIntentReceiver接口的Binder对象rd中,然后将这个对象放到ReceiverList对象中,这个ReceiverList对象是一个对应receiver的IntentFilter列表,但是这个列表对象也包含了该receiver对象,也就是将receiver以及其对应的IntentFilter列表封装到了ReceiverList对象中,这样每个广播接收者以及其Action都封装好了,然后将其放到该应用所在进程的ReceiverList对象列表中,这样整个广播注册就完成了。
其实缕清了这个结构就看懂广播注册了:首先是一个进程对象ProcessRecord,里面有一个广播的列表ArraySet<ReceiverList>,这个列表表示改进程注册的所有广播接收者,每个ReceiverList对象包含了一个广播接收者(实现了IIntentReceiver接口的Binder对象)封装和与该广播接收者对应的多个Action对应的IntentFilter对象的封装BroadcastFilter列表,这个ReceiverList对象是将注册的广播接收者以及对应的多个Action对应起来,这样就能查找对应的广播接收者,怎么调用我们下一篇发送广播会详细讲解。
Step-9:getRecordForAppLocked
final ProcessRecord getRecordForAppLocked(
IApplicationThread thread) {
if (thread == null) {
return null;
}
int appIndex = getLRURecordIndexForAppLocked(thread);
return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
}
这里是根据IApplicationThread获取是否存在了该进程,这里调用getLRURecordIndexForAppLocked获取该进程对应的index
Step-10:getLRURecordIndexForAppLocked
private 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);
if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
return i;
}
}
return -1;
}
这里主要通过for循环来从mLruProcesses列表中遍历是否存在该IApplicationThread,如果存在返回对应的Index,否则返回-1.
Step-11:UserController.handleIncomingUser
int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
int allowMode, String name, String callerPackage) {
final int callingUserId = UserHandle.getUserId(callingUid);
if (callingUserId == userId) {
return userId;
}
...
int targetUserId = unsafeConvertIncomingUserLocked(userId);
if (callingUid != 0 && callingUid != SYSTEM_UID) {
final boolean allow;
if (mService.checkComponentPermission(INTERACT_ACROSS_USERS_FULL, callingPid,
callingUid, -1, true) == PackageManager.PERMISSION_GRANTED) {
// If the caller has this permission, they always pass go. And collect $200.
allow = true;
}
...
if (!allow) {
if (userId == UserHandle.USER_CURRENT_OR_SELF) {
// In this case, they would like to just execute as their
// owner user instead of failing.
targetUserId = callingUserId;
} else {
...
}
}
}
...
return targetUserId;
}
这里主要获取callingPid等参数对应的用户id。
Step-24:BroadcastQueue.scheduleBroadcastsLocked
// 驱动广播,所有广播都应该从这里走,然后会到processNextBroadcast
public void scheduleBroadcastsLocked() {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
// mBroadcastsScheduled用来描述AMS是否已经向它所运行在的线程的消息队列发送了一个类型为
// BROADCAST_INTENT_MSG的消息。AMS就是通过这个BROADCAST_INTENT_MSG消息类调度保存在无
// 序广播调度队列mParallelBroadcasts和有序广播调度队列mOrderedBroadcasts中的广播转发任务的
if (mBroadcastsScheduled) {// 如果true说明消息队列已经存在一个类型为BROADCAST_INTENT_MSG的消息了
return;
}
// 虽然这里只发送了发送广播的消息,但是这一步执行完之后就已经标记广播发送了,因此可以看出广播发送和接
// 受是异步的,即广播发送者将一个广播发送给AMS后,不会等待AMS将这个广播转发给广播接收者处理
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
Broadcast的注销
了解了广播注册,广播注销就很简单了,就是从列表中删除对应的广播对象封装。
注销广播时序图Step-1:unregisterReceiver
public void unregisterReceiver(BroadcastReceiver receiver) {
if (mPackageInfo != null) {
IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher(
getOuterContext(), receiver);
try {
ActivityManagerNative.getDefault().unregisterReceiver(rd);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} else {
...
}
}
首先通过LoadedApk.forgetReceiverDispatcher方法获取与该注销广播接收者对应的实现IIntentReceiver接口的Binder对象。
Step-2:LoadedApk.forgetReceiverDispatcher
public IIntentReceiver forgetReceiverDispatcher(Context context,
BroadcastReceiver r) {
synchronized (mReceivers) {
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context);
LoadedApk.ReceiverDispatcher rd = null;
if (map != null) {
rd = map.get(r);
if (rd != null) {
map.remove(r);
if (map.size() == 0) {
mReceivers.remove(context);
}
...
return rd.getIIntentReceiver();
}
}
...
}
}
首先去mReceivers中获取,我们从上面注册知道,注册时会将实现了IIntentReceiver接口的广播接收者的封装放到mReceivers保存,所以这里先去获取有没有,注册了肯定是有的,因此将其移除。
Step-4:ActivityManagerProxy.unregisterReceiver
public void unregisterReceiver(IIntentReceiver receiver) throws RemoteException {
...
mRemote.transact(UNREGISTER_RECEIVER_TRANSACTION, data, reply, 0);
...
}
上面注册广播我们分析过调用ActivityManagerProxy这里的方法,然后通过Binder传递到AMS中对应的方法中
Step-5:ActivityManagerService.unregisterReceiver
// 注销广播
public void unregisterReceiver(IIntentReceiver receiver) {
...
try {
boolean doTrim = false;
synchronized (this) {
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
// 如果不为null,说明还没注销广播
if (rl != null) {
final BroadcastRecord r = rl.curBroadcast;
if (r != null && r == r.queue.getMatchingOrderedReceiver(r)) {
final boolean doNext = r.queue.finishReceiverLocked(
r, r.resultCode, r.resultData, r.resultExtras,
r.resultAbort, false);
if (doNext) {
doTrim = true;
r.queue.processNextBroadcast(false);
}
}
if (rl.app != null) {
// 从广播接收器对应的进程中移除
rl.app.receivers.remove(rl);
}
// 移除对应广播过滤器
removeReceiverLocked(rl);
if (rl.linkedToDeath) {
rl.linkedToDeath = false;
rl.receiver.asBinder().unlinkToDeath(rl, 0);
}
}
}
// If we actually concluded any broadcasts, we might now be able
// to trim the recipients' apps from our working set
if (doTrim) {
trimApplications();
return;
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
找到对应的注册广播对象ReceiverList,然后将其移除。
Step-6:BroadcastQueue.getMatchingOrderedReceiver
public BroadcastRecord getMatchingOrderedReceiver(IBinder receiver) {
if (mOrderedBroadcasts.size() > 0) {
final BroadcastRecord r = mOrderedBroadcasts.get(0);
if (r != null && r.receiver == receiver) {
return r;
}
}
return null;
}
从队列中找到对应的BroadcastRecord对象然后返回。
Step-8:BroadcastQueue.finishReceiverLocked
public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
final int state = r.state;
final ActivityInfo receiver = r.curReceiver;
r.state = BroadcastRecord.IDLE;
...
if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
&& r.queue.mOrderedBroadcasts.size() > 0
&& r.queue.mOrderedBroadcasts.get(0) == r) {
ActivityInfo nextReceiver;
if (r.nextReceiver < r.receivers.size()) {
Object obj = r.receivers.get(r.nextReceiver);
nextReceiver = (obj instanceof ActivityInfo) ? (ActivityInfo) obj : null;
} else {
nextReceiver = null;
}
// Don't do this if the next receive is in the same process as the current one.
if (receiver == null || nextReceiver == null
|| receiver.applicationInfo.uid != nextReceiver.applicationInfo.uid
|| !receiver.processName.equals(nextReceiver.processName)) {
if (mService.mServices.hasBackgroundServices(r.userId)) {
r.state = BroadcastRecord.WAITING_SERVICES;
return false;
}
}
}
r.curComponent = null;
// We will process the next receiver right now if this is finishing
// an app receiver (which is always asynchronous) or after we have
// come back from calling a receiver.
return state == BroadcastRecord.APP_RECEIVE
|| state == BroadcastRecord.CALL_DONE_RECEIVE;
}
这里判断是否结束广播接收,如果结束则处理下一条广播。
Step-10:BroadcastQueue.processNextBroadcast
这个是处理下一条广播的,也是广播的核心部分,这个我们在下一篇发送广播时会详细讲解。
Step-11:removeReceiverLocked
void removeReceiverLocked(ReceiverList rl) {
mRegisteredReceivers.remove(rl.receiver.asBinder());
for (int i = rl.size() - 1; i >= 0; i--) {
mReceiverResolver.removeFilter(rl.get(i));
}
}
这个就是通过for循环删除对应的BroadcastFilter对象,这样就注销了广播。
主要的基本都分析了,还有以下其他不重要的大家想要了解自己看看代码。
广播注册结构
注册广播结构图最后这里我们再加一个广播注册结构的总结,上面是一个广播注册时的结构图,也就是广播以及对应的IntentFilter列表封装,整个过程是由下向上注册。首先是将BroadcastReceiver封装成Binder对象IIntentReceiver,将IntentFilter封装成BroadcastFilter对象,ReceiverList继承的是ArrayList<BroadcastFilter>,因此它本身就是一个用来盛放BroadcastFilter对象列表的ArrayList对象,同时ReceiverList对象还放入了IntentFilter列表对应的BroadcastReceiver的封装对象IIntentReceiver,这样就将BroadcastReceiver和IntentFilter绑定到一起了,然后将ReceiverList放到mRegisteredReceivers中,保存在ActivityManagerService(AMS)中,同时将ReceiverList放置到该广播所在进程的receivers中,而该进程保存在AMS中的mLruProcesses中,同时将IntentFilter的封装对象BroadcastReceiver放置到AMS中的mReceiverResolver中,这样就注册完成了。
这样从整个机构来说就非常清楚了,其实里面还有一些相互引用的情况,我没有完全画出来,只画了主要的部分,相对清晰一些。
注
首发地址:http://www.codemx.cn
Android开发群:192508518
微信公众账号:Code-MX
注:本文原创,转载请注明出处,多谢。