Android 11 广播的注册、发送和接收流程分析

Android 11 广播的注册、发送和接收流程分析

一、广播的注册流程

在这里插入图片描述
BroadcastReceiver的注册有两种,静态注册和动态注册,静态注册是由PackageManagerService来完成的,这里只介绍BroadcastReceiver的动态注册。动态注册的实现其实在ContextImpl中,ContextWraper只是个代理类,没有实现真正的功能。那这里我们直接来看ContextImpl中的registerReceiver方法代码如下:

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

这里最终是调用了ContextImpl的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) {//1
            //在ReceiverDispatcher构造方法中会创建InnerReceiver这个IIntentReceiver binder实现类
                  //2
                rd = mPackageInfo.getReceiverDispatcher(
                    receiver, context, scheduler,
                    mMainThread.getInstrumentation(), true);
            } else {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                //3
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
		//4
            final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
                    mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(), rd,
                    filter, broadcastPermission, userId, flags);
            if (intent != null) {
                intent.setExtrasClassLoader(getClassLoader());
                intent.prepareToEnterProcess();
            }
            return intent;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

在注释1处首先对LoadedApk类型的mPackageInfo和context进行了非空判断,如果不为空就会执行注释2处的代码,从mPackageInfo获取rd对象,如果为null那么就执行注释3的代码创建一个rd对象。
这个rd对象其实是IIntentReceiver类型的Binder接口对象用于进行跨进程通讯的,它的具体实现在LoadedApk.ReceiverDispatcher.InnerReceiver中代码如下:

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;
              }
              ...
        }
        ...
}

这个类暂时还用不到,后面发送和接收的流程会用到。我们回到registerReceiverInternal方法注释4处,这里会调用ActivityManagerService的registerReceiverWithFeature方法并把rd和intentfilter传进去。这里低版本的源码在这调用有点区别,大家可以自行了解,接下来我们看一下ActivityManagerService的registerReceiverWithFeature代码,这里我们先看粘性广播处理部分,代码如下:

   public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
            String callerFeatureId, IIntentReceiver receiver, IntentFilter filter,
            String permission, int userId, int flags) {
       ...
        synchronized(this) {
        ...
            //1
            Iterator<String> actions = filter.actionsIterator();
            if (actions == null) {
                ArrayList<String> noAction = new ArrayList<String>(1);
                noAction.add(null);
                actions = noAction.iterator();
            }

            // Collect stickies of users
            int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
            while (actions.hasNext()) {
                String action = actions.next();
                for (int id : userIds) {
                    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                    if (stickies != null) {
                        ArrayList<Intent> intents = stickies.get(action);
                        if (intents != null) {
                            if (stickyIntents == null) {
                                stickyIntents = new ArrayList<Intent>();
                            }
                            stickyIntents.addAll(intents);//2
                        }
                    }
                }
            }
        }
        ArrayList<Intent> allSticky = null;
        if (stickyIntents != null) {
            final ContentResolver resolver = mContext.getContentResolver();
            for (int i = 0, N = stickyIntents.size(); i < N; i++) {
                Intent intent = stickyIntents.get(i);
                if (instantApp &&
                        (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                    continue;
                }
                if (filter.match(resolver, intent, true, TAG) >= 0) {
                    if (allSticky == null) {
                        allSticky = new ArrayList<Intent>();
                    }
                    allSticky.add(intent);//3
                }
            }
        }
        ...
}

注释1处通过filter获取对应的所有action的描述信息,然后根据action和userid获取所有粘性广播的intent并在注释2处添加到stickyIntents这个临时list集合中,然后遍历stickyIntents集合把匹配的intent添加到注释3处的allSticky中。
接着查看ActivityManagerService的registerReceiverWithFeature方法的剩余内容:

  public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
            String callerFeatureId, IIntentReceiver receiver, IntentFilter filter,
            String permission, int userId, int flags) {
        ...
        synchronized (this) {
            ...
          ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());//1
            if (rl == null) {
            	rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                    userId, receiver);//2
            if (rl.app != null) {
                final int totalReceiversForApp = rl.app.receivers.size();
                if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {//3
                    throw new IllegalStateException("Too many receivers, total of "
                            + totalReceiversForApp + ", registered for pid: "
                            + rl.pid + ", callerPackage: " + callerPackage);
                }
                rl.app.receivers.add(rl);
            } else {
               ...
            }
            mRegisteredReceivers.put(receiver.asBinder(), rl);
        }
            ...
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);//4
            if (rl.containsFilter(filter)) {
                Slog.w(TAG, "Receiver with filter " + filter
                        + " already registered for pid " + rl.pid
                        + ", callerPackage is " + callerPackage);
            } else {
                rl.add(bf);//5
                if (!bf.debugCheck()) {
                    Slog.w(TAG, "==> For Dynamic broadcast");
                }
                mReceiverResolver.addFilter(bf);//6
            }

            ...
            return sticky;
        }
    }

注释1处获取ReceiverList列表,如果为空则在注释2处创建一个ReceiverList,ReceiverList继承自ArrayList,用来存储广播接收者。在注释4处创建BroadcastFilter并传入此前创建的ReceiverList,BroadcastFilter用来描述注册的广播接收者,并在注释5通过add方法将自身添加到ReceiverList中。注释6处将BroadcastFilter添加到mReceiverResolver中,这样当AMS接收到广播时就可以从mReceiverResolver中找到对应的广播接收者了。注意:从注释3处可以看出一个进程注册广播的个数是有限制的,这里最多可以注册1000个。

二、广播的发送与接收流程

在这里插入图片描述
上面的这张图主要展示了,广播的发送与接收流程,整个流程止于BroadcastReceiver的onReceive方法。接下来我们就来分析具体的代码流程,我们在使用发送广播的时候一般是调用sendBroadcast方法,这里我们就从sendBroadcast开始。其实sendBroadcast是Context的抽象方法,具体的实现类是ContextImpl,具体为什么是ContextImpl前面的文章已经讲过了,这里就不在赘述了。我们就直接看一下ContextImpl中的 sendBroadcast的代码:

@Override
    public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
        warnIfCallingFromSystemProcess();
       ...
        try {
            intent.prepareToLeaveProcess(this);
            //1
            ActivityManager.getService().broadcastIntentWithFeature(
                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                    null, Activity.RESULT_OK, null, null, receiverPermissions,
                    AppOpsManager.OP_NONE, options, false, false, getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

注释1处直接调用了ActivityManagerService的broadcastIntentWithFeature()方法:

  public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
            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) {
            intent = verifyBroadcastLocked(intent);//1
            ...
            try {
                return broadcastIntentLocked(callerApp,
                        callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
                        intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                        requiredPermissions, appOp, bOptions, serialized, sticky,
                        callingPid, callingUid, callingUid, callingPid, userId);//2
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
        }
    }

我们先看一下注释1处的verifyBroadcastLocked方法:

    final Intent verifyBroadcastLocked(Intent intent) {
        // Refuse possible leaked file descriptors
        if (intent != null && intent.hasFileDescriptors() == true) {//1
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        int flags = intent.getFlags();//2

        if (!mProcessesReady) {
         
            if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {//3
                // This will be turned into a FLAG_RECEIVER_REGISTERED_ONLY later on if needed.
            } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {//4
                Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
                        + " before boot completion");
                throw new IllegalStateException("Cannot broadcast before boot completed");
            }
        }
    ...

        return intent;
    }

这个方法其实就是对Broadcast的验证是否合法,注释1处判断Intent不为null 并且intent包含文件描述符就会抛出参数不合法异常。注释2处获取flag,注释3处判断如果系统正在启动过程中,判断如果flag设置为FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT(启动检查时只接受动态注册的广播)则不做处理,如果不是则在注释4处判断如果flag没有设置为FLAG_RECEIVER_REGISTERED_ONLY(只接受动态注册的广播接收者)则会抛出异常。
接下来我们在回到broadcastIntentWithFeature的注释2处调用了broadcastIntentLocked方法代码如下:

@GuardedBy("this")
    final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,
            @Nullable String callerFeatureId, 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 realCallingUid,
            int realCallingPid, int userId, boolean allowBackgroundActivityStarts,
            @Nullable int[] broadcastWhitelist) {
           ...
        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.
            if (isCallerSystem) {
                checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                        isProtectedBroadcast, registeredReceivers);
            }
            final BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
                    callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
                    resultCode, resultData, resultExtras, ordered, sticky, false, userId,
                    allowBackgroundActivityStarts, timeoutExempt);//1
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
            final boolean replaced = replacePending
                    && (queue.replaceParallelBroadcastLocked(r) != null);
            // Note: We assume resultTo is null for non-ordered broadcasts.
            if (!replaced) {
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();   //2
            }
            registeredReceivers = null;
            NR = 0;
        }
        ...

        return ActivityManager.BROADCAST_SUCCESS;
    }

这个方法的代码非常长大概有600多行,这里我们只看关键部分。前面的工作主要做了一下几件事:
(1)、对一些特殊的action做权限的检查。
(2)、对一些系统广播做非系统应用的使用限制
(3)、对所有的静态和动态注册的广播进行收集
(4)、把有的广播接收者按照不同优先级合并到receivers这个集合中
这里我们只关心无序广播的调用流程,因为我们主要搞清楚广播是怎么送达的。接下来就是在注释1处创建BroadcastRecord对象并将registeredReceivers传进去,在注释2处调用BroadcastQueue的scheduleBroadcastsLocked方法。代码如下

public void scheduleBroadcastsLocked() {
    ...
        if (mBroadcastsScheduled) {
            return;
        }
        //1
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }

在注释1处通过BroadcastHandler类型的mHandler发送了一个BROADCAST_INTENT_MSG消息,然后在handleMessage中进行了处理。代码如下:

  @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BROADCAST_INTENT_MSG: {
                    if (DEBUG_BROADCAST) Slog.v(
                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG ["
                            + mQueueName + "]");
                    processNextBroadcast(true);
                } break;
             ...
            }
        }
    }

这里直接调用了BroadcastQueue的processNextBroadcast方法,但是这个方法里面什么也没处理直接调用了BroadcastQueue的processNextBroadcastLocked方法。代码如下:

  final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
        BroadcastRecord r;
        ...
        if (fromMsg) {
            mBroadcastsScheduled = false;//1
        }

        // First, deliver any non-serialized broadcasts right away.
         while (mParallelBroadcasts.size() > 0) {//2
            r = mParallelBroadcasts.remove(0);
            ...

            final int N = r.receivers.size();
            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
                    + mQueueName + "] " + r);
            for (int i=0; i<N; i++) {
                Object target = r.receivers.get(i);
                if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                        "Delivering non-ordered on [" + mQueueName + "] to registered "
                        + target + ": " + r);
                 //3       
                deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
            }
            addBroadcastToHistoryLocked(r);
            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
                    + mQueueName + "] " + r);
            }

           ...
    }

这个方法也是很长的大概700行左右,这里我们只看无序广播的逻辑。从上面我们知道fromMsg是true,所以就会在注释1处把mBroadcastsScheduled置为false,表示对于此前发来的BROADCAST_INTENT_MSG类型的消息已经处理了。注释2处的mParallelBroadcasts这个集合就是存储无序广播的集合,然后通过while循环将mParallelBroadcasts列表中一个一个取出并移除然后通过注释3处发给对应的广播接收者。deliverToRegisteredReceiverLocked方法的代码如下:

private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
        BroadcastFilter filter, boolean ordered, int index) {
   	...
    try {
        if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
                "Delivering to " + filter + " : " + r);
        if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
         ...
        } else {
            r.receiverTime = SystemClock.uptimeMillis();
            maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
            //1
            performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                    new Intent(r.intent), r.resultCode, r.resultData,
                    r.resultExtras, r.ordered, r.initialSticky, r.userId);
            // parallel broadcasts are fire-and-forget, not bookended by a call to
            // finishReceiverLocked(), so we manage their activity-start token here
            if (r.allowBackgroundActivityStarts && !r.ordered) {
                postActivityStartTokenRemoval(filter.receiverList.app, r);
            }
        }
       ...
    } catch (RemoteException e) {
     ...
}

这里省去了一部分权限检查的逻辑,和关于有序广播的处理逻辑。这里我们只关心注释1处的方法performReceiveLocked 代码如下:

void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
        Intent intent, int resultCode, String data, Bundle extras,
        boolean ordered, boolean sticky, int sendingUser)
        throws RemoteException {
     //1       
    if (app != null) {
        if (app.thread != null) {
            try {
                //2
                app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                        data, extras, ordered, sticky, sendingUser, app.getReportedProcState());

            } catch (RemoteException ex) {
             ...
            }
        } else {
           ...
        }
    } else {
        receiver.performReceive(intent, resultCode, data, extras, ordered,
                sticky, sendingUser);
    }
}

这里注释1处判断广播接收者所在的进程是否正在运行,如果正在运行然后就会调用注释2处的代码。这里的app.thread指的是ApplicationThread,接下来我们就来看一下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);
    //1
    receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
            sticky, sendingUser);
}

这里注释1处调用了IIntentReceiver的performReceive,这里的IIntentReceiver是一个binder的接口,具体的实现类是LoadedApk.ReceiverDispatcher.InnerReceiver,代码如下所示:

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

        @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);//1
            } else {
               ...
            }
        }
    }
}

这里在注释1处调用了ReceiverDispatcher的performReceive方法,代码如下:

   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);//1
    	...
        if (intent == null || !mActivityThread.post(args.getRunnable())) {//2
            if (mRegistered && ordered) {
                IActivityManager mgr = ActivityManager.getService();
                if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                        "Finishing sync broadcast to " + mReceiver);
                args.sendFinished(mgr);
            }
        }
    }

}

这里在注释1处将intent等广播信息封装到Args对象中,然后再注释2处调用mActivityThread的post方法并传入args的内部的Runnable对象。这里的mActivityThread其实指的就是ActivityThread的内部的Handler对象H。这个消息最终会在Args的run方法中执行。

    public final Runnable getRunnable() {
        return () -> {
            final BroadcastReceiver receiver = mReceiver;
        	...
            try {
                ClassLoader cl = mReceiver.getClass().getClassLoader();
                intent.setExtrasClassLoader(cl);
                intent.prepareToEnterProcess();
                setExtrasClassLoader(cl);
                receiver.setPendingResult(this);
                receiver.onReceive(mContext, intent);//1
            } catch (Exception e) {
              ...
            }

           ...
        };
    }
}

在注释1处调用了广播接收者的onReceive方法,到这里广播的注册、发送和接收过程到这里就分析完了。具体细节大家可以自行了解。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值