From 46eecb6b80d15b52dc2988e5d12181211f3449a7 Mon Sep 17 00:00:00 2001 From: Adam Stone Date: Tue, 15 Jan 2019 17:25:43 -0800 Subject: [PATCH] Add a metric decorator around cdm engine [ Merge from http://go/wvgerrit/69105 ] This adds a metric collecting decorator class around cdm engine. This implementation uses a templated decorator. The decorator enables: 1) Wrapping the CDM Engine methods to capture timing and error information. 2) Allows use of a mock CDM Engine for testing. Test: Unit tests. GPlay manual testing and GTS tests. BUG: http://b/64724336 Change-Id: I5e4a0f552974fab1939bc7ab02719a1f5849cf3f --- .../build_and_run_all_unit_tests.sh | 1 + libwvdrmengine/cdm/Android.mk | 1 + libwvdrmengine/cdm/core/include/cdm_engine.h | 34 +- .../cdm/core/include/cdm_engine_factory.h | 28 + .../include/cdm_engine_metrics_decorator.h | 263 +++++++++ libwvdrmengine/cdm/core/src/cdm_engine.cpp | 69 +-- .../cdm/core/src/cdm_engine_factory.cpp | 24 + .../cdm_engine_metrics_decorator_unittest.cpp | 529 ++++++++++++++++++ .../cdm/core/test/cdm_engine_test.cpp | 10 +- .../cdm/core/test/generic_crypto_unittest.cpp | 5 +- libwvdrmengine/cdm/core/test/test_base.cpp | 9 +- .../cdm/src/wv_content_decryption_module.cpp | 85 +-- libwvdrmengine/cdm/test/Android.mk | 5 + libwvdrmengine/run_all_unit_tests.sh | 1 + 14 files changed, 954 insertions(+), 110 deletions(-) create mode 100644 libwvdrmengine/cdm/core/include/cdm_engine_factory.h create mode 100644 libwvdrmengine/cdm/core/include/cdm_engine_metrics_decorator.h create mode 100644 libwvdrmengine/cdm/core/src/cdm_engine_factory.cpp create mode 100644 libwvdrmengine/cdm/core/test/cdm_engine_metrics_decorator_unittest.cpp diff --git a/libwvdrmengine/build_and_run_all_unit_tests.sh b/libwvdrmengine/build_and_run_all_unit_tests.sh index ba19e930..4a16bc34 100755 --- a/libwvdrmengine/build_and_run_all_unit_tests.sh +++ b/libwvdrmengine/build_and_run_all_unit_tests.sh @@ -83,6 +83,7 @@ try_adb_push() { try_adb_push base64_test try_adb_push buffer_reader_test try_adb_push cdm_engine_test +try_adb_push cdm_engine_metrics_decorator_unittest try_adb_push cdm_feature_test try_adb_push cdm_extended_duration_test try_adb_push cdm_session_unittest diff --git a/libwvdrmengine/cdm/Android.mk b/libwvdrmengine/cdm/Android.mk index 6a71e45b..cd63c219 100644 --- a/libwvdrmengine/cdm/Android.mk +++ b/libwvdrmengine/cdm/Android.mk @@ -29,6 +29,7 @@ METRICS_SRC_DIR := metrics/src LOCAL_SRC_FILES := \ $(CORE_SRC_DIR)/buffer_reader.cpp \ $(CORE_SRC_DIR)/cdm_engine.cpp \ + $(CORE_SRC_DIR)/cdm_engine_factory.cpp \ $(CORE_SRC_DIR)/cdm_session.cpp \ $(CORE_SRC_DIR)/cdm_session_map.cpp \ $(CORE_SRC_DIR)/certificate_provisioning.cpp \ diff --git a/libwvdrmengine/cdm/core/include/cdm_engine.h b/libwvdrmengine/cdm/core/include/cdm_engine.h index cde40e0a..e516f7c3 100644 --- a/libwvdrmengine/cdm/core/include/cdm_engine.h +++ b/libwvdrmengine/cdm/core/include/cdm_engine.h @@ -26,6 +26,7 @@ namespace wvcdm { class CdmClientPropertySet; +class CdmEngineFactory; class CdmSession; class CryptoEngine; class UsagePropertySet; @@ -37,7 +38,6 @@ typedef std::map metrics, + const std::string& spoid = EMPTY_SPOID); + private: // private methods CdmResponseType OpenSession( @@ -348,7 +375,8 @@ class CdmEngine { * ensure that all data has been properly recorded in the group before * it is published. */ - metrics::EngineMetrics metrics_; + std::shared_ptr metrics_; + std::string app_package_name_; CdmSessionMap session_map_; CdmReleaseKeySetMap release_key_sets_; diff --git a/libwvdrmengine/cdm/core/include/cdm_engine_factory.h b/libwvdrmengine/cdm/core/include/cdm_engine_factory.h new file mode 100644 index 00000000..5cd0e88e --- /dev/null +++ b/libwvdrmengine/cdm/core/include/cdm_engine_factory.h @@ -0,0 +1,28 @@ +// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine Master +// License Agreement. + +#ifndef WVCDM_CORE_CDM_ENGINE_FACTORY_H_ +#define WVCDM_CORE_CDM_ENGINE_FACTORY_H_ + +#include + +#include "cdm_engine.h" +#include "file_store.h" + +namespace wvcdm { + +// This factory is used to create an instance of the CdmEngine. +class CdmEngineFactory { + public: + // Creates a new instance of a CdmEngine. Caller retains ownership of the + // |files_system| which cannot be null. + static CdmEngine* CreateCdmEngine(FileSystem* file_system); + + private: + CORE_DISALLOW_COPY_AND_ASSIGN(CdmEngineFactory); +}; + +} // namespace wvcdm + +#endif // WVCDM_CORE_CDM_ENGINE_FACTORY_H_ diff --git a/libwvdrmengine/cdm/core/include/cdm_engine_metrics_decorator.h b/libwvdrmengine/cdm/core/include/cdm_engine_metrics_decorator.h new file mode 100644 index 00000000..04027b48 --- /dev/null +++ b/libwvdrmengine/cdm/core/include/cdm_engine_metrics_decorator.h @@ -0,0 +1,263 @@ + +// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine Master +// License Agreement. +#ifndef WVCDM_CORE_CDM_ENGINE_METRICS_DECORATOR_H_ +#define WVCDM_CORE_CDM_ENGINE_METRICS_DECORATOR_H_ + +#include +#include +#include + +#include "cdm_engine.h" +#include "cdm_session_map.h" +#include "certificate_provisioning.h" +#include "clock.h" +#include "crypto_session.h" +#include "disallow_copy_and_assign.h" +#include "file_store.h" +#include "initialization_data.h" +#include "metrics_collections.h" +#include "oemcrypto_adapter.h" +#include "properties.h" +#include "service_certificate.h" +#include "wv_cdm_constants.h" +#include "wv_cdm_types.h" + +namespace wvcdm { + +class CdmClientPropertySet; +class CdmEngineFactory; +class CdmSession; +class CryptoEngine; +class UsagePropertySet; +class WvCdmEventListener; + +// This is a templated decorator class implementation of the CdmEngine. +// It captures metric information related to the inner CdmEngine class. +// Usage: +// FileSystem* file_system; // Construction of FileSystem object not shown. +// std::shared_ptr metrics(new EngineMetrics); +// CdmEngine* e = new CdmEngineMetricsImpl(file_system, metrics); +template +class CdmEngineMetricsImpl : public T { + public: + // This constructor initializes the instance and takes ownership of |metrics|. + // |file_system| and |metrics| must not be null. + // |metrics| is used within the base class constructor. So, it must be + // passed in as a dependency and provided to the base constructor. + CdmEngineMetricsImpl(FileSystem* file_system, + std::shared_ptr metrics, + const std::string& spoid = EMPTY_SPOID) + : T(file_system, metrics, spoid), metrics_(metrics) { + metrics_->cdm_engine_creation_time_millis_.Record(clock_.GetCurrentTime()); + std::string cdm_version; + if(Properties::GetWVCdmVersion(&cdm_version)) { + metrics_->cdm_engine_cdm_version_.Record(cdm_version); + } else { + metrics_->cdm_engine_cdm_version_.SetError(false); + } + } + + ~CdmEngineMetricsImpl() override {}; + + bool GetMetricsSnapshot(drm_metrics::WvCdmMetrics *metrics) override { + if (metrics == nullptr) return false; + metrics_->Serialize(metrics); + return true; + } + + CdmResponseType OpenSession( + const CdmKeySystem& key_system, CdmClientPropertySet* property_set, + const CdmSessionId& forced_session_id, WvCdmEventListener* event_listener) + override { + CdmResponseType sts = T::OpenSession( + key_system, property_set, forced_session_id, event_listener); + metrics_->cdm_engine_open_session_.Increment(sts); + return sts; + } + + CdmResponseType OpenSession( + const CdmKeySystem& key_system, CdmClientPropertySet* property_set, + WvCdmEventListener* event_listener, CdmSessionId* session_id) + override { + CdmResponseType sts = T::OpenSession( + key_system, property_set, event_listener, session_id); + metrics_->cdm_engine_open_session_.Increment(sts); + return sts; + } + + CdmResponseType CloseSession(const CdmSessionId& session_id) override { + CdmResponseType sts = T::CloseSession(session_id); + metrics_->cdm_engine_close_session_.Increment(sts); + return sts; + } + + CdmResponseType OpenKeySetSession( + const CdmKeySetId& key_set_id, CdmClientPropertySet* property_set, + WvCdmEventListener* event_listener) override { + CdmResponseType sts = T::OpenKeySetSession(key_set_id, property_set, + event_listener); + metrics_->cdm_engine_open_key_set_session_.Increment(sts); + return sts; + } + + CdmResponseType GenerateKeyRequest( + const CdmSessionId& session_id, const CdmKeySetId& key_set_id, + const InitializationData& init_data, const CdmLicenseType license_type, + CdmAppParameterMap& app_parameters, CdmKeyRequest* key_request) override { + CdmResponseType sts; + M_TIME(sts = T::GenerateKeyRequest(session_id, key_set_id, init_data, + license_type, app_parameters, + key_request), + metrics_, cdm_engine_generate_key_request_, sts, license_type); + return sts; + } + + CdmResponseType AddKey( + const CdmSessionId& session_id, const CdmKeyResponse& key_data, + CdmLicenseType* license_type, CdmKeySetId* key_set_id) override { + if (license_type == nullptr) { + LOGE("CdmEngine::AddKey: license_type cannot be null."); + return PARAMETER_NULL; + } + + CdmResponseType sts; + M_TIME(sts = T::AddKey(session_id, key_data, license_type, key_set_id), + metrics_, cdm_engine_add_key_, sts, *license_type); + return sts; + } + + + CdmResponseType RestoreKey(const CdmSessionId& session_id, + const CdmKeySetId& key_set_id) override { + CdmResponseType sts; + M_TIME(sts = T::RestoreKey(session_id, key_set_id), + metrics_, cdm_engine_restore_key_, sts); + return sts; + } + + CdmResponseType RemoveKeys(const CdmSessionId& session_id) override { + CdmResponseType sts = T::RemoveKeys(session_id); + metrics_->cdm_engine_remove_keys_.Increment(sts); + return sts; + } + + CdmResponseType QueryKeyStatus(const CdmSessionId& session_id, + CdmQueryMap* query_response) override { + CdmResponseType sts; + M_TIME(sts = T::QueryKeyStatus(session_id, query_response), + metrics_, cdm_engine_query_key_status_, sts); + return sts; + } + + CdmResponseType GetProvisioningRequest( + CdmCertificateType cert_type, const std::string& cert_authority, + const std::string& service_certificate, + CdmProvisioningRequest* request, std::string* default_url) override { + CdmResponseType sts; + M_TIME(sts = T::GetProvisioningRequest(cert_type, cert_authority, + service_certificate, + request, default_url), + metrics_, cdm_engine_get_provisioning_request_, sts); + return sts; + } + + CdmResponseType HandleProvisioningResponse( + const CdmProvisioningResponse& response, std::string* cert, + std::string* wrapped_key) override { + CdmResponseType sts; + M_TIME( + sts = T::HandleProvisioningResponse(response, cert, wrapped_key), + metrics_, cdm_engine_handle_provisioning_response_, sts); + return sts; + } + + + CdmResponseType Unprovision(CdmSecurityLevel security_level) override { + CdmResponseType sts = T::Unprovision(security_level); + metrics_->cdm_engine_unprovision_.Increment(sts, security_level); + return sts; + } + + CdmResponseType GetUsageInfo(const std::string& app_id, + CdmUsageInfo* usage_info) override { + CdmResponseType sts; + M_TIME(sts = T::GetUsageInfo(app_id, usage_info), + metrics_, cdm_engine_get_usage_info_, sts); + return sts; + } + + + CdmResponseType GetUsageInfo(const std::string& app_id, + const CdmSecureStopId& ssid, + CdmUsageInfo* usage_info) override { + CdmResponseType sts; + M_TIME(sts = T::GetUsageInfo(app_id, ssid, usage_info), + metrics_, cdm_engine_get_usage_info_, sts); + return sts; + } + + CdmResponseType RemoveAllUsageInfo(const std::string& app_id) override { + CdmResponseType sts = T::RemoveAllUsageInfo(app_id); + metrics_->cdm_engine_remove_all_usage_info_.Increment(sts); + return sts; + } + + CdmResponseType RemoveAllUsageInfo(const std::string& app_id, + CdmSecurityLevel security_level) override { + CdmResponseType sts = T::RemoveAllUsageInfo(app_id, security_level); + metrics_->cdm_engine_remove_all_usage_info_.Increment(sts); + return sts; + } + + CdmResponseType RemoveUsageInfo( + const std::string& app_id, const CdmSecureStopId& secure_stop_id) + override { + CdmResponseType sts = T::RemoveUsageInfo(app_id, secure_stop_id); + metrics_->cdm_engine_remove_usage_info_.Increment(sts); + return sts; + } + + CdmResponseType ReleaseUsageInfo(const CdmUsageInfoReleaseMessage& message) + override { + CdmResponseType sts = T::ReleaseUsageInfo(message); + metrics_->cdm_engine_release_usage_info_.Increment(sts); + return sts; + } + + CdmResponseType ListUsageIds( + const std::string& app_id, CdmSecurityLevel security_level, + std::vector* ksids, + std::vector* provider_session_tokens) override { + CdmResponseType sts = T::ListUsageIds(app_id, security_level, + ksids, provider_session_tokens); + metrics_->cdm_engine_get_secure_stop_ids_.Increment(sts); + return sts; + } + + + bool FindSessionForKey(const KeyId& key_id, CdmSessionId* session_id) + override { + bool status = + T::FindSessionForKey(key_id, session_id); + metrics_->cdm_engine_find_session_for_key_.Increment(status); + return status; + } + + CdmResponseType Decrypt(const CdmSessionId& session_id, + const CdmDecryptionParameters& parameters) override { + CdmResponseType sts; + M_TIME(sts = T::Decrypt(session_id, parameters), + metrics_, cdm_engine_decrypt_, sts, + metrics::Pow2Bucket(parameters.encrypt_length)); + return sts; + } + + private: + std::shared_ptr metrics_; + Clock clock_; +}; + +} // wvcdm namespace +#endif // WVCDM_CORE_CDM_ENGINE_METRICS_DECORATOR_H_ diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index 110bd223..be832457 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -71,8 +71,11 @@ class UsagePropertySet : public CdmClientPropertySet { bool CdmEngine::seeded_ = false; -CdmEngine::CdmEngine(FileSystem* file_system, const std::string& spoid) - : cert_provisioning_(), +CdmEngine::CdmEngine(FileSystem* file_system, + std::shared_ptr metrics, + const std::string& spoid) + : metrics_(metrics), + cert_provisioning_(), cert_provisioning_requested_security_level_(kLevelDefault), file_system_(file_system), spoid_(spoid), @@ -85,16 +88,6 @@ CdmEngine::CdmEngine(FileSystem* file_system, const std::string& spoid) srand(clock_.GetCurrentTime()); seeded_ = true; } - - metrics_.cdm_engine_creation_time_millis_.Record(clock_.GetCurrentTime()); - - std::string cdm_version; - if(Properties::GetWVCdmVersion(&cdm_version)) { - metrics_.cdm_engine_cdm_version_.Record(cdm_version); - } else { - // Set error "false", the return value of GetWVCdmVersion. - metrics_.cdm_engine_cdm_version_.SetError(false); - } } CdmEngine::~CdmEngine() { @@ -141,7 +134,7 @@ CdmResponseType CdmEngine::OpenSession( CloseExpiredReleaseSessions(); std::unique_ptr new_session(new CdmSession(file_system_, - metrics_.AddSession())); + metrics_->AddSession())); CdmResponseType sts = new_session->Init(property_set, forced_session_id, event_listener); if (sts != NO_ERROR) { @@ -206,7 +199,7 @@ CdmResponseType CdmEngine::CloseSession(const CdmSessionId& session_id) { LOGE("CdmEngine::CloseSession: session not found = %s", session_id.c_str()); return SESSION_NOT_FOUND_1; } - metrics_.ConsolidateSessions(); + metrics_->ConsolidateSessions(); return NO_ERROR; } @@ -529,7 +522,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level, std::string* query_response) { LOGI("CdmEngine::QueryStatus"); std::unique_ptr crypto_session( - CryptoSession::MakeCryptoSession(metrics_.GetCryptoMetrics())); + CryptoSession::MakeCryptoSession(metrics_->GetCryptoMetrics())); CdmResponseType status; if (!query_response) { @@ -584,11 +577,11 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level, if (!got_info) { LOGW("CdmEngine::QueryStatus: UsageInformationSupport failed"); - metrics_.GetCryptoMetrics()->crypto_session_usage_information_support_ + metrics_->GetCryptoMetrics()->crypto_session_usage_information_support_ .SetError(got_info); return UNKNOWN_ERROR; } - metrics_.GetCryptoMetrics()->crypto_session_usage_information_support_ + metrics_->GetCryptoMetrics()->crypto_session_usage_information_support_ .Record(supports_usage_reporting); *query_response = @@ -677,7 +670,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level, M_TIME( status = crypto_session->Open( security_level), - metrics_.GetCryptoMetrics(), + metrics_->GetCryptoMetrics(), crypto_session_open_, status, security_level); @@ -688,7 +681,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level, if (query_token == QUERY_KEY_DEVICE_ID) { std::string deviceId; status = crypto_session->GetExternalDeviceUniqueId(&deviceId); - metrics_.GetCryptoMetrics()->crypto_session_get_device_unique_id_ + metrics_->GetCryptoMetrics()->crypto_session_get_device_unique_id_ .Increment(status); if (status != NO_ERROR) return status; @@ -878,7 +871,7 @@ CdmResponseType CdmEngine::GetProvisioningRequest( if (NULL == cert_provisioning_.get()) { cert_provisioning_.reset( - new CertificateProvisioning(metrics_.GetCryptoMetrics())); + new CertificateProvisioning(metrics_->GetCryptoMetrics())); CdmResponseType status = cert_provisioning_->Init(service_certificate); if (status != NO_ERROR) return status; } @@ -924,12 +917,12 @@ CdmResponseType CdmEngine::HandleProvisioningResponse( // Certificate provisioning object has been released. Check if a concurrent // provisioning attempt has succeeded before declaring failure. std::unique_ptr crypto_session( - CryptoSession::MakeCryptoSession(metrics_.GetCryptoMetrics())); + CryptoSession::MakeCryptoSession(metrics_->GetCryptoMetrics())); CdmResponseType status; M_TIME( status = crypto_session->Open( cert_provisioning_requested_security_level_), - metrics_.GetCryptoMetrics(), + metrics_->GetCryptoMetrics(), crypto_session_open_, status, cert_provisioning_requested_security_level_); @@ -967,7 +960,7 @@ bool CdmEngine::IsProvisioned(CdmSecurityLevel security_level) { property_set.set_security_level( security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault); - CdmSession session(file_system_, metrics_.AddSession()); + CdmSession session(file_system_, metrics_->AddSession()); CdmResponseType status = session.Init(&property_set); if (NO_ERROR != status) { @@ -981,7 +974,7 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) { // Devices with baked-in DRM certs cannot be reprovisioned and therefore must // not be unprovisioned. std::unique_ptr crypto_session( - CryptoSession::MakeCryptoSession(metrics_.GetCryptoMetrics())); + CryptoSession::MakeCryptoSession(metrics_->GetCryptoMetrics())); CdmClientTokenType token_type = kClientTokenUninitialized; CdmResponseType res = crypto_session->GetProvisioningMethod( security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault, @@ -1016,14 +1009,14 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) { CdmResponseType CdmEngine::DeleteUsageTable(CdmSecurityLevel security_level) { LOGI("CdmEngine::DeleteUsageTable: security level: %d", security_level); std::unique_ptr crypto_session( - CryptoSession::MakeCryptoSession(metrics_.GetCryptoMetrics())); + CryptoSession::MakeCryptoSession(metrics_->GetCryptoMetrics())); CdmResponseType status; M_TIME( status = crypto_session->Open( security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault), - metrics_.GetCryptoMetrics(), + metrics_->GetCryptoMetrics(), crypto_session_open_, status, security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault); @@ -1033,7 +1026,7 @@ CdmResponseType CdmEngine::DeleteUsageTable(CdmSecurityLevel security_level) { return UNPROVISION_ERROR_4; } status = crypto_session->DeleteAllUsageReports(); - metrics_.GetCryptoMetrics()->crypto_session_delete_all_usage_reports_ + metrics_->GetCryptoMetrics()->crypto_session_delete_all_usage_reports_ .Increment(status); if (status != NO_ERROR) { LOGE("CdmEngine::DeleteUsageTable: error deleteing usage reports: %d", @@ -1101,7 +1094,7 @@ CdmResponseType CdmEngine::DeleteUsageRecord(const std::string& app_id, // Got provider token. Remove from OEMCrypto. std::unique_ptr crypto_session( - CryptoSession::MakeCryptoSession(metrics_.GetCryptoMetrics())); + CryptoSession::MakeCryptoSession(metrics_->GetCryptoMetrics())); CdmResponseType status = crypto_session->Open( security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault); if (status == NO_ERROR) { @@ -1224,7 +1217,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_, metrics_.AddSession())); + 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); @@ -1244,7 +1237,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_, metrics_.AddSession())); + 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"); @@ -1324,7 +1317,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_, metrics_.AddSession())); + usage_session_.reset(new CdmSession(file_system_, metrics_->AddSession())); CdmResponseType status = usage_session_->Init(usage_property_set_.get()); if (NO_ERROR != status) { @@ -1408,7 +1401,7 @@ CdmResponseType CdmEngine::RemoveAllUsageInfo( // Got at least one provider token. Remove from OEMCrypto. std::unique_ptr crypto_session( - CryptoSession::MakeCryptoSession(metrics_.GetCryptoMetrics())); + CryptoSession::MakeCryptoSession(metrics_->GetCryptoMetrics())); CdmResponseType status = crypto_session->Open( security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault); if (status == NO_ERROR) { @@ -1437,7 +1430,7 @@ CdmResponseType CdmEngine::RemoveAllUsageInfo(const std::string& app_id) { ? kLevel3 : kLevelDefault; usage_property_set_->set_security_level(security_level); - usage_session_.reset(new CdmSession(file_system_, metrics_.AddSession())); + usage_session_.reset(new CdmSession(file_system_, metrics_->AddSession())); usage_session_->Init(usage_property_set_.get()); switch (usage_session_->get_usage_support_type()) { @@ -1530,7 +1523,7 @@ CdmResponseType CdmEngine::RemoveUsageInfo( ? kLevel3 : kLevelDefault; usage_property_set_->set_security_level(security_level); - usage_session_.reset(new CdmSession(file_system_, metrics_.AddSession())); + usage_session_.reset(new CdmSession(file_system_, metrics_->AddSession())); usage_session_->Init(usage_property_set_.get()); std::vector usage_data; @@ -1565,7 +1558,7 @@ CdmResponseType CdmEngine::RemoveUsageInfo( DeviceFiles::GetUsageInfoFileName(app_id), provider_session_token); std::unique_ptr crypto_session( - CryptoSession::MakeCryptoSession(metrics_.GetCryptoMetrics())); + CryptoSession::MakeCryptoSession(metrics_->GetCryptoMetrics())); status = crypto_session->Open( static_cast(j) == kSecurityLevelL3 ? kLevel3 : kLevelDefault); @@ -2086,18 +2079,18 @@ void CdmEngine::DeleteAllUsageReportsUponFactoryReset() { if (!file_system_->Exists(device_base_path_level1) && !file_system_->Exists(device_base_path_level3)) { std::unique_ptr crypto_session( - CryptoSession::MakeCryptoSession(metrics_.GetCryptoMetrics())); + CryptoSession::MakeCryptoSession(metrics_->GetCryptoMetrics())); CdmResponseType status; M_TIME( status = crypto_session->Open( cert_provisioning_requested_security_level_), - metrics_.GetCryptoMetrics(), + metrics_->GetCryptoMetrics(), crypto_session_open_, status, cert_provisioning_requested_security_level_); if (NO_ERROR == status) { status = crypto_session->DeleteAllUsageReports(); - metrics_.GetCryptoMetrics()->crypto_session_delete_all_usage_reports_ + metrics_->GetCryptoMetrics()->crypto_session_delete_all_usage_reports_ .Increment(status); if (NO_ERROR != status) { LOGW( diff --git a/libwvdrmengine/cdm/core/src/cdm_engine_factory.cpp b/libwvdrmengine/cdm/core/src/cdm_engine_factory.cpp new file mode 100644 index 00000000..ca9b2949 --- /dev/null +++ b/libwvdrmengine/cdm/core/src/cdm_engine_factory.cpp @@ -0,0 +1,24 @@ +// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine Master +// License Agreement. + +#include "cdm_engine_factory.h" + +#include +#include +#include "cdm_engine.h" +#include "cdm_engine_metrics_decorator.h" +#include "clock.h" +#include "file_store.h" + +namespace wvcdm { + +CdmEngine* CdmEngineFactory::CreateCdmEngine(FileSystem* file_system) { + std::unique_ptr engine_metrics( + new metrics::EngineMetrics()); + + return new CdmEngineMetricsImpl(file_system, + std::move(engine_metrics)); +} + +} // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/test/cdm_engine_metrics_decorator_unittest.cpp b/libwvdrmengine/cdm/core/test/cdm_engine_metrics_decorator_unittest.cpp new file mode 100644 index 00000000..1d3c3f2c --- /dev/null +++ b/libwvdrmengine/cdm/core/test/cdm_engine_metrics_decorator_unittest.cpp @@ -0,0 +1,529 @@ +// Copyright 2018 Google LLC. All Rights Reserved. This fil and proprietary +// source code may only be used and distributed under the Widevine Master +// License Agreement. + +// These tests are for the cdm engine metrics implementation. They ensure that +// The cdm engine metrics impl is correctly forwarding calls to the internal +// implementation and capturing metrics as appropriate. + +#include "cdm_engine_metrics_decorator.h" + +#include +#include + +#include "cdm_client_property_set.h" +#include "cdm_engine.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "metrics.pb.h" +#include "wv_cdm_event_listener.h" + +using ::testing::_; +using ::testing::ByRef; +using ::testing::Eq; +using ::testing::Matcher; +using ::testing::Return; +using ::testing::StrEq; +using ::testing::StrictMock; +using ::wvcdm::metrics::EngineMetrics; + +namespace wvcdm { + + +class MockCdmClientPropertySet : public CdmClientPropertySet { + public: + + MOCK_CONST_METHOD0(security_level, const std::string&()); + MOCK_CONST_METHOD0(use_privacy_mode, bool()); + MOCK_CONST_METHOD0(service_certificate, const std::string&()); + MOCK_METHOD1(set_service_certificate, void(const std::string&)); + MOCK_CONST_METHOD0(is_session_sharing_enabled, bool()); + MOCK_CONST_METHOD0(session_sharing_id, uint32_t()); + MOCK_METHOD1(set_session_sharing_id, void(uint32_t)); + MOCK_CONST_METHOD0(app_id, const std::string&()); +}; + +class MockWvCdmEventListener : public WvCdmEventListener { + MOCK_METHOD1(OnSessionRenewalNeeded, void(const CdmSessionId&)); + MOCK_METHOD3(OnSessionKeysChange, + void(const CdmSessionId&, const CdmKeyStatusMap&, + bool has_new_usable_key)); + MOCK_METHOD2(OnExpirationUpdate, void(const CdmSessionId&, int64_t)); +}; + +class MockCdmEngineImpl : public CdmEngine { + public: + MockCdmEngineImpl(FileSystem* file_system, + std::shared_ptr metrics, + const std::string& spoid) + : CdmEngine(file_system, metrics, spoid) {} + MOCK_METHOD4(OpenSession, CdmResponseType( + const CdmKeySystem&, CdmClientPropertySet*, + const CdmSessionId&, WvCdmEventListener*)); + MOCK_METHOD4(OpenSession, CdmResponseType( + const CdmKeySystem&, CdmClientPropertySet*, + WvCdmEventListener*, CdmSessionId*)); + MOCK_METHOD1(CloseSession, CdmResponseType(const CdmSessionId&)); + MOCK_METHOD3(OpenKeySetSession, + CdmResponseType(const CdmKeySetId&, CdmClientPropertySet*, + WvCdmEventListener*)); + MOCK_METHOD6(GenerateKeyRequest, + CdmResponseType(const CdmSessionId&, const CdmKeySetId&, + const InitializationData&, const CdmLicenseType, + CdmAppParameterMap&, CdmKeyRequest*)); + MOCK_METHOD4(AddKey, CdmResponseType( + const CdmSessionId&, const CdmKeyResponse&, + CdmLicenseType*, CdmKeySetId*)); + MOCK_METHOD2(RestoreKey, CdmResponseType(const CdmSessionId&, + const CdmKeySetId&)); + MOCK_METHOD1(RemoveKeys, CdmResponseType(const CdmSessionId&)); + MOCK_METHOD2(QueryKeyStatus, CdmResponseType(const CdmSessionId&, + CdmQueryMap*)); + MOCK_METHOD5(GetProvisioningRequest, CdmResponseType( + CdmCertificateType, const std::string&, const std::string&, + CdmProvisioningRequest*, std::string*)); + MOCK_METHOD3(HandleProvisioningResponse, CdmResponseType( + const CdmProvisioningResponse&, std::string*, std::string*)); + MOCK_METHOD1(Unprovision, CdmResponseType(CdmSecurityLevel)); + MOCK_METHOD4(ListUsageIds, CdmResponseType( + const std::string&, CdmSecurityLevel, + std::vector*, std::vector*)); + MOCK_METHOD1(RemoveAllUsageInfo, CdmResponseType(const std::string&)); + MOCK_METHOD2(RemoveAllUsageInfo, CdmResponseType(const std::string&, + CdmSecurityLevel)); + MOCK_METHOD2(RemoveUsageInfo, CdmResponseType(const std::string&, + const CdmSecureStopId&)); + MOCK_METHOD1(ReleaseUsageInfo, + CdmResponseType(const CdmUsageInfoReleaseMessage&)); + MOCK_METHOD2(Decrypt, CdmResponseType(const CdmSessionId&, + const CdmDecryptionParameters&)); + MOCK_METHOD2(FindSessionForKey, bool(const KeyId&, CdmSessionId*)); +}; + +class WvCdmEngineMetricsImplTest : public ::testing::Test { + public: + void SetUp() override { + file_system_.reset(new FileSystem); + std::shared_ptr engine_metrics(new EngineMetrics); + test_cdm_metrics_engine_.reset( + new CdmEngineMetricsImpl>( + file_system_.get(), engine_metrics)); + + } + + protected: + std::unique_ptr file_system_; + std::unique_ptr>> + test_cdm_metrics_engine_; +}; + +TEST_F(WvCdmEngineMetricsImplTest, OpenSession_Overload1) { + MockCdmClientPropertySet property_set; + MockWvCdmEventListener event_listener; + + EXPECT_CALL(*test_cdm_metrics_engine_, + OpenSession( + StrEq("foo"), Eq(&property_set), + Matcher(Eq("bar")), Eq(&event_listener))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->OpenSession("foo", &property_set, "bar", + &event_listener)); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ(1, metrics_proto.engine_metrics().cdm_engine_open_session_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_open_session(0).attributes().error_code()); +} + +TEST_F(WvCdmEngineMetricsImplTest, OpenSession_Overload2) { + MockCdmClientPropertySet property_set; + MockWvCdmEventListener event_listener; + CdmSessionId session_id; + + EXPECT_CALL(*test_cdm_metrics_engine_, + OpenSession( + StrEq("foo"), Eq(&property_set), + Eq(&event_listener), Matcher(Eq(&session_id)))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->OpenSession( + "foo", &property_set, &event_listener, &session_id)); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ(1, metrics_proto.engine_metrics().cdm_engine_open_session_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_open_session(0).attributes().error_code()); +} + +TEST_F(WvCdmEngineMetricsImplTest, CloseSession) { + MockCdmClientPropertySet property_set; + MockWvCdmEventListener event_listener; + + EXPECT_CALL(*test_cdm_metrics_engine_, CloseSession(Eq("bar"))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->CloseSession("bar")); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ(1, metrics_proto.engine_metrics().cdm_engine_close_session_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_close_session(0).attributes().error_code()); +} + +TEST_F(WvCdmEngineMetricsImplTest, OpenKeySetSession) { + MockCdmClientPropertySet property_set; + MockWvCdmEventListener event_listener; + + EXPECT_CALL(*test_cdm_metrics_engine_, + OpenKeySetSession(Eq("bar"), Eq(&property_set), Eq(&event_listener))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->OpenKeySetSession("bar", &property_set, + &event_listener)); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ( + 1, metrics_proto.engine_metrics().cdm_engine_open_key_set_session_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_open_key_set_session(0).attributes().error_code()); +} + +TEST_F(WvCdmEngineMetricsImplTest, GenerateKeyRequest) { + InitializationData initialization_data; + CdmAppParameterMap app_parameters; + CdmKeyRequest key_request; + + EXPECT_CALL(*test_cdm_metrics_engine_, + GenerateKeyRequest(Eq("foo"), Eq("bar"), _, Eq(kLicenseTypeStreaming), + Eq(app_parameters), Eq(&key_request))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->GenerateKeyRequest( + "foo", "bar", initialization_data, + kLicenseTypeStreaming, app_parameters, &key_request)); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ( + 1, metrics_proto.engine_metrics() + .cdm_engine_generate_key_request_time_us_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_generate_key_request_time_us(0) + .attributes().error_code()); +} + +TEST_F(WvCdmEngineMetricsImplTest, AddKey) { + CdmLicenseType license_type; + CdmKeySetId key_set_id; + + EXPECT_CALL(*test_cdm_metrics_engine_, + AddKey(Eq("fake session id"), Eq("fake response"), Eq(&license_type), + Eq(&key_set_id))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->AddKey( + "fake session id", "fake response", + &license_type, &key_set_id)); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ( + 1, metrics_proto.engine_metrics() + .cdm_engine_add_key_time_us_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_add_key_time_us(0) + .attributes().error_code()); +} + +TEST_F(WvCdmEngineMetricsImplTest, RestoreKey) { + EXPECT_CALL(*test_cdm_metrics_engine_, + RestoreKey(Eq("fake session id"), Eq("fake key set id"))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->RestoreKey( + "fake session id", "fake key set id")); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ( + 1, metrics_proto.engine_metrics() + .cdm_engine_restore_key_time_us_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_restore_key_time_us(0) + .attributes().error_code()); +} + +TEST_F(WvCdmEngineMetricsImplTest, RemoveKeys) { + EXPECT_CALL(*test_cdm_metrics_engine_, + RemoveKeys(Eq("fake session id"))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->RemoveKeys("fake session id")); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ( + 1, metrics_proto.engine_metrics() + .cdm_engine_remove_keys_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_remove_keys(0) + .attributes().error_code()); +} + +TEST_F(WvCdmEngineMetricsImplTest, QueryKeyStatus) { + CdmQueryMap query_response; + EXPECT_CALL(*test_cdm_metrics_engine_, + QueryKeyStatus(Eq("fake session id"), Eq(&query_response))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->QueryKeyStatus("fake session id", + &query_response)); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ( + 1, metrics_proto.engine_metrics() + .cdm_engine_query_key_status_time_us_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_query_key_status_time_us(0) + .attributes().error_code()); +} + +TEST_F(WvCdmEngineMetricsImplTest, GetProvisioningRequest) { + CdmProvisioningRequest request; + std::string default_url; + + EXPECT_CALL(*test_cdm_metrics_engine_, + GetProvisioningRequest(Eq(kCertificateX509), + Eq("fake certificate authority"), + Eq("fake service certificate"), + Eq(&request), Eq(&default_url))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->GetProvisioningRequest( + kCertificateX509, "fake certificate authority", + "fake service certificate", &request, &default_url)); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ( + 1, metrics_proto.engine_metrics() + .cdm_engine_get_provisioning_request_time_us_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_get_provisioning_request_time_us(0) + .attributes().error_code()); +} + +TEST_F(WvCdmEngineMetricsImplTest, HandleProvisioningResponse) { + CdmProvisioningResponse response; + std::string cert; + std::string wrapped_key; + + EXPECT_CALL(*test_cdm_metrics_engine_, + HandleProvisioningResponse(Eq("fake provisioning response"), + Eq(&cert), Eq(&wrapped_key))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->HandleProvisioningResponse( + "fake provisioning response", &cert, &wrapped_key)); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ( + 1, metrics_proto.engine_metrics() + .cdm_engine_handle_provisioning_response_time_us_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_handle_provisioning_response_time_us(0) + .attributes().error_code()); +} + +TEST_F(WvCdmEngineMetricsImplTest, Unprovision) { + EXPECT_CALL(*test_cdm_metrics_engine_, + Unprovision(Eq(kSecurityLevelL2))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->Unprovision(kSecurityLevelL2)); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ( + 1, metrics_proto.engine_metrics() + .cdm_engine_unprovision_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_unprovision(0) + .attributes().error_code()); +} + +TEST_F(WvCdmEngineMetricsImplTest, RemoveAllUsageInfo_Overload1) { + EXPECT_CALL(*test_cdm_metrics_engine_, + RemoveAllUsageInfo(Eq("fake app id"))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->RemoveAllUsageInfo("fake app id")); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ( + 1, metrics_proto.engine_metrics() + .cdm_engine_remove_all_usage_info_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_remove_all_usage_info(0) + .attributes().error_code()); +} + +TEST_F(WvCdmEngineMetricsImplTest, RemoveAllUsageInfo_Overload2) { + EXPECT_CALL(*test_cdm_metrics_engine_, + RemoveAllUsageInfo(Eq("fake app id"), Eq(kSecurityLevelL2))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->RemoveAllUsageInfo("fake app id", + kSecurityLevelL2)); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ( + 1, metrics_proto.engine_metrics() + .cdm_engine_remove_all_usage_info_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_remove_all_usage_info(0) + .attributes().error_code()); +} + + +TEST_F(WvCdmEngineMetricsImplTest, RemoveUsageInfo) { + EXPECT_CALL(*test_cdm_metrics_engine_, + RemoveUsageInfo(Eq("fake app id"), Eq("fake secure stop id"))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->RemoveUsageInfo("fake app id", + "fake secure stop id")); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ( + 1, metrics_proto.engine_metrics() + .cdm_engine_remove_usage_info_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_remove_usage_info(0) + .attributes().error_code()); +} + +TEST_F(WvCdmEngineMetricsImplTest, ReleaseUsageInfo) { + EXPECT_CALL(*test_cdm_metrics_engine_, + ReleaseUsageInfo(Eq("fake release message"))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->ReleaseUsageInfo("fake release message")); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ( + 1, metrics_proto.engine_metrics() + .cdm_engine_release_usage_info_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_release_usage_info(0) + .attributes().error_code()); +} + +TEST_F(WvCdmEngineMetricsImplTest, ListUsageIds) { + std::vector ksids; + std::vector provider_session_tokens; + + EXPECT_CALL(*test_cdm_metrics_engine_, + ListUsageIds(Eq("fake app id"), Eq(kSecurityLevelL2), + Eq(&ksids), Eq(&provider_session_tokens))) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->ListUsageIds( + "fake app id", kSecurityLevelL2, &ksids, + &provider_session_tokens)); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ( + 1, metrics_proto.engine_metrics() + .cdm_engine_get_secure_stop_ids_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_get_secure_stop_ids(0) + .attributes().error_code()); +} + +TEST_F(WvCdmEngineMetricsImplTest, FindSessionForKey) { + CdmSessionId session_id; + + EXPECT_CALL(*test_cdm_metrics_engine_, + FindSessionForKey(Eq("fake key id"), Eq(&session_id))) + .WillOnce(Return(true)); + + ASSERT_TRUE(test_cdm_metrics_engine_->FindSessionForKey("fake key id", + &session_id)); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ( + 1, metrics_proto.engine_metrics() + .cdm_engine_find_session_for_key_size()); + EXPECT_TRUE(metrics_proto.engine_metrics() + .cdm_engine_find_session_for_key(0) + .attributes().error_code_bool()); +} + +TEST_F(WvCdmEngineMetricsImplTest, Decrypt) { + CdmDecryptionParameters parameters; + EXPECT_CALL(*test_cdm_metrics_engine_, Decrypt(Eq("fake session id"), _)) + .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); + + ASSERT_EQ(wvcdm::UNKNOWN_ERROR, + test_cdm_metrics_engine_->Decrypt("fake session id", parameters)); + + drm_metrics::WvCdmMetrics metrics_proto; + test_cdm_metrics_engine_->GetMetricsSnapshot(&metrics_proto); + ASSERT_EQ( + 1, metrics_proto.engine_metrics() + .cdm_engine_decrypt_time_us_size()); + EXPECT_EQ(wvcdm::UNKNOWN_ERROR, + metrics_proto.engine_metrics() + .cdm_engine_decrypt_time_us(0) + .attributes().error_code()); +} + +} // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp b/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp index 010b98a8..08459042 100644 --- a/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp +++ b/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp @@ -32,6 +32,7 @@ namespace wvcdm { using drm_metrics::DistributionMetric; using drm_metrics::WvCdmMetrics; +using metrics::EngineMetrics; namespace { @@ -48,7 +49,9 @@ const std::string kComma = ","; class WvCdmEnginePreProvTest : public WvCdmTestBase { public: WvCdmEnginePreProvTest() - : cdm_engine_(&file_system_), session_opened_(false) {} + : dummy_engine_metrics_(new EngineMetrics), + cdm_engine_(&file_system_, dummy_engine_metrics_), + session_opened_(false) {} ~WvCdmEnginePreProvTest() override {} @@ -112,6 +115,7 @@ class WvCdmEnginePreProvTest : public WvCdmTestBase { } FileSystem file_system_; + shared_ptr dummy_engine_metrics_; CdmEngine cdm_engine_; bool session_opened_; std::string key_msg_; @@ -256,7 +260,7 @@ class WvCdmEngineTest : public WvCdmEnginePreProvTest { EXPECT_EQ(KEY_ADDED, status); EXPECT_EQ(expected_license_type, license_type); VerifyLicenseRequestLatency(kKeyRequestTypeInitial, - *cdm_engine_.GetMetrics()); + *dummy_engine_metrics_); } void VerifyRenewalKeyResponse(const std::string& server_url, @@ -264,7 +268,7 @@ class WvCdmEngineTest : public WvCdmEnginePreProvTest { std::string resp = GetKeyRequestResponse(server_url, client_auth); EXPECT_EQ(KEY_ADDED, cdm_engine_.RenewKey(session_id_, resp)); VerifyLicenseRequestLatency(kKeyRequestTypeRenewal, - *cdm_engine_.GetMetrics()); + *dummy_engine_metrics_); } void VerifyLicenseRequestLatency( diff --git a/libwvdrmengine/cdm/core/test/generic_crypto_unittest.cpp b/libwvdrmengine/cdm/core/test/generic_crypto_unittest.cpp index 1d88de66..0c882974 100644 --- a/libwvdrmengine/cdm/core/test/generic_crypto_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/generic_crypto_unittest.cpp @@ -32,7 +32,9 @@ namespace wvcdm { class WvGenericOperationsTest : public WvCdmTestBase { public: WvGenericOperationsTest() - : cdm_engine_(&file_system_), holder_(&cdm_engine_) {} + : dummy_engine_metrics_(new metrics::EngineMetrics), + cdm_engine_(&file_system_, dummy_engine_metrics_), + holder_(&cdm_engine_) {} void SetUp() override { WvCdmTestBase::SetUp(); @@ -73,6 +75,7 @@ class WvGenericOperationsTest : public WvCdmTestBase { protected: FileSystem file_system_; + std::shared_ptr dummy_engine_metrics_; CdmEngine cdm_engine_; TestLicenseHolder holder_; diff --git a/libwvdrmengine/cdm/core/test/test_base.cpp b/libwvdrmengine/cdm/core/test/test_base.cpp index b9b2d07d..e4aeebc5 100644 --- a/libwvdrmengine/cdm/core/test/test_base.cpp +++ b/libwvdrmengine/cdm/core/test/test_base.cpp @@ -27,6 +27,8 @@ #include "test_printers.h" #include "url_request.h" +using wvcdm::metrics::EngineMetrics; + namespace wvcdm { namespace { void show_menu(char* prog_name) { @@ -262,8 +264,10 @@ void WvCdmTestBase::Provision() { CdmSessionId session_id; FileSystem file_system; + // TODO(fredgc): provision for different SPOIDs. - CdmEngine cdm_engine(&file_system); + CdmEngine cdm_engine(&file_system, + std::shared_ptr(new EngineMetrics)); CdmResponseType result = cdm_engine.GetProvisioningRequest( cert_type, cert_authority, config_.provisioning_service_certificate(), @@ -325,7 +329,8 @@ void WvCdmTestBase::Provision() { void WvCdmTestBase::EnsureProvisioned() { CdmSessionId session_id; FileSystem file_system; - CdmEngine cdm_engine(&file_system); + CdmEngine cdm_engine(&file_system, + std::shared_ptr(new EngineMetrics)); CdmResponseType status = cdm_engine.OpenSession(config_.key_system(), NULL, NULL, &session_id); if (status == NEED_PROVISIONING) { diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index e4dac5b2..cba2bf50 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -6,6 +6,7 @@ #include "cdm_client_property_set.h" #include "cdm_engine.h" +#include "cdm_engine_factory.h" #include "initialization_data.h" #include "license.h" #include "log.h" @@ -64,7 +65,6 @@ CdmResponseType WvContentDecryptionModule::OpenSession( CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier); CdmResponseType sts = cdm_engine->OpenSession(key_system, property_set, event_listener, session_id); - cdm_engine->GetMetrics()->cdm_engine_open_session_.Increment(sts); if (sts == NO_ERROR) { cdm_by_session_id_[*session_id] = cdm_engine; } @@ -79,7 +79,6 @@ CdmResponseType WvContentDecryptionModule::CloseSession( if (!cdm_engine) return SESSION_NOT_FOUND_1; std::unique_lock auto_lock(cdms_lock_); CdmResponseType sts = cdm_engine->CloseSession(session_id); - cdm_engine->GetMetrics()->cdm_engine_close_session_.Increment(sts); if (sts == NO_ERROR) { cdm_by_session_id_.erase(session_id); } @@ -102,7 +101,6 @@ CdmResponseType WvContentDecryptionModule::GenerateKeyRequest( CdmResponseType sts; if (license_type == kLicenseTypeRelease) { sts = cdm_engine->OpenKeySetSession(key_set_id, property_set, NULL); - cdm_engine->GetMetrics()->cdm_engine_open_key_set_session_.Increment(sts); if (sts != NO_ERROR) return sts; cdm_by_session_id_[key_set_id] = cdm_engine; } @@ -124,11 +122,9 @@ CdmResponseType WvContentDecryptionModule::GenerateKeyRequest( InitializationData initialization_data(init_data_type, init_data, oec_version); - M_TIME(sts = cdm_engine->GenerateKeyRequest(session_id, key_set_id, - initialization_data, license_type, - app_parameters, key_request), - cdm_engine->GetMetrics(), cdm_engine_generate_key_request_, - sts, license_type); + sts = cdm_engine->GenerateKeyRequest(session_id, key_set_id, + initialization_data, license_type, + app_parameters, key_request); switch (license_type) { case kLicenseTypeRelease: if (sts != KEY_MESSAGE) { @@ -156,9 +152,7 @@ CdmResponseType WvContentDecryptionModule::AddKey( } CdmResponseType sts; CdmLicenseType license_type; - M_TIME(sts = cdm_engine->AddKey(session_id, key_data, - &license_type, key_set_id), - cdm_engine->GetMetrics(), cdm_engine_add_key_, sts, license_type); + sts = cdm_engine->AddKey(session_id, key_data, &license_type, key_set_id); // Empty session id indicates license type release. if (sts == KEY_ADDED && session_id.empty()) { cdm_engine->CloseKeySetSession(release_key_set_id); @@ -172,8 +166,7 @@ CdmResponseType WvContentDecryptionModule::RestoreKey( CdmEngine* cdm_engine = GetCdmForSessionId(session_id); if (!cdm_engine) return SESSION_NOT_FOUND_4; CdmResponseType sts; - M_TIME(sts = cdm_engine->RestoreKey(session_id, key_set_id), - cdm_engine->GetMetrics(), cdm_engine_restore_key_, sts); + sts = cdm_engine->RestoreKey(session_id, key_set_id); if (sts == KEY_ADDED) EnablePolicyTimer(); return sts; } @@ -183,7 +176,6 @@ CdmResponseType WvContentDecryptionModule::RemoveKeys( CdmEngine* cdm_engine = GetCdmForSessionId(session_id); if (!cdm_engine) return SESSION_NOT_FOUND_5; CdmResponseType sts = cdm_engine->RemoveKeys(session_id); - cdm_engine->GetMetrics()->cdm_engine_remove_keys_.Increment(sts); return sts; } @@ -205,8 +197,7 @@ CdmResponseType WvContentDecryptionModule::QueryKeyStatus( CdmEngine* cdm_engine = GetCdmForSessionId(session_id); if (!cdm_engine) return SESSION_NOT_FOUND_9; CdmResponseType sts; - M_TIME(sts = cdm_engine->QueryKeyStatus(session_id, key_info), - cdm_engine->GetMetrics(), cdm_engine_query_key_status_, sts); + sts = cdm_engine->QueryKeyStatus(session_id, key_info); return sts; } @@ -227,59 +218,41 @@ CdmResponseType WvContentDecryptionModule::GetProvisioningRequest( const CdmIdentifier& identifier, const std::string& service_certificate, CdmProvisioningRequest* request, std::string* default_url) { CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier); - CdmResponseType sts; - M_TIME(sts = cdm_engine->GetProvisioningRequest(cert_type, cert_authority, - service_certificate, - request, default_url), - cdm_engine->GetMetrics(), cdm_engine_get_provisioning_request_, sts); - return sts; + return cdm_engine->GetProvisioningRequest( + cert_type, cert_authority, service_certificate, request, default_url); } CdmResponseType WvContentDecryptionModule::HandleProvisioningResponse( const CdmIdentifier& identifier, CdmProvisioningResponse& response, std::string* cert, std::string* wrapped_key) { CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier); - CdmResponseType sts; - M_TIME( - sts = cdm_engine->HandleProvisioningResponse(response, cert, wrapped_key), - cdm_engine->GetMetrics(), cdm_engine_handle_provisioning_response_, sts); - return sts; + return cdm_engine->HandleProvisioningResponse(response, cert, wrapped_key); } CdmResponseType WvContentDecryptionModule::Unprovision( CdmSecurityLevel level, const CdmIdentifier& identifier) { CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier); - CdmResponseType sts = cdm_engine->Unprovision(level); - cdm_engine->GetMetrics()->cdm_engine_unprovision_.Increment(sts, level); - return sts; + return cdm_engine->Unprovision(level); } CdmResponseType WvContentDecryptionModule::GetUsageInfo( const std::string& app_id, const CdmIdentifier& identifier, CdmUsageInfo* usage_info) { CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier); - CdmResponseType sts; - M_TIME(sts = cdm_engine->GetUsageInfo(app_id, usage_info), - cdm_engine->GetMetrics(), cdm_engine_get_usage_info_, sts); - return sts; + return cdm_engine->GetUsageInfo(app_id, usage_info); } CdmResponseType WvContentDecryptionModule::GetUsageInfo( const std::string& app_id, const CdmSecureStopId& ssid, const CdmIdentifier& identifier, CdmUsageInfo* usage_info) { CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier); - CdmResponseType sts; - M_TIME(sts = cdm_engine->GetUsageInfo(app_id, ssid, usage_info), - cdm_engine->GetMetrics(), cdm_engine_get_usage_info_, sts); - return sts; + return cdm_engine->GetUsageInfo(app_id, ssid, usage_info); } CdmResponseType WvContentDecryptionModule::RemoveAllUsageInfo( const std::string& app_id, const CdmIdentifier& identifier) { CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier); - CdmResponseType sts = cdm_engine->RemoveAllUsageInfo(app_id); - cdm_engine->GetMetrics()->cdm_engine_remove_all_usage_info_.Increment(sts); - return sts; + return cdm_engine->RemoveAllUsageInfo(app_id); } CdmResponseType WvContentDecryptionModule::RemoveUsageInfo( @@ -287,18 +260,14 @@ CdmResponseType WvContentDecryptionModule::RemoveUsageInfo( const CdmIdentifier& identifier, const CdmSecureStopId& secure_stop_id) { CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier); - CdmResponseType sts = cdm_engine->RemoveUsageInfo(app_id, secure_stop_id); - cdm_engine->GetMetrics()->cdm_engine_remove_usage_info_.Increment(sts); - return sts; + return cdm_engine->RemoveUsageInfo(app_id, secure_stop_id); } CdmResponseType WvContentDecryptionModule::ReleaseUsageInfo( const CdmUsageInfoReleaseMessage& message, const CdmIdentifier& identifier) { CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier); - CdmResponseType sts = cdm_engine->ReleaseUsageInfo(message); - cdm_engine->GetMetrics()->cdm_engine_release_usage_info_.Increment(sts); - return sts; + return cdm_engine->ReleaseUsageInfo(message); } CdmResponseType WvContentDecryptionModule::GetSecureStopIds( @@ -318,9 +287,7 @@ CdmResponseType WvContentDecryptionModule::GetSecureStopIds( CdmResponseType sts_l3 = cdm_engine->ListUsageIds(app_id, kSecurityLevelL3, NULL, &secure_stop_ids); ssids->insert(ssids->end(), secure_stop_ids.begin(), secure_stop_ids.end()); - if (sts_l3 != NO_ERROR) sts = sts_l3; - cdm_engine->GetMetrics()->cdm_engine_get_secure_stop_ids_.Increment(sts); - return sts; + return sts_l3 != NO_ERROR ? sts_l3 : sts; } CdmResponseType WvContentDecryptionModule::Decrypt( @@ -339,8 +306,6 @@ CdmResponseType WvContentDecryptionModule::Decrypt( if (validate_key_id && Properties::GetSessionSharingId(session_id) != 0) { bool status = cdm_engine->FindSessionForKey(*parameters.key_id, &local_session_id); - cdm_engine->GetMetrics()->cdm_engine_find_session_for_key_.Increment( - status); if (!status) { // key does not need to be loaded if clear lead/frame has a // single subsample. It does in all other cases. @@ -351,11 +316,7 @@ CdmResponseType WvContentDecryptionModule::Decrypt( } } } - CdmResponseType sts; - M_TIME(sts = cdm_engine->Decrypt(local_session_id, parameters), - cdm_engine->GetMetrics(), cdm_engine_decrypt_, sts, - metrics::Pow2Bucket(parameters.encrypt_length)); - return sts; + return cdm_engine->Decrypt(local_session_id, parameters); } void WvContentDecryptionModule::NotifyResolution(const CdmSessionId& session_id, @@ -387,12 +348,12 @@ CdmResponseType WvContentDecryptionModule::GetMetrics( // TODO(blueeyes): Add a better error. return UNKNOWN_ERROR; } - it->second.cdm_engine->GetMetrics()->Serialize(metrics); - return NO_ERROR; + return it->second.cdm_engine->GetMetricsSnapshot(metrics) ? + NO_ERROR : UNKNOWN_ERROR; } WvContentDecryptionModule::CdmInfo::CdmInfo() - : cdm_engine(new CdmEngine(&file_system)) {} + : cdm_engine(CdmEngineFactory::CreateCdmEngine(&file_system)) {} CdmEngine* WvContentDecryptionModule::EnsureCdmForIdentifier( const CdmIdentifier& identifier) { @@ -406,9 +367,7 @@ CdmEngine* WvContentDecryptionModule::EnsureCdmForIdentifier( cdms_[identifier].file_system.set_origin(identifier.origin); cdms_[identifier].file_system.set_identifier(identifier.spoid + identifier.origin); - - // Set the app package name for use by metrics. - cdms_[identifier].cdm_engine->GetMetrics()->SetAppPackageName( + cdms_[identifier].cdm_engine->SetAppPackageName( identifier.app_package_name); } CdmEngine* cdm_engine = cdms_[identifier].cdm_engine.get(); diff --git a/libwvdrmengine/cdm/test/Android.mk b/libwvdrmengine/cdm/test/Android.mk index 069d8ec2..c8cbcfdf 100644 --- a/libwvdrmengine/cdm/test/Android.mk +++ b/libwvdrmengine/cdm/test/Android.mk @@ -21,6 +21,11 @@ test_src_dir := ../core/test test_main := ../core/test/test_main.cpp include $(LOCAL_PATH)/integration-test.mk +test_name := cdm_engine_metrics_decorator_unittest +test_src_dir := ../core/test +test_main := ../core/test/test_main.cpp +include $(LOCAL_PATH)/integration-test.mk + test_name := cdm_extended_duration_test test_src_dir := . test_main := ../core/test/test_main.cpp diff --git a/libwvdrmengine/run_all_unit_tests.sh b/libwvdrmengine/run_all_unit_tests.sh index 4269415e..ec796cfd 100755 --- a/libwvdrmengine/run_all_unit_tests.sh +++ b/libwvdrmengine/run_all_unit_tests.sh @@ -93,6 +93,7 @@ adb_shell_run request_license_test adb_shell_run base64_test adb_shell_run buffer_reader_test adb_shell_run cdm_engine_test +adb_shell_run cdm_engine_metrics_decorator_unittest adb_shell_run cdm_session_unittest adb_shell_run counter_metric_unittest adb_shell_run crypto_session_unittest