赞
踩
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<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> 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<BroadcastReceiver, LoadedApk.ReceiverDispatcher> 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<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); 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<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>(); //8、存储BroadcastFilter的广播解析器 /** * Resolver for broadcast intents to registered receivers. * Holds BroadcastFilter (subclass of IntentFilter). */ final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver = new IntentResolver<BroadcastFilter, BroadcastFilter>() {...}; ... 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<BroadcastFilter> 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<BroadcastFilter> 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源码解析(二)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。