Files
android/libwvdrmengine/cdm/metrics/include/value_metric.h
Alex Dale 08c703a7b8 Added numeric value guards to ValueMetric.
[ Merge of http://go/wvgerrit/137951 ]

ValueMetric was not checking whether certain unsigned types will
overflow when casted to protobuf's signed int64 type.  This CL
adds a max value to prevent potential overflows.

The value metric has also been updated to an emum to represent its
possible three state, as opposed to using two boolean flags.  For basic
value metrics, this saves about 4 bytes of space.  This works out to
being ~100 bytes per crypto session, ~20 bytes per CDM session and ~20
bytes per engine metrics.

Bug: 204946540
Test: Metric unit tests
Change-Id: I688bece8f31cccaf2a25bd8f99d9b080b0efd0de
2021-11-08 14:52:29 -08:00

118 lines
3.3 KiB
C++

// Copyright 2017 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// This file contains the declarations for the Metric class and related
// types.
#ifndef WVCDM_METRICS_VALUE_METRIC_H_
#define WVCDM_METRICS_VALUE_METRIC_H_
#include <stdint.h>
#include <mutex>
#include <string>
#include "wv_metrics.pb.h"
namespace wvcdm {
namespace metrics {
namespace internal {
// Helper function for setting a value in the proto.
template <typename T>
void SetValue(drm_metrics::ValueMetric* value_proto, const T& value);
} // namespace internal
// The ValueMetric class supports storing a single, overwritable value or an
// error code. This class can be serialized to a drm_metrics::ValueMetric proto.
// If an error or value was not provided, this metric will serialize to nullptr.
//
// Example Usage:
// ValueMetric<string> cdm_version().Record("a.b.c.d");
// std::unique_ptr<drm_metrics::ValueMetric> mymetric(
// cdm_version.ToProto());
//
// Example Error Usage:
//
// ValueMetric<string> cdm_version().SetError(error_code);
// std::unique_ptr<drm_metrics::ValueMetric> mymetric(
// cdm_version.ToProto());
//
template <typename T>
class ValueMetric {
public:
ValueMetric() {}
// Record the value of the metric.
void Record(const T& value) {
std::unique_lock<std::mutex> lock(mutex_);
value_ = value;
state_ = kHasValue;
}
// Set the error code if an error was encountered.
void SetError(int error_code) {
std::unique_lock<std::mutex> lock(mutex_);
error_code_ = error_code;
state_ = kHasError;
}
bool HasValue() const {
std::unique_lock<std::mutex> lock(mutex_);
return state_ == kHasValue;
}
const T& GetValue() const {
std::unique_lock<std::mutex> lock(mutex_);
return value_;
}
bool HasError() const {
std::unique_lock<std::mutex> lock(mutex_);
return state_ == kHasError;
}
int GetError() const {
std::unique_lock<std::mutex> lock(mutex_);
return error_code_;
}
// Clears the indicators that the metric or error was set.
void Clear() {
std::unique_lock<std::mutex> lock(mutex_);
state_ = kNone;
}
// Returns a new ValueMetric proto containing the metric value or the
// error code. If neither the error or value are set, it returns nullptr.
drm_metrics::ValueMetric* ToProto() const {
std::unique_lock<std::mutex> lock(mutex_);
switch (state_) {
case kHasValue: {
drm_metrics::ValueMetric* value_proto = new drm_metrics::ValueMetric;
internal::SetValue(value_proto, value_);
return value_proto;
}
case kHasError: {
drm_metrics::ValueMetric* value_proto = new drm_metrics::ValueMetric;
value_proto->set_error_code(error_code_);
return value_proto;
}
case kNone:
default:
return nullptr;
}
}
private:
enum ValueState { kNone, kHasValue, kHasError };
T value_;
int error_code_ = 0;
ValueState state_ = kNone;
// This locks the internal state of the value metric to ensure safety
// across multiple threads preventing the caller from worrying about
// locking.
mutable std::mutex mutex_;
};
} // namespace metrics
} // namespace wvcdm
#endif // WVCDM_METRICS_VALUE_METRIC_H_