展开说说:Android之广播BroadcastReceiver源码浅析

2023-12-18 10:28

本文主要是介绍展开说说:Android之广播BroadcastReceiver源码浅析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上一篇《展开说说:Android之广播BroadcastReceiver生命周期》总结了广播的简单应用,本篇记录一下梳理广播从消息发送到被被接收的完整流程。

概述:

a、本篇以Activity发送无序广播为例,以下代码基于sdk版本android-30。

b、以下记录切换出当前类则序号的首位数字加1第二位归1,当前类内部方法跳转仅序号第二位加1。

c、本文插入的代码较多,如果不习惯在博客内部阅读可以只关注文字提到的关键方法和类自行查找代码阅读。

1、Activity中发送广播sendBroadcast(intent);

2、首先会调用ContextWrappersendBroadcast

@Override
public void sendBroadcast(Intent intent) {mBase.sendBroadcast(intent);
}

这个mBase就是Context,Context内部的sendBroadcast是个抽象方法,因此Context也是个抽象类。

3、Context的sendBroadcast

public abstract void sendBroadcast(@RequiresPermission Intent intent);

4、来到Context的子类实现类ComtextImpl

    @Overridepublic void sendBroadcast(Intent intent) {warnIfCallingFromSystemProcess();String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());try {intent.prepareToLeaveProcess(this);ActivityManager.getService().broadcastIntentWithFeature(mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,false, getUserId());} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}

上面ActivityManager类的方法获取到IActivityManager:

   @UnsupportedAppUsagepublic static IActivityManager getService() {return IActivityManagerSingleton.get();}

他不是java类是个aidl文件,因此sendBroadcast方法的getService()是返回他的实例ActivityManagerServices。

4、ActivityManagerServices,下文简称AMS

4.1 broadcastIntentWithFeature方法实现

public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,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);final ProcessRecord callerApp = getRecordForAppLocked(caller);final int callingPid = Binder.getCallingPid();final int callingUid = Binder.getCallingUid();final long origId = Binder.clearCallingIdentity();try {return broadcastIntentLocked(callerApp,callerApp != null ? callerApp.info.packageName : null, callingFeatureId,intent, resolvedType, resultTo, resultCode, resultData, resultExtras,requiredPermissions, appOp, bOptions, serialized, sticky,callingPid, callingUid, callingUid, callingPid, userId);} finally {Binder.restoreCallingIdentity(origId);}}}

4.2他的broadcastintentwithfeature方法调用了broadcastIntentLocked

方法,然后它继续调用另一个重载方法broadcastIntentLocked,然后根据intent-filter找到对应的满足接收要求的广播接收者将其添加到BroadcastQueue中。然后它将广播消息发送给符合条件的广播接收者,部分代码:

 if ((receivers != null && receivers.size() > 0)|| resultTo != null) {BroadcastQueue queue = broadcastQueueForIntent(intent);BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,resultData, resultExtras, ordered, sticky, false, userId,allowBackgroundActivityStarts, timeoutExempt);if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);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();}} 

5、BroadcastQueue广播消息队列

5.1 broadcastIntentLocked中先发一个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;}

5.2 接收handler消息BROADCAST_INTENT_MSG:

  @Overridepublic void handleMessage(Message msg) {switch (msg.what) {case BROADCAST_INTENT_MSG: {if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Received BROADCAST_INTENT_MSG ["+ mQueueName + "]");processNextBroadcast(true);} break;case BROADCAST_TIMEOUT_MSG: {synchronized (mService) {broadcastTimeoutLocked(true);}} break;}}

5.3 processNextBroadcast方法内调用processNextBroadcastLocked加了Synchronization:

    final void processNextBroadcast(boolean fromMsg) {synchronized (mService) {processNextBroadcastLocked(fromMsg, false);}}

5.4遍历将final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();内的广播消息通过方法发送给所有广播接收者。

   while (mParallelBroadcasts.size() > 0) {r = mParallelBroadcasts.remove(0);r.dispatchTime = SystemClock.uptimeMillis();r.dispatchClockTime = System.currentTimeMillis();if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),System.identityHashCode(r));Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),System.identityHashCode(r));}final int N = r.receivers.size();if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["+ mQueueName + "] " + r);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);}addBroadcastToHistoryLocked(r);if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["+ mQueueName + "] " + r);}

5.5 上面方法可以看出是通过deliverToRegisteredReceiverLocked来发消息的,其内部又调用performReceiveLocked方法:

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 {app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,data, extras, ordered, sticky, sendingUser, app.getReportedProcState());// 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");}

app.thread.scheduleRegisteredReceiver,实际app.thread就是ApplicationThread。

6、ApplicationThread是ActivityThread的子类,scheduleRegisteredReceiver实现:

        // 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);}

7、通过IIntentReceiver的performReceive方法:

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);} 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的performReceive方法再调用外部类ReceiverDispatcher的performReceive方法:

 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);if (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())) {if (mRegistered && ordered) {IActivityManager mgr = ActivityManager.getService();if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing sync broadcast to " + mReceiver);args.sendFinished(mgr);}}}

创建一个args对象并通过ActivityThread的post执行args中的广播发送任务。args.getRunnabl方法:

public final Runnable getRunnable() {return () -> {final BroadcastReceiver receiver = mReceiver;final boolean ordered = mOrdered;if (ActivityThread.DEBUG_BROADCAST) {int seq = mCurIntent.getIntExtra("seq", -1);Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()+ " seq=" + seq + " to " + mReceiver);Slog.i(ActivityThread.TAG, "  mRegistered=" + mRegistered+ " mOrderedHint=" + ordered);}final IActivityManager mgr = ActivityManager.getService();final Intent intent = mCurIntent;if (intent == null) {Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched+ (mRunCalled ? ", run() has already been called" : ""));}mCurIntent = null;mDispatched = true;mRunCalled = true;if (receiver == null || intent == null || mForgotten) {if (mRegistered && ordered) {if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing null broadcast to " + mReceiver);sendFinished(mgr);}return;}Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");try {ClassLoader cl = mReceiver.getClass().getClassLoader();intent.setExtrasClassLoader(cl);intent.prepareToEnterProcess();setExtrasClassLoader(cl);receiver.setPendingResult(this);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);}}if (receiver.getPendingResult() != null) {finish();}Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);};}

上面一大段核心代码就是 receiver.onReceive(mContext, intent);这个receiver就是注册广播时使用的BroadcastReceiver对象,此时符合条件的广播接收者onReceive生命周期会被调用,因此也就接收到了广播消息

8、总体来看大概可以分为两步,两者是异步的通过BroadcastQueue内的handler消息发送BROADCAST_INTENT_MSG消息连接,分别是广播的发送和处理过程

8.1 、sendBroadcast发出广播,IActivityManager把消息通过Binder机制发送给ActivityManagerService(简称AMS),AMS根据广播的intent-filter匹配相应的广播接收者,然后把这个广播放进消息队列BroadcastQueue

8.2、AMS在消息循环中处理广播,并通过Binder机制把这个广播分发给注册的广播接收分发器ReceiverDispatcher的内部类IIntentReceiverperformReceive方法,它借助ReceiverDispatcher的另一个内部类Args处理这个广播,最终将这个广播分发给当初注册的BroadcastReceiver实例的onReceive()方法进行处理。

这篇关于展开说说:Android之广播BroadcastReceiver源码浅析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/508057

相关文章

在Android平台上实现消息推送功能

《在Android平台上实现消息推送功能》随着移动互联网应用的飞速发展,消息推送已成为移动应用中不可或缺的功能,在Android平台上,实现消息推送涉及到服务端的消息发送、客户端的消息接收、通知渠道(... 目录一、项目概述二、相关知识介绍2.1 消息推送的基本原理2.2 Firebase Cloud Me

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

Android中Dialog的使用详解

《Android中Dialog的使用详解》Dialog(对话框)是Android中常用的UI组件,用于临时显示重要信息或获取用户输入,本文给大家介绍Android中Dialog的使用,感兴趣的朋友一起... 目录android中Dialog的使用详解1. 基本Dialog类型1.1 AlertDialog(

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现

浅析CSS 中z - index属性的作用及在什么情况下会失效

《浅析CSS中z-index属性的作用及在什么情况下会失效》z-index属性用于控制元素的堆叠顺序,值越大,元素越显示在上层,它需要元素具有定位属性(如relative、absolute、fi... 目录1. z-index 属性的作用2. z-index 失效的情况2.1 元素没有定位属性2.2 元素处

Android App安装列表获取方法(实践方案)

《AndroidApp安装列表获取方法(实践方案)》文章介绍了Android11及以上版本获取应用列表的方案调整,包括权限配置、白名单配置和action配置三种方式,并提供了相应的Java和Kotl... 目录前言实现方案         方案概述一、 androidManifest 三种配置方式

python展开嵌套列表的多种方法

《python展开嵌套列表的多种方法》本文主要介绍了python展开嵌套列表的多种方法,包括for循环、列表推导式和sum函数三种方法,具有一定的参考价值,感兴趣的可以了解一下... 目录一、嵌套列表格式二、嵌套列表展开方法(一)for循环(1)for循环+append()(2)for循环+pyPhWiFd

Spring 中 BeanFactoryPostProcessor 的作用和示例源码分析

《Spring中BeanFactoryPostProcessor的作用和示例源码分析》Spring的BeanFactoryPostProcessor是容器初始化的扩展接口,允许在Bean实例化前... 目录一、概览1. 核心定位2. 核心功能详解3. 关键特性二、Spring 内置的 BeanFactory