前言
广播作为四大组件之一,使用频率远没有Activity高,但是广播的工作过程还是十分有必要了解的。广播的注册分为两种,分别是静态注册和动态注册,静态注册是在应用安装时由PackageManagerService来完成注册的,而动态注册则是由应用通过调用接口来完成注册的;本篇文章我们将会结合Android9的系统源码来具体分析一下广播的动态注册流程。
一、ContextImpl动态注册广播接收者
1、要想动态注册广播,需要调用registerReceiver方法,他在ContextWrapper中实现,代码如下所示:
framework/base/core/java/android/content/ContextWrapper.java
public class ContextWrapper extends Context {
...
@Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter) {
//这里mBase具体指向的就是ContextImpl
return mBase.registerReceiver(receiver, filter);
}
...
}
2、ContextImpl的registerReceiver方法如下所示。
framework/base/core/java/android/app/ContextImpl.java
class ContextImpl extends Context {
LoadedApk mPackageInfo;
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
return registerReceiver(receiver, filter, null, null);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
int flags) {
return registerReceiver(receiver, filter, null, null, flags);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler, int flags) {
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext(), flags);
}
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
IIntentReceiver rd = null;
if (receiver != null) {
//如果mPackageInfo不为空且context不为空
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
//调用LoadedApk对象的getReceiverDispatcher方法,
//将广播接收者receiver封装成一个实现了IIntentReceiver接口的Binder对象rd(ReceiverDispatcher)
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
//直接创建LoadedApk.ReceiverDispatcher对象
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
...代码暂时省略...
}
}
registerReceiver方法会进一步调用registerReceiverInternal方法,而在registerReceiverInternal方法中,首先会判断mPackageInfo是否为空,如果mPackageInfo不为空且context不为空则调用他的getReceiverDispatcher方法,如果不为空则直接将receiver作为参数封装成LoadedApk.ReceiverDispatcher对象。
3、LoadedApk的ReceiverDispatcher方法如下所示。
framework/base/core/java/android/app/LoadedApk.java
public final class LoadedApk {
private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
= new ArrayMap<>();
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) {
rd = map.get(r);
}
}
if (rd == null) {
//如果缓存中不存在,则将BroadcastReceiver对象封装成ReceiverDispatcher对象
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 {
rd.validate(context, handler);
}
rd.mForgotten = false;
return rd.getIIntentReceiver();
}
}
}
LoadedApk的getReceiverDispatcher方法的作用就是将BroadcastReceiver对象封装成ReceiverDispatcher对象。
结合LoadedApk的getReceiverDispatcher,重新回到前面第2步,当mPackageInfo为空的时候是直接将BroadcastReceiver作为参数创建LoadedApk.ReceiverDispatcher对象的。
4、ReceiverDispatcher是LoadedApk的静态内部类。
framework/base/core/java/android/app/LoadedApk.java
final static class InnerReceiver extends IIntentReceiver.Stub {
final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
final LoadedApk.ReceiverDispatcher mStrongRef;
InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
mStrongRef = strong ? rd : null;
}
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
...代码省略...
}
}
5、让我们重新回到第2步,继续往下看ContextImpl的registerReceiverInternal方法。
class ContextImpl extends Context {
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
IIntentReceiver rd = null;
...代码省略...
try {
//将前面封装的rd作为参数,调用AMS对象的registerReceiver方法来进行广播的动态注册
final Intent intent = ActivityManager.getService().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
broadcastPermission, userId, flags);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
intent.prepareToEnterProcess();
}
return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
在成功得到IIntentReceiver的对象实例之后,会调用ActivityManagerService对象的registerReceiver方法,将IIntentReceiver对象实例传进去,这里之所以不直接传入BroadcastReceiver而是传入IIntentReceiver,是因为注册广播是一个跨进程过程,需要具有跨进程的通信能力的IIntentreceiver。
二、AMS动态注册广播接收者
1、应用通过调用ContextImpl的registerReceiver来动态注册广播,最终会触发AMS的registerReceiver方法。
framework/base/service/core/java/com/android/service/am/ActivityManagerService.java
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
...
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
int flags) {
enforceNotIsolatedCaller("registerReceiver");
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
final boolean visibleToInstantApps
= (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
int callingUid;
int callingPid;
boolean instantApp;
synchronized (this) {
if (caller != null) {
// 0201 根据caller从ProcessRecord缓存列表中查询得到ProcessRecord类型的callerApp对象,它用来描述请求AMS注册广播接收者的Activity所在的应用程序进程。
callerApp = getRecordForAppLocked(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when registering receiver " + receiver);
}
if (callerApp.info.uid != SYSTEM_UID &&
!callerApp.pkgList.containsKey(callerPackage) &&
!"android".equals(callerPackage)) {
throw new SecurityException("Given caller package " + callerPackage
+ " is not running in process " + callerApp);
}
callingUid = callerApp.info.uid;
callingPid = callerApp.pid;
} else {
callerPackage = null;
callingUid = Binder.getCallingUid();
callingPid = Binder.getCallingPid();
}
instantApp = isInstantApp(callerApp, callerPackage, callingUid);
// 0203 获取注册广播的用户的userId(UserController是多用户功能的用户管理,一些系统包含访客模式,或者多用户,每个用户就会有一个id)
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
// 0204 根据传入的IntentFilter类型filter得到actions列表
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);
// Don't provided intents that aren't available to instant apps.
if (instantApp &&
(intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
continue;
}
// If intent has scheme "content", it will need to acccess
// provider that needs to lock mProviderMap in ActivityThread
// and also it may need to wait application response, so we
// cannot lock ActivityManagerService here.
// 查找与IntentFilter匹配的Intent
if (filter.match(resolver, intent, true, TAG) >= 0) {
if (allSticky == null) {
allSticky = new ArrayList<Intent>();
}
allSticky.add(intent);
}
}
}
// The first sticky in the list is returned directly back to the client.
Intent sticky = allSticky != null ? allSticky.get(0) : null;
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);
// 如果广播接收器为null,则直接返回第一个Intent结束注册
if (receiver == null) {
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) {
final int totalReceiversForApp = rl.app.receivers.size();
if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {
throw new IllegalStateException("Too many receivers, total of "
+ totalReceiversForApp + ", registered for pid: "
+ rl.pid + ", callerPackage: " + callerPackage);
}
rl.app.receivers.add(rl);
} else {//缓存中有,说明已经注册过了,不需要再添加
try {
receiver.asBinder().linkToDeath(rl, 0);
} catch (RemoteException e) {
return sticky;
}
rl.linkedToDeath = true;
}
// 将receiver以及对应的ReceiverList列表放到mRegisteredReceivers中
mRegisteredReceivers.put(receiver.asBinder(), rl);
} else if (rl.uid != callingUid) {
throw new IllegalArgumentException(
"Receiver requested to register for uid " + callingUid
+ " was previously registered for uid " + rl.uid
+ " callerPackage is " + callerPackage);
} else if (rl.pid != callingPid) {
throw new IllegalArgumentException(
"Receiver requested to register for pid " + callingPid
+ " was previously registered for pid " + rl.pid
+ " callerPackage is " + callerPackage);
} else if (rl.userId != userId) {
throw new IllegalArgumentException(
"Receiver requested to register for user " + userId
+ " was previously registered for user " + rl.userId
+ " callerPackage is " + callerPackage);
}
// 创建BroadcastFilter对象bf,用来描述正在注册的广播接收者,并添加到ReceiverList队列rl中
// 以及mReceiverResolver中
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId, instantApp, visibleToInstantApps);
if (rl.containsFilter(filter)) {
Slog.w(TAG, "Receiver with filter " + filter
+ " already registered for pid " + rl.pid
+ ", callerPackage is " + callerPackage);
} else {
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
// 添加到已注册接收器的广播解析器中,注册完成
mReceiverResolver.addFilter(bf);
}
// Enqueue broadcasts for all existing stickies that match
// this filter.
// 上面注册结束以后,如果筛选出了与当前注册的IntentFilter匹配的粘性广播的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, false, null, null, OP_NONE, null, receivers,
null, 0, null, null, false, true, true, -1);
// 将该广播记录加入广播队列中
queue.enqueueParallelBroadcastLocked(r);
// 0205调度广播,发送BROADCAST_INTENT_MSG消息,触发处理下一个广播。但是如果目前有广播还在发送的处理过程中,这次推动不会起作用
queue.scheduleBroadcastsLocked();
}
}
return sticky;
}
}
...
//0202 通过for循环来从mLruProcesses列表中遍历是否存在该IApplicationThread,如果存在返回对应的Index,否则返回-1.
private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
final IBinder threadBinder = thread.asBinder();
// Find the application record.
for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
final ProcessRecord rec = mLruProcesses.get(i);
if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
return i;
}
}
return -1;
}
// 0201获取进程信息
ProcessRecord getRecordForAppLocked(IApplicationThread thread) {
if (thread == null) {
return null;
}
//0202 调用方法获取app的索引
int appIndex = getLRURecordIndexForAppLocked(thread);
if (appIndex >= 0) {
return mLruProcesses.get(appIndex);
}
// Validation: if it isn't in the LRU list, it shouldn't exist, but let's
// double-check that.
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;
}
}
}
return null;
}
...
}
- 在【注释0201】处调用getRecordForAppLocked来查询ProcessRecord对象是否存在。
- 在【注释0202】处调用getLRURecordIndexForAppLocked方法获取app的索引。
上面时注册广播的核心代码,主要是先判断注册的广播的Action是不是已经存在AMS中的粘性广播中,如果存在就将这些Intent单独保存到一个列表中,然后处理广播接收器,上面代码和注释写的很清楚了,广播注册不是直接将receiver保存在AMS中,而是先将其封装到实现了IIntentReceiver接口的Binder对象rd中,然后将这个对象放到ReceiverList对象中,这个ReceiverList对象是一个对应receiver的IntentFilter列表,但是这个列表对象也包含了该receiver对象,也就是将receiver以及其对应的IntentFilter列表封装到了ReceiverList对象中,这样每个广播接收者以及其Action都封装好了,然后将其放到该应用所在进程的ReceiverList对象列表中,这样整个广播注册就完成了。
其实缕清了这个结构就看懂广播注册了:首先是一个进程对象ProcessRecord,里面有一个广播的列表ArraySet,这个列表表示该进程注册的所有广播接收者,每个ReceiverList对象包含了一个广播接收者(实现了IIntentReceiver接口的Binder对象)封装和与该广播接收者对应的多个Action对应的IntentFilter对象的封装BroadcastFilter列表,这个ReceiverList对象是将注册的广播接收者以及对应的多个Action对应起来,这样就能查找对应的广播接收者,怎么调用我们下一篇发送广播会详细讲解。
- FLAG的影响
1)FLAG_RECEIVER_REPLACE_PENDING
这个flag 将会将之前的Intent 替代掉。加了这个flag,在发送一系列的这样的Intent 之后, 中间有些Intent 有可能在你还没有来得及处理的时候,就被替代掉了。
2)FLAG_RECEIVER_REGISTERED_ONLY:
如果Intent 加了这个Flag, 那么在Androidmanifest.xml 里定义的Receiver 是接收不到这样的Intent 的。
3)FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT:
如果Intent加了这个Flag,那么在启动检查时只能接受在代码中注册的Receiver。这个标志是唯一使用的系统服务作为一种方便避免实施更复杂的机制在启动完成检测。
3、在【注释0203】处调用UserController的handleIncomingUser方法获取注册广播的用户id
framework/base/service/java/com/android/service/am/UserController.java
class UserController implements Handler.Callback {
...
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;
}
// Note that we may be accessing mCurrentUserId outside of a lock...
// shouldn't be a big deal, if this is being called outside
// of a locked context there is intrinsically a race with
// the value the caller will receive and someone else changing it.
// We assume that USER_CURRENT_OR_SELF will use the current user; later
// we will switch to the calling user if access to the current user fails.
int targetUserId = unsafeConvertIncomingUser(userId);
if (callingUid != 0 && callingUid != SYSTEM_UID) {
final boolean allow;
if (mInjector.isCallerRecents(callingUid)
&& callingUserId == getCurrentUserId()
&& isSameProfileGroup(callingUserId, targetUserId)) {
// If the caller is Recents and it is running in the current user, we then allow it
// to access its profiles.
allow = true;
} else if (mInjector.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;
} else if (allowMode == ALLOW_FULL_ONLY) {
// We require full access, sucks to be you.
allow = false;
} else if (mInjector.checkComponentPermission(INTERACT_ACROSS_USERS, callingPid,
callingUid, -1, true) != PackageManager.PERMISSION_GRANTED) {
// If the caller does not have either permission, they are always doomed.
allow = false;
} else if (allowMode == ALLOW_NON_FULL) {
// We are blanket allowing non-full access, you lucky caller!
allow = true;
} else if (allowMode == ALLOW_NON_FULL_IN_PROFILE) {
// We may or may not allow this depending on whether the two users are
// in the same profile.
allow = isSameProfileGroup(callingUserId, targetUserId);
} else {
throw new IllegalArgumentException("Unknown mode: " + allowMode);
}
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 {
StringBuilder builder = new StringBuilder(128);
builder.append("Permission Denial: ");
builder.append(name);
if (callerPackage != null) {
builder.append(" from ");
builder.append(callerPackage);
}
builder.append(" asks to run as user ");
builder.append(userId);
builder.append(" but is calling from user ");
builder.append(UserHandle.getUserId(callingUid));
builder.append("; this requires ");
builder.append(INTERACT_ACROSS_USERS_FULL);
if (allowMode != ALLOW_FULL_ONLY) {
builder.append(" or ");
builder.append(INTERACT_ACROSS_USERS);
}
String msg = builder.toString();
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
}
}
if (!allowAll) {
ensureNotSpecialUser(targetUserId);
}
// Check shell permission
if (callingUid == Process.SHELL_UID && targetUserId >= UserHandle.USER_SYSTEM) {
if (hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, targetUserId)) {
throw new SecurityException("Shell does not have permission to access user "
+ targetUserId + "\n " + Debug.getCallers(3));
}
}
return targetUserId;
}
}
4 在【注释0205】处调用BroadcastQueue的scheduleBroadcastsLocked方法来驱动广播。
framework/base/service/java/com/android/service/am/BroadcastQueue.java
public final class BroadcastQueue {
// 驱动广播,所有广播都应该从这里走,然后会到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;
}
}
下面的是一个广播注册时的结构图,也就是广播以及对应的IntentFilter列表封装,整个过程是由下向上注册。首先是将BroadcastReceiver封装成Binder对象IIntentReceiver,将IntentFilter封装成BroadcastFilter对象,ReceiverList继承的是ArrayList,因此它本身就是一个用来盛放BroadcastFilter对象列表的ArrayList对象,同时ReceiverList对象还放入了IntentFilter列表对应的BroadcastReceiver的封装对象IIntentReceiver,这样就将BroadcastReceiver和IntentFilter绑定到一起了,然后将ReceiverList放到mRegisteredReceivers中,保存在ActivityManagerService(AMS)中,同时将ReceiverList放置到该广播所在进程的receivers中,而该进程保存在AMS中的mLruProcesses中,同时将IntentFilter的封装对象BroadcastReceiver放置到AMS中的mReceiverResolver中,这样就注册完成了。