From 3343f886a32f8a9d2ebbda4d7fa96acc19c6dc8a Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Wed, 23 Sep 2015 18:45:05 -0700 Subject: [PATCH] Merge of CLs * Move Properties::Init into platform-specific code This enables a refactor where property initialization for CE CDM will use values provided by the application during library initialization. [ Merge of http://go/wvgerrit/14510/ ] * Add Properties::AlwaysUseKeySetIds(). When true, all sessions will have key set IDs and all session IDs will be the same as the corresponding key set ID. This will help the new CDM interface stick more closely to the EME APIs, in which there are no such things as key set IDs and sessions only have a single, random ID used for both streaming and offline. [ Merge of http://go/wvgerrit/14521/ ] * Reserve key set IDs in memory, rather than on the file system. This makes it more efficient to use key set IDs for non-offline sessions. [ Merge of http://go/wvgerrit/14535/ ] Change-Id: I765c3519619b17cc3c4ef95b1a6b125f479ee1d0 --- libwvdrmengine/cdm/core/include/cdm_session.h | 3 ++- .../cdm/core/include/device_files.h | 6 +++-- libwvdrmengine/cdm/core/include/properties.h | 1 + libwvdrmengine/cdm/core/src/cdm_engine.cpp | 21 +++++++++++----- libwvdrmengine/cdm/core/src/cdm_session.cpp | 19 +++++++++++--- libwvdrmengine/cdm/core/src/device_files.cpp | 13 ++++++---- libwvdrmengine/cdm/core/src/properties.cpp | 13 +--------- .../cdm/core/test/cdm_session_unittest.cpp | 2 +- .../cdm/core/test/device_files_unittest.cpp | 25 ++++++------------- libwvdrmengine/cdm/src/properties_android.cpp | 16 ++++++++++++ 10 files changed, 71 insertions(+), 48 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/cdm_session.h b/libwvdrmengine/cdm/core/include/cdm_session.h index 4a96a576..9a727189 100644 --- a/libwvdrmengine/cdm/core/include/cdm_session.h +++ b/libwvdrmengine/cdm/core/include/cdm_session.h @@ -23,7 +23,8 @@ class WvCdmEventListener; class CdmSession { public: CdmSession(const CdmClientPropertySet* cdm_client_property_set, - const std::string& origin, WvCdmEventListener* event_listener); + const std::string& origin, WvCdmEventListener* event_listener, + CdmSessionId* forced_session_id); virtual ~CdmSession(); virtual CdmResponseType Init(); diff --git a/libwvdrmengine/cdm/core/include/device_files.h b/libwvdrmengine/cdm/core/include/device_files.h index 840a673a..57f29fe7 100644 --- a/libwvdrmengine/cdm/core/include/device_files.h +++ b/libwvdrmengine/cdm/core/include/device_files.h @@ -4,6 +4,7 @@ #define WVCDM_CORE_DEVICE_FILES_H_ #include +#include #include #include "scoped_ptr.h" @@ -110,7 +111,6 @@ class DeviceFiles { static std::string GetCertificateFileName(const std::string& origin); static std::string GetLicenseFileNameExtension(); static std::string GetUsageInfoFileName(const std::string& app_id); - static std::string GetBlankFileData(); static std::string GetFileNameSafeHash(const std::string& input); // For testing only: @@ -122,7 +122,7 @@ class DeviceFiles { FRIEND_TEST(DeviceCertificateTest, HasCertificate); FRIEND_TEST(DeviceFilesStoreTest, StoreLicense); FRIEND_TEST(DeviceFilesTest, DeleteLicense); - FRIEND_TEST(DeviceFilesTest, ReserveLicenseIds); + FRIEND_TEST(DeviceFilesTest, ReserveLicenseIdsDoesNotUseFileSystem); FRIEND_TEST(DeviceFilesTest, RetrieveLicenses); FRIEND_TEST(DeviceFilesTest, AppParametersBackwardCompatibility); FRIEND_TEST(DeviceFilesTest, SecurityLevelPathBackwardCompatibility); @@ -141,6 +141,8 @@ class DeviceFiles { FRIEND_TEST(WvCdmExtendedDurationTest, UsageOverflowTest); #endif + static std::set reserved_license_ids_; + scoped_ptr file_; CdmSecurityLevel security_level_; bool initialized_; diff --git a/libwvdrmengine/cdm/core/include/properties.h b/libwvdrmengine/cdm/core/include/properties.h index 8acf750c..a0890317 100644 --- a/libwvdrmengine/cdm/core/include/properties.h +++ b/libwvdrmengine/cdm/core/include/properties.h @@ -54,6 +54,7 @@ class Properties { std::string* base_path); static bool GetFactoryKeyboxPath(std::string* keybox); static bool GetOEMCryptoPath(std::string* library_name); + static bool AlwaysUseKeySetIds(); static bool GetSecurityLevelDirectories(std::vector* dirs); static bool GetApplicationId(const CdmSessionId& session_id, std::string* app_id); diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index 1bab8f63..3b7bf096 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -91,8 +91,13 @@ CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system, return INVALID_PARAMETERS_ENG_1; } + CdmSessionId* forced_session_id = NULL; + if (Properties::AlwaysUseKeySetIds() && !session_id->empty()) { + forced_session_id = session_id; + } + scoped_ptr new_session( - new CdmSession(property_set, origin, event_listener)); + new CdmSession(property_set, origin, event_listener, forced_session_id)); if (new_session->session_id().empty()) { LOGE("CdmEngine::OpenSession: failure to generate session ID"); return EMPTY_SESSION_ID; @@ -180,7 +185,10 @@ CdmResponseType CdmEngine::GenerateKeyRequest( CdmSessionId id = session_id; CdmResponseType sts; - if (license_type == kLicenseTypeRelease) { + // NOTE: If AlwaysUseKeySetIds() is true, there is no need to consult the + // release_key_sets_ map for release licenses. + if (license_type == kLicenseTypeRelease && + !Properties::AlwaysUseKeySetIds()) { if (key_set_id.empty()) { LOGE("CdmEngine::GenerateKeyRequest: invalid key set ID"); return EMPTY_KEYSET_ID_ENG_2; @@ -666,7 +674,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(usage_property_set_.get(), EMPTY_ORIGIN, NULL)); + new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL, NULL)); CdmResponseType status = usage_session_->Init(); if (NO_ERROR != status) { LOGE("CdmEngine::GetUsageInfo: session init error"); @@ -685,7 +693,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id, usage_property_set_->set_security_level(kLevel3); usage_property_set_->set_app_id(app_id); usage_session_.reset( - new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL)); + new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL, NULL)); status = usage_session_->Init(); if (NO_ERROR != status) { LOGE("CdmEngine::GetUsageInfo: session init error"); @@ -754,7 +762,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id, usage_property_set_->set_app_id(app_id); usage_session_.reset( - new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL)); + new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL, NULL)); CdmResponseType status = usage_session_->Init(); if (NO_ERROR != status) { @@ -833,7 +841,8 @@ CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) { : kLevelDefault; usage_property_set_->set_security_level(security_level); usage_session_.reset( - new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL)); + new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL, + NULL)); CdmResponseType status2 = usage_session_-> DeleteMultipleUsageInformation(provider_session_tokens); if (status2 != NO_ERROR) { diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index a7c728ca..ddb8a662 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -25,14 +25,13 @@ namespace wvcdm { CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set, const std::string& origin, - WvCdmEventListener* event_listener) + WvCdmEventListener* event_listener, + CdmSessionId* forced_session_id) : initialized_(false), session_id_(GenerateSessionId()), origin_(origin), license_parser_(new CdmLicense), crypto_session_(new CryptoSession), - policy_engine_( - new PolicyEngine(session_id_, event_listener, crypto_session_.get())), file_handle_(new DeviceFiles), license_received_(false), is_offline_(false), @@ -43,6 +42,17 @@ CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set, has_decrypted_since_last_report_(false), is_initial_usage_update_(true), is_usage_update_needed_(false) { + if (Properties::AlwaysUseKeySetIds()) { + if (forced_session_id) { + key_set_id_ = *forced_session_id; + } else { + bool ok = GenerateKeySetId(&key_set_id_); + assert(ok); + } + session_id_ = key_set_id_; + } + policy_engine_.reset(new PolicyEngine( + session_id_, event_listener, crypto_session_.get())); if (cdm_client_property_set) { if (cdm_client_property_set->security_level() == QUERY_VALUE_SECURITY_LEVEL_L3) { @@ -203,7 +213,8 @@ CdmResponseType CdmSession::GenerateKeyRequest( LOGW("CdmSession::GenerateKeyRequest: init data absent"); return INIT_DATA_NOT_FOUND; } - if (is_offline_ && !GenerateKeySetId(&key_set_id_)) { + if (is_offline_ && key_set_id_.empty() && + !GenerateKeySetId(&key_set_id_)) { LOGE("CdmSession::GenerateKeyRequest: Unable to generate key set ID"); return KEY_REQUEST_ERROR_1; } diff --git a/libwvdrmengine/cdm/core/src/device_files.cpp b/libwvdrmengine/cdm/core/src/device_files.cpp index df0bbb9c..bc8ab008 100644 --- a/libwvdrmengine/cdm/core/src/device_files.cpp +++ b/libwvdrmengine/cdm/core/src/device_files.cpp @@ -46,8 +46,6 @@ const char* kSecurityLevelPathCompatibilityExclusionList[] = { size_t kSecurityLevelPathCompatibilityExclusionListSize = sizeof(kSecurityLevelPathCompatibilityExclusionList) / sizeof(*kSecurityLevelPathCompatibilityExclusionList); -// Some platforms cannot store a truly blank file, so we use a W for Widevine. -const char kBlankFileData[] = "W"; bool Hash(const std::string& data, std::string* hash) { if (!hash) return false; @@ -64,6 +62,9 @@ bool Hash(const std::string& data, std::string* hash) { namespace wvcdm { +// static +std::set DeviceFiles::reserved_license_ids_; + DeviceFiles::DeviceFiles() : file_(NULL), security_level_(kSecurityLevelUninitialized), @@ -228,6 +229,7 @@ bool DeviceFiles::StoreLicense( std::string serialized_file; file.SerializeToString(&serialized_file); + reserved_license_ids_.erase(key_set_id); return StoreFileWithHash(key_set_id + kLicenseFileNameExt, serialized_file); } @@ -331,6 +333,8 @@ bool DeviceFiles::LicenseExists(const std::string& key_set_id) { return false; } return FileExists(key_set_id + kLicenseFileNameExt); + return reserved_license_ids_.count(key_set_id) || + FileExists(key_set_id + kLicenseFileNameExt); } bool DeviceFiles::ReserveLicenseId(const std::string& key_set_id) { @@ -338,7 +342,8 @@ bool DeviceFiles::ReserveLicenseId(const std::string& key_set_id) { LOGW("DeviceFiles::ReserveLicenseId: not initialized"); return false; } - return StoreFileRaw(key_set_id + kLicenseFileNameExt, kBlankFileData); + reserved_license_ids_.insert(key_set_id); + return true; } bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token, @@ -804,8 +809,6 @@ std::string DeviceFiles::GetUsageInfoFileName(const std::string& app_id) { return kUsageInfoFileNamePrefix + hash + kUsageInfoFileNameExt; } -std::string DeviceFiles::GetBlankFileData() { return kBlankFileData; } - std::string DeviceFiles::GetFileNameSafeHash(const std::string& input) { std::vector hash(MD5_DIGEST_LENGTH); const unsigned char* input_ptr = diff --git a/libwvdrmengine/cdm/core/src/properties.cpp b/libwvdrmengine/cdm/core/src/properties.cpp index fb0d4309..686f2e43 100644 --- a/libwvdrmengine/cdm/core/src/properties.cpp +++ b/libwvdrmengine/cdm/core/src/properties.cpp @@ -1,7 +1,7 @@ // Copyright 2013 Google Inc. All Rights Reserved. #include "log.h" -#include "properties_configuration.h" +#include "properties.h" #include "wv_cdm_constants.h" namespace { @@ -16,17 +16,6 @@ bool Properties::use_certificates_as_identification_; bool Properties::security_level_path_backward_compatibility_support_; scoped_ptr Properties::session_property_set_; -void Properties::Init() { - oem_crypto_use_secure_buffers_ = kPropertyOemCryptoUseSecureBuffers; - oem_crypto_use_fifo_ = kPropertyOemCryptoUseFifo; - oem_crypto_use_userspace_buffers_ = kPropertyOemCryptoUseUserSpaceBuffers; - use_certificates_as_identification_ = - kPropertyUseCertificatesAsIdentification; - security_level_path_backward_compatibility_support_ = - kSecurityLevelPathBackwardCompatibilitySupport; - session_property_set_.reset(new CdmClientPropertySetMap()); -} - bool Properties::AddSessionPropertySet( const CdmSessionId& session_id, const CdmClientPropertySet* property_set) { if (NULL == session_property_set_.get()) { diff --git a/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp b/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp index 1e4cd121..bcc8c953 100644 --- a/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp @@ -132,7 +132,7 @@ class MockCdmLicense : public CdmLicense { class CdmSessionTest : public ::testing::Test { protected: virtual void SetUp() { - cdm_session_.reset(new CdmSession(NULL, kTestOrigin, NULL)); + cdm_session_.reset(new CdmSession(NULL, kTestOrigin, NULL, NULL)); // Inject testing mocks. license_parser_ = new MockCdmLicense(); cdm_session_->set_license_parser(license_parser_); diff --git a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp index e2647104..ab81d77d 100644 --- a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp @@ -2118,26 +2118,15 @@ TEST_F(DeviceFilesTest, DeleteLicense) { EXPECT_FALSE(device_files.LicenseExists(license_test_data[0].key_set_id)); } -TEST_F(DeviceFilesTest, ReserveLicenseIds) { +TEST_F(DeviceFilesTest, ReserveLicenseIdsDoesNotUseFileSystem) { + // Validate that ReserveLicenseIds does not touch the file system. MockFile file; - EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_))) - .Times(kNumberOfLicenses) - .WillRepeatedly(Return(true)); + EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_))).Times(0); EXPECT_CALL(file, CreateDirectory(_)).Times(0); - for (size_t i = 0; i < kNumberOfLicenses; ++i) { - std::string license_path = device_base_path_ + - license_test_data[i].key_set_id + - DeviceFiles::GetLicenseFileNameExtension(); - InSequence calls; - EXPECT_CALL(file, Open(StrEq(license_path), - AllOf(IsCreateFileFlagSet(), IsBinaryFileFlagSet()))) - .WillOnce(Return(true)); - EXPECT_CALL(file, Write(StrEq(DeviceFiles::GetBlankFileData()), - DeviceFiles::GetBlankFileData().size())) - .WillOnce(ReturnArg<1>()); - EXPECT_CALL(file, Close()); - } + EXPECT_CALL(file, Open(_, _)).Times(0); + EXPECT_CALL(file, Write(_, _)).Times(0); + EXPECT_CALL(file, Close()).Times(0); EXPECT_CALL(file, Read(_, _)).Times(0); DeviceFiles device_files; @@ -2145,6 +2134,8 @@ TEST_F(DeviceFilesTest, ReserveLicenseIds) { device_files.SetTestFile(&file); for (size_t i = 0; i < kNumberOfLicenses; i++) { EXPECT_TRUE(device_files.ReserveLicenseId(license_test_data[i].key_set_id)); + // Validate that the license IDs are actually reserved. + EXPECT_TRUE(device_files.LicenseExists(license_test_data[i].key_set_id)); } } diff --git a/libwvdrmengine/cdm/src/properties_android.cpp b/libwvdrmengine/cdm/src/properties_android.cpp index 97567742..6753f39b 100644 --- a/libwvdrmengine/cdm/src/properties_android.cpp +++ b/libwvdrmengine/cdm/src/properties_android.cpp @@ -1,6 +1,7 @@ // Copyright 2013 Google Inc. All Rights Reserved. #include "properties.h" +#include "properties_configuration.h" #include #include @@ -42,6 +43,17 @@ bool GetAndroidProperty(const char* key, std::string* value) { namespace wvcdm { +void Properties::Init() { + oem_crypto_use_secure_buffers_ = kPropertyOemCryptoUseSecureBuffers; + oem_crypto_use_fifo_ = kPropertyOemCryptoUseFifo; + oem_crypto_use_userspace_buffers_ = kPropertyOemCryptoUseUserSpaceBuffers; + use_certificates_as_identification_ = + kPropertyUseCertificatesAsIdentification; + security_level_path_backward_compatibility_support_ = + kSecurityLevelPathBackwardCompatibilitySupport; + session_property_set_.reset(new CdmClientPropertySetMap()); +} + bool Properties::GetCompanyName(std::string* company_name) { if (!company_name) { LOGW("Properties::GetCompanyName: Invalid parameter"); @@ -139,4 +151,8 @@ bool Properties::GetOEMCryptoPath(std::string* library_name) { return true; } +bool Properties::AlwaysUseKeySetIds() { + return false; +} + } // namespace wvcdm