Boardcast Receiver 源码分析:广播的动态注册、发送和接收过程

动态注册过程

ContextWrapper#registerReceiver(以下代码基于API26)

动态注册的过程从ContextWrapper的registerReceiver方法开始

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

和Activity、Service一样,ContextWrapper没有做任何操作,而是把任务交给了ContextImpl(mBase的实现类型是ContextImpl)来完成。接着看ContextImpl的registerReceiver方法。

ContextImpl#registerReceiver

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

又调用自己的registerReceiverInternal方法

ContextImpl#registerReceiverInternal

    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context, int flags) {
            
        IIntentReceiver rd = null;
        
        //广播接收器不为空时,获取IIntentReceiver对象(IIntentReceiver是一个Binder接口)
        if (receiver != null) {
            if (mPackageInfo != null && context != null) {
                //...
                rd = mPackageInfo.getReceiverDispatcher(
                    receiver, context, scheduler,
                    mMainThread.getInstrumentation(), true);
            } else {
                //...
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        
        try {
            //通过AMS的registerReceiver方法注册广播
            final Intent intent = ActivityManager.getService().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                    broadcastPermission, userId, flags);
            //...
            return intent;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

为什么需要先将BroadcastReceiver转化为IIntentReceiver?

因为广播的注册过程是一个进程间通信的进程,而BroadcastReceiver是Android的一个组件,不能直接跨进程传递,而IIntentReceiver是一个Binder接口,可以跨进程,所以需要先将BroadcastReceiver转化为IIntentReceiver。

下面看一下IIntentReceiver的获取,无论是哪种情况,最后都是调用LoadedApk.ReceiverDispatcher的getIIntentReceiver方法

LoadedApk.ReceiverDispatcher#getIIntentReceiver

    IIntentReceiver getIIntentReceiver() {
        return mIIntentReceiver;
    }

其中mIIntentReceiver是一个IIntentReceiver.Stub对象

    final IIntentReceiver.Stub mIIntentReceiver;

mIIntentReceiver是在ReceiverDispatcher的构造方法中初始化的

    ReceiverDispatcher(BroadcastReceiver receiver, Context context,
            Handler activityThread, Instrumentation instrumentation,
            boolean registered) {
        //...

        mIIntentReceiver = new InnerReceiver(this, !registered);

        //...
    }

可以看到,最终IIntentReceiver的实现类是LoadedApk.ReceiverDispatcher.InnerReceiver

继续看回注册过程:

    //ActivityManager.getService()返回的是ActivityManagerService对象
    final Intent intent = ActivityManager.getService().registerReceiver(
            mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
            broadcastPermission, userId, flags);
    //...
    return intent;

可以看到,注册过程的真正实现是AMS的registerReceiver方法

ActivityManagerService#registerReceiver

    public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
            int flags) {
        
        //...

        synchronized (this) {
            //...
            
            //获取该receiver(IIntentReceiver对象)对应的ReceiverList
            //ReceiverList继承于ArrayList<BroadcastFilter>,是一个存储BroadcastFilter的集合
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            
            //若rl为空,则根据receiver创建对应的ReceiverList,并使两者建立映射关系存入HashMap中
            if (rl == null) {
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                //...
                
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            }   
            //...
            
            //BroadcastFilter继承于IntentFilter
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            //将该BroadcastFilter添加进ReceiverList中
            rl.add(bf);

            mReceiverResolver.addFilter(bf);

            //...
        }
    }

其中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<>();

可以看到,一个IIntentReceiver对应着一个ReceiverList

最终,通过HashMap把IIntentReceiver与对应的ReceiverList保存起来;而ReceiverList又把可以启动该BroadcastReceiver的IntentFilter保存起来。

发送、接收普通广播

以下是一个发送普通广播的例子:

    Intent intent = new Intent();
    intent.setAction("FIRST_RECEIVER");     
    sendBroadcast(intent);      //发送广播

仍然是从ContextWrapper开始,调用其sendBroadcast方法

ContextWrapper#sendBroadcast

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

依然是交给ContextImpl来处理,调用其sendBroadcast方法

ContextImpl#sendBroadcast

    @Override
    public void sendBroadcast(Intent intent) {
        //...
        try {
            intent.prepareToLeaveProcess(this);
            //调用AMS的broadcastIntent方法
            ActivityManager.getService().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                    getUserId());
        } //...
    }

ContextImpl也没做什么,它直接调用AMS的broadcastIntent方法

ActivityManagerService#broadcastIntent

    public final int broadcastIntent(IApplicationThread caller,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle resultExtras,
            String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean serialized, boolean sticky, int userId) {
        //...
        synchronized(this) {
            //...
            
            int res = broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null,
                    intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                    requiredPermissions, appOp, bOptions, serialized, sticky,
                    callingPid, callingUid, userId);

            //...
            return res;
        }
    }

继续调用broadcastIntentLocked方法

ActivityManagerService#broadcastIntentLocked

    final int broadcastIntentLocked(ProcessRecord callerApp,
            String callerPackage, Intent intent, String resolvedType,
            IIntentReceiver resultTo, int resultCode, String resultData,
            Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
        //...

        //添加这个标志后,广播不会发送给已经停止的应用
        intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

        //...
       
        //判断是否有添加FLAG_RECEIVER_REPLACE_PENDING标记位
        //这个flag将会将之前的Intent替代掉。加了这个flag,在发送一系列的这样的Intent之后, //中间有些Intent有可能在你还没有来得及处理的时候,就被替代掉了。
        final boolean replacePending =
                (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
                
        //...

        if ((receivers != null && receivers.size() > 0)
                || resultTo != null) {
            //获取AMS的广播队列
            BroadcastQueue queue = broadcastQueueForIntent(intent);
            //先将匹配的广播接收器封装成一个BroadcastRecord对象r
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
                    resultData, resultExtras, ordered, sticky, false, userId);

            //...

            final BroadcastRecord oldRecord =
                    replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
            if (oldRecord != null) {
                // Replaced, fire the result-to receiver.
                //...
            } else {
                //将BroadcastRecord对象r插入广播队列queue中
                queue.enqueueOrderedBroadcastLocked(r);
                //在BroadcastRecord中发送广播
                queue.scheduleBroadcastsLocked();
            }
            
        } //...

        return ActivityManager.BROADCAST_SUCCESS;
    }

该方法最终将满足条件的广播接收器封装到BroadcastRecord中,并添加到广播队列BroadcastQueue中,通过BroadcastQueue的scheduleBroadcastsLocked方法发送给相应的广播接收器。接下来看一下BroadcastQueue的scheduleBroadcastsLocked方法。

BroadcastQueue#scheduleBroadcastsLocked

    public void scheduleBroadcastsLocked() {
        //...
        
        //mBroadcastsScheduled是一个布尔变量,表明是否发送过BROADCAST_INTENT_MSG消息
        if (mBroadcastsScheduled) { 
            return;
        }
        
        //发送BROADCAST_INTENT_MSG消息
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }

对BROADCAST_INTENT_MSG消息的处理是

    case BROADCAST_INTENT_MSG: {
        //...
        processNextBroadcast(true);
    } break;

可以看到,收到BROADCAST_INTENT_MSG消息后,执行processNextBroadcast方法

BroadcastQueue#processNextBroadcast

    final void processNextBroadcast(boolean fromMsg) {
        synchronized(mService) {
            BroadcastRecord r;

            //...

            //如果是从BROADCAST_INTENT_MSG消息而来,重置mBroadcastsScheduled
            if (fromMsg) {
                mBroadcastsScheduled = false;
            }

            //发送无序广播,无序广播存储在mParallelBroadcasts中
            while (mParallelBroadcasts.size() > 0) {
                r = mParallelBroadcasts.remove(0);
                
                //...

                final int N = r.receivers.size();
                for (int i=0; i<N; i++) {
                    Object target = r.receivers.get(i);
                    //该方法负责将广播发送给特定的接收器
                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
                }
                addBroadcastToHistoryLocked(r);

            }
    }

可以看到,将广播发送到对应接收器的过程是通过deliverToRegisteredReceiverLocked方法实现的

BroadcastQueue#deliverToRegisteredReceiverLocked

    private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered, int index) {
        
        //...
        
        try {
            if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
                //...
            } else {
                //通过该方法完成具体的发送过程
                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                        new Intent(r.intent), r.resultCode, r.resultData,
                        r.resultExtras, r.ordered, r.initialSticky, r.userId);
            }
            //...
        } //...
    }

继续看performReceiveLocked方法

BroadcastQueue#performReceiveLocked

    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser) throws RemoteException {

        if (app != null) {
            if (app.thread != null) {
                try {
                    //app.thread的实现是ActivityThread.ApplicationThread
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.repProcState);

                } //...
            } //...
        } //...
    }

接着调用ApplicationThread的scheduleRegisteredReceiver方法

ActivityThread.ApplicationThread#scheduleRegisteredReceiver

    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);
        //调用InnerReceiver的performReceive方法
        receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                sticky, sendingUser);
    }

ReceiverDispatcher.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) {
                rd = null;
            } else {
                rd = mDispatcher.get();
            }
            //...
            
            if (rd != null) {
                //调用LoadedApk.ReceiverDispatcher的performReceive方法
                rd.performReceive(intent, resultCode, data, extras,
                        ordered, sticky, sendingUser);
            } //...
        }
    }

继续调用LoadedApk.ReceiverDispatcher的performReceive方法

LoadedApk.ReceiverDispatcher#performReceive

    public void performReceive(Intent intent, int resultCode, String data,
            Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
        
        //Args是LoadedApk.ReceiverDispatcher的内部类
        final Args args = new Args(intent, resultCode, data, extras, ordered,
                sticky, sendingUser);
        
        //...
        
        //mActivityThread是一个Handler对象,指向ActivityThread中的handler对象
        if (intent == null || !mActivityThread.post(args.getRunnable())) {
            //...
        }
    }

在post里面执行了Args的getRunnable方法,其实现如下

LoadedApk.ReceiverDispatcher.Args#getRunnable

    public final Runnable getRunnable() {
        return () -> {
            final BroadcastReceiver receiver = mReceiver;

            //...

            try {
                //...
                
                //回调了BoradcastReceiver的onReceive方法
                receiver.onReceive(mContext, intent);
            } //...
        };
    }

可以看到,最终在Args抛出的一个Runnable的run方法中回调了BoradcastReceiver的onReceive方法,并且是在广播接收器的主线程中执行的。

至此,普通广播的发送及接收过程分析完毕。

参考

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容