Android 广播内部机制详解(一)

前言

相信大家在应用开发中都用过Broadcast,单纯从使用的角度来说,是非常容易的,但对于系统开发工程师来说,需要了解广播运行的机制,那还是有必要去阅读它的源码。
关于Broadcast的代码也是非常非常多的,我这里将分成几个部分来讲,分别是:
广播的类型、广播的注册、广播的发送、广播的处理、广播总结和建议。

传送门:
Android 广播内部机制详解(二)
Android 广播内部机制详解(三)

1. 广播的类型

广播分为:
普通广播:通过Context.sendBroadcast()发送
有序广播:通过Context.sendOrderedBroadcast()发送
粘性广播:通过Context.sendStickyBroadcast()发送

2. 广播的注册

众所周知,注册有两种方法,分别为动态注册和静态注册,这里我们先来说说动态注册。

2.1 动态注册

动态注册调用的是context中的registerReceiver,这个方法在ContextImpl中实现

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

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

    @Override
    public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
            IntentFilter filter, String broadcastPermission, Handler scheduler) {
        return registerReceiverInternal(receiver, user.getIdentifier(),
                filter, broadcastPermission, scheduler, getOuterContext());
    }

大家可以看到这些注册的方法最终都调用了registerReceiverInternal,接下来,我们再来看看registerReceiverInternal

2.1.1 registerReceiverInternal

java文件:ContextImpl.java

    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context) {
        IIntentReceiver rd = null;
        if (receiver != null) {
            //mPackageInfo的类型为Loade
            if (mPackageInfo != null && context != null) {
                //没有设置scheduler的话,就使用主线程的Handler
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                //见2.1.2
                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 {
            //见2.1.4
            final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName,
                    rd, filter, broadcastPermission, userId);
            if (intent != null) {
                intent.setExtrasClassLoader(getClassLoader());
                intent.prepareToEnterProcess();
            }
            return intent;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

一般情况下,mPackageInfo和context不为null,scheduler用的主线程的Handler,接着会调用rd = mPackageInfo.getReceiverDispatcher(receiver, context, scheduler,mMainThread.getInstrumentation(), true);

2.1.2 getReceiverDispatcher

java文件: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);
                }
            }
            //第一次注册肯定会走这里,rd == null
            if (rd == null) {
                //见2.1.3
                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,mReceivers一张存储了所有所有receiver的哈希表,在这里通过context和对应的receiver可以得到对应的ReceiverDispatcher,进而返回IIntentReceiver。
大家都知道,其实广播的发送其实靠AMS来传递的,AMS通过匹配注册的信息然后然后将广播发给对应的进程,对应进程的Receiver再调用它的onReceive(),这利用的是binder机制,上文中的rd对象(IIntentReceiver rd)就是binder实体,并用ReceiveDispatcher这个类来管理它,接下来我们来看看ReceiveDispatcher

2.1.3 ReceiverDispatcher

文件:LoadedApk.java

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 (ActivityThread.DEBUG_BROADCAST) {
                    int seq = intent.getIntExtra("seq", -1);
                    Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction()
                            + " seq=" + seq + " to " + (rd != null ? rd.mReceiver : null));
                }
                if (rd != null) {
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);
                } else {
                    // The activity manager dispatched a broadcast to a registered
                    // receiver in this process, but before it could be delivered the
                    // receiver was unregistered.  Acknowledge the broadcast on its
                    // behalf so that the system's broadcast sequence can continue.
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing broadcast to unregistered receiver");
                    IActivityManager mgr = ActivityManagerNative.getDefault();
                    try {
                        if (extras != null) {
                            extras.setAllowFds(false);
                        }
                        mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                }
            }
        }
        //它就是上面的rd
        final IIntentReceiver.Stub mIIntentReceiver;
        //持有对应的BroacastReceiver,和BroacastReceiver一一对应
        final BroadcastReceiver mReceiver;
        final Context mContext;
        final Handler mActivityThread;
        final Instrumentation mInstrumentation;
        final boolean mRegistered;
        final IntentReceiverLeaked mLocation;
        RuntimeException mUnregisterLocation;
        boolean mForgotten;

        .........

        ReceiverDispatcher(BroadcastReceiver receiver, Context context,
                Handler activityThread, Instrumentation instrumentation,
                boolean registered) {
            if (activityThread == null) {
                throw new NullPointerException("Handler must not be null");
            }

            mIIntentReceiver = new InnerReceiver(this, !registered);
            mReceiver = receiver;
            mContext = context;
            mActivityThread = activityThread;
            mInstrumentation = instrumentation;
            mRegistered = registered;
            mLocation = new IntentReceiverLeaked(null);
            mLocation.fillInStackTrace();
        }

        ..........

    }

BroadcastReceiver和ReceiverDispatcher是一一对应的,AMS通过对应的mIIntentReceiver(ReceiverDispatcher类里)来响应对应广播的onReceiver。

2.1.4 registerReceiver

            final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName,
                    rd, filter, broadcastPermission, userId);

看这代码我们可以知道registerReceiver的实现肯定是在AMS里面,我们在去AMS里面看看:
java文件:ActivityManagerService.java

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

        ......

            userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                    ALLOW_FULL_ONLY, "registerReceiver", callerPackage);

            Iterator<String> actions = filter.actionsIterator();
            if (actions == null) {
                ArrayList<String> noAction = new ArrayList<String>(1);
                noAction.add(null);
                actions = noAction.iterator();
            }

            // 收集所有与注册用户userId相关所有的已经广播过的粘性广播,并将它放到stickyIntents里面
            // 这里仅仅只是先做一层关于action的筛选
            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);
                        }
                    }
                }
            }
        }
        // 通过IntentFilter.match方法对上面筛选出来的stickyIntents进行一次精准的筛选
        ArrayList<Intent> allSticky = null;
        if (stickyIntents != null) {
            final ContentResolver resolver = mContext.getContentResolver();
            // Look for any matching sticky broadcasts...
            for (int i = 0, N = stickyIntents.size(); i < N; i++) {
                Intent intent = stickyIntents.get(i);
                //将匹配成功的粘性广播的intent放入allSticky中
                if (filter.match(resolver, intent, true, TAG) >= 0) {
                    if (allSticky == null) {
                        allSticky = new ArrayList<Intent>();
                    }
                    allSticky.add(intent);
                }
            }
        }

        // The first sticky in the list is returned directly back to the client.
        Intent sticky = allSticky != null ? allSticky.get(0) : null;
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);
        if (receiver == null) {
            return sticky;
        }

        synchronized (this) {
            if (callerApp != null && (callerApp.thread == null
                    || callerApp.thread.asBinder() != caller.asBinder())) {
                // 如果调用进程已经死了,返回null
                return null;
            }
            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.asBinder().linkToDeath(rl, 0);
                    } catch (RemoteException e) {
                        return sticky;
                    }
                    rl.linkedToDeath = true;
                }
                //存储了当前系统中所与receiver注册的所有的filter
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            } 

            ......

            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId);
            rl.add(bf);
            if (!bf.debugCheck()) {
                Slog.w(TAG, "==> For Dynamic broadcast");
            }
            // 存储了当前系统中所有的BraodcastFilter
            mReceiverResolver.addFilter(bf);

            // Enqueue broadcasts for all existing stickies that match
            // this filter.
            if (allSticky != null) {
                ArrayList receivers = new ArrayList();
                receivers.add(bf);

                final int stickyCount = allSticky.size();
                for (int i = 0; i < stickyCount; i++) {
                    Intent intent = allSticky.get(i);
                    BroadcastQueue queue = broadcastQueueForIntent(intent);
                    BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                            null, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers,
                            null, 0, null, null, false, true, true, -1);
                    //将BroadcastRecord加到BroadcastQueue.ParallelBroadcasts中
                    queue.enqueueParallelBroadcastLocked(r);
                    //发送广播,如果当前还有广播正在处理发送,这次推动不会执行
                    queue.scheduleBroadcastsLocked();
                }
            }
            return sticky;
        }
    }

这部分代码比较长,重点的地方我在代码中都有注释,我这里再总结一下:

  • 将发送过的粘性广播和注册的filter的action进行匹配,匹配成功的放到stickyIntents,然后再进行一个精准的筛选,包括type、scheme、data等,匹配成功放到allSticky,接着如果传入的receiver为null,返回sticky(如果allSticky不为null,则返回allSticky的第一个,否则返回)

  • 调用进程如果为已经死了,则返回null;返回对应receiver.asBinder()(也就是ReceiverDispatcher)的ReceiverList

  • 根据当前的IntentFilter创建BroadcastFilter对象,创建完毕之后,将BroadcastFilter对象对象放入mReceiverResolver中

  • 发送筛选出来的sticky广播

2.2 静态注册

广播的静态注册是通过在AdroidManifest.xml中声明receiver来实现的,用法非常简单。这些信息会在系统启动的时候,由PKMS解析并记录下来,并对外提供接口,比如:AMS就可以用过queryIntentReceivers()函数来察看有多少receiver对目标action感兴趣

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值