android U广播详解(一)

概念介绍

进程队列

BroadcastQueueModernImpl 的设计围绕着为设备上的每个潜在进程维护一个单独的 BroadcastProcessQueue 实例。表明用于传送到特定进程的Pending {@link BroadcastRecord} 条目队列。整个类都标记为 {@code NotThreadSafe},因为调用者有责任始终与持有的相关锁进行交互。

结构

在内部,每个队列由一个等待调度的待处理广播和一个当前正在调度的活动广播组成。给等待调度的广播分别维护了紧急、普通、负载三个有序集合,优先级为紧急(3) > 普通(10) > 负载,但是当优先级高的集合被处理的广播数量超过一定限制时,优先级低的广播也有机会得到执行。

可运行

每个队列都有一个在未来特定时间“可运行”(runnable at 时间戳)的概念,它支持在每个进程的基础上任意暂停或延迟交付。当它下一次符合执行条件时,该值会受到各种策略的影响,例如:

  • 哪些广播正在等待发送给给定进程。 例如,“紧急”(前台、源于用户交互、闹钟)广播通常会导致较早的runnable at(-120s)时间,或者“延迟”广播通常会导致较晚的runnable at时间。
  • 进程或 UID 的当前状态。 例如,“cached”(procState > PROCESS_STATE_RECEIVER)进程通常会导致较晚的runnable at(+120s)时间,或者“instrumented”进程通常会导致较早的runnable at(-120s)时间。
  • 阻塞等待较早的接收器完成。 例如,“有序”或“优先”广播通常会导致not currently runnable值。

并行调度

调度

给定具有有效 runnable at 时间戳的每个进程队列的集合,BroadcastQueueModernImpl 然后愿意将这些 runnable队列提升为 running 状态。 我们根据 runnable at 时间戳的排序顺序选择下一个要提升的每个进程队列,首先选择等待时间最长的进程,旨在减少整体广播调度延迟。
限制

  • 为了保持系统健康(因为有序或静态注册的会在binder线程接着分发),在任何给定时间最多允许“BroadcastConstants.MAX_RUNNING_PROCESS_QUEUES”(4,低内存2个)进程处于running状态,额外会在此基础上再允许运行一个有紧急广播的队列。
  • 在任何给定时间最多允许一个进程被冷启动。 (对于后台,通过fork和专门化 zygote 的冷启动进程是一项相对繁重的操作,因此将我们自己限制在单个挂起的冷启动减少了系统范围的资源争用。)等前一个进程冷启结束后可立刻安排下一次调度。
分批派发

考虑将进程队列中任何其他Pending广播分派到该进程,旨在分批分派以更好地分摊 OOM 调整的成本。每个进程队列一次可最多分派MAX_RUNNING_ACTIVE_BROADCASTS(16,低内存8)个广播,以避免其他进程处于饥饿状态。

有序

收集一次可分发到的receivers时,如果遇到有序广播或静态注册的receiver,则直接中断收集 ,将已有receivers分发到app进程。等app进程完成分发后告知系统,仍然在binder线程继续完成当前进程队列的分发。

饥饿注意事项

仔细关注几种类型的潜在资源匮乏,以及缓解机制:

  • 进程队列的应用延迟runnable at 策略可能会导致Pending列表变得非常大。 当队列变得太大时,“BroadcastConstants.MAX_PENDING_BROADCASTS”会绕过任何延迟来缓解这种情况。
  • 具有大量Pending广播的进程队列可能会独占有限的 runnable 插槽之一。 这可以通过使用“BroadcastConstants.MAX_RUNNING_ACTIVE_BROADCASTS”来暂时“退出”正在运行的进程以让其他进程有机会运行来缓解。
  • 一个“紧急”广播被发送到一个有大量“非紧急”广播积压的进程可能会有很大的发送延迟。 这可以通过维护一个单独的紧急事件的 mPendingUrgent 队列来缓解,我们更愿意在正常的 mPending 队列之前调度它。
  • 具有有序广播的进程希望执行,但严重的 CPU 争用可能会导致进程在触发 ANR 超时之前无法接收到足够的资源。 这可以通过将“软”ANR 超时延长至原始超时长度的两倍来缓解。

BroadcastQueueModernImpl

替代 {@link BroadcastQueue} 实现,它以每个进程为基础调度广播。
每个进程现在都有自己的广播队列,由 {@link BroadcastProcessQueue} 实例表示。 每个队列都有一个在未来特定时间“可运行”的概念,它支持在每个进程的基础上任意暂停或延迟交付。
为了让事情更容易推理,有一种非常强烈的偏好,即让广播交互以这种特定顺序通过一组一致的方法流动:

  • {@link #updateRunnableList} 在每个进程队列有相关的未决广播时将其提升为可运行
  • {@link #updateRunningList} 促进可运行队列运行并安排第一次广播的传送
  • {@link #scheduleReceiverColdLocked} 请求任何需要的冷启动,结果{@link#onApplicationAttachedLocked} 报告
  • {@link #scheduleReceiverWarmLocked} 请求将当前活动的广播发送到正在运行的应用程序,并通过 {@link #finishReceiverLocked} 报告结果

主要特点

android U广播机制重构原因:

  • 遗留广播队列以串行方式一次一个地向接收方应用程序发送广播(有序)
  • 最初是一个合理的选择,因为这些是后台任务
  • 这些年来,病态的案例不断涌现,就像在许多接收器中翻滚一样。
  • 除了一些迭代改进外,整体架构自Android~1.0以来保持不变

高效的广播传输

允许多个进程并行处理广播,并通过一次将多个广播分派给一个进程来最小化 OOm 调整成本。

  • 引入每个进程队列来处理广播传输并在每个进程的基础上设置策略(暂停/延迟)
  • 允许多个进程(4+1)并行处理广播,同时保留来自每个应用程序 PoV 的广播传送顺序
  • 通过连续向一个进程传送多个广播(16)来最小化 OOM 调整成本

广播从入队到分发的大致流程,更新mRunning列表在ActivityManager线程。
在这里插入图片描述

允许多个进程(4+1)并行处理广播:

  • 有序广播分发后会等到receiver finish后重新在binder线程继续分发当前进程队列里等待分发的广播,直到没有广播分发或达到分发上限。
  • 同一时间内只会允许冷启动一个进程,进程启动成功后会在binder线程中分发当前进程队列里等待分发的广播。

所以最多会有5个线程可同时针对5个各自的进程队列进行广播反而分发,大大提高了广播的分发速度(尤其是有序广播或功能清单注册的接收器)。

在这里插入图片描述

消除冗余广播

丢弃和合并频繁发送的广播

允许系统丢弃和合并某些高频广播的新 API

广播发送者可以指定如何处理他们的广播

  • 使用 setDeliveryGroupMatching*() API 指示应如何对广播进行分组
  • 使用 setDeliveryGroupPolicy() API 来指示如何“合并”属于一个组的广播
    在这里插入图片描述
    下发组策略:
    // 下发组策略,表示下发组内的所有广播都需要按原样下发。@SystemApipublic static final int DELIVERY_GROUP_POLICY_ALL = 0;// 下发组策略,表示只下发该下发组中最新的广播,其余的可以丢弃。@SystemApipublic static final int DELIVERY_GROUP_POLICY_MOST_RECENT = 1;// 交付组策略,指示交付组中广播的额外数据需要合并到单个广播中,其余数据可以丢弃。public static final int DELIVERY_GROUP_POLICY_MERGED = 2;
例子

将 MOST_RECENT 策略应用于 CONNECTIVITY_ACTION

  • 将networkType设置为匹配键,表示特定网络类型对应的所有广播都属于同一个投递组
  • 设置MOST_RECENT为policy,表示只需要传递一个传递组中最近的广播,其余的可以丢弃
    在这里插入图片描述
应用策略的示例广播

在这里插入图片描述

减少后台工作(已被废弃)

阻止处于缓存状态的应用程序使用广播(已废弃,改为阻止冻结状态)
防止处于Cached状态的应用使用广播消耗系统资源

  • 添加了一个新的BroadcastOptions BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE以允许发送者指示他们对缓存应用程序的广播可以延迟到它们变为活跃状态

限制cache进程接收广播的更改历史:

  • 谷歌从开始的限制(procState > 11)的进程接收广播;
  • 到后面限制(procState > 15)的进程接收广播;
  • 再到现在只限制冻结的进程接收广播。
/** {@hide} */
@IntDef(prefix = { "DEFERRAL_POLICY_" }, value = {DEFERRAL_POLICY_DEFAULT,DEFERRAL_POLICY_NONE,DEFERRAL_POLICY_UNTIL_ACTIVE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface DeferralPolicy {}public @NonNull BroadcastOptions setDeferralPolicy(@DeferralPolicy int deferralPolicy) {mDeferralPolicy = deferralPolicy;return this;
}

如何分析

通过执行如下命令可以查看历史的广播分发记录等信息。

adb shell dumpsys activity broadcasts

整体结构

  // 完整的广播队列列表,如果没有Active状态的广播则不打印当前的进程队列📋 Per-process queues:// mRunnableHead 中保存的进程队列(可运行的)🧍 Runnable:(none)// mRunning 中保存的进程队列(正在运行的)🏃 Running:(none)(none)(none)(none)(none)// 可暂不管,系统配置的是否忽略传递组策略Broadcasts with ignored delivery group policies:{}// mUidForeground ,保存当前处于前台(procstate为PROCESS_STATE_TOP)的uidForeground UIDs:{}// 一些常量Broadcast parameters (key=bcast_fg_constants, observing=true):bcast_timeout=+10s0ms bcast_slow_time=+5s0ms bcast_deferral=+5s0ms bcast_deferral_decay_factor=0.75 bcast_deferral_floor=0 bcast_allow_bg_activity_start_timeout=+10s0ms Broadcast parameters (namespace=activity_manager_native_boot):modern_queue_enabled=true  // 使用现代广播队列逻辑处理广播bcast_max_running_process_queues=4 // 一次最多可同时进行分发的广播队列数量bcast_max_running_active_broadcasts=16 // 单个广播队列一次最多可分发的广播数量bcast_max_core_running_blocking_broadcasts=16 bcast_max_core_running_non_blocking_broadcasts=64 bcast_max_pending_broadcasts=256  bcast_delay_normal_millis=+500ms bcast_delay_cached_millis=+2m0s0ms bcast_delay_urgent_millis=-2m0s0ms bcast_delay_foreground_proc_millis=-2m0s0ms bcast_delay_persistent_proc_millis=-2m0s0ms bcast_max_history_complete_size=256  // 最多可保存的完整的历史已分发完成的广播数量bcast_max_history_summary_size=1024 // 最多可保存的简要的历史已分发完成的广播数量bcast_max_consecutive_urgent_dispatches=3 bcast_max_consecutive_normal_dispatches=10 bcast_core_defer_until_active=true pending_cold_start_check_interval_millis=30000 // 广播的历史记录// 正在被分发或等待被分发的广播Pending broadcasts:<empty>// 已经分发完毕的广播(完整的信息)Historical broadcasts [modern]:Historical Broadcast modern #0:// 已经分发完毕的广播(简要的信息)Historical broadcasts summary [modern]:#0: act=miui.intent.action.CYCLE_CHECK flg=0x400000100 dispatch +5ms finishenq=2023-10-12 19:04:51.070 disp=2023-10-12 19:04:51.070 fin=2023-10-12 19:04:51.075

广播的分发状态

    @IntDef(flag = false, prefix = { "DELIVERY_" }, value = {DELIVERY_PENDING, // 初始状态:等待未来运行DELIVERY_DELIVERED, // 终端状态:成功完成DELIVERY_SKIPPED, // 终端状态:由于内部政策而跳过DELIVERY_TIMEOUT, // 终端状态:尝试投递时超时DELIVERY_SCHEDULED, // 中间状态:当前正在执行DELIVERY_FAILURE, // 终端状态:派送失败})
PENDING
    // 设置进程队列中的息屏广播正在等待被分发ba971da 5456:com.android.settings/1000 not runnable because BLOCKEDrunningOomAdjusted:truee:10 d:8 f:3 fd:1 o:0 a:0 p:8 pd:8 int:0 rt:8 ins:0 m:9 csi:0 adcsi:0 ccu:3 ccn:2-334ms 67ebdbd android.intent.action.SCREEN_OFF/u-1PENDING URGENT for registered 9f581c2 // 广播receiver状态为PENDING,广播为urgent(前台)blocked until 20, currently at 10 of 94 // 有序广播,需要等待前面的广播分发完成

App注意事项

如何让广播更快被分发

这里针对的是广播发送断

  1. 标记广播的intent为interactive
BroadcastOptions options = BroadcastOptions.makeBasic();
options.setInteractive(true);
pendingIntent.send(options.toBundle());

一般用于标记用户启动的 PendingIntent,需要声明如下权限:

<uses-permission android:name="android.permission.COMPONENT_OPTION_INTERACTIVE" />
  1. 给广播的intent添加前台标记
Intent intent = new Intent(XXX);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);

App须知

  1. 耗时时间长&接受者多的广播建议加上负载标志FLAG_RECEIVER_OFFLOAD,目前而言就开机广播;
  2. 短时间内发送频率高的广播,建议发送时按需指定DELIVERY_GROUP_POLICY_MOST_RECENT或DELIVERY_GROUP_POLICY_MERGED的policy。
final Bundle mostRecentDeliveryOptions = BroadcastOptions.makeBasic().setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT).toBundle();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/156136.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Javascript笔记:Web页面中的事件处理

1 任务队列 2事件处理&#xff1a;⼀个只有宏任务的示例 3 Web⻚⾯中的事件处理 3.1 定时器与事件处理&#xff1a;一个实例 4 Web⻚⾯中的事件处理 5 事件在DOM中的传播 5.1 两个阶段

wins打开ftp服务,跳转到浏览器解决方式

问题: 在wins的资源管理器中输入 ftp://服务器ip的时候&#xff0c;会突然跳转到浏览器中 百度上的方法归纳汇总 解决方法: 百度上最多的方式&#xff0c;但是我电脑试了不行 启动 InternetExplorer 在 菜单栏 选择 工具 -> Internet 选项 -> 高级 -> 勾选 启用 …

平衡二叉树(AVL) 的认识与实现

文章目录 1 基本1.1 概念1.2 特点1.3 构建1.4 调整1.4.1 RR1.4.1.1 示例1.4.1.2 多棵树不平衡 1.4.2 LL1.4.2.1 示例 1.4.3 LR1.4.3.1 示例 1.4.4 RL1.4.4.1 示例 1.5 实现1.5.1 示例1.5.2 完善 1 基本 1.1 概念 平衡二叉树是一棵合理的二叉排序树 解释 对于这么一个序列 如…

【Ceph Block Device】块设备挂载使用

文章目录 前言创建pool创建user创建image列出image检索image信息调整image大小增加image大小减少image大小 删除image从pool中删除image从pool中“延迟删除”image从pool中移除“延迟删除的image” 恢复image恢复指定pool中延迟删除的image恢复并重命名image 映射块设备格式化i…

C++DAY44

#include <iostream>using namespace std;class Animal//封装 动物 基类 { private:string name; public:Animal() {}Animal(string n):name(n){}virtual void perform() //虚函数{cout << "欢迎来到动物园" << endl;} };class Lion:public Animal…

c/c++--字节对齐(byte alignment)

1. 默认字节对齐 在所有结构体成员的字节长度都没有超出操作系统基本字节单位(32位操作系统是4,64位操作系统是8)的情况下 按照结构体中字节最大的变量长度来对齐&#xff1b;若结构体中某个变量字节超出操作系统基本字节单位 那么就按照系统字节单位来对齐。 注意&#xff1…

视频监控系统/安防视频平台EasyCVR广场视频细节优化

安防视频监控系统/视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。安防视频汇聚平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;可实现视频监控直播、视频轮播、…

【Python 零基础入门 】安装 环境配置

【Python 零基础入门 】第一课 安装 & 环境配置 Python 零基础入门 第一课 安装 & 环境配置Python 的历史Python 的前景安装了解你的操作系统Python 安装环境配置 PyCharm 安装第一个程序 Python 零基础入门 第一课 安装 & 环境配置 在当今的技术时代, 编程语言正…

微信小程序/vue3/uview-plus form兜底校验

效果图 代码 <template><u-form :model"form" ref"formRole" :rules"rules"><u-form-item prop"nickname"><u-input v-model"form.nickname" placeholder"姓名" border"none" /&…

没用的知识增加了,尝试用文心实现褒义词贬义词快速分类

尝试用文心实现褒义词贬义词快速分类 一、我的需求二、项目环境搭建千帆SDK安装及使用流程 三、项目实现过程创建应用获取签名调用接口计算向量积总结 百度世界大会将于10月17日在北京首钢园举办&#xff0c;今天进入倒计时五天了。通过官方渠道的信息了解到&#xff0c;这次是…

Web后端开发登录校验及JWT令牌,过滤器,拦截器详解

如果用户名正确则成功进入 登录功能 代码 Controller Service Mapper 结果 若登录成功结果如下: 如果登录失败,结果如下 登录校验 为什么需要登录校验 有时再未登录情况下, 我们也可以直接访问部门管理, 员工管理等功能 因此我们需要一个登录校验操作, 只有确认用户登录…

【Debian】报错:su: Authentication failure

项目场景&#xff1a; 今天我重新刷了一个debian系统。 系统版本&#xff1a; # 查看系统版本 lsb_release -a 我的系统版本&#xff1a; No LSB modules are available. Distributor ID&#xff1a;Debian Description: Debian GNU/Linux 12 &#xff08;bookworm&#xff…

优雅而高效的JavaScript——箭头函数

&#x1f917;博主&#xff1a;小猫娃来啦 &#x1f917;文章核心&#xff1a;优雅而高效的JavaScript——箭头函数 文章目录 前言箭头函数的基本语法和特点箭头函数的语法箭头函数的词法绑定特性箭头函数的this值箭头函数无法使用arguments对象 箭头函数与传统函数的比较箭头函…

每年高考时间是几月几号 高考开始时间

高考是高中生最重要的一个阶段&#xff0c;甚至影响着很多学生的未来&#xff0c;相信大家都很关注高考的具体时间是什么时候&#xff0c;本次将详细给您介绍高考的具体开始时间以及结束时间。 每年高考的时间都是6月7日开始&#xff0c;一共持续三天时间左右&#xff0c;但是…

身份证号码,格式校验:@IdCard(自定义注解)

目标 自定义一个用于校验 身份证号码 格式的注解IdCard&#xff0c;能够和现有的 Validation 兼容&#xff0c;使用方式和其他校验注解保持一致&#xff08;使用 Valid 注解接口参数&#xff09;。 校验逻辑 有效格式 符合国家标准。 公民身份号码按照GB11643&#xff0d;…

竞赛选题 深度学习+opencv+python实现车道线检测 - 自动驾驶

文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络3.1卷积层3.2 池化层3.3 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 YOLOV56 数据集处理7 模型训练8 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &am…

印度网络安全:威胁与应对

随着今年过半&#xff0c;我们需要评估并了解不断崛起的网络威胁复杂性&#xff0c;这些威胁正在改变我们的数字景观。 从破坏性的网络钓鱼攻击到利用人工智能的威胁&#xff0c;印度的网络犯罪正在升级。然而&#xff0c;在高调的数据泄露事件风暴中&#xff0c;我们看到了政…

游戏反虚拟机检测方案

近年来&#xff0c;游戏市场高速发展&#xff0c;随之而来的还有图谋利益的游戏黑产。在利益吸引下&#xff0c;游戏黑产扩张迅猛&#xff0c;攻击趋势呈现出角度多样化的特点。 在这一趋势下&#xff0c;游戏安全防护的检测覆盖率显得尤为重要。如果游戏在某一环节出现被绕过…

Linux系统卡顿处理记录(Debian)

问题现象描述 现象linux操作系统卡顿&#xff08;就是很慢&#xff09;&#xff0c;但是系统任然能够使用。 文章一步步的排查并且定位问题。 排查步骤 1. 使用top命令查看CPU是否占用过高。&#xff08;未发现&#xff09;排除问题 2. 使用df -h查看硬盘是否被占满。&#…

浏览器唤起钉钉 各项功能

浏览器唤起钉钉对应人员聊天 文档地址 https://open.dingtalk.com/document/client/unified-routing-protocol 唤起聊天 不过只能唤起叮叮的名片 id为叮叮号 <a href"dingtalk://dingtalkclient/action/sendmsg?dingtalk_id{id}"></a>id&#xff1a; …