美文网首页
BroadcastReceiver广播原理分析

BroadcastReceiver广播原理分析

作者: feifei_fly | 来源:发表于2020-12-16 21:42 被阅读0次

    一、 Boradcast前题概要

    1、广播分为前台广播和后台广播

    发送前台广播(Intent.FLAG_RECEIVER_FOREGROUND标志)

    val intent = Intent(Intent.ACTION_SHUTDOWN)
    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
    sendBroadcast(intent)
    

    默认发送的是后台广播

    val intent = Intent(Intent.ACTION_SHUTDOWN)
    sendBroadcast(intent)
    

    在ActivityManagerService中,前台广播和后台广播各自分别有一个广播队列,互不干扰。

    mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
            "foreground", BROADCAST_FG_TIMEOUT, false);
    mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
            "background", BROADCAST_BG_TIMEOUT, true);
    mBroadcastQueues[0] = mFgBroadcastQueue;
    mBroadcastQueues[1] = mBgBroadcastQueue;
    
    • 前台队列相对比较空闲,处理广播会相对快一些
    • 前台队列的超时时间是10s,而后台是60s.后台广播的设计思想就是当前应用优先,尽可能多让收到广播的应用有充足的时间把事件做完。而前台广播的目的是紧急通知,设计上就倾向于当前应用赶快处理完,尽快传给下一个。
    • 前台队列不等后台服务,而后台队列要多等后台服务一定的时间

    2、有序广播(串行广播)和无序广播(并发广播)

    2.1、发送广播的时候,可以指定发送的广播是并发广播还是串行广播。

    //并发广播
    sendBroadcast(intent)
    //串行广播
    sendOrderedBroadcast(intent)
    

    串行和并发是相对于订阅了广播的多个接收者而言的,比如A、B、C都注册了同一个广播。

    如果发送并发广播,则A、B、C会"并发”地收到消息,A、B、C没有明确的先后顺序。
    如果发送串行广播,则A、B、C三个接收者会按照priority优先级排序,顺序地接收广播消息,假设优先级顺序为A>B>C,则A首先接收到广播,处理完之后,B才接收广播,然后是C接收广播。

    串行广播的特性:

    • 先接收的广播接收者可以对广播进行截断(abortBroadcast()),即后接收的广播接收者不再接收到此广播;
    • 先接收的广播接收者可以对广播进行修改,再使用setResult()函数来结果传给下一个广播接收器接收,那么后接收的广播接收者将通过getResult()函数来取得上个广播接收器接收返回的结果

    2.2、静态注册的广播,无论发送时是否执行串行广播,AMS 处理的时候都会按照串行广播来处理。

    由于静态广播 可以启动新的进程,如果采用串行广播处理,可能会出现统一时间启动大量进程的场景,造成系统资源进程。因此静态注册的广播,统一按串行广播处理。

    2.3、只有串行广播才有有超时时间处理。

    • 串行广播才有超时时间限制:前台广播10s处理时间,后台广播60s处理事件;
    • 并发广播没有处理时间的限制。

    3、应用内广播LocalBroadCastManager

    context发送广播存在两个问题:

    • context发送的广播,都需要ActivityManagerService统一管理,中间需要经过多次IPC的处理,另外ActivityManagerService中分发广播消息时,都统一加了锁,当Android系统中安装了众多App,同时发送广播,有可能会造成AMS处理繁忙,造成发送广播效率低下
    • context发送的广播,可以跨app接收,这就造成了一定的安全隐患。

    针对上面两点问题,对于只需要在app内部发送和接收消息的场景,推荐用LocalBroadCastManager。LocalBroadCastManager 非常简单,采用订阅者模式,利用Handler机制(而非Binder)实现广播消息的分发和处理。

    二、源码解析

    2.1、几个重要的类

    2.2.1、BroadcastRecord

    sendBroadCast发送出的广播,在SystemServer进程会映射成一个BroadCastRecord对象,代表一条广播消息。
    其中重要的属性:

    • ordered 是否是有序广播
    • sticky 是否是粘性广播
    • receivers 改广播的接收者数组
    • callerApp 发送该广播消息的进程
    final class BroadcastRecord extends Binder {
        final Intent intent;    // the original intent that generated us
        final ComponentName targetComp; // original component name set on the intent
        final ProcessRecord callerApp; // process that sent this //代表发送广播的进程
        final String callerPackage; // who sent this //发送广播的包名
        final int callingPid;   // the pid of who sent this //发送者的进程ID
        final int callingUid;   // the uid of who sent this //发送这的userID
        final boolean callerInstantApp; // caller is an Instant App? //发送这是否是即时应用
        final boolean ordered;  // serialize the send to receivers? //是否是优先广播
        final boolean sticky;   // originated from existing sticky data? //是否是粘性广播
    
        final List receivers;   // contains BroadcastFilter and ResolveInfo //该条广播的接收这
    
    
     
        long enqueueClockTime;  // the clock time the broadcast was enqueued //广播的入队列时间
        long dispatchTime;      // when dispatch started on this set of receivers//广播的分发时间
        long dispatchClockTime; // the clock time the dispatch started //广播的分发时间
        long receiverTime;      // when current receiver started for timeouts. //广播分发完成的时间
        long finishTime;        // when we finished the broadcast. //接收者处理完广播的时间
    
    
        int nextReceiver;       // next receiver to be executed. //下一个接收广播消息的接受者
       
        BroadcastQueue queue;   // the outbound queue handling this broadcast //该广播所属的广播队列
    }
    

    2.1.2、BroadcastQueue

    BroadcastQueue: 广播队列:
    在AMS中定义了两个队列mFgBroadcastQueue和mBroadcastQueues,处理广播时根据Intent中的Intent.FLAG_RECEIVER_FOREGROUND 来区分是放在前台广播队列处理,还是后台广播队列处理。

    public class ActivityManagerService extends IActivityManager.Stub{
        BroadcastQueue mFgBroadcastQueue;
        BroadcastQueue mBgBroadcastQueue;
        // Convenient for easy iteration over the queues. Foreground is first
        // so that dispatch of foreground broadcasts gets precedence.
        final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[2];
        
         public ActivityManagerService(Context systemContext) {
                mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
                        "foreground", BROADCAST_FG_TIMEOUT, false);
                mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
                        "background", BROADCAST_BG_TIMEOUT, true);
         }
         
          BroadcastQueue broadcastQueueForIntent(Intent intent) {
            final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
            if (DEBUG_BROADCAST_BACKGROUND) Slog.i(TAG_BROADCAST,
                    "Broadcast intent " + intent + " on "
                    + (isFg ? "foreground" : "background") + " queue");
            return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
        }
     }
    

    广播消息的核心处理操作都由在BroadCastQueue完成的

    • 持有两个BroadCastRecord的数组,mParallelBroadcasts 用于保存待处理的并发广播记录,mOrderedBroadcasts用于保存待处理串行广播记录
    • mBroadcastHistory 用于保存已经处理过的历史消息
    • BroadcastHandler 用处将processNextBroadcast处理广播消息,broadcastTimeoutLocked 广播消息超时终止操作,组织到一个单线程队列中。
    • scheduleBroadcastsLocked()中发送BROADCAST_INTENT_MSG 消息,触发队里中广播的一次分发。
    • processNextBroadcast 处理下一条广播,该方法利用mServices 对广播的分发的整个过程做了线程同步处理。也就是说无论前台广播还是后台广播 消息的处理 受制于同步锁,必须是串行执行的。
    • processNextBroadcastLocked()方法是广播的具体分发操作
    • processCurBroadcastLocked:处理静态注册的BroadCastReceiver 会调用此方法,最终会new 出一个BroadCastReceiver对象,调用其onReceive()
    • deliverToRegisteredReceiverLocked():处理动态注册的BroadCastReceiver,会调用此方法,最终会索引到最初注册的BroadCastReceiver对象实例,调用其onReceive()
    public final class BroadcastQueue {
     
     //并行消息队列
     final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();
     //串行消息队列
     final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();
     //已处理消息历史
     final BroadcastRecord[] mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY];
     // AMS 对象实例
     final ActivityManagerService mService;
    
    
    private final class BroadcastHandler extends Handler {
            public BroadcastHandler(Looper looper) {
                super(looper, null, true);
            }
    
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case BROADCAST_INTENT_MSG: {
                        if (DEBUG_BROADCAST) Slog.v(
                                TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
                        processNextBroadcast(true);
                    } break;
                    case BROADCAST_TIMEOUT_MSG: {
                        synchronized (mService) {
                            broadcastTimeoutLocked(true);
                        }
                    } break;
                }
            }
        }
    
       //触发消息分发
      public void scheduleBroadcastsLocked() {
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                    + mQueueName + "]: current="
                    + mBroadcastsScheduled);
    
            if (mBroadcastsScheduled) {
                return;
            }
            mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
            mBroadcastsScheduled = true;
        }
    
        //处理广播超时
       final void broadcastTimeoutLocked(boolean fromMsg){
    
       }
    
       //消息分发的处理函数,整个处理过程都用mService加了锁。
       final void processNextBroadcast(boolean fromMsg) {
            synchronized (mService) {
                processNextBroadcastLocked(fromMsg, false);
            }
        }
    
        final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
            //1、处理所有的并发队列中广播
            //2、判断有无正在处理的串行消息(等待新启线程),有 则等待新线程启动完成
            //3、串行队列中队首消息的超时处理
            //4、取出串行队列中的第一个BroadCastRecord,分发给下一个Receiver,如果是动态注册的广播,则调用deliverToRegisteredReceiverLocked()
            // 如果是静态注册的广播,则调用processCurBroadcastLocked,若广播的进程未启动,则首先启动新的进程。
    
        }
    
        
    
    
        // 处理静态注册的BroadCastReceiver ->最终会new 出一个BroadCastReceiver对象,调用其onReceive()
        private final void processCurBroadcastLocked(BroadcastRecord r,
                ProcessRecord app, boolean skipOomAdj){
    
                }
    
         //处理动态注册的BroadCastReceiver -> 会取出注册的BroadCastReceiver对象,然后调用其onReceive()
         private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
        BroadcastFilter filter, boolean ordered, int index) {
    
        }
    
    }
    

    2.1.3、ReceiverDispatcher Receiver分发器

    ReceiverDispatcher是LoadedApk的内部类,用于接收AMS的IPC消息,进行BroadCast的分发,适用于动态注册的BroadCastReceiver。

    • ReceiverDispatcher 持有注册BroadcastReceiver实例
    • ReceiverDispatcher 持有一个IIntentReceiver.Stub实例,用于接收AMS的IPC消息,分发广播消息。
    • ReceiverDispatcher.performReceive 用于接收广播后的处理操作。
    tatic final class ReceiverDispatcher {
    
            final IIntentReceiver.Stub mIIntentReceiver; //用于接收AMS IPC 消息的Binder
            final BroadcastReceiver mReceiver; //自定义的广播接收者
            final Context mContext;
            final Handler mActivityThread;
                
            ReceiverDispatcher(BroadcastReceiver receiver, Context context,
                            Handler activityThread, Instrumentation instrumentation,
                            boolean registered) {
    
                        mIIntentReceiver = new InnerReceiver(this, !registered);
                        mReceiver = receiver;
                        mContext = context;
                        mActivityThread = activityThread;
                  
                    }
             public void performReceive(Intent intent, int resultCode, String data,
                            Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                        final Args args = new Args(intent, resultCode, data, extras, ordered,
                                sticky, sendingUser);
                        i
                        if (intent == null || !mActivityThread.post(args.getRunnable())) {
                            if (mRegistered && ordered) {
                                IActivityManager mgr = ActivityManager.getService();
                                args.sendFinished(mgr);
                            }
                        }
                    }
                    
             IIntentReceiver getIIntentReceiver() {
                return mIIntentReceiver;
            }
        
    }
    
    

    创建一个Args实例,在主线程中执行args.getRunnable()

         public void performReceive(Intent intent, int resultCode, String data,
                            Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                        final Args args = new Args(intent, resultCode, data, extras, ordered,
                                sticky, sendingUser);
                        i
                        if (intent == null || !mActivityThread.post(args.getRunnable())) {
                            if (mRegistered && ordered) {
                                IActivityManager mgr = ActivityManager.getService();
                                args.sendFinished(mgr);
                            }
                        }
                    }
    
    • Args.getRunnable()中 完成对Intent和Receiver的一些参数设置,然后调用receiver.onReceive()方法。
    • 最后调用finish():针对串行广播,需要通知AMS 广播处理完成。
     //Args是ReceiverDispatcher的一个内部类,持有可以方便的持有 ReceiverDispatcher中的mReceiver属性
    //代表一个未处理完的结果,getRunnable()返回出现广播的真正的操作,处理完成之后,需要调用finish 通知AMS
    final class Args extends BroadcastReceiver.PendingResult {
            private Intent mCurIntent;
            private final boolean mOrdered;
            private boolean mDispatched;
       
    
            public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
                    boolean ordered, boolean sticky, int sendingUser) {
                super(resultCode, resultData, resultExtras,
                        mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
                        sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
                mCurIntent = intent;
                mOrdered = ordered;
            }
    
            public final Runnable getRunnable() {
                return () -> {
                    final BroadcastReceiver receiver = mReceiver;
                    final boolean ordered = mOrdered;
    
                    final IActivityManager mgr = ActivityManager.getService();
              
                    try {
                        //提取ClassLoader
                        ClassLoader cl = mReceiver.getClass().getClassLoader();
                        intent.setExtrasClassLoader(cl);
                        intent.prepareToEnterProcess();
                        setExtrasClassLoader(cl);
                        //设置receiver的pendingResult() 
                        receiver.setPendingResult(this);
                        //调用onReceive() 
                        receiver.onReceive(mContext, intent);
                    } catch (Exception e) {
                        if (mRegistered && ordered) {
                            sendFinished(mgr);
                        }
                        
                    }
    
                    //对于有序广播,消息接收完毕,需要发送am.finishReceiver()消息,通知AMS 消息处理完毕,可以将分发下一个串行消息了。
                    if (receiver.getPendingResult() != null) {
                        finish();
                    }
             
                };
            }
        }
    

    我们再看一下InnerReceiver类,它继承自IIntentReceiver.Stub,属于Binder的一个服务端类,可以被AMS 调用,通过IPC 进行广播的分发。

    • InnerReceiver 持有ReceiverDispatcher的一个弱引用
    • AMS 分发广播时,会调用InnerReceiver的performReceive。
    • InnerReceiver.performReceive() 直接会调用ReceiverDispatcher的performReceive()方法
     //InnerReceiver 是专门用于接收AMS IPC 消息的Binder,AMS 向动态注册的BroadCastReceiver分发广播消息时,会调用InnerReceiver.performReceive() 
            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 (rd != null) {
                                rd.performReceive(intent, resultCode, data, extras,
                                        ordered, sticky, sendingUser);
                            } else {
                      
                                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();
                                }
                            }
                        }
                    }
    
             }
    

    总结一下 动态注册BroadCastReceiver时的广播分发流程:

    AMS 分发广播->InnerReceiver.performReceive()->BroadcastReceiver.performReceive()->Args().getRunnable()->BroadcastReceiver.onReceive()
    

    2.2、广播的注册

    发送广播是Context的行为能力,具体调用过程如下:

    • Context.registerReceiver()
    • ContextImpl.registerReceiver()
    • ContextImpl.registerReceiverInternal()
    • IActivityManager.registerReceiver()
    • ActivityManagerService.registerReceiver()
    ## ContextImpl.java
    
     private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
                IntentFilter filter, String broadcastPermission,
                Handler scheduler, Context context, int flags) {
            IIntentReceiver rd = null;
        if (receiver != null) {
            
            //(1)LoadedApk.getReceiverDispatcher()创建一个IIntentReceiver对象
            rd = mPackageInfo.getReceiverDispatcher(
                        receiver, context, scheduler,
                        mMainThread.getInstrumentation(), true);
               
           //(2) IActivityManager.registerReceiver(),向AMS发送IPC消息,并将applicationThread和IIntentReceiver传递给AMS
                final Intent intent = ActivityManager.getService().registerReceiver(
                        mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                        broadcastPermission, userId, flags);
                if (intent != null) {
                    intent.setExtrasClassLoader(getClassLoader());
                    intent.prepareToEnterProcess();
                }
                return intent;
          
        }
    

    我们再看一下IIntentReceiver实例是如何创建的:

    • 首先创建了一个ReceiverDispatcher()实例,ReceiverDispatcher内部持有一个IIntentReceiver实例.
    • ReceiverDispatcher.getIIntentReceiver() 将ReceiverDispatcher内部的IIntentReceiver返回。

    调用IActivityManager.registerReceiver()之后,我们梳理一下,对象的持有关系

    • ActivtivityMangerService 通过Binder 持有IIntentReceiver实例
    • IIntentReceiver 持有一个ReceiverDispatcher的WeakReference 弱引用。
    • ReceiverDispatcher 持有注册的BroadCastReceiver实例。
    ## LoadedApk.java
    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();
            }
        }
    

    我们看一下ActivityManagerService.registerReceiver()方法

    ## ActivityManagerService.java
    final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();
        
    public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
            int flags) {
    
    
        // 创建ReceiverList对象,以receiver为key,以eceiverList为value, 保存到mRegisteredReceivers.
        ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
         if (rl == null) {
                    rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                            userId, receiver);
                    mRegisteredReceivers.put(receiver.asBinder(), rl);
                } 
    
        // 创建BroadcastFilter,保存到mReceiverResolver中
         BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                permission, callingUid, userId, instantApp, visibleToInstantApps);
    
    
         rl.add(bf);
         mReceiverResolver.addFilter(bf);
    
    }
    

    mReceiverResolver记录着所有已经注册的广播,是以receiver IBinder为key, ReceiverList为value的ArrayMap。

    2.3、广播的发送

    发送广播是Context的行为,所以调用的起点也是Context

    • Context.sendBroadcast()
    • ContextImpl.sendBroadcast()
    • ActivityManager.getService().broadcastIntent()
    • ActivityManagerService.broadcastIntent()
    • ActivityManagerService.broadcastIntentLocked()

    broadcastIntentLocked 是具体发送广播地方,代码较长,主要做了以下8步操作

     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 = new Intent(intent);
    
            //setp1:设置广播flags
             //setp2:广播权限验证
             //setp3:处理系统相关广播
             //setp4:增加sticky广播
             //setp5:查询receivers和registeredReceivers
             //setp6:处理并行广播
             //setp7:合并registeredReceivers到receivers
             //setp8:处理串行广播
    
    
    }
    

    我们只看重要的操作 step5-step8

    2.3.1、查询有哪些Receiver会接收该广播

    // Figure out who all will receive this broadcast.
            List receivers = null;
            List<BroadcastFilter> registeredReceivers = null;
            // Need to resolve the intent to interested receivers...
             //当允许静态接收者处理广播时,则通过PKMS根据intent查询静态receivers
            if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                     == 0) {
                receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
            }
            if (intent.getComponent() == null) {
                if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
                    // Query one target user at a time, excluding shell-restricted users
                    for (int i = 0; i < users.length; i++) {
                        if (mUserController.hasUserRestriction(
                                UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
                            continue;
                        }
    
                         //查询匹配的动态注册广播Receiver
                        List<BroadcastFilter> registeredReceiversForUser =
                                mReceiverResolver.queryIntent(intent,
                                        resolvedType, false /*defaultOnly*/, users[i]);
                        if (registeredReceivers == null) {
                            registeredReceivers = registeredReceiversForUser;
                        } else if (registeredReceiversForUser != null) {
                            registeredReceivers.addAll(registeredReceiversForUser);
                        }
                    }
                } else {
                    registeredReceivers = mReceiverResolver.queryIntent(intent,
                            resolvedType, false /*defaultOnly*/, userId);
                }
            }
    

    1.根据userId判断发送的是全部的接收者还是指定的userId

    2.查询广播,并将其放入到两个列表:

    registeredReceivers:来匹配当前intent的所有动态注册的广播接收者(mReceiverResolver见2.4节)

    receivers:记录当前intent的所有静态注册的广播接收者

     private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
                int callingUid, int[] users) {
           ...
          //调用PKMS的queryIntentReceivers,可以获取AndroidManifeset中注册的接收信息
           List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
                            .queryIntentReceivers(intent, resolvedType, pmFlags, user).getList();
           ...        
           return receivers;
        }
    

    2.3.2、处理并行广播

    int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
            if (!ordered && NR > 0) {
                // If we are not serializing this broadcast, then send the
                // registered receivers separately so they don't wait for the
                // components to be launched.
             
                //(1)判断是前台广播队列还是后台广播队列
                final BroadcastQueue queue = broadcastQueueForIntent(intent);
                //(2)创建BroadcastRecord实例,指定接收者为registeredReceivers
                BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                        callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                        requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
                        resultCode, resultData, resultExtras, ordered, sticky, false, userId);
               
                final boolean replaced = replacePending
                        && (queue.replaceParallelBroadcastLocked(r) != null);
                // Note: We assume resultTo is null for non-ordered broadcasts.
                if (!replaced) {
                    //(3)将BroadcastRecord加入到并发队列
                    queue.enqueueParallelBroadcastLocked(r);
                    //(4)处理该BroadcastRecord
                    queue.scheduleBroadcastsLocked();
                }
                
                //(5)处理完成后,将registeredReceivers置空
                registeredReceivers = null;
                NR = 0;
            }
    

    广播队列中有一个mParallelBroadcasts变量,类型为ArrayList,记录所有的并行广播

     public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
            mParallelBroadcasts.add(r);
            enqueueBroadcastHelper(r);
      }
    

    2.3.3、合并registeredReceivers到receivers

     // Merge into one list.
            int ir = 0;
            if (receivers != null) {
                // A special case for PACKAGE_ADDED: do not allow the package
                // being added to see this broadcast.  This prevents them from
                // using this as a back door to get run as soon as they are
                // installed.  Maybe in the future we want to have a special install
                // broadcast or such for apps, but we'd like to deliberately make
                // this decision.
                String skipPackages[] = null;
                if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
                        || Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
                        || Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
                    Uri data = intent.getData();
                    if (data != null) {
                        String pkgName = data.getSchemeSpecificPart();
                        if (pkgName != null) {
                            skipPackages = new String[] { pkgName };
                        }
                    }
                } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
                    skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                }
                if (skipPackages != null && (skipPackages.length > 0)) {
                    for (String skipPackage : skipPackages) {
                        if (skipPackage != null) {
                            int NT = receivers.size();
                            for (int it=0; it<NT; it++) {
                                ResolveInfo curt = (ResolveInfo)receivers.get(it);
                                if (curt.activityInfo.packageName.equals(skipPackage)) {
                                    receivers.remove(it);
                                    it--;
                                    NT--;
                                }
                            }
                        }
                    }
                }
    
                int NT = receivers != null ? receivers.size() : 0;
                int it = 0;
                ResolveInfo curt = null;
                BroadcastFilter curr = null;
                while (it < NT && ir < NR) {
                    if (curt == null) {
                        curt = (ResolveInfo)receivers.get(it);
                    }
                    if (curr == null) {
                        curr = registeredReceivers.get(ir);
                    }
                    if (curr.getPriority() >= curt.priority) {
                        // Insert this broadcast record into the final list.
                        receivers.add(it, curr);
                        ir++;
                        curr = null;
                        it++;
                        NT++;
                    } else {
                        // Skip to the next ResolveInfo in the final list.
                        it++;
                        curt = null;
                    }
                }
            }
            while (ir < NR) {
                if (receivers == null) {
                    receivers = new ArrayList();
                }
                receivers.add(registeredReceivers.get(ir));
                ir++;
            }
    

    registeredReceivers 代表动态注册的BroadCastReceiver,它可以接收串行广播,也可以接收并行广播。

    • 如果当前的广播是并发的,则 在 2.3.2节中,registeredReceivers中的receiver就已经被消费,registeredReceivers会置空,registeredReceivers合并到receiver 等于没有合并。
    • 如果当前的广播是串行的,则registeredReceivers会被保留,而receivers保存的是静态注册的BroadReceiver,静态注册的Receiver都会被按照串行来处理
    • 所以registeredReceivers合并到receiver的最终结果,是一个需要被串行处理的recevier的集合。
    • 静态广播保存在receivers中的是ResolveInfo,动态广播保存在receivers中的是BroadcastFilter

    2.3.4、处理串行广播

     if ((receivers != null && receivers.size() > 0)
                    || resultTo != null) {
                
                //(1)选择BroadcastQueue 区分前台广播还是后台广播
                BroadcastQueue queue = broadcastQueueForIntent(intent);
    
                //(2)生成BroadcastRecord对象,指定接收者为receivers
                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.
                    if (oldRecord.resultTo != null) {
                        final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);
                        try {
                            oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
                                    oldRecord.intent,
                                    Activity.RESULT_CANCELED, null, null,
                                    false, false, oldRecord.userId);
                        } catch (RemoteException e) {
                            Slog.w(TAG, "Failure ["
                                    + queue.mQueueName + "] sending broadcast result of "
                                    + intent, e);
    
                        }
                    }
                } else {
                    //(3)将BroadcastRecord 加入到串行队列
                    queue.enqueueOrderedBroadcastLocked(r);
                    //(4)BroadcastQueue处理该广播
                    queue.scheduleBroadcastsLocked();
                }
            } else {
                // There was nobody interested in the broadcast, but we still want to record
                // that it happened.
                if (intent.getComponent() == null && intent.getPackage() == null
                        && (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
                    // This was an implicit broadcast... let's record it for posterity.
                    addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
                }
            }
    

    广播队列中有一个mOrderedBroadcasts变量,类型为ArrayList,记录所有的有序广播

    /串行广播加入到mOrderedBroadcasts队列
    public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
            mOrderedBroadcasts.add(r);
            enqueueBroadcastHelper(r);
      }
    

    2.3.5、小结

    发送广播的过程:

    1. 默认不发送给已停止的(FLAG_EXCLUDE_STOPPED_PACKAGES)应用和即时应用(需要添加该FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS标记才可以)
    2. 对广播进行权限验证,是否是受保护的广播,是否允许后台接收广播,是否允许后台发送广播
    3. 处理系统广播,主要是package、时间、网络相关的广播
    4. 当为粘性广播时,将sticky广播增加到list,并放入mStickyBroadcasts队列
    5. 当广播的intent没有设置FLAG_RECEIVER_REGISTERED_ONLY,则允许静态广播接收者来处理该广播
    6. 创建BroadcastRecord对象,并将该对象加入到相应的广播队列,然后调用BroadcastQueue的scheduleBroadcastsLocked方法来完成不同广播的处理。

    不同广播的处理方式:

    1. sticky广播:广播注册过程中处理AMS.registerReceiver,开始处理粘性广播,
    • 创建BroadcastRecord对象
    • 添加到mParallelBroadcasts队列
    • 然后执行 queue.scheduleBroadcastsLocked()
    1. 并行广播
    • 只有动态注册的registeredReceivers才会进行并行处理
    • 创建BroadcastRecord对象
    • 添加到mParallelBroadcasts队列
    • 然后执行 queue.scheduleBroadcastsLocked()
    1. 串行广播
    • 所有静态注册的receivers以及动态注册的registeredReceivers(当发送的广播是有序广播时)合并到一张表处理
    • 创建BroadcastRecord对象
    • 添加到mOrderedBroadcasts队列
    • 然后执行 queue.scheduleBroadcastsLocked()

    2.4、广播的接收

    上一节讲到创建的BroadcastRecord添加到BroadcastQue中,都会调用queue.scheduleBroadcastsLocked() 来对BroadcastRecord 向BroadcastReceier进行分发。

    scheduleBroadcastsLocked 实际上是发送了一调Handler消息BROADCAST_INTENT_MSG

    BroadcastQueue.java
      public void scheduleBroadcastsLocked() {
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                    + mQueueName + "]: current="
                    + mBroadcastsScheduled);
    
            if (mBroadcastsScheduled) {
                return;
            }
            mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
            mBroadcastsScheduled = true;
        }
    
    

    参照2.1.2节,调用过程如下

    • BroadcastQueue.scheduleBroadcastsLocked
    • 发送BROADCAST_INTENT_MSG
    • BroadcastQueue.processNextBroadcast()
    • BroadcastQueue.processNextBroadcastLocked()
      final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
            BroadcastRecord r;
    
            // First, deliver any non-serialized broadcasts right away.
            // (1) 遍历mParallelBroadcasts中的所有BroadRecord,依次分发给BroadRecord指定的receivers
            while (mParallelBroadcasts.size() > 0) {
                r = mParallelBroadcasts.remove(0);
                r.dispatchTime = SystemClock.uptimeMillis();
                r.dispatchClockTime = System.currentTimeMillis();
    
              System.identityHashCode(r));
                }
    
                final int N = r.receivers.size();
            
                for (int i=0; i<N; i++) {
                    Object target = r.receivers.get(i);
                    //调用deliverToRegisteredReceiverLocked 向BroadcastReceiver进行广播分发
                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
                }
                //将处理过的BroadcastReceiver,保存到mBroadcastHistory当中
                addBroadcastToHistoryLocked(r);
               
            }
    
    
            //(2) mPendingBroadcast != null, 如果当前正在等待新的进程启动,来处理下一个串行广播,则继续等待;如果等待的进程已死,则mPendingBroadcast置空
    
            // If we are waiting for a process to come up to handle the next
            // broadcast, then do nothing at this point.  Just in case, we
            // check that the process we're waiting for still exists.
            if (mPendingBroadcast != null) {
                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                        "processNextBroadcast [" + mQueueName + "]: waiting for "
                        + mPendingBroadcast.curApp);
    
                boolean isDead;
                if (mPendingBroadcast.curApp.pid > 0) {
                    synchronized (mService.mPidsSelfLocked) {
                        ProcessRecord proc = mService.mPidsSelfLocked.get(
                                mPendingBroadcast.curApp.pid);
                        isDead = proc == null || proc.crashing;
                    }
                } else {
                    final ProcessRecord proc = mService.mProcessNames.get(
                            mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid);
                    isDead = proc == null || !proc.pendingStart;
                }
                if (!isDead) {
                    // It's still alive, so keep waiting
                    return;
                } else {
                    Slog.w(TAG, "pending app  ["
                            + mQueueName + "]" + mPendingBroadcast.curApp
                            + " died before responding to broadcast");
                    mPendingBroadcast.state = BroadcastRecord.IDLE;
                    mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
                    mPendingBroadcast = null;
                }
            }
    
    
    
            //(3) 对mOrderedBroadcasts 串行中的BroadcastRecord做 超时判断,若已超时,则broadcastTimeoutLocked()做超时处理,直到mOrderedBroadcasts队首的BroadcastRecord 未超时
            do {
                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;
                    }
                }
    
                if (r.receivers == null || r.nextReceiver >= numReceivers
                        || r.resultAbort || forceReceive) {
                    mOrderedBroadcasts.remove(0);
                    r = null;
                    looped = true;
                    continue;
                }
            } while (r == null);
    
    
            //(4) 取出当前BroadcastRecord的 下一个接收者Receiver, 仅完成对该单个Receiver的广播分发。
            //若接收者的进程已经存在,则直接分发,若接收者的进程不存在,则首先创建接收者进程。
    
          
            int recIdx = r.nextReceiver++;
     
            final Object nextReceiver = r.receivers.get(recIdx);
    
            //如果接收者是动态注册的BroadcastReceiver,直接调用deliverToRegisteredReceiverLocked() 来向receiver分发广播
            if (nextReceiver instanceof BroadcastFilter) {
                // Simple case: this is a registered receiver who gets
                // a direct call.
                BroadcastFilter filter = (BroadcastFilter)nextReceiver;
        
                deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
               
                return;
            }
    
    
            //如果接收者是静态注册广播,
             ResolveInfo info = (ResolveInfo)nextReceiver;
               // 接收者的进程存在,则调用processCurBroadcastLocked,想receiver进行广播分发
            if (app != null && app.thread != null && !app.killed) {
                try {
                    app.addPackage(info.activityInfo.packageName,
                            info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
                    processCurBroadcastLocked(r, app, skipOomAdj);
                    return;
                }
    
                // 接收者的进程不存在,则调用startProcessLocked 创建接收者进程
                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) {
    
                 }
                mPendingBroadcast = r;
    
    }
    
    

    processNextBroadcastLocked 代码很长,大概分为四个主要操作

    • (1)遍历mParallelBroadcasts中的所有BroadcastRecord,针对BroadcastRecord的所有接收者receiver 并发进行分发。所有并发BroadcastRecord的所有接收者Recevier在此 都派发完成。
    • (2) mPendingBroadcast != null, 当前正在等待新的进程启动,来处理下一个串行广播,则继续等待;如果等待的进程已死,则mPendingBroadcast置空。
    • 对mOrderedBroadcasts 串行中的BroadcastRecord做 超时判断,若已超时,则broadcastTimeoutLocked()做超时处理,直到mOrderedBroadcasts队首的BroadcastRecord 未超时
    • (4) 取出队首BroadcastRecord的 下一个接收者Receiver,仅完成对该单个Receiver的广播分发。
    若接收者的进程已经存在,则直接调用deliverToRegisteredReceiverLocked进行分发
    若接收者的进程不存在,则首先创建接收者进程。
    

    备注:
    一次processNextBroadcastLocked调用

    • 所有mParallelBroadcasts中的BroadcasrRecord都会被分发完成。
    • 对于mOrderedBroadcasts,最多会处理队首串行BroadcastRecord 向其中一个receiver的广播分发。比如队首串行BroadcastRecord有10个接收者receiver,那么需要10次processNextBroadcastLocked 才能完成BroadcastRecord的分发。

    2.4.1、deliverToRegisteredReceiverLocked

    deliverToRegisteredReceiverLocked完成动态注册BroadcastReceiver的分发

    • deliverToRegisteredReceiverLocked
    • performReceiveLocked
      void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
                Intent intent, int resultCode, String data, Bundle extras,
                boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
            // Send the intent to the receiver asynchronously using one-way binder calls.
            if (app != null) {
                if (app.thread != null) {
                    // If we have an app thread, do the call through that so it is
                    // correctly ordered with other one-way calls.
                  
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.repProcState);
                
                    
                } else {
                    // Application has died. Receiver doesn't exist.
                    throw new RemoteException("app.thread must not be null");
                }
            } else {
                receiver.performReceive(intent, resultCode, data, extras, ordered,
                        sticky, sendingUser);
            }
        }
    

    ApplicationThread.scheduleRegisteredReceive()方法内部会调用

    IIntentReceiver.performReceive(),参照 2.1.3节,可知最终会调用BroadcastReceiver.onReceive()方法。

     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);
                receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                        sticky, sendingUser);
            }
    

    2.4.2、processCurBroadcastLocked()

    processCurBroadcastLocked 完成静态注册广播的分发

        private final void processCurBroadcastLocked(BroadcastRecord r,
                ProcessRecord app, boolean skipOomAdj) throws RemoteException {
         
            ...
            app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
                    r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
                    app.repProcState);
            ...
           
           
        }
    

    processCurBroadcastLocked 内部会调用ApplicationThread.scheduleReceiver()

    • ApplicationThread.scheduleReceiver()
    • sendMessage(H.RECEIVER, r);
    • ActivityThread.handleReceiver()
    private void handleReceiver(ReceiverData data) {
      
          
            LoadedApk packageInfo = getPackageInfoNoCheck(
                    data.info.applicationInfo, data.compatInfo);
    
            IActivityManager mgr = ActivityManager.getService();
    
             //(1) 调用通过loadedApk 创建一个receiver实例
            app = packageInfo.makeApplication(false, mInstrumentation);
            context = (ContextImpl) app.getBaseContext();
            if (data.info.splitName != null) {
                context = (ContextImpl) context.createContextForSplit(data.info.splitName);
            }
            java.lang.ClassLoader cl = context.getClassLoader();
            data.intent.setExtrasClassLoader(cl);
            data.intent.prepareToEnterProcess();
            data.setExtrasClassLoader(cl);
         
            receiver = packageInfo.getAppFactory()
                    .instantiateReceiver(cl, data.info.name, data.intent);
         
    
          
            //(2)调用receiver.onReceive
            sCurrentBroadcastIntent.set(data.intent);
            receiver.setPendingResult(data);
            receiver.onReceive(context.getReceiverRestrictedContext(),
                    data.intent);
           
           //(3)广播接收完毕,需要调用finish,通知AMS,触发下一次广播分发
            if (receiver.getPendingResult() != null) {
                data.finish();
            }
        }
    

    2.5 总结

    image

    广播机制

    1. 当发送串行广播(order= true)时
    • 静态注册的广播接收者(receivers),采用串行处理
    • 动态注册的广播接收者(registeredReceivers),采用串行处理
    1. 当发送并行广播(order= false)时
    • 静态注册的广播接收者(receivers),采用串行处理
    • 动态注册的广播接收者(registeredReceivers),采用并行处理

    静态注册的receiver都是采用串行处理;动态注册的registeredReceivers处理方式是串行还是并行,取决于广播的发送方式(processNextBroadcast);静态注册的广播由于其所在的进程没有创建,而进程的创建需要耗费系统的资源比较多,所以让静态注册的广播串行化,防止瞬间启动大量的进程。

    广播ANR只有在串行广播时才需要考虑,因为接收者是串行处理的,前一个receiver处理慢,会影响后一个receiver;并行广播通过一个循环一次性将所有的receiver分发完,不存在彼此影响的问题,没有广播超时。

    串行超时情况:某个广播处理时间>2receiver总个数mTimeoutPeriod,其中mTimeoutPeriod,前后队列为10s,后台队列为60s;某个receiver的执行时间超过mTimeoutPeriod。

    三、参考文章

    https://blog.csdn.net/cao861544325/article/details/103846442
    https://www.jianshu.com/p/fecc4023abb8

    相关文章

      网友评论

          本文标题:BroadcastReceiver广播原理分析

          本文链接:https://www.haomeiwen.com/subject/gcgogktx.html