diff --git a/libwvdrmengine/cdm/core/include/cdm_engine.h b/libwvdrmengine/cdm/core/include/cdm_engine.h index 375982c2..633e0616 100644 --- a/libwvdrmengine/cdm/core/include/cdm_engine.h +++ b/libwvdrmengine/cdm/core/include/cdm_engine.h @@ -4,6 +4,7 @@ #define WVCDM_CORE_CDM_ENGINE_H_ #include +#include #include "certificate_provisioning.h" #include "clock.h" @@ -128,19 +129,29 @@ class CdmEngine { virtual CdmResponseType QueryOemCryptoSessionId( const CdmSessionId& session_id, CdmQueryMap* query_response); - // Provisioning related methods + // Generate and return a valid provisioning request. virtual CdmResponseType GetProvisioningRequest( CdmCertificateType cert_type, const std::string& cert_authority, CdmProvisioningRequest* request, std::string* default_url); + // Verify and process a provisioning response. virtual CdmResponseType HandleProvisioningResponse( const CdmProvisioningResponse& response, std::string* cert, std::string* wrapped_key); + // Return true if there is a device certificate on the current + // (origin-specific) file system. virtual bool IsProvisioned(CdmSecurityLevel security_level); + // Remove DRM certificate from the current (origin-specific) + // file system. This will force the device to reprovision itself. virtual CdmResponseType Unprovision(CdmSecurityLevel security_level); + // Return the list of key_set_ids stored on the current (origin-specific) + // file system. + virtual CdmResponseType ListStoredLicenses( + CdmSecurityLevel security_level, std::vector* key_set_ids); + // Usage related methods for streaming licenses // Retrieve a random usage info from the list of all usage infos for this app // id. diff --git a/libwvdrmengine/cdm/core/include/cdm_session.h b/libwvdrmengine/cdm/core/include/cdm_session.h index ec6ad0ef..d5fcb6d3 100644 --- a/libwvdrmengine/cdm/core/include/cdm_session.h +++ b/libwvdrmengine/cdm/core/include/cdm_session.h @@ -5,6 +5,7 @@ #include #include +#include #include "crypto_session.h" #include "device_files.h" @@ -119,6 +120,7 @@ class CdmSession { // release the underlying crypto session) rather than call this method. virtual CdmResponseType ReleaseCrypto(); + // Delete current license and matching usage record bool DeleteLicense(); // Generate unique ID for each new session. diff --git a/libwvdrmengine/cdm/core/include/crypto_session.h b/libwvdrmengine/cdm/core/include/crypto_session.h index 1473c000..22f3c2e9 100644 --- a/libwvdrmengine/cdm/core/include/crypto_session.h +++ b/libwvdrmengine/cdm/core/include/crypto_session.h @@ -141,17 +141,19 @@ class CryptoSession { const std::string& signature); // Usage table header and usage entry related methods + virtual CdmResponseType GetUsageSupportType(CdmUsageSupportType* type); virtual CdmResponseType CreateUsageTableHeader( - std::string* usage_table_header); + CdmUsageTableHeader* usage_table_header); virtual CdmResponseType LoadUsageTableHeader( - const std::string& usage_table_header); + const CdmUsageTableHeader& usage_table_header); virtual CdmResponseType CreateUsageEntry(uint32_t* entry_number); virtual CdmResponseType LoadUsageEntry(uint32_t entry_number, - const std::string& usage_entry); - virtual CdmResponseType UpdateUsageEntry(std::string* usage_table_header, - std::string* usage_entry); - virtual CdmResponseType DecrementUsageTableHeaderSize( - uint32_t current_usage_table_size, std::string* usage_table_header); + const CdmUsageEntry& usage_entry); + virtual CdmResponseType UpdateUsageEntry( + CdmUsageTableHeader* usage_table_header, + CdmUsageEntry* usage_entry); + virtual CdmResponseType ShrinkUsageTableHeader( + uint32_t new_entry_count, CdmUsageTableHeader* usage_table_header); virtual CdmResponseType MoveUsageEntry(uint32_t new_entry_number); virtual CdmResponseType CopyOldUsageEntry( const std::string& provider_session_token); @@ -212,6 +214,9 @@ class CryptoSession { KeyId cached_key_id_; + bool is_usage_support_type_valid_; + CdmUsageSupportType usage_support_type_; + uint64_t request_id_base_; static uint64_t request_id_index_; diff --git a/libwvdrmengine/cdm/core/include/device_files.h b/libwvdrmengine/cdm/core/include/device_files.h index 1b97754d..8a669a13 100644 --- a/libwvdrmengine/cdm/core/include/device_files.h +++ b/libwvdrmengine/cdm/core/include/device_files.h @@ -7,6 +7,7 @@ #include #include +#include #include "device_files.pb.h" #include "scoped_ptr.h" @@ -68,7 +69,7 @@ class DeviceFiles { int64_t last_playback_time, int64_t grace_period_end_time, const CdmAppParameterMap& app_parameters, - const std::string& usage_entry); + const CdmUsageEntry& usage_entry); virtual bool RetrieveLicense( const std::string& key_set_id, LicenseState* state, CdmInitData* pssh_data, CdmKeyMessage* key_request, @@ -76,8 +77,9 @@ class DeviceFiles { CdmKeyResponse* key_renewal_response, std::string* release_server_url, int64_t* playback_start_time, int64_t* last_playback_time, int64_t* grace_period_end_time, CdmAppParameterMap* app_parameters, - std::string* usage_entry); + CdmUsageEntry* usage_entry); virtual bool DeleteLicense(const std::string& key_set_id); + virtual bool ListLicenses(std::vector* key_set_ids); virtual bool DeleteAllFiles(); virtual bool DeleteAllLicenses(); virtual bool LicenseExists(const std::string& key_set_id); @@ -89,7 +91,7 @@ class DeviceFiles { const CdmKeyResponse& key_response, const std::string& app_id, const std::string& key_set_id, - const std::string& usage_entry); + const CdmUsageEntry& usage_entry); virtual bool DeleteUsageInfo(const std::string& app_id, const std::string& provider_session_token); // Delete usage information from the file system. Puts a list of all the @@ -108,14 +110,14 @@ class DeviceFiles { const std::string& provider_session_token, CdmKeyMessage* license_request, CdmKeyResponse* license_response, - std::string* usage_entry); + CdmUsageEntry* usage_entry); // Retrieve the usage info entry specified by |key_set_id|. // Returns false if the entry could not be found. virtual bool RetrieveUsageInfoByKeySetId(const std::string& app_id, const std::string& key_set_id, CdmKeyMessage* license_request, CdmKeyResponse* license_response, - std::string* usage_entry); + CdmUsageEntry* usage_entry); virtual bool StoreHlsAttributes(const std::string& key_set_id, const CdmHlsMethod method, @@ -126,11 +128,11 @@ class DeviceFiles { virtual bool DeleteHlsAttributes(const std::string& key_set_id); virtual bool StoreUsageTableInfo( - const std::string& usage_table_header, + const CdmUsageTableHeader& usage_table_header, const std::vector& usage_entry_info); virtual bool RetrieveUsageTableInfo( - std::string* usage_table_header, + CdmUsageTableHeader* usage_table_header, std::vector* usage_entry_info); private: @@ -143,6 +145,7 @@ class DeviceFiles { bool RetrieveHashedFile(const std::string& name, video_widevine_client::sdk::File* file); bool FileExists(const std::string& name); + bool ListFiles(std::vector* names); bool RemoveFile(const std::string& name); ssize_t GetFileSize(const std::string& name); diff --git a/libwvdrmengine/cdm/core/include/file_store.h b/libwvdrmengine/cdm/core/include/file_store.h index 5b207ce3..fd27e788 100644 --- a/libwvdrmengine/cdm/core/include/file_store.h +++ b/libwvdrmengine/cdm/core/include/file_store.h @@ -55,6 +55,11 @@ class FileSystem { virtual bool Remove(const std::string& file_path); virtual ssize_t FileSize(const std::string& file_path); + // Return the filenames stored at dir_path. + // dir_path will be stripped from the returned names. + virtual bool List(const std::string& dir_path, + std::vector* names); + const std::string& origin() const { return origin_; } void SetOrigin(const std::string& origin); diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 31d29e75..045b3fa6 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -28,6 +28,8 @@ typedef std::vector CdmUsageInfo; typedef std::string CdmUsageInfoReleaseMessage; typedef std::string CdmProvisioningRequest; typedef std::string CdmProvisioningResponse; +typedef std::string CdmUsageTableHeader; +typedef std::string CdmUsageEntry; enum CdmKeyRequestType { kKeyRequestTypeUnknown, @@ -271,6 +273,12 @@ enum CdmResponseType { SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR, MOVE_USAGE_ENTRY_UNKNOWN_ERROR, COPY_OLD_USAGE_ENTRY_UNKNOWN_ERROR, + INVALID_PARAMETERS_ENG_22, + STORE_LICENSE_ERROR_4, /* 235 */ + LIST_LICENSES_ERROR, + INVALID_PARAMETERS_ENG_23, + USAGE_INFORMATION_SUPPORT_FAILED, + USAGE_SUPPORT_GET_API_FAILED, }; enum CdmKeyStatus { @@ -343,6 +351,19 @@ enum CdmClientTokenType { kClientTokenOemCert }; +// kNonSecureUsageSupport - TEE does not provide any support for usage +// information. +// kUsageTableSupport - TEE persists usage information securely in a fixed +// size table, commonly 50 entries. (OEMCrypto v9+) +// kUsageEntrySupport - usage information (table headers and entries) are +// persisted in non-secure storage but are loaded and unloaded from +// the TEE during use (OEMCrypto v13+) +enum CdmUsageSupportType { + kNonSecureUsageSupport, + kUsageTableSupport, + kUsageEntrySupport, +}; + class CdmKeyAllowedUsage { public: CdmKeyAllowedUsage() { diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index ea5d81e3..f81d4c69 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -1011,6 +1011,23 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) { } } +CdmResponseType CdmEngine::ListStoredLicenses( + CdmSecurityLevel security_level, std::vector* key_set_ids) { + DeviceFiles handle(file_system_); + if (!key_set_ids) { + LOGE("CdmEngine::QueryStoredLicenses: no response destination"); + return INVALID_PARAMETERS_ENG_22; + } + if (!handle.Init(security_level)) { + LOGE("CdmEngine::ListStoredLicenses: unable to initialize device files"); + return STORE_LICENSE_ERROR_4; + } + if (!handle.ListLicenses(key_set_ids)) { + return LIST_LICENSES_ERROR; + } + return NO_ERROR; +} + CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id, const CdmSecureStopId& ssid, CdmUsageInfo* usage_info) { diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index 2ea19f4b..0b630b8c 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -31,6 +31,7 @@ std::string EncodeUint32(unsigned int u) { const uint32_t kRsaSignatureLength = 256; const size_t kMaximumChunkSize = 100 * 1024; // 100 KiB const size_t kEstimatedInitialUsageTableHeader = 40; +const size_t kOemCryptoApiVersionSupportsBigUsageTables = 13; } namespace wvcdm { @@ -46,6 +47,8 @@ CryptoSession::CryptoSession(metrics::MetricsGroup* metrics) update_usage_table_after_close_session_(false), is_destination_buffer_type_valid_(false), requested_security_level_(kLevelDefault), + is_usage_support_type_valid_(false), + usage_support_type_(kNonSecureUsageSupport), request_id_base_(0), cipher_mode_(kCipherModeCtr) { Init(); @@ -120,24 +123,23 @@ void CryptoSession::Terminate() { } bool CryptoSession::GetTokenFromKeybox(std::string* token) { - OEMCryptoResult status; std::string temp_buffer(KEYBOX_KEY_DATA_SIZE, '\0'); // lock is held by caller size_t buf_size = temp_buffer.size(); uint8_t* buf = reinterpret_cast(&temp_buffer[0]); - OEMCryptoResult sts; + OEMCryptoResult status; M_TIME( - sts = OEMCrypto_GetKeyData( + status = OEMCrypto_GetKeyData( buf, &buf_size, requested_security_level_), metrics_, oemcrypto_get_key_data_, - sts, + status, metrics::Pow2Bucket(buf_size), requested_security_level_); - if (OEMCrypto_SUCCESS == sts) { + if (OEMCrypto_SUCCESS == status) { token->swap(temp_buffer); return true; } @@ -1811,8 +1813,47 @@ CdmResponseType CryptoSession::GenericVerify(const std::string& message, return NO_ERROR; } +CdmResponseType CryptoSession::GetUsageSupportType( + CdmUsageSupportType* usage_support_type) { + LOGV("GetUsageSupportType: id=%ld", (uint32_t)oec_session_id_); + + if (usage_support_type == NULL) { + LOGE("GetUsageSupportType: usage_support_type param not provided"); + return INVALID_PARAMETERS_ENG_23; + } + + if (is_usage_support_type_valid_) { + *usage_support_type = usage_support_type_; + return NO_ERROR; + } + + bool has_support = false; + if (!UsageInformationSupport(&has_support)) { + LOGE("GetUsageSupportType: UsageInformationSupport failed"); + return USAGE_INFORMATION_SUPPORT_FAILED; + } + + if (!has_support) { + *usage_support_type = usage_support_type_ = kNonSecureUsageSupport; + is_usage_support_type_valid_ = true; + return NO_ERROR; + } + + uint32_t api_version = 0; + if (!GetApiVersion(&api_version)) { + LOGE("GetUsageSupportType: GetApiVersion failed"); + return USAGE_SUPPORT_GET_API_FAILED; + } + + *usage_support_type = usage_support_type_ = + (api_version >= kOemCryptoApiVersionSupportsBigUsageTables) ? + kUsageEntrySupport : kUsageTableSupport; + is_usage_support_type_valid_ = true; + return NO_ERROR; +} + CdmResponseType CryptoSession::CreateUsageTableHeader( - std::string* usage_table_header) { + CdmUsageTableHeader* usage_table_header) { LOGV("CreateUsageTableHeader: id=%ld", (uint32_t)oec_session_id_); if (usage_table_header == NULL) { @@ -1848,7 +1889,7 @@ CdmResponseType CryptoSession::CreateUsageTableHeader( } CdmResponseType CryptoSession::LoadUsageTableHeader( - const std::string& usage_table_header) { + const CdmUsageTableHeader& usage_table_header) { LOGV("LoadUsageTableHeader: id=%ld", (uint32_t)oec_session_id_); OEMCryptoResult result = OEMCrypto_LoadUsageTableHeader( @@ -1908,8 +1949,9 @@ CdmResponseType CryptoSession::CreateUsageEntry(uint32_t* entry_number) { } } -CdmResponseType CryptoSession::LoadUsageEntry(uint32_t entry_number, - const std::string& usage_entry) { +CdmResponseType CryptoSession::LoadUsageEntry( + uint32_t entry_number, + const CdmUsageEntry& usage_entry) { LOGV("LoadUsageEntry: id=%ld", (uint32_t)oec_session_id_); OEMCryptoResult result = OEMCrypto_LoadUsageEntry( @@ -1937,8 +1979,9 @@ CdmResponseType CryptoSession::LoadUsageEntry(uint32_t entry_number, } } -CdmResponseType CryptoSession::UpdateUsageEntry(std::string* usage_table_header, - std::string* usage_entry) { +CdmResponseType CryptoSession::UpdateUsageEntry( + CdmUsageTableHeader* usage_table_header, + CdmUsageEntry* usage_entry) { LOGV("UpdateUsageEntry: id=%ld", (uint32_t)oec_session_id_); if (usage_table_header == NULL) { @@ -1979,27 +2022,26 @@ CdmResponseType CryptoSession::UpdateUsageEntry(std::string* usage_table_header, return NO_ERROR; } -CdmResponseType CryptoSession::DecrementUsageTableHeaderSize( - uint32_t current_usage_table_size, std::string* usage_table_header) { - LOGV("DecrementUsageTableHeaderSize: id=%ld", (uint32_t)oec_session_id_); +CdmResponseType CryptoSession::ShrinkUsageTableHeader( + uint32_t new_entry_count, CdmUsageTableHeader* usage_table_header) { + LOGV("ShrinkUsageTableHeader: id=%ld", (uint32_t)oec_session_id_); if (usage_table_header == NULL) { LOGE( - "DecrementUsageTableHeaderSize: usage_table_header param not " - "provided"); + "ShrinkUsageTableHeader: usage_table_header param not provided"); return INVALID_PARAMETERS_ENG_21; } size_t usage_table_header_len = 0; OEMCryptoResult result = OEMCrypto_ShrinkUsageTableHeader( - requested_security_level_, current_usage_table_size, NULL, + requested_security_level_, new_entry_count, NULL, &usage_table_header_len); if (result == OEMCrypto_ERROR_SHORT_BUFFER) { usage_table_header->resize(usage_table_header_len); result = OEMCrypto_ShrinkUsageTableHeader( - requested_security_level_, --current_usage_table_size, + requested_security_level_, new_entry_count, reinterpret_cast( const_cast(usage_table_header->data())), &usage_table_header_len); @@ -2007,8 +2049,7 @@ CdmResponseType CryptoSession::DecrementUsageTableHeaderSize( if (result != OEMCrypto_SUCCESS) { LOGE( - "DecrementUsageTableHeaderSize: OEMCrypto_ShrinkUsageTableHeader " - "error: %d", + "ShrinkUsageTableHeader: OEMCrypto_ShrinkUsageTableHeader error: %d", result); return SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR; } diff --git a/libwvdrmengine/cdm/core/src/device_files.cpp b/libwvdrmengine/cdm/core/src/device_files.cpp index 291c9143..eff98e2c 100644 --- a/libwvdrmengine/cdm/core/src/device_files.cpp +++ b/libwvdrmengine/cdm/core/src/device_files.cpp @@ -177,7 +177,7 @@ bool DeviceFiles::StoreLicense( const std::string& release_server_url, int64_t playback_start_time, int64_t last_playback_time, int64_t grace_period_end_time, const CdmAppParameterMap& app_parameters, - const std::string& usage_entry) { + const CdmUsageEntry& usage_entry) { if (!initialized_) { LOGW("DeviceFiles::StoreLicense: not initialized"); return false; @@ -233,7 +233,7 @@ bool DeviceFiles::RetrieveLicense( CdmKeyMessage* license_renewal_request, CdmKeyResponse* license_renewal, std::string* release_server_url, int64_t* playback_start_time, int64_t* last_playback_time, int64_t* grace_period_end_time, - CdmAppParameterMap* app_parameters, std::string* usage_entry) { + CdmAppParameterMap* app_parameters, CdmUsageEntry* usage_entry) { if (!initialized_) { LOGW("DeviceFiles::RetrieveLicense: not initialized"); return false; @@ -299,6 +299,39 @@ bool DeviceFiles::DeleteLicense(const std::string& key_set_id) { return RemoveFile(key_set_id + kLicenseFileNameExt); } +bool DeviceFiles::ListLicenses(std::vector* key_set_ids) { + if (!initialized_) { + LOGW("DeviceFiles::ListLicenses: not initialized"); + return false; + } + + if (key_set_ids == NULL) { + LOGW("DeviceFiles::ListLicenses: key_set_ids parameter not provided"); + return false; + } + + // Get list of filenames + std::vector filenames; + if (!ListFiles(&filenames)) { + return false; + } + + // Scan list of returned filenames, remove extension, and return + // as a list of key_set_ids. + key_set_ids->clear(); + for (size_t i = 0; i < filenames.size(); i++) { + std::string* name = &filenames[i]; + std::size_t pos = name->find(kLicenseFileNameExt); + if (pos == std::string::npos) { + // Skip this file - extension does not match + continue; + } + // Store filename (minus extension). This should be a key set ID. + key_set_ids->push_back(name->substr(0, pos)); + } + return true; +} + bool DeviceFiles::DeleteAllLicenses() { if (!initialized_) { LOGW("DeviceFiles::DeleteAllLicenses: not initialized"); @@ -351,7 +384,7 @@ bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token, const CdmKeyResponse& key_response, const std::string& app_id, const std::string& key_set_id, - const std::string& usage_entry) { + const CdmUsageEntry& usage_entry) { if (!initialized_) { LOGW("DeviceFiles::StoreUsageInfo: not initialized"); return false; @@ -492,7 +525,7 @@ bool DeviceFiles::RetrieveUsageInfo(const std::string& app_id, const std::string& provider_session_token, CdmKeyMessage* license_request, CdmKeyResponse* license_response, - std::string* usage_entry) { + CdmUsageEntry* usage_entry) { if (!initialized_) { LOGW("DeviceFiles::RetrieveUsageInfo: not initialized"); return false; @@ -522,7 +555,7 @@ bool DeviceFiles::RetrieveUsageInfoByKeySetId( const std::string& key_set_id, CdmKeyMessage* license_request, CdmKeyResponse* license_response, - std::string* usage_entry) { + CdmUsageEntry* usage_entry) { if (!initialized_) { LOGW("DeviceFiles::RetrieveUsageInfoByKeySetId: not initialized"); return false; @@ -645,7 +678,7 @@ bool DeviceFiles::DeleteHlsAttributes(const std::string& key_set_id) { } bool DeviceFiles::StoreUsageTableInfo( - const std::string& usage_table_header, + const CdmUsageTableHeader& usage_table_header, const std::vector& usage_entry_info) { if (!initialized_) { LOGW("DeviceFiles::StoreUsageTableHeader: not initialized"); @@ -690,7 +723,7 @@ bool DeviceFiles::StoreUsageTableInfo( } bool DeviceFiles::RetrieveUsageTableInfo( - std::string* usage_table_header, + CdmUsageTableHeader* usage_table_header, std::vector* usage_entry_info) { if (!initialized_) { LOGW("DeviceFiles::RetrieveUsageTableInfo: not initialized"); @@ -821,7 +854,7 @@ bool DeviceFiles::RetrieveHashedFile( std::string path; if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) { - LOGW("DeviceFiles::StoreFileWithHash: Unable to get base path"); + LOGW("DeviceFiles::RetrieveHashedFile: Unable to get base path"); return false; } @@ -898,6 +931,15 @@ bool DeviceFiles::FileExists(const std::string& name) { return file_system_->Exists(path); } +bool DeviceFiles::ListFiles(std::vector* names) { + std::string path; + if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) { + LOGW("DeviceFiles::RemoveFile: Unable to get base path"); + return false; + } + return file_system_->List(path, names); +} + bool DeviceFiles::RemoveFile(const std::string& name) { std::string path; if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) { diff --git a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp index c198ebb3..0f751d0a 100644 --- a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp @@ -1570,6 +1570,7 @@ class MockFileSystem : public FileSystem { MOCK_METHOD1(Exists, bool(const std::string&)); MOCK_METHOD1(Remove, bool(const std::string&)); MOCK_METHOD1(FileSize, ssize_t(const std::string&)); + MOCK_METHOD2(List, bool(const std::string&, std::vector*)); }; } // namespace diff --git a/libwvdrmengine/cdm/core/test/file_store_unittest.cpp b/libwvdrmengine/cdm/core/test/file_store_unittest.cpp index 48bfcd17..fe5d9694 100644 --- a/libwvdrmengine/cdm/core/test/file_store_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/file_store_unittest.cpp @@ -1,5 +1,6 @@ // Copyright 2013 Google Inc. All Rights Reserved. +#include #include #include "file_store.h" @@ -11,7 +12,9 @@ namespace { const std::string kTestDirName = "test_dir"; const std::string kTestFileName = "test.txt"; const std::string kTestFileName2 = "test2.txt"; +const std::string kTestFileName3 = "test3.other"; const std::string kTestFileNameExt = ".txt"; +const std::string kTestFileNameExt3 = ".other"; const std::string kWildcard = "*"; } // namespace @@ -135,4 +138,56 @@ TEST_F(FileTest, WriteReadBinaryFile) { EXPECT_EQ(write_data, read_data); } +TEST_F(FileTest, ListFiles) { + std::vector names; + + std::string not_path("zzz"); + std::string path1 = test_vectors::kTestDir + kTestFileName; + std::string path2 = test_vectors::kTestDir + kTestFileName2; + std::string path3 = test_vectors::kTestDir + kTestFileName3; + std::string path_dir = test_vectors::kTestDir; + + File* file = file_system.Open(path1, FileSystem::kCreate); + ASSERT_TRUE(file); + file->Close(); + file = file_system.Open(path2, FileSystem::kCreate); + ASSERT_TRUE(file); + file->Close(); + file = file_system.Open(path3, FileSystem::kCreate); + ASSERT_TRUE(file); + file->Close(); + + EXPECT_TRUE(file_system.Exists(path1)); + EXPECT_TRUE(file_system.Exists(path2)); + EXPECT_TRUE(file_system.Exists(path3)); + + // Ask for non-existent path. + EXPECT_FALSE(file_system.List(not_path, &names)); + + // Valid path, but no way to return names. + EXPECT_FALSE(file_system.List(path_dir, NULL)); + + // Valid path, valid return. + EXPECT_TRUE(file_system.List(path_dir, &names)); + + // Should find three files. Order not important. + EXPECT_EQ(3, names.size()); + EXPECT_THAT(names, ::testing::UnorderedElementsAre(kTestFileName, + kTestFileName2, + kTestFileName3)); + + std::string wild_card_path = path_dir + kWildcard + kTestFileNameExt; + EXPECT_TRUE(file_system.Remove(wild_card_path)); + EXPECT_TRUE(file_system.List(path_dir, &names)); + + EXPECT_EQ(1, names.size()); + EXPECT_TRUE(names[0].compare(kTestFileName3) == 0); + + std::string wild_card_path2 = path_dir + kWildcard + kTestFileNameExt3; + EXPECT_TRUE(file_system.Remove(wild_card_path2)); + EXPECT_TRUE(file_system.List(path_dir, &names)); + + EXPECT_EQ(0, names.size()); +} + } // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/test/test_printers.cpp b/libwvdrmengine/cdm/core/test/test_printers.cpp index 61d8b3f9..aea9bf6d 100644 --- a/libwvdrmengine/cdm/core/test/test_printers.cpp +++ b/libwvdrmengine/cdm/core/test/test_printers.cpp @@ -304,6 +304,8 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { break; case STORE_LICENSE_ERROR_2: *os << "STORE_LICENSE_ERROR_2"; break; + case STORE_LICENSE_ERROR_4: *os << "STORE_LICENSE_ERROR_4"; + break; case STORE_USAGE_INFO_ERROR: *os << "STORE_USAGE_INFO_ERROR"; break; case UNPROVISION_ERROR_1: *os << "UNPROVISION_ERROR_1"; @@ -448,6 +450,8 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { break; case INVALID_PARAMETERS_ENG_16: *os << "INVALID_PARAMETERS_ENG_16"; break; + case INVALID_PARAMETERS_ENG_17: *os << "INVALID_PARAMETERS_ENG_17"; + break; case CERT_PROVISIONING_CLIENT_TOKEN_ERROR_1: *os << "CERT_PROVISIONING_CLIENT_TOKEN_ERROR_1"; break; @@ -476,8 +480,6 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { case LOAD_USAGE_HEADER_UNKNOWN_ERROR: *os << "LOAD_USAGE_HEADER_UNKNOWN_ERROR"; break; - case INVALID_PARAMETERS_ENG_17: *os << "INVALID_PARAMETERS_ENG_17"; - break; case INVALID_PARAMETERS_ENG_18: *os << "INVALID_PARAMETERS_ENG_18"; break; case INSUFFICIENT_CRYPTO_RESOURCES_3: @@ -504,6 +506,8 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { break; case INVALID_PARAMETERS_ENG_21: *os << "INVALID_PARAMETERS_ENG_21"; break; + case INVALID_PARAMETERS_ENG_22: *os << "INVALID_PARAMETERS_ENG_22"; + break; case SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR: *os << "SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR"; break; @@ -513,6 +517,17 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { case COPY_OLD_USAGE_ENTRY_UNKNOWN_ERROR: *os << "COPY_OLD_USAGE_ENTRY_UNKNOWN_ERROR"; break; + case LIST_LICENSES_ERROR: *os << "LIST_LICENSES_ERROR"; + break; + case INVALID_PARAMETERS_ENG_23: + *os << "INVALID_PARAMETERS_ENG_23"; + break; + case USAGE_INFORMATION_SUPPORT_FAILED: + *os << "USAGE_INFORMATION_SUPPORT_FAILED"; + break; + case USAGE_SUPPORT_GET_API_FAILED: + *os << "USAGE_SUPPORT_GET_API_FAILED"; + break; default: *os << "Unknown CdmResponseType"; diff --git a/libwvdrmengine/cdm/src/file_store.cpp b/libwvdrmengine/cdm/src/file_store.cpp index 9a278473..844d808f 100644 --- a/libwvdrmengine/cdm/src/file_store.cpp +++ b/libwvdrmengine/cdm/src/file_store.cpp @@ -171,6 +171,11 @@ ssize_t FileSystem::FileSize(const std::string& in_path) { return -1; } +bool FileSystem::List(const std::string& path, + std::vector* filenames) { + return FileUtils::List(GetFileNameForIdentifier(path, origin_), filenames); +} + void FileSystem::SetOrigin(const std::string& origin) { origin_ = origin; } void FileSystem::SetIdentifier(const std::string& identifier) { diff --git a/libwvdrmengine/include/WVErrors.h b/libwvdrmengine/include/WVErrors.h index 53e6b16d..552979cd 100644 --- a/libwvdrmengine/include/WVErrors.h +++ b/libwvdrmengine/include/WVErrors.h @@ -238,10 +238,16 @@ enum { kShrinkUsageTablerHeaderUnknownError = ERROR_DRM_VENDOR_MIN + 224, kMoveUsageEntryUnknownError = ERROR_DRM_VENDOR_MIN + 225, kCopyOldUsageEntryUnknownError = ERROR_DRM_VENDOR_MIN + 226, + kInvalidParametersEng22 = ERROR_DRM_VENDOR_MIN + 227, + kStoreLicenseError4 = ERROR_DRM_VENDOR_MIN + 228, + kListLicensesError = ERROR_DRM_VENDOR_MIN + 229, + kInvalidParametersEng23 = ERROR_DRM_VENDOR_MIN + 230, + kUsageInformationSupportFailed = ERROR_DRM_VENDOR_MIN + 231, + kUsageSupportGetApiFailed = ERROR_DRM_VENDOR_MIN + 232, // This should always follow the last error code. // The offset value should be updated each time a new error code is added. - kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 226, + kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 232, // 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 674f23f6..d9ff873c 100644 --- a/libwvdrmengine/include/mapErrors-inl.h +++ b/libwvdrmengine/include/mapErrors-inl.h @@ -419,6 +419,8 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kInvalidParametersEng15; case wvcdm::INVALID_PARAMETERS_ENG_16: return kInvalidParametersEng16; + case wvcdm::INVALID_PARAMETERS_ENG_17: + return kInvalidParametersEng17; case wvcdm::CERT_PROVISIONING_CLIENT_TOKEN_ERROR_1: return kCertProvisioningClientTokenError1; case wvcdm::CERT_PROVISIONING_CLIENT_TOKEN_ERROR_2: @@ -439,8 +441,6 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kLoadUsageHeaderBadMagic; case wvcdm::LOAD_USAGE_HEADER_UNKNOWN_ERROR: return kLoadUsageHeaderUnknownError; - case wvcdm::INVALID_PARAMETERS_ENG_17: - return kInvalidParametersEng17; case wvcdm::INVALID_PARAMETERS_ENG_18: return kInvalidParametersEng18; case wvcdm::INSUFFICIENT_CRYPTO_RESOURCES_3: @@ -461,12 +461,24 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kUpdateUsageEntryUnknownError; case wvcdm::INVALID_PARAMETERS_ENG_21: return kInvalidParametersEng21; + case wvcdm::INVALID_PARAMETERS_ENG_22: + return kInvalidParametersEng22; case wvcdm::SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR: return kShrinkUsageTablerHeaderUnknownError; case wvcdm::MOVE_USAGE_ENTRY_UNKNOWN_ERROR: return kMoveUsageEntryUnknownError; case wvcdm::COPY_OLD_USAGE_ENTRY_UNKNOWN_ERROR: return kCopyOldUsageEntryUnknownError; + case wvcdm::STORE_LICENSE_ERROR_4: + return kStoreLicenseError4; + case wvcdm::LIST_LICENSES_ERROR: + return kListLicensesError; + case wvcdm::INVALID_PARAMETERS_ENG_23: + return kInvalidParametersEng23; + case wvcdm::USAGE_INFORMATION_SUPPORT_FAILED: + return kUsageInformationSupportFailed; + case wvcdm::USAGE_SUPPORT_GET_API_FAILED: + return kUsageSupportGetApiFailed; case wvcdm::UNUSED_1: case wvcdm::UNUSED_2: