美文网首页
重温广播注册(详细版)

重温广播注册(详细版)

作者: 我叫王菜鸟 | 来源:发表于2018-01-06 14:59 被阅读0次
    从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) {
        return registerReceiverInternal(receiver, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext());
    }
    

    这里从参数中可以看到两个特殊参数,一个时权限,一个是Handler,于此同时传递进去的还有getOuterContext()

    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context) {
        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 {
            return ActivityManagerNative.getDefault().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName,
                    rd, filter, broadcastPermission, userId);
        } catch (RemoteException e) {
            return null;
        }
    }
    

    有个参数是通过ActivityThread得到的,这个对象是一个监控对象,在ActivityThread创建的时候创建

    public Instrumentation getInstrumentation()
    {
        return mInstrumentation;
    }
    
    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);
                }
            }
            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();
        }
    }
    

    在这里需要注意几个数据结构

    private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
    

    这个方法的逻辑是:

    首先会从这个mReceivers数据结构中根据Context获取

    ArrayMap<BroadcastReceiver, ReceiverDispatcher>
    

    这个数据结构,如果这个广播有ReceiverDispatcher,则调用

    LoadedApk.ReceiverDispatcher.getIIntentReceiver();
    

    将结果返回,如果没有的话将传递进来的

    BroadcastReceiver r
    Context context
    Handler handler
    Instrumentation instrumentation
    

    封装成一个ReceiverDispatcher然后添加到mReceivers.put(context, map);

    总体来说,就是mReceivers这个数据结构是根据Context存储一个ArrayMap<BroadcastReceiver, ReceiverDispatcher> map的数据结构,这也就是一个Context可以存储多个广播,一个广播是以广播注册者为单位,可以对应多个广播派发者。

    ==那我们要知道==

    LoadedApk.ReceiverDispatcher.getIIntentReceiver();
    

    这个到底是什么?

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

    我们通过

    IIntentReceiver getIIntentReceiver() {
        return mIIntentReceiver;
    }
    

    得到的就是ReceiverDispatcher构造中创建的这个:

     mIIntentReceiver = new InnerReceiver(this, !registered);
    

    我们好奇这个对象干啥

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

    通过构造和类的声明我们知道目的是包装了LoadedApk.ReceiverDispatcher,我们记得之前传递的时false,现在这里就是true,所以保存的强弱引用都有。并且这个时Binder对象。

    也就是说getReceiverDispatcher将这个对象返回出去。传递到了AMS中。

    return ActivityManagerNative.getDefault().registerReceiver(
            mMainThread.getApplicationThread(), mBasePackageName,
            rd, filter, broadcastPermission, userId);
    

    所以传递进去的参数有:

    • ActivityThread
    • 包名
    • Dispatcher
    • IntentFilter
    • broadcastPermission
    • userId

    AMS中的registerReceiver

    
        public Intent registerReceiver(IApplicationThread caller, String callerPackage,
                IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
            enforceNotIsolatedCaller("registerReceiver");
            ArrayList<Intent> stickyIntents = null;
            ProcessRecord callerApp = null;
            int callingUid;
            int callingPid;
            synchronized(this) {
                //得到调用者进程的信息
                if (caller != null) {
                    callerApp = getRecordForAppLocked(caller);
                    callingUid = callerApp.info.uid;
                    callingPid = callerApp.pid;
                } else {
                    callerPackage = null;
                    callingUid = Binder.getCallingUid();
                    callingPid = Binder.getCallingPid();
                }
                //得到userid
                userId = handleIncomingUser(callingPid, callingUid, userId,
                        true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
                //遍历filter的action
                Iterator<String> actions = filter.actionsIterator();
                if (actions == null) {
                    ArrayList<String> noAction = new ArrayList<String>(1);
                    noAction.add(null);
                    actions = noAction.iterator();
                }
                //所有都会有一个actions列表
                
                //得到userId列表
                int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
                //遍历所有的actions,对于每一个action遍历所有的id
                //并且从粘连广播集合中根据id获取一个以Activity对应多个Intent的列表
                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);
                            }
                        }
                    }
                }            
                //这块也就是说,如果有粘连广播,并且粘连广播有intent则将这些intents添加到粘连广播列表集合中。
                
                
                //小结就是:
                //根据filter得到这条广播所有的actions
                //根据actions得到每一条action
                //然后看看总体的粘连广播列表中有没有对应的action如果有,则将所有的intent遍历出来,添加到一个缓存集合中。
                
                
                //也就是说如果mStickyBroadcasts有当前记录的action则将其缓存到stickyIntents的集合中
                
                
                
                
                //这块代码时粘连广播intent将其将其与filter进行匹配将匹配到的intent添加到一个缓存中去(allSticky)
                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);
                        // 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);
                        }
                    }
                }
                //到了这一步allSticky就存储有关当前这个广播对应的所有intent
                Intent sticky = allSticky != null ? allSticky.get(0) : null; 如果intent的话,拿出第一个intent赋给sticky,否则就是null
                
                synchronized (this) {
                    if (callerApp != null && (callerApp.thread == null
                            || callerApp.thread.asBinder() != caller.asBinder())) {
                        return null;
                    }
                    ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());   
                    //从一个HashMap<IBinder, ReceiverList>中看这个receiver有木有ReceiverList
                    //如果木有则进行添加到这个列表中,并且注册死亡回调。
                     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;
                        }
                        mRegisteredReceivers.put(receiver.asBinder(), rl);
                    }
                    
                    //将filter进行封装,并且添加到ReceiverList中
                BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                        permission, callingUid, userId);
                rl.add(bf);
                if (!bf.debugCheck()) {
                    Slog.w(TAG, "==> For Dynamic broadcast");
                }
                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);
                        queue.enqueueParallelBroadcastLocked(r);
                        queue.scheduleBroadcastsLocked();
                    }
                }
                return sticky;
    }
    

    这里需要清楚数据结构的关系

    如果第一次进入则:

    rl = new ReceiverList(this, callerApp, callingPid, callingUid, userId, receiver);
    rl.app.receivers.add(rl);
    

    也就是将生成的rl添加到调用者的ProcessRecord的ArraySet<ReceiverList> receivers

    然后将这个ReceiverList添加到AMS的HashMap<IBinder, ReceiverList> mRegisteredReceivers,也就是ReceiverList,在那个app进程中有记录,在AMS中也有记录.于此同时mReceiverResolver中有对应的BroadcastFilter,这个BroadcastFilter也在那个app进程中也有.

    最后面是将匹配到的粘连广播发送,所以粘连广播时在广播注册的时候发送的.

    也就是说,只要有一个广播注册,就会匹配看是不粘连广播,如果是粘连则将粘连广播发送给这个接收者.

    清楚这些数据结构之间的关系

    final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();
    
    ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
    if (rl == null) {
        ReceiverList  rl = new ReceiverList(this, callerApp, callingPid, callingUid,userId, receiver);
        mRegisteredReceivers.put(receiver.asBinder(), rl);
    }
    BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,permission, callingUid, userId);
    rl.add(bf);
    

    也就是说,mRegisteredReceivers中是根据receiver.asBinder()进行匹配的,然后对应一个集合,这个集合存储的时一个BroadcastFilter列表.说明一个接收者对应多个Filter.

    ==我们在看看ContextImpl中==

    在LoadedApk.getReceiverDispatcher()中

    private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceiversx= new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
    

    这个是以BroadcastReceiver为键ReceiverDispatcher为值

    相关文章

      网友评论

          本文标题:重温广播注册(详细版)

          本文链接:https://www.haomeiwen.com/subject/ptyynxtx.html