Broadcast流程1--注册广播

来源:互联网 发布:手机数据连接上不了网 编辑:程序博客网 时间:2024/05/17 03:08

1. 广播类型:

普通广播:通过Context.sendBroadcast()发送,可并行处理
有序广播:通过Context.sendOrderedBroadcast()发送,串行处理
Sticky广播:通过Context.sendStickyBroadcast()发送,黏性广播,本文不分析

2.广播注册方式:

动态注册:在Activity中通过registerReceiver和unRegisterReceiver方法
静态注册:在AndroidManifest.xml文件中配置

3.动态注册广播流程

activity中registerReceiver,其实就是调用ContextImpl.java的registerReceiver方法,如下:

    @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());    }
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();            }            //mPackageInfo是LoadedApk。            //在Android的架构里,应用进程里是用LoadedApk来对应一个apk的。进程里加载了多少个apk,就会有多少LoadedApk。每个LoadedApk里会有一张“关于本apk动态注册的所有receiver”的哈希表(mReceivers)。            //查找和context对应的“子哈希表”里的ReceiverDispatcher,如果找不到,就重新new一个            *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 = 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();    }}

上面最重要的就是获得一个实现IIntentReceiver 接口的对象,最后将这个对象注册到AMS中
如图所示,拥有IIntentReceiver 接口的对象,跟BroadcastReceiver对象一一对应,
其实就相当于BroadcastReceiver对象的中间步骤的映射,但是能够跨进程。

下图是引用品茗论道说广播 悠然红茶的
https://my.oschina.net/youranhongcha/blog/226274的图片,非常经典的图片,显示了动态注册的过程
这里写图片描述

在AMS中的方法:

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) {            //获取注册广播的activity所对应的进程                callerApp = getRecordForAppLocked(caller);                if (callerApp == null) {                    throw new SecurityException(                            "Unable to find app for caller " + caller                            + " (pid=" + Binder.getCallingPid()                            + ") when registering receiver " + receiver);                }                if (callerApp.info.uid != Process.SYSTEM_UID &&                        !callerApp.pkgList.containsKey(callerPackage) &&                        !"android".equals(callerPackage)) {                    throw new SecurityException("Given caller package " + callerPackage                            + " is not running in process " + callerApp);                }                callingUid = callerApp.info.uid;                callingPid = callerApp.pid;            } else {                callerPackage = null;                callingUid = Binder.getCallingUid();                callingPid = Binder.getCallingPid();            }            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();            }           ...        synchronized (this) {            if (callerApp != null && (callerApp.thread == null                    || callerApp.thread.asBinder() != caller.asBinder())) {                // Original caller already died                return null;            }            //这句最重要,就是为了获取IIntentReceiver 接口是否在AMS中存在ReceiverList,也就是在            //寻找,在AMS中是否存在对应的动态注册的广播接受者(如果是之前就动态注册过,应该存在AMS中名单中)            //这个ReceiverList的作用是一个映射,关于BroadcastReceiver和IntentFilter的映射关系            //在一个activity中,一个BroadcastReceiver可以接受几个IntentFilter的过滤条件            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;                }                //新建立的ReceiverList(代表BroadcastReceiver),放入AMS中已经注册的mRegisteredReceivers                //(相当于在AMS中动态注册的所有BroadcastReceiver),这个是注册的角度的变量,用来通过这个寻找广播的接收者。                mRegisteredReceivers.put(receiver.asBinder(), rl);            } else if (rl.uid != callingUid) {                throw new IllegalArgumentException(                        "Receiver requested to register for uid " + callingUid                        + " was previously registered for uid " + rl.uid);            } else if (rl.pid != callingPid) {                throw new IllegalArgumentException(                        "Receiver requested to register for pid " + callingPid                        + " was previously registered for pid " + rl.pid);            } else if (rl.userId != userId) {                throw new IllegalArgumentException(                        "Receiver requested to register for user " + userId                        + " was previously registered for user " + rl.userId);            }            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,                    permission, callingUid, userId);            rl.add(bf);            if (!bf.debugCheck()) {                Slog.w(TAG, "==> For Dynamic broadcast");            }            //mReceiverResolver这个从解析广播的角度考虑的,用来解析BroadcastRecord。            //作用是AMS将广播队列中的广播寻找到对应的BroadcastFilter ,            //通过这个BroadcastFilter 再回朔ReceiverList,然后找到BroadcastReceiver。            mReceiverResolver.addFilter(bf);    }