重温广播注册(详细版)

2018-01-06  本文已影响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);

所以传递进去的参数有:

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为值

上一篇下一篇

猜你喜欢

热点阅读