来源:

https://blog.csdn.net/shift_wwx/article/details/81223021

 

前言:

本文主要解析Android 中广播的注册过程,其中包括动态广播的注册和静态广播的注册。

静态广播:一般是在AndroidManifest.xml 中注册,在PMS 会进行解析(详见 android PMS 如何解析 APK)。

动态广播:一般通过AMS 中registerReceiver(),动态存在灵活性,注意在最后unRegisterReceiver()。

 

基于版本:Android O

 

动态广播注册过程:

1、context.registerReceiver()

    @Override    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {        return registerReceiver(receiver, filter, null, null);    }    @Override    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,            int flags) {        return registerReceiver(receiver, filter, null, null, flags);    }    @Override    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,            String broadcastPermission, Handler scheduler) {        return registerReceiverInternal(receiver, getUserId(),                filter, broadcastPermission, scheduler, getOuterContext(), 0);    }    @Override    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,            String broadcastPermission, Handler scheduler, int flags) {        return registerReceiverInternal(receiver, getUserId(),                filter, broadcastPermission, scheduler, getOuterContext(), flags);    }    @Override    public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,            IntentFilter filter, String broadcastPermission, Handler scheduler) {        return registerReceiverInternal(receiver, user.getIdentifier(),                filter, broadcastPermission, scheduler, getOuterContext(), 0);    }

注册的接口比较多,存在异议是在传入的参数。

 

1.1 参数

receiver:这个是broadcast 中的接受者,本文的关键,注意其中的成员函数onReceive和成员变量mPendingResult。

filter:广播中的过滤器。

broadcatPermission:广播所需要的permission,后面会进行check

scheduler:线程Handler 对象,默认是主线程的handler

context:通过getOuterContext()传入。

 

1.2 registerReceiverInternal

    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,            IntentFilter filter, String broadcastPermission,            Handler scheduler, Context context, int flags) {        IIntentReceiver rd = null;        if (receiver != null) {            //mPackageInfo 为LoadedApk            if (mPackageInfo != null && context != null) {                // Handler 如果没有定义,将主线程的Handler传入                if (scheduler == null) {                    scheduler = mMainThread.getHandler();                }                //rd 为LoadedApk 中的ReceiverDispatcher,详见【1.3】                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 {            //最终将receiver 注册到AMS 中,因为分发也是从AMS 中开始            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();        }    }

见上面代码中的注释,在activity/service 中注册广播,此时的LoadApk 是已经创建的,广播最终会注册到AMS,如果进行进程间调用,主要是通过这里的IIntentReceiver 进行binder 通信。LoadApk 中的ReceiverDispatcher 相当于server 端,即当时注册广播的activity/service 为server。最终会将binder 的server 端传入AMS 中方便后面AMS 的分发调用。后面继续解读IIntentReceiver。

 

1.3 getReceiverDispatcher()

    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);                }            }            //首次注册的时候rd 为null            if (rd == null) {                //将之前BroadcastReceiver、handler、context 都传入                rd = new ReceiverDispatcher(r, context, handler,                        instrumentation, registered);                if (registered) {                    if (map == null) {                        map = new ArrayMap();                        mReceivers.put(context, map);                    }                    //map 将receiver和dispatcher对应                    map.put(r, rd);                }            } else {                rd.validate(context, handler);            }            rd.mForgotten = false;            return rd.getIIntentReceiver();        }    }

见上面代码中的注释,函数最后返回的是IIntentReceiver的Binder 的server 对象。来看下ReceiverDispatcher 构造:

        ReceiverDispatcher(BroadcastReceiver receiver, Context context,                Handler activityThread, Instrumentation instrumentation,                boolean registered) {            if (activityThread == null) {                throw new NullPointerException("Handler must not be null");            }            //IIntentReceiver 的server 端            mIIntentReceiver = new InnerReceiver(this, !registered);            mReceiver = receiver;            mContext = context;            mActivityThread = activityThread;            mInstrumentation = instrumentation;            mRegistered = registered;            mLocation = new IntentReceiverLeaked(null);            mLocation.fillInStackTrace();        }

 

1.4 AMS.registerReceiver()

    public Intent registerReceiver(IApplicationThread caller, String callerPackage,            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,            int flags) {        ...ProcessRecord callerApp = null;        ...        synchronized(this) {            if (caller != null) {                //获取ProcessRecord 对象,这个是注册端的所有信息所在                callerApp = getRecordForAppLocked(caller);                if (callerApp == null) {                    throw new SecurityException(                            "Unable to find app for caller " + caller                            + " (pid=" + Binder.getCallingPid()                            + ") when registering receiver " + receiver);                }                ...                callingUid = callerApp.info.uid;                callingPid = callerApp.pid;            } else {                callerPackage = null;                callingUid = Binder.getCallingUid();                callingPid = Binder.getCallingPid();            }            instantApp = isInstantApp(callerApp, callerPackage, callingUid);            userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,                    ALLOW_FULL_ONLY, "registerReceiver", callerPackage);            //获取filter 中的actions            Iterator actions = filter.actionsIterator();            if (actions == null) {                ArrayList noAction = new ArrayList(1);                noAction.add(null);                actions = noAction.iterator();            }            // Collect stickies of users            int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };            //while 循环查找sticky intent            while (actions.hasNext()) {                String action = actions.next();                for (int id : userIds) {                    ArrayMap> stickies = mStickyBroadcasts.get(id);                    if (stickies != null) {                        ArrayList intents = stickies.get(action);                        if (intents != null) {                            if (stickyIntents == null) {                                stickyIntents = new ArrayList();                            }                            stickyIntents.addAll(intents);                        }                    }                }            }        }        //处理sticky 广播        ...        // The first sticky in the list is returned directly back to the client.        Intent sticky = allSticky != null ? allSticky.get(0) : null;        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);        if (receiver == null) {            return sticky;        }        synchronized (this) {            //确定之前注册广播的进程是否已经died            if (callerApp != null && (callerApp.thread == null                    || callerApp.thread.asBinder() != caller.asBinder())) {                // Original caller already died                return null;            }            //广播都会在mRegisteredReceivers 的map 中            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;                }                //新注册的receiver 会添加到mRegisteredReceivers 中                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                        + " callerPackage is " + callerPackage);            } else if (rl.pid != callingPid) {                throw new IllegalArgumentException(                        "Receiver requested to register for pid " + callingPid                        + " was previously registered for pid " + rl.pid                        + " callerPackage is " + callerPackage);            } else if (rl.userId != userId) {                throw new IllegalArgumentException(                        "Receiver requested to register for user " + userId                        + " was previously registered for user " + rl.userId                        + " callerPackage is " + callerPackage);            }            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,                    permission, callingUid, userId, instantApp, visibleToInstantApps);            rl.add(bf);            if (!bf.debugCheck()) {                Slog.w(TAG, "==> For Dynamic broadcast");            }            //根据filter,创建新的广播接收过滤器            mReceiverResolver.addFilter(bf);            // 如果注册的广播为sticky,那么就会直接加入广播发送队列            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, false, null, null, AppOpsManager.OP_NONE, null, receivers,                            null, 0, null, null, false, true, true, -1);                    // 作为并行广播进行处理                    queue.enqueueParallelBroadcastLocked(r);                    queue.scheduleBroadcastsLocked();                }            }            return sticky;        }    }

如上面code 中的注释,其中mRegisteredReceivers记录着所有已注册的广播,以receiver IBinder为key, ReceiverList为value为HashMap。

在BroadcastQueue中有两个广播队列mParallelBroadcasts,mOrderedBroadcasts,数据类型都为ArrayList:

  • mParallelBroadcasts:并行广播队列,可以立刻执行,而无需等待另一个广播运行完成,该队列只允许动态已注册的广播,从而避免发生同时拉起大量进程来执行广播,前台的和后台的广播分别位于独立的队列。
  • mOrderedBroadcasts:有序广播队列,同一时间只允许执行一个广播,该队列顶部的广播便是活动广播,其他广播必须等待该广播结束才能运行,也是独立区别前台的和后台的广播。

其中有几个地方需要注意:

1、getRecordForAppLocked()

    final ProcessRecord getRecordForAppLocked(            IApplicationThread thread) {        if (thread == null) {            return null;        }        int appIndex = getLRURecordIndexForAppLocked(thread);        if (appIndex >= 0) {            return mLruProcesses.get(appIndex);        }

ProcessRecord 是从mLruProcesses 中获取

2、ReceiverList

final class ReceiverList extends ArrayList        implements IBinder.DeathRecipient {    final ActivityManagerService owner;    public final IIntentReceiver receiver;    public final ProcessRecord app;    public final int pid;    public final int uid;    public final int userId;    BroadcastRecord curBroadcast = null;    boolean linkedToDeath = false;

我们看到最后我们会将receiver 保存到mRegisteredReceivers,也可以说以后AMS 中每一个ReceiverList 就会对应一个LoadedApk 中的ReceiverDispatcher。

另外,ReceiverList 是继承ArrayList,其中最后会根据传入的filter 新建BroadcastFilter 的对象,并且最终添加到ReceiverList 中,这样就形成了一幅图。

3、sticky intent

从code 中可以看到,注册广播首先会确认是否是sticky 广播,如果是的话,最终会作为并行广播scheduleBroadcastsLocked()。

这也是sticky 广播跟普通广播的区别,粘性消息在发送后就一直存在于系统的消息容器里面,等待对应的处理器去处理,如果暂时没有处理器处理这个消息则一直在消息容器里面处于等待状态,粘性广播的Receiver如果被销毁,那么下次重建时会自动接收到消息数据。

 

至此,广播的动态注册过程就基本解读完,下面来看下静态注册的广播。

 

静态广播的注册过程:

android PMS 如何解析 APK 详细的说明了receiver 的解析过程。当AMS调用PKMS的接口来查询“和intent匹配的组件”时,PKMS内部就会去查询当初记录下来的数据,并把结果返回AMS。有人认为静态receiver是常驻内存的,这种说法并不准确。因为常驻内存的只是静态receiver的描述性信息,并不是receiver实体本身。

这里以BOOT_COMPLETED 广播为例,在AMS 启动完成的时候会发送此广播,在此时会通过PMS 的接口进行检查所有注册此广播的应用。

                List newReceivers = AppGlobals.getPackageManager()                        .queryIntentReceivers(intent, resolvedType, pmFlags, user).getList();

得到的ResolveInfo 为:

public class ResolveInfo implements Parcelable {    private static final String TAG = "ResolveInfo";    public ActivityInfo activityInfo;    ...    ...    public IntentFilter filter;

 

至此,广播的两种注册方式就解读完成,下面一篇博文来继续分析广播的另外一半功能——广播的发送过程解析。

 

 

 

更多相关文章

  1. Android(安卓)技术专题系列之十七 -- volume 服务
  2. Android的IPC机制(六)—— BroadcastReceiver的使用
  3. Android(安卓)3.0之后开机无法接收系统广播权限原因
  4. Android(安卓)消息机制之 MessageQueue 消息队列
  5. android Application Component研究之BroadcastReceiver
  6. Android总结篇系列:Android广播机制
  7. Android实现简单的闹钟
  8. Android这四个你不可不知的知识点,你都了解多少?
  9. Android总结篇系列:Android广播机制

随机推荐

  1. Android 唤醒锁
  2. Android中读取短信信息
  3. Android Content Framework(1)Concept
  4. android本地定时通知
  5. Android Studio中断开SVN连接
  6. android 网络连接判断
  7. [android]android自动化测试五之Robolect
  8. 引用自定义资源需注意数据类型
  9. Android应用程序键盘(Keyboard)消息处理机
  10. 工作记录[续] android OBB