Refactored metrics to support pull model.

MetricsGroup split into 3 groups, session, engine, and crypto.
MetricsFrontEnd and Report removed.

This is a merge from wvgerrit/28420

Bug: 36217927
Test: Added unit tests to cover modified code.
Change-Id: I2f39f99ce88cc2229d6d1aa9459c67c5b86ccef4
This commit is contained in:
Adam Stone
2017-03-29 17:03:43 -07:00
parent 0a5fe1ffad
commit a34e279d0f
22 changed files with 478 additions and 505 deletions

View File

@@ -12,6 +12,7 @@
#include "file_store.h"
#include "initialization_data.h"
#include "lock.h"
#include "metrics_collections.h"
#include "oemcrypto_adapter.h"
#include "scoped_ptr.h"
#include "timer_metric.h"
@@ -241,7 +242,7 @@ class CdmEngine {
// dead lock.
virtual void OnTimerEvent();
virtual metrics::MetricsGroup* GetMetrics() { return &metrics_; }
virtual metrics::EngineMetrics* GetMetrics() { return &metrics_; }
private:
// private methods
@@ -273,7 +274,7 @@ class CdmEngine {
* ensure that all data has been properly recorded in the group before
* it is published.
*/
metrics::MetricsGroup metrics_;
metrics::EngineMetrics metrics_;
metrics::TimerMetric life_span_;
CdmSessionMap sessions_;

View File

@@ -12,7 +12,7 @@
#include "file_store.h"
#include "initialization_data.h"
#include "license.h"
#include "metrics_group.h"
#include "metrics_collections.h"
#include "oemcrypto_adapter.h"
#include "policy_engine.h"
#include "scoped_ptr.h"
@@ -27,10 +27,24 @@ class UsageTableHeader;
class CdmSession {
public:
CdmSession(FileSystem* file_system);
// Creates a new instance of the CdmSession with the given |file_system|
// and |metrics| parameters. Both parameters are owned by the caller and
// must remain in scope througout the scope of the new instance.
CdmSession(FileSystem* file_system, metrics::SessionMetrics* metrics);
virtual ~CdmSession();
// Initializes this instance of CdmSession with the given property set.
// |cdm_client_property_set| MAY be null, is owned by the caller,
// and must remain in scope throughout the scope of this session.
virtual CdmResponseType Init(CdmClientPropertySet* cdm_client_property_set);
// Initializes this instance of CdmSession with the given parmeters.
// All parameters are owned by the caller.
// |cdm_client_property_set| is caller owned, may be null, but must be
// in scope as long as the session is in scope.
// |forced_session_id| is caller owned and may be null.
// |event_listener| is caller owned, may be null, but must be in scope
// as long as the session is in scope.
virtual CdmResponseType Init(CdmClientPropertySet* cdm_client_property_set,
const CdmSessionId* forced_session_id,
WvCdmEventListener* event_listener);
@@ -166,7 +180,7 @@ class CdmSession {
CdmSigningAlgorithm algorithm,
const std::string& signature);
virtual metrics::MetricsGroup* GetMetrics() { return &metrics_; }
virtual metrics::SessionMetrics* GetMetrics() { return metrics_; }
private:
friend class CdmSessionTest;
@@ -185,19 +199,13 @@ class CdmSession {
void set_file_handle(DeviceFiles* file_handle);
// instance variables
/*
* The metrics group must be the first variable declared to ensure
* that it is the last member destroyed so that no child members
* try to use a reference to it after it is destroyed. This will
* ensure that all data has been properly recorded in the group before
* it is published.
*/
metrics::MetricsGroup metrics_;
metrics::SessionMetrics* metrics_;
metrics::CryptoMetrics* crypto_metrics_;
metrics::TimerMetric life_span_;
bool initialized_;
CdmSessionId session_id_;
FileSystem* file_system_;
scoped_ptr<CdmLicense> license_parser_;
scoped_ptr<CryptoSession> crypto_session_;
scoped_ptr<PolicyEngine> policy_engine_;

View File

@@ -6,7 +6,7 @@
#include <string>
#include "crypto_session.h"
#include "metrics_group.h"
#include "metrics_collections.h"
#include "oemcrypto_adapter.h"
#include "service_certificate.h"
#include "wv_cdm_types.h"
@@ -18,7 +18,7 @@ class FileSystem;
class CertificateProvisioning {
public:
CertificateProvisioning(metrics::MetricsGroup* metrics) :
CertificateProvisioning(metrics::CryptoMetrics* metrics) :
crypto_session_(metrics),
cert_type_(kCertificateWidevine),
service_certificate_(NULL) {};

View File

@@ -9,7 +9,7 @@
#include "OEMCryptoCENC.h"
#include "lock.h"
#include "metrics_group.h"
#include "metrics_collections.h"
#include "oemcrypto_adapter.h"
#include "timer_metric.h"
#include "wv_cdm_types.h"
@@ -36,7 +36,10 @@ class CryptoSession {
bool rsa_cast;
};
CryptoSession(metrics::MetricsGroup* metrics);
// Creates an instance of CryptoSession with the given |crypto_metrics|.
// |crypto_metrics| is owned by the caller, must NOT be null, and must
// exist as long as the new CryptoSession exists.
CryptoSession(metrics::CryptoMetrics* crypto_metrics);
virtual ~CryptoSession();
virtual bool GetClientToken(std::string* client_token);
@@ -206,7 +209,7 @@ class CryptoSession {
static bool initialized_;
static int session_count_;
metrics::MetricsGroup* metrics_;
metrics::CryptoMetrics* metrics_;
metrics::TimerMetric life_span_;
bool open_;

View File

@@ -9,7 +9,7 @@
#include "device_files.h"
#include "file_store.h"
#include "lock.h"
#include "metrics_group.h"
#include "metrics_collections.h"
#include "scoped_ptr.h"
#include "wv_cdm_types.h"
@@ -66,29 +66,29 @@ class UsageTableHeader {
// should not be in use by any open CryptoSession objects when calls
// to DeleteEntry and MoveEntry are made.
CdmResponseType DeleteEntry(uint32_t usage_entry_number, DeviceFiles* handle,
metrics::MetricsGroup* metrics);
metrics::CryptoMetrics* metrics);
private:
CdmResponseType MoveEntry(uint32_t from /* usage entry number */,
const CdmUsageEntry& from_usage_entry,
uint32_t to /* usage entry number */,
DeviceFiles* handle,
metrics::MetricsGroup* metrics);
metrics::CryptoMetrics* metrics);
CdmResponseType GetEntry(uint32_t usage_entry_number, DeviceFiles* handle,
CdmUsageEntry* usage_entry);
CdmResponseType StoreEntry(uint32_t usage_entry_number, DeviceFiles* handle,
const CdmUsageEntry& usage_entry);
CdmResponseType Shrink(metrics::MetricsGroup* metrics,
CdmResponseType Shrink(metrics::CryptoMetrics* metrics,
uint32_t number_of_usage_entries_to_delete);
CdmResponseType UpgradeFromUsageTable(DeviceFiles* handle,
metrics::MetricsGroup* metrics);
metrics::CryptoMetrics* metrics);
bool UpgradeLicensesFromUsageTable(DeviceFiles* handle,
metrics::MetricsGroup* metrics);
metrics::CryptoMetrics* metrics);
bool UpgradeUsageInfoFromUsageTable(DeviceFiles* handle,
metrics::MetricsGroup* metrics);
metrics::CryptoMetrics* metrics);
virtual bool is_inited() { return is_inited_; }

View File

@@ -14,7 +14,6 @@
#include "file_store.h"
#include "license_protocol.pb.h"
#include "log.h"
#include "metrics_front_end.h"
#include "properties.h"
#include "string_conversions.h"
#include "wv_cdm_constants.h"
@@ -130,7 +129,8 @@ CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
CloseExpiredReleaseSessions();
scoped_ptr<CdmSession> new_session(new CdmSession(file_system_));
scoped_ptr<CdmSession> new_session(new CdmSession(file_system_,
metrics_.AddSession()));
CdmResponseType sts = new_session->Init(property_set, forced_session_id,
event_listener);
if (sts != NO_ERROR) {
@@ -498,13 +498,13 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
const std::string& query_token,
std::string* query_response) {
LOGI("CdmEngine::QueryStatus");
CryptoSession crypto_session(&metrics_);
CryptoSession crypto_session(metrics_.GetCryptoMetrics());
if (security_level == kLevel3) {
CdmResponseType status;
M_TIME(
status = crypto_session.Open(
kLevel3),
&metrics_,
metrics_.GetCryptoMetrics(),
crypto_session_open_,
status,
kLevel3);
@@ -520,7 +520,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
CdmSecurityLevel security_level;
M_TIME(
security_level = crypto_session.GetSecurityLevel(),
&metrics_,
metrics_.GetCryptoMetrics(),
crypto_session_get_security_level_,
security_level);
switch (security_level) {
@@ -548,7 +548,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
M_TIME(
got_id = crypto_session.GetExternalDeviceUniqueId(
&deviceId),
&metrics_,
metrics_.GetCryptoMetrics(),
crypto_session_get_device_unique_id_,
got_id);
if (!got_id) {
@@ -563,7 +563,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
M_TIME(
got_id = crypto_session.GetSystemId(
&system_id),
&metrics_,
metrics_.GetCryptoMetrics(),
crypto_session_get_system_id_,
got_id,
system_id);
@@ -600,7 +600,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
M_TIME(
got_info = crypto_session.UsageInformationSupport(
&supports_usage_reporting),
&metrics_,
metrics_.GetCryptoMetrics(),
crypto_session_usage_information_support_,
got_info);
if (!got_info) {
@@ -782,7 +782,8 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
DeleteAllUsageReportsUponFactoryReset();
if (NULL == cert_provisioning_.get()) {
cert_provisioning_.reset(new CertificateProvisioning(&metrics_));
cert_provisioning_.reset(
new CertificateProvisioning(metrics_.GetCryptoMetrics()));
}
CdmResponseType ret = cert_provisioning_->GetProvisioningRequest(
cert_provisioning_requested_security_level_, cert_type, cert_authority,
@@ -824,12 +825,12 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
if (NULL == cert_provisioning_.get()) {
// Certificate provisioning object has been released. Check if a concurrent
// provisioning attempt has succeeded before declaring failure.
CryptoSession crypto_session(&metrics_);
CryptoSession crypto_session(metrics_.GetCryptoMetrics());
CdmResponseType status;
M_TIME(
status = crypto_session.Open(
cert_provisioning_requested_security_level_),
&metrics_,
metrics_.GetCryptoMetrics(),
crypto_session_open_,
status,
cert_provisioning_requested_security_level_);
@@ -842,7 +843,7 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
CdmSecurityLevel security_level;
M_TIME(
security_level = crypto_session.GetSecurityLevel(),
&metrics_,
metrics_.GetCryptoMetrics(),
crypto_session_get_security_level_,
security_level);
if (!IsProvisioned(security_level)) {
@@ -892,14 +893,14 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
return UNPROVISION_ERROR_3;
}
CryptoSession crypto_session(&metrics_);
CryptoSession crypto_session(metrics_.GetCryptoMetrics());
CdmResponseType status;
M_TIME(
status = crypto_session.Open(
security_level == kSecurityLevelL3 ?
kLevel3 :
kLevelDefault),
&metrics_,
metrics_.GetCryptoMetrics(),
crypto_session_open_,
status,
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
@@ -909,7 +910,7 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
}
M_TIME(
status = crypto_session.DeleteAllUsageReports(),
&metrics_,
metrics_.GetCryptoMetrics(),
crypto_session_delete_all_usage_reports_,
status);
if (status != NO_ERROR) {
@@ -948,7 +949,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
}
usage_property_set_->set_security_level(kLevelDefault);
usage_property_set_->set_app_id(app_id);
usage_session_.reset(new CdmSession(file_system_));
usage_session_.reset(new CdmSession(file_system_, metrics_.AddSession()));
CdmResponseType status = usage_session_->Init(usage_property_set_.get());
if (NO_ERROR != status) {
LOGE("CdmEngine::GetUsageInfo: session init error: %d", status);
@@ -968,7 +969,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
ssid, &usage_data)) {
usage_property_set_->set_security_level(kLevel3);
usage_property_set_->set_app_id(app_id);
usage_session_.reset(new CdmSession(file_system_));
usage_session_.reset(new CdmSession(file_system_, metrics_.AddSession()));
status = usage_session_->Init(usage_property_set_.get());
if (NO_ERROR != status) {
LOGE("CdmEngine::GetUsageInfo: session init error");
@@ -1042,7 +1043,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
usage_property_set_->set_security_level(requested_security_level);
usage_property_set_->set_app_id(app_id);
usage_session_.reset(new CdmSession(file_system_));
usage_session_.reset(new CdmSession(file_system_, metrics_.AddSession()));
CdmResponseType status = usage_session_->Init(usage_property_set_.get());
if (NO_ERROR != status) {
@@ -1120,7 +1121,8 @@ CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) {
? kLevel3
: kLevelDefault;
usage_property_set_->set_security_level(security_level);
usage_session_.reset(new CdmSession(file_system_));
usage_session_.reset(
new CdmSession(file_system_, metrics_.AddSession()));
usage_session_->Init(usage_property_set_.get());
if (usage_session_->get_usage_support_type() == kUsageEntrySupport) {
@@ -1544,19 +1546,20 @@ void CdmEngine::DeleteAllUsageReportsUponFactoryReset() {
if (!file_system_->Exists(device_base_path_level1) &&
!file_system_->Exists(device_base_path_level3)) {
scoped_ptr<CryptoSession> crypto_session(new CryptoSession(&metrics_));
scoped_ptr<CryptoSession> crypto_session(
new CryptoSession(metrics_.GetCryptoMetrics()));
CdmResponseType status;
M_TIME(
status = crypto_session->Open(
cert_provisioning_requested_security_level_),
&metrics_,
metrics_.GetCryptoMetrics(),
crypto_session_open_,
status,
cert_provisioning_requested_security_level_);
if (NO_ERROR == status) {
M_TIME(
status = crypto_session->DeleteAllUsageReports(),
&metrics_,
metrics_.GetCryptoMetrics(),
crypto_session_delete_all_usage_reports_,
status);
if (NO_ERROR != status) {

View File

@@ -12,7 +12,6 @@
#include "clock.h"
#include "file_store.h"
#include "log.h"
#include "metrics_front_end.h"
#include "properties.h"
#include "string_conversions.h"
#include "wv_cdm_constants.h"
@@ -25,9 +24,10 @@ const size_t kKeySetIdLength = 14;
namespace wvcdm {
CdmSession::CdmSession(FileSystem* file_system) :
CdmSession::CdmSession(FileSystem* file_system,
metrics::SessionMetrics* metrics) :
metrics_(metrics),
initialized_(false),
crypto_session_(new CryptoSession(&metrics_)),
file_handle_(new DeviceFiles(file_system)),
license_received_(false),
is_offline_(false),
@@ -44,6 +44,9 @@ CdmSession::CdmSession(FileSystem* file_system) :
usage_entry_number_(0),
mock_license_parser_in_use_(false),
mock_policy_engine_in_use_(false) {
// If metrics was not provided, then use a NULL CryptoMetrics instance, too.
crypto_metrics_ = metrics_ == NULL ? NULL : metrics_->GetCryptoMetrics();
crypto_session_.reset(new CryptoSession(crypto_metrics_));
life_span_.Start();
}
@@ -54,7 +57,10 @@ CdmSession::~CdmSession() {
}
Properties::RemoveSessionPropertySet(session_id_);
M_RECORD(&metrics_, cdm_session_life_span_, life_span_.AsMs());
if (metrics_) {
M_RECORD(metrics_, cdm_session_life_span_, life_span_.AsMs());
metrics_->SetCompleted();
}
}
CdmResponseType CdmSession::Init(
@@ -78,16 +84,15 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
}
CdmResponseType sts;
M_TIME(
sts = crypto_session_->Open(
requested_security_level_),
&metrics_,
sts = crypto_session_->Open(requested_security_level_),
crypto_metrics_,
crypto_session_open_,
sts,
requested_security_level_);
if (NO_ERROR != sts) return sts;
M_TIME(
security_level_ = crypto_session_->GetSecurityLevel(),
&metrics_,
crypto_metrics_,
crypto_session_get_security_level_,
security_level_);
if (!file_handle_->Init(security_level_)) {
@@ -121,7 +126,7 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
M_TIME(
get_client_token_sts = crypto_session_->GetClientToken(
&client_token),
&metrics_,
crypto_metrics_,
crypto_session_get_token_,
get_client_token_sts);
if (!get_client_token_sts) {
@@ -138,7 +143,7 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
M_TIME(
load_cert_sts = crypto_session_->LoadCertificatePrivateKey(
wrapped_key),
&metrics_,
crypto_metrics_,
crypto_session_load_certificate_private_key_,
load_cert_sts);
if(!load_cert_sts) {
@@ -157,6 +162,7 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
session_id_ =
Properties::AlwaysUseKeySetIds() ? key_set_id_ : GenerateSessionId();
metrics_->SetSessionId(session_id_);
if (session_id_.empty()) {
LOGE("CdmSession::Init: empty session ID");
@@ -454,7 +460,8 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response) {
if (sts != KEY_ADDED) {
CdmResponseType sts =
usage_table_header_->DeleteEntry(usage_entry_number_,
file_handle_.get(), &metrics_);
file_handle_.get(),
crypto_metrics_);
if (sts != NO_ERROR) {
LOGW("CdmSession::AddKey: Delete usage entry failed = %d", sts);
}
@@ -687,10 +694,10 @@ CdmResponseType CdmSession::DeleteUsageEntry(uint32_t usage_entry_number) {
// it, so close and reopen session.
CdmResponseType sts;
crypto_session_->Close();
crypto_session_.reset(new CryptoSession(&metrics_));
crypto_session_.reset(new CryptoSession(crypto_metrics_));
M_TIME(
sts = crypto_session_->Open(requested_security_level_),
&metrics_,
crypto_metrics_,
crypto_session_open_,
sts,
requested_security_level_);
@@ -711,7 +718,7 @@ CdmResponseType CdmSession::DeleteUsageEntry(uint32_t usage_entry_number) {
return usage_table_header_->DeleteEntry(usage_entry_number,
file_handle_.get(),
&metrics_);
crypto_metrics_);
}
bool CdmSession::IsKeyLoaded(const KeyId& key_id) {
@@ -861,7 +868,7 @@ CdmResponseType CdmSession::DeleteMultipleUsageInformation(
M_TIME(
sts = crypto_session_->DeleteMultipleUsageInformation(
provider_session_tokens),
&metrics_,
crypto_metrics_,
crypto_session_delete_multiple_usage_information_,
sts);
return sts;
@@ -871,7 +878,7 @@ CdmResponseType CdmSession::UpdateUsageTableInformation() {
CdmResponseType sts;
M_TIME(
sts = crypto_session_->UpdateUsageInformation(),
&metrics_,
crypto_metrics_,
crypto_session_update_usage_information_,
sts);
return sts;
@@ -917,7 +924,7 @@ CdmResponseType CdmSession::GenericEncrypt(const std::string& in_buffer,
iv,
algorithm,
out_buffer),
&metrics_,
crypto_metrics_,
crypto_session_generic_encrypt_,
sts,
metrics::Pow2Bucket(in_buffer.size()),
@@ -942,7 +949,7 @@ CdmResponseType CdmSession::GenericDecrypt(const std::string& in_buffer,
iv,
algorithm,
out_buffer),
&metrics_,
crypto_metrics_,
crypto_session_generic_decrypt_,
sts,
metrics::Pow2Bucket(in_buffer.size()),
@@ -965,7 +972,7 @@ CdmResponseType CdmSession::GenericSign(const std::string& message,
key_id,
algorithm,
signature),
&metrics_,
crypto_metrics_,
crypto_session_generic_sign_,
sts,
metrics::Pow2Bucket(message.size()),
@@ -984,7 +991,7 @@ CdmResponseType CdmSession::GenericVerify(const std::string& message,
key_id,
algorithm,
signature),
&metrics_,
crypto_metrics_,
crypto_session_generic_verify_,
sts,
metrics::Pow2Bucket(message.size()),

View File

@@ -12,7 +12,6 @@
#include "crypto_key.h"
#include "log.h"
#include "metrics_front_end.h"
#include "openssl/sha.h"
#include "properties.h"
#include "pst_report.h"
@@ -45,7 +44,7 @@ uint64_t CryptoSession::request_id_index_ = 0;
UsageTableHeader* CryptoSession::usage_table_header_l1_ = NULL;
UsageTableHeader* CryptoSession::usage_table_header_l3_ = NULL;
CryptoSession::CryptoSession(metrics::MetricsGroup* metrics)
CryptoSession::CryptoSession(metrics::CryptoMetrics* metrics)
: metrics_(metrics),
open_(false),
update_usage_table_after_close_session_(false),

View File

@@ -29,8 +29,7 @@
#include "level3.h"
#include "lock.h"
#include "log.h"
#include "metrics_front_end.h"
#include "metrics_group.h"
#include "metrics_collections.h"
#include "properties.h"
#include "wv_cdm_constants.h"
@@ -425,8 +424,12 @@ class Adapter {
* To avoid changing the function signature and function contract - declare
* a one-off metrics group to collect detailed information about how
* oemcrypto was intialized.
*
* TODO(blueeyes): Refactor this to allow Initialize to provide the
* details to the caller or to use the metrics instance provided by
* the caller.
*/
wvcdm::metrics::MetricsGroup metrics;
wvcdm::metrics::CryptoMetrics metrics;
level1_ = FunctionPointers(); // start with all null pointers.
level3_ = FunctionPointers(); // start with all null pointers.
@@ -474,7 +477,7 @@ class Adapter {
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_L1_OPEN_FAILED);
return result;
}
if (LoadLevel1(metrics)) {
if (LoadLevel1(&metrics)) {
LOGD("OEMCrypto_Initialize Level 1 success. I will use level 1.");
} else {
level1_ = FunctionPointers(); // revert to all null pointers.
@@ -485,7 +488,7 @@ class Adapter {
return result;
}
bool LoadLevel1(wvcdm::metrics::MetricsGroup& metrics) {
bool LoadLevel1(wvcdm::metrics::CryptoMetrics* metrics) {
level1_valid_ = true;
const uint32_t kMinimumVersion = 8;
const uint32_t kMaximumVersion = 13;
@@ -495,7 +498,7 @@ class Adapter {
LOOKUP_ALL(8, Terminate, OEMCrypto_Terminate);
if (!level1_valid_) {
M_RECORD(
&metrics,
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_INVALID_L1);
@@ -505,7 +508,7 @@ class Adapter {
if (st != OEMCrypto_SUCCESS) {
LOGW("Could not initialize L1. Falling Back to L3.");
M_RECORD(
&metrics,
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_INITIALIZE_L1);
@@ -513,7 +516,7 @@ class Adapter {
}
level1_.version = level1_.APIVersion();
M_RECORD(
&metrics,
metrics,
oemcrypto_l1_api_version_,
NO_TIME,
level1_.version,
@@ -522,7 +525,7 @@ class Adapter {
LOGW("liboemcrypto.so is version %d, not %d. Falling Back to L3.",
level1_.version, kMinimumVersion);
M_RECORD(
&metrics,
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_WRONG_L1_VERSION);
@@ -600,7 +603,7 @@ class Adapter {
// If we have a valid keybox, initialization is done. We're good.
if (OEMCrypto_SUCCESS == level1_.IsKeyboxValid()) {
M_RECORD(
&metrics,
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L1_WITH_KEYBOX);
@@ -612,7 +615,7 @@ class Adapter {
if (level1_.version > 11 &&
(level1_.GetProvisioningMethod() == OEMCrypto_OEMCertificate)) {
M_RECORD(
&metrics,
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L1_WITH_PROVISIONING_3_0);
@@ -632,13 +635,13 @@ class Adapter {
LOGE("OEMCrypto uses cert as identification, but cdm does not!");
LOGE("This will not work on a production device.");
M_RECORD(
&metrics,
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L1_CERTIFICATE_MIX);
} else {
M_RECORD(
&metrics,
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L1_WITH_CERTIFICATE);
@@ -651,7 +654,7 @@ class Adapter {
LOGW("Bad Level 1 Keybox. Falling Back to L3.");
level1_.Terminate();
M_RECORD(
&metrics,
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_BAD_KEYBOX);
@@ -663,7 +666,7 @@ class Adapter {
LOGW("Could not open %s. Falling Back to L3.", filename.c_str());
level1_.Terminate();
M_RECORD(
&metrics,
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_OPEN_FACTORY_KEYBOX);
@@ -677,7 +680,7 @@ class Adapter {
filename.c_str());
level1_.Terminate();
M_RECORD(
&metrics,
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_INSTALL_KEYBOX);
@@ -685,7 +688,7 @@ class Adapter {
}
LOGI("Installed keybox from %s", filename.c_str());
M_RECORD(
&metrics,
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L1_INSTALLED_KEYBOX);

View File

@@ -5,7 +5,6 @@
#include "crypto_session.h"
#include "license.h"
#include "log.h"
#include "metrics_group.h"
namespace {
std::string kEmptyString;
@@ -140,7 +139,7 @@ CdmResponseType UsageTableHeader::UpdateEntry(CryptoSession* crypto_session,
CdmResponseType UsageTableHeader::DeleteEntry(uint32_t usage_entry_number,
DeviceFiles* handle,
metrics::MetricsGroup* metrics) {
metrics::CryptoMetrics* metrics) {
LOGV("UsageTableHeader::DeleteEntry: Lock");
AutoLock auto_lock(usage_table_header_lock_);
if (usage_entry_number >= usage_entry_info_.size())
@@ -189,14 +188,13 @@ CdmResponseType UsageTableHeader::DeleteEntry(uint32_t usage_entry_number,
number_of_entries_to_be_deleted =
usage_entry_info_.size() - swap_entry_number;
}
return Shrink(metrics, number_of_entries_to_be_deleted);
}
CdmResponseType UsageTableHeader::MoveEntry(
uint32_t from_usage_entry_number, const CdmUsageEntry& from_usage_entry,
uint32_t to_usage_entry_number, DeviceFiles* handle,
metrics::MetricsGroup* metrics) {
metrics::CryptoMetrics* metrics) {
LOGV("UsageTableHeader::MoveEntry");
// crypto_session points to an object whose scope is this method or a test
@@ -373,7 +371,7 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number,
}
CdmResponseType UsageTableHeader::Shrink(
metrics::MetricsGroup* metrics,
metrics::CryptoMetrics* metrics,
uint32_t number_of_usage_entries_to_delete) {
if (usage_entry_info_.empty()) {
LOGE("UsageTableHeader::Shrink: usage entry info table unexpectedly empty");
@@ -414,14 +412,14 @@ CdmResponseType UsageTableHeader::Shrink(
}
CdmResponseType UsageTableHeader::UpgradeFromUsageTable(
DeviceFiles* handle, metrics::MetricsGroup* metrics) {
DeviceFiles* handle, metrics::CryptoMetrics* metrics) {
UpgradeLicensesFromUsageTable(handle, metrics);
UpgradeUsageInfoFromUsageTable(handle, metrics);
return NO_ERROR;
}
bool UsageTableHeader::UpgradeLicensesFromUsageTable(
DeviceFiles* handle, metrics::MetricsGroup* metrics) {
DeviceFiles* handle, metrics::CryptoMetrics* metrics) {
// Fetch the key set IDs for each offline license. For each license
// * retrieve the provider session token,
// * create a new usage entry
@@ -510,7 +508,7 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable(
}
bool UsageTableHeader::UpgradeUsageInfoFromUsageTable(
DeviceFiles* handle, metrics::MetricsGroup* metrics) {
DeviceFiles* handle, metrics::CryptoMetrics* metrics) {
// Fetch all usage files. For each file retrieve all the usage info records
// within the file. For each piece of usage information
// * create a new usage entry

View File

@@ -139,7 +139,7 @@ using ::testing::StrEq;
class CdmSessionTest : public ::testing::Test {
protected:
virtual void SetUp() {
cdm_session_.reset(new CdmSession(NULL));
cdm_session_.reset(new CdmSession(NULL, &metrics_));
// Inject testing mocks.
license_parser_ = new MockCdmLicense(cdm_session_->session_id());
cdm_session_->set_license_parser(license_parser_);
@@ -151,6 +151,13 @@ class CdmSessionTest : public ::testing::Test {
cdm_session_->set_file_handle(file_handle_);
}
virtual void TearDown() {
// Force the cdm_session_ to be deleted. This enforces a requirement that
// the CDM session metrics exist at least as long as the CDM session.
cdm_session_.reset();
}
metrics::SessionMetrics metrics_;
scoped_ptr<CdmSession> cdm_session_;
MockCdmLicense* license_parser_;
MockCryptoSession* crypto_session_;

View File

@@ -395,7 +395,7 @@ TEST_F(UsageTableHeaderTest, UpdateEntry) {
TEST_F(UsageTableHeaderTest, DeleteEntry_InvalidUsageEntryNumber) {
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
uint32_t usage_entry_number = kUsageEntryInfoVector.size();
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
EXPECT_NE(NO_ERROR, usage_table_header_->DeleteEntry(
usage_entry_number, device_files_, &metrics));
@@ -426,7 +426,7 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_CryptoSessionError) {
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 1; // kUsageEntryInfoOfflineLicense2
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(
@@ -462,7 +462,7 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastOfflineEntry) {
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 1; // kUsageEntryInfoOfflineLicense2
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(
@@ -507,7 +507,7 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastSecureStopEntry) {
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 1; // kUsageEntryInfoSecureStop2
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(
@@ -558,7 +558,7 @@ TEST_F(UsageTableHeaderTest,
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense1
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
device_files_->DeleteAllLicenses();
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
@@ -608,7 +608,7 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastSecureStopEntriesAreMissing) {
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoSecureStop1
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(
@@ -671,7 +671,7 @@ TEST_F(UsageTableHeaderTest,
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense1
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
EXPECT_TRUE(device_files_->StoreLicense(
usage_entry_info_vector[usage_entry_info_vector.size() - 1].key_set_id,
@@ -739,7 +739,7 @@ TEST_F(UsageTableHeaderTest,
usage_entry_info_vector.size() - 3; // kUsageEntryInfoSecureStop1
uint32_t usage_entry_number_after_deleted_entry =
usage_entry_number_to_be_deleted + 1;
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(
@@ -812,7 +812,7 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreStorageTypeUnknown) {
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense3
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(
@@ -867,7 +867,7 @@ TEST_F(UsageTableHeaderTest,
usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense1
uint32_t last_usage_entry_number =
usage_entry_info_vector.size() - 1; // kUsageEntryInfoOfflineLicense3
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
EXPECT_TRUE(device_files_->StoreLicense(
usage_entry_info_vector[last_usage_entry_number].key_set_id,
@@ -933,7 +933,7 @@ TEST_F(UsageTableHeaderTest,
usage_entry_info_vector.size() - 3; // kUsageEntryInfoSecureStop1
uint32_t last_usage_entry_number =
usage_entry_info_vector.size() - 1; // kUsageEntryInfoSecureStop3
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(*crypto_session_,
@@ -1007,7 +1007,7 @@ TEST_F(UsageTableHeaderTest,
usage_entry_info_vector.size() - 5; // kUsageEntryInfoOfflineLicense1
uint32_t last_valid_usage_entry_number =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense3
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
EXPECT_TRUE(device_files_->StoreLicense(
usage_entry_info_vector[last_valid_usage_entry_number].key_set_id,
@@ -1085,7 +1085,7 @@ TEST_F(UsageTableHeaderTest,
usage_entry_info_vector.size() - 5; // kUsageEntryInfoOfflineLicense1
uint32_t last_valid_usage_entry_number =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense3
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault))
.Times(2)
@@ -1157,7 +1157,7 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntryIsOffline) {
usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense1
uint32_t last_usage_entry_number =
usage_entry_info_vector.size() - 1; // kUsageEntryInfoOfflineLicense3
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
EXPECT_TRUE(device_files_->StoreLicense(
usage_entry_info_vector[last_usage_entry_number].key_set_id,
@@ -1271,7 +1271,7 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntryIsSecureStop) {
usage_entry_info_vector.size() - 3; // kUsageEntryInfoSecureStop1
uint32_t last_usage_entry_number =
usage_entry_info_vector.size() - 1; // kUsageEntryInfoSecureStop3
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault))
.Times(2)
@@ -1371,7 +1371,7 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreOfflineAndUnknknown) {
usage_entry_info_vector.size() - 5; // kUsageEntryInfoOfflineLicense1
uint32_t last_valid_usage_entry_number =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense3
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
EXPECT_TRUE(device_files_->StoreLicense(
usage_entry_info_vector[last_valid_usage_entry_number].key_set_id,
@@ -1490,7 +1490,7 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreSecureStopAndUnknknown) {
usage_entry_info_vector.size() - 5; // kUsageEntryInfoSecureStop1
uint32_t last_valid_usage_entry_number =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoSecureStop3
metrics::MetricsGroup metrics;
metrics::CryptoMetrics metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault))
.Times(2)

View File

@@ -18,7 +18,7 @@
#include "lock.h"
#include "distribution.h"
#include "metric_publisher.h"
#include "metric_serialization.h"
namespace wvcdm {
namespace metrics {
@@ -27,11 +27,11 @@ class EventMetricTest;
// This base class provides the common defintion used by all templated
// instances of EventMetric.
class BaseEventMetric : public MetricPublisher {
class BaseEventMetric : public MetricSerializable {
public:
// Publish metric values to the MetricNotification. |subscriber| must
// Send metric values to the MetricSerializer. |serializer| must
// not be null and is owned by the caller.
virtual void Publish(MetricNotification* subscriber);
virtual void Serialize(MetricSerializer* serializer);
protected:
// Instantiates a BaseEventMetric.

View File

@@ -1,46 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// This file contains the declarations for the Metric class and related
// types.
#ifndef WVCDM_METRICS_METRIC_PUBLISHER_H_
#define WVCDM_METRICS_METRIC_PUBLISHER_H_
namespace wvcdm {
namespace metrics {
// The MetricNotification is implemented by the code that instantiates
// MetricPublisher instances. The caller provides this MetricNotification
// instance to MetricPublisher::Publish. In turn, Publish will make a call to
// UpdateMetric for each value to be published. The Metric may contain zero or
// more values to be updated.
class MetricNotification {
public:
virtual ~MetricNotification() {};
// The metric_id is the metric name, plus the metric part name, and the
// metric field name/value string. E.g.
// name: "drm/cdm/decrypt/duration"
// part: "mean"
// field name/value string: "{error_code:0&buffer_size:1024}"
// becomes: "drm/cdm/decrypt/duration/mean/{error_code:0&buffer_size:1024}".
virtual void UpdateString(const std::string& metric_id,
const std::string& value) = 0;
virtual void UpdateInt32(const std::string& metric_id, int32_t value) = 0;
virtual void UpdateInt64(const std::string& metric_id, int64_t value) = 0;
virtual void UpdateDouble(const std::string& metric_id, double value) = 0;
};
// This abstract class merely provides the definition for publishing the value
// of the metric.
class MetricPublisher {
public:
virtual ~MetricPublisher() { }
// Publish metric values to the MetricNotification. |subscriber| must
// not be null and is owned by the caller.
virtual void Publish(MetricNotification* subscriber) = 0;
};
} // namespace metrics
} // namespace wvcdm
#endif // WVCDM_METRICS_METRIC_PUBLISHER_H_

View File

@@ -0,0 +1,46 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// This file contains the declarations for the Metric class and related
// types.
#ifndef WVCDM_METRICS_METRIC_SERIALIZATION_H_
#define WVCDM_METRICS_METRIC_SERIALIZATION_H_
namespace wvcdm {
namespace metrics {
// The MetricSerializer is implemented by the code that instantiates
// MetricSerializable instances. The caller provides this MetricSerializer
// instance to MetricSerializable::Serialize. In turn, Serialize will make a
// call to Set* for each value to be Serialized. The MetricSerialiable
// implementation may set zero or more values on the MetricSerializer.
class MetricSerializer {
public:
virtual ~MetricSerializer() {};
// The metric_id is the metric name, plus the metric part name, and the
// metric field name/value string. E.g.
// name: "drm/cdm/decrypt/duration"
// part: "mean"
// field name/value string: "{error_code:0&buffer_size:1024}"
// becomes: "drm/cdm/decrypt/duration/mean/{error_code:0&buffer_size:1024}".
virtual void SetString(const std::string& metric_id,
const std::string& value) = 0;
virtual void SetInt32(const std::string& metric_id, int32_t value) = 0;
virtual void SetInt64(const std::string& metric_id, int64_t value) = 0;
virtual void SetDouble(const std::string& metric_id, double value) = 0;
};
// This abstract class merely provides the definition for serializing the value
// of the metric.
class MetricSerializable {
public:
virtual ~MetricSerializable() { }
// Serialize metric values to the MetricSerializer. |serializer| must
// not be null and is owned by the caller.
virtual void Serialize(MetricSerializer* serializer) = 0;
};
} // namespace metrics
} // namespace wvcdm
#endif // WVCDM_METRICS_METRIC_SERIALIZATION_H_

View File

@@ -1,4 +1,7 @@
// Copyright 2016 Google Inc. All Rights Reserved.
//
// This file contains definitions for metrics being collected throughout the
// CDM.
#ifndef WVCDM_METRICS_METRICS_GROUP_H_
#define WVCDM_METRICS_METRICS_GROUP_H_
@@ -6,14 +9,52 @@
#include <stddef.h>
#include <stdint.h>
#include "OEMCryptoCENC.h"
#include "event_metric.h"
#include "metric_publisher.h"
#include "OEMCryptoCENC.h"
#include "wv_cdm_types.h"
// This definition indicates that a given metric does not need timing
// stats. Example:
//
// M_RECORD(my_metrics, my_metric_name, NO_TIME);
#define NO_TIME 0
// Used to record metric timing and additional information about a specific
// event. Assumes that a microsecond timing has been provided. Example:
//
// long total_time = 0;
// long error_code = TimeSomeOperation(&total_time);
// M_RECORD(my_metrics, my_metric_name, total_time, error_code);
#define M_RECORD(GROUP, METRIC, TIME, ...) \
if ( GROUP ) { \
( GROUP ) -> METRIC . Record( TIME, ##__VA_ARGS__ ); \
}
// This definition automatically times an operation and records the time and
// additional information such as error code to the provided metric.
// Example:
//
// OEMCryptoResult sts;
// M_TIME(
// sts = OEMCrypto_Initialize(),
// my_metrics_collection,
// oemcrypto_initialize_,
// sts);
#define M_TIME(CALL, GROUP, METRIC, ...) \
if ( GROUP ) { \
wvcdm::metrics::TimerMetric timer; \
timer.Start(); \
CALL; \
( GROUP ) -> METRIC . Record(timer.AsUs(), ##__VA_ARGS__ ); \
} else { \
CALL; \
}
namespace wvcdm {
namespace metrics {
// This enum defines the conditions encountered during OEMCrypto Initialization
// in oemcrypto_adapter_dynamic.
typedef enum OEMCryptoInitializationMode {
OEMCrypto_INITIALIZED_USING_IN_APP = 0,
OEMCrypto_INITIALIZED_FORCING_L3 = 1,
@@ -33,35 +74,12 @@ typedef enum OEMCryptoInitializationMode {
OEMCrypto_INITIALIZED_USING_L1_WITH_PROVISIONING_3_0 = 15
} OEMCryptoInitializationMode;
/*
* The metrics group is the group of all metrics that be be recorded. They
* are kept together to allow calls to be correlated to one another.
*/
class MetricsGroup {
// This class contains metrics for Crypto Session and OEM Crypto.
class CryptoMetrics {
public:
/* CDM ENGINE */
EventMetric<CdmResponseType> cdm_engine_add_key_;
EventMetric<CdmResponseType> cdm_engine_close_session_;
EventMetric<CdmResponseType> cdm_engine_decrypt_;
EventMetric<bool> cdm_engine_find_session_for_key_;
EventMetric<CdmResponseType> cdm_engine_generate_key_request_;
EventMetric<CdmResponseType> cdm_engine_get_provisioning_request_;
EventMetric<CdmResponseType> cdm_engine_get_usage_info_;
EventMetric<CdmResponseType> cdm_engine_handle_provisioning_response_;
EventMetric<> cdm_engine_life_span_;
EventMetric<CdmResponseType> cdm_engine_open_key_set_session_;
EventMetric<CdmResponseType> cdm_engine_open_session_;
EventMetric<CdmResponseType> cdm_engine_query_key_status_;
EventMetric<CdmResponseType> cdm_engine_release_all_usage_info_;
EventMetric<CdmResponseType> cdm_engine_release_usage_info_;
EventMetric<CdmResponseType> cdm_engine_remove_keys_;
EventMetric<CdmResponseType> cdm_engine_restore_key_;
EventMetric<CdmResponseType, CdmSecurityLevel> cdm_engine_unprovision_;
/* CDM SESSION */
EventMetric<> cdm_session_life_span_;
EventMetric<CdmResponseType> cdm_session_renew_key_;
EventMetric<CdmResponseType> cdm_session_restore_offline_session_;
EventMetric<CdmResponseType> cdm_session_restore_usage_session_;
CryptoMetrics();
/* CRYPTO SESSION */
EventMetric<CdmResponseType> crypto_session_delete_all_usage_reports_;
EventMetric<CdmResponseType> crypto_session_delete_multiple_usage_information_;
@@ -127,14 +145,99 @@ class MetricsGroup {
/* Internal OEMCrypto Metrics */
EventMetric<OEMCryptoInitializationMode> oemcrypto_initialization_mode_;
EventMetric<uint32_t, uint32_t> oemcrypto_l1_api_version_;
};
MetricsGroup();
~MetricsGroup();
// This class contains session-scoped metrics. All properties and
// statistics related to operations within a single session are
// recorded here.
class SessionMetrics {
public:
SessionMetrics();
// Sets the session id of the metrics group. This allows the session
// id to be captured and reported as part of the collection of metrics.
void SetSessionId(const CdmSessionId& session_id) {
session_id_ = session_id; }
// Returns the session id or an empty session id if it has not been set.
const CdmSessionId& GetSessionId() const { return session_id_; }
// Marks the metrics object as completed and ready for serialization.
void SetCompleted() { completed_ = true; }
// Returns true if the object is completed. This is used to determine
// when the stats are ready to be published.
bool IsCompleted() const { return completed_; }
// Returns a pointer to the crypto metrics belonging to the engine instance.
// This instance retains ownership of the object.
CryptoMetrics* GetCryptoMetrics() { return &crypto_metrics_; }
// Metrics collected at the session level.
EventMetric<> cdm_session_life_span_;
EventMetric<CdmResponseType> cdm_session_renew_key_;
EventMetric<CdmResponseType> cdm_session_restore_offline_session_;
EventMetric<CdmResponseType> cdm_session_restore_usage_session_;
private:
void Publish(MetricNotification* subscriber);
CdmSessionId session_id_;
bool completed_;
CryptoMetrics crypto_metrics_;
};
// This class contains engine-scoped metrics. All properties and
// statistics related to operations within the engine, but outside
// the scope of a session are recorded here.
class EngineMetrics {
public:
EngineMetrics();
~EngineMetrics();
// Add a new SessionMetrics instance and return a pointer to the caller.
// The new SessionMetrics instance is owned by this EngineMetrics instance
// and will exist until RemoveSession is called or this object is deleted.
SessionMetrics* AddSession();
// Removes the metrics object for the given session id. This should only
// be called when the SessionMetrics instance is no longer in use.
void RemoveSession(CdmSessionId session_id);
// Returns a pointer to the crypto metrics belonging to the engine instance.
// The CryptoMetrics instance is still owned by this object and will exist
// until this object is deleted.
CryptoMetrics* GetCryptoMetrics() { return &crypto_metrics_; }
// Serialize all engine and completed session metrics to json format and
// send them to the output string. |out| must NOT be null. |completed_only|
// indicates that this call should only publish SessionMetrics instances
// that are marked as completed.
void JsonSerialize(std::string* out, bool completed_only);
// Metrics recorded at the engine level.
EventMetric<CdmResponseType> cdm_engine_add_key_;
EventMetric<CdmResponseType> cdm_engine_close_session_;
EventMetric<CdmResponseType> cdm_engine_decrypt_;
EventMetric<bool> cdm_engine_find_session_for_key_;
EventMetric<CdmResponseType> cdm_engine_generate_key_request_;
EventMetric<CdmResponseType> cdm_engine_get_provisioning_request_;
EventMetric<CdmResponseType> cdm_engine_get_usage_info_;
EventMetric<CdmResponseType> cdm_engine_handle_provisioning_response_;
EventMetric<> cdm_engine_life_span_;
EventMetric<CdmResponseType> cdm_engine_open_key_set_session_;
EventMetric<CdmResponseType> cdm_engine_open_session_;
EventMetric<CdmResponseType> cdm_engine_query_key_status_;
EventMetric<CdmResponseType> cdm_engine_release_all_usage_info_;
EventMetric<CdmResponseType> cdm_engine_release_usage_info_;
EventMetric<CdmResponseType> cdm_engine_remove_keys_;
EventMetric<CdmResponseType> cdm_engine_restore_key_;
EventMetric<CdmResponseType, CdmSecurityLevel> cdm_engine_unprovision_;
private:
Lock session_metrics_lock_;
std::vector<metrics::SessionMetrics*> session_metrics_list_;
CryptoMetrics crypto_metrics_;
};
} // namespace metrics
} // namespace wvcdm
#endif

View File

@@ -1,58 +0,0 @@
// Copyright 2016 Google Inc. All Rights Reserved.
#ifndef WVCDM_METRICS_METRICS_FRONT_END_H_
#define WVCDM_METRICS_METRICS_FRONT_END_H_
#include <map>
#include "report.h"
#include "timer_metric.h" /* needed for the macro */
namespace wvcdm {
namespace metrics {
class MetricsFrontEnd {
public:
MetricsFrontEnd(Report* root);
MetricNotification* CreateSubscriber();
static MetricsFrontEnd& Instance();
static void OverrideInstance(MetricsFrontEnd* instance);
private:
static MetricsFrontEnd* instance_;
Report* root_;
/* Disallow copy and assign. */
MetricsFrontEnd(const MetricsFrontEnd&);
void operator=(const MetricsFrontEnd&);
};
} // namespace metrics
} // namespace wvcdm
#define MFE wvcdm::metrics::MetricsFrontEnd::Instance()
#define NO_TIME 0
#define M_RECORD(GROUP, METRIC, TIME, ...) \
if ( GROUP ) { \
( GROUP ) -> METRIC . Record( TIME, ##__VA_ARGS__ ); \
}
#define M_TIME(CALL, GROUP, METRIC, ...) \
if ( GROUP ) { \
wvcdm::metrics::TimerMetric timer; \
timer.Start(); \
CALL; \
( GROUP ) -> METRIC . Record(timer.AsUs(), ##__VA_ARGS__ ); \
} else { \
CALL; \
}
#endif

View File

@@ -1,29 +0,0 @@
// Copyright 2016 Google Inc. All Rights Reserved.
#ifndef WVCDM_METRICS_REPORT_H_
#define WVCDM_METRICS_REPORT_H_
#include <stdint.h>
#include "event_metric.h"
namespace wvcdm {
namespace metrics {
class Report : public MetricNotification {
public:
virtual ~Report() { }
/* Create a new report of the same type. The new report is not
* a copy of this report. The pointer is to be owned by whoever
* calls this function. */
virtual Report* NewReport() const;
};
} // metrics
} //wvcdm
#endif

View File

@@ -32,24 +32,24 @@ void BaseEventMetric::Record(const std::string& field_names_values,
distribution->Record(value);
}
void BaseEventMetric::Publish(MetricNotification* notification) {
void BaseEventMetric::Serialize(MetricSerializer* serializer) {
AutoLock lock(internal_lock_);
for (std::map<std::string, Distribution*>::iterator it
= value_map_.begin(); it != value_map_.end(); it++) {
notification->UpdateInt64(
serializer->SetInt64(
metric_name_ + "/count" + it->first,
it->second->Count());
notification->UpdateDouble(
serializer->SetDouble(
metric_name_ + "/mean" + it->first,
it->second->Mean());
notification->UpdateDouble(
serializer->SetDouble(
metric_name_ + "/variance" + it->first,
it->second->Variance());
notification->UpdateDouble(
serializer->SetDouble(
metric_name_ + "/min" + it->first,
it->second->Min());
notification->UpdateDouble(
serializer->SetDouble(
metric_name_ + "/max" + it->first,
it->second->Max());
}

View File

@@ -1,75 +1,27 @@
// Copyright 2016 Google Inc. All Rights Reserved.
#include "metrics_group.h"
#include "metrics_collections.h"
#include "metrics_front_end.h"
#include <algorithm>
namespace {
// Helper struct for comparing session ids.
struct CompareSessionIds {
const std::string& target_;
CompareSessionIds(const wvcdm::CdmSessionId& target) : target_(target) {};
bool operator()(const wvcdm::metrics::SessionMetrics* metrics) const {
return metrics->GetSessionId() == target_;
}
};
} // anonymous namespace
namespace wvcdm {
namespace metrics {
MetricsGroup::MetricsGroup() :
cdm_engine_add_key_(
"/drm/widevine/cdm_engine/add_key/time",
"error"),
cdm_engine_close_session_(
"/drm/widevine/cdm_engine/close_session/time",
"error"),
cdm_engine_decrypt_(
"/drm/widevine/cdm_engine/decrypt/time",
"error"),
cdm_engine_find_session_for_key_(
"/drm/widevine/cdm_engine/find_session_for_key/time",
"success"),
cdm_engine_generate_key_request_(
"/drm/widevine/cdm_engine/generate_key_request/time",
"error"),
cdm_engine_get_provisioning_request_(
"/drm/widevine/cdm_engine/get_provisioning_request/time",
"error"),
cdm_engine_get_usage_info_(
"/drm/widevine/cdm_engine/get_usage_info/time",
"error"),
cdm_engine_handle_provisioning_response_(
"/drm/widevine/cdm_engine/handle_provisioning_response/time",
"error"),
cdm_engine_life_span_(
"/drm/widevine/cdm_engine/life_span/time"),
cdm_engine_open_key_set_session_(
"/drm/widevine/cdm_engine/open_key_set_session/time",
"error"),
cdm_engine_open_session_(
"/drm/widevine/cdm_engine/open_session/time",
"error"),
cdm_engine_query_key_status_(
"/drm/widevine/cdm_engine/query_key_status/time",
"error"),
cdm_engine_release_all_usage_info_(
"/drm/widevine/cdm_engine/release_all_usage_info/time",
"error"),
cdm_engine_release_usage_info_(
"/drm/widevine/cdm_engine/release_usage_info/time",
"error"),
cdm_engine_remove_keys_(
"/drm/widevine/cdm_engine/remove_keys/time",
"error"),
cdm_engine_restore_key_(
"/drm/widevine/cdm_engine/restore_key/time",
"error"),
cdm_engine_unprovision_(
"/drm/widevine/cdm_engine/unprovision/time",
"error",
"security_level"),
cdm_session_life_span_(
"/drm/widevine/cdm_session/life_span/time"),
cdm_session_renew_key_(
"/drm/widevine/cdm_session/renew_key/time",
"error"),
cdm_session_restore_offline_session_(
"/drm/widevine/cdm_session/restore_offline_session/time",
"error"),
cdm_session_restore_usage_session_(
"/drm/widevine/cdm_session/restore_usage_session/time",
"error"),
CryptoMetrics::CryptoMetrics() :
crypto_session_delete_all_usage_reports_(
"/drm/widevine/crypto_session/delete_all_usage_reports/time",
"error"),
@@ -287,99 +239,106 @@ MetricsGroup::MetricsGroup() :
oemcrypto_l1_api_version_(
"/drm/widevine/oemcrypto/l1_api_version",
"version",
"min_version") { }
"min_version") {}
MetricsGroup::~MetricsGroup() {
#if 0 // Disable metrics for now to work around P0:b/35093325
MetricNotification* subscriber = MFE.CreateSubscriber();
if (subscriber) {
Publish(subscriber);
SessionMetrics::SessionMetrics() :
cdm_session_life_span_(
"/drm/widevine/cdm_session/life_span/time"),
cdm_session_renew_key_(
"/drm/widevine/cdm_session/renew_key/time",
"error"),
cdm_session_restore_offline_session_(
"/drm/widevine/cdm_session/restore_offline_session/time",
"error"),
cdm_session_restore_usage_session_(
"/drm/widevine/cdm_session/restore_usage_session/time",
"error"),
completed_(false) {
}
EngineMetrics::EngineMetrics() :
cdm_engine_add_key_(
"/drm/widevine/cdm_engine/add_key/time",
"error"),
cdm_engine_close_session_(
"/drm/widevine/cdm_engine/close_session/time",
"error"),
cdm_engine_decrypt_(
"/drm/widevine/cdm_engine/decrypt/time",
"error"),
cdm_engine_find_session_for_key_(
"/drm/widevine/cdm_engine/find_session_for_key/time",
"success"),
cdm_engine_generate_key_request_(
"/drm/widevine/cdm_engine/generate_key_request/time",
"error"),
cdm_engine_get_provisioning_request_(
"/drm/widevine/cdm_engine/get_provisioning_request/time",
"error"),
cdm_engine_get_usage_info_(
"/drm/widevine/cdm_engine/get_usage_info/time",
"error"),
cdm_engine_handle_provisioning_response_(
"/drm/widevine/cdm_engine/handle_provisioning_response/time",
"error"),
cdm_engine_life_span_(
"/drm/widevine/cdm_engine/life_span/time"),
cdm_engine_open_key_set_session_(
"/drm/widevine/cdm_engine/open_key_set_session/time",
"error"),
cdm_engine_open_session_(
"/drm/widevine/cdm_engine/open_session/time",
"error"),
cdm_engine_query_key_status_(
"/drm/widevine/cdm_engine/query_key_status/time",
"error"),
cdm_engine_release_all_usage_info_(
"/drm/widevine/cdm_engine/release_all_usage_info/time",
"error"),
cdm_engine_release_usage_info_(
"/drm/widevine/cdm_engine/release_usage_info/time",
"error"),
cdm_engine_remove_keys_(
"/drm/widevine/cdm_engine/remove_keys/time",
"error"),
cdm_engine_restore_key_(
"/drm/widevine/cdm_engine/restore_key/time",
"error"),
cdm_engine_unprovision_(
"/drm/widevine/cdm_engine/unprovision/time",
"error",
"security_level") {
}
EngineMetrics::~EngineMetrics() {
AutoLock kock(session_metrics_lock_);
std::vector<SessionMetrics*>::iterator i;
for (i = session_metrics_list_.begin(); i != session_metrics_list_.end();
i++) {
delete *i;
}
delete subscriber;
#endif
session_metrics_list_.clear();
}
void MetricsGroup::Publish(MetricNotification* subscriber) {
cdm_engine_add_key_.Publish(subscriber);
cdm_engine_close_session_.Publish(subscriber);
cdm_engine_decrypt_.Publish(subscriber);
cdm_engine_find_session_for_key_.Publish(subscriber);
cdm_engine_generate_key_request_.Publish(subscriber);
cdm_engine_get_provisioning_request_.Publish(subscriber);
cdm_engine_get_usage_info_.Publish(subscriber);
cdm_engine_handle_provisioning_response_.Publish(subscriber);
cdm_engine_life_span_.Publish(subscriber);
cdm_engine_open_key_set_session_.Publish(subscriber);
cdm_engine_open_session_.Publish(subscriber);
cdm_engine_query_key_status_.Publish(subscriber);
cdm_engine_release_all_usage_info_.Publish(subscriber);
cdm_engine_release_usage_info_.Publish(subscriber);
cdm_engine_remove_keys_.Publish(subscriber);
cdm_engine_restore_key_.Publish(subscriber);
cdm_engine_unprovision_.Publish(subscriber);
cdm_session_life_span_.Publish(subscriber);
cdm_session_renew_key_.Publish(subscriber);
cdm_session_restore_offline_session_.Publish(subscriber);
cdm_session_restore_usage_session_.Publish(subscriber);
crypto_session_delete_all_usage_reports_.Publish(subscriber);
crypto_session_delete_multiple_usage_information_.Publish(subscriber);
crypto_session_generic_decrypt_.Publish(subscriber);
crypto_session_generic_sign_.Publish(subscriber);
crypto_session_generic_verify_.Publish(subscriber);
crypto_session_get_device_unique_id_.Publish(subscriber);
crypto_session_get_security_level_.Publish(subscriber);
crypto_session_get_system_id_.Publish(subscriber);
crypto_session_get_token_.Publish(subscriber);
crypto_session_life_span_.Publish(subscriber);
crypto_session_load_certificate_private_key_.Publish(subscriber);
crypto_session_open_.Publish(subscriber);
crypto_session_update_usage_information_.Publish(subscriber);
crypto_session_usage_information_support_.Publish(subscriber);
oemcrypto_api_version_.Publish(subscriber);
oemcrypto_close_session_.Publish(subscriber);
oemcrypto_copy_buffer_.Publish(subscriber);
oemcrypto_deactivate_usage_entry_.Publish(subscriber);
oemcrypto_decrypt_cenc_.Publish(subscriber);
oemcrypto_delete_usage_entry_.Publish(subscriber);
oemcrypto_delete_usage_table_.Publish(subscriber);
oemcrypto_derive_keys_from_session_key_.Publish(subscriber);
oemcrypto_force_delete_usage_entry_.Publish(subscriber);
oemcrypto_generate_derived_keys_.Publish(subscriber);
oemcrypto_generate_nonce_.Publish(subscriber);
oemcrypto_generate_rsa_signature_.Publish(subscriber);
oemcrypto_generate_signature_.Publish(subscriber);
oemcrypto_generic_decrypt_.Publish(subscriber);
oemcrypto_generic_encrypt_.Publish(subscriber);
oemcrypto_generic_sign_.Publish(subscriber);
oemcrypto_generic_verify_.Publish(subscriber);
oemcrypto_get_device_id_.Publish(subscriber);
oemcrypto_get_hdcp_capability_.Publish(subscriber);
oemcrypto_get_key_data_.Publish(subscriber);
oemcrypto_get_max_number_of_sessions_.Publish(subscriber);
oemcrypto_get_number_of_open_sessions_.Publish(subscriber);
oemcrypto_get_oem_public_certificate_.Publish(subscriber);
oemcrypto_get_provisioning_method_.Publish(subscriber);
oemcrypto_get_random_.Publish(subscriber);
oemcrypto_install_keybox_.Publish(subscriber);
oemcrypto_is_anti_rollback_hw_present_.Publish(subscriber);
oemcrypto_is_keybox_valid_.Publish(subscriber);
oemcrypto_load_device_rsa_key_.Publish(subscriber);
oemcrypto_load_keys_.Publish(subscriber);
oemcrypto_load_test_keybox_.Publish(subscriber);
oemcrypto_load_test_rsa_key_.Publish(subscriber);
oemcrypto_open_session_.Publish(subscriber);
oemcrypto_refresh_keys_.Publish(subscriber);
oemcrypto_report_usage_.Publish(subscriber);
oemcrypto_rewrap_device_rsa_key_.Publish(subscriber);
oemcrypto_rewrap_device_rsa_key_30_.Publish(subscriber);
oemcrypto_security_level_.Publish(subscriber);
oemcrypto_security_patch_level_.Publish(subscriber);
oemcrypto_select_key_.Publish(subscriber);
oemcrypto_supports_usage_table_.Publish(subscriber);
oemcrypto_update_usage_table_.Publish(subscriber);
oemcrypto_wrap_keybox_.Publish(subscriber);
oemcrypto_initialization_mode_.Publish(subscriber);
oemcrypto_l1_api_version_.Publish(subscriber);
SessionMetrics* EngineMetrics::AddSession() {
AutoLock lock(session_metrics_lock_);
SessionMetrics* metrics = new SessionMetrics();
session_metrics_list_.push_back(metrics);
return metrics;
}
void EngineMetrics::RemoveSession(wvcdm::CdmSessionId session_id) {
AutoLock lock(session_metrics_lock_);
session_metrics_list_.erase(
std::remove_if(session_metrics_list_.begin(),
session_metrics_list_.end(),
CompareSessionIds(session_id)),
session_metrics_list_.end());
}
void JsonSerialize(std::string* out, bool completed_only) {
// TODO(blueeyes): Implement this.
}
} // metrics
} // wvcdm

View File

@@ -1,31 +0,0 @@
// Copyright 2016 Google Inc. All Rights Reserved
#include "metrics_front_end.h"
#include <stddef.h>
#include <log.h>
namespace wvcdm {
namespace metrics {
MetricsFrontEnd* MetricsFrontEnd::instance_ = NULL;
MetricsFrontEnd::MetricsFrontEnd(Report* root) :
root_(root) { }
MetricNotification* MetricsFrontEnd::CreateSubscriber() {
return root_ == NULL ? NULL : root_->NewReport();
}
MetricsFrontEnd& MetricsFrontEnd::Instance() {
static MetricsFrontEnd kDummy(NULL);
return instance_ == NULL ? kDummy : *instance_;
}
void MetricsFrontEnd::OverrideInstance(MetricsFrontEnd* instance) {
instance_ = instance;
}
} // namespace metrics
} // namespace wvcdm

View File

@@ -3,7 +3,7 @@
// Unit tests for EventMetric
#include "event_metric.h"
#include "metric_publisher.h"
#include "metric_serialization.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -15,22 +15,22 @@ using testing::NotNull;
namespace wvcdm {
namespace metrics {
class MockEventMetricNotification : public MetricNotification {
class MockEventMetricSerializer : public MetricSerializer {
public:
MOCK_METHOD2(UpdateString, void(const std::string& metric_id,
MOCK_METHOD2(SetString, void(const std::string& metric_id,
const std::string& value));
MOCK_METHOD2(UpdateInt32, void(const std::string& metric_id,
MOCK_METHOD2(SetInt32, void(const std::string& metric_id,
int32_t value));
MOCK_METHOD2(UpdateInt64, void(const std::string& metric_id,
MOCK_METHOD2(SetInt64, void(const std::string& metric_id,
int64_t value));
MOCK_METHOD2(UpdateDouble, void(const std::string& metric_id,
MOCK_METHOD2(SetDouble, void(const std::string& metric_id,
double value));
};
class EventMetricTest : public ::testing::Test {
public:
void SetUp() {
mock_notification_.reset(new MockEventMetricNotification());
mock_serializer_.reset(new MockEventMetricSerializer());
}
protected:
template<typename F1,
@@ -44,7 +44,7 @@ class EventMetricTest : public ::testing::Test {
return metric.value_map_;
}
scoped_ptr<MockEventMetricNotification> mock_notification_;
scoped_ptr<MockEventMetricSerializer> mock_serializer_;
};
TEST_F(EventMetricTest, NoFieldsSuccessNullCallback) {
@@ -60,19 +60,19 @@ TEST_F(EventMetricTest, NoFieldsSuccessNullCallback) {
TEST_F(EventMetricTest, NoFieldsSuccessWithCallback) {
wvcdm::metrics::EventMetric<> metric("no/fields/metric");
EXPECT_CALL(*mock_notification_,
UpdateInt64("no/fields/metric/count", 1.0));
EXPECT_CALL(*mock_notification_,
UpdateDouble("no/fields/metric/mean", 10.0));
EXPECT_CALL(*mock_notification_,
UpdateDouble("no/fields/metric/variance", 0.0));
EXPECT_CALL(*mock_notification_,
UpdateDouble("no/fields/metric/min", 10.0));
EXPECT_CALL(*mock_notification_,
UpdateDouble("no/fields/metric/max", 10.0));
EXPECT_CALL(*mock_serializer_,
SetInt64("no/fields/metric/count", 1.0));
EXPECT_CALL(*mock_serializer_,
SetDouble("no/fields/metric/mean", 10.0));
EXPECT_CALL(*mock_serializer_,
SetDouble("no/fields/metric/variance", 0.0));
EXPECT_CALL(*mock_serializer_,
SetDouble("no/fields/metric/min", 10.0));
EXPECT_CALL(*mock_serializer_,
SetDouble("no/fields/metric/max", 10.0));
metric.Record(10);
metric.Publish(mock_notification_.get());
metric.Serialize(mock_serializer_.get());
std::map<std::string, Distribution*> value_map = GetValueMap(metric);
ASSERT_EQ(1u, GetValueMap(metric).size());
@@ -142,24 +142,24 @@ TEST_F(EventMetricTest, TwoFieldsSuccessWithCallback) {
// Callbacks from second record operation.
EXPECT_CALL(
*mock_notification_,
UpdateInt64("two/fields/metric/count{error_code:11&pow2_size:16}", 2.0));
*mock_serializer_,
SetInt64("two/fields/metric/count{error_code:11&pow2_size:16}", 2.0));
EXPECT_CALL(
*mock_notification_,
UpdateDouble("two/fields/metric/mean{error_code:11&pow2_size:16}", 3.5));
*mock_serializer_,
SetDouble("two/fields/metric/mean{error_code:11&pow2_size:16}", 3.5));
EXPECT_CALL(
*mock_notification_,
UpdateDouble("two/fields/metric/variance{error_code:11&pow2_size:16}",
*mock_serializer_,
SetDouble("two/fields/metric/variance{error_code:11&pow2_size:16}",
0.25));
EXPECT_CALL(
*mock_notification_,
UpdateDouble("two/fields/metric/min{error_code:11&pow2_size:16}", 3.0));
*mock_serializer_,
SetDouble("two/fields/metric/min{error_code:11&pow2_size:16}", 3.0));
EXPECT_CALL(
*mock_notification_,
UpdateDouble("two/fields/metric/max{error_code:11&pow2_size:16}", 4.0));
*mock_serializer_,
SetDouble("two/fields/metric/max{error_code:11&pow2_size:16}", 4.0));
metric.Record(3, 11, Pow2Bucket(29));
metric.Record(4, 11, Pow2Bucket(29));
metric.Publish(mock_notification_.get());
metric.Serialize(mock_serializer_.get());
}
TEST_F(EventMetricTest, ThreeFieldsSuccess) {