diff --git a/libwvdrmengine/cdm/include/cdm_identifier.h b/libwvdrmengine/cdm/include/cdm_identifier.h index 820b93e9..618c4e5b 100644 --- a/libwvdrmengine/cdm/include/cdm_identifier.h +++ b/libwvdrmengine/cdm/include/cdm_identifier.h @@ -30,28 +30,12 @@ struct CdmIdentifier { // provide a friendly name of the application package for the purposes of // logging and metrics. std::string app_package_name; - - // The unique identifier guarantees that no two identifiers share the same - // CdmEngine instance. We're moving to a model where a plugin maps 1 to 1 - // with a CdmEngine instance. This is a simple way to implement that. - uint32_t unique_id; - - // This method is needed to check to see if the identifier is equivalent - // to the default cdm. E.g. no spoid, origin or app package name. Use this - // comparison in lieu of the == operator when checking to see if the - // identifier would cause the default provisioned certificate to be used. - bool IsEquivalentToDefault() { - return spoid == EMPTY_SPOID - && origin == EMPTY_ORIGIN - && app_package_name == EMPTY_APP_PACKAGE_NAME; - } }; // Provide comparison operators inline bool operator==(const CdmIdentifier& lhs, const CdmIdentifier& rhs) { return lhs.spoid == rhs.spoid && lhs.origin == rhs.origin - && lhs.app_package_name == rhs.app_package_name - && lhs.unique_id == rhs.unique_id; + && lhs.app_package_name == rhs.app_package_name; } inline bool operator!=(const CdmIdentifier& lhs, const CdmIdentifier& rhs) { @@ -63,9 +47,7 @@ inline bool operator<(const CdmIdentifier& lhs, const CdmIdentifier& rhs) { || ((lhs.spoid == rhs.spoid) && (lhs.origin < rhs.origin || (lhs.origin == rhs.origin - && (lhs.app_package_name < rhs.app_package_name - || (lhs.app_package_name == rhs.app_package_name - && lhs.unique_id < rhs.unique_id))))); + && lhs.app_package_name < rhs.app_package_name))); } inline bool operator>(const CdmIdentifier& lhs, const CdmIdentifier& rhs) { @@ -84,8 +66,7 @@ inline bool operator>=(const CdmIdentifier& lhs, const CdmIdentifier& rhs) { static const CdmIdentifier kDefaultCdmIdentifier = { EMPTY_SPOID, EMPTY_ORIGIN, - EMPTY_APP_PACKAGE_NAME, - 0 + EMPTY_APP_PACKAGE_NAME }; } // namespace wvcdm diff --git a/libwvdrmengine/cdm/include/wv_content_decryption_module.h b/libwvdrmengine/cdm/include/wv_content_decryption_module.h index 88fedfcb..85198525 100644 --- a/libwvdrmengine/cdm/include/wv_content_decryption_module.h +++ b/libwvdrmengine/cdm/include/wv_content_decryption_module.h @@ -127,14 +127,9 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler { // Validate a passed-in service certificate virtual bool IsValidServiceCertificate(const std::string& certificate); - // Fill the metrics parameter with the metrics data for the CdmEngine - // associated with the given CdmIdentifier. If the CdmEngine instance does - // not exist, this will return an error. - virtual CdmResponseType GetMetrics(const CdmIdentifier& identifier, - drm_metrics::WvCdmMetrics* metrics); - - // Closes the CdmEngine and sessions associated with the given CdmIdentifier. - virtual CdmResponseType CloseCdm(const CdmIdentifier& identifier); + // Retrieve the serialized metrics from CdmEngine and CdmSession instances + // that have been closed. + virtual void GetSerializedMetrics(std::string* serialized_metrics); private: struct CdmInfo { @@ -150,10 +145,10 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler { // Finds the CdmEngine instance for the given session id, returning NULL if // not found. CdmEngine* GetCdmForSessionId(const std::string& session_id); - - // Close all of the open CdmEngine instances. This is used when ready to close - // the WvContentDecryptionModule instance. - void CloseAllCdms(); + // Closes CdmEngine instances that don't have any open sessions. Also stores + // metrics data for closed CdmEngine instances. + // Callers must acquire the cdms_lock_ before calling this method. + void CloseCdmsWithoutSessions(); uint32_t GenerateSessionSharingId(); @@ -175,6 +170,9 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler { // This contains weak pointers to the CDM instances contained in |cdms_|. std::map cdm_by_session_id_; + // The metrics for cdm engines and sessions that have been closed. + drm_metrics::WvCdmMetricsGroup metrics_group_; + CORE_DISALLOW_COPY_AND_ASSIGN(WvContentDecryptionModule); }; diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index 1b071953..8d50d172 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -24,7 +24,6 @@ Lock WvContentDecryptionModule::session_sharing_id_generation_lock_; WvContentDecryptionModule::WvContentDecryptionModule() {} WvContentDecryptionModule::~WvContentDecryptionModule() { - CloseAllCdms(); ForceDisablePolicyTimer(); } @@ -76,6 +75,8 @@ CdmResponseType WvContentDecryptionModule::CloseSession( cdm_by_session_id_.erase(session_id); } + DisablePolicyTimer(); + return sts; } @@ -329,21 +330,12 @@ bool WvContentDecryptionModule::IsValidServiceCertificate( return cert.has_certificate(); } - -CdmResponseType WvContentDecryptionModule::GetMetrics( - const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics* metrics) { - if (!metrics) { - return PARAMETER_NULL; - } +void WvContentDecryptionModule::GetSerializedMetrics( + std::string* serialized_metrics) { AutoLock auto_lock(cdms_lock_); - auto it = cdms_.find(identifier); - if (it == cdms_.end()) { - LOGE("WVContentDecryptionModule::Close. cdm_identifier not found"); - // TODO(blueeyes): Add a better error. - return UNKNOWN_ERROR; - } - it->second.cdm_engine->GetMetrics()->Serialize(metrics); - return NO_ERROR; + CloseCdmsWithoutSessions(); + metrics_group_.SerializeToString(serialized_metrics); + metrics_group_.Clear(); } WvContentDecryptionModule::CdmInfo::CdmInfo() @@ -379,26 +371,30 @@ CdmEngine* WvContentDecryptionModule::GetCdmForSessionId( return it->second; } -void WvContentDecryptionModule::CloseAllCdms() { - AutoLock auto_lock(cdms_lock_); +// This method requires that the caller first acquire cdms_lock_. +void WvContentDecryptionModule::CloseCdmsWithoutSessions() { for (auto it = cdms_.begin(); it != cdms_.end();) { - it = cdms_.erase(it); - } -} + if (it->second.cdm_engine->SessionSize() != 0) { + ++it; + } else { + // Retrieve the metrics from the engine and any completed + // sessions. Clear the metrics from any completed sessions. + metrics::EngineMetrics* engine_metrics = + it->second.cdm_engine->GetMetrics(); + // engine_metrics should never be null. + if (engine_metrics != NULL) { + engine_metrics->Serialize(metrics_group_.add_metrics()); + } else { + // Engine metrics should never be null. + LOGI( + "WvContentDecryptionModule::CloseCdmsWithoutSessions." + "engine_metrics was unexpectedly NULL."); + } -CdmResponseType WvContentDecryptionModule::CloseCdm( - const CdmIdentifier& cdm_identifier) { - AutoLock auto_lock(cdms_lock_); - auto it = cdms_.find(cdm_identifier); - if (it == cdms_.end()) { - LOGE("WVContentDecryptionModule::Close. cdm_identifier not found"); - // TODO(blueeyes): Create a better error. - return UNKNOWN_ERROR; + // The CDM is no longer used for this identifier, delete it. + it = cdms_.erase(it); + } } - cdms_.erase(it); - - DisablePolicyTimer(); - return NO_ERROR; } void WvContentDecryptionModule::EnablePolicyTimer() { @@ -407,16 +403,28 @@ void WvContentDecryptionModule::EnablePolicyTimer() { policy_timer_.Start(this, kCdmPolicyTimerDurationSeconds); } -// This implementation assumes that the caller has already acquired the -// cdms_lock_. void WvContentDecryptionModule::DisablePolicyTimer() { + bool cdms_is_empty = false; + { + AutoLock auto_lock(cdms_lock_); + CloseCdmsWithoutSessions(); + cdms_is_empty = cdms_.empty(); + } + AutoLock auto_lock(policy_timer_lock_); - if (cdms_.empty() && policy_timer_.IsRunning()) { - policy_timer_.Stop(); + if (cdms_is_empty) { + if (policy_timer_.IsRunning()) { + policy_timer_.Stop(); + } } } void WvContentDecryptionModule::ForceDisablePolicyTimer() { + { + AutoLock auto_lock(cdms_lock_); + CloseCdmsWithoutSessions(); + } + AutoLock auto_lock(policy_timer_lock_); if (policy_timer_.IsRunning()) { policy_timer_.Stop(); diff --git a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp index b96e3a7f..0d4332c1 100644 --- a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp +++ b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp @@ -605,21 +605,24 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase { EXPECT_TRUE(license_renewal.has_key_control_nonce()); } - void ValidateHasUpdateUsageEntry(const drm_metrics::WvCdmMetrics& metrics) + void ValidateHasUpdateUsageEntry(const std::string& serialized_metrics) const { + drm_metrics::WvCdmMetricsGroup group; + ASSERT_TRUE(group.ParseFromString(serialized_metrics)); bool has_update_usage_entry_metrics = false; - for (const auto& session : metrics.session_metrics()) { - has_update_usage_entry_metrics |= - session.crypto_metrics() - .crypto_session_update_usage_entry_time_us().size() > 0; - has_update_usage_entry_metrics |= - session.crypto_metrics().oemcrypto_update_usage_entry().size() > 0; + for (const auto& metrics : group.metrics()) { + for (const auto& session : metrics.session_metrics()) { + has_update_usage_entry_metrics |= + session.crypto_metrics() + .crypto_session_update_usage_entry_time_us().size() > 0; + has_update_usage_entry_metrics |= + session.crypto_metrics().oemcrypto_update_usage_entry().size() > 0; + } } - std::string serialized_metrics; - ASSERT_TRUE(metrics.SerializeToString(&serialized_metrics)); EXPECT_TRUE(has_update_usage_entry_metrics) << "metrics: " << wvcdm::b2a_hex(serialized_metrics); + } void QueryKeyStatus(bool streaming, bool expect_renewal, @@ -1449,9 +1452,9 @@ TEST_P(WvCdmStreamingUsageReportTest, UsageTest) { } // Validate that update usage table entry is exercised. - drm_metrics::WvCdmMetrics metrics; - ASSERT_EQ(NO_ERROR, decryptor_.GetMetrics(kDefaultCdmIdentifier, &metrics)); - ValidateHasUpdateUsageEntry(metrics); + std::string serialized_metrics; + decryptor_.GetSerializedMetrics(&serialized_metrics); + ValidateHasUpdateUsageEntry(serialized_metrics); } INSTANTIATE_TEST_CASE_P(Cdm, WvCdmStreamingUsageReportTest, diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index 50ede011..9af2eea2 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -51,8 +51,7 @@ const int kHttpInternalServerError = 500; const wvcdm::CdmIdentifier kExampleIdentifier = { wvcdm::EMPTY_SPOID, "com.example", - "com.example", - 7 + "com.example" }; // Protobuf generated classes @@ -393,19 +392,15 @@ const uint32_t kSingleEncryptedSubSampleIcpLicenseExpirationWindow = 2; struct SessionSharingSubSampleInfo { SubSampleInfo* sub_sample; bool session_sharing_enabled; - wvcdm::CdmIdentifier cdm_identifier; }; SessionSharingSubSampleInfo session_sharing_sub_samples[] = { - {&clear_sub_sample, false, wvcdm::kDefaultCdmIdentifier}, - {&clear_sub_sample, true, wvcdm::kDefaultCdmIdentifier}, - {&clear_sub_sample_no_key, false, wvcdm::kDefaultCdmIdentifier}, - {&clear_sub_sample_no_key, true, wvcdm::kDefaultCdmIdentifier}, - {&single_encrypted_sub_sample, false, wvcdm::kDefaultCdmIdentifier}, - {&single_encrypted_sub_sample, true, wvcdm::kDefaultCdmIdentifier}, - // The last entry simulates session sharing using the non default - // identifier. - {&single_encrypted_sub_sample, true, kExampleIdentifier}}; + {&clear_sub_sample, false}, + {&clear_sub_sample, true}, + {&clear_sub_sample_no_key, false}, + {&clear_sub_sample_no_key, true}, + {&single_encrypted_sub_sample, false}, + {&single_encrypted_sub_sample, true}}; struct UsageInfoSubSampleInfo { SubSampleInfo* sub_sample; @@ -1306,14 +1301,6 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase { GenerateKeyRequest(init_data, license_type, NULL); } - void GenerateKeyRequest(const std::string& init_data, - CdmLicenseType license_type, - const CdmIdentifier& identifier) { - CdmAppParameterMap app_parameters; - GenerateKeyRequest(wvcdm::KEY_MESSAGE, "video/mp4", init_data, - app_parameters, license_type, identifier, NULL); - } - void GenerateKeyRequest(const std::string& init_data, CdmLicenseType license_type, CdmClientPropertySet* property_set) { @@ -1355,13 +1342,7 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase { decryptor_.GenerateKeyRequest( session_id_, key_set_id, init_data_type, init_data, license_type, app_parameters, property_set, - cdm_identifier, &key_request)) - << "session_id_ " << session_id_ << std::endl - << "init_data (hex) " << wvcdm::b2a_hex(init_data) << std::endl - << "key_set_id " << key_set_id << std::endl - << "cdm_identifier.origin " << cdm_identifier.origin << std::endl - << "cdm_identifier.app_package_name " << cdm_identifier.app_package_name << std::endl - << "cdm_identifier.unique_id " << cdm_identifier.unique_id << std::endl; + cdm_identifier, &key_request)); key_msg_ = key_request.message; EXPECT_EQ(0u, key_request.url.size()); } @@ -3881,20 +3862,14 @@ class WvCdmSessionSharingTest TEST_P(WvCdmSessionSharingTest, SessionSharingTest) { SessionSharingSubSampleInfo* session_sharing_info = GetParam(); - CdmIdentifier cdm_identifier = session_sharing_info->cdm_identifier; - if (!cdm_identifier.IsEquivalentToDefault()) { - Provision(session_sharing_info->cdm_identifier, kLevelDefault); - } - TestWvCdmClientPropertySet property_set; property_set.set_session_sharing_mode( session_sharing_info->session_sharing_enabled); - ASSERT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, &property_set, - cdm_identifier, NULL, - &session_id_)); + decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier, + NULL, &session_id_); CdmSessionId gp_session_id_1 = session_id_; - GenerateKeyRequest(g_key_id, kLicenseTypeStreaming, cdm_identifier); + GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); VerifyKeyRequestResponse(g_license_server, g_client_auth); // TODO(rfrias): Move content information to ConfigTestEnv @@ -3905,11 +3880,10 @@ TEST_P(WvCdmSessionSharingTest, SessionSharingTest) { "edef8ba979d64acea3c827dcd51d21ed00000014" // Widevine system id "08011210bdf1cb4fffc6506b8b7945b0bd2917fb"); // pssh data - ASSERT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, &property_set, - cdm_identifier, NULL, - &session_id_)); + decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier, + NULL, &session_id_); CdmSessionId gp_session_id_2 = session_id_; - GenerateKeyRequest(gp_key_id2, kLicenseTypeStreaming, cdm_identifier); + GenerateKeyRequest(gp_key_id2, kLicenseTypeStreaming); VerifyKeyRequestResponse(g_license_server, gp_client_auth2); SubSampleInfo* data = session_sharing_info->sub_sample; @@ -3924,10 +3898,7 @@ TEST_P(WvCdmSessionSharingTest, SessionSharingTest) { if (session_sharing_info->session_sharing_enabled || !data->is_encrypted) { EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(gp_session_id_2, data->validate_key_id, - decryption_parameters)) - << "session_sharing_info->session_sharing_enabled " - << session_sharing_info->session_sharing_enabled << std::endl - << "data->is_encrypted " << data->is_encrypted << std::endl; + decryption_parameters)); EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(), decrypt_buffer.begin())); } else { @@ -3936,19 +3907,13 @@ TEST_P(WvCdmSessionSharingTest, SessionSharingTest) { decryption_parameters)); } - if (!cdm_identifier.IsEquivalentToDefault()) { - // Unprovision both security level certs. - decryptor_.Unprovision(kSecurityLevelL1, cdm_identifier); - decryptor_.Unprovision(kSecurityLevelL3, cdm_identifier); - } - decryptor_.CloseSession(gp_session_id_1); decryptor_.CloseSession(gp_session_id_2); } INSTANTIATE_TEST_CASE_P(Cdm, WvCdmSessionSharingTest, ::testing::Range(&session_sharing_sub_samples[0], - &session_sharing_sub_samples[7])); + &session_sharing_sub_samples[6])); TEST_F(WvCdmRequestLicenseTest, SessionSharingTest) { TestWvCdmClientPropertySet property_set; diff --git a/libwvdrmengine/cdm/test/wv_cdm_metrics_test.cpp b/libwvdrmengine/cdm/test/wv_cdm_metrics_test.cpp index 3963d036..e620a9cd 100644 --- a/libwvdrmengine/cdm/test/wv_cdm_metrics_test.cpp +++ b/libwvdrmengine/cdm/test/wv_cdm_metrics_test.cpp @@ -30,10 +30,11 @@ class WvContentDecryptionModuleMetricsTest : public ::testing::Test { wvcdm::WvContentDecryptionModule decryptor_; }; -TEST_F(WvContentDecryptionModuleMetricsTest, IdentifierNotFound) { - drm_metrics::WvCdmMetrics metrics; - ASSERT_EQ(wvcdm::UNKNOWN_ERROR, - decryptor_.GetMetrics(kDefaultCdmIdentifier, &metrics)); +TEST_F(WvContentDecryptionModuleMetricsTest, NoMetrics) { + // Get metrics before any operations are performed. + std::string serialized_metrics; + decryptor_.GetSerializedMetrics(&serialized_metrics); + EXPECT_TRUE(serialized_metrics.empty()); } TEST_F(WvContentDecryptionModuleMetricsTest, EngineOnlyMetrics) { @@ -47,21 +48,27 @@ TEST_F(WvContentDecryptionModuleMetricsTest, EngineOnlyMetrics) { decryptor_.GetProvisioningRequest(cert_type, cert_authority, kDefaultCdmIdentifier, &request, &provisioning_server_url)); + std::string serialized_metrics; + decryptor_.GetSerializedMetrics(&serialized_metrics); - drm_metrics::WvCdmMetrics metrics; - ASSERT_EQ(wvcdm::NO_ERROR, - decryptor_.GetMetrics(kDefaultCdmIdentifier, &metrics)); + drm_metrics::WvCdmMetricsGroup metrics_group; + ASSERT_TRUE(metrics_group.ParseFromString(serialized_metrics)) + << "Unexpected failure deserializing metrics: " + << wvcdm::b2a_hex(serialized_metrics); + ASSERT_THAT(metrics_group.metrics().size(), Eq(1)); // 100 is an arbitrary high value that shouldn't ever occur. EXPECT_THAT( - metrics.engine_metrics().oemcrypto_initialization_mode().int_value(), + metrics_group.metrics(0).engine_metrics() + .oemcrypto_initialization_mode().int_value(), Lt(100)); EXPECT_THAT( - metrics.engine_metrics().oemcrypto_initialization_mode().int_value(), + metrics_group.metrics(0).engine_metrics() + .oemcrypto_initialization_mode().int_value(), Ge(0)); - ASSERT_THAT(metrics.engine_metrics() + ASSERT_THAT(metrics_group.metrics(0).engine_metrics() .cdm_engine_get_provisioning_request_time_us().size(), Eq(1)); - EXPECT_THAT(metrics.engine_metrics() + EXPECT_THAT(metrics_group.metrics(0).engine_metrics() .cdm_engine_get_provisioning_request_time_us(0) .operation_count(), Eq(1u)); @@ -78,80 +85,81 @@ TEST_F(WvContentDecryptionModuleMetricsTest, EngineAndSessionMetrics) { decryptor_.OpenSession(key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id)); - drm_metrics::WvCdmMetrics metrics; - ASSERT_EQ(wvcdm::NO_ERROR, - decryptor_.GetMetrics(kDefaultCdmIdentifier, &metrics)); + // The metrics will have a single engine and single session stats. std::string serialized_metrics; - ASSERT_TRUE(metrics.SerializeToString(&serialized_metrics)); + decryptor_.GetSerializedMetrics(&serialized_metrics); // Spot check some metric values. + drm_metrics::WvCdmMetricsGroup metrics_group; + ASSERT_TRUE(metrics_group.ParseFromString(serialized_metrics)) + << "Unexpected failure deserializing metrics: " + << wvcdm::b2a_hex(serialized_metrics); + ASSERT_THAT(metrics_group.metrics().size(), Eq(1)); + // Validate engine-level metrics. - EXPECT_TRUE(metrics.engine_metrics().has_oemcrypto_initialization_mode()); - ASSERT_THAT(metrics.engine_metrics().cdm_engine_open_session().size(), Eq(1)); - EXPECT_THAT(metrics.engine_metrics().cdm_engine_open_session(0).count(), - Eq(1)); - EXPECT_THAT(metrics.engine_metrics() + EXPECT_TRUE(metrics_group.metrics(0).engine_metrics() + .has_oemcrypto_initialization_mode()); + ASSERT_THAT( + metrics_group.metrics(0).engine_metrics().cdm_engine_open_session().size(), + Eq(1)); + EXPECT_THAT(metrics_group.metrics(0).engine_metrics() + .cdm_engine_open_session(0).count(), Eq(1)); + EXPECT_THAT(metrics_group.metrics(0).engine_metrics() .cdm_engine_open_session(0).attributes().error_code(), Eq(CdmResponseType::NEED_PROVISIONING)); // Validate a session-level metric. - ASSERT_THAT(metrics.session_metrics().size(), Eq(1)); + ASSERT_THAT(metrics_group.metrics(0).session_metrics().size(), Eq(1)); EXPECT_THAT( - metrics.session_metrics(0).cdm_session_life_span_ms().double_value(), + metrics_group.metrics(0).session_metrics(0) + .cdm_session_life_span_ms().double_value(), Gt(0.0)) << "Unexpected failure with session_metrics: " << wvcdm::b2a_hex(serialized_metrics); } -TEST_F(WvContentDecryptionModuleMetricsTest, - DifferentCdmIdentifiersHaveDifferentMetrics) { +TEST_F(WvContentDecryptionModuleMetricsTest, MultipleEngineMetric) { CdmSessionId session_id; wvcdm::CdmKeySystem key_system("com.widevine"); - CdmIdentifier identifiers[] = { kDefaultCdmIdentifier, - { "foo", "bar", "baz", 7 }, - // Note that this has all the same parameters - // as the one above except for the unique_id. - { "foo", "bar", "baz", 8 }}; - const int cdm_engine_count = 3; - for (int i = 0; i < cdm_engine_count; i++) { - // To make sure we can detect different engine metrics, - // make the open session call a different number of times for - // each identifier. - for (int j = 0; j <= i; j ++) { - EXPECT_EQ(CdmResponseType::NEED_PROVISIONING, - decryptor_.OpenSession(key_system, NULL, - identifiers[i], NULL, &session_id)); - } - } + CdmIdentifier identifier = { "foo", "bar", "baz" }; - for (int i = 0; i < cdm_engine_count; i++) { - drm_metrics::WvCdmMetrics metrics; - metrics.Clear(); - ASSERT_EQ(wvcdm::NO_ERROR, - decryptor_.GetMetrics(identifiers[i], &metrics)); - std::string serialized_metrics; - ASSERT_TRUE(metrics.SerializeToString(&serialized_metrics)); + // Openning the session will fail with NEEDS_PROVISIONING error. But it will + // still create some session-level stats. + EXPECT_EQ(CdmResponseType::NEED_PROVISIONING, + decryptor_.OpenSession(key_system, NULL, + kDefaultCdmIdentifier, NULL, &session_id)); + // Open a second engine with a custom identifier. + EXPECT_EQ(CdmResponseType::NEED_PROVISIONING, + decryptor_.OpenSession(key_system, NULL, + identifier, NULL, &session_id)); - ASSERT_THAT(metrics.engine_metrics().cdm_engine_open_session().size(), - Eq(1)); - // The number of times open session was called should match the index - // of the identifier - EXPECT_THAT(metrics.engine_metrics().cdm_engine_open_session(0).count(), - Eq(i + 1)); + // The metrics will now have two engines with single session stats each. + std::string serialized_metrics; + decryptor_.GetSerializedMetrics(&serialized_metrics); + + // Spot check some metric values. + drm_metrics::WvCdmMetricsGroup metrics_group; + ASSERT_TRUE(metrics_group.ParseFromString(serialized_metrics)); + + // Two engine-level metrics are expected. + ASSERT_THAT(metrics_group.metrics().size(), Eq(2)); + + for (int i = 0; i < metrics_group.metrics().size(); i++) { + drm_metrics::WvCdmMetrics::EngineMetrics engine_metrics = + metrics_group.metrics(i).engine_metrics(); + // Validate an engine-level metric. + EXPECT_TRUE(engine_metrics.has_oemcrypto_initialization_mode()); + ASSERT_THAT(engine_metrics.cdm_engine_open_session().size(), Eq(1)); + EXPECT_THAT(engine_metrics.cdm_engine_open_session(0).count(), Eq(1)); EXPECT_THAT( - metrics.engine_metrics() - .cdm_engine_open_session(0).attributes().error_code(), + engine_metrics.cdm_engine_open_session(0).attributes().error_code(), Eq(CdmResponseType::NEED_PROVISIONING)); - // Spot check a session-level metric. - ASSERT_THAT(metrics.session_metrics().size(), Eq(i + 1)) - << "Unexpected failure with session_metrics: " - << wvcdm::b2a_hex(serialized_metrics); - EXPECT_THAT(metrics.session_metrics(0) - .cdm_session_life_span_ms().double_value(), Gt(0.0)) - << "Unexpected failure with session_metrics: " - << wvcdm::b2a_hex(serialized_metrics); + // Validate a session-level metric. + ASSERT_THAT(metrics_group.metrics(i).session_metrics().size(), Eq(1)); + EXPECT_THAT(metrics_group.metrics(i).session_metrics(0) + .cdm_session_life_span_ms().double_value(), Gt(0.0)); } } -} // wvcdm namespace +} diff --git a/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h index 8b6db1e3..34f68cad 100644 --- a/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h @@ -365,10 +365,6 @@ struct WVDrmPlugin : public IDrmPlugin, IDrmPluginListener, const std::string& origin() const { return mCdmIdentifier.origin; } bool set_origin(const std::string& id); - // Indicates whether the builder can still be modified. This returns false - // until a call to getCdmIdentifier. - bool is_sealed() { return mIsIdentifierSealed; } - private: WVDRM_DISALLOW_COPY_AND_ASSIGN(CdmIdentifierBuilder); @@ -386,13 +382,6 @@ struct WVDrmPlugin : public IDrmPlugin, IDrmPluginListener, // outside this class should use getDeviceUniqueId() to get the // application-safe device-unique ID. Status getOemcryptoDeviceId(std::string* id); - - // The unique identifier is meant to ensure that two clients with the - // same spoid, origin and app package name still get different cdm engine - // instances. This is a stepping stone to simplifying the implementation. - // Note that we do not have a lock or mutex around this object. We assume - // that locking is handled external to this object. - uint32_t getNextUniqueId(); } mCdmIdentifierBuilder; sp const mCDM; diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp index cc2eb2ab..6782fdd1 100644 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp @@ -392,7 +392,7 @@ status_t WVDrmPlugin::provideProvisionResponse( } CdmProvisioningResponse cdmResponse(response.begin(), response.end()); if (cdmResponse == kSpecialUnprovisionResponse) { - if (mCdmIdentifier.IsEquivalentToDefault()) { + if (mCdmIdentifier == kDefaultCdmIdentifier) { return kErrorNoOriginSpecified; } return unprovision(mCdmIdentifier); @@ -540,14 +540,9 @@ status_t WVDrmPlugin::getPropertyByteArray(const String8& name, } else if (name == "serviceCertificate") { value = ToVector(mPropertySet.service_certificate()); } else if (name == "metrics") { - std::string serialized_metrics; - drm_metrics::WvCdmMetrics metrics; - mCDM->GetMetrics(mCdmIdentifier, &metrics); - if (!metrics.SerializeToString(&serialized_metrics)) { - return android::ERROR_DRM_UNKNOWN; - } else { - value = ToVector(serialized_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 0cd85fd2..2d909850 100644 --- a/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp @@ -14,7 +14,6 @@ #include "mapErrors-inl.h" #include "media/stagefright/MediaErrors.h" -#include "metrics.pb.h" #include "openssl/sha.h" #include "wv_cdm_constants.h" @@ -140,16 +139,6 @@ WVDrmPlugin::~WVDrmPlugin() { } } mCryptoSessions.clear(); - CdmIdentifier identifier; - Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - ALOGE("Failed to get cdm identifier %d", status); - } else { - status = mapCdmResponseType(mCDM->CloseCdm(identifier)); - if (status != Status::OK) { - ALOGE("Failed to get close cdm %d", status); - } - } } Status WVDrmPlugin::openSessionCommon(std::vector& sessionId) { @@ -627,7 +616,7 @@ Return WVDrmPlugin::provideProvisionResponse( CdmProvisioningResponse cdmResponse(resp.begin(), resp.end()); if (cdmResponse == kSpecialUnprovisionResponse) { - if (identifier.IsEquivalentToDefault()) { + if (identifier == kDefaultCdmIdentifier) { ALOGW("Returns UNKNOWN error for legacy status kErrorNoOriginSpecified"); _hidl_cb(Status::ERROR_DRM_UNKNOWN, toHidlVec(certificate), toHidlVec(wrappedKey)); @@ -995,27 +984,9 @@ Return WVDrmPlugin::getPropertyByteArray( } else if (name == "serviceCertificate") { value = StrToVector(mPropertySet.service_certificate()); } else if (name == "metrics") { - drm_metrics::WvCdmMetrics metrics; - // If the cdm identifier is not yet sealed, then there are no metrics - // for that cdm engine. Avoid calling getCdmIdentifier and sealing - // the identifier builder. - if (mCdmIdentifierBuilder.is_sealed()) { - CdmIdentifier identifier; - status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - ALOGE("Unexpected error retrieving cdm identifier: %d", status); - } else { - status = mapCdmResponseType(mCDM->GetMetrics(identifier, &metrics)); - } - } - if (status == Status::OK) { - std::string serialized_metrics; - if (!metrics.SerializeToString(&serialized_metrics)) { - status = Status::ERROR_DRM_UNKNOWN; - } else { - value = StrToVector(serialized_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 = Status::ERROR_DRM_CANNOT_HANDLE; @@ -1670,7 +1641,6 @@ WVDrmPlugin::CdmIdentifierBuilder::CdmIdentifierBuilder( mAppPackageName(appPackageName), mParent(parent) { mCdmIdentifier.app_package_name = mAppPackageName; - mCdmIdentifier.unique_id = getNextUniqueId(); } Status WVDrmPlugin::CdmIdentifierBuilder::getCdmIdentifier( @@ -1678,6 +1648,7 @@ Status WVDrmPlugin::CdmIdentifierBuilder::getCdmIdentifier( if (!mIsIdentifierSealed) { Status res = calculateSpoid(); if (res != Status::OK) return res; + mIsIdentifierSealed = true; } *identifier = mCdmIdentifier; @@ -1746,12 +1717,6 @@ Status WVDrmPlugin::CdmIdentifierBuilder::getOemcryptoDeviceId( return mParent.queryProperty(wvcdm::QUERY_KEY_DEVICE_ID, *id); } -uint32_t WVDrmPlugin::CdmIdentifierBuilder::getNextUniqueId() { - // Start with 1. 0 is reserved for the default cdm identifier. - static uint32_t unique_id = 1; - return ++unique_id; -} - } // namespace widevine } // namespace V1_1 } // namespace drm diff --git a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp index fd36288a..3876f1f0 100644 --- a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp +++ b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp @@ -20,7 +20,6 @@ #include "gtest/gtest.h" #include "media/stagefright/foundation/ABase.h" #include "media/stagefright/MediaErrors.h" -#include "string_conversions.h" #include "wv_cdm_constants.h" #include "wv_cdm_types.h" #include "wv_content_decryption_module.h" @@ -121,17 +120,15 @@ const uint8_t* const kUnprovisionResponse = const size_t kUnprovisionResponseSize = 11; const std::string kDeviceId("0123456789\0ABCDEF", 17); -// This is a serialized WvCdmMetrics message containing a small amount of +// 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 kSerializedMetricsHex[] = - "0a580a001a0210072202100d2a02100832182216636f6d2e676f6f676c652e616e64726f69" - "642e676d734208220631342e302e304a06080112020800520610d5f3fad5056a0b1d00fd4c" - "47280132020804a2010608011202080012cb010a0622047369643412b5010a021001520919" - "1d5a643bdfff50405a0b1d00d01945280132021001620d1d00f8e84528013204080020006a" - "0310b739820102100d8a01060801120248009a010310ff01da0106080112024800e2010e1d" - "005243472801320528800248009a020d1d00b016452801320428404800a202060801120248" - "19aa0206080212024800b2020b1d8098f047280132024800ba02021001ca020b1d00101945" - "280132024800e202021004fa02021002a203021000b2030210021a09196891ed7c3f355040"; +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 +}; #define N_ELEM(a) (sizeof(a)/sizeof(a[0])) } // anonymous namespace @@ -201,8 +198,7 @@ class MockCDM : public WvContentDecryptionModule { MOCK_METHOD1(IsValidServiceCertificate, bool(const std::string&)); - MOCK_METHOD2(GetMetrics, CdmResponseType(const CdmIdentifier&, - drm_metrics::WvCdmMetrics*)); + MOCK_METHOD1(GetSerializedMetrics, void(std::string*)); }; class MockCrypto : public WVGenericCryptoInterface { @@ -1130,9 +1126,8 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { static const std::string oemCryptoApiVersion = "13"; static const std::string currentSRMVersion = "1"; static const std::string cdmVersion = "Infinity Minus 1"; - drm_metrics::WvCdmMetrics expected_metrics; - std::string serialized_metrics = wvcdm::a2bs_hex(kSerializedMetricsHex); - ASSERT_TRUE(expected_metrics.ParseFromString(serialized_metrics)); + std::string serializedMetrics( + kSerializedMetrics, kSerializedMetrics + sizeof(kSerializedMetrics)); EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1), @@ -1176,9 +1171,8 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { .WillOnce(DoAll(SetArgPointee<2>(cdmVersion), testing::Return(wvcdm::NO_ERROR))); - EXPECT_CALL(*cdm, GetMetrics(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(expected_metrics), - testing::Return(wvcdm::NO_ERROR))); + EXPECT_CALL(*cdm, GetSerializedMetrics(_)) + .WillOnce(SetArgPointee<0>(serializedMetrics)); WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); std::string stringResult; @@ -1281,51 +1275,14 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { EXPECT_STREQ(currentSRMVersion.c_str(), stringResult.c_str()); }); - // This call occurs before any open session or other call. This means - // that the cdm identifer is not yet sealed, and metrics return empty - // metrics data. plugin.getPropertyByteArray( hidl_string("metrics"), [&](Status status, hidl_vec vectorResult) { ASSERT_EQ(Status::OK, status); std::vector id(vectorResult); - const char empty[] = {}; - EXPECT_THAT(id, ElementsAreArray(empty, sizeof(empty))); + EXPECT_THAT(id, ElementsAreArray(serializedMetrics.data(), + serializedMetrics.size())); }); - - // Set expectations for the OpenSession call and a CloseSession call. - EXPECT_CALL(*cdm, - OpenSession(StrEq("com.widevine"), _, HasOrigin(EMPTY_ORIGIN), _, _)) - .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))); - // Provide expected behavior when plugin requests session control info - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - EXPECT_CALL(*cdm, CloseSession(_)) - .Times(AtLeast(0)); - - // This call causes the cdm identifier to become sealed. - std::vector sessionId; - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), - hSessionId.data() + hSessionId.size()); - }); - - // This call occurs after open session. The CDM identifer should be sealed. - // And the call should populate the mock metrics data. - plugin.getPropertyByteArray( - hidl_string("metrics"), - [&](Status status, hidl_vec vectorResult) { - ASSERT_EQ(Status::OK, status); - std::vector id(vectorResult); - EXPECT_THAT(id, ElementsAreArray(serialized_metrics.data(), - serialized_metrics.size())); - }); - - ASSERT_EQ(Status::OK, plugin.closeSession(toHidlVec(sessionId))); } 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 f9df36fb..50fddc43 100644 --- a/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp +++ b/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp @@ -13,7 +13,6 @@ #include "media/stagefright/foundation/ABase.h" #include "media/stagefright/foundation/AString.h" #include "media/stagefright/MediaErrors.h" -#include "string_conversions.h" #include "wv_cdm_constants.h" #include "wv_cdm_types.h" #include "wv_content_decryption_module.h" @@ -34,18 +33,14 @@ const uint8_t* const kUnprovisionResponse = reinterpret_cast("unprovision"); const size_t kUnprovisionResponseSize = 11; -// This is a serialized WvCdmMetrics message containing a small amount of +// 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 kSerializedMetricsHex[] = - "0a580a001a0210072202100d2a02100832182216636f6d2e676f6f676c652e616e64726f69" - "642e676d734208220631342e302e304a06080112020800520610d5f3fad5056a0b1d00fd4c" - "47280132020804a2010608011202080012cb010a0622047369643412b5010a021001520919" - "1d5a643bdfff50405a0b1d00d01945280132021001620d1d00f8e84528013204080020006a" - "0310b739820102100d8a01060801120248009a010310ff01da0106080112024800e2010e1d" - "005243472801320528800248009a020d1d00b016452801320428404800a202060801120248" - "19aa0206080212024800b2020b1d8098f047280132024800ba02021001ca020b1d00101945" - "280132024800e202021004fa02021002a203021000b2030210021a09196891ed7c3f355040"; - +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 { @@ -113,8 +108,7 @@ class MockCDM : public WvContentDecryptionModule { MOCK_METHOD1(IsValidServiceCertificate, bool(const std::string&)); - MOCK_METHOD2(GetMetrics, CdmResponseType(const CdmIdentifier&, - drm_metrics::WvCdmMetrics*)); + MOCK_METHOD1(GetSerializedMetrics, void(std::string*)); }; class MockCrypto : public WVGenericCryptoInterface { @@ -856,10 +850,8 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { static const string oemCryptoApiVersion = "10"; static const string currentSRMVersion = "1"; static const string cdmVersion = "Infinity Minus 1"; - - drm_metrics::WvCdmMetrics expected_metrics; - std::string serialized_metrics = wvcdm::a2bs_hex(kSerializedMetricsHex); - ASSERT_TRUE(expected_metrics.ParseFromString(serialized_metrics)); + string serializedMetrics(kSerializedMetrics, + kSerializedMetrics + sizeof(kSerializedMetrics)); EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1), @@ -903,9 +895,8 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { .WillOnce(DoAll(SetArgPointee<2>(cdmVersion), Return(wvcdm::NO_ERROR))); - EXPECT_CALL(*cdm, GetMetrics(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(expected_metrics), - testing::Return(wvcdm::NO_ERROR))); + EXPECT_CALL(*cdm, GetSerializedMetrics(_)) + .WillOnce(SetArgPointee<0>(serializedMetrics)); String8 stringResult; Vector vectorResult; @@ -971,8 +962,8 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { vectorResult.clear(); res = plugin.getPropertyByteArray(String8("metrics"), vectorResult); ASSERT_EQ(OK, res); - EXPECT_THAT(vectorResult, ElementsAreArray(serialized_metrics.data(), - serialized_metrics.size())); + EXPECT_THAT(vectorResult, ElementsAreArray(serializedMetrics.data(), + serializedMetrics.size())); } TEST_F(WVDrmPluginTest, DoesNotGetUnknownProperties) {