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