android framework开发之广播broadcast源码分析2-千里马

Posted Android高级知识分享官

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android framework开发之广播broadcast源码分析2-千里马相关的知识,希望对你有一定的参考价值。

hi,上一节我们主要分析了broadcast的发送部分,本节我们来分析一下接受部分,即一般我们作为一个广播接受者是怎么一步步被AMS发送过来的信息的。
一般我们注册成为一个广播监听接受者都是调用Context.java中的如下方法:

    public abstract Intent registerReceiver(@Nullable BroadcastReceiver receiver,
                                            IntentFilter filter);

这里一样其实最后都会调用到ContextImpl.java中:

   @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) 
        return registerReceiverInternal(receiver, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext(), 0);
    

最后会调用到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) 
            //构造出IIntentReceiver
                rd = mPackageInfo.getReceiverDispatcher(
                    receiver, context, scheduler,
                    mMainThread.getInstrumentation(), true);
             
        
        try 
        //调用 ActivityManager对应的registerReceiver方法来注册到AMS且把rd传递进去
            final Intent intent = ActivityManager.getService().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                    broadcastPermission, userId, flags);
            return intent;
         
    

这里主要其实就分为2部分:
1、构造出一个IIntentReceiver对象

   rd = mPackageInfo.getReceiverDispatcher(
                    receiver, context, scheduler,
                    mMainThread.getInstrumentation(), true);

这里会调用到getReceiverDispatcher方法:

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;
            //判断是否已经缓存了对应的IIntentReceiver对象
            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();
        
    

这里应该比较容易看懂,就是简单的判断是否有缓存,没有就再进行构造,但是这里要注意哦,返回要求是IIntentReceiver类型,而new的是一个ReceiverDispatcher类型,那么这个IIntentReceiver是哪里构造来的呢?这里就要看ReceiverDispatcher构造源码了:

  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);//这个地方new出来了这个InnerReceiver对象
            mReceiver = receiver;
            mContext = context;
            mActivityThread = activityThread;
            mInstrumentation = instrumentation;
            mRegistered = registered;
            mLocation = new IntentReceiverLeaked(null);
            mLocation.fillInStackTrace();
        

这里的

 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) 
                //省略部分
                
            
        

这里最后发现InnerReceiver其实是实现了IIntentReceiver.Stub 这个跨进程对象的一个实体,也就是我们说的Binder的实现端,服务端,因为这里我们注册广播属于接受者,当然是由客户端调用到我们这端,所以当然就是服务端。

2、调用 ActivityManager对应的registerReceiver方法来注册到AMS且把rd传递进去
这里就是调用了:

ActivityManager.getService().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                    broadcastPermission, userId, flags);

这个方法一看大家就应该知道最后会跨进程调用到AMS中:

 public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
            int flags) 
   //省略部分
        synchronized (this) 
           //省略部分
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) 
            //根据receiver创建出一个ReceiverList,为啥是个List?因为很有可能一个Receiver可能接受多个广播
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
               //省略部分
                mRegisteredReceivers.put(receiver.asBinder(), rl);
             
               //省略部分
               //构造出对应的BroadcastFilter,主要为了方便到时候发端方便寻找到这个接受端
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            if (rl.containsFilter(filter)) 
               
             else 
                rl.add(bf);//bf被添加到了对应的rl
                mReceiverResolver.addFilter(bf);
            

           //省略部分
        
    

这里其实就是在AMS中把广播的对应ReceiverList创建出来,而且与Filter进行映射好,这样广播接受者在AMS中的注册就算完成

总结图如下:

最后宣传一下课程:

[入门课,实战课,跨进程专题
ps需要学习深入framework课程和课程优惠
(可以加我qq:2102309716 优惠购买)

以上是关于android framework开发之广播broadcast源码分析2-千里马的主要内容,如果未能解决你的问题,请参考以下文章

android framework开发之广播broadcast源码分析2-千里马

android framework开发之广播broadcast源码分析-千里马

BroadcastReceiver机制-Android12

BroadcastReceiver机制-Android12

Android开发之广播

Android获取当前电量信息(BroadcastReceiver的使用)