Android 广播的注册流程

引言

广播是一种典型的发布/订阅模式,消息的生产者发布消息,而接收者订阅感兴趣的信息。高内聚低耦合性是判断软件设计好坏的标准,Broadcast把高内聚低耦合做得非常好,当你想发送广播的时候,你根本不用知道接收者的名字,也不用关心谁来接收,你只管发消息即可。



由图可知:广播主要分为三个阶段。第一个阶段:广播接收者APP1、APP2、APP3先往AMS注册感兴趣的广播。第二个阶段:广播发送者APP4发送一个广播。第三个阶段:AMS查找谁对APP4发送的广播感兴趣,找到后就把广播发送给对其感兴趣的广播接收者APP1、APP2、APP3.

应用层如何注册动态广播

    private static final String TAG = "TEST_BROADCAST";
    public static final String ACTION_TEST_BROADCAST = "android.intent.action.TEST_BROADCAST";
    public static final String ACTION_TEST_BROADCAST2 = "android.intent.action.TEST_BROADCAST2";
    private void registerReceiver() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ACTION_TEST_BROADCAST);
        intentFilter.addAction(ACTION_TEST_BROADCAST2);
        registerReceiver(mBroadcastReceiver,intentFilter);
    }
    public static BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(ACTION_TEST_BROADCAST)){
                Log.d(TAG, "mBroadcastReceiver onReceive action = " + ACTION_TEST_BROADCAST);
            } else if (intent.getAction().equals(ACTION_TEST_BROADCAST2)){
                Log.d(TAG, "mBroadcastReceiver onReceive action = " + ACTION_TEST_BROADCAST2);
            }
        }
    };
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mBroadcastReceiver);
    }

通过方法registerReceiver注册一个广播。它需要两个参数,第一个参数类型是BroadcastReceiver,第二个参数类型是IntentFilter。BroadcastReceiver用来接收广播,IntentFilter用来存放广播的Action等信息。目的在将Action与BroadcastReceiver进行绑定,Action与BroadcastReceiver在这里是多对一的关系,在其他场景下可能是多对多的关系。

流程分析

应用进程部分

registerReceiver是广播进行注册的核心方法,我们看看这个方法的调用过程。registerReceiver调用的是定义在ContextWrapper中的方法。

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

ContextWrapper类中的registerReceiver方法又调用了mBase对象的registerReceiver,mBase指的是ContextImpl对象。

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

两个参数的会调用4个参数的。其中broadcastPermission和Handler类型的数据传入null。

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

registerReceiver又会调用registerReceiverInternal。这里增加了三个参数。第一个getUserId()是进程的userid,第二个getOuterContext()是MainActivity对象,第三个flags是一个int类型的值,这里传入的是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) {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                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 {
            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是前面传递过来的BroadcastReceiver类型的对象,它不为空,第一个if条件成立。context是getOuterContext的值,值为MainActivity对象,也不为空。变量mPackageInfo是一个LoadedApk类型的变量,它用来负责处理广播的接收,发送广播之后会经过它分发出去,它也不为空(这个的赋值过程以后再讲,我们着眼于重点部分),所以if (mPackageInfo != null && context != null) {成立。scheduler为空,因为传递的过程中赋值给null,所以这里scheduler会通过mMainThread的getHandler方法获得Handler对象,这个Handler就是ActivityThread中的Handler对象,也就是主线程的Handler对象。接着,会通过mPackageInfo的getReceiverDispatcher获取一个IIntentReceiver类型的对象rd,它是一个binder对象。

我们看下getReceiverDispatcher方法。它一共有5个参数,分别是BroadcastReceiver类型的对象,MainActivity对象,Handler对象,Instrumentation对象,以及一个bool类型的变量。

    public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
            Context context, Handler handler,
            Instrumentation instrumentation, boolean registered) {
        synchronized (mReceivers) {
            LoadedApk.ReceiverDispatcher rd = null;
            ArrayMap 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();
                        mReceivers.put(context, map);
                    }
                    map.put(r, rd);
                }
            } else {
                rd.validate(context, handler);
            }
            rd.mForgotten = false;
            return rd.getIIntentReceiver();
        }
    }
    private final ArrayMap> mReceivers
        = new ArrayMap<>();

这里首先会拿一把锁mReceivers,mReceivers如上,是一个ArrayMap数组,key是Context类型的,value也是一个ArrayMap,k是BroadcastReceiver类型,v是ReceiverDispatcher类型。
接着看第一个if,registered是传递进来的,是true,所以这个条件成立,条件成立就会去mReceivers中查找是否有以传入进来的context对象为key的value,如果有取出这个value,也就是ArrayMap,接着看是否有以当前传入进来的BroadcastReceiver对象为key的value,也就是LoadedApk.ReceiverDispatcher。然后进入第二个判断条件,如果LoadedApk.ReceiverDispatcher对象为null,也就是ArrayMap不存在以BroadcastReceiver对象为key,LoadedApk.ReceiverDispatcher为value的数据,这个时候就会new一个ReceiverDispatcher对象。因为if (registered) {为true,接下来往mReceivers存入Context、BroadcastReceiver、ReceiverDispatcher,当然这里的Context就是MainActivity对象。说这么多,其实就是将MainActivity对象,BroadcastReceiver对象,ReceiverDispatcher对象存放在类型为ArrayMap的mReceivers数据结构中。

ReceiverDispatcher,顾名思义,是一个广播分发器。从mReceivers数据结构就可以得出,通过MainActivity对象就可以找到ArrayMap,通过BroadcastReceiver对象就可以知道ReceiverDispatcher。

现在看下getReceiverDispatcher的返回值,它的类型是IIntentReceiver,通过ReceiverDispatcher的getIIntentReceiver方法获取。我们看下ReceiverDispatcher和getIIntentReceiver。

    static final class ReceiverDispatcher {

        final static class InnerReceiver extends IIntentReceiver.Stub {
            final WeakReference mDispatcher;
            final LoadedApk.ReceiverDispatcher mStrongRef;

            InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
                mDispatcher = new WeakReference(rd);
                mStrongRef = strong ? rd : null;
            }
        ...
        final IIntentReceiver.Stub mIIntentReceiver;
        ...
        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 getIntentReceiver() {
            return mReceiver;
        }
        IIntentReceiver getIIntentReceiver() {
            return mIIntentReceiver;
        }
    ...
    }

由上可知,getIIntentReceiver返回mIIntentReceiver,它是InnerReceiver类的对象。InnerReceiver是ReceiverDispatcher的内部类,创建是在ReceiverDispatcher构造方法中,InnerReceiver继承自IIntentReceiver.Stub,它是一个Binder对象。InnerReceiver保存了外部类ReceiverDispatcher的对象。所以通过返回的InnerReceiver binder对象,就可以找到ReceiverDispatcher对象。如图所示:


mReceivers.png

现在返回registerReceiverInternal方法中。

        try {
            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();
        }

registerReceiverInternal获取到IIntentReceiver binder对象之后,会通过ActivityManager调用registerReceiver,它是一个binder调用,它一共有7个参数:第一个参数是ApplicationThread binder对象,第二个参数是包名,第三个参数IIntentReceiver binder对象,第四个参数Intentfilter对象,第五个参数是广播权限,第六个参数是进程的userid,第七个参数是一个int类型的flag。

总结:

  1. 一个Context(Activity或者Service)可能会有多个BroadcastReceiver,多个BroadcastReceiver又一一对应多个ReceiverDispatcher,多个ReceiverDispatcher又一一对应多个IIntentReceiver。


    mReceivers.png
  2. 你会发现在应用层并没有处理filter对象,而是当作参数传给了system_server进程。

system_server 部分

ActivityManager.getService().registerReceiver会调用到AMS的registerReceiver方法。

    public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
            int flags) {
        ...
        ProcessRecord callerApp = null;
    ...
        int callingUid;
        int callingPid;
    ...
        synchronized(this) {
            // 1
            if (caller != null) {
                callerApp = getRecordForAppLocked(caller);
         ...
                callingUid = callerApp.info.uid;
                callingPid = callerApp.pid;
            } else {
                callerPackage = null;
                callingUid = Binder.getCallingUid();
                callingPid = Binder.getCallingPid();
            }
        ...

            // Collect stickies of users
        ...
        }

    ...

        // The first sticky in the list is returned directly back to the client.
    ...

        synchronized (this) {
        ...
            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);
                } 
                ...
                // 2
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            } 
            ...
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            if (rl.containsFilter(filter)) {
                Slog.w(TAG, "Receiver with filter " + filter
                        + " already registered for pid " + rl.pid
                        + ", callerPackage is " + callerPackage);
            } else {
                rl.add(bf);
         ...
                // 3
                mReceiverResolver.addFilter(bf);
            }

            // Enqueue broadcasts for all existing stickies that match
            // this filter.
        ...

            return sticky;
        }
    }
    /**
     * Keeps track of all IIntentReceivers that have been registered for broadcasts.
     * Hash keys are the receiver IBinder, hash value is a ReceiverList.
     */
    final HashMap mRegisteredReceivers = new HashMap<>();
 /**
     * Resolver for broadcast intents to registered receivers.
     * Holds BroadcastFilter (subclass of IntentFilter).
     */
    final IntentResolver mReceiverResolver
            = new IntentResolver() {
       ...
    };
    ReceiverList(ActivityManagerService _owner, ProcessRecord _app,
            int _pid, int _uid, int _userId, IIntentReceiver _receiver) {
        owner = _owner;
        receiver = _receiver;
        app = _app;
        pid = _pid;
        uid = _uid;
        userId = _userId;
    }
    BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList,
            String _packageName, String _requiredPermission, int _owningUid, int _userId,
            boolean _instantApp, boolean _visibleToInstantApp) {
        super(_filter);
        receiverList = _receiverList;
        packageName = _packageName;
        requiredPermission = _requiredPermission;
        owningUid = _owningUid;
        owningUserId = _userId;
        instantApp = _instantApp;
        visibleToInstantApp = _visibleToInstantApp;
    }
    /**
     * All filters that have been registered.
     */
    private final ArraySet mFilters = new ArraySet();

AMS的registerReceiver主要分为三个部分,分别是代码1,代码2,代码3.
代码1:利用传递过来的ApplicationThread binder对象获取注册广播的应用的信息的存储变量callerApp,它的类型是ProcessRecord。在这里获取应用的uid和进程的pid。system_server如果注册的广播,会走到else部分,即callerPackage=null。
代码2:mRegisteredReceivers是一个以IIntentReceiver为key,以rl即ReceiverList列表为value的hashmap,IIntentReceiver不再多做解释,ReceiverList用来保存IIntentReceiver。
代码3:BroadcastFilter对象的目的是关联ReceiverList和IntentFilter。mReceiverResolver存储所有的BroadcastFilter到mFilters。


mRegisteredReceivers_mReceiverResolver.png

参考

忘了参考的哪里了,大部分自己看的。继续努力。

你可能感兴趣的:(Android 广播的注册流程)