热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

AMSBroadcast和BroadcastReceiver

         注册BroadcastReceiver通过ActivityManagerService#registerReceiver注册到AMS

              《AMS-Broadcast和BroadcastReceiver》

注册BroadcastReceiver

通过ActivityManagerService#registerReceiver注册到AMS中

              《AMS-Broadcast和BroadcastReceiver》

介绍几个跟注册有关的重要成员

* mRegisteredReceivers :  HashMap    ReceiverList

  ReceiverList extends ArrayList,持有PorcessRecord和IIntentReceiver,并且保存了该IIntentReceiver对应的所有BroadcastIntent。

  其中IIntentReceiver持有BroadcastReceiver。

                《AMS-Broadcast和BroadcastReceiver》

在注册的时候,有一种stickyBroadcast,发送过一次后,AMS会记录下来,每次有新注册的Receiver,都会发给这个新的Receiver。

 

 

发送广播(sendBroadcast):

ActivityManagerService#broadcastIntentLocked(…)

* 若是特殊广播,如UID_REMOVED, PACKEAGE_REMOVED, PACKAGE_ADDED,

  TIMEZONE变化广播,CLEAR_DNS_CACHE广播,PROXY_CHANGE广播等

  需要特殊处理

* 关于sticky广播的一些处理

* 在该方法中,定义了两个List,分别是receivers:Lsit和registeredReceivers

  分别保存所有符合条件的广播接收者(包括静态和动态)和动态接收者。

  receiver = AppGlobals.getPackageManager().queryIntentReceivers(inent, resolvedType, STOCK_PM_FLAGS);

  registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);

* 若不是有序广播,创建一个BroadcastRecord,代表了一个广播,该对象持有所有能接收该广播的动态接收者的引用。

   将该广播加入一个queue,并开始广播,即与各进程通信,使receiver的onreceive方法在各自进程中执行。

 

if (!replaced) {
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}

queque:BroadcastQueue,其中scheduleBroadcastsLocked会触发processNextBroadcast
BroadcastQueue#processNextBroadcast

 

  该方法重要的一段代码:

 

// First, deliver any non-serialized broadcasts right away.
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
final int N = r.receivers.size();
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
+ mQueueName + "] " + r);
for (int i=0; i Object target = r.receivers.get(i);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Delivering non-ordered on [" + mQueueName + "] to registered "
+ target + ": " + r);
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
}
addBroadcastToHistoryLocked(r);
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
+ mQueueName + "] " + r);
}

逐个启动各进程中的receiver的onreceive方法。最后将给broadcasstRecord放入History中。

 

* 还要处理静态的接收者,因静态接收者所在进程可能没有启动,所以不能像静态接收者一样处理。

  需要逐个处理,像有序广播那样处理

ActivityThread#scheduleRegisteredReceiver(…)

 

public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
int resultCode, String dataStr, Bundle extras, boolean ordered,
boolean sticky, int sendingUser, int processState) throws RemoteException {
updateProcessState(processState, false);
receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
sticky, sendingUser);
}

IIntentReceiver的实例类型是LoadedAPK.ReceiverDispatcher,而ReceiverDispatcher持有BroadcastReceiver

 

最终去到LoadedAPK.ReceiverDispatcher.Args#run()

 

public void run() {
final BroadcastReceiver receiver = mReceiver;
final boolean ordered = mOrdered;

if (ActivityThread.DEBUG_BROADCAST) {
int seq = mCurIntent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
+ " seq=" + seq + " to " + mReceiver);
Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered
+ " mOrderedHint=" + ordered);
}

final IActivityManager mgr = ActivityManagerNative.getDefault();
final Intent intent = mCurIntent;
mCurIntent = null;

if (receiver == null || mForgotten) {
if (mRegistered && ordered) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing null broadcast to " + mReceiver);
sendFinished(mgr);
}
return;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);//在此调用了onreceive()
} catch (Exception e) {
if (mRegistered && ordered) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing failed broadcast to " + mReceiver);
sendFinished(mgr);
}
if (mInstrumentation == null ||
!mInstrumentation.onException(mReceiver, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Error receiving broadcast " + intent
+ " in " + mReceiver, e);
}
}

if (receiver.getPendingResult() != null) {
finish();
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}

1.注册广播

/*
功能和前面类似,但增加了两个参数,分别是broadcastPermission和scheduler,作用有
两个:
其一:对广播者的权限增加了控制,只有拥有相应权限的广播者发出的广播才能被此接收者接收
其二:BroadcastReceiver对象的onReceiver函数可调度到scheduler所在的线程中执行
*/
publicIntent registerReceiver(BroadcastReceiver receiver,
IntentFilterfilter, String broadcastPermission, Handler scheduler) {
/*

 用上面这些参数通过LoadedApk.ReceiverDispatcher.getIIntentReceiver(…)构造一个个IIntentReceiver,传给AMS,同时ApplicationThread也会传给AMS,调用AMS以下方法:

public Intent registerReceiver(IApplicationThreadcaller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission)

注册时并没有把本地创建的 BroadcastReceiver对象保存到本应用进程的某个结构体中,而是

2.接收广播。

IIntentReceiver是一个Binder对象,但是最后AMS和应用进程通信时使用的是ApplicationThread,通过ApplicationThread#scheduleRegisteredReceiver的方法

public voidscheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
intresultCode, String dataStr, Bundle extras, boolean ordered,
boolean sticky) throws RemoteException {
//又把receiver对象传了回来。还记得注册时传递的一个IIntentReceiver类型
//的对象吗?
receiver.performReceive(intent,resultCode, dataStr, extras, ordered,
sticky);
}

通过该方法把注册时传递过去的IIntentReceiver又传回来了。然后就调用该对象performReceiver,最终会调用到BroadcastReceiver#onReceive()。

 


推荐阅读
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • Week04面向对象设计与继承学习总结及作业要求
    本文总结了Week04面向对象设计与继承的重要知识点,包括对象、类、封装性、静态属性、静态方法、重载、继承和多态等。同时,还介绍了私有构造函数在类外部无法被调用、static不能访问非静态属性以及该类实例可以共享类里的static属性等内容。此外,还提到了作业要求,包括讲述一个在网上商城购物或在班级博客进行学习的故事,并使用Markdown的加粗标记和语句块标记标注关键名词和动词。最后,还提到了参考资料中关于UML类图如何绘制的范例。 ... [详细]
  • 本文介绍了在CentOS 6.4系统中更新源地址的方法,包括备份现有源文件、下载163源、修改文件名、更新列表和系统,并提供了相应的命令。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
author-avatar
Pen-彭静丹h
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有