Android四大组件——BroadcastReceiver(基础篇)里面介绍了BroadcastReceiver相关的基础知识,本文将从Android 8.0源码来分析一下广播的注册和接收原理。
Android系统中BroadcastReceiver的注册方式分为动态注册和静态注册两种。动态注册必须在程序运行期动态注册,其实际的注册动作由ContextImpl对象完成;静态注册则是在AndroidManifest.xml中声明的。在基础篇中提到过,因为静态注册耗电、占内存、不受程序生命周期影响,所以Google在Android 8.0上禁止了大部分广播的静态注册,以此来减少耗电、增加待机时间、节省内存空间、提升性能。
Activity是通过Context类的registerReceiver()方法进行动态注册广播监听的。Context是一个抽象类,它是应用端和AMS、WMS等系统服务进行通信的接口,Activity、Service和Application都是继承它的子类。Context的实现类是ContextImpl,也就是说注册时最终调用到的是ContextImpl中的registerReceiver方法。下面将以registerReceiver为入口一步步分析广播是如何动态注册和接收的。
ContextImpl中的registerReceiver方法最终会调用本类的私有方法registerReceiverInternal。在这个方法里面主要做了两件事情,一件是通过LoadedApk类提供的方法获得IIntentReceiver的实例,另一件是通过ActivityManagerService.registerReceiver方法把广播注册到AMS中。
/**
* Common implementation of Context API, which provides the base
* context object for Activity and other application components.
*/
class ContextImpl extends Context {
...
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
//1、通过LoadedApk类提供的方法获得IIntentReceiver的实例
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 {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
//2、通过ActivityManagerService.registerReceiver方法把广播注册到AMS中
try {
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();
}
}
...
}
接下来跳转到LoadedApk和ActivityManagerService中看看在IIntentReceiver实例化和广播注册到AMS的时候具体做了什么事情。
当Activity中有新的BroadcastReceiver被注册,LoadedApk就会为他生成一个ReceiverDispatcher实例,然后把Context、BroadcastReceiver和ReceiverDispatcher三者的关系存储到关系映射表中。其中,在ReceiverDispatcher的构造方法中生成了IIntentReceiver类的实例,并可以通过ReceiverDispatcher.getIIntentReceiver方法获得。
LoadedApk的相关源码如下:
/**
* Local state maintained about a currently loaded .apk.
* @hide
*/
public final class LoadedApk {
...
//3、Context、BroadcastReceiver和ReceiverDispatcher三者映射关系表
private final ArrayMap> mReceivers
= new ArrayMap<>();
...
//4、把Context、BroadcastReceiver和ReceiverDispatcher三者映射关系存储到映射表中
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
synchronized (mReceivers) {
LoadedApk.ReceiverDispatcher rd = null;
ArrayMap map = null;
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) {
map = new ArrayMap();
mReceivers.put(context, map);
}
map.put(r, rd);
}
} else {
rd.validate(context, handler);
}
rd.mForgotten = false;
return rd.getIIntentReceiver();
}
}
...
static final class ReceiverDispatcher {
ReceiverDispatcher(BroadcastReceiver receiver, Context context,
Handler activityThread, Instrumentation instrumentation,
boolean registered) {
if (activityThread == null) {
throw new NullPointerException("Handler must not be null");
}
//5、实例化IIntentReceiver
mIIntentReceiver = new InnerReceiver(this, !registered);
mReceiver = receiver;
mContext = context;
mActivityThread = activityThread;
mInstrumentation = instrumentation;
mRegistered = registered;
mLocation = new IntentReceiverLeaked(null);
mLocation.fillInStackTrace();
}
}
...
//6、获取IIntentReceiver类的实例
IIntentReceiver getIIntentReceiver() {
return mIIntentReceiver;
}
...
}
AMS在收到客户端广播注册请求时,会把提供服务的IIntentReceivers接口、ReceiverList和BroadcastFilter的映射关系存储到映射关系表中。同时,把BroadcastFilter存储到广播解析器IntentResolver中。
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
...
//7、提供服务的IBinder接口、ReceiverList和BroadcastFilter的映射关系表
/**
* Keeps track of all IIntentReceivers that have been registered for broadcasts.
* Hash keys are the receiver IBinder, hash value is a ReceiverList.
*/
final HashMap mRegisteredReceivers = new HashMap<>();
//8、存储BroadcastFilter的广播解析器
/**
* Resolver for broadcast intents to registered receivers.
* Holds BroadcastFilter (subclass of IntentFilter).
*/
final IntentResolver mReceiverResolver
= new IntentResolver() {...};
...
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
int flags) {
...
synchronized (this) {
if (callerApp != null && (callerApp.thread == null
|| callerApp.thread.asBinder() != caller.asBinder())) {
// Original caller already died
return null;
}
//9、把IBinder、ReceiverList和BroadcastFilter的映射关系存储到映射关系表中
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 {
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);
}
//10、把BroadcastFilter存储到对应的ReceiverList中,BroadcastFilter里面包含了IntentFilter和ReceiverList等相关信息
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId, instantApp, visibleToInstantApps);
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
//11、把BroadcastFilter存储到广播解析器IntentResolver中
mReceiverResolver.addFilter(bf);
...
}
}
...
}
每一个应用都持有一个LoadedApk实例,LoadedApk实例中包含多个Context实例(一个进程对应多个Activity和Service以及一个Application),每个Context实例可能创建了多个BroadcastReceiver实例,每个BroadcastReceiver实例在动态注册的时候都会生成一个对应的ReceiverDispatcher实例,每个ReceiverDispatcher实例内部又会由InnerReceiver类生成一个IIntentReceiver实例。这个IIntentReceiver实例在动态注册BroadcastReceiver的时候会被传递给AMS,AMS会为每个IIntentReceiver实例创建一个ReceiverList实例,每个ReceiverList实例中保存了多个BroadcastFilter实例,而这个BroadcastFilter实例里面包含了具体的IntentFilter和ReceiverList等相关信息。
BroadcastReceiver静态注册指的是在AndroidManifest.xml中声明的接收器,在系统启动的时候,会由PMS去解析。当AMS调用PMS的接口来查询广播注册的时候,PMS会查询记录并且返回给AMS。
以最简单普通广播为例,直接跳到Context的实现类ContextImpl的sendBroadcast方法。从源码看sendBroadcast里面基本没干什么事,直接去调用的AMS的broadcastIntent方法。
@Override
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
// 1、调用的AMS的broadcastIntent方法发送广播
ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
AMS中的broadcastIntent方法里面也没干什么,直接调用本类的broadcastIntentLocked方法(broadcastIntentLocked方法有600多行代码,OMG)。
final int broadcastIntentLocked(ProcessRecord callerApp,
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
// Figure out who all will receive this broadcast.
List receivers = null;
// 2、注册的BroadcastFilter列表,BroadcastFilter里面包含了IntentFilter和ReceiverList等相关信息
List registeredReceivers = null;
// Need to resolve the intent to interested receivers...
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
== 0) {
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
if (intent.getComponent() == null) {
if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
// Query one target user at a time, excluding shell-restricted users
for (int i = 0; i < users.length; i++) {
if (mUserController.hasUserRestriction(
UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
continue;
}
//3、根据intent从广播解析器mReceiverResolver中查询符合的BroadcastFilter列表
List registeredReceiversForUser =
mReceiverResolver.queryIntent(intent,
resolvedType, false /*defaultOnly*/, users[i]);
if (registeredReceivers == null) {
registeredReceivers = registeredReceiversForUser;
} else if (registeredReceiversForUser != null) {
registeredReceivers.addAll(registeredReceiversForUser);
}
}
} else {
//4、根据intent从广播解析器mReceiverResolver中查询符合的BroadcastFilter列表
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false /*defaultOnly*/, userId);
}
}
final boolean replacePending =
(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) {
// If we are not serializing this broadcast, then send the
// registered receivers separately so they don't wait for the
// components to be launched.
if (isCallerSystem) {
checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
isProtectedBroadcast, registeredReceivers);
}
final BroadcastQueue queue = broadcastQueueForIntent(intent);
//5、封装成BroadcastRecord类实例
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
resultCode, resultData, resultExtras, ordered, sticky, false, userId);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
final boolean replaced = replacePending
&& (queue.replaceParallelBroadcastLocked(r) != null);
// Note: We assume resultTo is null for non-ordered broadcasts.
if (!replaced) {
//6、把BroadcastRecord类实例添加到并发的广播序列中并准备发送
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
registeredReceivers = null;
NR = 0;
}
}
接下来看一下BroadcastRecord类中的scheduleBroadcastsLocked方法是如何把广播发送到对应的BroadcastReceiver中的。
/**
* BROADCASTS
*
* We keep two broadcast queues and associated bookkeeping, one for those at
* foreground priority, and one for normal (background-priority) broadcasts.
*/
public final class BroadcastQueue {
...
//7、scheduleBroadcastsLocked方法发送BROADCAST_INTENT_MSG消息给handler
public void scheduleBroadcastsLocked() {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
if (mBroadcastsScheduled) {
return;
}
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
...
private final class BroadcastHandler extends Handler {
public BroadcastHandler(Looper looper) {
super(looper, null, true);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
if (DEBUG_BROADCAST) Slog.v(
TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
//8、handler执行processNextBroadcast方法开始发送广播
processNextBroadcast(true);
} break;
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
broadcastTimeoutLocked(true);
}
} break;
}
}
}
...
final void processNextBroadcast(boolean fromMsg) {
...
do {
...
if (r.receivers == null || r.nextReceiver >= numReceivers
|| r.resultAbort || forceReceive) {
// No more receivers for this broadcast! Send the final
// result if requested...
if (r.resultTo != null) {
try {
//9、逐个发送BroadcastRecord中的广播
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId);
// Set this to null so that the reference
// (local and remote) isn't kept in the mBroadcastHistory.
r.resultTo = null;
} catch (RemoteException e) {
r.resultTo = null;
}
}
...
}
} while (r == null);
...
}
...
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
// Send the intent to the receiver asynchronously using one-way binder calls.
if (app != null) {
if (app.thread != null) {
// If we have an app thread, do the call through that so it is
// correctly ordered with other one-way calls.
try {
//10、由ActivityThread中的scheduleRegisteredReceiver方法发送给相应的的BroadcastReceiver
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.repProcState);
// TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
// DeadObjectException when the process isn't actually dead.
//} catch (DeadObjectException ex) {
// Failed to call into the process. It's dying so just let it die and move on.
// throw ex;
} catch (RemoteException ex) {
// Failed to call into the process. It's either dying or wedged. Kill it gently.
synchronized (mService) {
Slog.w(TAG, "Can't deliver broadcast to " + app.processName
+ " (pid " + app.pid + "). Crashing it.");
app.scheduleCrash("can't deliver broadcast");
}
throw ex;
}
} else {
// Application has died. Receiver doesn't exist.
throw new RemoteException("app.thread must not be null");
}
} else {
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
}
...
}
在ActivityThread的scheduleRegisteredReceiver方法中执行了IIntentReceiver.performReceive方法。
// This function exists to make sure all receiver dispatching is
// correctly ordered, since these are one-way calls and the binder driver
// applies transaction ordering per object for such calls.
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
int resultCode, String dataStr, Bundle extras, boolean ordered,
boolean sticky, int sendingUser, int processState) throws RemoteException {
updateProcessState(processState, false);
receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
sticky, sendingUser);
}
逐个IIntentReceiver接口的实现是在LoadedApk中的,回去调用LoadedApk的performReceive方法,最终调到Args.getRunnable方法。
public final Runnable getRunnable() {
...
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
//11、回调BroadcastReceiver.onReceive方法
receiver.onReceive(mContext, intent);
} catch (Exception e) {
if (mRegistered && ordered) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing failed broadcast to " + mReceiver);
sendFinished(mgr);
}
if (mInstrumentation == null ||
!mInstrumentation.onException(mReceiver, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Error receiving broadcast " + intent
+ " in " + mReceiver, e);
}
}
...
};
应用端调用系统服务(AMS)发送广播,AMS会去广播解析器IntentResolver中查询哪些BroadcastFilter跟这个广播有关联,然后把相关信息封装成 BroadcastRecord类的实例添加到广播发送序列BroadcastQueue中逐个广播。在BroadcastQueue中广播的时候会从BroadcastRecord中获得BroadcastFilter进而获得对应的ReceiverList,ReceiverList中包含了对应的IIntentReceiver实例,通过这个IIntentReceiver实例就可以找到对应的BroadcastReceiver,调用其BroadcastReceiver.OnReceive方法把广播传递给对应的BroadcastReceiver。
通过上面的分析,我们深入了解了广播接收器BroadcastReceiver是如何完成动态注册的,以及广播是如何发送和被接收的。中间涉及到诸多个类的多个方法调来调去,看起来比较复杂,但是如果你看懂了之前BroadcastReceiver动态注册的关系图,理解起来就相对简单了。
广播接收器BroadcastReceiver的动态注册过程可以简单的理解为建立两个映射关系的过程:
- 建立LoadedApk、Context、BroadcastReceiver和ReceiverDispatcher的映射关系。
- 建立ReceiverList和BroadcastFilter的映射关系。
这两个映射关系共同持有同一个IIntentReceiver,IIntentReceiver是这两个映射关系中间的桥梁,客户端和服务端通过IIntentReceiver接口来完成进程间通信。
知道了上面的两个映射关系以及这两个映射关系之间的关联之处,广播的发送和接收就可以简单的理解为一个反向关系查找的过程。AMS根据Context广播的Intent信息对照映射关系表从BroadcastFilter开始,反向一层一层找到与之对应的BroadcastReceiver,最终完成BroadcastReceiver.OnReceive的调用,把Intent传递给对应的BroadcastReceiver。
《Android开发艺术探索》——9.4BroadcastReceiver的工作过程
BroadcastReceiver源码解析(一)
BroadcastReceiver源码解析(二)