From a34e279d0f8427eaa1b15bc4c4826fac4a370b30 Mon Sep 17 00:00:00 2001 From: Adam Stone Date: Wed, 29 Mar 2017 17:03:43 -0700 Subject: [PATCH 1/3] 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 --- libwvdrmengine/cdm/core/include/cdm_engine.h | 5 +- libwvdrmengine/cdm/core/include/cdm_session.h | 32 ++- .../core/include/certificate_provisioning.h | 4 +- .../cdm/core/include/crypto_session.h | 9 +- .../cdm/core/include/usage_table_header.h | 14 +- libwvdrmengine/cdm/core/src/cdm_engine.cpp | 47 +-- libwvdrmengine/cdm/core/src/cdm_session.cpp | 47 +-- .../cdm/core/src/crypto_session.cpp | 3 +- .../core/src/oemcrypto_adapter_dynamic.cpp | 37 +-- .../cdm/core/src/usage_table_header.cpp | 14 +- .../cdm/core/test/cdm_session_unittest.cpp | 9 +- .../core/test/usage_table_header_unittest.cpp | 34 +-- .../cdm/metrics/include/event_metric.h | 8 +- .../cdm/metrics/include/metric_publisher.h | 46 --- .../metrics/include/metric_serialization.h | 46 +++ ...{metrics_group.h => metrics_collections.h} | 171 ++++++++--- .../cdm/metrics/include/metrics_front_end.h | 58 ---- libwvdrmengine/cdm/metrics/include/report.h | 29 -- .../cdm/metrics/src/event_metric.cpp | 12 +- ...rics_group.cpp => metrics_collections.cpp} | 267 ++++++++---------- .../cdm/metrics/src/metrics_front_end.cpp | 31 -- .../cdm/metrics/test/event_metric_test.cpp | 60 ++-- 22 files changed, 478 insertions(+), 505 deletions(-) delete mode 100644 libwvdrmengine/cdm/metrics/include/metric_publisher.h create mode 100644 libwvdrmengine/cdm/metrics/include/metric_serialization.h rename libwvdrmengine/cdm/metrics/include/{metrics_group.h => metrics_collections.h} (63%) delete mode 100644 libwvdrmengine/cdm/metrics/include/metrics_front_end.h delete mode 100644 libwvdrmengine/cdm/metrics/include/report.h rename libwvdrmengine/cdm/metrics/src/{metrics_group.cpp => metrics_collections.cpp} (68%) delete mode 100644 libwvdrmengine/cdm/metrics/src/metrics_front_end.cpp diff --git a/libwvdrmengine/cdm/core/include/cdm_engine.h b/libwvdrmengine/cdm/core/include/cdm_engine.h index 4e323e92..6adcda6e 100644 --- a/libwvdrmengine/cdm/core/include/cdm_engine.h +++ b/libwvdrmengine/cdm/core/include/cdm_engine.h @@ -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_; diff --git a/libwvdrmengine/cdm/core/include/cdm_session.h b/libwvdrmengine/cdm/core/include/cdm_session.h index 4321ca76..0b3c97ee 100644 --- a/libwvdrmengine/cdm/core/include/cdm_session.h +++ b/libwvdrmengine/cdm/core/include/cdm_session.h @@ -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 license_parser_; scoped_ptr crypto_session_; scoped_ptr policy_engine_; diff --git a/libwvdrmengine/cdm/core/include/certificate_provisioning.h b/libwvdrmengine/cdm/core/include/certificate_provisioning.h index b124fb70..d54d859c 100644 --- a/libwvdrmengine/cdm/core/include/certificate_provisioning.h +++ b/libwvdrmengine/cdm/core/include/certificate_provisioning.h @@ -6,7 +6,7 @@ #include #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) {}; diff --git a/libwvdrmengine/cdm/core/include/crypto_session.h b/libwvdrmengine/cdm/core/include/crypto_session.h index b6214789..17029e55 100644 --- a/libwvdrmengine/cdm/core/include/crypto_session.h +++ b/libwvdrmengine/cdm/core/include/crypto_session.h @@ -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_; diff --git a/libwvdrmengine/cdm/core/include/usage_table_header.h b/libwvdrmengine/cdm/core/include/usage_table_header.h index 3357a3c8..0fb8f748 100644 --- a/libwvdrmengine/cdm/core/include/usage_table_header.h +++ b/libwvdrmengine/cdm/core/include/usage_table_header.h @@ -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_; } diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index 556b5f94..a25c5753 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -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 new_session(new CdmSession(file_system_)); + scoped_ptr 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 crypto_session(new CryptoSession(&metrics_)); + scoped_ptr 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) { diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index 91fe43ac..073d01d6 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -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()), diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index 8cd99493..cb2693ab 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -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), diff --git a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp index 5cc3027e..231ca0da 100644 --- a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp +++ b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp @@ -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); diff --git a/libwvdrmengine/cdm/core/src/usage_table_header.cpp b/libwvdrmengine/cdm/core/src/usage_table_header.cpp index 790aeffb..dc547ace 100644 --- a/libwvdrmengine/cdm/core/src/usage_table_header.cpp +++ b/libwvdrmengine/cdm/core/src/usage_table_header.cpp @@ -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 diff --git a/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp b/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp index b4083a14..34437826 100644 --- a/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp @@ -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 cdm_session_; MockCdmLicense* license_parser_; MockCryptoSession* crypto_session_; diff --git a/libwvdrmengine/cdm/core/test/usage_table_header_unittest.cpp b/libwvdrmengine/cdm/core/test/usage_table_header_unittest.cpp index 26bb500e..075a40ac 100644 --- a/libwvdrmengine/cdm/core/test/usage_table_header_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/usage_table_header_unittest.cpp @@ -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) diff --git a/libwvdrmengine/cdm/metrics/include/event_metric.h b/libwvdrmengine/cdm/metrics/include/event_metric.h index f9179b64..61012fa2 100644 --- a/libwvdrmengine/cdm/metrics/include/event_metric.h +++ b/libwvdrmengine/cdm/metrics/include/event_metric.h @@ -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. diff --git a/libwvdrmengine/cdm/metrics/include/metric_publisher.h b/libwvdrmengine/cdm/metrics/include/metric_publisher.h deleted file mode 100644 index 11a1a3ed..00000000 --- a/libwvdrmengine/cdm/metrics/include/metric_publisher.h +++ /dev/null @@ -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_ diff --git a/libwvdrmengine/cdm/metrics/include/metric_serialization.h b/libwvdrmengine/cdm/metrics/include/metric_serialization.h new file mode 100644 index 00000000..b2aa3a2b --- /dev/null +++ b/libwvdrmengine/cdm/metrics/include/metric_serialization.h @@ -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_ diff --git a/libwvdrmengine/cdm/metrics/include/metrics_group.h b/libwvdrmengine/cdm/metrics/include/metrics_collections.h similarity index 63% rename from libwvdrmengine/cdm/metrics/include/metrics_group.h rename to libwvdrmengine/cdm/metrics/include/metrics_collections.h index 495044b4..8b2ea675 100644 --- a/libwvdrmengine/cdm/metrics/include/metrics_group.h +++ b/libwvdrmengine/cdm/metrics/include/metrics_collections.h @@ -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 #include -#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 cdm_engine_add_key_; - EventMetric cdm_engine_close_session_; - EventMetric cdm_engine_decrypt_; - EventMetric cdm_engine_find_session_for_key_; - EventMetric cdm_engine_generate_key_request_; - EventMetric cdm_engine_get_provisioning_request_; - EventMetric cdm_engine_get_usage_info_; - EventMetric cdm_engine_handle_provisioning_response_; - EventMetric<> cdm_engine_life_span_; - EventMetric cdm_engine_open_key_set_session_; - EventMetric cdm_engine_open_session_; - EventMetric cdm_engine_query_key_status_; - EventMetric cdm_engine_release_all_usage_info_; - EventMetric cdm_engine_release_usage_info_; - EventMetric cdm_engine_remove_keys_; - EventMetric cdm_engine_restore_key_; - EventMetric cdm_engine_unprovision_; - /* CDM SESSION */ - EventMetric<> cdm_session_life_span_; - EventMetric cdm_session_renew_key_; - EventMetric cdm_session_restore_offline_session_; - EventMetric cdm_session_restore_usage_session_; + CryptoMetrics(); + /* CRYPTO SESSION */ EventMetric crypto_session_delete_all_usage_reports_; EventMetric crypto_session_delete_multiple_usage_information_; @@ -127,14 +145,99 @@ class MetricsGroup { /* Internal OEMCrypto Metrics */ EventMetric oemcrypto_initialization_mode_; EventMetric 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 cdm_session_renew_key_; + EventMetric cdm_session_restore_offline_session_; + EventMetric 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 cdm_engine_add_key_; + EventMetric cdm_engine_close_session_; + EventMetric cdm_engine_decrypt_; + EventMetric cdm_engine_find_session_for_key_; + EventMetric cdm_engine_generate_key_request_; + EventMetric cdm_engine_get_provisioning_request_; + EventMetric cdm_engine_get_usage_info_; + EventMetric cdm_engine_handle_provisioning_response_; + EventMetric<> cdm_engine_life_span_; + EventMetric cdm_engine_open_key_set_session_; + EventMetric cdm_engine_open_session_; + EventMetric cdm_engine_query_key_status_; + EventMetric cdm_engine_release_all_usage_info_; + EventMetric cdm_engine_release_usage_info_; + EventMetric cdm_engine_remove_keys_; + EventMetric cdm_engine_restore_key_; + EventMetric cdm_engine_unprovision_; + + private: + Lock session_metrics_lock_; + std::vector session_metrics_list_; + CryptoMetrics crypto_metrics_; +}; + } // namespace metrics } // namespace wvcdm #endif diff --git a/libwvdrmengine/cdm/metrics/include/metrics_front_end.h b/libwvdrmengine/cdm/metrics/include/metrics_front_end.h deleted file mode 100644 index 12838a82..00000000 --- a/libwvdrmengine/cdm/metrics/include/metrics_front_end.h +++ /dev/null @@ -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 - -#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 diff --git a/libwvdrmengine/cdm/metrics/include/report.h b/libwvdrmengine/cdm/metrics/include/report.h deleted file mode 100644 index 49216e69..00000000 --- a/libwvdrmengine/cdm/metrics/include/report.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. - -#ifndef WVCDM_METRICS_REPORT_H_ -#define WVCDM_METRICS_REPORT_H_ - -#include - -#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 diff --git a/libwvdrmengine/cdm/metrics/src/event_metric.cpp b/libwvdrmengine/cdm/metrics/src/event_metric.cpp index 1f9bba5d..0671418d 100644 --- a/libwvdrmengine/cdm/metrics/src/event_metric.cpp +++ b/libwvdrmengine/cdm/metrics/src/event_metric.cpp @@ -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::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()); } diff --git a/libwvdrmengine/cdm/metrics/src/metrics_group.cpp b/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp similarity index 68% rename from libwvdrmengine/cdm/metrics/src/metrics_group.cpp rename to libwvdrmengine/cdm/metrics/src/metrics_collections.cpp index b9a8904a..f0d06582 100644 --- a/libwvdrmengine/cdm/metrics/src/metrics_group.cpp +++ b/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp @@ -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 + +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::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 diff --git a/libwvdrmengine/cdm/metrics/src/metrics_front_end.cpp b/libwvdrmengine/cdm/metrics/src/metrics_front_end.cpp deleted file mode 100644 index 13658cc4..00000000 --- a/libwvdrmengine/cdm/metrics/src/metrics_front_end.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved - -#include "metrics_front_end.h" - -#include - -#include - -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 diff --git a/libwvdrmengine/cdm/metrics/test/event_metric_test.cpp b/libwvdrmengine/cdm/metrics/test/event_metric_test.cpp index bbcb7dcf..dc0c410c 100644 --- a/libwvdrmengine/cdm/metrics/test/event_metric_test.cpp +++ b/libwvdrmengine/cdm/metrics/test/event_metric_test.cpp @@ -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 mock_notification_; + scoped_ptr 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 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) { From b851dd8cfdcbcace23b60f60309a783679ca3d41 Mon Sep 17 00:00:00 2001 From: Adam Stone Date: Thu, 30 Mar 2017 10:26:58 -0700 Subject: [PATCH 2/3] CDM Metrics Protocol buffer serialization. An implementation that serializes metrics to a protocol buffer. This is a merge from wvgerrit/28440. I intend to submit 2048751, 2048750, and 2048509 together. Bug: 36217927 Bug: 36220975 Test: Added unit tests to cover modified code. Change-Id: Ie8b9d8b91d2602b015f5568890a16c0419c126df --- libwvdrmengine/Android.mk | 7 +- .../cdm/metrics/include/metrics_collections.h | 26 +- .../cdm/metrics/src/event_metric.cpp | 21 +- libwvdrmengine/cdm/metrics/src/metrics.proto | 36 ++ .../cdm/metrics/src/metrics_collections.cpp | 172 ++++++- .../cdm/metrics/test/event_metric_test.cpp | 19 +- .../metrics/test/metrics_collections_test.cpp | 444 ++++++++++++++++++ 7 files changed, 706 insertions(+), 19 deletions(-) create mode 100644 libwvdrmengine/cdm/metrics/src/metrics.proto create mode 100644 libwvdrmengine/cdm/metrics/test/metrics_collections_test.cpp diff --git a/libwvdrmengine/Android.mk b/libwvdrmengine/Android.mk index f689ec44..5c85356a 100644 --- a/libwvdrmengine/Android.mk +++ b/libwvdrmengine/Android.mk @@ -79,7 +79,9 @@ include $(CLEAR_VARS) LOCAL_MODULE := libcdm_protos LOCAL_MODULE_CLASS := STATIC_LIBRARIES -LOCAL_SRC_FILES := $(call all-proto-files-under, cdm/core/src) +CORE_PROTO_SRC_FILES := $(call all-proto-files-under, cdm/core/src) +METRICS_PROTO_SRC_FILES := $(call all-proto-files-under, cdm/metrics/src) +LOCAL_SRC_FILES := $(CORE_PROTO_SRC_FILES) $(METRICS_PROTO_SRC_FILES) generated_sources_dir := $(call local-generated-sources-dir) @@ -91,7 +93,8 @@ generated_sources_dir := $(call local-generated-sources-dir) # with this path. LOCAL_EXPORT_C_INCLUDE_DIRS := \ $(generated_sources_dir)/proto \ - $(generated_sources_dir)/proto/$(LOCAL_PATH)/cdm/core/src + $(generated_sources_dir)/proto/$(LOCAL_PATH)/cdm/core/src \ + $(generated_sources_dir)/proto/$(LOCAL_PATH)/cdm/metrics/src include $(BUILD_STATIC_LIBRARY) diff --git a/libwvdrmengine/cdm/metrics/include/metrics_collections.h b/libwvdrmengine/cdm/metrics/include/metrics_collections.h index 8b2ea675..2b5e4fdd 100644 --- a/libwvdrmengine/cdm/metrics/include/metrics_collections.h +++ b/libwvdrmengine/cdm/metrics/include/metrics_collections.h @@ -6,10 +6,12 @@ #ifndef WVCDM_METRICS_METRICS_GROUP_H_ #define WVCDM_METRICS_METRICS_GROUP_H_ +#include #include #include #include "event_metric.h" +#include "metrics.pb.h" #include "OEMCryptoCENC.h" #include "wv_cdm_types.h" @@ -80,6 +82,8 @@ class CryptoMetrics { public: CryptoMetrics(); + void Serialize(drm_metrics::MetricsGroup* metrics); + /* CRYPTO SESSION */ EventMetric crypto_session_delete_all_usage_reports_; EventMetric crypto_session_delete_multiple_usage_information_; @@ -173,6 +177,10 @@ class SessionMetrics { // This instance retains ownership of the object. CryptoMetrics* GetCryptoMetrics() { return &crypto_metrics_; } + // Serialize the session metrics to the provided |metric_group|. + // |metric_group| is owned by the caller and must not be null. + void Serialize(drm_metrics::MetricsGroup* metric_group); + // Metrics collected at the session level. EventMetric<> cdm_session_life_span_; EventMetric cdm_session_renew_key_; @@ -180,6 +188,7 @@ class SessionMetrics { EventMetric cdm_session_restore_usage_session_; private: + void SerializeSessionMetrics(drm_metrics::MetricsGroup* metric_group); CdmSessionId session_id_; bool completed_; CryptoMetrics crypto_metrics_; @@ -207,11 +216,16 @@ class EngineMetrics { // 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); + // Serialize engine and session metrics into a serialized MetricsGroup + // instance and output that instance to the provided |metric_group|. + // |metric_group| is owned by the caller and must NOT be null. + // |completed_only| indicates that this call should only publish + // SessionMetrics instances that are marked as completed. + // |clear_sessions| indicates that this call should clear sessions metrics + // for those sessions that were serialized. This allows atomic + // serialization and closing of session-level metrics. + void Serialize(drm_metrics::MetricsGroup* metric_group, bool completed_only, + bool clear_serialized_sessions); // Metrics recorded at the engine level. EventMetric cdm_engine_add_key_; @@ -236,6 +250,8 @@ class EngineMetrics { Lock session_metrics_lock_; std::vector session_metrics_list_; CryptoMetrics crypto_metrics_; + + void SerializeEngineMetrics(drm_metrics::MetricsGroup* out); }; } // namespace metrics diff --git a/libwvdrmengine/cdm/metrics/src/event_metric.cpp b/libwvdrmengine/cdm/metrics/src/event_metric.cpp index 0671418d..06e2ac51 100644 --- a/libwvdrmengine/cdm/metrics/src/event_metric.cpp +++ b/libwvdrmengine/cdm/metrics/src/event_metric.cpp @@ -43,15 +43,18 @@ void BaseEventMetric::Serialize(MetricSerializer* serializer) { serializer->SetDouble( metric_name_ + "/mean" + it->first, it->second->Mean()); - serializer->SetDouble( - metric_name_ + "/variance" + it->first, - it->second->Variance()); - serializer->SetDouble( - metric_name_ + "/min" + it->first, - it->second->Min()); - serializer->SetDouble( - metric_name_ + "/max" + it->first, - it->second->Max()); + // Only publish additional information if there was more than one sample. + if (it->second->Count() > 1) { + serializer->SetDouble( + metric_name_ + "/variance" + it->first, + it->second->Variance()); + serializer->SetDouble( + metric_name_ + "/min" + it->first, + it->second->Min()); + serializer->SetDouble( + metric_name_ + "/max" + it->first, + it->second->Max()); + } } } diff --git a/libwvdrmengine/cdm/metrics/src/metrics.proto b/libwvdrmengine/cdm/metrics/src/metrics.proto new file mode 100644 index 00000000..4df1fe53 --- /dev/null +++ b/libwvdrmengine/cdm/metrics/src/metrics.proto @@ -0,0 +1,36 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// This file contains a proto definition for serialization of metrics data. +// +syntax = "proto2"; + +package drm_metrics; + +// need this if we are using libprotobuf-cpp-2.3.0-lite +option optimize_for = LITE_RUNTIME; + +// The MetricsGroup is a collection of metric name/value pair instances +// that can be serialized and provided to a caller. +message MetricsGroup { + message Metric { + message MetricValue { + // Only one of the following values must be set. Note that the oneof + // keyword is not supported in the protobuf version checked into the CDM. + optional int64 int_value = 1; + optional double double_value = 2; + optional string string_value = 3; + } + + // The name of the metric. Must be valid UTF-8. Required. + optional string name = 1; + + // The value of the metric. Required. + optional MetricValue value = 2; + } + + // The list of name/value pairs of metrics. + repeated Metric metric = 1; + + // Allow multiple sub groups of metrics. + repeated MetricsGroup metric_sub_group = 2; +} diff --git a/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp b/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp index f0d06582..936cae8b 100644 --- a/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp +++ b/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp @@ -4,6 +4,11 @@ #include +#include "metrics.pb.h" + +using drm_metrics::MetricsGroup; +using wvcdm::metrics::MetricSerializer; + namespace { // Helper struct for comparing session ids. struct CompareSessionIds { @@ -16,6 +21,41 @@ struct CompareSessionIds { } }; +// Local class used to serialize to the MetricsGroup proto message. +class ProtoMetricSerializer : public wvcdm::metrics::MetricSerializer { + public: + ProtoMetricSerializer(MetricsGroup* metric_group) + : metric_group_(metric_group) {} + + virtual void SetString(const std::string& metric_id, + const std::string& value) { + MetricsGroup::Metric* metric = metric_group_->add_metric(); + metric->set_name(metric_id); + metric->mutable_value()->set_string_value(value); + } + + virtual void SetInt32(const std::string& metric_id, int32_t value) { + MetricsGroup::Metric* metric = metric_group_->add_metric(); + metric->set_name(metric_id); + metric->mutable_value()->set_int_value(value); + } + + virtual void SetInt64(const std::string& metric_id, int64_t value) { + MetricsGroup::Metric* metric = metric_group_->add_metric(); + metric->set_name(metric_id); + metric->mutable_value()->set_int_value(value); + } + + virtual void SetDouble(const std::string& metric_id, double value) { + MetricsGroup::Metric* metric = metric_group_->add_metric(); + metric->set_name(metric_id); + metric->mutable_value()->set_double_value(value); + } + + private: + MetricsGroup* metric_group_; +}; + } // anonymous namespace namespace wvcdm { @@ -241,6 +281,76 @@ CryptoMetrics::CryptoMetrics() : "version", "min_version") {} +void CryptoMetrics::Serialize(MetricsGroup* metrics) { + ProtoMetricSerializer serializer(metrics); + /* CRYPTO SESSION */ + crypto_session_delete_all_usage_reports_.Serialize(&serializer); + crypto_session_delete_multiple_usage_information_.Serialize(&serializer); + crypto_session_generic_decrypt_.Serialize(&serializer); + crypto_session_generic_encrypt_.Serialize(&serializer); + crypto_session_generic_sign_.Serialize(&serializer); + crypto_session_generic_verify_.Serialize(&serializer); + crypto_session_get_device_unique_id_.Serialize(&serializer); + crypto_session_get_security_level_.Serialize(&serializer); + crypto_session_get_system_id_.Serialize(&serializer); + crypto_session_get_token_.Serialize(&serializer); + crypto_session_life_span_.Serialize(&serializer); + crypto_session_load_certificate_private_key_.Serialize(&serializer); + crypto_session_open_.Serialize(&serializer); + crypto_session_update_usage_information_.Serialize(&serializer); + crypto_session_usage_information_support_.Serialize(&serializer); + + /* OEMCRYPTO */ + oemcrypto_api_version_.Serialize(&serializer); + oemcrypto_close_session_.Serialize(&serializer); + oemcrypto_copy_buffer_.Serialize(&serializer); + oemcrypto_deactivate_usage_entry_.Serialize(&serializer); + oemcrypto_decrypt_cenc_.Serialize(&serializer); + oemcrypto_delete_usage_entry_.Serialize(&serializer); + oemcrypto_delete_usage_table_.Serialize(&serializer); + oemcrypto_derive_keys_from_session_key_.Serialize(&serializer); + oemcrypto_force_delete_usage_entry_.Serialize(&serializer); + oemcrypto_generate_derived_keys_.Serialize(&serializer); + oemcrypto_generate_nonce_.Serialize(&serializer); + oemcrypto_generate_rsa_signature_.Serialize(&serializer); + oemcrypto_generate_signature_.Serialize(&serializer); + oemcrypto_generic_decrypt_.Serialize(&serializer); + oemcrypto_generic_encrypt_.Serialize(&serializer); + oemcrypto_generic_sign_.Serialize(&serializer); + oemcrypto_generic_verify_.Serialize(&serializer); + oemcrypto_get_device_id_.Serialize(&serializer); + oemcrypto_get_hdcp_capability_.Serialize(&serializer); + oemcrypto_get_key_data_.Serialize(&serializer); + oemcrypto_get_max_number_of_sessions_.Serialize(&serializer); + oemcrypto_get_number_of_open_sessions_.Serialize(&serializer); + oemcrypto_get_oem_public_certificate_.Serialize(&serializer); + oemcrypto_get_provisioning_method_.Serialize(&serializer); + oemcrypto_get_random_.Serialize(&serializer); + oemcrypto_initialize_.Serialize(&serializer); + oemcrypto_install_keybox_.Serialize(&serializer); + oemcrypto_is_anti_rollback_hw_present_.Serialize(&serializer); + oemcrypto_is_keybox_valid_.Serialize(&serializer); + oemcrypto_load_device_rsa_key_.Serialize(&serializer); + oemcrypto_load_keys_.Serialize(&serializer); + oemcrypto_load_test_keybox_.Serialize(&serializer); + oemcrypto_load_test_rsa_key_.Serialize(&serializer); + oemcrypto_open_session_.Serialize(&serializer); + oemcrypto_refresh_keys_.Serialize(&serializer); + oemcrypto_report_usage_.Serialize(&serializer); + oemcrypto_rewrap_device_rsa_key_.Serialize(&serializer); + oemcrypto_rewrap_device_rsa_key_30_.Serialize(&serializer); + oemcrypto_security_level_.Serialize(&serializer); + oemcrypto_security_patch_level_.Serialize(&serializer); + oemcrypto_select_key_.Serialize(&serializer); + oemcrypto_supports_usage_table_.Serialize(&serializer); + oemcrypto_update_usage_table_.Serialize(&serializer); + oemcrypto_wrap_keybox_.Serialize(&serializer); + + /* Internal OEMCrypto Metrics */ + oemcrypto_initialization_mode_.Serialize(&serializer); + oemcrypto_l1_api_version_.Serialize(&serializer); +} + SessionMetrics::SessionMetrics() : cdm_session_life_span_( "/drm/widevine/cdm_session/life_span/time"), @@ -256,6 +366,21 @@ SessionMetrics::SessionMetrics() : completed_(false) { } +void SessionMetrics::Serialize(MetricsGroup* metric_group) { + SerializeSessionMetrics(metric_group); + crypto_metrics_.Serialize(metric_group); +} + +void SessionMetrics::SerializeSessionMetrics(MetricsGroup* metric_group) { + ProtoMetricSerializer serializer(metric_group); + // Add the session id as a single-valued metric. + serializer.SetString("/drm/widevine/cdm_session/session_id", session_id_); + cdm_session_life_span_.Serialize(&serializer); + cdm_session_renew_key_.Serialize(&serializer); + cdm_session_restore_offline_session_.Serialize(&serializer); + cdm_session_restore_usage_session_.Serialize(&serializer); +} + EngineMetrics::EngineMetrics() : cdm_engine_add_key_( "/drm/widevine/cdm_engine/add_key/time", @@ -336,8 +461,51 @@ void EngineMetrics::RemoveSession(wvcdm::CdmSessionId session_id) { session_metrics_list_.end()); } -void JsonSerialize(std::string* out, bool completed_only) { - // TODO(blueeyes): Implement this. +void EngineMetrics::Serialize(drm_metrics::MetricsGroup* metric_group, + bool completed_only, + bool clear_serialized_sessions) { + AutoLock lock(session_metrics_lock_); + + SerializeEngineMetrics(metric_group); + std::vector::iterator i; + for (i = session_metrics_list_.begin(); i != session_metrics_list_.end(); + /* no increment */) { + bool serialized = false; + if (!completed_only || (*i)->IsCompleted()) { + (*i)->Serialize(metric_group->add_metric_sub_group()); + serialized = true; + } + + // Clear the serialized session metrics if requested. + if (serialized && clear_serialized_sessions) { + session_metrics_list_.erase(i); + } else { + i++; + } + } +} + +void EngineMetrics::SerializeEngineMetrics(MetricsGroup* metric_group) { + ProtoMetricSerializer serializer(metric_group); + cdm_engine_add_key_.Serialize(&serializer); + cdm_engine_close_session_.Serialize(&serializer); + cdm_engine_decrypt_.Serialize(&serializer); + cdm_engine_find_session_for_key_.Serialize(&serializer); + cdm_engine_generate_key_request_.Serialize(&serializer); + cdm_engine_get_provisioning_request_.Serialize(&serializer); + cdm_engine_get_usage_info_.Serialize(&serializer); + cdm_engine_handle_provisioning_response_.Serialize(&serializer); + cdm_engine_life_span_.Serialize(&serializer); + cdm_engine_open_key_set_session_.Serialize(&serializer); + cdm_engine_open_session_.Serialize(&serializer); + cdm_engine_query_key_status_.Serialize(&serializer); + cdm_engine_release_all_usage_info_.Serialize(&serializer); + cdm_engine_release_usage_info_.Serialize(&serializer); + cdm_engine_remove_keys_.Serialize(&serializer); + cdm_engine_restore_key_.Serialize(&serializer); + cdm_engine_unprovision_.Serialize(&serializer); + + crypto_metrics_.Serialize(metric_group); } } // metrics diff --git a/libwvdrmengine/cdm/metrics/test/event_metric_test.cpp b/libwvdrmengine/cdm/metrics/test/event_metric_test.cpp index dc0c410c..ac376308 100644 --- a/libwvdrmengine/cdm/metrics/test/event_metric_test.cpp +++ b/libwvdrmengine/cdm/metrics/test/event_metric_test.cpp @@ -61,7 +61,7 @@ TEST_F(EventMetricTest, NoFieldsSuccessNullCallback) { TEST_F(EventMetricTest, NoFieldsSuccessWithCallback) { wvcdm::metrics::EventMetric<> metric("no/fields/metric"); EXPECT_CALL(*mock_serializer_, - SetInt64("no/fields/metric/count", 1.0)); + SetInt64("no/fields/metric/count", 2)); EXPECT_CALL(*mock_serializer_, SetDouble("no/fields/metric/mean", 10.0)); EXPECT_CALL(*mock_serializer_, @@ -71,6 +71,23 @@ TEST_F(EventMetricTest, NoFieldsSuccessWithCallback) { EXPECT_CALL(*mock_serializer_, SetDouble("no/fields/metric/max", 10.0)); + metric.Record(10); + metric.Record(10); + metric.Serialize(mock_serializer_.get()); + + std::map value_map = GetValueMap(metric); + ASSERT_EQ(1u, GetValueMap(metric).size()); + EXPECT_EQ(2, value_map.begin()->second->Count()); + EXPECT_EQ("", value_map.begin()->first); +} + +TEST_F(EventMetricTest, NoFieldsSuccessSingleRecordWithCallback) { + wvcdm::metrics::EventMetric<> metric("no/fields/metric"); + EXPECT_CALL(*mock_serializer_, + SetInt64("no/fields/metric/count", 1.0)); + EXPECT_CALL(*mock_serializer_, + SetDouble("no/fields/metric/mean", 10.0)); + metric.Record(10); metric.Serialize(mock_serializer_.get()); diff --git a/libwvdrmengine/cdm/metrics/test/metrics_collections_test.cpp b/libwvdrmengine/cdm/metrics/test/metrics_collections_test.cpp new file mode 100644 index 00000000..7a724e19 --- /dev/null +++ b/libwvdrmengine/cdm/metrics/test/metrics_collections_test.cpp @@ -0,0 +1,444 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Unit tests for the metrics collections, +// EngineMetrics, SessionMetrics and CrytpoMetrics. + +#include "metrics_collections.h" + +#include + +#include "gmock/gmock.h" +#include "google/protobuf/text_format.h" +#include "gtest/gtest.h" +#include "log.h" +#include "metrics.pb.h" +#include "wv_cdm_types.h" + +using drm_metrics::MetricsGroup; +using google::protobuf::TextFormat; + +namespace wvcdm { +namespace metrics { + +// TODO(blueeyes): Improve this implementation by supporting full message +// API In CDM. That allows us to use MessageDifferencer. +class EngineMetricsTest : public ::testing::Test { +}; + +TEST_F(EngineMetricsTest, AllEngineMetrics) { + EngineMetrics engine_metrics; + + // Set some values in all of the engine metrics. + engine_metrics.cdm_engine_add_key_.Record(1.0, KEY_ADDED); + engine_metrics.cdm_engine_close_session_.Record(1.0, NO_ERROR); + engine_metrics.cdm_engine_decrypt_.Record(1.0, NO_ERROR); + engine_metrics.cdm_engine_find_session_for_key_.Record(1.0, false); + engine_metrics.cdm_engine_generate_key_request_.Record(1.0, NO_ERROR); + engine_metrics.cdm_engine_get_provisioning_request_.Record(1.0, NO_ERROR); + engine_metrics.cdm_engine_get_usage_info_.Record(1.0, NO_ERROR); + engine_metrics.cdm_engine_handle_provisioning_response_.Record(1.0, NO_ERROR); + engine_metrics.cdm_engine_life_span_.Record(1.0); + engine_metrics.cdm_engine_open_key_set_session_.Record(1.0, NO_ERROR); + engine_metrics.cdm_engine_open_session_.Record(1.0, NO_ERROR); + engine_metrics.cdm_engine_query_key_status_.Record(1.0, NO_ERROR); + engine_metrics.cdm_engine_release_all_usage_info_.Record(1.0, NO_ERROR); + engine_metrics.cdm_engine_release_usage_info_.Record(1.0, NO_ERROR); + engine_metrics.cdm_engine_remove_keys_.Record(1.0, NO_ERROR); + engine_metrics.cdm_engine_restore_key_.Record(1.0, NO_ERROR); + engine_metrics.cdm_engine_unprovision_.Record(1.0, NO_ERROR, kSecurityLevelL1); + + drm_metrics::MetricsGroup actual_metrics; + engine_metrics.Serialize(&actual_metrics, true, false); + + // For each EventMetric, 2 metrics get serialized since only one sample was + // taken. So, the total number of serialized metrics are 2*17. + ASSERT_EQ(2 * 17, actual_metrics.metric_size()); + EXPECT_EQ(0, actual_metrics.metric_sub_group_size()); + + // Spot check some metrics. + EXPECT_EQ("/drm/widevine/cdm_engine/add_key/time/count{error:2}", + actual_metrics.metric(0).name()); + EXPECT_EQ("/drm/widevine/cdm_engine/close_session/time/mean{error:0}", + actual_metrics.metric(3).name()); + EXPECT_EQ("/drm/widevine/cdm_engine/decrypt/time/mean{error:0}", + actual_metrics.metric(5).name()); + EXPECT_EQ(1.0, actual_metrics.metric(5).value().double_value()); +} + +TEST_F(EngineMetricsTest, EngineAndCryptoMetrics) { + EngineMetrics engine_metrics; + + // Set some values in some of the engine metrics and some crypto metrics. + engine_metrics.cdm_engine_add_key_.Record(1.0, KEY_ADDED); + engine_metrics.cdm_engine_close_session_.Record(1.0, NO_ERROR); + CryptoMetrics* crypto_metrics = engine_metrics.GetCryptoMetrics(); + + crypto_metrics->crypto_session_generic_decrypt_ + .Record(2.0, NO_ERROR, Pow2Bucket(1025), kEncryptionAlgorithmAesCbc128); + crypto_metrics->crypto_session_get_device_unique_id_ + .Record(4.0, false); + + drm_metrics::MetricsGroup actual_metrics; + engine_metrics.Serialize(&actual_metrics, true, false); + + // For each EventMetric, 2 metrics get serialized since only one sample was + // taken. So, the total number of serialized metrics are 2*4 since we + // touched 4 metrics. + ASSERT_EQ(2 * 4, actual_metrics.metric_size()); + EXPECT_EQ(0, actual_metrics.metric_sub_group_size()); + + // Spot check some metrics. + EXPECT_EQ("/drm/widevine/cdm_engine/add_key/time/count{error:2}", + actual_metrics.metric(0).name()); + EXPECT_EQ( + "/drm/widevine/crypto_session/generic_decrypt/time/count" + "{error:0&length:1024&algorithm:1}", + actual_metrics.metric(4).name()); + EXPECT_EQ( + "/drm/widevine/crypto_session/get_device_unique_id/time/mean{success:0}", + actual_metrics.metric(7).name()); + EXPECT_EQ(4.0, actual_metrics.metric(7).value().double_value()); +} + +TEST_F(EngineMetricsTest, EmptyEngineMetrics) { + EngineMetrics engine_metrics; + + drm_metrics::MetricsGroup actual_metrics; + engine_metrics.Serialize(&actual_metrics, true, false); + + EXPECT_EQ(0, actual_metrics.metric_size()); + EXPECT_EQ(0, actual_metrics.metric_sub_group_size()); +} + +TEST_F(EngineMetricsTest, EngineMetricsWithCompletedSessions) { + EngineMetrics engine_metrics; + + // Set a values in an engine metric and in a crypto metric. + engine_metrics.cdm_engine_add_key_.Record(1.0, KEY_ADDED); + engine_metrics.GetCryptoMetrics() + ->crypto_session_load_certificate_private_key_.Record(2.0, true); + + // Create two sessions and record some metrics. + SessionMetrics* session_metrics_1 = engine_metrics.AddSession(); + session_metrics_1->SetSessionId("session_id_1"); + SessionMetrics* session_metrics_2 = engine_metrics.AddSession(); + session_metrics_2->SetSessionId("session_id_2"); + // Record a CryptoMetrics metric in the session. + session_metrics_2->GetCryptoMetrics()->crypto_session_generic_decrypt_ + .Record(2.0, NO_ERROR, Pow2Bucket(1025), kEncryptionAlgorithmAesCbc128); + session_metrics_2->SetSessionId("session_id_2"); + // Mark only session 2 as completed. + session_metrics_2->SetCompleted(); + + drm_metrics::MetricsGroup actual_metrics; + engine_metrics.Serialize(&actual_metrics, true, false); + + // Validate metric counts. + // For each EventMetric, 2 metrics get serialized since only one sample was + // taken. So, the total number of serialized metrics are 2*2 since we + // touched 2 metrics. + ASSERT_EQ(2 * 2, actual_metrics.metric_size()); + ASSERT_EQ(1, actual_metrics.metric_sub_group_size()); + ASSERT_EQ(3, actual_metrics.metric_sub_group(0).metric_size()); + + // Spot check some metrics. + EXPECT_EQ("/drm/widevine/cdm_engine/add_key/time/count{error:2}", + actual_metrics.metric(0).name()); + EXPECT_EQ("/drm/widevine/crypto_session/load_certificate_private_key" + "/time/count{success:1}", + actual_metrics.metric(2).name()); + EXPECT_EQ("/drm/widevine/cdm_session/session_id", + actual_metrics.metric_sub_group(0).metric(0).name()); + EXPECT_EQ( + "session_id_2", + actual_metrics.metric_sub_group(0).metric(0).value().string_value()); + EXPECT_EQ( + "/drm/widevine/crypto_session/generic_decrypt/time/count" + "{error:0&length:1024&algorithm:1}", + actual_metrics.metric_sub_group(0).metric(1).name()); +} + +TEST_F(EngineMetricsTest, EngineMetricsSerializeAllSessions) { + EngineMetrics engine_metrics; + + // Create two sessions and record some metrics. + SessionMetrics* session_metrics_1 = engine_metrics.AddSession(); + session_metrics_1->SetSessionId("session_id_1"); + SessionMetrics* session_metrics_2 = engine_metrics.AddSession(); + session_metrics_2->SetSessionId("session_id_2"); + // Mark only session 2 as completed. + session_metrics_2->SetCompleted(); + + drm_metrics::MetricsGroup actual_metrics; + engine_metrics.Serialize(&actual_metrics, false, false); + + // Validate metric counts. + // No Engine-level metrics were recorded. + ASSERT_EQ(0, actual_metrics.metric_size()); + // Two sub groups, 1 per session. + ASSERT_EQ(2, actual_metrics.metric_sub_group_size()); + ASSERT_EQ(1, actual_metrics.metric_sub_group(0).metric_size()); + + // Spot check some metrics. + EXPECT_EQ("/drm/widevine/cdm_session/session_id", + actual_metrics.metric_sub_group(0).metric(0).name()); + EXPECT_EQ( + "session_id_1", + actual_metrics.metric_sub_group(0).metric(0).value().string_value()); + EXPECT_EQ("/drm/widevine/cdm_session/session_id", + actual_metrics.metric_sub_group(1).metric(0).name()); + EXPECT_EQ( + "session_id_2", + actual_metrics.metric_sub_group(1).metric(0).value().string_value()); +} + +TEST_F(EngineMetricsTest, EngineMetricsRemoveSessions) { + EngineMetrics engine_metrics; + + // Create two sessions and record some metrics. + SessionMetrics* session_metrics_1 = engine_metrics.AddSession(); + session_metrics_1->SetSessionId("session_id_1"); + SessionMetrics* session_metrics_2 = engine_metrics.AddSession(); + session_metrics_2->SetSessionId("session_id_2"); + // Mark only session 2 as completed. + session_metrics_2->SetCompleted(); + + // Serialize all metrics, don't remove any. + drm_metrics::MetricsGroup actual_metrics; + engine_metrics.Serialize(&actual_metrics, false, false); + + // Validate metric counts. + // Two sub groups, 1 per session. + ASSERT_EQ(2, actual_metrics.metric_sub_group_size()); + + // Serialize completed metrics, remove them. + actual_metrics.Clear(); + engine_metrics.Serialize(&actual_metrics, true, true); + // Validate metric counts. + // Only one, completed session should exist. + ASSERT_EQ(1, actual_metrics.metric_sub_group_size()); + ASSERT_EQ(1, actual_metrics.metric_sub_group(0).metric_size()); + EXPECT_EQ( + "session_id_2", + actual_metrics.metric_sub_group(0).metric(0).value().string_value()); + + // Serialize all metrics, remove them. + actual_metrics.Clear(); + engine_metrics.Serialize(&actual_metrics, false, true); + // Validate metric counts. + // Only one, non-complete session should exist. + ASSERT_EQ(1, actual_metrics.metric_sub_group_size()); + ASSERT_EQ(1, actual_metrics.metric_sub_group(0).metric_size()); + EXPECT_EQ( + "session_id_1", + actual_metrics.metric_sub_group(0).metric(0).value().string_value()); + + // Serialize all metrics, don't remove any. + actual_metrics.Clear(); + engine_metrics.Serialize(&actual_metrics, false, false); + // Validate metric counts. + // There should be no more metric subgroups left. + ASSERT_EQ(0, actual_metrics.metric_sub_group_size()); +} + +class SessionMetricsTest : public ::testing::Test { +}; + +TEST_F(SessionMetricsTest, AllSessionMetrics) { + SessionMetrics session_metrics; + session_metrics.SetSessionId("session_id 1"); + + session_metrics.cdm_session_life_span_.Record(1.0); + session_metrics.cdm_session_renew_key_.Record(1.0, NO_ERROR); + session_metrics.cdm_session_restore_offline_session_.Record(1.0, NO_ERROR); + session_metrics.cdm_session_restore_usage_session_.Record(1.0, NO_ERROR); + + // Record a CryptoMetrics metric in the session. + session_metrics.GetCryptoMetrics()->crypto_session_generic_decrypt_ + .Record(2.0, NO_ERROR, Pow2Bucket(1025), kEncryptionAlgorithmAesCbc128); + + MetricsGroup actual_metrics; + session_metrics.Serialize(&actual_metrics); + + ASSERT_EQ(11, actual_metrics.metric_size()); + EXPECT_EQ(0, actual_metrics.metric_sub_group_size()); + + // Spot check some metrics. + EXPECT_EQ("/drm/widevine/cdm_session/session_id", + actual_metrics.metric(0).name()); + EXPECT_EQ("/drm/widevine/cdm_session/life_span/time/count", + actual_metrics.metric(1).name()); + EXPECT_EQ("/drm/widevine/cdm_session/renew_key/time/mean{error:0}", + actual_metrics.metric(4).name()); + EXPECT_EQ(1.0, actual_metrics.metric(4).value().double_value()); + EXPECT_EQ("/drm/widevine/crypto_session/generic_decrypt/time/count" + "{error:0&length:1024&algorithm:1}", + actual_metrics.metric(9).name()); +} + +TEST_F(SessionMetricsTest, EmptySessionMetrics) { + SessionMetrics session_metrics; + + MetricsGroup actual_metrics; + session_metrics.Serialize(&actual_metrics); + + // Session metric always has a session id. + ASSERT_EQ(1, actual_metrics.metric_size()); + EXPECT_EQ("/drm/widevine/cdm_session/session_id", + actual_metrics.metric(0).name()); + EXPECT_EQ("", actual_metrics.metric(0).value().string_value()); + EXPECT_EQ(0, actual_metrics.metric_sub_group_size()); +} + +class CryptoMetricsTest : public ::testing::Test { +}; + +TEST_F(CryptoMetricsTest, AllCryptoMetrics) { + CryptoMetrics crypto_metrics; + + // Crypto session metrics. + crypto_metrics.crypto_session_delete_all_usage_reports_ + .Record(1.0, NO_ERROR); + crypto_metrics.crypto_session_delete_multiple_usage_information_ + .Record(1.0, NO_ERROR); + crypto_metrics.crypto_session_generic_decrypt_ + .Record(2.0, NO_ERROR, Pow2Bucket(1025), kEncryptionAlgorithmAesCbc128); + crypto_metrics.crypto_session_generic_encrypt_ + .Record(2.0, NO_ERROR, Pow2Bucket(1025), kEncryptionAlgorithmAesCbc128); + crypto_metrics.crypto_session_generic_sign_ + .Record(2.0, NO_ERROR, Pow2Bucket(1025), kSigningAlgorithmHmacSha256); + crypto_metrics.crypto_session_generic_verify_ + .Record(2.0, NO_ERROR, Pow2Bucket(1025), kSigningAlgorithmHmacSha256); + crypto_metrics.crypto_session_get_device_unique_id_.Record(1.0, true); + crypto_metrics.crypto_session_get_security_level_ + .Record(1.0, kSecurityLevelL1); + crypto_metrics.crypto_session_get_system_id_.Record(1.0, true, 1234); + crypto_metrics.crypto_session_get_token_.Record(1.0, true); + crypto_metrics.crypto_session_life_span_.Record(1.0); + crypto_metrics.crypto_session_load_certificate_private_key_ + .Record(1.0, true); + crypto_metrics.crypto_session_open_.Record(1.0, NO_ERROR, kLevelDefault); + crypto_metrics.crypto_session_update_usage_information_ + .Record(1.0, NO_ERROR); + crypto_metrics.crypto_session_usage_information_support_.Record(1.0, true); + + // Oem crypto metrics. + crypto_metrics.oemcrypto_api_version_.Record(1.0, 123, kLevelDefault); + crypto_metrics.oemcrypto_close_session_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_copy_buffer_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, + kLevelDefault, Pow2Bucket(1025)); + crypto_metrics.oemcrypto_deactivate_usage_entry_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_decrypt_cenc_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, Pow2Bucket(1025)); + crypto_metrics.oemcrypto_delete_usage_entry_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_delete_usage_table_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_derive_keys_from_session_key_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_force_delete_usage_entry_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_generate_derived_keys_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_generate_nonce_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_generate_rsa_signature_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, Pow2Bucket(1025)); + crypto_metrics.oemcrypto_generate_signature_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, Pow2Bucket(1025)); + crypto_metrics.oemcrypto_generic_decrypt_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, Pow2Bucket(1025)); + crypto_metrics.oemcrypto_generic_encrypt_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, Pow2Bucket(1025)); + crypto_metrics.oemcrypto_generic_sign_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, Pow2Bucket(1025)); + crypto_metrics.oemcrypto_generic_verify_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, Pow2Bucket(1025)); + crypto_metrics.oemcrypto_get_device_id_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, kLevelDefault); + crypto_metrics.oemcrypto_get_hdcp_capability_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, kLevelDefault); + crypto_metrics.oemcrypto_get_key_data_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, + Pow2Bucket(1025), kLevelDefault); + crypto_metrics.oemcrypto_get_max_number_of_sessions_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, kLevelDefault); + crypto_metrics.oemcrypto_get_number_of_open_sessions_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, kLevelDefault); + crypto_metrics.oemcrypto_get_oem_public_certificate_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + + crypto_metrics.oemcrypto_get_provisioning_method_ + .Record(1.0, OEMCrypto_Keybox, kLevelDefault); + + crypto_metrics.oemcrypto_get_random_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, Pow2Bucket(1025)); + crypto_metrics.oemcrypto_initialize_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_install_keybox_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, kLevelDefault); + crypto_metrics.oemcrypto_is_anti_rollback_hw_present_ + .Record(1.0, true, kLevelDefault); + + crypto_metrics.oemcrypto_is_keybox_valid_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, kLevelDefault); + crypto_metrics.oemcrypto_load_device_rsa_key_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_load_keys_.Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_load_test_keybox_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_load_test_rsa_key_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_open_session_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, kLevelDefault); + crypto_metrics.oemcrypto_refresh_keys_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_report_usage_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_rewrap_device_rsa_key_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_rewrap_device_rsa_key_30_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_security_level_.Record(1.0, "test", kLevelDefault); + crypto_metrics.oemcrypto_security_patch_level_ + .Record(1.0, 123, kLevelDefault); + crypto_metrics.oemcrypto_select_key_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_supports_usage_table_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED, kLevelDefault); + crypto_metrics.oemcrypto_update_usage_table_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_wrap_keybox_ + .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + + // Internal OEMCrypto Metrics + crypto_metrics.oemcrypto_initialization_mode_ + .Record(1.0, OEMCrypto_INITIALIZED_FORCING_L3); + crypto_metrics.oemcrypto_l1_api_version_.Record(1.0, 12, 123); + + MetricsGroup actual_metrics; + crypto_metrics.Serialize(&actual_metrics); + + // 61 EventMetric instances, 2 values each. + ASSERT_EQ(122, actual_metrics.metric_size()); + + // Spot check some metrics. + EXPECT_EQ( + "/drm/widevine/crypto_session/delete_all_usage_reports/time/count" + "{error:0}", + actual_metrics.metric(0).name()); + EXPECT_EQ(1, actual_metrics.metric(0).value().int_value()); + EXPECT_EQ( + "/drm/widevine/oemcrypto/l1_api_version/mean{version:12&min_version:123}", + actual_metrics.metric(121).name()); + EXPECT_EQ(1.0, actual_metrics.metric(121).value().double_value()); + + // No subgroups should exist. + EXPECT_EQ(0, actual_metrics.metric_sub_group_size()); +} + +} // namespace metrics +} // namespace wvcdm From a0da1f067b603ae82aaf3b1f8b58c2401b48ecc8 Mon Sep 17 00:00:00 2001 From: Adam Stone Date: Thu, 30 Mar 2017 11:31:51 -0700 Subject: [PATCH 3/3] Support GetPropertyByteArray for getting metrics. Adds support for GetPropertyByteArray to return a serialized set of metrics to the caller. This should be the last part of the widevine plugin changes that fix the referenced bug. More changes are coming on the MediaDrm side. This is a merge of wvgerrit/28422 I intend to submit 2048751, 2048750, and 2048509 together. Bug: 36217927 Test: Added additional unit tests for affected code. Change-Id: I2618c2be48d7d780127e35f237e2276efd080879 --- libwvdrmengine/cdm/Android.mk | 3 +- libwvdrmengine/cdm/include/ami_adapter.h | 7 ++-- .../include/wv_content_decryption_module.h | 7 ++-- libwvdrmengine/cdm/src/ami_adapter.cpp | 4 --- .../cdm/src/wv_content_decryption_module.cpp | 35 +++++++++++-------- libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp | 5 ++- .../mediadrm/src_hidl/WVDrmPlugin.cpp | 4 +++ .../mediadrm/test/WVDrmPlugin_test.cpp | 28 ++++++++++++++- .../test/legacy_src/WVDrmPlugin_test.cpp | 24 ++++++++++++- 9 files changed, 85 insertions(+), 32 deletions(-) diff --git a/libwvdrmengine/cdm/Android.mk b/libwvdrmengine/cdm/Android.mk index bf02ae64..9c54844b 100644 --- a/libwvdrmengine/cdm/Android.mk +++ b/libwvdrmengine/cdm/Android.mk @@ -39,8 +39,7 @@ LOCAL_SRC_FILES := \ $(SRC_DIR)/wv_content_decryption_module.cpp \ $(METRICS_SRC_DIR)/distribution.cpp \ $(METRICS_SRC_DIR)/event_metric.cpp \ - $(METRICS_SRC_DIR)/metrics_front_end.cpp \ - $(METRICS_SRC_DIR)/metrics_group.cpp \ + $(METRICS_SRC_DIR)/metrics_collections.cpp \ $(METRICS_SRC_DIR)/timer_metric.cpp \ diff --git a/libwvdrmengine/cdm/include/ami_adapter.h b/libwvdrmengine/cdm/include/ami_adapter.h index 75999233..42bc4b1f 100644 --- a/libwvdrmengine/cdm/include/ami_adapter.h +++ b/libwvdrmengine/cdm/include/ami_adapter.h @@ -4,22 +4,19 @@ #define CDM_AMI_ADAPTER_H_ #include +#include #include -#include "report.h" - namespace wvcdm { -class AmiAdapter : public metrics::Report { +class AmiAdapter { public: AmiAdapter(); AmiAdapter(int64_t parent); ~AmiAdapter(); - metrics::Report* NewReport() const; - void UpdateString(const std::string& metric_id, const std::string& value); void UpdateInt32(const std::string& metric_id, int32_t value); void UpdateInt64(const std::string& metric_id, int64_t value); diff --git a/libwvdrmengine/cdm/include/wv_content_decryption_module.h b/libwvdrmengine/cdm/include/wv_content_decryption_module.h index 8d0b5d27..11cf96cb 100644 --- a/libwvdrmengine/cdm/include/wv_content_decryption_module.h +++ b/libwvdrmengine/cdm/include/wv_content_decryption_module.h @@ -11,7 +11,6 @@ #include "cdm_identifier.h" #include "file_store.h" #include "lock.h" -#include "metrics_front_end.h" #include "timer.h" #include "wv_cdm_types.h" @@ -122,6 +121,9 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler { // Validate a passed-in service certificate virtual bool IsValidServiceCertificate(const std::string& certificate); + // Retrieve the serialized metrics from the CDM. + virtual void GetSerializedMetrics(std::string* serialized_metrics); + private: struct CdmInfo { CdmInfo(); @@ -156,9 +158,6 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler { // This contains weak pointers to the CDM instances contained in |cdms_|. std::map cdm_by_session_id_; - metrics::Report* report_root_; - metrics::MetricsFrontEnd* front_end_; - CORE_DISALLOW_COPY_AND_ASSIGN(WvContentDecryptionModule); }; diff --git a/libwvdrmengine/cdm/src/ami_adapter.cpp b/libwvdrmengine/cdm/src/ami_adapter.cpp index 73dd4ee9..4c7cfc29 100644 --- a/libwvdrmengine/cdm/src/ami_adapter.cpp +++ b/libwvdrmengine/cdm/src/ami_adapter.cpp @@ -22,10 +22,6 @@ AmiAdapter::~AmiAdapter() { analytics_item_.selfrecord(); } -metrics::Report* AmiAdapter::NewReport() const { - return new AmiAdapter(analytics_item_.getSessionID()); -} - void AmiAdapter::UpdateString(const std::string& metric_id, const std::string& value) { analytics_item_.setCString(metric_id.c_str(), value.c_str()); diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index 6668fc60..21fecfe5 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -7,7 +7,7 @@ #include "initialization_data.h" #include "license.h" #include "log.h" -#include "metrics_front_end.h" +#include "metrics.pb.h" #include "properties.h" #include "service_certificate.h" #include "wv_cdm_constants.h" @@ -21,22 +21,10 @@ namespace wvcdm { Lock WvContentDecryptionModule::session_sharing_id_generation_lock_; -WvContentDecryptionModule::WvContentDecryptionModule() { - // TODO (b/36497276) - // replace call to new AmiAdapter() and remove ami_apdater.* - report_root_ = NULL; // new AmiAdapter(); - front_end_ = new metrics::MetricsFrontEnd(report_root_); - metrics::MetricsFrontEnd::OverrideInstance(front_end_); -} +WvContentDecryptionModule::WvContentDecryptionModule() {} WvContentDecryptionModule::~WvContentDecryptionModule() { DisablePolicyTimer(true); - - metrics::MetricsFrontEnd::OverrideInstance(NULL); - delete front_end_; - delete report_root_; - front_end_ = NULL; - report_root_ = NULL; } bool WvContentDecryptionModule::IsSupported(const std::string& init_data_type) { @@ -406,6 +394,25 @@ bool WvContentDecryptionModule::IsValidServiceCertificate( NO_ERROR; } +void WvContentDecryptionModule::GetSerializedMetrics( + std::string* serialized_metrics) { + drm_metrics::MetricsGroup metric_group; + { + AutoLock auto_lock(cdms_lock_); + for (auto it = cdms_.begin(); it != cdms_.end(); it++) { + metrics::EngineMetrics* engine_metrics = + it->second.cdm_engine->GetMetrics(); + if (engine_metrics) { + // Serialize the metrics from the engine and any completed sessions. + // Clear the metrics from any completed sessions. + engine_metrics->Serialize( + metric_group.add_metric_sub_group(), true, true); + } + } + } + metric_group.SerializeToString(serialized_metrics); +} + WvContentDecryptionModule::CdmInfo::CdmInfo() : cdm_engine(new CdmEngine(&file_system)) {} diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp index 5a8603cc..b5607418 100644 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp @@ -528,13 +528,16 @@ status_t WVDrmPlugin::getPropertyString(const String8& name, status_t WVDrmPlugin::getPropertyByteArray(const String8& name, Vector& value) const { - if (name == "deviceUniqueId") { return queryProperty(QUERY_KEY_DEVICE_ID, value); } else if (name == "provisioningUniqueId") { return queryProperty(QUERY_KEY_PROVISIONING_ID, value); } else if (name == "serviceCertificate") { value = ToVector(mPropertySet.service_certificate()); + } else if (name == "metrics") { + std::string metrics_value; + mCDM->GetSerializedMetrics(&metrics_value); + value = ToVector(metrics_value); } else { ALOGE("App requested unknown byte array property %s", name.string()); return android::ERROR_DRM_CANNOT_HANDLE; diff --git a/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp index bcbe9903..0c7941bc 100644 --- a/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp @@ -685,6 +685,10 @@ Return WVDrmPlugin::getPropertyByteArray( } } else if (name == "serviceCertificate") { value = StrToVector(mPropertySet.service_certificate()); + } else if (name == "metrics") { + std::string metrics_value; + mCDM->GetSerializedMetrics(&metrics_value); + value = StrToVector(metrics_value); } else { ALOGE("App requested unknown byte array property %s", name.c_str()); status = android::ERROR_DRM_CANNOT_HANDLE; diff --git a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp index 9d20462d..e08bb45d 100644 --- a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp +++ b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp @@ -114,7 +114,17 @@ const std::string kAppId("com.unittest.mock.app.id"); const uint8_t* const kUnprovisionResponse = reinterpret_cast("unprovision"); const size_t kUnprovisionResponseSize = 11; -} +const std::string kDeviceId = "0123456789ABCDEF"; + +// This is a serialized MetricsGroup message containing a small amount of +// sample data. This ensures we're able to extract it via a property. +const char kSerializedMetrics[] = { + 0x0a, 0x0a, 0x0a, 0x04, 0x74, 0x65, 0x73, 0x74, 0x12, 0x02, 0x08, 0x00, + 0x0a, 0x12, 0x0a, 0x05, 0x74, 0x65, 0x73, 0x74, 0x32, 0x12, 0x09, 0x11, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x15, 0x0a, 0x05, + 0x74, 0x65, 0x73, 0x74, 0x33, 0x12, 0x0c, 0x1a, 0x0a, 0x74, 0x65, 0x73, + 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65}; +} // anonymous namespace class MockCDM : public WvContentDecryptionModule { public: @@ -177,6 +187,8 @@ class MockCDM : public WvContentDecryptionModule { CdmResponseType(const CdmUsageInfoReleaseMessage&)); MOCK_METHOD1(IsValidServiceCertificate, bool(const std::string&)); + + MOCK_METHOD1(GetSerializedMetrics, void(std::string*)); }; class MockCrypto : public WVGenericCryptoInterface { @@ -1040,6 +1052,8 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { static const std::string openSessions = "42"; static const std::string maxSessions = "54"; static const std::string oemCryptoApiVersion = "13"; + std::string serializedMetrics( + kSerializedMetrics, kSerializedMetrics + sizeof(kSerializedMetrics)); EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1), @@ -1071,6 +1085,9 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { .WillOnce(DoAll(SetArgPointee<2>(oemCryptoApiVersion), testing::Return(wvcdm::NO_ERROR))); + EXPECT_CALL(*cdm, GetSerializedMetrics(_)) + .WillOnce(SetArgPointee<0>(serializedMetrics)); + WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); std::string stringResult; std::vector vectorResult; @@ -1157,6 +1174,15 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { ASSERT_EQ(Status::OK, status); EXPECT_EQ(oemCryptoApiVersion, stringResult.c_str()); }); + + plugin.getPropertyByteArray( + hidl_string("metrics"), + [&](Status status, hidl_vec vectorResult) { + ASSERT_EQ(Status::OK, status); + std::vector id(vectorResult); + EXPECT_THAT(id, ElementsAreArray(serializedMetrics.data(), + serializedMetrics.size())); + }); } TEST_F(WVDrmPluginTest, DoesNotGetUnknownProperties) { diff --git a/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp b/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp index e00fbb82..49742623 100644 --- a/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp +++ b/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp @@ -32,7 +32,16 @@ const String8 kAppId("com.unittest.mock.app.id"); const uint8_t* const kUnprovisionResponse = reinterpret_cast("unprovision"); const size_t kUnprovisionResponseSize = 11; -} + +// This is a serialized MetricsGroup message containing a small amount of +// sample data. This ensures we're able to extract it via a property. +const char kSerializedMetrics[] = { + 0x0a, 0x0a, 0x0a, 0x04, 0x74, 0x65, 0x73, 0x74, 0x12, 0x02, 0x08, 0x00, + 0x0a, 0x12, 0x0a, 0x05, 0x74, 0x65, 0x73, 0x74, 0x32, 0x12, 0x09, 0x11, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x15, 0x0a, 0x05, + 0x74, 0x65, 0x73, 0x74, 0x33, 0x12, 0x0c, 0x1a, 0x0a, 0x74, 0x65, 0x73, + 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65}; +} // anonymous namespace class MockCDM : public WvContentDecryptionModule { public: @@ -95,6 +104,8 @@ class MockCDM : public WvContentDecryptionModule { CdmResponseType(const CdmUsageInfoReleaseMessage&)); MOCK_METHOD1(IsValidServiceCertificate, bool(const std::string&)); + + MOCK_METHOD1(GetSerializedMetrics, void(std::string*)); }; class MockCrypto : public WVGenericCryptoInterface { @@ -833,6 +844,8 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { static const string openSessions = "15"; static const string maxSessions = "18"; static const string oemCryptoApiVersion = "10"; + string serializedMetrics(kSerializedMetrics, + kSerializedMetrics + sizeof(kSerializedMetrics)); EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1), @@ -864,6 +877,9 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { .WillOnce(DoAll(SetArgPointee<2>(oemCryptoApiVersion), Return(wvcdm::NO_ERROR))); + EXPECT_CALL(*cdm, GetSerializedMetrics(_)) + .WillOnce(SetArgPointee<0>(serializedMetrics)); + String8 stringResult; Vector vectorResult; @@ -915,6 +931,12 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { res = plugin.getPropertyString(String8("oemCryptoApiVersion"), stringResult); ASSERT_EQ(OK, res); EXPECT_EQ(oemCryptoApiVersion, stringResult.string()); + + vectorResult.clear(); + res = plugin.getPropertyByteArray(String8("metrics"), vectorResult); + ASSERT_EQ(OK, res); + EXPECT_THAT(vectorResult, ElementsAreArray(serializedMetrics.data(), + serializedMetrics.size())); } TEST_F(WVDrmPluginTest, DoesNotGetUnknownProperties) {