解析BroadcastReceiver的注册、发送与接收过程
广播的注册、 发送和接收过程
广播作为四大组件之 ,使用频率远没有 Activity 高,但是广播的工作过程还是十分有必要了解的。本节主要从三个方面讲解广播工作过程,分别是广播的注册、发送和接收。本文基于Android8.1.0系统分析广播的注册、发送和接收过程。
1. 广播的注册过程
广播的注册通俗来讲就是广播接受者注册自己感兴趣的广播,广播的注册分为两种形式,分别是静态注册和动态注册,静态注册在应用安装时由PackageManagerService来完成注册过程,关于这一过程本文先不做介绍,本文主要分析广播的动态注册过程。
想要动态注册广播,需要调用registerReceiver方法,它在ContextWrapper中实现,代码如下所示:
frameworks/base/core/java/android/content/ContextWrapper.java
@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {return mBase.registerReceiver(receiver, filter);}
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,IntentFilter filter, String broadcastPermission,Handler scheduler, Context context, int flags) {IIntentReceiver rd = null;if (receiver != null) {if (mPackageInfo != null && context != null) { // ... 1if (scheduler == null) {scheduler = mMainThread.getHandler();}rd = mPackageInfo.getReceiverDispatcher(receiver, context, scheduler,mMainThread.getInstrumentation(), true); // ... 2} else {if (scheduler == null) {scheduler = mMainThread.getHandler();}rd = new LoadedApk.ReceiverDispatcher(receiver, context, scheduler, null, true).getIIntentReceiver(); // ... 3}}try {final Intent intent = ActivityManager.getService().registerReceiver(mMainThread.getApplicationThread(), mBasePackageName, rd, filter,broadcastPermission, userId, flags); // ... 4if (intent != null) {intent.setExtrasClassLoader(getClassLoader());intent.prepareToEnterProcess();}return intent;} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}
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;}...}... }
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) {...ArrayList<Intent> stickyIntents = null;ProcessRecord callerApp = null;...synchronized(this) {if (caller != null) {callerApp = getRecordForAppLocked(caller); // ... 1...} else {...}... Iterator<String> actions = filter.actionsIterator(); // ... 2if (actions == null) {ArrayList<String> noAction = new ArrayList<String>(1);noAction.add(null);actions = noAction.iterator();}// Collect stickies of usersint[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };while (actions.hasNext()) {String action = actions.next();for (int id : userIds) {ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);if (stickies != null) {ArrayList<Intent> intents = stickies.get(action);if (intents != null) {if (stickyIntents == null) {stickyIntents = new ArrayList<Intent>();}stickyIntents.addAll(intents); // ... 3}}}}}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); // ... 4}}}// 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) {... ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()); // ... 5if (rl == null) {rl = new ReceiverList(this, callerApp, callingPid, callingUid,userId, receiver); // ... 6...} ...BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,permission, callingUid, userId, instantApp, visibleToInstantApps); // ... 7rl.add(bf); // ... 8if (!bf.debugCheck()) {Slog.w(TAG, "==> For Dynamic broadcast");}mReceiverResolver.addFilter(bf); // ... 9...return sticky;}}
2. 广播的发送和接收过程
广播的发送和接收过程分为两个部分来进行讲解,分别是 Contextlmpl 到 AMS 的调用过程和 AMS 到 BroadcastReceiver 的调用过程。
2.1 ContextImpl到AMS的调用过程
public void sendBroadcast(Intent intent) {mBase.sendBroadcast(intent);}
在“解析Service的启动过程”一文章我们分析过,mBase具体指向就是ContextImpl,接下来查看ContextImpl的sendBroadcast方法,代码如下所示:
frameworks/base/core/java/android/app/Contextlmpl.java
public void sendBroadcast(Intent intent) {warnIfCallingFromSystemProcess();String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());try {intent.prepareToLeaveProcess(this);ActivityManager.getService().broadcastIntent(mMainThread.getApplicationThread(), intent, resolvedType, null,Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,getUserId()); // ... 1} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}
在注释1处最终会调用AMS的broadcastIntent方法,代码如下所示:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public final int broadcastIntent(IApplicationThread caller,Intent intent, String resolvedType, IIntentReceiver resultTo,int resultCode, String resultData, Bundle resultExtras,String[] requiredPermissions, int appOp, Bundle bOptions,boolean serialized, boolean sticky, int userId) {enforceNotIsolatedCaller("broadcastIntent");synchronized(this) {// 验证广播是否合法intent = verifyBroadcastLocked(intent); // ... 1final ProcessRecord callerApp = getRecordForAppLocked(caller);final int callingPid = Binder.getCallingPid();final int callingUid = Binder.getCallingUid();final long origId = Binder.clearCallingIdentity();int res = broadcastIntentLocked(callerApp,callerApp != null ? callerApp.info.packageName : null,intent, resolvedType, resultTo, resultCode, resultData, resultExtras,requiredPermissions, appOp, bOptions, serialized, sticky,callingPid, callingUid, userId); // ... 2Binder.restoreCallingIdentity(origId);return res;}}
在注释1处,首先验证广播是否合法,我们先分析verifyBroadcastLocked方法,代码如下所示:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
final Intent verifyBroadcastLocked(Intent intent) {// Refuse possible leaked file descriptorsif (intent != null && intent.hasFileDescriptors() == true) { // ... 1throw new IllegalArgumentException("File descriptors passed in Intent");}int flags = intent.getFlags(); // ... 2if (!mProcessesReady) {// if the caller really truly claims to know what they're doing, go// ahead and allow the broadcast without launching any receiversif ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) { // ... 3// This will be turned into a FLAG_RECEIVER_REGISTERED_ONLY later on if needed.} else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { // ... 4Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent+ " before boot completion");throw new IllegalStateException("Cannot broadcast before boot completed");}}if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {throw new IllegalArgumentException("Can't use FLAG_RECEIVER_BOOT_UPGRADE here");}if ((flags & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {switch (Binder.getCallingUid()) {case ROOT_UID:case SHELL_UID:break;default:Slog.w(TAG, "Removing FLAG_RECEIVER_FROM_SHELL because caller is UID "+ Binder.getCallingUid());intent.removeFlags(Intent.FLAG_RECEIVER_FROM_SHELL);break;}}return intent;}
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
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) {...if ((receivers != null && receivers.size() > 0)|| resultTo != null) {BroadcastQueue queue = broadcastQueueForIntent(intent);BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,resultData, resultExtras, ordered, sticky, false, userId); // ... 1if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r+ ": prev had " + queue.mOrderedBroadcasts.size());if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,"Enqueueing broadcast " + r.intent.getAction());final BroadcastRecord oldRecord =replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;if (oldRecord != null) {// Replaced, fire the result-to receiver.if (oldRecord.resultTo != null) {final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);try {oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,oldRecord.intent,Activity.RESULT_CANCELED, null, null,false, false, oldRecord.userId);} catch (RemoteException e) {Slog.w(TAG, "Failure ["+ queue.mQueueName + "] sending broadcast result of "+ intent, e);}}} else {queue.enqueueOrderedBroadcastLocked(r);queue.scheduleBroadcastsLocked(); // ... 2}} else {// There was nobody interested in the broadcast, but we still want to record// that it happened.if (intent.getComponent() == null && intent.getPackage() == null&& (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {// This was an implicit broadcast... let's record it for posterity.addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);}}return ActivityManager.BROADCAST_SUCCESS;
}
这里省略了很多代码,前面的工作主要是将动态注册的广播接收者和静态注册的广播接受者按照优先级高低不同存储在不同的列表中,再将这两个列表合并到receivers列表中,这样receivers列表包含了所有广播接受者(无序广播和有序广播)。在注释1处创建BroadcastRecord对象并将receivers传进去,在注释2处调用BroadcastQueue的scheduleBroadcastsLocked方法。
2.2 AMS到BroadcastReceiver的调用过程
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)); // ... 1mBroadcastsScheduled = true;}
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
private final class BroadcastHandler extends Handler {public BroadcastHandler(Looper looper) {super(looper, null, true);}@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case BROADCAST_INTENT_MSG: {if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");processNextBroadcast(true);} break;case BROADCAST_TIMEOUT_MSG: {synchronized (mService) {broadcastTimeoutLocked(true);}} break;}}}
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
final void processNextBroadcast(boolean fromMsg) {synchronized(mService) {...if (fromMsg) {// 已经处理了BROADCAST_INTENT_MSG类型的消息mBroadcastsScheduled = false; // ... 1}// First, deliver any non-serialized broadcasts right away.// 遍历存储无序广播的mParallelBroadcasts列表while (mParallelBroadcasts.size() > 0) { // ... 2// 获取无序广播r = mParallelBroadcasts.remove(0); // ... 3...for (int i=0; i<N; i++) {Object target = r.receivers.get(i);if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Delivering non-ordered on [" + mQueueName + "] to registered "+ target + ": " + r);deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);// ... 4}...}...}}
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,BroadcastFilter filter, boolean ordered, int index) {...try {if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,"Delivering to " + filter + " : " + r);if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {// Skip delivery if full backup in progress// If it's an ordered broadcast, we need to continue to the next receiver.if (ordered) {skipReceiverLocked(r);}} else {performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,new Intent(r.intent), r.resultCode, r.resultData,r.resultExtras, r.ordered, r.initialSticky, r.userId); // ... 1}if (ordered) {r.state = BroadcastRecord.CALL_DONE_RECEIVE;}} catch (RemoteException e) {Slog.w(TAG, "Failure sending broadcast " + r.intent, e);if (ordered) {r.receiver = null;r.curFilter = null;filter.receiverList.curBroadcast = null;if (filter.receiverList.app != null) {filter.receiverList.app.curReceivers.remove(r);}}}}
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) { // ... 1if (app.thread != null) { // ... 2// If we have an app thread, do the call through that so it is// correctly ordered with other one-way calls.try {app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,data, extras, ordered, sticky, sendingUser, app.repProcState); // ... 3// 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);}}
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);}
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;}@Overridepublic 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); // ... 1} 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();}}}... }}
public void performReceive(Intent intent, int resultCode, String data,Bundle extras, boolean ordered, boolean sticky, int sendingUser) {final Args args = new Args(intent, resultCode, data, extras, ordered,sticky, sendingUser); // ... 1if (intent == null) {Log.wtf(TAG, "Null intent received");} else {if (ActivityThread.DEBUG_BROADCAST) {int seq = intent.getIntExtra("seq", -1);Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()+ " seq=" + seq + " to " + mReceiver);}}if (intent == null || !mActivityThread.post(args.getRunnable())) { // ... 2if (mRegistered && ordered) {IActivityManager mgr = ActivityManager.getService();if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing sync broadcast to " + mReceiver);args.sendFinished(mgr);}}}
final class Args extends BroadcastReceiver.PendingResult {...public final Runnable getRunnable() {return () -> {final BroadcastReceiver receiver = mReceiver;...try {ClassLoader cl = mReceiver.getClass().getClassLoader();intent.setExtrasClassLoader(cl);intent.prepareToEnterProcess();setExtrasClassLoader(cl);receiver.setPendingResult(this);receiver.onReceive(mContext, intent); // ... 1} 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);}}if (receiver.getPendingResult() != null) {finish();}Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);};}}
解析BroadcastReceiver的注册、发送与接收过程相关推荐
- Android筑基——BroadcastReceiver 的动态注册、发送和接收过程(基于api21)
目录 1. 前言 2. 正文 2.1 广播接收者的动态注册 2.1.1 ContextWrapper.registerReceiver() 方法 2.1.2 ContextImpl.registerR ...
- Android深入四大组件(八)广播的注册、发送和接收过程
前言 我们接着来学习Android四大组件中的BroadcastReceiver,广播主要就是分为注册.接收和发送过程.建议阅读此文前请先阅读Android深入理解四大组件系列的文章,知识重复的部分, ...
- Android-Framework学习笔记(九)—— Broadcast的注册、发送和接收过程
系列文章 Android-Framework学习笔记(一)-- Android系统架构 Android-Framework学习笔记(二)-- Zygote进程启动过程 Android-Framewor ...
- Boardcast Receiver 源码分析:广播的动态注册、发送和接收过程
文章目录 动态注册过程 ContextWrapper#registerReceiver(以下代码基于API26) ContextImpl#registerReceiver ContextImpl#re ...
- 邮件的发送和接收过程——STMP、POP、IMAP、MIME
电子邮件发送协议 是一种基于" 推 "的协议,主要包括 SMTP : 邮件接收协议 则是一种基于" 拉 "的协议,主要包括 POP协议 和 IMAP协议 ,在正 ...
- Broadcast的注册、发送和接收过程
上层接口调用registerReceiver frameworks\base\core\java\android\content\ContextWrapper.java @Overridepublic ...
- 邮件的发送和接收过程-----简单邮件传输协议(SMTP)和邮件读取协议!!!
图中就是电子邮件的系统结构 以用户A向用户B发送邮件为例 用户A向用户B发送邮件,首先用户A利用由用户代理撰写邮件,包括填写收件人邮箱地址等,然后基于SMTP将邮件发送到其注册的邮箱服务器A的外出邮件 ...
- 数据在网络中的发送和接收过程--简略版(TCP/IP五层结构)
在应用层上设备A想给IP地址为P的设备B发送信息:(假定已知B的IP) 数据信息从应用层而来,在传输层指定特定的端口号,再将这些数据放到TCP报文或者UDP报文内. 若使用UDP,不论从应用层来的数据 ...
- 电子邮件发送和接收过程 一一 SMTP、POP3、IMAP
电子邮件发送协议主要是SMTP,收件协议主要是POP3和IMAP: SMTP 的全称是"Simple Mail Transfer Protocol",即简单邮件传输协议.它是一组用 ...
最新文章
- SQL Server统计信息:问题和解决方式
- 使用WKWebView替换UIWebView
- java中的Calendar
- [转]你打算如何提升自己?
- 影场与属性访问器界面
- 【LeetCode笔记】581. 最短无序连续子数组(Java、数组)
- 微信APP支付(基于Java实现微信APP支付)
- Java解析excel表格
- C#枚举中使用Flags特性
- VS2013环境下GSL数学库的使用说明(亲测)
- C11 多线程初学1
- matlab 小波变换程序,matlab 小波变换
- java 万年历绪论_基于安卓Android的万年历的设计与开发(含录像)
- 对短信验证码发送次数的限制
- MessageBox confirm弹框确认和取消按钮的使用-回调
- 【计算机网络】计网学习——总览(超多图+超详解)
- Linux ---动态监控
- TVbox带会员带推广版本
- html保存至心愿单按钮,王者荣耀添加心愿单有什么用 心愿单怎么实现
- 初中使用计算机教学反思,初中信息技术课堂教学反思随笔