broadcast receiver_consolidator

broadcast receiver_consolidator应用调用RegisterReciever,实质是调用的ContextImpl的registerReceiver,接下来跟一下这个流程:@OverridepublicIntentregisterReceiver(BroadcastReceiverreceiver,IntentFilterfilter){returnregisterReceiver(receiver,…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

应用调用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<LoadedApk.ReceiverDispatcher> mDispatcher;
            final LoadedApk.ReceiverDispatcher mStrongRef;

            InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
                mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(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<Intent> 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<String> actions = filter.actionsIterator();
            if (actions == null) {
                ArrayList<String> noAction = new ArrayList<String>(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<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);
                        }
                    }
                }
            }
        }

        //在stickyIntents中查询和IntentFilter匹配的intent
        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.
                ...//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<Intent>();
                    }
                    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<IBinder, ReceiverList> 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<BroadcastFilter, BroadcastFilter> mReceiverResolver
            = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
        ...//实现部分方法
    }

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

关联如下:

broadcast receiver_consolidator

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

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/194627.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 好博客[通俗易懂]

    好博客[通俗易懂]Elar的博客 http://www.cnblogs.com/elaron/peghoty的博客 http://blog.csdn.net/itplus/article/details/10484553炼数成金         http://f.dataguru.cn/thread-339602-1-1.htmlverydemo    http://www.verydemo.

  • VS Code关闭eslint校验

    VS Code关闭eslint校验一、产生原因:在编写vue代码的时候,一直因为格式问题报错,按照要求改了格式,虽不报错,但当选择格式化文档,就会再次报错,所以需要关闭格式校验功能。二、解决办法:①:若报错,可将鼠标放在报错位置,按照提示内容,单机右键,选择快速恢复;但后期影响继续存在②:关闭校验功能步骤:1.点击左下角的设置图标并选择设置2.搜索eslint,如图并勾选可取消报错:3.重启VSCode,编译时不再报错…

  • 浅谈Console.WriteLine();「建议收藏」

    今日看《老粱故事汇》,介绍日本已逝巨星高仓健,才初步对此人有所了解。老高一生演绎了许多经典的影幕形象,男主角都收获了真挚的爱情……可现实生活中,真实的老高,却一辈子只经历过一次婚姻,在离婚后终究不能从失败的婚姻中走出,最终孤老一生……所以,看事物,看人,不能光看表面,要有一双发现的眼睛,看到他的本质……   借此机会,讲一个C#中用于输出的最常见不过的语句的一个注意事项……谈到Cons

  • Nginx的https配置记录以及http强制跳转到https的方法梳理

    Nginx的https配置记录以及http强制跳转到https的方法梳理Nginx的https配置记录以及http强制跳转到https的方法梳理

  • 安卓反编译_apk可以反编译吗

    安卓反编译_apk可以反编译吗本帖最后由好奇害死猫咪啊于2017-5-621:48编辑本教程为长期更新贴,有问题请及时反馈。如有更新请恕不另行通知。【前言】闲来无事水一贴。。。今天写个教程吧,反编译SystemUI实现状态栏时钟居中。其实说实话本来对华为靠右边的时间不怎么介意的,可一位朋友说什么也想换成类似iPhone的居中式,甚至不惜去刷XP框架,装重力工具箱。。当然了,结果大家可能已经想到了,首先是重力工…

  • mac 安装ll命令[通俗易懂]

    mac 安装ll命令[通俗易懂]mac安装ll命令mac-bash:ll:commandnotfound在linux系统下我们经常使用ll、la命令。但在mac系统时缺没有。提示:-bash:ll:commandnotfound。这是因为ll、la不是真的命令,而是一些常用命令和参数搭配的别名。所以我们在MacOS下配置下就好了。1、跳到个人目录下面localhost:~huangfy20$cdlocalhost:~huangfy20$pwd/Users/huangfy202、打开.bash

发表回复

您的电子邮箱地址不会被公开。

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