blob: dbb9a81de82ef8fd54e1c75f18b6f149c73bb3e9 [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "iioservice/daemon/sensor_metrics.h"
#include <algorithm>
#include <memory>
#include <string>
#include <utility>
#include <base/logging.h>
#include <base/stl_util.h>
#include <base/strings/stringprintf.h>
#include <base/strings/string_util.h>
#include <libmems/common_types.h>
#include "iioservice/include/common.h"
namespace iioservice {
namespace {
constexpr base::TimeDelta kMetricsHourlyTimeOnlineSamplePeriod =
base::TimeDelta::FromHours(1);
constexpr int kFrequencyThresholds[] = {0, 10, 50, 100};
// UMA metric names:
// Device Type and Location
constexpr char kSensorUsage[] = "ChromeOS.IioService.SensorUsage.%iHz";
constexpr char kSensorObserver[] = "ChromeOS.IioService.SensorObserver";
constexpr char kSensorObserverOpen[] = "ChromeOS.IioService.SensorObserverOpen";
constexpr char kSensorClientConcurrent[] =
"ChromeOS.IioService.SensorClientConcurrent";
// UMA histogram ranges:
constexpr int kSensorUsageEnumMax =
(static_cast<int>(cros::mojom::DeviceType::kMaxValue) + 1) *
static_cast<int>(SensorMetrics::Location::kMax);
constexpr int kSensorObserverMax = 20;
constexpr int kSensorObserverBuckets = 21;
constexpr int kSensorObserverOpenMax = 100;
constexpr int kSensorObserverOpenBuckets = 50;
constexpr int kSensorClientConcurrentMax = 10;
constexpr int kSensorClientConcurrentBuckets = 11;
bool SensorTypeSupported(cros::mojom::DeviceType type) {
return type != cros::mojom::DeviceType::NONE &&
type <= cros::mojom::DeviceType::kMaxValue;
}
SensorMetrics* g_sensor_metrics = nullptr;
} // namespace
// static
void SensorMetrics::Initialize() {
if (g_sensor_metrics) {
LOGF(WARNING) << "SensorMetrics was already initialized";
return;
}
SetInstance(new SensorMetrics(std::make_unique<MetricsLibrary>()));
}
// static
void SensorMetrics::Shutdown() {
if (!g_sensor_metrics) {
LOGF(WARNING) << "SensorMetrics::Shutdown() called with null metrics";
return;
}
delete g_sensor_metrics;
SetInstance(nullptr);
}
// static
SensorMetrics* SensorMetrics::GetInstance() {
return g_sensor_metrics;
}
SensorMetrics::~SensorMetrics() {
summarize_timer_.Stop();
}
void SensorMetrics::SetConfigForDevice(
int iio_device_id,
const std::vector<cros::mojom::DeviceType>& types,
const std::string& location) {
if (device_configs_.find(iio_device_id) != device_configs_.end()) {
LOGF(WARNING) << "DeviceConfig already set for device with id: "
<< iio_device_id;
return;
}
auto& config = device_configs_[iio_device_id];
config.types = types;
config.location = FilterLocationString(std::string(base::TrimString(
location, base::StringPiece("\0\n", 2), base::TRIM_TRAILING)));
}
void SensorMetrics::SendSensorUsage(int iio_device_id, double frequency) {
DCHECK_GE(frequency, 0.0);
auto it = device_configs_.find(iio_device_id);
if (it == device_configs_.end())
return;
it->second.frequency = frequency;
it->second.max_frequency = std::max(it->second.max_frequency, frequency);
}
void SensorMetrics::SendSensorObserverOpened() {
++enable_sensor_observer_counter_;
++sensor_observer_counter_;
max_sensor_observer_counter_ =
std::max(max_sensor_observer_counter_, sensor_observer_counter_);
}
void SensorMetrics::SendSensorObserverClosed() {
DCHECK_GT(sensor_observer_counter_, 0);
--sensor_observer_counter_;
}
void SensorMetrics::SendSensorClientConnected() {
++sensor_client_counter_;
max_sensor_client_counter_ =
std::max(max_sensor_client_counter_, sensor_client_counter_);
}
void SensorMetrics::SendSensorClientDisconnected() {
DCHECK_GT(sensor_client_counter_, 0);
--sensor_client_counter_;
}
// static
void SensorMetrics::SetInstance(SensorMetrics* sensor_metrics) {
g_sensor_metrics = sensor_metrics;
}
SensorMetrics::SensorMetrics(
std::unique_ptr<MetricsLibraryInterface> metrics_lib)
: metrics_lib_(std::move(metrics_lib)) {
summarize_timer_.Start(FROM_HERE, kMetricsHourlyTimeOnlineSamplePeriod,
base::BindRepeating(&SensorMetrics::SummarizeTime,
base::Unretained(this)));
}
SensorMetrics::Location SensorMetrics::FilterLocationString(
std::string location) {
if (location == cros::mojom::kLocationBase)
return Location::kBase;
if (location == cros::mojom::kLocationLid)
return Location::kLid;
if (location == cros::mojom::kLocationCamera)
return Location::kCamera;
return Location::kOthers;
}
void SensorMetrics::SummarizeTime() {
for (auto& device_config : device_configs_) {
auto& config = device_config.second;
for (auto type : config.types) {
if (!SensorTypeSupported(type))
continue;
int device_enum =
(static_cast<int>(type) - 1) * static_cast<int>(Location::kMax) +
static_cast<int>(config.location);
for (int freq_threshold : kFrequencyThresholds) {
if (config.max_frequency < freq_threshold)
continue;
std::string action_name =
base::StringPrintf(kSensorUsage, freq_threshold);
metrics_lib_->SendEnumToUMA(action_name, device_enum,
kSensorUsageEnumMax);
}
}
config.max_frequency = config.frequency;
}
metrics_lib_->SendToUMA(kSensorObserver, max_sensor_observer_counter_, 1,
kSensorObserverMax, kSensorObserverBuckets);
max_sensor_observer_counter_ = sensor_observer_counter_;
metrics_lib_->SendToUMA(kSensorObserverOpen, enable_sensor_observer_counter_,
1, kSensorObserverOpenMax,
kSensorObserverOpenBuckets);
metrics_lib_->SendToUMA(kSensorClientConcurrent, max_sensor_client_counter_,
1, kSensorClientConcurrentMax,
kSensorClientConcurrentBuckets);
max_sensor_client_counter_ = sensor_client_counter_;
}
} // namespace iioservice