diff --git a/libwvdrmengine/cdm/core/include/crypto_engine.h b/libwvdrmengine/cdm/core/include/crypto_engine.h index df651960..4efa40bc 100644 --- a/libwvdrmengine/cdm/core/include/crypto_engine.h +++ b/libwvdrmengine/cdm/core/include/crypto_engine.h @@ -5,6 +5,7 @@ #ifndef CDM_BASE_CRYPTO_ENGINE_H_ #define CDM_BASE_CRYPTO_ENGINE_H_ +#include #include #include "crypto_session.h" @@ -48,7 +49,8 @@ class CryptoEngine { } SecurityLevel; SecurityLevel GetSecurityLevel(); - std::string GetDeviceUniqueId(); + bool GetDeviceUniqueId(std::string* deviceId); + bool GetSystemId(uint32_t* systemId); private: diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h index 64662ccc..67d1b88b 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h @@ -37,6 +37,8 @@ static const std::string QUERY_KEY_SECURITY_LEVEL = "SecurityLevel"; // "L1", "L3" static const std::string QUERY_KEY_DEVICE_ID = "DeviceID"; // device unique id +static const std::string QUERY_KEY_SYSTEM_ID = "SystemID"; + // system id static const std::string QUERY_VALUE_TRUE = "True"; static const std::string QUERY_VALUE_FALSE = "False"; diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index 6e560102..2a996707 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -3,6 +3,7 @@ #include "cdm_engine.h" #include +#include #include "buffer_reader.h" #include "cdm_session.h" @@ -315,7 +316,19 @@ CdmResponseType CdmEngine::QueryStatus(CdmQueryMap* key_info) { return KEY_ERROR; } - (*key_info)[QUERY_KEY_DEVICE_ID] = crypto_engine->GetDeviceUniqueId(); + std::string deviceId; + bool success = crypto_engine->GetDeviceUniqueId(&deviceId); + if (success) { + (*key_info)[QUERY_KEY_DEVICE_ID] = deviceId; + } + + uint32_t system_id; + success = crypto_engine->GetSystemId(&system_id); + if (success) { + std::ostringstream system_id_stream; + system_id_stream << system_id; + (*key_info)[QUERY_KEY_SYSTEM_ID] = system_id_stream.str(); + } return NO_ERROR; } diff --git a/libwvdrmengine/cdm/core/src/crypto_engine.cpp b/libwvdrmengine/cdm/core/src/crypto_engine.cpp index 42c6056f..f911ffc0 100644 --- a/libwvdrmengine/cdm/core/src/crypto_engine.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_engine.cpp @@ -5,6 +5,7 @@ #include "crypto_engine.h" +#include // TODO(fredgc): Add ntoh to wv_cdm_utilities.h #include #include @@ -195,7 +196,7 @@ CryptoEngine::SecurityLevel CryptoEngine::GetSecurityLevel() { return kSecurityLevelUnknown; } -std::string CryptoEngine::GetDeviceUniqueId() { +bool CryptoEngine::GetDeviceUniqueId(std::string* deviceId) { std::vector id; size_t idLength = 32; @@ -204,10 +205,29 @@ std::string CryptoEngine::GetDeviceUniqueId() { OEMCryptoResult sts = OEMCrypto_GetDeviceID(&id[0], &idLength); if (OEMCrypto_SUCCESS != sts) { - return std::string(); + return false; } - return std::string(reinterpret_cast(&id[0])); + *deviceId = reinterpret_cast(&id[0]); + return true; +} + +bool CryptoEngine::GetSystemId(uint32_t* systemId) { + uint8_t buf[72]; + size_t buflen = 72; + + OEMCryptoResult sts = OEMCrypto_GetKeyData(buf, &buflen); + + if (OEMCrypto_SUCCESS != sts) { + return false; + } + + // Decode 32-bit int encoded as network-byte-order byte array starting at + // index 4. + uint32_t* id = reinterpret_cast(&buf[4]); + + *systemId = ntohl(*id); + return true; } }; // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index 9eb9380a..528720ba 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -154,8 +154,11 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data, client_info->set_value(value); } - client_info->set_name(kDeviceIdKey); - client_info->set_value(CryptoEngine::GetInstance()->GetDeviceUniqueId()); + if (CryptoEngine::GetInstance()->GetDeviceUniqueId(&value)) { + client_info = client_id->add_client_info(); + client_info->set_name(kDeviceIdKey); + client_info->set_value(value); + } // Content Identification may be a cenc_id, a webm_id or a license_id LicenseRequest_ContentIdentification* content_id = diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index a746d7b1..66900262 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "config_test_env.h" #include "gtest/gtest.h" @@ -217,6 +218,13 @@ TEST_F(WvCdmRequestLicenseTest, QueryStatus) { ASSERT_TRUE(itr != query_info.end()); EXPECT_GT((int)itr->second.size(), 0); + 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()); + decryptor_.CloseSession(session_id_); } diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp index 45fca515..e2da7aba 100644 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp @@ -285,9 +285,7 @@ status_t WVDrmPlugin::getPropertyString(const String8& name, value = "AES/CBC/NoPadding,HmacSHA256"; } else if (name == "securityLevel") { CdmQueryMap status; - CdmResponseType res = mCDM->QueryStatus(&status); - if (!isCdmResponseTypeSuccess(res)) { ALOGE("Error querying CDM status: %u", res); return mapCdmResponseType(res); @@ -295,11 +293,18 @@ status_t WVDrmPlugin::getPropertyString(const String8& name, ALOGE("CDM did not report a security level"); return kErrorCDMGeneric; } - - const string& securityLevel = status[QUERY_KEY_SECURITY_LEVEL]; - - value.clear(); - value.append(securityLevel.data(), securityLevel.size()); + value = status[QUERY_KEY_SECURITY_LEVEL].c_str(); + } else if (name == "systemId") { + CdmQueryMap status; + CdmResponseType res = mCDM->QueryStatus(&status); + if (res != wvcdm::NO_ERROR) { + ALOGE("Error querying CDM status: %u", res); + return mapCdmResponseType(res); + } else if (!status.count(QUERY_KEY_SYSTEM_ID)) { + ALOGE("CDM did not report a system ID"); + return kErrorCDMGeneric; + } + value = status[QUERY_KEY_SYSTEM_ID].c_str(); } else { ALOGE("App requested unknown property %s", name.string()); return android::ERROR_DRM_CANNOT_HANDLE; diff --git a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp index c6760b87..859cf001 100644 --- a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp +++ b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp @@ -422,48 +422,57 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { l3Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L3; static const string uniqueId = "The Universe"; - CdmQueryMap idMap; - idMap[QUERY_KEY_DEVICE_ID] = uniqueId; + CdmQueryMap deviceIDMap; + deviceIDMap[QUERY_KEY_DEVICE_ID] = uniqueId; + + static const string systemId = "42"; + CdmQueryMap systemIDMap; + systemIDMap[QUERY_KEY_SYSTEM_ID] = systemId; EXPECT_CALL(cdm, QueryStatus(_)) .WillOnce(DoAll(SetArgPointee<0>(l1Map), Return(wvcdm::NO_ERROR))) .WillOnce(DoAll(SetArgPointee<0>(l3Map), Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<0>(idMap), + .WillOnce(DoAll(SetArgPointee<0>(deviceIDMap), + Return(wvcdm::NO_ERROR))) + .WillOnce(DoAll(SetArgPointee<0>(systemIDMap), Return(wvcdm::NO_ERROR))); String8 stringResult; + Vector vectorResult; status_t res = plugin.getPropertyString(String8("vendor"), stringResult); ASSERT_EQ(OK, res); - EXPECT_EQ(String8("Google"), stringResult); + EXPECT_STREQ("Google", stringResult.string()); res = plugin.getPropertyString(String8("version"), stringResult); ASSERT_EQ(OK, res); - EXPECT_EQ(String8("1.0"), stringResult); + EXPECT_STREQ("1.0", stringResult.string()); res = plugin.getPropertyString(String8("description"), stringResult); ASSERT_EQ(OK, res); - EXPECT_EQ(String8("Widevine CDM"), stringResult); + EXPECT_STREQ("Widevine CDM", stringResult.string()); res = plugin.getPropertyString(String8("algorithms"), stringResult); ASSERT_EQ(OK, res); - EXPECT_EQ(String8("AES/CBC/NoPadding,HmacSHA256"), stringResult); + EXPECT_STREQ("AES/CBC/NoPadding,HmacSHA256", stringResult.string()); res = plugin.getPropertyString(String8("securityLevel"), stringResult); ASSERT_EQ(OK, res); - EXPECT_EQ(String8("L1"), stringResult); + EXPECT_STREQ(QUERY_VALUE_SECURITY_LEVEL_L1.c_str(), stringResult.string()); res = plugin.getPropertyString(String8("securityLevel"), stringResult); ASSERT_EQ(OK, res); - EXPECT_EQ(String8("L3"), stringResult); - - Vector vectorResult; + EXPECT_STREQ(QUERY_VALUE_SECURITY_LEVEL_L3.c_str(), stringResult.string()); res = plugin.getPropertyByteArray(String8("deviceUniqueId"), vectorResult); ASSERT_EQ(OK, res); EXPECT_THAT(vectorResult, ElementsAreArray(uniqueId.data(), uniqueId.size())); + + res = plugin.getPropertyString(String8("systemId"), stringResult); + ASSERT_EQ(OK, res); + EXPECT_STREQ(systemId.c_str(), stringResult.string()); } TEST_F(WVDrmPluginTest, DoesNotGetUnknownProperties) {