一 前言
接收广播(Broadcast),必须先要注册接收广播的组件——广播接收者(receiver),广播接收者的注册分为动态注册和静态注册,注册中心是AMS,AMS再把广播分发到各个广播接收者(receiver)。
静态动态广播的区别
1 动态注册广播不是常驻型广播,广播跟随Activity的生命周期,在Activity结束前,需要移除广播接收器。
静态注册是常驻型,当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。
2 动态注册在程序中使用Context.registerReceiver注册。
静态注册在应用安装时由PackageManagerService来完成注册过程。
二 图示调用流程
三 代码具体流程
1 frameworks/base/core/java/android/content/ContextWrapper.java
@Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}
mBase指向就是ContextImpl,可以返回看Activity的启动流程:Android组件管理框架—视图容器Activity之启动流程(Android P)
2 frameworks/base/core/java/android/app/ContextImpl.java
@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(), 0);
}
继续看registerReceiverInternal。
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
IIntentReceiver rd = null;
if (receiver != null) {
//mPackageInfo是LoadedApk类型
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
//获取ReceiverDispatcher对象
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
//创建ReceiverDispatcher对象
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
try {
//将ReceiverDispatcher,IntentFilter等发送给AMS
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();
}
}
传进来的receiver不是直接发送给AMS的,首先会把receiver封装成一个IIntentReceiver的对象rd,rd是一个binder本地对象,便具备了跨进程通信的能力。
mPackageInfo是LoadedApk的类型,LoadedApk类包含了当前加载的apk的主要的信息。 如果mPackageInfo不为空,则通过mPackageInfo.getReceiverDispatcher获取ReceiverDispatcher对象,否则通过new LoadedApk.ReceiverDispatcher来创建ReceiverDispatcher对象。
3 frameworks/base/core/java/android/app/LoadedApk.java
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
synchronized (mReceivers) {
LoadedApk.ReceiverDispatcher rd = null;
//位置1
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
//位置2 如果注册过直接取出map
if (registered) {
map = mReceivers.get(context);
if (map != null) {
rd = map.get(r);
}
}
if (rd == null) {
rd = new ReceiverDispatcher(r, context, handler,
instrumentation, registered);
if (registered) {
if (map == null) {
//位置3 把map创建出来,后面存到mReceivers中
map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
//位置4 把map放到mReceivers中
mReceivers.put(context, map);
}
//位置5 把ReceiverDispatcher放到map中
map.put(r, rd);
}
} else {
//检查广播分发者的context、handler是否一致
rd.validate(context, handler);
}
rd.mForgotten = false;
return rd.getIIntentReceiver();
}
}
位置1的 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map ,每一个BroadcastReceiver(广播接收者)对应一个ReceiverDispatcher(广播分发者)。 当AMS向app发送广播时会调用到app进程的广播分发者,然后再将广播以message形式post到app的主线程,来执行onReceive()方法。
位置4的mReceivers.put(context, map),mReceivers以Context为key,如果是在Activity中发送的,这个Context就指向与这个Activity,如果是在Service中发送的,这个Context就指向了这个Service。mReceivers是LoadedApk的成员变量,mReceivers表记录了所有动态注册的receiver。
private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
= new ArrayMap<>();
假如一个app只有两个Activity(MainActivity和SecondActivity),该app被打包成xxx.apk,在内存中,该xxx.apk由LoadedApk来描述,如果MainActivity和SecondActivity都注册了广播,那么LoadedApk内部维持的mReceivers的长度就为2。
getReceiverDispatcher的代码逻辑
位置2 当一个BroadcastReceiver要注册时,会优先使用Context查看一下,这个组件有没有注册过广播,如果有就取出来,类型是一个ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> 的map。
位置3 如果没有,就把map创建出来,并且存到mReceivers中。
位置5 有了map之后,就需要把ReceiverDispatcher(广播分发者)存到map里面去。
第一次注册时走的是if(rd==null),这样rd对象被创建出来。
ReceiverDispatcher的实现在LoadedApk.ReceiverDispatcher.InnerReceiver。
static final class ReceiverDispatcher {
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) {
final LoadedApk.ReceiverDispatcher rd;
if (intent == null) {
Log.wtf(TAG, "Null intent received");
rd = null;
} else {
rd = mDispatcher.get();
}
if (ActivityThread.DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction()
+ " seq=" + seq + " to " + (rd != null ? rd.mReceiver : null));
}
if (rd != null) {
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
} else {
// The activity manager dispatched a broadcast to a registered
// receiver in this process, but before it could be delivered the
// receiver was unregistered. Acknowledge the broadcast on its
// behalf so that the system's broadcast sequence can continue.
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to unregistered receiver");
IActivityManager mgr = ActivityManager.getService();
try {
if (extras != null) {
extras.setAllowFds(false);
}
mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
...
}
其中IIntentReceiver是一个Binder接口,通过它可以进行跨进程的通信。InnerReceiver是ReceiverDispatcher的内部类,是一个实现Binder的本地对象,最终是将一个InnerReceiver对象注册到了AMS中。
用户进程走到SystemServer进程。继续看ActivityManagerService的registerReceiver。
4 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
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) {
//由caller获取当前进程对象
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);
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
//根据传进来的IntentFilter得到actions列表(ArrayList)
Iterator<String> actions = filter.actionsIterator();
if (actions == null) {
ArrayList<String> noAction = new ArrayList<String>(1);
noAction.add(null);
actions = noAction.iterator();
}
// Collect stickies of users
//从actions中,先把粘性广播选出来放进stickyIntents中
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
while (actions.hasNext()) {
String action = actions.next();
for (int id : userIds) {
//从mStickyBroadcasts中查看用户的sticky Intent,mStickyBroadcasts存了系统所有的粘性广播
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
if (stickies != null) {
//获取所有粘性广播的intent
ArrayList<Intent> intents = stickies.get(action);
if (intents != null) {
if (stickyIntents == null) {
stickyIntents = new ArrayList<Intent>();
}
stickyIntents.addAll(intents);
}
}
}
}
}
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.
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);
if (receiver == null) {
return sticky;
}
synchronized (this) {
if (callerApp != null && (callerApp.thread == null
|| callerApp.thread.asBinder() != caller.asBinder())) {
// Original caller already died
return null;
}
//位置1 获取ReceiverList列表,用来存储广播接收者
//mRegisteredReceivers存了所有动态注册的广播接收者
//由receiver作为key,因为一个广播可能会有多个接收者所以是ReceiverList
//而不是一个Receiver
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
//如果为空则创建ReceiverList对象
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;
}
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);
}
//位置2 创建BroadcastFilter并传入之前创建的ReceiverList
//在AMS内部,广播接收者实际上是BroadcastFilter来描述的
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 {
//将BroadcastFilter添加到ReceiverList中
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
//位置3 将BroadcastFilter添加到mReceiverResolver
mReceiverResolver.addFilter(bf);
}
// Enqueue broadcasts for all existing stickies that match
// this filter.
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);
BroadcastQueue queue = broadcastQueueForIntent(intent);
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);
queue.scheduleBroadcastsLocked();
}
}
return sticky;
}
}
位置1的ReceiverList继承ArrayList,用来存储广播接收者。位置2的BroadcastFilter用来描述注册的广播接收者。位置3 将BroadcastFilter添加到mReceiverResolver中,这样当AMS接收到广播时就可以从mReceiverResolver中找到对应的广播接收者了。
四 总结
1 关键类与对象
LoadedApk 包含了当前加载的apk的主要的信息。
mReceivers ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>>, LoadedApk的成员变量,一张表记录了所有动态注册的receiver。
IIntentReceiver 一个binder本地对象,具备了跨进程通信的能力。
InnerReceiver ReceiverDispatcher的内部类,是一个实现Binder的本地对象,最终是将InnerReceiver对象注册到AMS中。
ReceiverDispatcher 广播分发者,ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>,每个广播接收者对应一个广播分发者, 当AMS向app发送广播时会调用到app进程(Client端)的广播分发者,然后再将广播以message形式post到app的主线程,来执行onReceive()方法。
mRegisteredReceivers HashMap<IBinder, ReceiverList>,存了所有动态注册的广播接收者。
BroadcastFilter AMS内部广播接收者用BroadcastFilter来描述。
ReceiverList 用来存储广播接收者。
mReceiverResolver AMS接收到广播时就可以从mReceiverResolver中找到对应的广播接收者。
2 注册流程
在Android系统中,系统每加载一个apk,会有一个LoadedApk对象。
每个LoadedApk对象里会有mReceivers表,类型为ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>>,用来记录每个apk里面动态注册了哪些广播接收者。
Context代表是谁注册的,后面的值也是个map ,ArrayMap<BroadcastReceiver, ReceiverDispatcher>表示一个BroadcastReceiver对应一个ReceiverDispatcher。不管一个Activity注册了多少BroadcastReceiver,ReceiverDispatcher只有一个。
ReceiverDispatcher内部有一个InnerReceiver的Binder对象,最终是把这个InnerReceiver发送给了AMS。
AMS内部维护一张表mRegisteredReceivers,记录所有动态注册的接收者,首先会根据传进来的InnerReceiver对象取出来一个ReceiverList,ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()),所以实质上每个ReceiverList都对应着Client端的一个ReceiverDispatcher。
最后把创建的对象BroadcastFilter(AMS内部广播接收者用BroadcastFilter来描述)添加到ReceiverList接收者队列中。