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注意事项
如何让广播更快被分发
这里针对的是广播发送断
- 标记广播的intent为interactive
BroadcastOptions options = BroadcastOptions.makeBasic();
options.setInteractive(true);
pendingIntent.send(options.toBundle());
一般用于标记用户启动的 PendingIntent,需要声明如下权限:
<uses-permission android:name="android.permission.COMPONENT_OPTION_INTERACTIVE" />
- 给广播的intent添加前台标记
Intent intent = new Intent(XXX);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
App须知
- 耗时时间长&接受者多的广播建议加上负载标志FLAG_RECEIVER_OFFLOAD,目前而言就开机广播;
- 短时间内发送频率高的广播,建议发送时按需指定DELIVERY_GROUP_POLICY_MOST_RECENT或DELIVERY_GROUP_POLICY_MERGED的policy。
final Bundle mostRecentDeliveryOptions = BroadcastOptions.makeBasic().setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT).toBundle();
相关文章:

android U广播详解(一)
概念介绍 进程队列 BroadcastQueueModernImpl 的设计围绕着为设备上的每个潜在进程维护一个单独的 BroadcastProcessQueue 实例。表明用于传送到特定进程的Pending {link BroadcastRecord} 条目队列。整个类都标记为 {code NotThreadSafe},因为调用者有责任始终与…...

input标签的23种type类型
一、概述 随着html5的出现,input标签新增了多种类型,用以接收各种类型的用户输入。其中传统输入控件有10种,新增输入控件有13种。 二、传统类型 传统输入控件有10种,如下所示。 text 定义单行文本输入框 password 定…...

分类预测 | MATLAB实现基于RF-Adaboost随机森林结合AdaBoost多输入分类预测
分类预测 | MATLAB实现基于RF-Adaboost随机森林结合AdaBoost多输入分类预测 目录 分类预测 | MATLAB实现基于RF-Adaboost随机森林结合AdaBoost多输入分类预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现基于RF-Adaboost随机森林结合AdaBoost多输…...

解决echarts配置滚动(dataZoom)后导出图片数据不全问题
先展现一个echarts,并配置dataZoom,每页最多10条数据,超出滚动 <div class"echartsBox" id"echartsBox"></div>onMounted(() > {nextTick(() > {var chartDom document.getElementById(echartsBox);…...

【vue3+ts】项目初始化
1、winr呼出cmd,输入构建命令 //用vite构建 npm init vitelatest//用cli脚手架构建 npm init vurlatest2、设置vscode插件 搜索volar,安装前面两个 如果安装了vue2的插件vetur,要禁用掉,否则插件会冲突...

c++视觉图像----扩充边界
图像扩充边界 #include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp>int main() {// 读取图像cv::Mat image cv::imread("1.jpg", cv::IMREAD_COLOR);if (image.empty()) {std::cerr << "Could not open or find the imag…...

邮政编码,格式校验:@ZipCode(自定义注解)
目标 自定义一个用于校验邮政编码格式的注解ZipCode,能够和现有的 Validation 兼容,使用方式和其他校验注解保持一致(使用 Valid 注解接口参数)。 校验逻辑 有效格式 不能包含空格;应为6位数字; 不校验…...

Appium自动化测试框架:关键字驱动+数据驱动
1. 关键字驱动框架简介 原理及特点 关键字驱动测试是数据驱动测试的一种改进类型,它也被称为表格驱动测试或者基于动作字的测试。主要关键字包括三类:被操作对象(Item)、操作行为(Operation)和操作值&…...

简单多状态dp【动态规划】
目录 一、按摩师 二、打家劫舍 三、删除并获得点数 四、粉刷房子 五、买卖股票的最佳时机 六、买卖股票的最佳时机(含手续费) 七、买卖股票的最佳时机III 八、买卖股票的最佳时机IV 一、按摩师 class Solution { public:int massage(vector<int>…...

OpenCV中initUndistortRectifyMap ()函数与十四讲中去畸变公式的区别探究
文章目录 1.十四讲中的去畸变公式2. OpenCV中的去畸变公式3. 4个参数和8个参数之间的区别4.initUndistortRectifyMap()函数源码 最近在使用OpenCV对鱼眼相机图像去畸变时发现一个问题,基于针孔模型去畸变时所使用的参数和之前十四讲以及视觉SLAM中的畸变系数有一点不…...

【C++】C++11——智能指针、内存泄漏、智能指针的使用和原理、RAII、auto_ptr、unique_ptr、shared_ptr、weak_ptr
文章目录 C117.智能指针7.1内存泄漏7.2智能指针的概念7.3智能指针的使用7.3.1 auto_ptr7.3.2 unique_ptr7.3.3 shared_ptr7.3.4 weak_ptr C11 7.智能指针 7.1内存泄漏 什么是内存泄漏: 内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏…...

EDUSRC-记某擎未授权与sql注入
目录 360天擎 - 未授权与sql注入 信息收集 FOFA语法 鹰图搜索 360天擎未授权访问 - 数据库信息泄露 漏洞复现 修复方案 360天擎终端安全管理系统ccid处SQL注入 漏洞复现 手动测试方法 修复方案 360天擎 - 未授权与sql注入 通常访问的页面如下,存在登录框…...

1688拍立淘API接口分享
拍立淘接口,顾名思义,就是通过图片搜索到相关商品列表。通过此接口,可以实现图片搜索爆款商品等功能。 接口地址:1688.item_search_img 公共参数 名称类型必须描述keyString是调用key(必须以GET方式拼接在URL中&…...

昇腾910使用记录
一. 压缩文件和解压文件 1. 压缩文件 tar -czvf UNITE-main.tar.gz ./UNITE-main/2. 解压文件 tar -xvf ./UNITE-main/二. CUDA更改为NPU data[label] data[label].cuda() data[instance] data[instance].cuda() data[image] data[image].cuda()更改为 data[label] da…...

从一部iPhone手机看芯片的分类
目录 问题 iPhone X 手机处理器:A11 iPhone X 的两大存储芯片 数字 IC CPU:计算设备的运算核心和控制核心 GPU:图形处理器 ASIC:为解决特定应用问题而定制设计的集成电路 存储芯片:DRAM 和 NAND Flash iPhone…...

arm day 7
完成字符串收发函数的封装并且验证现象,一个字符串发送接受后会有‘\n’ \r src/uart.c #include"uart.h"void uart4_init() {//设置UART4的RCc时钟使能//RCC_MP_APB1ENSETR[16]->1RCC->MP_APB1ENSETR | (0x1<<16);//设置GPIOB和GPIOG的时钟…...

Java基础面试-面向对象
什么是面向对象? 对比面向过程,是两种不同的处理问题角度 面向过程更注重事情的每一个步骤及顺序,面向对象更注重事情有哪些参与者(对象),及各自需要做什么 比如洗衣机洗衣服 面向过程会将任务拆解成一系…...

GCC vs. G++:C 与 C++ 编译器的差异和比较
本文将介绍 GCC(GNU Compiler Collection)和 G 编译器的区别,并对它们在 C 和 C 程序开发中的特性和用法进行比较和总结。 引言 在 C 和 C 程序开发中,选择合适的编译器是至关重要的。GCC(GNU Compiler Collection&a…...

MAC m系列docker login报错
错误:ERROR: failed to solve: XXX error getting credentials - err: exit status 1, out: 解决: vi ~/.docker/config.jsonzsxzsx [15时55分55秒] [~] { {"auths": {"harbor-g42c.corp.matrx.team": {"auth": "…...

Redis通用指令和五大基本数据类型常用指令总结
通用指令 keys parttern 查询key (parttern即通配符,不是正则表达式,例如 keys a? 匹配以a开头的长度为2的key) del key 删除key exists key 获取key是否存在 type key 获取key的类型 expire key seconds 为指定key设置有效期,单位秒 …...

uCharts常用图表组件demo
带渐变阴影的曲线图 <view class"charts-box"><qiun-data-charts type"area" :opts"opts" :chartData"chartData" :ontouch"true":background"rgba(256,256,256,0)" /> </view>data(){return{…...

VNC:Timed out waiting for a response from the computer
VNC的服务端使用的是TigerVNC,客户端使用的是RealVNC TigerVNC按其他博客配好后,防火墙ip什么的都配了,vnc客户端怎么连都是超时。 这里建议大家可以尝试一下重启服务器。我的是CentOS的 shutdown -r now 配了2天,最后服务器重启…...

Kotlin 协程 知识点
Android 上的 Kotlin 协程 | Android Developers (google.cn) 官方网址 1.什么是协程? 我觉得协程就是kotlin中一种优雅的实现异步请求 协程(Coroutines)是一种轻量级的并发编程概念,旨在简化异步编程和并发任务的处理。它是…...

简单大方的自我介绍 PPT 格式
自我介绍是展示自己的机会,同时也是展现自信和魅力的重要时刻。通过简单大方的PPT格式,可以更好地展示自己的个性和才华。下面是一些建议,帮助你在自我介绍中展现自信和魅力。 1. 打造简洁而有吸引力的PPT布局: - 选择简洁大方的背…...

panads操作excel
panads简介 pandas是基于Numpy创建的Python包,内置了大量标准函数,能够高效地解决数据分析数据处理和分析任务,pandas支持多种文件的操作,比如Excel,csv,json,txt 文件等,读取文件之…...

【MySQL】联合查询、子查询、合并查询
这里提供了三个表: 表1: mysql> select * from class; -------------- | id | name | -------------- | 1 | 一班 | | 2 | 二班 | | 3 | 三班 | -------------- 3 rows in set (0.01 sec) 表2: mysql> select * fro…...

小程序中如何设置所服务地区的时区
在全球化的背景下,小程序除了在中国使用外,还为海外的华人地区提供服务。例如我们采云小程序为泰国、阿根廷、缅甸等国家的商家就提供过微信小程序。这些商家开通小程序,为本地的华人提供服务。但通常小程序的开发者/服务商位于中国ÿ…...

Linux环境安装mysql8.0
1个人习惯我喜欢给软件安装在/use/local下,我使用的finalshell软件,直接手动新建一个文件夹名字为mysql 2下载mysql wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz 3解压文件 tar -xvf mysql-8.0.2…...

STM32_DMA_多通道采集ADC出现错位现象
STM32_DMA_多通道采集ADC出现错位现象 问题描述: adcSensorValue[0],adcSensorValue[3],adcSensorValue[6]… //存储通道1数据 adcSensorValue[1],adcSensorValue[4],adcSensorValue[7]… //存储通道2数据 adcSensorValue[2],adcSensorValue[5],adcSensorValue[8]……...

Linux内存管理 (2):memblock 子系统的建立
前一篇:Linux内存管理 (1):内核镜像映射临时页表的建立 文章目录 1. 前言2. 分析背景3. memblock 简介3.1 memblock 数据结构3.2 memblock 接口 4. memblock 的构建过程 1. 前言 限于作者能力水平,本文可能存在谬误,因此而给读者…...