Broadcast组件研究

本文详细介绍了Android平台中的广播组件,包括广播的类型、注册方式、发送流程及处理机制。特别是对粘性广播、有序广播的特点进行了深入剖析,并给出了广播权限设置的具体实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Broadcast组件研究

注册

简介

广播分为三种:
普通广播:这种广播可以依次传递给各个处理器去处理
有序广播:这种广播在处理器端的处理顺序是按照处理器的不同优先级来区分的,高优先级的处理器会优先截获这个消息,并且可以将这个消息删除
粘性广播:粘性消息在发送后就一直存在于系统的消息容器里面,等待对应的处理器去处理,如果暂时没有处理器处理这个消息则一直在消息容器里面处于等待状态,粘性广播的Receiver如果被销毁,那么下次重建时会自动接收到消息数据

粘性广播补充说明

  • 所有的注册者随时随地都能收到。(随时的意思是从他发出开始直到他的下次更新为止这段时间内所有注册该广播的都能收到)
  • 这条广播会更新,而且一直会维持最新的广播发送给接受者

IntentFilter相关说明
IntentFilter中具有和Intent对应的用于过滤Action,Data和Category的字段,一个隐式Intent要想被一个组件处理,必须通过这三个环节的检查。

  • 检查 Action 尽管一个Intent只可以设置一个Action,但一个Intentfilter可以持有一个或多个Action用于过滤,到达的Intent只需要匹配其中一个Action即可。 深入思考: 如果一个Intentfilter没有设置Action的值,那么,任何一个Intent都不会被通过;反之,如果一个Intent对象没有设置Action值,那么它能通过所有的Intentfilter的Action检查
  • 检查 Data 同Action一样,Intentfilter中的Data部分也可以是一个或者多个,而且可以没有。每个Data包含的内容为URL和数据类型,进行Data检查时主要也是对这两点进行比较,比较规则: 如果一个Intent对象没有设置Data,只有Intentfilter也没有设置Data时才可通过检查。 如果一个Intent对象包含URI,但不包含数据类型:仅当Intentfilter也不指定数据类型,同时它们的URI匹配,才能通过检测。 如果一个Intent对象包含数据类型,但不包含URI:仅当Intentfilter也没指定URL,而只包含数据类型且与Intent相同,才通过检测。 如果一个Intent对象既包含URI,也包含数据类型(或数据类型能够从URI推断出),只有当其数据类型匹配Intentfilter中的数据类型,并且通过了URL检查时,该Intent对象才能通过检查。
    其中URL由四部分组成:它有四个属性scheme、host、port、path对应于URI的每个部分。
  • 检查 Category Intentfilter中可以设置多个Category,Intent中也可以含有多个Category,只有Intent中的所有Category都能匹配到Intentfilter中的Category,Intent才能通过检查。也就是说,如果Intent中的Category集合是Intentfilter中Category的集合的子集时,Intent才能通过检查。如果Intent中没有设置Category,则它能通过所有Intentfilter的Category检查。 如果一个Intent能够通过不止一个组件的Intentfilter,用户可能会被问那个组件被激活。如果没有目标找到,会产生一个异常。

其他: registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler)

  • 如果需要另开线程做receiver的事情,需要指定scheduler。否则会在主线程做receiver
  • 参数三指定一个广播权限,只有拥有该权限的broadcaster才能发广播给receiver

sendOrderedBroadcast(Intent intent, String receiverPermission)参数二即为发送广播权限

    //新开线程接收广播范例
    HandlerThread handlerThread = new HandlerThread("ht");
    handlerThread.start();
    Looper looper = handlerThread.getLooper();
    Handler handler = new Handler(looper);
    context.registerReceiver(receiver, filter, null, handler); // Will not run on main thread

    //添加广播权限范例
    //sender方
    Intent broadcast = new Intent(this, MyBroadcastReceiver.class);
    sendBroadcast(broadcast, "andro.jf.mypermission");
    //Manifest增加权限
    <permission android:name="andro.jf.mypermission" 
    android:label="my_permission" 
    android:protectionLevel="dangerous"></permission>
    //receiver方
    //增加权限
    <uses-permission android:name="andro.jf.mypermission"/>
    //receiver权限
    <receiver android:name="MyBroadcastReceiver" android:exported="true" />
    //registerReceiver中不用多说

ReceiverDispatcher: 封装用户自定义的receiver对象。内部类InnerReceiver为binder对象,用于与AMS的传递与通信。
ReceiverList: 继承自ArrayList,存放了Receiver的binder对象以及其注册的BroadcastFilter列表。AMS中的mRegisteredReceivers为一个hashmap,key为receiver的binder对象。ProcessRecord的receivers中也记录了其内部的receiver对象。
BroadcastFilter: 封装了IntentFilter,增加了注册Broadcast时的来源信息。
IntentResolver: 解析Intent,在addFilter时即进行解析。其内部有mSchemeToFilter,mActionToFilter,mTypedActionToFilter三个map对象。key为对应的action(scheme或者type),value为Filter。
BroadcastRecord: 将intent封装成BroadcastRecord,交给BroadcastQueue进行处理。
BroadcastQueue: BroadcastQueue为Broadcast处理队列,分为Fg和Bg,FgBroadcastQueue会有更高的权限,被优先处理。

流程

Created with Raphaël 2.1.0ContextImplContextImplReceiverDispatcherReceiverDispatcherActivityManagerServiceActivityManagerServiceregisterReceiverregisterReceiverInternalnew将receiver,scheduler等封装成ReceiverDispatcher对象registerReceivergetStickiesLocked获取注册监听的粘性广播将receiver保存到mRegisteredReceivers中enqueueParallelBroadcastLocked将broadcast压入queue,待处理scheduleBroadcastsLocked处理粘性广播

发送

简介

流程

Created with Raphaël 2.1.0ContextImplContextImplActivityManagerServiceActivityManagerServicePackageManagerServicePackageManagerServiceBroadcastQueueBroadcastQueuesendBroadcastbroadcastIntentbroadcastIntentLocked检测callerApp是否活着检测如果是系统广播,是否是系统发出来的对一些特殊广播进行处理,比如卸载应用程序,必须在AMS中移除其activities,还有时间改变,时区改变之类处理sticky广播,1、检查是否有权限发送 2、检查是否指定目标组件处理sticky广播,如果sticky broadcast的目标不为所有人,则需要在All的队列里做一次检查。因为All User维护了另外维护了一个队列。最新android使用UserHandler维护一个多用户登录的系统。将sticky广播存入mStickyBroadcasts。mStickyBroadcasts为一个SparseArray,key为userid,value也为map。value的key为action,value为对应的intentcollectReceiverComponents如果intent不含有标记 FLAG_RECEIVER_REGISTERED_ONLY,调用collectReceiverComponents。加了该标记的broadcast不会触发组件的自启动,只发给动态注册的组件queryIntentReceivers遍历可以接收该广播的User列表,根据user id查找能够处理该intent的ReceiverInfo列表对查找出来的ReceiverInfo列表进行筛选。1、如果该receiver设置了只发给primary user,就移除该receiver;2、如果receiver设置了FLAG_SINGLE_USER,说明多个用户共用一个receiver,因此移除重复receiver从mReceiverResolver查询对应registe的receiver如果非有序广播,立即处理register的broadcast否则,合并register的广播和固定广播,一起处理enqueueParallelBroadcastLockedscheduleBroadcastsLocked

BroadcastQueue分发广播消息流程

Created with Raphaël 2.1.0BroadcastQueueBroadcastQueueBroadcastQueue(self)BroadcastQueue(self)processNextBroadcast首先处理无序广播deliverToRegisteredReceiverLocked判断是否有挂起的,未处理的broadcast准备处理有序广播队列,获取broadcast record对象r如果有序广播队列为空,代表处理完毕判断广播超时,如果距离广播第一次分发已过去时长2*mTimeoutPeriod*numReceivers,认为已经超时broadcastTimeoutLocked判断是否还有尚未处理的receiver,如果没有performReceiveLockedcancelBroadcastTimeoutLockedaddBroadcastToHistoryLocked开始处理有序广播,setBroadcastTimeoutLocked设置处理超时消息setBroadcastTimeoutLocked如果receiver类型为BroadcastFilterdeliverToRegisteredReceiverLocked如果receiver类型为静态广播1. 判断权限 2. 判断是否需要skip,重新调度处理(1、app存活但是已经崩溃 2、app的package被stop)scheduleBroadcastsLocked对于静态广播,如果app已经启动,则正常处理,调用processCurBroadcastLocked。如果app未启动,则启动该app,将其设置为mPendingBroadcast。如果启动失败,调用scheduleBroadcastsLocked重新调度
  1. 处理并行广播

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

        if (fromMsg) {
            mBroadcastsScheduled = false;
        }
    
        //对于并行广播,直接转发
        while (mParallelBroadcasts.size() > 0) {
            r = mParallelBroadcasts.remove(0);
            r.dispatchTime = SystemClock.uptimeMillis();
            r.dispatchClockTime = System.currentTimeMillis();
            final int N = r.receivers.size();
            for (int i=0; i<N; i++) {
                Object target = r.receivers.get(i);
                //处理
                deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
            }
            addBroadcastToHistoryLocked(r);
        }
    
  2. 从有序队列选取需要处理的BroadcastRecord

    //处理挂起的广播
    boolean isDead;
    synchronized (mService.mPidsSelfLocked) {
    ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);
    isDead = proc == null || proc.crashing;
    }
    if (!isDead) {
    //如果该进程还活着,可能出于启动过程中,继续等待
    return;
    } else {
    //该进程没起得来,标记该broadcast为IDLE
    //不在优先处理该广播
    mPendingBroadcast.state = BroadcastRecord.IDLE;
    mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
    mPendingBroadcast = null;
    }
    }

选取下一个要处理的broadcast

 boolean looped = false;

        do {
        // 如果队列为空,说明处理完毕,直接返回
            if (mOrderedBroadcasts.size() == 0) {
                mService.scheduleAppGcsLocked();
                if (looped) {
                    mService.updateOomAdjLocked();
                }
                return;
            }
            r = mOrderedBroadcasts.get(0);
            boolean forceReceive = false;


            int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
            if (mService.mProcessesReady && r.dispatchTime > 0) {
                long now = SystemClock.uptimeMillis();
                if ((numReceivers > 0) &&
                        (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
                   // 超时处理
                    broadcastTimeoutLocked(false); // forcibly finish this broadcast
                    // 强行认为已接收
                    forceReceive = true;
                    r.state = BroadcastRecord.IDLE;
                }
            }

            //对于有序广播,只有上层调用了finishReceiver,才能进行后续的广播
            //finishReceiver会将state设为IDLE,不为IDLE代表该广播尚未处理完毕
            if (r.state != BroadcastRecord.IDLE) {
                return;
            }

            // broadcast中的所有receiver都已经处理完毕,发送result
            if (r.receivers == null || r.nextReceiver >= numReceivers
                    || r.resultAbort || forceReceive) {
                if (r.resultTo != null) {
                    try {
                    // 如果需要返回result,进行相关处理
                        performReceiveLocked(r.callerApp, r.resultTo,
                            new Intent(r.intent), r.resultCode,
                            r.resultData, r.resultExtras, false, false, r.userId);
                        r.resultTo = null;
                    } catch (RemoteException e) {
                        r.resultTo = null; 
                    }
                }
                //取消之前预设的Timeout消息
                cancelBroadcastTimeoutLocked();
                //该broadcast不合要求,remove
                addBroadcastToHistoryLocked(r);
                mOrderedBroadcasts.remove(0);
                r = null;
                looped = true;
                continue;
            }
        } while (r == null);

        //准备处理该广播,先发送定时超时信息
            if (! mPendingBroadcastTimeoutMessage) {
            long timeoutTime = r.receiverTime + mTimeoutPeriod;
            setBroadcastTimeoutLocked(timeoutTime);
        }

Object nextReceiver = r.receivers.get(recIdx);
        // 获取下一个需要处理的receiver,如果是动态广播
        if (nextReceiver instanceof BroadcastFilter) {
            BroadcastFilter filter = (BroadcastFilter)nextReceiver;
            //进一步将该广播传递下去
            deliverToRegisteredReceiverLocked(r, filter, r.ordered);
            if (r.receiver == null || !r.ordered) {
                //如果不是有序广播或者receiver已经全部处理完
                //接着处理下一个广播
                r.state = BroadcastRecord.IDLE;
                scheduleBroadcastsLocked();
            }
            return;
        }

//此为静态广播
 ResolveInfo info =
            (ResolveInfo)nextReceiver;
        ComponentName component = new ComponentName(
                info.activityInfo.applicationInfo.packageName,
                info.activityInfo.name);

        boolean skip = false;
        int perm = mService.checkComponentPermission(info.activityInfo.permission,
                r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
                info.activityInfo.exported);
        //判断权限
        if (perm != PackageManager.PERMISSION_GRANTED) {
            ......
            // 跳过该广播
            skip = true;
        }
        if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
            r.requiredPermission != null) {
            ......
            //跳过
        }
        // 未启用OPS,略过
        if (r.appOp != AppOpsManager.OP_NONE) {
            ......
        }
        ......
        //一系列判断是否需要跳过的broadcast
        // 需要跳过的broadcast,重新调度处理其他broadcast
        if (skip) {
            r.receiver = null;
            r.curFilter = null;
            r.state = BroadcastRecord.IDLE;
            scheduleBroadcastsLocked();
            return;
        }

// 开始处理静态广播
        r.state = BroadcastRecord.APP_RECEIVE;
        String targetProcess = info.activityInfo.processName;
        r.curComponent = component;
        final int receiverUid = info.activityInfo.applicationInfo.uid;
        if (r.callingUid != Process.SYSTEM_UID && isSingleton
                && mService.isValidSingletonCall(r.callingUid, receiverUid)) {
            info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
        }
        r.curReceiver = info.activityInfo;

        //执行过程中的package不允许被stop
        try {
            AppGlobals.getPackageManager().setPackageStoppedState(
                    r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));
        } catch (RemoteException e) {
        } catch (IllegalArgumentException e) {
        }

        // Is this receiver's application already running?
        ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
                info.activityInfo.applicationInfo.uid, false);
        // 判断该app是否在运行,如果已在运行
        if (app != null && app.thread != null) {
            try {
                app.addPackage(info.activityInfo.packageName,
                        info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
                // 正常处理
                processCurBroadcastLocked(r, app);
                return;
            } catch (RemoteException e) {
            } catch (RuntimeException e) {
                //有异常,finishReceiver
                logBroadcastReceiverDiscardLocked(r);
                finishReceiverLocked(r, r.resultCode, r.resultData,
                        r.resultExtras, r.resultAbort, false);
                //重新调度
                scheduleBroadcastsLocked();
                r.state = BroadcastRecord.IDLE;
                return;
            }

//启动app
if ((r.curApp=mService.startProcessLocked(targetProcess,
                info.activityInfo.applicationInfo, true,
                r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
                "broadcast", r.curComponent,
                (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                        == null) {
           //启动app失败
            logBroadcastReceiverDiscardLocked(r);
            finishReceiverLocked(r, r.resultCode, r.resultData,
                    r.resultExtras, r.resultAbort, false);
            //重新调度
            scheduleBroadcastsLocked();
            r.state = BroadcastRecord.IDLE;
            return;
        }

        // 由于等待新启动的app处理广播消息,该广播被置为pendingBroadcast
        mPendingBroadcast = r;
        mPendingBroadcastRecvIndex = recIdx;
    }
  1. 重新调度scheduleBroadcastsLocked

    //只能调度一次
    if (mBroadcastsScheduled) {
            return;
        }
    //通过Handler,调用processNextBroadcast
    mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    
  2. 处理超时信息 broadcastTimeoutLocked

     if (fromMsg) {
            // 代表handle中是否有timeout message
            // 如果有的话,置为false,代表timeout message已经被处理
            mPendingBroadcastTimeoutMessage = false;
        }
        long now = SystemClock.uptimeMillis();
        BroadcastRecord r = mOrderedBroadcasts.get(0);
        // 是否从时限消息处理函数过来
        if (fromMsg) {
            if (mService.mDidDexOpt) {
                // Delay timeouts until dexopt finishes.
                // 等待dexopt结束,重设超时信息
                mService.mDidDexOpt = false;
                long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
                setBroadcastTimeoutLocked(timeoutTime);
                return;
            }
            if (!mService.mProcessesReady) { //系统尚未启动好
            return;
        }
    
        long timeoutTime = r.receiverTime + mTimeoutPeriod;
        if (timeoutTime > now) {
        //过早的超时广播,重设
            setBroadcastTimeoutLocked(timeoutTime);
            return;
        }
    
        BroadcastRecord br = mOrderedBroadcasts.get(0);
    // 该broadcast还在等待service结束,但是已经等了很久,因此结束整个过程,跳到下一个广播
    if (br.state == BroadcastRecord.WAITING_SERVICES) {
        br.curComponent = null;
        br.state = BroadcastRecord.IDLE;
        // 跳转到下一个广播的执行
    
        // processNextBroadcast的仍然是当前的广播,
        // 由于state发生变化,不会再进该处。
        // 会放弃该广播,并处理下一个广播,然后返回
        processNextBroadcast(false);
        return;
    }
    
    r.receiverTime = now;
    r.anrCount++;
    
    // Current receiver has passed its expiration date.
    if (r.nextReceiver <= 0) {
        Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0");
        return;
    }
    
    ProcessRecord app = null;
    String anrMessage = null;
    
    // 找到当前receiver对应的app,弹窗提示
    Object curReceiver = r.receivers.get(r.nextReceiver-1);
    Slog.w(TAG, "Receiver during timeout: " + curReceiver);
    logBroadcastReceiverDiscardLocked(r);
    if (curReceiver instanceof BroadcastFilter) {
        BroadcastFilter bf = (BroadcastFilter)curReceiver;
        if (bf.receiverList.pid != 0
                && bf.receiverList.pid != ActivityManagerService.MY_PID) {
            synchronized (mService.mPidsSelfLocked) {
                app = mService.mPidsSelfLocked.get(
                        bf.receiverList.pid);
            }
        }
    } else {
        app = r.curApp;
    }
    
    if (app != null) {
        anrMessage = "Broadcast of " + r.intent.toString();
    }
    
    // 如果挂起的broadcast即为该broadcast,直接清空
    if (mPendingBroadcast == r) {
        mPendingBroadcast = null;
    }
    
    // 结束并且重新调度下一个receiver
    finishReceiverLocked(r, r.resultCode, r.resultData,
            r.resultExtras, r.resultAbort, false);
    scheduleBroadcastsLocked();
    
    if (anrMessage != null) {
    // 弹出对话框提示ANR
        mHandler.post(new AppNotResponding(app, anrMessage));
    }
    
  3. 正常处理动态广播 deliverToRegisteredReceiverLocked

    //双向检查权限,如果权限不够,skip 为 true
    if (!skip) {
        // 以下设置为跟踪有序广播,非有序广播则不做设置
        if (ordered) {
            r.receiver = filter.receiverList.receiver.asBinder();
            r.curFilter = filter;
            filter.receiverList.curBroadcast = r;
            // 标记
            r.state = BroadcastRecord.CALL_IN_RECEIVE;
            if (filter.receiverList.app != null) {
                r.curApp = filter.receiverList.app;
                filter.receiverList.app.curReceiver = r;
                mService.updateOomAdjLocked(r.curApp);
            }
        }
        try {
            // 处理广播信息的函数
            performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                new Intent(r.intent), r.resultCode, r.resultData,
                r.resultExtras, r.ordered, r.initialSticky, r.userId);
            if (ordered) {
                r.state = BroadcastRecord.CALL_DONE_RECEIVE;
            }
        }
    

    performReceiveLocked:

    //application自己处理广播信息,
     if (app != null) {
        if (app.thread != null) {
    
            app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                    data, extras, ordered, sticky, sendingUser, app.repProcState);
        } else {
            throw new RemoteException("app.thread must not be null");
        }
    } else {
        receiver.performReceive(intent, resultCode, data, extras, ordered,
                sticky, sendingUser);
    }
    
Created with Raphaël 2.1.0BroadcastQueueBroadcastQueueActivityThreadActivityThreadInnerReceiver(LoadedApk)InnerReceiver(LoadedApk)ReceiverDispatcher(LoadedApk)ReceiverDispatcher(LoadedApk)Args(LoadedApk)Args(LoadedApk)BroadcastReceiverBroadcastReceiverPendingResultPendingResultActivityManagerServiceActivityManagerServicescheduleRegisteredReceiverperformReceiveperformReceive如果rd为空,到BroadcastQueue中finishReceiverrun推送至主线程执行onReceive通知BroadcastQueue,该receiver处理完finishsendFinishedfinishReceiverfinishReceiverLocked函数会根据broadcast的state判断是否继续处理广播消息,有序广播的state为CALL_DONE_RECEIVE,返回值为true,执行processNextBroadcastfinishReceiverLockedprocessNextBroadcast
  1. 正常处理静态广播 processCurBroadcastLocked
    该函数与deliverToRegisteredReceiverLocked类似,只是由于是静态广播,app未必已经启动,因此多了 ensure dexopt完成,和 receiver class的load工作。
Created with Raphaël 2.1.0BroadcastQueueBroadcastQueueActivityManagerServiceActivityManagerServiceActivityThreadActivityThreadClassLoadClassLoadBroadcastReceiverBroadcastReceiverReceiverDataReceiverDataPendingResultPendingResult确保做完dexoptensurePackageDexOptscheduleReceiverhandleReceiver加载receiver代码loadClass回调onReceive方法onReceivefinishfinish
  1. 由广播唤醒的app,处理广播信息
    启动app后有一步为,调用ActivityManagerService attachApplicationLocked函数

    // 判断当前启动app是否为pending的broadcast的receiver
    if (!badApp && isPendingBroadcastProcessLocked(pid)) {
        try {
        // 如果是,发送pending的broadcast
            didSomething |= sendPendingBroadcastsLocked(app);
        } catch (Exception e) {
            badApp = true;
        }
    }
    
Created with Raphaël 2.1.0ActivityManagerServiceActivityManagerServiceBroadcastQueueBroadcastQueuesendPendingBroadcastsLockedsendPendingBroadcastsLockedprocessCurBroadcastLocked

执行完广播会调用finish函数,通知AMS广播执行完毕,在AMS的finishReceiverLocked函数中会根据broadcast的state判断是否继续处理广播消息,有序广播的state为CALL_DONE_RECEIVE,返回值为true,执行processNextBroadcast,从而完成一个循环的有序广播处理流程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值