【Broadcast】registerReceiver流程

【Broadcast】registerReceiver流程应用调用 RegisterReci 实质是调用的 ContextImpl 的 registerRece 接下来跟一下这个流程 Overridepubl BroadcastRec IntentFilter returnregist receiver

应用调用RegisterReciever,实质是调用的ContextImpl的registerReceiver,接下来跟一下这个流程:

@Override public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { return registerReceiver(receiver, filter, null, null); } 

其中receiver,即应用中自定义的receiver。

@Override public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) { return registerReceiverInternal(receiver, getUserId(), filter, broadcastPermission, scheduler, getOuterContext(), 0); }

即此处的参数:

参数
receiver 即应用中已定义的receiver
filter 应用中的filter
broadcastPermission null
scheduler null

该函数中新增了两个参数broadcastPermission和scheduler。

  • broadcastPermission:对广播者增加了权限控制,只有拥有对应权限的广播者发出的广播才能被此接收者接收;
  • scheduler:BroacastReceiver对象的onReceive函数可调度到scheduler所在的线程中执行。

接下来是registerReceiverInternal函数:

registerReceiverInternal

 private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, IntentFilter filter, String broadcastPermission, Handler scheduler, Context context, int flags) { //创建一个IIntentReciever对象 IIntentReceiver rd = null; if (receiver != null) { if (mPackageInfo != null && context != null) { if (scheduler == null) { //没有scheduler,则默认使用主线程的Handler 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(); } } 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(); } }

该函数中的参数值:

参数
receiver 应用中自定义的receiver
userId getUserId的返回值
filter 应用中的filter
broadcastPermission null
scheduler null
context

getOuterContext()。Context家族中真正干活的是ContextImpl,而其代理对象可以是Application或者Actiivity等,getOuterContext就返回的是这个代理。如果是在Activity中调用的registerReceiver,那此处的context就是Activity.

flags 0

此函数中else中对rd的赋值:

rd = new LoadedApk.ReceiverDispatcher( receiver, context, scheduler, null, true).getIIntentReceiver(); 

先看LoadedApk.ReceiverDispatcher构造函数

/*参数解读: receiver---应用中的receiver context---调用registerReceiver的Activity activityThread---null instrumentation---null registered --- true */ ReceiverDispatcher(BroadcastReceiver receiver, Context context, Handler activityThread, Instrumentation instrumentation, boolean registered) { if (activityThread == null) { throw new NullPointerException("Handler must not be null"); } mIIntentReceiver = new InnerReceiver(this, !registered); mReceiver = receiver; mContext = context; mActivityThread = activityThread; mInstrumentation = instrumentation; mRegistered = registered; mLocation = new IntentReceiverLeaked(null); mLocation.fillInStackTrace(); } 

注意到其中有个变量mIIntentReceiver:

 final IIntentReceiver.Stub mIIntentReceiver;

IIntentReceiver是个interface,关系图谱:

明朗晨光

由上面的关系图可知:

  • BrocastReceiver内部有一个PendingResult类,该类是用于异步处理广播信息的。如当BroacastReceiver收到广播时,其onReceive函数被调用,一般都是直接在该函数里处理广播。不过,若广播处理比较耗时,可以采用异步的方式进行处理,即先调用BroadcastReceiver的goAsync函数得到一个PendingResult对象,然后将该对象放到工作线程中去处理,这样onReceive函数就可以立即返回而不至于耽误太长时间。工作线程处理完这条广播后,需要调用PendingResult的finish函数来完成整个广播的处理流程。
  • 广播由AMS发出,而处理却在另一个进程中进行。整个过程一定涉及进程间通信,虽然在BroadcastReceiver定义了了一个广播接收者,但是它与Binder没有任何关系,故其不直接参与进程间通信。与之相反的是,IIntentReceiver接口和Binder密切相关,故可知广播的接收者是由IIntentReceiver接口来完成的。在整个流程中,首先接收到来自AMS的广播的将是该接口的Bn端,即LoadedApk.ReceiverDispatcher.InnerReceiver。

而InnerReceiver类的具体实现:

final static class InnerReceiver extends IIntentReceiver.Stub { final WeakReference 
  
    mDispatcher; final LoadedApk.ReceiverDispatcher mStrongRef; InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) { mDispatcher = new WeakReference 
   
     (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(); } } } } 
    
  

而rd =new LoadedApk.ReceiverDispatcher(receiver, context, scheduler, null, true).getIIntentReceiver();中的getIIntentReceiver就是返回的mIIntentReceiver变量。

小结

registerReceiverInternal函数主要完成了2个工作:

  • 创建了一个IIntentReceiver对象
  • 调用AMS的registerReceiver函数

接下来看AMS的registerReceiver函数:

AMS.registerReceiver

//ContextImpl.java final Intent intent = ActivityManager.getService().registerReceiver( mMainThread.getApplicationThread(), mBasePackageName, rd, filter, broadcastPermission, userId, flags); //ActivityManagerService.java public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId, int flags) { //.... }

由上可知,传入AMS.registerReceiver的参数表:

参数
caller 应用主线程的ApplicationThread
callerPackage 进程创建时new ContextImpl时的package
receiver 即IIntentReceiver,接收来自AMS的Bn端
filter 应用传入的filter
permission null

userId

进程的userId

public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId, int flags) { enforceNotIsolatedCaller("registerReceiver"); ArrayList 
  
    stickyIntents = null; ProcessRecord callerApp = null; ... int callingUid; int callingPid; synchronized(this) { if (caller != null) { callerApp = getRecordForAppLocked(caller); if (callerApp == null) { //系统不允许未注册的进程注册动态receiver throw new SecurityException( "Unable to find app for caller " + caller + " (pid=" + Binder.getCallingPid() + ") when registering receiver " + receiver); } //检查调用进程是否有callerPackage信息,如果没有,抛出异常 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的处理 //从系统的Sticky Intent中查询匹配IntentFilter的intent,结果保存到allSticky中 Iterator 
   
     actions = filter.actionsIterator(); if (actions == null) { ArrayList 
    
      noAction = new ArrayList 
     
       (1); noAction.add(null); actions = noAction.iterator(); } // Collect stickies of users int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) }; while (actions.hasNext()) { String action = actions.next(); for (int id : userIds) { ArrayMap 
      
        > stickies = mStickyBroadcasts.get(id); if (stickies != null) { ArrayList 
       
         intents = stickies.get(action); if (intents != null) { if (stickyIntents == null) { stickyIntents = new ArrayList 
        
          (); } stickyIntents.addAll(intents); } } } } } //在stickyIntents中查询和IntentFilter匹配的intent ArrayList 
         
           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. ...//Instant APP的相关处理 // 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 
          
            (); } allSticky.add(intent); } } } //如果allSticky不为空,则选择第一个Intent作为本函数的返回值 // The first sticky in the list is returned directly back to the client. Intent sticky = allSticky != null ? allSticky.get(0) : null; //如果没有设置接收者,则直接返回Sticky的intent if (receiver == null) { return sticky; } synchronized (this) { if (callerApp != null && (callerApp.thread == null || callerApp.thread.asBinder() != caller.asBinder())) { // Original caller already died //之前的调用者所在进程已经die了 return null; } //在mRegisteredReceivers中查询receiver对应的IBinder对象的ReceiverList ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()); if (rl == null) {//如果是首次调用,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; } //将rl保存到mRegisterReceivers中 mRegisteredReceivers.put(receiver.asBinder(), rl); } else if (...) { ......//其他情况,抛出异常信息 } //新建BroadcastFilter对象 BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId, instantApp, visibleToInstantApps); //保存到rl中 rl.add(bf); mReceiverResolver.addFilter(bf); // Enqueue broadcasts for all existing stickies that match // this filter. //allSticky不为空,表示有Sticky的intent,需要立即调度广播发送 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对象 BroadcastRecord r = new BroadcastRecord(queue, intent, null, null, -1, -1, false, null, null, AppOpsManager.OP_NONE, null, receivers, null, 0, null, null, false, true, true, -1); queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } } return sticky; } 
           
          
         
        
       
      
     
    
  

这段code中有几个变量需要说明:

  • mRegisteredReceivers
 / * 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<>(); 
  

HashMap变量,用于保存IIntentReceiver和对应ReceiverList的关系,即使用接收者(receiver)的IBinder为key,value是receiver对应的ReceiverList(因为一个receiver可能对应多个IntentFilter,所以用List来保存IntentFilter)。

  • mReceiverResolver
 / * Resolver for broadcast intents to registered receivers. * Holds BroadcastFilter (subclass of IntentFilter). */ final IntentResolver 
  
    mReceiverResolver = new IntentResolver 
   
     () { ...//实现部分方法 } 
    
  

保存receiver设置的过滤条件(IntentFilter)

关联如下:

【Broadcast】registerReceiver流程

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/199378.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月20日 下午1:07
下一篇 2026年3月20日 下午1:07


相关推荐

  • 在吗?认识一下JWT(JSON Web Token) ?[通俗易懂]

    在吗?认识一下JWT(JSON Web Token) ?

    2022年2月14日
    47
  • Python:Flask使用jsonify格式化时间

    Python:Flask使用jsonify格式化时间代码如下#-*-coding:utf-8-*-fromdatetimeimportdatetime,datefromflask.jsonimportJSONEncoderclassCustomJSONEncoder(JSONEncoder):defdefault(self,obj):ifisinstance(obj,datetime):returnobj.strftime(‘%Y-%m-%d%H:%M:%

    2022年5月20日
    82
  • 【强化学习】Deep Q Network(DQN)算法详解

    【强化学习】Deep Q Network(DQN)算法详解DQN DeepQ Learning 是将深度学习 deeplearning 与强化学习 reinforcemen 相结合 实现了从感知到动作的端到端的革命性算法 使用 DQN 玩游戏的话简直 6 的飞起 其中 fladdybird 这个游戏就已经被 DQN 玩坏了 当我们的 Q table 他过于庞大无法建立的话 使用 DQN 是一种很好的选择 1 算法思想 DQN 与 Qleanring 类似

    2026年3月18日
    2
  • oracle在schema是什么意思?

    oracle在schema是什么意思?看来有些人还在 schema 不明白的真正含义 今天 我再次整理 我希望能帮助 我们先来看看它们的定义 Aschemaisaco usedbyauser Schemaobject sdata

    2026年3月19日
    1
  • 什么是mdc_mdc网站

    什么是mdc_mdc网站MDC中包含的可以被同一线程中执行的代码所访问内容。当前线程的子线程会继承其父线程中的MDC的内容。记录日志时,只需要从MDC中获取所需的信息即可。简单来说就是日志的增强功能,如果配置了MDC,并添加了相应的keyvalue,就会在打日志的时候把key对应的value打印出来。内部是用ThreadLocal来实现的,可以携带当前线程的context信息。转载于…

    2025年7月5日
    4
  • 云服务器搭建青龙面板每日自动拿京豆

    云服务器搭建青龙面板每日自动拿京豆前言:之前网上有只要扫码一下就可以每天领上百京豆和一些红包的活动,后来呢,扫码就失效了,但是呢,这背后的技术还没有失效。这白嫖活动其实就是用脚本代替我们去参与京东的各种活动,去获取红包和京豆,而这些脚本是部署在电脑上,定时去执行的,接下来,根据网上的大佬的教程,我们也来实现一下。每天100-200京豆不等,坐收渔利,快来试试吧。一、安装前的准备​青龙面板是使用Docker来安装的,理论上,只要有可以运行Docker的电脑都可以进行安装。但是呢,因为脚本要定时运行,所以最好安装在服务器上,或

    2022年10月14日
    6

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号