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),其核心職責包括:
功能點解析:
-
緩存統計項
- 使用
CacheCount(int32_t key, int64_t count)
將特定的計數項臨時緩存在內存中(如某類事件的觸發次數)。
- 使用
-
定時上報
- 通過
os::RepeatingAlarm
每 6 小時調用DrainBufferedCounters()
,將緩存中的計數上報給系統的 metrics 框架(如statsd
)。
- 通過
-
線程安全
- 內部通過
std::mutex
鎖保護counters_
map,保證并發場景下的正確性。
- 內部通過
-
溢出保護
- 如果某個計數項的總值超出
LLONG_MAX
,將其鉗制為LLONG_MAX
并發出警告。
- 如果某個計數項的總值超出
3. 設計該模塊的目的是什么?
背后的設計理念:
設計需求 | 說明 |
---|---|
低頻統計上傳 | 某些藍牙事件(如連接失敗次數、重連次數、A2DP 播放錯誤等)不適合立即上報或日志輸出。 |
延遲處理,降低性能影響 | 延遲上報避免頻繁調用 I/O 操作(如寫文件、上報 statsd)。 |
可擴展性強 | 只需新增對應的 key,即可添加新的統計項,無需修改上層邏輯。 |
幫助調優與問題排查 | 比如分析 Bluetooth 啟動失敗次數、配對錯誤數,輔助 Google 收集大數據做產品改進。 |
4. 如果去掉這個模塊會怎樣?
-
無法延遲上報
- 每次計數都需要即時上報,性能開銷顯著增加。
-
缺失統計數據
- 某些只有內部記錄但未及時上報的數據將無法收集,影響用戶反饋分析與 QA 問題定位。
-
不利于數據分析平臺接入
- Google 的
statsd
、OEM 的大數據平臺等依賴此模塊的統一接口上傳藍牙計數指標。
- Google 的
5. 實際應用場景舉例(車機)
場景 | CounterMetrics 的作用 |
---|---|
A2DP 播放中斷 | 記錄播放異常次數,輔助分析車機藍牙不穩定問題 |
HFP 通話失敗 | 統計通話連接失敗次數,用于判斷兼容性問題 |
藍牙重啟頻率 | 如果藍牙頻繁崩潰,CounterMetrics 可以記錄頻率幫助開發定位根因 |
配對異常 | 統計不同品牌手機配對失敗的頻率,為白名單機制提供數據 |
6. 總結
項目 | 內容 |
---|---|
模塊名稱 | CounterMetrics |
主要功能 | 緩存并定期上報藍牙內部計數數據 |
設計意義 | 降低性能開銷、支持延遲上報、提高調試能力 |
可否去除 | 不能,否則將嚴重影響日志分析、問題定位及大數據支持能力 |
PS:
車機/手機 中 如果要對藍牙服務 埋點, 診斷等。 其實可以結合這個模塊來添加。