From d2e91faf8eb3f9b7bbcbbce22385ec4f1699a3d9 Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Thu, 7 May 2015 10:26:07 -0700 Subject: [PATCH] Respect Client Properties when reporting CDM Status [ Merge from go/wvgerrit/14286 ] CDM now reports status information associated with the specified security level. Earlier information would be reported from the default security level. b/18709693 Change-Id: I7a01e8ea9773b56951c207437ce85e567fd32b09 --- libwvdrmengine/cdm/core/include/cdm_engine.h | 3 +- .../cdm/core/include/oemcrypto_adapter.h | 3 +- .../cdm/core/include/wv_cdm_types.h | 6 +++ libwvdrmengine/cdm/core/src/cdm_engine.cpp | 7 ++- .../include/wv_content_decryption_module.h | 3 +- .../cdm/src/wv_content_decryption_module.cpp | 6 ++- .../cdm/test/request_license_test.cpp | 53 +++++++++++++++++-- libwvdrmengine/include/WVErrors.h | 3 +- libwvdrmengine/include/mapErrors-inl.h | 2 + libwvdrmengine/mediadrm/include/WVDrmPlugin.h | 6 ++- libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp | 20 +++++-- .../mediadrm/test/WVDrmPlugin_test.cpp | 28 +++++----- 12 files changed, 110 insertions(+), 30 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/cdm_engine.h b/libwvdrmengine/cdm/core/include/cdm_engine.h index a50ed281..335b59d8 100644 --- a/libwvdrmengine/cdm/core/include/cdm_engine.h +++ b/libwvdrmengine/cdm/core/include/cdm_engine.h @@ -98,7 +98,8 @@ class CdmEngine { const CdmKeyResponse& key_data); // Query system information - virtual CdmResponseType QueryStatus(CdmQueryMap* info); + virtual CdmResponseType QueryStatus(SecurityLevel security_level, + CdmQueryMap* info); // Query session information virtual CdmResponseType QuerySessionStatus(const CdmSessionId& session_id, diff --git a/libwvdrmengine/cdm/core/include/oemcrypto_adapter.h b/libwvdrmengine/cdm/core/include/oemcrypto_adapter.h index c759e8a2..5d7a648c 100644 --- a/libwvdrmengine/cdm/core/include/oemcrypto_adapter.h +++ b/libwvdrmengine/cdm/core/include/oemcrypto_adapter.h @@ -4,11 +4,10 @@ #define WVCDM_CORE_OEMCRYPTO_ADAPTER_H_ #include "OEMCryptoCENC.h" +#include "wv_cdm_types.h" namespace wvcdm { -enum SecurityLevel { kLevelDefault, kLevel3 }; - // This attempts to open a session at the desired security level. // If one level is not available, the other will be used instead. OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session, diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 5abafb5d..47714cb5 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -185,6 +185,7 @@ enum CdmResponseType { CLIENT_ID_AES_ENCRYPT_ERROR, CLIENT_ID_RSA_INIT_ERROR, CLIENT_ID_RSA_ENCRYPT_ERROR, + INVALID_QUERY_STATUS, }; enum CdmKeyStatus { @@ -206,6 +207,11 @@ enum CdmLicenseType { kLicenseTypeRelease }; +enum SecurityLevel { + kLevelDefault, + kLevel3 +}; + enum CdmSecurityLevel { kSecurityLevelUninitialized, kSecurityLevelL1, diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index a3953713..3ff1728a 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -393,9 +393,14 @@ CdmResponseType CdmEngine::RenewKey(const CdmSessionId& session_id, return KEY_ADDED; } -CdmResponseType CdmEngine::QueryStatus(CdmQueryMap* key_info) { +CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level, + CdmQueryMap* key_info) { LOGI("CdmEngine::QueryStatus"); CryptoSession crypto_session; + if (security_level == kLevel3) { + CdmResponseType status = crypto_session.Open(kLevel3); + if (NO_ERROR != status) return INVALID_QUERY_STATUS; + } switch (crypto_session.GetSecurityLevel()) { case kSecurityLevelL1: (*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L1; diff --git a/libwvdrmengine/cdm/include/wv_content_decryption_module.h b/libwvdrmengine/cdm/include/wv_content_decryption_module.h index b52e190a..182ec088 100644 --- a/libwvdrmengine/cdm/include/wv_content_decryption_module.h +++ b/libwvdrmengine/cdm/include/wv_content_decryption_module.h @@ -60,7 +60,8 @@ class WvContentDecryptionModule : public TimerHandler { virtual CdmResponseType RemoveKeys(const CdmSessionId& session_id); // Query system information - virtual CdmResponseType QueryStatus(CdmQueryMap* key_info); + virtual CdmResponseType QueryStatus(SecurityLevel security_level, + CdmQueryMap* key_info); // Query session information virtual CdmResponseType QuerySessionStatus(const CdmSessionId& session_id, diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index fd8c99fa..770238da 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -117,8 +117,10 @@ CdmResponseType WvContentDecryptionModule::RemoveKeys( return cdm_engine_->RemoveKeys(session_id); } -CdmResponseType WvContentDecryptionModule::QueryStatus(CdmQueryMap* key_info) { - return cdm_engine_->QueryStatus(key_info); +CdmResponseType WvContentDecryptionModule::QueryStatus( + SecurityLevel security_level, + CdmQueryMap* key_info) { + return cdm_engine_->QueryStatus(security_level, key_info); } CdmResponseType WvContentDecryptionModule::QuerySessionStatus( diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index afbdb952..33b25ac5 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -28,6 +28,7 @@ using ::testing::_; using ::testing::AllOf; using ::testing::AtLeast; +using ::testing::Contains; using ::testing::Each; using ::testing::IsEmpty; using ::testing::Not; @@ -1723,7 +1724,8 @@ TEST_F(WvCdmRequestLicenseTest, QueryUnmodifiedSessionStatus) { // Test that the global value is returned when no properties are modifying it. CdmQueryMap system_query_info; CdmQueryMap::iterator system_itr; - ASSERT_EQ(wvcdm::NO_ERROR, decryptor_.QueryStatus(&system_query_info)); + ASSERT_EQ(wvcdm::NO_ERROR, + decryptor_.QueryStatus(kLevelDefault, &system_query_info)); system_itr = system_query_info.find(wvcdm::QUERY_KEY_SECURITY_LEVEL); ASSERT_TRUE(system_itr != system_query_info.end()); @@ -1790,7 +1792,8 @@ TEST_F(WvCdmRequestLicenseTest, QueryKeyStatus) { TEST_F(WvCdmRequestLicenseTest, QueryStatus) { CdmQueryMap query_info; CdmQueryMap::iterator itr; - EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.QueryStatus(&query_info)); + EXPECT_EQ(wvcdm::NO_ERROR, + decryptor_.QueryStatus(kLevelDefault, &query_info)); itr = query_info.find(wvcdm::QUERY_KEY_SECURITY_LEVEL); ASSERT_TRUE(itr != query_info.end()); @@ -1813,6 +1816,49 @@ TEST_F(WvCdmRequestLicenseTest, QueryStatus) { EXPECT_EQ(16u, itr->second.size()); } +TEST_F(WvCdmRequestLicenseTest, QueryStatusL3) { + CdmQueryMap query_info, query_info_default; + CdmQueryMap::iterator itr; + + EXPECT_EQ(wvcdm::NO_ERROR, + decryptor_.QueryStatus(kLevel3, &query_info)); + EXPECT_EQ(wvcdm::NO_ERROR, + decryptor_.QueryStatus(kLevelDefault, &query_info_default)); + + EXPECT_THAT(query_info, Contains(Pair(wvcdm::QUERY_KEY_SECURITY_LEVEL, + wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3))); + + itr = query_info.find(wvcdm::QUERY_KEY_DEVICE_ID); + ASSERT_TRUE(itr != query_info.end()); + EXPECT_GT(itr->second.size(), 0u); + + itr = query_info.find(wvcdm::QUERY_KEY_SYSTEM_ID); + ASSERT_TRUE(itr != query_info.end()); + std::istringstream ss(itr->second); + uint32_t system_id; + EXPECT_TRUE(ss >> system_id); + EXPECT_TRUE(ss.eof()); + + itr = query_info.find(wvcdm::QUERY_KEY_PROVISIONING_ID); + ASSERT_TRUE(itr != query_info.end()); + EXPECT_EQ(16u, itr->second.size()); + + itr = query_info_default.find(wvcdm::QUERY_KEY_SECURITY_LEVEL); + ASSERT_TRUE(itr != query_info_default.end()); + EXPECT_EQ(2u, itr->second.size()); + EXPECT_EQ(wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3.at(0), itr->second.at(0)); + + if (wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3.compare(itr->second) != 0) { + itr = query_info_default.find(wvcdm::QUERY_KEY_SYSTEM_ID); + ASSERT_TRUE(itr != query_info_default.end()); + std::istringstream ss(itr->second); + uint32_t default_system_id; + EXPECT_TRUE(ss >> system_id); + EXPECT_TRUE(ss.eof()); + EXPECT_NE(system_id, default_system_id); + } +} + TEST_F(WvCdmRequestLicenseTest, QueryKeyControlInfo) { Unprovision(); Provision(kLevelDefault); @@ -1848,7 +1894,8 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) { CdmQueryMap query_info; CdmQueryMap::iterator itr; - EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.QueryStatus(&query_info)); + EXPECT_EQ(wvcdm::NO_ERROR, + decryptor_.QueryStatus(kLevelDefault, &query_info)); itr = query_info.find(wvcdm::QUERY_KEY_SECURITY_LEVEL); ASSERT_TRUE(itr != query_info.end()); EXPECT_EQ(2u, itr->second.size()); diff --git a/libwvdrmengine/include/WVErrors.h b/libwvdrmengine/include/WVErrors.h index 9432e140..480fac97 100644 --- a/libwvdrmengine/include/WVErrors.h +++ b/libwvdrmengine/include/WVErrors.h @@ -160,7 +160,8 @@ enum { kClientIdAesEncryptError = ERROR_DRM_VENDOR_MIN + 144, kClientIdRsaInitError = ERROR_DRM_VENDOR_MIN + 145, kClientIdRsaEncryptError = ERROR_DRM_VENDOR_MIN + 146, - kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 146, + kInvalidQueryStatus = ERROR_DRM_VENDOR_MIN + 147, + kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 147, // Used by crypto test mode kErrorTestMode = ERROR_DRM_VENDOR_MAX, diff --git a/libwvdrmengine/include/mapErrors-inl.h b/libwvdrmengine/include/mapErrors-inl.h index 767c3ace..cd0479ac 100644 --- a/libwvdrmengine/include/mapErrors-inl.h +++ b/libwvdrmengine/include/mapErrors-inl.h @@ -309,6 +309,8 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { // KEY_ERROR is used by the CDM to mean just about any kind of error, not // just license errors, so it is mapped to the generic response. return kErrorCDMGeneric; + case wvcdm::INVALID_QUERY_STATUS: + return kInvalidQueryStatus; case wvcdm::UNKNOWN_ERROR: return android::ERROR_DRM_UNKNOWN; } diff --git a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h index 83d340d7..d2fa6f4f 100644 --- a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h @@ -254,7 +254,11 @@ class WVDrmPlugin : public android::DrmPlugin, map mCryptoSessions; status_t queryProperty(const std::string& property, - std::string& string_value) const; + std::string& stringValue) const; + + status_t queryProperty(wvcdm::SecurityLevel securityLevel, + const std::string& property, + std::string& stringValue) const; status_t queryProperty(const std::string& property, String8& string8_value) const; diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp index 461ddb3a..240d6e83 100644 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp @@ -537,7 +537,8 @@ status_t WVDrmPlugin::setPropertyString(const String8& name, // We must be sure we CAN set the security level to L1. std::string current_security_level; status_t status = - queryProperty(QUERY_KEY_SECURITY_LEVEL, current_security_level); + queryProperty(kLevelDefault, QUERY_KEY_SECURITY_LEVEL, + current_security_level); if (status != android::OK) return status; if (current_security_level != QUERY_VALUE_SECURITY_LEVEL_L1) { @@ -880,9 +881,20 @@ void WVDrmPlugin::OnExpirationUpdate(const CdmSessionId& cdmSessionId, } status_t WVDrmPlugin::queryProperty(const std::string& property, - std::string& string_value) const { + std::string& stringValue) const { + SecurityLevel securityLevel = + mPropertySet.security_level().compare(QUERY_VALUE_SECURITY_LEVEL_L3) == 0 + ? kLevel3 + : kLevelDefault; + return queryProperty(securityLevel, property, stringValue); +} + +status_t WVDrmPlugin::queryProperty(SecurityLevel securityLevel, + const std::string& property, + std::string& stringValue) const { CdmQueryMap status; - CdmResponseType res = mCDM->QueryStatus(&status); + CdmResponseType res = mCDM->QueryStatus(securityLevel, &status); + if (res != wvcdm::NO_ERROR) { ALOGE("Error querying CDM status: %u", res); return mapCdmResponseType(res); @@ -890,7 +902,7 @@ status_t WVDrmPlugin::queryProperty(const std::string& property, ALOGE("CDM did not report %s", property.c_str()); return kErrorCDMGeneric; } - string_value = status[property]; + stringValue = status[property]; return android::OK; } diff --git a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp index 629a7f6c..15ba7f7e 100644 --- a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp +++ b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp @@ -60,7 +60,7 @@ class MockCDM : public WvContentDecryptionModule { MOCK_METHOD2(RestoreKey, CdmResponseType(const CdmSessionId&, const CdmKeySetId&)); - MOCK_METHOD1(QueryStatus, CdmResponseType(CdmQueryMap*)); + MOCK_METHOD2(QueryStatus, CdmResponseType(SecurityLevel, CdmQueryMap*)); MOCK_METHOD2(QueryKeyStatus, CdmResponseType(const CdmSessionId&, CdmQueryMap*)); @@ -812,20 +812,20 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { CdmQueryMap maxSessionsMap; maxSessionsMap[QUERY_KEY_MAX_NUMBER_OF_SESSIONS] = maxSessions; - EXPECT_CALL(cdm, QueryStatus(_)) - .WillOnce(DoAll(SetArgPointee<0>(l1Map), + EXPECT_CALL(cdm, QueryStatus(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(l1Map), Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<0>(l3Map), + .WillOnce(DoAll(SetArgPointee<1>(l3Map), Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<0>(deviceIDMap), + .WillOnce(DoAll(SetArgPointee<1>(deviceIDMap), Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<0>(systemIDMap), + .WillOnce(DoAll(SetArgPointee<1>(systemIDMap), Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<0>(provisioningIDMap), + .WillOnce(DoAll(SetArgPointee<1>(provisioningIDMap), Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<0>(openSessionsMap), + .WillOnce(DoAll(SetArgPointee<1>(openSessionsMap), Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<0>(maxSessionsMap), + .WillOnce(DoAll(SetArgPointee<1>(maxSessionsMap), Return(wvcdm::NO_ERROR))); String8 stringResult; @@ -1457,8 +1457,8 @@ TEST_F(WVDrmPluginTest, CanSetAppId) { Return(wvcdm::NO_ERROR))); // Provide expected behavior when plugin queries for the security level - EXPECT_CALL(cdm, QueryStatus(_)) - .WillRepeatedly(DoAll(SetArgPointee<0>(l3Map), + EXPECT_CALL(cdm, QueryStatus(_, _)) + .WillRepeatedly(DoAll(SetArgPointee<1>(l3Map), Return(wvcdm::NO_ERROR))); // Provide expected behavior when plugin requests session control info @@ -1539,10 +1539,10 @@ TEST_F(WVDrmPluginTest, CanSetSecurityLevel) { CdmQueryMap l3Map; l3Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L3; - EXPECT_CALL(cdm, QueryStatus(_)) - .WillOnce(DoAll(SetArgPointee<0>(l3Map), + EXPECT_CALL(cdm, QueryStatus(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(l3Map), Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<0>(l1Map), + .WillOnce(DoAll(SetArgPointee<1>(l1Map), Return(wvcdm::NO_ERROR))); // Provide expected mock behavior