注册广播接收器

Android系统的广播机制是一种消息订阅/发布机制,因此,使用这种消息驱动模型的第一步便是订阅消息;而对Android应用程序来说,订阅消息其实就是注册广播接收器。在Android的广播机制中,ActivityManagerService扮演着广播中心的角色,负责系统中所有广播的注册和发布操作,因此,Android应用程序注册广播接收器的过程就把是广播接收器注册到ActivityManagerService的过程。Android应用程序是通过调用ContextWrapper类的registerReceiver函数来把广播接收器BroadcastReceiver注册到ActivityManagerService中去的,而ContextWrapper类本身又借助ContextImpl类来注册广播接收器。在Android应用程序框架中,Activity和Service类都继承了ContextWrapper类,因此,我们可以在Activity或者Service的子类中调用registerReceiver函数来注册广播接收器。Activity、Service、ContextWrapper和ContextImpl这四个类的关系:

registerReceiver函数播接收器注册过程的时序图如下:

接下来对registerReceiver注册广播接收器的源码进行详细分析,由于Activity继承于Context类,Context类是一个抽象类,定义了registerReceiver接口函数,因此在Activity的子类中,可以直接调用registerregisterReceiver函数,但是Activity及其父类都没有实现registerReceiver接口函数,在Activity调用registerReceiver来注册广播接收器时,根据Activity类继承关系,会依次调用一遍其父类的registerReceiver函数,父类ContextWrapper对registerReceiver函数实现如下:

@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {return mBase.registerReceiver(receiver, filter);
}@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,String broadcastPermission, Handler scheduler) {return mBase.registerReceiver(receiver, filter, broadcastPermission,scheduler);
}

这里定义了两个registerReceiver重载函数,以上两个函数的实现都是间接调用mBase对象的registerReceiver函数,mBase定义为Context类型,在Context的子类中,ContextImpl类实现了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, filter, broadcastPermission,scheduler, getOuterContext());
}

在ContextImpl类中仍然实现了两个registerReceiver函数的重载,但他们都并没有真正实现该函数,而是调用函数registerReceiverInternal函数来完成,registerReceiverInternal函数的定义如下:

private Intent registerReceiverInternal(BroadcastReceiver receiver,IntentFilter filter, String broadcastPermission,Handler scheduler, Context context) {/* broadcastPermission = nullscheduler = null */IIntentReceiver rd = null;if (receiver != null) {if (mPackageInfo != null && context != null) {if (scheduler == null) {//获取应用程序主线程的handle对象scheduler = mMainThread.getHandler();}//获取IIntentReceiver广播接收分发器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 {/* ActivityManagerNative.getDefault()得到ActivityManagerService在客户进程的代理类对象ActivityManagerProxy,通过Binder进程间通信,远程调用ActivityManagerService的registerReceiver函数 */return ActivityManagerNative.getDefault().registerReceiver(mMainThread.getApplicationThread(), mBasePackageName,rd, filter, broadcastPermission);} catch (RemoteException e) {return null;}
}

获取Activity的上下文

final Context getOuterContext() {return mOuterContext;
}ContextImpl() {mOuterContext = this;
}

由于ContextImpl类为Activity的父类,因此getOuterContext()函数得到的是注册广播接收器的Activity的上下文。

获取应用程序主线程的消息分发器handle

mMainThread.getHandler()

frameworks\base\core\java\android\app\ActivityThread.java

final Handler getHandler() {return mH;
}final H mH = new H();private class H extends Handler {public static final int LAUNCH_ACTIVITY         = 100;public void handleMessage(Message msg) {if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));switch (msg.what) {case LAUNCH_ACTIVITY: {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");ActivityClientRecord r = (ActivityClientRecord)msg.obj;r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);handleLaunchActivity(r, null);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);} break;}}
}

该handle是在ActivityThread类中定义,用于处理应用程序主线程的消息分发处理。

获取广播接收分发器

frameworks\base\core\java\android\app\LoadedApk.java

public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,Context context, Handler handler,Instrumentation instrumentation, boolean registered) {synchronized (mReceivers) {LoadedApk.ReceiverDispatcher rd = null;HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;//注册广播接收器if (registered) {//以注册广播接收器的Activity为key从mReceivers的Hashmap表中取出该上下文对应的广播接收器表map = mReceivers.get(context);//根据BroadcastReceiver从广播接收器表中取出对应的LoadedApk.ReceiverDispatcherif (map != null) {rd = map.get(r);}}//如果表中不存在,直接创建ReceiverDispatcher对象if (rd == null) {rd = new ReceiverDispatcher(r, context, handler,instrumentation, registered);//并且以<BroadcastReceiver,LoadedApk.ReceiverDispatcher>为键值对的形式保存if (registered) {if (map == null) {map = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();mReceivers.put(context, map);}map.put(r, rd);}} else {rd.validate(context, handler);}rd.mForgotten = false;//取得ReceiverDispatcher对象的成员变量mIIntentReceiverreturn rd.getIIntentReceiver();}
}

注册的广播接收器的存储方式如下:

LoadedApk.mReceivers

该广播接收器表保存在LoadedApk对象的成员变量mReceivers中。

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

ActivityManagerProxy注册广播接收器

public Intent registerReceiver(IApplicationThread caller, String packageName,IIntentReceiver receiver,IntentFilter filter, String perm) throws RemoteException
{Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IActivityManager.descriptor);data.writeStrongBinder(caller != null ? caller.asBinder() : null);data.writeString(packageName);data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);filter.writeToParcel(data, 0);data.writeString(perm);mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);reply.readException();Intent intent = null;int haveIntent = reply.readInt();if (haveIntent != 0) {intent = Intent.CREATOR.createFromParcel(reply);}reply.recycle();data.recycle();return intent;
}

ActivityManagerProxy通过Binder驱动程序远程调用服务进程的ActivityManagerService的registerReceiver函数来注册广播接收器。

ActivityManagerService注册广播接收器

关于广播接收器的数据结构图:

public Intent registerReceiver(IApplicationThread caller, String callerPackage,IIntentReceiver receiver, IntentFilter filter, String permission) {enforceNotIsolatedCaller("registerReceiver");synchronized(this) {ProcessRecord callerApp = null;if (caller != null) {//caller = mMainThread.getApplicationThread()//获取应用程序的ProcessRecordcallerApp = 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.contains(callerPackage)) {throw new SecurityException("Given caller package " + callerPackage+ " is not running in process " + callerApp);}} else {callerPackage = null;}List allSticky = null;// Look for any matching sticky broadcasts...Iterator actions = filter.actionsIterator();if (actions != null) {while (actions.hasNext()) {String action = (String)actions.next();allSticky = getStickiesLocked(action, filter, allSticky);}} else {allSticky = getStickiesLocked(null, filter, allSticky);}// The first sticky in the list is returned directly back to// the client.Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;if (receiver == null) {return sticky;}//从mRegisteredReceivers表中取出receiver对应的ReceiverList,ReceiverList列表用于保存BroadcastFilterReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());if (rl == null) {//创建ReceiverList对象rl = new ReceiverList(this, callerApp,Binder.getCallingPid(),Binder.getCallingUid(), receiver);if (rl.app != null) {//保存到ProcessRecord的receivers成员变量中rl.app.receivers.add(rl);} else {try {receiver.asBinder().linkToDeath(rl, 0);} catch (RemoteException e) {return sticky;}rl.linkedToDeath = true;}//注册到mRegisteredReceivers HashMap表中mRegisteredReceivers.put(receiver.asBinder(), rl);}//根据IntentFilter创建广播接收过滤器BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission);//为当前广播接收器设置Action过滤器rl.add(bf);if (!bf.debugCheck()) {Slog.w(TAG, "==> For Dynamic broadast");}mReceiverResolver.addFilter(bf);// Enqueue broadcasts for all existing stickies that match// this filter.if (allSticky != null) {ArrayList receivers = new ArrayList();receivers.add(bf);int N = allSticky.size();for (int i=0; i<N; i++) {Intent intent = (Intent)allSticky.get(i);BroadcastQueue queue = broadcastQueueForIntent(intent);BroadcastRecord r = new BroadcastRecord(queue, intent, null,null, -1, -1, null, receivers, null, 0, null, null,false, true, true);queue.enqueueParallelBroadcastLocked(r);queue.scheduleBroadcastsLocked();}}return sticky;}
}

在ActivityManagerService中,用一个进程记录块来表示这个应用程序进程,它里面有一个列表receivers,专门用来保存这个进程注册的广播接收器。接着,又把这个ReceiverList列表以receiver为Key值保存在ActivityManagerService的成员变量mRegisteredReceivers中。创建BroadcastFilter来把广播接收器列表rl和filter关联起来,然后保存在ActivityManagerService中的成员变量mReceiverResolver中去。

注消广播接收器

frameworks\base\core\java\android\content\ContextWrapper.java

public void unregisterReceiver(BroadcastReceiver receiver) {mBase.unregisterReceiver(receiver);
}

frameworks\base\core\java\android\app\ContextImpl.java

public void unregisterReceiver(BroadcastReceiver receiver) {if (mPackageInfo != null) {IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher(getOuterContext(), receiver);try {ActivityManagerNative.getDefault().unregisterReceiver(rd);} catch (RemoteException e) {}} else {throw new RuntimeException("Not supported in system context");}
}

函数首先从表中查找指定广播接收器的IIntentReceiver

public IIntentReceiver forgetReceiverDispatcher(Context context,BroadcastReceiver r) {synchronized (mReceivers) {//从mReceivers表中取出对应的广播接收器表HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context);LoadedApk.ReceiverDispatcher rd = null;if (map != null) {//从广播接收器表中取出指定的广播接收器的分发器rd = map.get(r);if (rd != null) {map.remove(r);if (map.size() == 0) {mReceivers.remove(context);}if (r.getDebugUnregister()) {HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder= mUnregisteredReceivers.get(context);if (holder == null) {holder = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();mUnregisteredReceivers.put(context, holder);}RuntimeException ex = new IllegalArgumentException("Originally unregistered here:");ex.fillInStackTrace();rd.setUnregisterLocation(ex);holder.put(r, rd);}//返回ReceiverDispatcher的IntentReceiverrd.mForgotten = true;return rd.getIIntentReceiver();}}HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder= mUnregisteredReceivers.get(context);if (holder != null) {rd = holder.get(r);if (rd != null) {RuntimeException ex = rd.getUnregisterLocation();throw new IllegalArgumentException("Unregistering Receiver " + r+ " that was already unregistered", ex);}}if (context == null) {throw new IllegalStateException("Unbinding Receiver " + r+ " from Context that is no longer in use: " + context);} else {throw new IllegalArgumentException("Receiver not registered: " + r);}}
}

通过ActivityManagerProxy代理向ActivityManagerService发送注销广播接收器的请求

public void unregisterReceiver(IIntentReceiver receiver) throws RemoteException
{Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IActivityManager.descriptor);data.writeStrongBinder(receiver.asBinder());mRemote.transact(UNREGISTER_RECEIVER_TRANSACTION, data, reply, 0);reply.readException();data.recycle();reply.recycle();
} 

ActivityManagerService负责广播接收器的注销工作:

public void unregisterReceiver(IIntentReceiver receiver) {if (DEBUG_BROADCAST) Slog.v(TAG, "Unregister receiver: " + receiver);final long origId = Binder.clearCallingIdentity();try {boolean doTrim = false;synchronized(this) {//从mRegisteredReceivers表中查找到receiver对应的ReceiverListReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());if (rl != null) {if (rl.curBroadcast != null) {BroadcastRecord r = rl.curBroadcast;final boolean doNext = finishReceiverLocked(receiver.asBinder(), r.resultCode, r.resultData,r.resultExtras, r.resultAbort, true);if (doNext) {doTrim = true;r.queue.processNextBroadcast(false);}}if (rl.app != null) {//从应用进程的receivers表中移除当前广播接收器对应的ReceiverListrl.app.receivers.remove(rl);}//从mRegisteredReceivers表中移除receiver,同时从mReceiverResolver的过滤ActionremoveReceiverLocked(rl);if (rl.linkedToDeath) {rl.linkedToDeath = false;rl.receiver.asBinder().unlinkToDeath(rl, 0);}}}// If we actually concluded any broadcasts, we might now be able// to trim the recipients' apps from our working setif (doTrim) {trimApplications();return;}} finally {Binder.restoreCallingIdentity(origId);}
}

至此广播接收器的注册与注销就介绍完了,注册的本质其实就是将广播接收器添加到ActivityManagerService的相应成员变量中存储,从而在分发广播的时候,可以根据表中注册的接收器来分发;而广播接收器的注销工作就是从相应的存储表中移除。

Android 广播接收器注册与注销源码分析相关推荐

  1. 【Android 启动过程】Activity 启动源码分析 ( ActivityThread -> Activity、主线程阶段 二 )

    文章目录 前言 一.ActivityThread 类 handleLaunchActivity -> performLaunchActivity 方法 二.Instrumentation.new ...

  2. 【Android 启动过程】Activity 启动源码分析 ( ActivityThread -> Activity、主线程阶段 一 )

    文章目录 前言 一.ClientTransactionHandler.scheduleTransaction 二.ActivityThread.H 处理 EXECUTE_TRANSACTION 消息 ...

  3. 【Android 启动过程】Activity 启动源码分析 ( AMS -> ActivityThread、AMS 线程阶段 二 )

    文章目录 前言 一.热启动与冷启动选择 二.AMS 进程中执行的相关操作 三.通过 Binder 机制转到 ActivityThread 中执行的操作 总结 前言 上一篇博客 [Android 启动过 ...

  4. 【Android 电量优化】JobScheduler 相关源码分析 ( JobSchedulerService 源码分析 | 任务检查 | 任务执行 )

    文章目录 一.回调 StateChangedListener 接口 二.JobHandler 处理 ( 任务检查 ) 三.maybeRunPendingJobsH 方法 四.assignJobsToC ...

  5. Android 9 (P) Zygote进程启动源码分析指南二

         Android 9 Zygote进程启动源码分析指南二 Android 9 (P) 系统启动及进程创建源码分析目录: Android 9 (P)之init进程启动源码分析指南之一 Andro ...

  6. 【Android 启动过程】Activity 启动源码分析 ( ActivityThread 流程分析 二 )

    文章目录 前言 一.ActivityManagerService.attachApplicationLocked 二.ActivityStackSupervisor.attachApplication ...

  7. 【Android 电量优化】JobScheduler 相关源码分析 ( ConnectivityController 底层源码分析 | 构造函数 | 追踪任务更新 | 注册接收者监听连接变化 )

    文章目录 一.ConnectivityController 连接控制器引入 二.ConnectivityController 构造方法解析 ( 注册接收者 ) 三.mConnectivityRecei ...

  8. 【Android 启动过程】Activity 启动源码分析 ( AMS -> ActivityThread、AMS 线程阶段 )

    文章目录 一.Activity 启动源码分析 ( AMS | ActivityManagerService ) 1.Instrumentation 调用 AMS 方法 2.ActivityStarte ...

  9. 微服务发现与注册之Eureka源码分析

    作者:陌北有棵树,Java人,架构师社区合伙人! [一]微服务之服务发现概述 关于微服务,近年来可谓是大火,业界也吹刮着一种实践微服务的风潮.本人有幸在去年参与到一个向微服务过渡的产品,再结合自己所学 ...

最新文章

  1. 定时调度模块:sched
  2. 轮播图最后一张图结束如何平缓回到第一张_产品经理早期如何学习?
  3. Explore Optimization
  4. C++ Primer 第十六章 模板与范型编程
  5. Ubuntu14.04下搭建LAMP环境
  6. Django模型层的多表操作(2)
  7. 【matlab函数】convn多维卷积
  8. PoE交换机的4种连接方法
  9. numpy线性代数基础 - Python和MATLAB矩阵处理的不同
  10. mtk6595能否运行linux,“被妖魔化”的联发科MTK6595到底如何?
  11. 三十而立,从零开始学ios开发(八):Autorotation and Autosizing
  12. mac上配置rails开发环境
  13. 《JAVA程序设计基础与应用》pdf 附下载链接
  14. 信息安全概论———网络安全协议
  15. 2、什么是软件过程?它与软件工程方法学有何关系?
  16. fir1截止频率计算_如果给定通带截止频率和阻带截止频率以及阻带最小衰减,如何用窗函数法设计线性相位低通滤波器?请写出设计...
  17. Java输出PPT文件(三) - 饼图数据替换
  18. Oracle中CONCAT详解
  19. unity中AO、metallic、roughness贴图的使用方式
  20. php雅思老师,雅思口语话题:最喜欢的老师

热门文章

  1. 软件开发:到底谁还在传言软件巨头濒临死亡?
  2. 字符串反转python 测试_Python中的反转字符串问题
  3. 不写一行代码,搭建Jenkins+Jmeter+Ant接口自动化框架
  4. java 日期 yyyy_java日期中YYYY与yyyy的区别
  5. 2018/11/22工作日志
  6. oracle 删除函数对象不存在_Python 函数式编程指北,不只是面向对象哦
  7. java 中j= i_java中 i = i++和 j = i++ 的区别
  8. pycharm 里面配置pip,安装库
  9. qmake manual=Variables
  10. 19复变函数的积分(五)