From 4069e721027b159c2ef5c29a249c80cfa7d1a9e0 Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Mon, 23 Jan 2017 23:09:04 -0800 Subject: [PATCH] Infrastructure changes to support big usage tables [ Merge of http://go/wvgerrit/23161 ] The usage table redesign will require storing usage table headers and usage entries in non-secure persistent store. This information will be signed by the TEE to prevent against modification. New Storage and retrieval methods have been added for usage table headers, while usage entries will be stored alongside (offline) licenses and (secure stops/)usage info. b/34327459 Test: All unittests, including newly introduced ones other than some oemcrypto, request_license_test passed. Those tests failed with or without this CL. Change-Id: I9b8d6210e33774b0803f8af1711b2d593d467aec --- .../cdm/core/include/device_files.h | 40 +- libwvdrmengine/cdm/core/src/cdm_engine.cpp | 8 +- libwvdrmengine/cdm/core/src/cdm_session.cpp | 10 +- libwvdrmengine/cdm/core/src/device_files.cpp | 142 ++++++- .../cdm/core/src/device_files.proto | 23 +- .../cdm/core/test/device_files_unittest.cpp | 349 +++++++++++++++--- 6 files changed, 498 insertions(+), 74 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/device_files.h b/libwvdrmengine/cdm/core/include/device_files.h index 40ae4d2b..1b97754d 100644 --- a/libwvdrmengine/cdm/core/include/device_files.h +++ b/libwvdrmengine/cdm/core/include/device_files.h @@ -28,6 +28,19 @@ class DeviceFiles { kLicenseStateUnknown, } LicenseState; + typedef enum { + kStorageLicense, // persistent license + kStorageUsageInfo, // secure stop + } UsageEntryStorage; + + struct UsageEntryInfo { + UsageEntryStorage storage_type; + std::string key_set_id; // used when storage_type is kStorageLicense + std::string + provider_session_token; // used when storage_type is kStorageUsageInfo + std::string app_id; // used when storage_type is kStorageUsageInfo + }; + DeviceFiles(FileSystem*); virtual ~DeviceFiles(); @@ -54,14 +67,16 @@ class DeviceFiles { int64_t playback_start_time, int64_t last_playback_time, int64_t grace_period_end_time, - const CdmAppParameterMap& app_parameters); + const CdmAppParameterMap& app_parameters, + const std::string& usage_entry); virtual bool RetrieveLicense( const std::string& key_set_id, LicenseState* state, CdmInitData* pssh_data, CdmKeyMessage* key_request, CdmKeyResponse* key_response, CdmKeyMessage* key_renewal_request, 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); + int64_t* grace_period_end_time, CdmAppParameterMap* app_parameters, + std::string* usage_entry); virtual bool DeleteLicense(const std::string& key_set_id); virtual bool DeleteAllFiles(); virtual bool DeleteAllLicenses(); @@ -73,7 +88,8 @@ class DeviceFiles { const CdmKeyMessage& key_request, const CdmKeyResponse& key_response, const std::string& app_id, - const std::string& key_set_id); + const std::string& key_set_id, + const std::string& 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 @@ -91,13 +107,15 @@ class DeviceFiles { virtual bool RetrieveUsageInfo(const std::string& app_id, const std::string& provider_session_token, CdmKeyMessage* license_request, - CdmKeyResponse* license_response); + CdmKeyResponse* license_response, + std::string* 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); + CdmKeyResponse* license_response, + std::string* usage_entry); virtual bool StoreHlsAttributes(const std::string& key_set_id, const CdmHlsMethod method, @@ -106,6 +124,15 @@ class DeviceFiles { CdmHlsMethod* method, std::vector* media_segment_iv); virtual bool DeleteHlsAttributes(const std::string& key_set_id); + + virtual bool StoreUsageTableInfo( + const std::string& usage_table_header, + const std::vector& usage_entry_info); + + virtual bool RetrieveUsageTableInfo( + std::string* usage_table_header, + std::vector* usage_entry_info); + private: // Helpers that wrap the File interface and automatically handle hashing, as // well as adding the device files base path to to the file name. @@ -123,6 +150,7 @@ class DeviceFiles { static std::string GetHlsAttributesFileNameExtension(); static std::string GetLicenseFileNameExtension(); static std::string GetUsageInfoFileName(const std::string& app_id); + static std::string GetUsageTableFileName(); static std::string GetFileNameSafeHash(const std::string& input); #if defined(UNIT_TEST) @@ -144,6 +172,8 @@ class DeviceFiles { FRIEND_TEST(DeviceFilesUsageInfoTest, DeleteAll); FRIEND_TEST(DeviceFilesUsageInfoTest, Read); FRIEND_TEST(DeviceFilesUsageInfoTest, Store); + FRIEND_TEST(DeviceFilesUsageTableTest, Read); + FRIEND_TEST(DeviceFilesUsageTableTest, Store); FRIEND_TEST(WvCdmRequestLicenseTest, UnprovisionTest); FRIEND_TEST(WvCdmRequestLicenseTest, ForceL3Test); FRIEND_TEST(WvCdmRequestLicenseTest, UsageInfoRetryTest); diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index 682da758..e41227fc 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -854,8 +854,9 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id, CdmKeyMessage license_request; CdmKeyResponse license_response; + std::string usage_entry; if (!handle.RetrieveUsageInfo(app_id, ssid, &license_request, - &license_response)) { + &license_response, &usage_entry)) { usage_property_set_->set_security_level(kLevel3); usage_property_set_->set_app_id(app_id); usage_session_.reset(new CdmSession(file_system_)); @@ -869,7 +870,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id, return GET_USAGE_INFO_ERROR_2; } if (!handle.RetrieveUsageInfo(app_id, ssid, &license_request, - &license_response)) { + &license_response, &usage_entry)) { // No entry found for that ssid. return USAGE_INFO_NOT_FOUND; } @@ -1084,8 +1085,9 @@ CdmResponseType CdmEngine::LoadUsageSession(const CdmKeySetId& key_set_id, CdmKeyMessage key_message; CdmKeyResponse key_response; + std::string usage_entry; if (!handle.RetrieveUsageInfoByKeySetId(app_id, key_set_id, &key_message, - &key_response)) { + &key_response, &usage_entry)) { LOGE("CdmEngine::LoadUsageSession: unable to find usage information"); return LOAD_USAGE_INFO_MISSING; } diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index 6503932a..3c060115 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -146,13 +146,14 @@ CdmResponseType CdmSession::RestoreOfflineSession( int64_t playback_start_time; int64_t last_playback_time; int64_t grace_period_end_time; + std::string usage_entry; if (!file_handle_->RetrieveLicense( key_set_id, &license_state, &offline_init_data_, &key_request_, &key_response_, &offline_key_renewal_request_, &offline_key_renewal_response_, &offline_release_server_url_, &playback_start_time, &last_playback_time, &grace_period_end_time, - &app_parameters_)) { + &app_parameters_, &usage_entry)) { LOGE("CdmSession::Init failed to retrieve license. key set id = %s", key_set_id.c_str()); return GET_LICENSE_ERROR; @@ -573,8 +574,10 @@ CdmResponseType CdmSession::StoreLicense() { std::string app_id; GetApplicationId(&app_id); + std::string usage_entry; if (!file_handle_->StoreUsageInfo(provider_session_token, key_request_, - key_response_, app_id, key_set_id_)) { + key_response_, app_id, key_set_id_, + usage_entry)) { LOGE("CdmSession::StoreLicense: Unable to store usage info"); return STORE_USAGE_INFO_ERROR; } @@ -582,12 +585,13 @@ CdmResponseType CdmSession::StoreLicense() { } bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) { + std::string usage_entry; return file_handle_->StoreLicense( key_set_id_, state, offline_init_data_, key_request_, key_response_, offline_key_renewal_request_, offline_key_renewal_response_, offline_release_server_url_, policy_engine_->GetPlaybackStartTime(), policy_engine_->GetLastPlaybackTime(), - policy_engine_->GetGracePeriodEndTime(), app_parameters_); + policy_engine_->GetGracePeriodEndTime(), app_parameters_, usage_entry); } CdmResponseType CdmSession::ReleaseCrypto() { diff --git a/libwvdrmengine/cdm/core/src/device_files.cpp b/libwvdrmengine/cdm/core/src/device_files.cpp index 7f760886..291c9143 100644 --- a/libwvdrmengine/cdm/core/src/device_files.cpp +++ b/libwvdrmengine/cdm/core/src/device_files.cpp @@ -34,6 +34,12 @@ using video_widevine_client::sdk::License_LicenseState_RELEASING; using video_widevine_client::sdk::NameValue; using video_widevine_client::sdk::UsageInfo; using video_widevine_client::sdk::UsageInfo_ProviderSession; +using video_widevine_client::sdk::UsageTableInfo; +using video_widevine_client::sdk::UsageTableInfo_UsageEntryInfo; +using video_widevine_client::sdk:: + UsageTableInfo_UsageEntryInfo_UsageEntryStorage_LICENSE; +using video_widevine_client::sdk:: + UsageTableInfo_UsageEntryInfo_UsageEntryStorage_USAGE_INFO; namespace { @@ -43,6 +49,7 @@ const char kUsageInfoFileNamePrefix[] = "usage"; const char kUsageInfoFileNameExt[] = ".bin"; const char kLicenseFileNameExt[] = ".lic"; const char kEmptyFileName[] = ""; +const char kUsageTableFileName[] = "usagetable.bin"; const char kWildcard[] = "*"; bool Hash(const std::string& data, std::string* hash) { @@ -169,7 +176,8 @@ bool DeviceFiles::StoreLicense( const CdmKeyResponse& license_renewal, 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 CdmAppParameterMap& app_parameters, + const std::string& usage_entry) { if (!initialized_) { LOGW("DeviceFiles::StoreLicense: not initialized"); return false; @@ -210,6 +218,7 @@ bool DeviceFiles::StoreLicense( app_params->set_name(iter->first); app_params->set_value(iter->second); } + license->set_usage_entry(usage_entry); std::string serialized_file; file.SerializeToString(&serialized_file); @@ -224,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) { + CdmAppParameterMap* app_parameters, std::string* usage_entry) { if (!initialized_) { LOGW("DeviceFiles::RetrieveLicense: not initialized"); return false; @@ -278,6 +287,7 @@ bool DeviceFiles::RetrieveLicense( (*app_parameters)[license.app_parameters(i).name()] = license.app_parameters(i).value(); } + *usage_entry = license.usage_entry(); return true; } @@ -340,7 +350,8 @@ bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token, const CdmKeyMessage& key_request, const CdmKeyResponse& key_response, const std::string& app_id, - const std::string& key_set_id) { + const std::string& key_set_id, + const std::string& usage_entry) { if (!initialized_) { LOGW("DeviceFiles::StoreUsageInfo: not initialized"); return false; @@ -366,6 +377,7 @@ bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token, provider_session->set_license_request(key_request.data(), key_request.size()); provider_session->set_license(key_response.data(), key_response.size()); provider_session->set_key_set_id(key_set_id.data(), key_set_id.size()); + provider_session->set_usage_entry(usage_entry); std::string serialized_file; file.SerializeToString(&serialized_file); @@ -479,7 +491,8 @@ bool DeviceFiles::RetrieveUsageInfo( bool DeviceFiles::RetrieveUsageInfo(const std::string& app_id, const std::string& provider_session_token, CdmKeyMessage* license_request, - CdmKeyResponse* license_response) { + CdmKeyResponse* license_response, + std::string* usage_entry) { if (!initialized_) { LOGW("DeviceFiles::RetrieveUsageInfo: not initialized"); return false; @@ -496,6 +509,7 @@ bool DeviceFiles::RetrieveUsageInfo(const std::string& app_id, if (file.usage_info().sessions(index).token() == provider_session_token) { *license_request = file.usage_info().sessions(index).license_request(); *license_response = file.usage_info().sessions(index).license(); + *usage_entry = file.usage_info().sessions(index).usage_entry(); return true; } } @@ -507,7 +521,8 @@ bool DeviceFiles::RetrieveUsageInfoByKeySetId( const std::string& app_id, const std::string& key_set_id, CdmKeyMessage* license_request, - CdmKeyResponse* license_response) { + CdmKeyResponse* license_response, + std::string* usage_entry) { if (!initialized_) { LOGW("DeviceFiles::RetrieveUsageInfoByKeySetId: not initialized"); return false; @@ -524,6 +539,7 @@ bool DeviceFiles::RetrieveUsageInfoByKeySetId( if (file.usage_info().sessions(index).key_set_id() == key_set_id) { *license_request = file.usage_info().sessions(index).license_request(); *license_response = file.usage_info().sessions(index).license(); + *usage_entry = file.usage_info().sessions(index).usage_entry(); return true; } } @@ -628,6 +644,118 @@ bool DeviceFiles::DeleteHlsAttributes(const std::string& key_set_id) { return RemoveFile(key_set_id + kHlsAttributesFileNameExt); } +bool DeviceFiles::StoreUsageTableInfo( + const std::string& usage_table_header, + const std::vector& usage_entry_info) { + if (!initialized_) { + LOGW("DeviceFiles::StoreUsageTableHeader: not initialized"); + return false; + } + + // Fill in file information + video_widevine_client::sdk::File file; + + file.set_type(video_widevine_client::sdk::File::USAGE_TABLE_INFO); + file.set_version(video_widevine_client::sdk::File::VERSION_1); + + UsageTableInfo* usage_table_info = file.mutable_usage_table_info(); + usage_table_info->set_usage_table_header(usage_table_header); + for (size_t i = 0; i < usage_entry_info.size(); ++i) { + UsageTableInfo_UsageEntryInfo* info = + usage_table_info->add_usage_entry_info(); + switch (usage_entry_info[i].storage_type) { + case kStorageLicense: + info->set_storage( + UsageTableInfo_UsageEntryInfo_UsageEntryStorage_LICENSE); + info->set_key_set_id(usage_entry_info[i].key_set_id); + break; + case kStorageUsageInfo: + info->set_storage( + UsageTableInfo_UsageEntryInfo_UsageEntryStorage_USAGE_INFO); + info->set_provider_session_token( + usage_entry_info[i].provider_session_token); + info->set_app_id(usage_entry_info[i].app_id); + break; + default: + LOGW("DeviceFiles::StoreUsageTableHeader: unknown storage type: %d", + usage_entry_info[i].storage_type); + return false; + } + } + + std::string serialized_file; + file.SerializeToString(&serialized_file); + + return StoreFileWithHash(GetUsageTableFileName(), serialized_file); +} + +bool DeviceFiles::RetrieveUsageTableInfo( + std::string* usage_table_header, + std::vector* usage_entry_info) { + if (!initialized_) { + LOGW("DeviceFiles::RetrieveUsageTableInfo: not initialized"); + return false; + } + + if (usage_table_header == NULL) { + LOGW( + "DeviceFiles::RetrieveUsageTableInfo: usage_table_header not provided"); + return false; + } + + if (usage_entry_info == NULL) { + LOGW("DeviceFiles::RetrieveUsageTableInfo: usage_entry_info not provided"); + return false; + } + + video_widevine_client::sdk::File file; + if (!RetrieveHashedFile(GetUsageTableFileName(), &file)) { + return false; + } + + if (file.type() != video_widevine_client::sdk::File::USAGE_TABLE_INFO) { + LOGW("DeviceFiles::RetrieveUsageTableInfo: Incorrect file type"); + return false; + } + + if (file.version() != video_widevine_client::sdk::File::VERSION_1) { + LOGW("DeviceFiles::RetrieveUsageTableInfo: Incorrect file version"); + return false; + } + + if (!file.has_usage_table_info()) { + LOGW("DeviceFiles::RetrieveUsageTableInfo: Usage table info not present"); + return false; + } + + const UsageTableInfo& usage_table_info = file.usage_table_info(); + + *usage_table_header = usage_table_info.usage_table_header(); + usage_entry_info->resize(usage_table_info.usage_entry_info_size()); + for (int i = 0; i < usage_table_info.usage_entry_info_size(); ++i) { + const UsageTableInfo_UsageEntryInfo& info = + usage_table_info.usage_entry_info(i); + switch (info.storage()) { + case UsageTableInfo_UsageEntryInfo_UsageEntryStorage_LICENSE: + (*usage_entry_info)[i].storage_type = kStorageLicense; + (*usage_entry_info)[i].key_set_id = info.key_set_id(); + break; + case UsageTableInfo_UsageEntryInfo_UsageEntryStorage_USAGE_INFO: + (*usage_entry_info)[i].storage_type = kStorageUsageInfo; + (*usage_entry_info)[i].provider_session_token = + info.provider_session_token(); + (*usage_entry_info)[i].app_id = info.app_id(); + break; + default: + LOGW("DeviceFiles::RetrieveUsageTableInfo: Unknown storage type: %d", + info.storage()); + return false; + } + } + + return true; +} + bool DeviceFiles::StoreFileWithHash(const std::string& name, const std::string& serialized_file) { // calculate SHA hash @@ -796,6 +924,10 @@ std::string DeviceFiles::GetCertificateFileName() { return kCertificateFileName; } +std::string DeviceFiles::GetUsageTableFileName() { + return kUsageTableFileName; +} + std::string DeviceFiles::GetHlsAttributesFileNameExtension() { return kHlsAttributesFileNameExt; } diff --git a/libwvdrmengine/cdm/core/src/device_files.proto b/libwvdrmengine/cdm/core/src/device_files.proto index eef367d6..1bfb21ce 100644 --- a/libwvdrmengine/cdm/core/src/device_files.proto +++ b/libwvdrmengine/cdm/core/src/device_files.proto @@ -43,6 +43,7 @@ message License { // contains the playback_start_time we should use as an override. This is // ignored if there is no grace period. optional int64 grace_period_end_time = 11 [default = 0]; + optional bytes usage_entry = 12; } message UsageInfo { @@ -51,13 +52,14 @@ message UsageInfo { optional bytes license_request = 2; optional bytes license = 3; optional bytes key_set_id = 4; + optional bytes usage_entry = 5; } repeated ProviderSession sessions = 1; } message HlsAttributes { - enum Method { + enum Method { AES_128 = 1; SAMPLE_AES = 2; } @@ -65,12 +67,30 @@ message HlsAttributes { optional bytes media_segment_iv = 2; } +message UsageTableInfo { + message UsageEntryInfo { + enum UsageEntryStorage { + LICENSE = 1; + USAGE_INFO = 2; + } + + optional UsageEntryStorage storage = 1; + optional bytes key_set_id = 2; // used if storage is LICENSE + optional bytes provider_session_token = 3; // used if storage is USAGE_INFO + optional bytes app_id = 4; // used if storage is USAGE_INFO + } + + optional bytes usage_table_header = 1; + repeated UsageEntryInfo usage_entry_info = 2; +} + message File { enum FileType { DEVICE_CERTIFICATE = 1; LICENSE = 2; USAGE_INFO = 3; HLS_ATTRIBUTES = 4; + USAGE_TABLE_INFO = 5; } enum FileVersion { @@ -83,6 +103,7 @@ message File { optional License license = 4; optional UsageInfo usage_info = 5; optional HlsAttributes hls_attributes = 6; + optional UsageTableInfo usage_table_info = 7; } message HashedFile { diff --git a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp index 4b08a553..c198ebb3 100644 --- a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp @@ -22,6 +22,9 @@ const uint32_t kLicenseRequestLen = 300; const uint32_t kLicenseLen = 500; const uint32_t kProviderSessionTokenLen = 128; const uint32_t kKeySetIdLen = 20; +const uint32_t kUsageEntryLen = 50; + +const std::string kEmptyString; // Structurally valid test certificate. // The data elements in this module are used to test the storage and @@ -120,6 +123,7 @@ struct LicenseInfo { int64_t last_playback_time; int64_t grace_period_end_time; std::string app_parameters; + std::string usage_entry; std::string file_data; }; @@ -226,9 +230,9 @@ LicenseInfo license_test_data[] = { "0112001A16200342120A106B63746C0000000000ECDCBE0000000020DBDF" "A68F051A20182F029E35047A3841FA176C74E5B387350E8D58DEA6878FF0" "BEA6CABACA1C2C"), - "https://test.google.com/license/GetCencLicense", 0x0, 0x0, 0x0, "", + "https://test.google.com/license/GetCencLicense", 0x0, 0x0, 0x0, "", "", a2bs_hex( - "0AAA150802100122A3150801121408011210303132333435363738394142434445461" + "0AAC150802100122A5150801121408011210303132333435363738394142434445461" "A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0" "7A7D507618A5D3A68F05228E023082010A0282010100A947904B8DBD55FB685FDB302" "5574517CCCC74EE4FEAF6629D5179A52FF85CE7409528EFFA0E5DFC3DE9A34BA5F08B" @@ -307,8 +311,8 @@ LicenseInfo license_test_data[] = { "106B63746C0000000000ECDCBE0000000020DBDFA68F051A20182F029E35047A3841F" "A176C74E5B387350E8D58DEA6878FF0BEA6CABACA1C2C3A2E68747470733A2F2F7465" "73742E676F6F676C652E636F6D2F6C6963656E73652F47657443656E634C6963656E7" - "365400048005800122066F4FFF1CB2C0F978149A9402F3E4FF8D49B19635E646A0678" - "71AA08E7A8FDC3")}, + "3654000480058006200122039CB77169260F923E5D4BA5BBF6A7611117483253F2869" + "9DF3D9D14C3718E309")}, // license 1 {"ksidC8EAA2579A282EB0", DeviceFiles::kLicenseStateReleasing, @@ -409,7 +413,10 @@ LicenseInfo license_test_data[] = { "https://test.google.com/license/GetCencLicense", 0x12345678, 0x12348765, 0x0, "Name1 Value1", a2bs_hex( - "0AC3150802100122BC150802121408011210303132333435363738394142434445461" + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" + "22232425262728292a2b2c2d2e2f"), + a2bs_hex( + "0AF5150802100122EE150802121408011210303132333435363738394142434445461" "A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0" "7A7D507618A5D3A68F05228E023082010A0282010100A947904B8DBD55FB685FDB302" "5574517CCCC74EE4FEAF6629D5179A52FF85CE7409528EFFA0E5DFC3DE9A34BA5F08B" @@ -488,8 +495,10 @@ LicenseInfo license_test_data[] = { "106B63746C00000000CA3A6A75000000002083E5A68F051A20BDA6A56F7CBFD094219" "8F87C23A34AA5CBD64AFEB134277774CCF8E789D815DD3A2E68747470733A2F2F7465" "73742E676F6F676C652E636F6D2F6C6963656E73652F47657443656E634C6963656E7" - "36540F8ACD1910148E58ED29101520F0A054E616D6531120656616C75653158001220" - "9C0315FC1812C6A0E5936E36D04ECE2FA56AF4AB544ECDF3C9135D54B4A26167")}, + "36540F8ACD1910148E58ED29101520F0A054E616D6531120656616C75653158006230" + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212" + "2232425262728292A2B2C2D2E2F1220312487214ACA5A9AF5ED9D45F209DC77E03CA1" + "DBFFDF86C44A35A1351CE968B9")}, // license 2 {"ksidE8C37662C88DC673", DeviceFiles::kLicenseStateReleasing, @@ -590,7 +599,10 @@ LicenseInfo license_test_data[] = { "https://test.google.com/license/GetCencLicense", 0x0123456789abcdef, 0x123456789abfedc, 0x0, "Name1 Value1 Name2 Param2", a2bs_hex( - "0AE9150802100122E2150802121408011210303132333435363738394142434445461" + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" + "22232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"), + a2bs_hex( + "0AAB160802100122A4160802121408011210303132333435363738394142434445461" "A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0" "7A7D507618A5D3A68F05228E023082010A0282010100A947904B8DBD55FB685FDB302" "5574517CCCC74EE4FEAF6629D5179A52FF85CE7409528EFFA0E5DFC3DE9A34BA5F08B" @@ -671,8 +683,9 @@ LicenseInfo license_test_data[] = { "73742E676F6F676C652E636F6D2F6C6963656E73652F47657443656E634C6963656E7" "36540EF9BAFCDF8ACD1910148DCFDAFCDF8ACD1910152150A054E616D6531120C5661" "6C756531204E616D653252160A0C4E616D653220506172616D321206506172616D325" - "8001220616E6AC4AF6EB4F7147E98CF7302425E2390B293BBC01F9F8E89B49F653EA3" - "45")}}; + "8006240000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E" + "1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F122" + "07CEAAE401B81E635808AC830A0F3F43308A38FAB16069E542F994B6EC1325280")}}; // Sample license data and related data for storage and use for offline // playback. The license data and URLs in this test are not real. @@ -777,7 +790,10 @@ LicenseInfo license_update_test_data[] = { "https://test.google.com/license/GetCencLicense", 0x0123456789abcdef, 0x123456789abfedc, 0x0, "Name1 Value1 Name2 Value2 Name3 Value3", a2bs_hex( - "0ABA150802100122B3150801121408011210303132333435363738394142434445461" + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" + "22232425262728292a2b2c2d2e2f"), + a2bs_hex( + "0AEC150802100122E5150801121408011210303132333435363738394142434445461" "A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0" "7A7D5076189EDFB68F05228E023082010A0282010100CC1715C81AD3F6F279C686F82" "6E6D7C8961EB13318367D06B4061BBC57E3C616A226A10F042CAD54D44C6484C725CD" @@ -856,14 +872,16 @@ LicenseInfo license_update_test_data[] = { "106B63746C0000000071FEF30B0000000020F4DFB68F051A2000351030900858FCFD6" "977B67803ADFD1280AA661E6B0BD30B08B2C4673551293A2E68747470733A2F2F7465" "73742E676F6F676C652E636F6D2F6C6963656E73652F47657443656E634C6963656E7" - "36540EF9BAFCDF8ACD1910148DCFDAFCDF8ACD191015800122051F15CDA5B9414919D" - "B67769A781CC4F43138D314DAFFCBFBD620E53167E4AF2")}, + "36540EF9BAFCDF8ACD1910148DCFDAFCDF8ACD1910158006230000102030405060708" + "090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2" + "B2C2D2E2F1220A33C179B7718632337DFDC32D3711FD543336EBE838979DFDEB3A168" + "BC9AFB27")}, // license being released. all fields are identical except for license // state and hashed file data {"", DeviceFiles::kLicenseStateReleasing, "", "", "", "", "", "", 0, 0, 0, - "", + "", "", a2bs_hex( - "0ABA150802100122B3150802121408011210303132333435363738394142434445461" + "0AEC150802100122E5150802121408011210303132333435363738394142434445461" "A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0" "7A7D5076189EDFB68F05228E023082010A0282010100CC1715C81AD3F6F279C686F82" "6E6D7C8961EB13318367D06B4061BBC57E3C616A226A10F042CAD54D44C6484C725CD" @@ -942,8 +960,10 @@ LicenseInfo license_update_test_data[] = { "106B63746C0000000071FEF30B0000000020F4DFB68F051A2000351030900858FCFD6" "977B67803ADFD1280AA661E6B0BD30B08B2C4673551293A2E68747470733A2F2F7465" "73742E676F6F676C652E636F6D2F6C6963656E73652F47657443656E634C6963656E7" - "36540EF9BAFCDF8ACD1910148DCFDAFCDF8ACD191015800122093FDE0D42BC60D3932" - "02E0D5A49775E08093BF01560EF72C298321E921716E24")}}; + "36540EF9BAFCDF8ACD1910148DCFDAFCDF8ACD1910158006230000102030405060708" + "090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2" + "B2C2D2E2F1220394BA01DFB519C1A7311115F8B2A0AC3141F981FFEA09FCD48A8EFA3" + "A045AAE6")}}; // Application parameters were added to the License message. This data // is used to verify that a License saved without application parameters can @@ -1045,7 +1065,7 @@ LicenseInfo license_app_parameters_backwards_compatibility_test_data = { "0112001A16200342120A106B63746C0000000000ECDCBE0000000020DBDF" "A68F051A20182F029E35047A3841FA176C74E5B387350E8D58DEA6878FF0" "BEA6CABACA1C2C"), - "https://test.google.com/license/GetCencLicense", 0x0, 0x0, 0x0, "", + "https://test.google.com/license/GetCencLicense", 0x0, 0x0, 0x0, "", "", a2bs_hex( "0AA8150802100122A1150801121408011210303132333435363738394142434445461" "A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0" @@ -1133,14 +1153,14 @@ struct UsageInfo { std::string provider_session_token; std::string license_request; std::string license; + std::string usage_entry; std::string file_data; }; UsageInfo kUsageInfoTestData[] = { - {"", "", "", // 0 usage info records - a2bs_hex( - "0A06080210012A00122095053501C5FA405B7EF01DA94685C6B20CB36493" - "A9CF1653B720E2BEA3B77929")}, + {"", "", "", "", // 0 usage info records + a2bs_hex("0A06080210012A00122095053501C5FA405B7EF01DA94685C6B20CB36493" + "A9CF1653B720E2BEA3B77929")}, {// 1 usage info record a2bs_hex( "924B035FBDA56AE5EF0ED05A08DE7AECC8ABE1835E0C4A548F7803937F4C3B4520EB7" @@ -1173,6 +1193,9 @@ UsageInfo kUsageInfoTestData[] = { "E103904BBE4C031A6483858FBAD74DACD01711F7B882749FFFBA0DB6C7D7109D82989" "C7D4DB5A0F1E7506AC24C89CECAF231EFF99F96AD76E57DABDD3C2DFBA7BAA869A771" "F561B165987E552824B0C914E708E425C3"), + a2bs_hex( + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" + "22232425262728292a2b2c2d2e2f"), a2bs_hex( "0AB307080210012AAC070AA9070A8001924B035FBDA56AE5EF0ED05A08DE7AECC8ABE" "1835E0C4A548F7803937F4C3B4520EB7F3334FFCDFA00DE56408F09D5019FCE87072D" @@ -1235,6 +1258,9 @@ UsageInfo kUsageInfoTestData[] = { "9D4D0AA2B358990F244BA76C8E40791D29A0C63C9EF620B97FDFFA9B671E5A65AFCC1" "C94CAACE0443E9D91F14028935BEA3988831BEBBFD3EB7C3A5AC9605B3534712A0912" "4345ACB09665E357E58946871BC140D365"), + a2bs_hex( + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" + "22232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"), a2bs_hex( "0ADF0E080210012AD80E0AA9070A8001924B035FBDA56AE5EF0ED05A08DE7AECC8ABE" "1835E0C4A548F7803937F4C3B4520EB7F3334FFCDFA00DE56408F09D5019FCE87072D" @@ -1324,6 +1350,9 @@ UsageInfo kUsageInfoTestData[] = { "0FF37DF85BE23D58C17379FEC08DC0648236A107AE66178EEBF78F05F3B898424FA02" "668B51F838AFA90D367B5CB425372D8CC3790BEA8AFB8795251FA09340D85A7F0B003" "134C838F08BB1054D18404C3F69130700E"), + a2bs_hex( + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" + "22232425262728292a2b2c2d2e2f"), a2bs_hex( "0A8B16080210012A84160AA9070A8001924B035FBDA56AE5EF0ED05A08DE7AECC8ABE" "1835E0C4A548F7803937F4C3B4520EB7F3334FFCDFA00DE56408F09D5019FCE87072D" @@ -1433,6 +1462,93 @@ HlsAttributesInfo kHlsAttributesTestData[] = { "41"), }}; +// Usage Table and Entry Test Data +// Note: Make sure the number of entries in kUsageEntriesTestData and +// kUsageTableInfoTestData are equal. +DeviceFiles::UsageEntryInfo kUsageEntriesTestData[] = { + // usage entry 0 + { + DeviceFiles::kStorageLicense, "ksid0", "", "", + }, + // usage entry 1 + { + DeviceFiles::kStorageLicense, "ksid1", "", "", + }, + // usage entry 2 + { + DeviceFiles::kStorageUsageInfo, "", "provider_session_token_2", + "app_id_2", + }, + // usage entry 3 + { + DeviceFiles::kStorageUsageInfo, "", "provider_session_token_3", + "app_id_3", + }, + // usage entry 4 + { + DeviceFiles::kStorageLicense, "ksid4", "", "", + }, + // usage entry 5 + { + DeviceFiles::kStorageUsageInfo, "", "provider_session_token_5", + "app_id_5", + }, + +}; + +struct UsageTableTestInfo { + std::string usage_table_header; + std::string file_data; +}; + +UsageTableTestInfo kUsageTableInfoTestData[] = { + // usage table 0 + {a2bs_hex("5574517CCC"), + a2bs_hex("0A18080510013A120A055574517CCC1209080112056B73696430122018268E3F" + "384F28D04BEE00304089C000463C22E987532855390915FD02C36B5C")}, + // usage table 1 + {a2bs_hex("CA870203010001288001"), + a2bs_hex("0A28080510013A220A0ACA8702030100012880011209080112056B7369643012" + "09080112056B7369643112202D3638164ADC3B4276734A8EDE96C40BFE14DDB2" + "8013337A3A1A9DFC09F34923")}, + // usage table 2 + {a2bs_hex("7A7D507618A5D3A68F05228E023082010A028201"), + a2bs_hex("0A5A080510013A540A147A7D507618A5D3A68F05228E023082010A0282011209" + "080112056B736964301209080112056B73696431122608021A1870726F766964" + "65725F73657373696F6E5F746F6B656E5F3222086170705F69645F321220CB07" + "CA08A1E76C61A5F45067176B960A9DB40D169025AF245CF1AFC66C979F47")}, + // usage table 3 + {a2bs_hex("E83A4902772DAFD2740B7748E9C3B1752D6F12859CED07E82969B4EC"), + a2bs_hex("0A8B01080510013A84010A1CE83A4902772DAFD2740B7748E9C3B1752D6F1285" + "9CED07E82969B4EC1209080112056B736964301209080112056B736964311226" + "08021A1870726F76696465725F73657373696F6E5F746F6B656E5F3222086170" + "705F69645F32122608021A1870726F76696465725F73657373696F6E5F746F6B" + "656E5F3322086170705F69645F331220C4157F80E81C923A9F0885CE6B928D15" + "7E1648384C3E44F04A966815EB09B260")}, + // usage table 4 + {a2bs_hex("CA870203010001288001300112800250D1F8B1ECF849B60FF93E37C4DEEF" + "52F1CCFC047EF42300131F9C4758F4"), + a2bs_hex("0AA701080510013AA0010A2DCA870203010001288001300112800250D1F8B1EC" + "F849B60FF93E37C4DEEF52F1CCFC047EF42300131F9C4758F41209080112056B" + "736964301209080112056B73696431122608021A1870726F76696465725F7365" + "7373696F6E5F746F6B656E5F3222086170705F69645F32122608021A1870726F" + "76696465725F73657373696F6E5F746F6B656E5F3322086170705F69645F3312" + "09080112056B7369643412203F75C53693E7A3DC9BA5BF3E23D7EFCF3C05687A" + "A6082E3AB78F563525981999")}, + // usage table 5 + {a2bs_hex("EC83A4902772DAFD2740B7748E9C3B1752D6F12859CED07E8882969B433E" + "C29AC6FDBE79230B0FAED5D94CF6B829A420BBE3270323941776EE60DD6B"), + a2bs_hex("0ADE01080510013AD7010A3CEC83A4902772DAFD2740B7748E9C3B1752D6F128" + "59CED07E8882969B433EC29AC6FDBE79230B0FAED5D94CF6B829A420BBE32703" + "23941776EE60DD6B1209080112056B736964301209080112056B736964311226" + "08021A1870726F76696465725F73657373696F6E5F746F6B656E5F3222086170" + "705F69645F32122608021A1870726F76696465725F73657373696F6E5F746F6B" + "656E5F3322086170705F69645F331209080112056B73696434122608021A1870" + "726F76696465725F73657373696F6E5F746F6B656E5F3522086170705F69645F" + "3512203B35BD5C615BBA79008A7A1DA29AFA69F5CD529DFDE794A0544E423B72" + "1CB8E8")}, +}; + class MockFile : public File { public: MockFile() : File(NULL) {} @@ -1488,10 +1604,18 @@ class DeviceFilesTest : public ::testing::Test { } size_t GetLicenseDataSize(LicenseInfo& data) { + CdmAppParameterMap app_parameters = GetAppParameters(data.app_parameters); + size_t app_parameters_len = 0; + CdmAppParameterMap::const_iterator itr = app_parameters.begin(); + for (itr = app_parameters.begin(); itr != app_parameters.end(); ++itr) { + app_parameters_len += itr->first.length(); + app_parameters_len += itr->second.length(); + } return sizeof(DeviceFiles::LicenseState) + data.pssh_data.size() + data.key_request.size() + data.key_response.size() + data.key_renewal_request.size() + data.key_renewal_response.size() + - data.key_release_url.size() + 3 * sizeof(int64_t); + data.key_release_url.size() + 3 * sizeof(int64_t) + + app_parameters_len + data.usage_entry.size(); } CdmAppParameterMap GetAppParameters(std::string str) { @@ -1533,12 +1657,30 @@ class DeviceFilesHlsAttributesTest : public DeviceFilesTest, public ::testing::WithParamInterface {}; +class DeviceFilesUsageTableTest : public DeviceFilesTest, + public ::testing::WithParamInterface {}; + MATCHER(IsCreateFileFlagSet, "") { return FileSystem::kCreate & arg; } MATCHER_P(IsStrEq, str, "") { // Estimating the length of data. We can have gmock provide length // as well as pointer to data but that will introduce a dependency on tr1 return memcmp(arg, str.c_str(), str.size()) == 0; } +MATCHER_P(ContainsAllElementsInVector, str_vector, "") { + // Estimating the length of data. We can have gmock provide length + // as well as pointer to data but that will introduce a dependency on tr1 + size_t str_length = 0; + for (size_t i = 0; i < str_vector.size(); ++i) { + str_length += str_vector[i].size(); + } + std::string data(arg, str_length + kProtobufEstimatedOverhead); + bool all_entries_found = true; + for (size_t i = 0; i < str_vector.size(); ++i) { + if (data.find(str_vector[i]) == std::string::npos) + all_entries_found = false; + } + return all_entries_found; +} MATCHER_P2(Contains, str1, size, "") { // Estimating the length of data. We can have gmock provide length // as well as pointer to data but that will introduce a dependency on tr1 @@ -1562,30 +1704,19 @@ MATCHER_P4(Contains, str1, str2, str3, size, "") { data.find(str2) != std::string::npos && data.find(str3) != std::string::npos); } -MATCHER_P5(Contains, str1, str2, str3, str4, size, "") { +MATCHER_P6(Contains, str1, str2, str3, str4, str5, size, "") { // Estimating the length of data. We can have gmock provide length // as well as pointer to data but that will introduce a dependency on tr1 std::string data(arg, size + str1.size() + str2.size() + str3.size() + - str4.size() + kProtobufEstimatedOverhead); - return (data.find(str1) != std::string::npos && - data.find(str2) != std::string::npos && - data.find(str3) != std::string::npos && - data.find(str4) != std::string::npos); -} -MATCHER_P6(Contains, str1, str2, str3, str4, str5, str6, "") { - // Estimating the length of data. We can have gmock provide length - // as well as pointer to data but that will introduce a dependency on tr1 - std::string data(arg, str1.size() + str2.size() + str3.size() + str4.size() + - str5.size() + str6.size() + + str4.size() + str5.size() + kProtobufEstimatedOverhead); return (data.find(str1) != std::string::npos && data.find(str2) != std::string::npos && data.find(str3) != std::string::npos && data.find(str4) != std::string::npos && - data.find(str5) != std::string::npos && - data.find(str6) != std::string::npos); + data.find(str5) != std::string::npos); } -MATCHER_P7(Contains, str1, str2, str3, str4, str5, str6, map7, "") { +MATCHER_P8(Contains, str1, str2, str3, str4, str5, str6, map7, str8, "") { // Estimating the length of data. We can have gmock provide length // as well as pointer to data but that will introduce a dependency on tr1 size_t map7_len = 0; @@ -1595,7 +1726,7 @@ MATCHER_P7(Contains, str1, str2, str3, str4, str5, str6, map7, "") { map7_len += itr->second.length(); } std::string data(arg, str1.size() + str2.size() + str3.size() + str4.size() + - str5.size() + str6.size() + map7_len + + str5.size() + str6.size() + map7_len + str8.size() + kProtobufEstimatedOverhead); bool map7_entries_present = true; for (itr = map7.begin(); itr != map7.end(); ++itr) { @@ -1608,7 +1739,8 @@ MATCHER_P7(Contains, str1, str2, str3, str4, str5, str6, map7, "") { data.find(str3) != std::string::npos && data.find(str4) != std::string::npos && data.find(str5) != std::string::npos && - data.find(str6) != std::string::npos && map7_entries_present); + data.find(str6) != std::string::npos && map7_entries_present && + data.find(str8) != std::string::npos); } TEST_F(DeviceCertificateStoreTest, StoreCertificate) { @@ -1731,7 +1863,8 @@ TEST_P(DeviceFilesStoreTest, StoreLicense) { license_test_data[license_num].key_renewal_request, license_test_data[license_num].key_renewal_response, license_test_data[license_num].key_release_url, - app_parameters), + app_parameters, + license_test_data[license_num].usage_entry), Gt(GetLicenseDataSize(license_test_data[license_num])))) .WillOnce(ReturnArg<1>()); EXPECT_CALL(file, Close()).Times(1); @@ -1750,7 +1883,8 @@ TEST_P(DeviceFilesStoreTest, StoreLicense) { license_test_data[license_num].key_release_url, license_test_data[license_num].playback_start_time, license_test_data[license_num].last_playback_time, - license_test_data[license_num].grace_period_end_time, app_parameters)); + license_test_data[license_num].grace_period_end_time, app_parameters, + license_test_data[license_num].usage_entry)); } INSTANTIATE_TEST_CASE_P(StoreLicense, DeviceFilesStoreTest, ::testing::Bool()); @@ -1776,7 +1910,8 @@ TEST_F(DeviceFilesTest, StoreLicenses) { license_test_data[i].key_renewal_request, license_test_data[i].key_renewal_response, license_test_data[i].key_release_url, - app_parameters), + app_parameters, + license_test_data[i].usage_entry), Gt(GetLicenseDataSize(license_test_data[i])))) .WillOnce(ReturnArg<1>()); } @@ -1798,7 +1933,8 @@ TEST_F(DeviceFilesTest, StoreLicenses) { license_test_data[i].key_release_url, license_test_data[i].playback_start_time, license_test_data[i].last_playback_time, - license_test_data[i].grace_period_end_time, app_parameters)); + license_test_data[i].grace_period_end_time, app_parameters, + license_test_data[i].usage_entry)); } } @@ -1839,6 +1975,7 @@ TEST_F(DeviceFilesTest, RetrieveLicenses) { int64_t grace_period_end_time; std::string release_server_url; CdmAppParameterMap app_parameters; + std::string usage_entry; for (size_t i = 0; i < kNumberOfLicenses; i++) { DeviceFiles::LicenseState license_state; @@ -1846,7 +1983,8 @@ TEST_F(DeviceFilesTest, RetrieveLicenses) { license_test_data[i].key_set_id, &license_state, &pssh_data, &key_request, &key_response, &key_renewal_request, &key_renewal_response, &release_server_url, &playback_start_time, - &last_playback_time, &grace_period_end_time, &app_parameters)); + &last_playback_time, &grace_period_end_time, &app_parameters, + &usage_entry)); EXPECT_EQ(license_test_data[i].license_state, license_state); EXPECT_EQ(license_test_data[i].pssh_data, pssh_data); EXPECT_EQ(license_test_data[i].key_request, key_request); @@ -1857,6 +1995,7 @@ TEST_F(DeviceFilesTest, RetrieveLicenses) { EXPECT_EQ(license_test_data[i].last_playback_time, last_playback_time); EXPECT_EQ(license_test_data[i].grace_period_end_time, grace_period_end_time); + EXPECT_EQ(license_test_data[i].usage_entry, usage_entry); std::map::iterator itr; for (itr = app_parameters.begin(); itr != app_parameters.end(); ++itr) { @@ -1904,12 +2043,13 @@ TEST_F(DeviceFilesTest, AppParametersBackwardCompatibility) { int64_t grace_period_end_time; std::string release_server_url; CdmAppParameterMap app_parameters; + std::string usage_entry; EXPECT_TRUE(device_files.RetrieveLicense( test_data->key_set_id, &license_state, &pssh_data, &key_request, &key_response, &key_renewal_request, &key_renewal_response, &release_server_url, &playback_start_time, &last_playback_time, - &grace_period_end_time, &app_parameters)); + &grace_period_end_time, &app_parameters, &usage_entry)); EXPECT_EQ(test_data->license_state, license_state); EXPECT_EQ(test_data->pssh_data, pssh_data); EXPECT_EQ(test_data->key_request, key_request); @@ -1920,6 +2060,7 @@ TEST_F(DeviceFilesTest, AppParametersBackwardCompatibility) { EXPECT_EQ(test_data->last_playback_time, last_playback_time); EXPECT_EQ(test_data->grace_period_end_time, grace_period_end_time); EXPECT_EQ(0u, app_parameters.size()); + EXPECT_EQ(test_data->usage_entry, usage_entry); } TEST_F(DeviceFilesTest, UpdateLicenseState) { @@ -1955,7 +2096,8 @@ TEST_F(DeviceFilesTest, UpdateLicenseState) { license_update_test_data[0].playback_start_time, license_update_test_data[0].last_playback_time, license_update_test_data[0].grace_period_end_time, - GetAppParameters(license_test_data[0].app_parameters))); + GetAppParameters(license_test_data[0].app_parameters), + license_update_test_data[0].usage_entry)); EXPECT_TRUE(device_files.StoreLicense( license_update_test_data[0].key_set_id, @@ -1969,7 +2111,8 @@ TEST_F(DeviceFilesTest, UpdateLicenseState) { license_update_test_data[0].playback_start_time, license_update_test_data[0].last_playback_time, license_update_test_data[0].grace_period_end_time, - GetAppParameters(license_test_data[0].app_parameters))); + GetAppParameters(license_test_data[0].app_parameters), + license_update_test_data[0].usage_entry)); } TEST_F(DeviceFilesTest, DeleteLicense) { @@ -2009,12 +2152,13 @@ TEST_F(DeviceFilesTest, DeleteLicense) { std::string release_server_url; int64_t playback_start_time, last_playback_time, grace_period_end_time; CdmAppParameterMap app_parameters; + std::string usage_entry; EXPECT_TRUE(device_files.RetrieveLicense( license_test_data[0].key_set_id, &license_state, &pssh_data, &key_request, &key_response, &key_renewal_request, &key_renewal_response, &release_server_url, &playback_start_time, &last_playback_time, - &grace_period_end_time, &app_parameters)); + &grace_period_end_time, &app_parameters, &usage_entry)); EXPECT_EQ(license_test_data[0].license_state, license_state); EXPECT_EQ(license_test_data[0].pssh_data, pssh_data); EXPECT_EQ(license_test_data[0].key_request, key_request); @@ -2031,6 +2175,7 @@ TEST_F(DeviceFilesTest, DeleteLicense) { EXPECT_NE(license_test_data[0].app_parameters.find(itr->second), std::string::npos); } + EXPECT_EQ(license_test_data[0].usage_entry, usage_entry); EXPECT_TRUE(device_files.DeleteLicense(license_test_data[0].key_set_id)); EXPECT_FALSE(device_files.LicenseExists(license_test_data[0].key_set_id)); @@ -2112,6 +2257,7 @@ TEST_P(DeviceFilesUsageInfoTest, Store) { std::string license_request(GenerateRandomData(kLicenseRequestLen)); std::string license(GenerateRandomData(kLicenseLen)); std::string key_set_id(GenerateRandomData(kKeySetIdLen)); + std::string usage_entry(GenerateRandomData(kUsageEntryLen)); std::string path = device_base_path_ + DeviceFiles::GetUsageInfoFileName(app_id); @@ -2140,19 +2286,17 @@ TEST_P(DeviceFilesUsageInfoTest, Store) { EXPECT_CALL(file, Close()); } - EXPECT_CALL(file, - Write(Contains(pst, license_request, license, key_set_id, - data.size()), - Gt(pst.size() + license_request.size() + license.size() + - key_set_id.size()))) + EXPECT_CALL(file, Write(Contains(pst, license_request, license, key_set_id, + usage_entry, data.size()), + Gt(pst.size() + license_request.size() + + license.size() + key_set_id.size()))) .WillOnce(ReturnArg<1>()); DeviceFiles device_files(&file_system); EXPECT_TRUE(device_files.Init(kSecurityLevelL1)); - ASSERT_TRUE( - device_files.StoreUsageInfo(pst, license_request, license, app_id, - key_set_id)); + ASSERT_TRUE(device_files.StoreUsageInfo(pst, license_request, license, app_id, + key_set_id, usage_entry)); } TEST_P(DeviceFilesUsageInfoTest, Delete) { @@ -2323,4 +2467,95 @@ INSTANTIATE_TEST_CASE_P(HlsAttributes, DeviceFilesHlsAttributesTest, ::testing::Range(&kHlsAttributesTestData[0], &kHlsAttributesTestData[2])); +TEST_P(DeviceFilesUsageTableTest, Store) { + MockFileSystem file_system; + MockFile file; + int index = GetParam(); + + size_t entry_data_length = 0; + std::vector entry_data; + std::vector usage_entry_info; + usage_entry_info.resize(index + 1); + for (int i = 0; i <= index; ++i) { + usage_entry_info[i] = kUsageEntriesTestData[i]; + if (kUsageEntriesTestData[i].storage_type == DeviceFiles::kStorageLicense) { + entry_data.push_back(kUsageEntriesTestData[i].key_set_id); + entry_data_length += kUsageEntriesTestData[i].key_set_id.size(); + } else { + entry_data.push_back(kUsageEntriesTestData[i].provider_session_token); + entry_data.push_back(kUsageEntriesTestData[i].app_id); + entry_data_length += + kUsageEntriesTestData[i].provider_session_token.size() + + kUsageEntriesTestData[i].app_id.size(); + } + } + entry_data.push_back(kUsageTableInfoTestData[index].usage_table_header); + entry_data_length += kUsageTableInfoTestData[index].usage_table_header.size(); + + std::string path = device_base_path_ + DeviceFiles::GetUsageTableFileName(); + + EXPECT_CALL(file_system, Exists(StrEq(path))).WillRepeatedly(Return(true)); + EXPECT_CALL(file_system, Open(StrEq(path), _)).WillOnce(Return(&file)); + EXPECT_CALL(file, Write(ContainsAllElementsInVector(entry_data), + Gt(entry_data_length))) + .WillOnce(ReturnArg<1>()); + EXPECT_CALL(file, Read(_, _)).Times(0); + EXPECT_CALL(file, Close()).Times(1); + + DeviceFiles device_files(&file_system); + EXPECT_TRUE(device_files.Init(kSecurityLevelL1)); + ASSERT_TRUE(device_files.StoreUsageTableInfo( + kUsageTableInfoTestData[index].usage_table_header, usage_entry_info)); +} + +TEST_P(DeviceFilesUsageTableTest, Read) { + MockFileSystem file_system; + MockFile file; + int index = GetParam(); + + std::string path = device_base_path_ + DeviceFiles::GetUsageTableFileName(); + + const std::string& file_data = kUsageTableInfoTestData[index].file_data; + EXPECT_CALL(file_system, Exists(StrEq(path))).WillRepeatedly(Return(true)); + EXPECT_CALL(file_system, FileSize(StrEq(path))) + .WillRepeatedly(Return(file_data.size())); + EXPECT_CALL(file_system, Open(StrEq(path), _)).WillOnce(Return(&file)); + EXPECT_CALL(file, Read(NotNull(), Eq(file_data.size()))) + .WillOnce(DoAll(SetArrayArgument<0>(file_data.begin(), file_data.end()), + Return(file_data.size()))); + EXPECT_CALL(file, Close()).Times(1); + + EXPECT_CALL(file, Write(_, _)).Times(0); + + DeviceFiles device_files(&file_system); + EXPECT_TRUE(device_files.Init(kSecurityLevelL1)); + + std::vector usage_entry_info; + std::string usage_table_header; + ASSERT_TRUE(device_files.RetrieveUsageTableInfo(&usage_table_header, + &usage_entry_info)); + EXPECT_EQ(kUsageTableInfoTestData[index].usage_table_header, + usage_table_header); + EXPECT_EQ(index + 1, usage_entry_info.size()); + + for (int i = 0; i <= index; ++i) { + EXPECT_EQ(kUsageEntriesTestData[i].storage_type, + usage_entry_info[i].storage_type); + if (usage_entry_info[i].storage_type == DeviceFiles::kStorageLicense) { + EXPECT_EQ(kUsageEntriesTestData[i].key_set_id, + usage_entry_info[i].key_set_id); + EXPECT_EQ(kEmptyString, usage_entry_info[i].provider_session_token); + EXPECT_EQ(kEmptyString, usage_entry_info[i].app_id); + } else { + EXPECT_EQ(kEmptyString, usage_entry_info[i].key_set_id); + EXPECT_EQ(kUsageEntriesTestData[i].provider_session_token, + usage_entry_info[i].provider_session_token); + EXPECT_EQ(kUsageEntriesTestData[i].app_id, usage_entry_info[i].app_id); + } + } +} + +INSTANTIATE_TEST_CASE_P(UsageInfo, DeviceFilesUsageTableTest, + ::testing::Range(0, 6)); + } // namespace wvcdm