Android 广播的注册流程

引言

广播是一种典型的发布/订阅模式,消息的生产者发布消息,而接收者订阅感兴趣的信息。高内聚低耦合性是判断软件设计好坏的标准,Broadcast把高内聚低耦合做得非常好,当你想发送广播的时候,你根本不用知道接收者的名字,也不用关心谁来接收,你只管发消息即可。



由图可知:广播主要分为三个阶段。第一个阶段:广播接收者APP1、APP2、APP3先往AMS注册感兴趣的广播。第二个阶段:广播发送者APP4发送一个广播。第三个阶段:AMS查找谁对APP4发送的广播感兴趣,找到后就把广播发送给对其感兴趣的广播接收者APP1、APP2、APP3.

应用层如何注册动态广播

    private static final String TAG = "TEST_BROADCAST";
    public static final String ACTION_TEST_BROADCAST = "android.intent.action.TEST_BROADCAST";
    public static final String ACTION_TEST_BROADCAST2 = "android.intent.action.TEST_BROADCAST2";
    private void registerReceiver() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ACTION_TEST_BROADCAST);
        intentFilter.addAction(ACTION_TEST_BROADCAST2);
        registerReceiver(mBroadcastReceiver,intentFilter);
    }
    public static BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(ACTION_TEST_BROADCAST)){
                Log.d(TAG, "mBroadcastReceiver onReceive action = " + ACTION_TEST_BROADCAST);
            } else if (intent.getAction().equals(ACTION_TEST_BROADCAST2)){
                Log.d(TAG, "mBroadcastReceiver onReceive action = " + ACTION_TEST_BROADCAST2);
            }
        }
    };
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mBroadcastReceiver);
    }

通过方法registerReceiver注册一个广播。它需要两个参数,第一个参数类型是BroadcastReceiver,第二个参数类型是IntentFilter。BroadcastReceiver用来接收广播,IntentFilter用来存放广播的Action等信息。目的在将Action与BroadcastReceiver进行绑定,Action与BroadcastReceiver在这里是多对一的关系,在其他场景下可能是多对多的关系。

流程分析

应用进程部分

registerReceiver是广播进行注册的核心方法,我们看看这个方法的调用过程。registerReceiver调用的是定义在ContextWrapper中的方法。

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

ContextWrapper类中的registerReceiver方法又调用了mBase对象的registerReceiver,mBase指的是ContextImpl对象。

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

两个参数的会调用4个参数的。其中broadcastPermission和Handler类型的数据传入null。

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

registerReceiver又会调用registerReceiverInternal。这里增加了三个参数。第一个getUserId()是进程的userid,第二个getOuterContext()是MainActivity对象,第三个flags是一个int类型的值,这里传入的是0. 我们看下registerReceiverInternal。

    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) {
                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 {
            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是前面传递过来的BroadcastReceiver类型的对象,它不为空,第一个if条件成立。context是getOuterContext的值,值为MainActivity对象,也不为空。变量mPackageInfo是一个LoadedApk类型的变量,它用来负责处理广播的接收,发送广播之后会经过它分发出去,它也不为空(这个的赋值过程以后再讲,我们着眼于重点部分),所以if (mPackageInfo != null && context != null) {成立。scheduler为空,因为传递的过程中赋值给null,所以这里scheduler会通过mMainThread的getHandler方法获得Handler对象,这个Handler就是ActivityThread中的Handler对象,也就是主线程的Handler对象。接着,会通过mPackageInfo的getReceiverDispatcher获取一个IIntentReceiver类型的对象rd,它是一个binder对象。

我们看下getReceiverDispatcher方法。它一共有5个参数,分别是BroadcastReceiver类型的对象,MainActivity对象,Handler对象,Instrumentation对象,以及一个bool类型的变量。

    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();
        }
    }
    private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
        = new ArrayMap<>();

这里首先会拿一把锁mReceivers,mReceivers如上,是一个ArrayMap数组,key是Context类型的,value也是一个ArrayMap,k是BroadcastReceiver类型,v是ReceiverDispatcher类型。
接着看第一个if,registered是传递进来的,是true,所以这个条件成立,条件成立就会去mReceivers中查找是否有以传入进来的context对象为key的value,如果有取出这个value,也就是ArrayMap<BroadcastReceiver, ReceiverDispatcher>,接着看是否有以当前传入进来的BroadcastReceiver对象为key的value,也就是LoadedApk.ReceiverDispatcher。然后进入第二个判断条件,如果LoadedApk.ReceiverDispatcher对象为null,也就是ArrayMap<BroadcastReceiver, ReceiverDispatcher>不存在以BroadcastReceiver对象为key,LoadedApk.ReceiverDispatcher为value的数据,这个时候就会new一个ReceiverDispatcher对象。因为if (registered) {为true,接下来往mReceivers存入Context、BroadcastReceiver、ReceiverDispatcher,当然这里的Context就是MainActivity对象。说这么多,其实就是将MainActivity对象,BroadcastReceiver对象,ReceiverDispatcher对象存放在类型为ArrayMap的mReceivers数据结构中。

ReceiverDispatcher,顾名思义,是一个广播分发器。从mReceivers数据结构就可以得出,通过MainActivity对象就可以找到ArrayMap<BroadcastReceiver, ReceiverDispatcher>,通过BroadcastReceiver对象就可以知道ReceiverDispatcher。

现在看下getReceiverDispatcher的返回值,它的类型是IIntentReceiver,通过ReceiverDispatcher的getIIntentReceiver方法获取。我们看下ReceiverDispatcher和getIIntentReceiver。

    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;
            }
        ...
        final IIntentReceiver.Stub mIIntentReceiver;
        ...
        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();
        }
    ...
        BroadcastReceiver getIntentReceiver() {
            return mReceiver;
        }
        IIntentReceiver getIIntentReceiver() {
            return mIIntentReceiver;
        }
    ...
    }

由上可知,getIIntentReceiver返回mIIntentReceiver,它是InnerReceiver类的对象。InnerReceiver是ReceiverDispatcher的内部类,创建是在ReceiverDispatcher构造方法中,InnerReceiver继承自IIntentReceiver.Stub,它是一个Binder对象。InnerReceiver保存了外部类ReceiverDispatcher的对象。所以通过返回的InnerReceiver binder对象,就可以找到ReceiverDispatcher对象。如图所示:


mReceivers.png

现在返回registerReceiverInternal方法中。

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

registerReceiverInternal获取到IIntentReceiver binder对象之后,会通过ActivityManager调用registerReceiver,它是一个binder调用,它一共有7个参数:第一个参数是ApplicationThread binder对象,第二个参数是包名,第三个参数IIntentReceiver binder对象,第四个参数Intentfilter对象,第五个参数是广播权限,第六个参数是进程的userid,第七个参数是一个int类型的flag。

总结:

  1. 一个Context(Activity或者Service)可能会有多个BroadcastReceiver,多个BroadcastReceiver又一一对应多个ReceiverDispatcher,多个ReceiverDispatcher又一一对应多个IIntentReceiver。


    mReceivers.png
  2. 你会发现在应用层并没有处理filter对象,而是当作参数传给了system_server进程。

system_server 部分

ActivityManager.getService().registerReceiver会调用到AMS的registerReceiver方法。

    public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
            int flags) {
        ...
        ProcessRecord callerApp = null;
    ...
        int callingUid;
        int callingPid;
    ...
        synchronized(this) {
            // 1
            if (caller != null) {
                callerApp = getRecordForAppLocked(caller);
         ...
                callingUid = callerApp.info.uid;
                callingPid = callerApp.pid;
            } else {
                callerPackage = null;
                callingUid = Binder.getCallingUid();
                callingPid = Binder.getCallingPid();
            }
        ...

            // Collect stickies of users
        ...
        }

    ...

        // The first sticky in the list is returned directly back to the client.
    ...

        synchronized (this) {
        ...
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) {
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                if (rl.app != null) {
             ...
                    rl.app.receivers.add(rl);
                } 
                ...
                // 2
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            } 
            ...
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            if (rl.containsFilter(filter)) {
                Slog.w(TAG, "Receiver with filter " + filter
                        + " already registered for pid " + rl.pid
                        + ", callerPackage is " + callerPackage);
            } else {
                rl.add(bf);
         ...
                // 3
                mReceiverResolver.addFilter(bf);
            }

            // Enqueue broadcasts for all existing stickies that match
            // this filter.
        ...

            return sticky;
        }
    }
    /**
     * 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<>();
 /**
     * Resolver for broadcast intents to registered receivers.
     * Holds BroadcastFilter (subclass of IntentFilter).
     */
    final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
            = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
       ...
    };
    ReceiverList(ActivityManagerService _owner, ProcessRecord _app,
            int _pid, int _uid, int _userId, IIntentReceiver _receiver) {
        owner = _owner;
        receiver = _receiver;
        app = _app;
        pid = _pid;
        uid = _uid;
        userId = _userId;
    }
    BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList,
            String _packageName, String _requiredPermission, int _owningUid, int _userId,
            boolean _instantApp, boolean _visibleToInstantApp) {
        super(_filter);
        receiverList = _receiverList;
        packageName = _packageName;
        requiredPermission = _requiredPermission;
        owningUid = _owningUid;
        owningUserId = _userId;
        instantApp = _instantApp;
        visibleToInstantApp = _visibleToInstantApp;
    }
    /**
     * All filters that have been registered.
     */
    private final ArraySet<F> mFilters = new ArraySet<F>();

AMS的registerReceiver主要分为三个部分,分别是代码1,代码2,代码3.
代码1:利用传递过来的ApplicationThread binder对象获取注册广播的应用的信息的存储变量callerApp,它的类型是ProcessRecord。在这里获取应用的uid和进程的pid。system_server如果注册的广播,会走到else部分,即callerPackage=null。
代码2:mRegisteredReceivers是一个以IIntentReceiver为key,以rl即ReceiverList列表为value的hashmap,IIntentReceiver不再多做解释,ReceiverList用来保存IIntentReceiver。
代码3:BroadcastFilter对象的目的是关联ReceiverList和IntentFilter。mReceiverResolver存储所有的BroadcastFilter到mFilters。


mRegisteredReceivers_mReceiverResolver.png

参考

忘了参考的哪里了,大部分自己看的。继续努力。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 141,390评论 1 297
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 60,682评论 1 254
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 93,205评论 0 211
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 40,718评论 0 171
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 48,406评论 1 250
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 38,590评论 1 170
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 30,271评论 2 267
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,052评论 0 163
  • 想象着我的养父在大火中拼命挣扎,窒息,最后皮肤化为焦炭。我心中就已经是抑制不住地欢快,这就叫做以其人之道,还治其人...
    爱写小说的胖达阅读 28,801评论 6 227
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 32,404评论 0 212
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,176评论 2 212
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 30,489评论 1 222
  • 白月光回国,霸总把我这个替身辞退。还一脸阴沉的警告我。[不要出现在思思面前, 不然我有一百种方法让你生不如死。]我...
    爱写小说的胖达阅读 24,156评论 0 31
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,031评论 2 210
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 31,402评论 3 201
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,583评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 25,927评论 0 163
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 33,352评论 2 228
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 33,478评论 2 229

推荐阅读更多精彩内容