技术控

    今日:120| 主题:49552
收藏本版 (1)
最新软件应用技术尽在掌握

[其他] BroadcastReceiver 的工作过程分析

[复制链接]
三生池水覆流年 发表于 2016-10-5 04:58:48
149 0

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
《 Android开发艺术探索 》 笔记 - 了解 BroadcastReceiver 的注册过程以及广播的发送与接收的过程。  
  
       
  • 文章来源:itsCoder 的      WeeklyBolg项目   
  • itsCoder主页:      http://itscoder.com/   
  • 作者:Melodyxxx   
  • 审阅者:      JoeSteven  
  在 Android 中,广播的注册分为静态注册和动态注册,静态注册是指在 AndroidManifest 文件中注册,动态注册是指在 Java 代码中通过    registerReceiver方法注册的。静态注册的广播在应用安装时由系统自动完成注册,具体来说是由 PMS (PackageManagerService)来完成注册的。本文只分析广播的动态注册过程。  
    本文为 《 Android开发艺术探索 》 笔记
    源码为 Android 6.0
    广播的注册过程  

  首先,分析过程当然从注册的入口说起,我们平常在 Activity 内写 registerReceiver 来注册动态广播调用的是父类 ContextWrapper 内的 registerReceiver 方法,代码如下:
           
  1. @Overridepublic Intent registerReceiver(    BroadcastReceiver receiver, IntentFilter filter) {    return mBase.registerReceiver(receiver, filter);}
复制代码
       内部使用的是典型的桥接模式,转而调用 mBase 的 registerReceiver 方法,这里的 mBase 是一个 Context 类型对象,其实现类是 ContextImpl (在 Activity 的启动过程和创建过程中可以分析得出其实现类是 ContextImpl ),所以下面直接来看 ContextImpl 的    registerReceiver方法,如下:  
           
  1. @Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {    return registerReceiver(receiver, filter, null, null);}
复制代码
       继续跟下去:
           
  1. @Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,        String broadcastPermission, Handler scheduler) {    return registerReceiverInternal(receiver, getUserId(),            filter, broadcastPermission, scheduler, getOuterContext());}
复制代码
       内部调用了 registerReceiverInternal ,再继续跟下去:
           
  1. private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,        IntentFilter filter, String broadcastPermission,        Handler scheduler, Context context) {    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();        }    }    try {        return ActivityManagerNative.getDefault().registerReceiver(                mMainThread.getApplicationThread(), mBasePackageName,                rd, filter, broadcastPermission, userId);    } catch (RemoteException e) {        return null;    }}
复制代码
       上面一段代码不长,也很好理解,看代码的最后面一段:  
           
  1. ...try {    return ActivityManagerNative.getDefault().registerReceiver(            mMainThread.getApplicationThread(), mBasePackageName,            rd, filter, broadcastPermission, userId);} catch (RemoteException e) {    return null;}...
复制代码
       先看这个 ActivityManagerNative 的    getDefault()方法:  
           
  1. static public IActivityManager getDefault() {    return gDefault.get();}
复制代码
       返回类型是 IActivity Manager ,是一个 Binder 接口,实际上就是 ActivityManagerService (后面简称 AMS ),因为 ActivityManagerNative 继承自 Binder 且实现了 IActivityManager 接口,而 AMS 继承自 ActivityManagerNative 。
  所以到这里可以得到的结论是,注册广播时,最终会跨进程调用交给 AMS 去完成注册。
  因为需要 AMS 来注册,所以需要把广播传给 AMS ,但是这里 ActivityManagerService 的    registerReceiver方法的第三个参数传的是 IIntentReceiver 类型的 rd ,为 IIntentReceiver 类型对象,不像类似启动 Service 或者 Activity 直接传递 Intent 给 AMS 那样来直接传递广播。之所以采用 IIntentReceiver 而不是直接采用 BroadcastReceiver ,这是因为上述注册过程是一个进程间通信的过程,而 BroadcastReceiver 作为 Android 的一个组件是不能直接跨进程传递的,所以需要 IIntentReceiver 来中转一下,毫无疑问, IIntentReceiver 必须是一个 Binder 接口。  
  所以看第三个参数 IIntentReceiver 的实例化过程,其中可以看到:  
           
  1. ...rd = mPackageInfo.getReceiverDispatcher(    receiver, context, scheduler,    mMainThread.getInstrumentation(), true);...
复制代码
       mPackageInfo 为 LoadApk 类型对象,看    getReceiverDispatcher方法实现:  
           
  1. 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();    }}
复制代码
       最后一行    return rd.getIIntentReceiver();,这里的 rd 为 LoadedApk 的内部类 ReceiverDispatcher , ReceiverDispatcher 的内部封装了 BroadcastReceiver 和 InnerReceiver ( InnerReceiver 为 ReceiverDispatcher 的内部类)对象。这个 InnerReceiver 继承自 IIntentReceiver.Stub ,很明显是 AIDL 的形式,没错,就是 IIntentReceiver 的具体实现,其也含有 ReceiverDispatcher 的弱引用。 ReceiverDispatcher的    getIIntentReceiver()方法返回的就是这个 InnerReceiver 对象,将其传递给了 AMS 。 ReceiverDispatcher 构造器实现:  
           
  1. 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();}
复制代码
       再来梳理一遍,跨进程交由 AMS 去注册广播的时候,将 InnerReceiver 对象传递给了 AMS , InnerReceiver 是 ReceiverDispatcher 的内部类, ReceiverDispatcher 内保存了要注册的 BroadcastReceiver 和继承了 IIntentReceiver.Stub 的 InnerReceiver , InnerReceiver 也有其外部类的 ReceiverDispatcher 的引用,后面可以方便的调用 ReceiverDispatcher 内部的 BroadcastReceiver 的    onReceive()方法。  
  下面再看 AMS 中的 registerReceiver 的方法,这个方法很长,只看关键的部分:  
           
  1. public Intent registerReceiver(IApplicationThread caller, String callerPackage,        IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {        ...        ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());        ....        // 将远程receiver(IIntentReceiver)对象保存起来        if (rl == null) {                ...                mRegisteredReceivers.put(receiver.asBinder(), rl);                ...        }            ....    BroadcastFilter bf = new BroadcastFilter(filter/*远程IntentFilter*/, rl, callerPackage,            permission, callingUid, userId);    rl.add(bf);    if (!bf.debugCheck()) {        Slog.w(TAG, "==> For Dynamic broadcast");    }        // 保存远程IntentFilter    mReceiverResolver.addFilter(bf);        ....
复制代码
       rl 是一个 ReceiverList 对象,ReceiverList 继承自 ArrayList,只用于保存 BroadcastFilter 的。BroadcastFilter 看源码确实是封装了一些信息,有那个rl,还有包名,权限,UID , UserID什么之类的。因为一个 Receiver 可能被多个 IntentFilter 注册,所以 Android 采用了一个 HashMap 数据结构,key 就是那个传递到AMS的那个IIntentReceiver Binder(可以理解成一个Receiver,因为Receiver不能直接传,前面有说道),value 就是这个rl ReceiverList 对象了(可以理解其里面全是这个 Receiver 注册的IntentFilter,BroadcastFilter 就是继承自 IntentFilter 的) ,所以AMS注册时,先会取出这个 Receiver 之前已注册过的所有的意图集合( ReceiverList )
  最终在 AMS 内,将远程 receiver ( IIntentReceiver ) 对象和远程 IntentFilter 保存起来,完成动态广播的注册。
  广播的发送与接收过程  

  下面开始分析发送广播和接收广播的过程,也是先从 ContextImpl 的    sendBroadcast方法出发:  
           
  1. @Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {    return registerReceiver(receiver, filter, null, null);}0
复制代码
       内部没干什么事情,由上面分析可知,直接跨进程交由AMS处理,调用了 AMS 的    broadcastIntent方法,在 AMS 的    broadcastIntent方法内调用了    broadcastIntentLocked方法,这个方法很长,先看该方法的最前面有下面这句话:  
           
  1. @Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {    return registerReceiver(receiver, filter, null, null);}1
复制代码
       从注释可以看出,添加这个标记的目的是默认广播不会传递给那些已经停止的应用,一个应用处于停止状态有两种情形:
  
       
  • 应用安装后未运行   
  • 应用被手动或者其他应用强行停止了  
  从Android 3.1开始,为Intent添加了两个标记位:
  
       
  •       FLAG_EXCLUDE_STOPPED_PACKAGES :表示不包含已经停止的应用,这个时候广播不会发送给已经停止的应用   
  •       FLAG_INCLUDE_STOPPED_PACKAGES :表示包含已经停止的应用,这个时候广播会发送给已经停止的应用  
  从 Android 3.1 开始,系统为所有的广播默认添加了    FLAG_EXCLUDE_STOPPED_PACKAGES标志,这样做是为了防止广播无意间或者在不必要的时候调起已经停止运行的应用。如果的确需要调起已经停止的应用,那么只需要为广播的Intent添加    FLAG_INCLUDE_STOPPED_PACKAGES标记即可。当两个标记共存时,以    FLAG_INCLUDE_STOPPED_PACKAGES为准。  
  下面继续分析发送流程,在    broadcastIntentLocked内部,会根据 intent-filter 查找出匹配的广播接收者并经过一系列的过滤,最终会将满足条件的广播接收者添加到 BroadcastQueue 中,接着 BroadcastQueue 就会将广播发送给相应的广播接收者,过程如下:  
           
  1. @Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {    return registerReceiver(receiver, filter, null, null);}2
复制代码
       对应 BroadcastQueue 的    enqueueParallelBroadcastLocked和    enqueueOrderedBroadcastLocked两个方法实现:  
           
  1. @Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {    return registerReceiver(receiver, filter, null, null);}3
复制代码
       在最后的    queue.scheduleBroadcastsLocked();内看广播的发送过程,下面是 BroadcastQueue 的    scheduleBroadcastsLocked方法:  
           
  1. @Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {    return registerReceiver(receiver, filter, null, null);}4
复制代码
           scheduleBroadcastsLocked里面并没有实际的处理广播,而是发送了一个    BROADCAST_INTENT_MSG消息:  
           
  1. @Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {    return registerReceiver(receiver, filter, null, null);}5
复制代码
       收到消息后,调用了    processNextBroadcast方法,在这个方法中有一段:  
           
  1. @Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {    return registerReceiver(receiver, filter, null, null);}6
复制代码
       通过注释可以看到, mParallelBroadcasts 中保存的都是无序广播,系统会遍历这个集合,然后将广播发送给它们的所有接收者,具体过程是通过    deliverToRegisteredReceiverLocked方法实现的,在    deliverToRegisteredReceiverLocked方法内部,调用了    performReceiveLocked方法,如下:  
           
  1. @Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {    return registerReceiver(receiver, filter, null, null);}7
复制代码
       上面的    app.thread就是我们最开始在 ContextImpl 中的注册广播的时候    registerReceiverInternal内传给AMS的    mMainThread.getApplicationThread():  
           
  1. @Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {    return registerReceiver(receiver, filter, null, null);}8
复制代码
       所以    app.therad就是 ApplicationThread 类型对象,下面看 ApplicationThread 的    scheduleRegisteredReceiver方法实现:  
           
  1. @Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {    return registerReceiver(receiver, filter, null, null);}9
复制代码
       直接调用了 IIntentReceiver 的    performReceive方法,这个 IIntentReceiver 就是我们上面传递给 AMS 的那个,其实现类是 LoadApk 的内部类 InnerReceiver ,而 InnerReceiver 的    performReceive方法内转而调用了其内部之前保存着的 ReceiverDispatcher 的    performReceive方法,所以下面直接看 ReceiverDispatcher 的    performReceive方法:  
           
  1. @Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,        String broadcastPermission, Handler scheduler) {    return registerReceiverInternal(receiver, getUserId(),            filter, broadcastPermission, scheduler, getOuterContext());}0
复制代码
       看    mActivityThread.post(args),这个 mActivityThread 是一个 Handler ,其实就是 ActivityThread 中的那个    mH,是一个与 UI 主线程相关联的 Handler , Args 类实现了 Runnable 接口,所以其    run方法是在主线程执行的,所以看 Args 的    run方法:  
           
  1. @Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,        String broadcastPermission, Handler scheduler) {    return registerReceiverInternal(receiver, getUserId(),            filter, broadcastPermission, scheduler, getOuterContext());}1
复制代码
       很明显,在这里终于回调了 mReceiver 的    onReceive方法,也是就我们自己继承 BroadcastReceiver 时所必须实现的那个    onReceive方法,而且是在主线程中执行的。
友荐云推荐




上一篇:Guccifer 2.0 Hacked Clinton Foundation
下一篇:48 characters enough to crash most Linux distros, says sysadmin
酷辣虫提示酷辣虫禁止发表任何与中华人民共和国法律有抵触的内容!所有内容由用户发布,并不代表酷辣虫的观点,酷辣虫无法对用户发布内容真实性提供任何的保证,请自行验证并承担风险与后果。如您有版权、违规等问题,请通过"联系我们"或"违规举报"告知我们处理。

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表手机版
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )|网站地图 酷辣虫

© 2001-2016 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表