Android Broadcast原理分析之registerReceiver有什么用

这篇文章主要为大家展示了“Android Broadcast原理分析之registerReceiver有什么用”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Android Broadcast原理分析之registerReceiver有什么用”这篇文章吧。

    1. BroadcastReceiver概述

    广播作为四大组件之一,在平时开发过程中会大量使用到,使用方式也是多种多样的,既可以自己在manifest中注册,也可以在java代码中动态注册,既可以接收由系统发出的广播,也可以接受自己定义并发送的广播。广播可以实现进程内以及跨进程之间的通信。从本文开始将分别介绍广播的注册,广播的派发,本地广播(LocalBroadcast)以及Android O上对广播的限制,本文主要介绍广播动态注册。

    2. BroadcastReceiver分类

    从注册方式上区分:动态注册以及静态注册(显示广播和隐式广播)
    从发送方式上区分:无序广播和有序广播
    从处理类型上区分:前台广播和后台广播
    从运行方式上区分:普通广播和Sticky广播(已弃用)
    从发送者区分:系统广播和自定义广播
    此外还有protect broadcast(只允许指定应用可以发送)
    sticky广播:系统保存了一部分广播的状态,当你注册的时候,不需要等到下次这个广播发出来,直接把最近上一次发送的这个广播返回给你

    以上的这些概念在接下来的介绍中都会逐个涉及。

    3. registerReceiver流程图

    Android Broadcast原理分析之registerReceiver有什么用

    其中的APP,ContextImpl,LoadedApk,ActivityManagerProxy都在APP本身的进程中,ActivityManagerService在system_server进程中。

    1. 首先在APP的进程中发起广播的注册,通过registerReceiver接口,这个方法有很多重载方法,但是最终的入口都是在ContextImpl中,后面会详细介绍

    2. 从之前的Context的学习可以知道,registerReceiver最终调用的实现在ContextImpl

    3. 如果没有指定处理广播的handler,则默认使用主线程的handler

    4. 获取要注册的ReceiverDispatcher,在注册的Context相同的情况下,每个Receiver对应一个ReceiverDispatcher

    5. 通过binder call到systemserver进行广播注册

    4. 源码解析

    4.1 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) {
                    if (scheduler == null) {
                        // 注册receiver的时候可以指定接受recover的Handler
                        // 如果没有指定,则默认用主线程的handler处理
                        scheduler = mMainThread.getHandler();
                    }
                    // 获取IIntentReceiver
                    // 这个是一个Binder对象,当广播来临时,用于AMS向客户端发起回调
                    rd = mPackageInfo.getReceiverDispatcher(
                        receiver, context, scheduler,
                        mMainThread.getInstrumentation(), true);
                } else {
                    if (scheduler == null) {
                        scheduler = mMainThread.getHandler();
                    }
                    rd = new LoadedApk.ReceiverDispatcher(
                            receiver, context, scheduler, null, true).getIIntentReceiver();
                }
            }
            try {
                // binder call至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;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

    参数解析:

    receiver:将要注册的receiver
    userId:用户空间标志,默认情况下我们都只有一个user,现在一些手机推出的分身,其实就是用的第二个user,这种情况下userid会变,否则默认主空间的都是0
    IntentFilter:要注册的广播的filter
    broadcastPermission:指定要注册的广播的权限
    scheduler:指定广播接受(也就是onReceive)所在的线程,也就是说注册的时候就可以指定好广播处理放在哪个线程,如果receiver中事情太多,可以放在另外一个线程,这样可以避免主线程被卡住
    context:通过getOuterContext获取到,前面在介绍context的时候有提到,application/service/activity中获取到的是不一样的
    flags:注册广播所携带的flag

    4.2 LoadedApk.getReceiverDispatcher

    public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
                Context context, Handler handler,
                Instrumentation instrumentation, boolean registered) {
            synchronized (mReceivers) {
                // 如果Context相同,每个receiver对应一个ReceiverDispatcher
                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();
            }
        }

    mReceivers是一个二级map,一级key是context,二级key是BroadcastReceiver,value是ReceiverDispatcher。

    这里的ReceiverDispatcher又是什么呢?

    它是LoadedApk中的一个内部类,保存了这个receiver的信息,用于在广播派发到本进程的时候执行,上面这方法最重要的是getIIntentReceiver,这个就非常重要了,它是一个Binder对象,说在广播注册的时候将这个binder对象传递到了AMS,然后当广播派发到本进程的时候,通过这个binder对象再会调回来,它在ReceiverDispatcher创建的时候创建。

    static final class ReceiverDispatcher {
            // 是一个binder对象
            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) {
                        // 这里就是广播真正派发到本进程的时候从systemserver binder call过来执行的
                    ...
            }
    
            final IIntentReceiver.Stub mIIntentReceiver;
            final BroadcastReceiver mReceiver;
            final Context mContext;
            final Handler mActivityThread;
            final Instrumentation mInstrumentation;
            final boolean mRegistered;
            final IntentReceiverLeaked mLocation;
            RuntimeException mUnregisterLocation;
            boolean mForgotten;
            ...
        }

    到这里,广播注册在APP进程的流程就走完了,主要做了几件事:

    1. 获取handler

    2. 获取ReceiverDispatcher

    3. 获取InnerReceiver

    4. 将上面这些连带receiver的相关信息,发起binder call到ActivityManagerService

    4.3 ActivityManagerService.registerReceiver

    public Intent registerReceiver(IApplicationThread caller, String callerPackage,
                IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
                int flags) {
            enforceNotIsolatedCaller("registerReceiver");
            ArrayList<Intent> stickyIntents = null;
            ProcessRecord callerApp = null;
            final boolean visibleToInstantApps
                    = (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
            int callingUid;
            int callingPid;
            boolean instantApp;
            synchronized(this) {
                if (caller != null) {
                    // 正常来讲caller是发起binder call的客户端进程对应的ApplicationThread对象
                    // 如果为null则抛异常
                    callerApp = getRecordForAppLocked(caller);
                    if (callerApp == null) {
                        throw new SecurityException(
                                "Unable to find app for caller " + caller
                                + " (pid=" + Binder.getCallingPid()
                                + ") when registering receiver " + receiver);
                    }
                    if (callerApp.info.uid != SYSTEM_UID &&
                            !callerApp.pkgList.containsKey(callerPackage) &&
                            !"android".equals(callerPackage)) {
                        throw new SecurityException("Given caller package " + callerPackage
                                + " is not running in process " + callerApp);
                    }
                    callingUid = callerApp.info.uid;
                    callingPid = callerApp.pid;
                } else {
                    callerPackage = null;
                    callingUid = Binder.getCallingUid();
                    callingPid = Binder.getCallingPid();
                }
    
                // 判断caller是否为instant app
                instantApp = isInstantApp(callerApp, callerPackage, callingUid);
                userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                        ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
    
                // 获取广播注册的filter中的action封装到list中
                Iterator<String> actions = filter.actionsIterator();
                if (actions == null) {
                    ArrayList<String> noAction = new ArrayList<String>(1);
                    noAction.add(null);
                    actions = noAction.iterator();
                }
    
                // mStickyBroadcasts是一个二级map
                // 一级key是userId,二级key是广播对应的action,value是广播对应intent的list(一般只有一个intent)
                // 这里是为了查询对于当前user,本次注册的所有action对应的sticky广播的intent
                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);
                            }
                        }
                    }
                }
            }
    
            ArrayList<Intent> allSticky = null;
            // 这里不为null表示本次注册的广播中有sticky广播
            if (stickyIntents != null) {
                final ContentResolver resolver = mContext.getContentResolver();
                // 查找匹配的sticky广播
                for (int i = 0, N = stickyIntents.size(); i < N; i++) {
                    Intent intent = stickyIntents.get(i);
                    // 如果caller是instant app,且intent的flag不允许对instant可见,则跳过
                    if (instantApp &&
                            (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                        continue;
                    }
                    // If intent has scheme "content", it will need to acccess
                    // provider that needs to lock mProviderMap in ActivityThread
                    // and also it may need to wait application response, so we
                    // cannot lock ActivityManagerService here.
                    if (filter.match(resolver, intent, true, TAG) >= 0) {
                        if (allSticky == null) {
                            allSticky = new ArrayList<Intent>();
                        }
                        allSticky.add(intent);
                    }
                }
            }
    
            // 直接把最近的一个匹配到的sticky广播返回
            Intent sticky = allSticky != null ? allSticky.get(0) : null;
            // 广播注册的时候receiver是可以为null的,这种情况下这里直接return
            if (receiver == null) {
                return sticky;
            }
    
            synchronized (this) {
                // 校验caller进程是否正常
                if (callerApp != null && (callerApp.thread == null
                        || callerApp.thread.asBinder() != caller.asBinder())) {
                    // Original caller already died
                    return null;
                }
                // mRegisteredReceivers中存放了所有的已注册的receiver
                // 每个BroadcastReceiver对应一个InnerReceiver,即Binder对象
                // binder对象做key,value是ReceiverList
                // ReceiverList是一个ArrayList
                ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
                if (rl == null) {
                    rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                            userId, receiver);
                    if (rl.app != null) {
                        rl.app.receivers.add(rl);
                    } else {
                        try {
                            // 如果是新创建的receiver,还需要linkToDeath
                            receiver.asBinder().linkToDeath(rl, 0);
                        } catch (RemoteException e) {
                            return sticky;
                        }
                        rl.linkedToDeath = true;
                    }
                    // 放入mRegisteredReceivers
                    mRegisteredReceivers.put(receiver.asBinder(), rl);
                } else if (rl.uid != callingUid) {
                    throw new IllegalArgumentException(
                            "Receiver requested to register for uid " + callingUid
                            + " was previously registered for uid " + rl.uid
                            + " callerPackage is " + callerPackage);
                } else if (rl.pid != callingPid) {
                    throw new IllegalArgumentException(
                            "Receiver requested to register for pid " + callingPid
                            + " was previously registered for pid " + rl.pid
                            + " callerPackage is " + callerPackage);
                } else if (rl.userId != userId) {
                    throw new IllegalArgumentException(
                            "Receiver requested to register for user " + userId
                            + " was previously registered for user " + rl.userId
                            + " callerPackage is " + callerPackage);
                }
                // 每一个IntentFilter对应一个BroadcastFilter
                BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                        permission, callingUid, userId, instantApp, visibleToInstantApps);
                // receiverList中存放了通过这个receiver注册的所有的filter
                // 每调用一次register就会add一次
                rl.add(bf);
                // mReceiverResolver中存放所有的BroadcastFilter
                mReceiverResolver.addFilter(bf);
    
                // 有匹配的sticky广播,则直接开始调度派发
                if (allSticky != null) {
                    ArrayList receivers = new ArrayList();
                    receivers.add(bf);
    
                    // 对于每一个sticky广播,创建BroadcastRecord并入队(并行)
                    final int stickyCount = allSticky.size();
                    for (int i = 0; i < stickyCount; i++) {
                        Intent intent = allSticky.get(i);
                        // 根据flag是否有FLAG_RECEIVER_FOREGROUND判断入队是前台还是后台队列
                        BroadcastQueue queue = broadcastQueueForIntent(intent);
                        BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                                null, -1, -1, false, null, null, AppOpsManager.OP_NONE, null, receivers,
                                null, 0, null, null, false, true, true, -1);
                        // 入队,并行队列
                        queue.enqueueParallelBroadcastLocked(r);
                        // 启动广播的调度,也就是开始派发广播
                        queue.scheduleBroadcastsLocked();
                    }
                }
                return sticky;
            }
        }

    上面主要做了几件事情:

    1. 对caller的判断

    2. 遍历action,查询是否有匹配的sticky广播

    3. 将本次注册的广播放到mRegisteredReceivers中记录

    4. 如果是sticky广播,开始派发

    以上是“Android Broadcast原理分析之registerReceiver有什么用”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!