当前位置: 首页 > web >正文

【android bluetooth 框架分析 02】【Module详解 13】【CounterMetrics 模块介绍】

1. CounterMetrics 介绍

CounterMetrics 模块代码很少, 我简单介绍一下。

// system/gd/metrics/counter_metrics.cc
#define LOG_TAG "BluetoothCounterMetrics"#include "metrics/counter_metrics.h"#include "common/bind.h"
#include "os/log.h"
#include "os/metrics.h"namespace bluetooth {
namespace metrics {const int COUNTER_METRICS_PERDIOD_MINUTES = 360; // Drain counters every 6 hoursconst ModuleFactory CounterMetrics::Factory = ModuleFactory([]() { return new CounterMetrics(); });void CounterMetrics::ListDependencies(ModuleList* list) const {
}void CounterMetrics::Start() {alarm_ = std::make_unique<os::RepeatingAlarm>(GetHandler());alarm_->Schedule(common::Bind(&CounterMetrics::DrainBufferedCounters,bluetooth::common::Unretained(this)),std::chrono::minutes(COUNTER_METRICS_PERDIOD_MINUTES));LOG_INFO("Counter metrics initialized");initialized_ = true;
}void CounterMetrics::Stop() {DrainBufferedCounters();initialized_ = false;alarm_->Cancel();alarm_.reset();LOG_INFO("Counter metrics canceled");
}bool CounterMetrics::CacheCount(int32_t key, int64_t count) {if (!IsInitialized()) {LOG_WARN("Counter metrics isn't initialized");return false;}if (count <= 0) {LOG_WARN("count is not larger than 0. count: %s, key: %d", std::to_string(count).c_str(), key);return false;}int64_t total = 0;std::lock_guard<std::mutex> lock(mutex_);if (counters_.find(key) != counters_.end()) {total = counters_[key];}if (LLONG_MAX - total < count) {LOG_WARN("Counter metric overflows. count %s current total: %s key: %d",std::to_string(count).c_str(), std::to_string(total).c_str(), key);counters_[key] = LLONG_MAX;return false;}counters_[key] = total + count;return true;
}bool CounterMetrics::Count(int32_t key, int64_t count) {if (!IsInitialized()) {LOG_WARN("Counter metrics isn't initialized");return false;}if (count <= 0) {LOG_WARN("count is not larger than 0. count: %s, key: %d", std::to_string(count).c_str(), key);return false;}os::LogMetricBluetoothCodePathCounterMetrics(key, count);return true;
}void CounterMetrics::DrainBufferedCounters() {if (!IsInitialized()) {LOG_WARN("Counter metrics isn't initialized");return ;}std::lock_guard<std::mutex> lock(mutex_);LOG_INFO("Draining buffered counters");for (auto const& pair : counters_) {Count(pair.first, pair.second);}counters_.clear();
}}  // namespace metrics
}  // namespace bluetooth

如果你 看过我之前其他模块的介绍。应该很容易看明白, CounterMetrics 模块对应函数的触发流程。 我这里简单的介绍一下。CounterMetrics模块的作用。

2. CounterMetrics 的功能作用是什么?

该模块主要用于 收集并定期上报蓝牙栈内部的计数型指标(Counter Metrics),其核心职责包括:

功能点解析:

  1. 缓存统计项

    • 使用 CacheCount(int32_t key, int64_t count) 将特定的计数项临时缓存在内存中(如某类事件的触发次数)。
  2. 定时上报

    • 通过 os::RepeatingAlarm 每 6 小时调用 DrainBufferedCounters(),将缓存中的计数上报给系统的 metrics 框架(如 statsd)。
  3. 线程安全

    • 内部通过 std::mutex 锁保护 counters_ map,保证并发场景下的正确性。
  4. 溢出保护

    • 如果某个计数项的总值超出 LLONG_MAX,将其钳制为 LLONG_MAX 并发出警告。

3. 设计该模块的目的是什么?

背后的设计理念:

设计需求说明
低频统计上传某些蓝牙事件(如连接失败次数、重连次数、A2DP 播放错误等)不适合立即上报或日志输出。
延迟处理,降低性能影响延迟上报避免频繁调用 I/O 操作(如写文件、上报 statsd)。
可扩展性强只需新增对应的 key,即可添加新的统计项,无需修改上层逻辑。
帮助调优与问题排查比如分析 Bluetooth 启动失败次数、配对错误数,辅助 Google 收集大数据做产品改进。

4. 如果去掉这个模块会怎样?

  1. 无法延迟上报

    • 每次计数都需要即时上报,性能开销显著增加。
  2. 缺失统计数据

    • 某些只有内部记录但未及时上报的数据将无法收集,影响用户反馈分析与 QA 问题定位。
  3. 不利于数据分析平台接入

    • Google 的 statsd、OEM 的大数据平台等依赖此模块的统一接口上传蓝牙计数指标。

5. 实际应用场景举例(车机)

场景CounterMetrics 的作用
A2DP 播放中断记录播放异常次数,辅助分析车机蓝牙不稳定问题
HFP 通话失败统计通话连接失败次数,用于判断兼容性问题
蓝牙重启频率如果蓝牙频繁崩溃,CounterMetrics 可以记录频率帮助开发定位根因
配对异常统计不同品牌手机配对失败的频率,为白名单机制提供数据

6. 总结

项目内容
模块名称CounterMetrics
主要功能缓存并定期上报蓝牙内部计数数据
设计意义降低性能开销、支持延迟上报、提高调试能力
可否去除不能,否则将严重影响日志分析、问题定位及大数据支持能力

PS:
车机/手机 中 如果要对蓝牙服务 埋点, 诊断等。 其实可以结合这个模块来添加。

http://www.xdnf.cn/news/5760.html

相关文章:

  • 继承关系下创建对象的具体流程
  • 生活破破烂烂,AI 缝缝补补(附提示词)
  • 进程间的通信
  • python-75-Nacos技术之Python+Nacos实现微服务架构
  • 打破效率枷锁,数企云外呼一骑绝尘
  • beyond compare 免密钥进入使用(删除注册表)
  • MacOS 上构建 gem5
  • 排错-harbor-db容器异常重启
  • PCB抄板过程、抄板软件介绍
  • 基于Qt6 + MuPDF在 Arm IMX6ULL运行的PDF浏览器(项目推介)
  • 做为一个平台,给第三方提供接口的时候,除了要求让他们申请 appId 和 AppSecret 之外,还应当有哪些安全选项,要过等保3级
  • BUUCTF Pwn hitcontraining_uaf WP
  • 学习黑客5分钟深入浅出理解系列之Windows注册表
  • Odoo 18 安全组与访问权限管理指南
  • SQLite 数据库常见问题及解决方法
  • 一般纯软工程学习路径
  • 使用达梦数据库官方管理工具SQLark导入与导出数据库表
  • 解决IDEA无法运行git的问题
  • CVE-2020-1957 漏洞报告
  • 基于MCP的智能体架构设计:实现智能体与外部世界的无缝连接
  • 辣椒青椒幼苗和杂草检测数据集VOC+YOLO格式706张2类别
  • IP协议、以太网包头及UNIX域套接字
  • 在 Java 8 中 常用时间日期类
  • 【Linux系统】自动化构建-make/Makefile的使用
  • AI Agent开发第64课-DIFY和企业现有系统结合实现高可配置的智能零售AI Agent(上)
  • #S4U2SELF#S4U2Proxy#CVE-2021-42278/42287
  • 按指定位置或关键字批量删除工作表-Excel易用宝
  • 关系实验课--笛卡尔积
  • cURL:通过URL传输数据的命令行工具库介绍
  • 请求参数:Header 参数,Body 参数,Path 参数,Query 参数分别是什么意思,什么样的,分别通过哪个注解获取其中的信息