BroadcastReceiver消息型组件,用于不同组件之间或应用之间传递消息。消息订阅不同于观察者模式,观察者模式耦合性太强,消息订阅模式中发布消息者完全不需要知道订阅者的存在,所以就需要第三方的组件来帮助存储转发,这个组件就是ActivityManagerService。
注册广播的入口ContextImpl,对应的时序图。
//两个重载的方法:
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
return registerReceiver(receiver, filter, null, null);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext());
}
broadcastPermission广播者需要有相应的权限才接收(权限当然在Manifest声明),scheduler表示收到广播处理消息的Handler,默认是在主线程ActivityThread里执行的,所以不能有耗时的操作。
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context) {
IIntentReceiver rd = null;
if (receiver != null) {
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
//..
}
}
try {
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
} catch (RemoteException e) {
return null;
}
}
mPackageInfo是LoadedApk的类型,调用getReceiverDispatcher得到IItentReceiver,用于收到广播后服务端回调performReceive方法,并将注册广播的信息放到LoadedApk的mReceivers集合里,ReceiverDispatcher内部保存了BroadcastReceiver和InnerReceiver,当接收到广播时,ReceiverDispatcher可以方便地调用BroadcastReceiver#onReceive。
//一个Context对应一个注册的广播集合,重复注册只接收一次,不同的Context注册相同的广播每个注册的Context会收到广播
private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
= new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
//registered为传递过来的true
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 (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 {
//...
}
rd.mForgotten = false;
return rd.getIIntentReceiver();
}
}
然后通过ActivityManagerNative.getDefault()获得ActivityManagerProxy向AMS发起IPC,调用registerReceiver方法:
public 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);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(packageName);
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;
}
然后就执行到了AMS的registerReceiver方法:
//为了更快地查找,这里使用的就不是ArrayMap了
final HashMap<IBinder, ReceiverList> mRegisteredReceivers =
new HashMap<IBinder, ReceiverList>();
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
//...
int callingUid;
int callingPid;
synchronized(this) {
ProcessRecord callerApp = null;
if (caller != null) {
callerApp = getRecordForAppLocked(caller);
if (callerApp == null) {
//...throw exception
}
//如果调用进程没有运行
if (callerApp.info.uid != Process.SYSTEM_UID &&
!callerApp.pkgList.containsKey(callerPackage) &&
!"android".equals(callerPackage)) {
//...throw exception
}
callingUid = callerApp.info.uid;
callingPid = callerApp.pid;
} else {
//...
}
userId = this.handleIncomingUser(callingPid, callingUid, userId,
true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
List allSticky = null;
Iterator actions = filter.actionsIterator();
if (actions != null) {
while (actions.hasNext()) {
String action = (String)actions.next();
allSticky = getStickiesLocked(action, filter, allSticky,
UserHandle.USER_ALL);
allSticky = getStickiesLocked(action, filter, allSticky,
UserHandle.getUserId(callingUid));
}
} else {
//...
}
// The first sticky in the list is returned directly back to
// the client.
Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
//直接返回sticky的结果
if (receiver == null) {
return sticky;
}
ReceiverList rl
= (ReceiverList)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 {
try {
receiver.asBinder().linkToDeath(rl, 0);
} catch (RemoteException e) {
return sticky;
}
rl.linkedToDeath = true;
}
mRegisteredReceivers.put(receiver.asBinder(), rl);
} else if (rl.uid != callingUid) {
//...
}
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.
if (allSticky != null) {
//...
}
return sticky;
}
}
final SparseArray<ArrayMap<String, ArrayList<Intent>>> mStickyBroadcasts =
new SparseArray<ArrayMap<String, ArrayList<Intent>>>();
private final List getStickiesLocked(String action, IntentFilter filter,
List cur, int userId) {
final ContentResolver resolver = mContext.getContentResolver();
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
if (stickies == null) {
return cur;
}
final ArrayList<Intent> list = stickies.get(action);
if (list == null) {
return cur;
}
int N = list.size();
for (int i=0; i<N; i++) {
Intent intent = list.get(i);
if (filter.match(resolver, intent, true, TAG) >= 0) {
if (cur == null) {
cur = new ArrayList<Intent>();
}
cur.add(intent);
}
}
return cur;
}
当我们发送sticky广播的时候,AMS会把其保存在mStickyBroadcasts集合里,如果能在里面匹配到对应的action,就会把Intent寻找出来并返回,如果只想获取结果而不想注册广播可以将BroadcastReceiver传递为null。
mRegisteredReceivers用于保存IIntentReceiver与注册广播的对应关系,用于使用IIntentReceiver快速找到注册的广播ReceiverList(里面存储多个BroadcastFilter),例如反注册广播。所以一个广播可以接收到多个不同action的广播。
mReceiverResolver用于保存注册的所有广播(BroadcastFilter),用于发送广播快速找到注册的IIntentReceiver,进行分发。
入口同样是在ContextImpl
@Override
public void unregisterReceiver(BroadcastReceiver receiver) {
if (mPackageInfo != null) {
IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher(
getOuterContext(), receiver);
try {
ActivityManagerNative.getDefault().unregisterReceiver(rd);
} catch (RemoteException e) {
}
} else {
//...
}
}
调用mPackageInfo#forgetReceiverDispatcher移除mReceiver里面注册过的广播。
//LoadedApk.java
public IIntentReceiver forgetReceiverDispatcher(Context context,
BroadcastReceiver r) {
synchronized (mReceivers) {
//找到Context注册的广播集合
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);
}
if (r.getDebugUnregister()) {
//...调试使用的
}
rd.mForgotten = true;
return rd.getIIntentReceiver();
}
}
//...
if (context == null) {
throw new IllegalStateException("Unbinding Receiver " + r
- " from Context that is no longer in use: " + context);
} else {
throw new IllegalArgumentException("Receiver not registered: " + r);
}
}
}
从mReceivers找到注册广播的集合(没找到就抛异常),移除已经注册的BroadcastRecevier,并返回对应的IIntentReceiver,用于AMS反注册。
接着通过ActivityManagerNative.getDefault()得到ActivityManagerProxy,向AMS发起IPC调用:
//ActivityManagerProxy
public void unregisterReceiver(IIntentReceiver receiver) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(receiver.asBinder());
mRemote.transact(UNREGISTER_RECEIVER_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
进入到AMS的unregisterReceiver:
public void unregisterReceiver(IIntentReceiver receiver) {
final long origId = Binder.clearCallingIdentity();
try {
boolean doTrim = false;
synchronized(this) {
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl != null) {
if (rl.curBroadcast != null) {
//...
}
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);
}
}
void removeReceiverLocked(ReceiverList rl) {
mRegisteredReceivers.remove(rl.receiver.asBinder());
int N = rl.size();
for (int i=0; i<N; i++) {
mReceiverResolver.removeFilter(rl.get(i));
}
}
将注册的IIntentReceiver和BroadcastFilter(只移除对应IIntentReceiver注册的)移除。