Merge "Revert "Core CDM: Removed ability to add secure stop entry.""
This commit is contained in:
@@ -67,9 +67,15 @@ class UsageTableHeader {
|
||||
// the entry with the provided |crypto_session|. The index of the new
|
||||
// usage entry will be returned by |usage_entry_number|.
|
||||
//
|
||||
// Type of entry depends on the value of |persistent_license|:
|
||||
// false - usage info / secure stop record
|
||||
// true - offline license
|
||||
//
|
||||
// Threading: Method takes exclusive use of |usage_table_header_lock_|.
|
||||
virtual CdmResponseType AddEntry(CryptoSession* crypto_session,
|
||||
bool persistent_license,
|
||||
const CdmKeySetId& key_set_id,
|
||||
const std::string& usage_info_filename,
|
||||
const CdmKeyResponse& license_message,
|
||||
uint32_t* usage_entry_number);
|
||||
// Threading: Method takes exclusive use of |usage_table_header_lock_|.
|
||||
@@ -115,6 +121,9 @@ class UsageTableHeader {
|
||||
return potential_table_capacity_ == 0;
|
||||
}
|
||||
|
||||
// Returns the number of entries currently tracked by the CDM that
|
||||
// are related to usage info (streaming licenses).
|
||||
size_t UsageInfoCount() const;
|
||||
// Returns the number of entries currently tracked by the CDM that
|
||||
// are related to offline licenses.
|
||||
size_t OfflineEntryCount() const;
|
||||
@@ -196,12 +205,15 @@ class UsageTableHeader {
|
||||
// unoccupied (released).
|
||||
bool IsEntryUnoccupied(const uint32_t usage_entry_number) const;
|
||||
|
||||
// Populates the entry's meta-data with the required information based
|
||||
// SetOfflineEntryInfo() and SetUsageInfoEntryInfo() populate the
|
||||
// entry meta-data with the required information based on the type
|
||||
// on the license content.
|
||||
// of entry.
|
||||
void SetOfflineEntryInfo(const uint32_t usage_entry_number,
|
||||
const std::string& key_set_id,
|
||||
const CdmKeyResponse& license_message);
|
||||
void SetUsageInfoEntryInfo(const uint32_t usage_entry_number,
|
||||
const std::string& key_set_id,
|
||||
const std::string& usage_info_file_name);
|
||||
|
||||
// Shrinks the table, removing all trailing unoccupied entries.
|
||||
// |usage_entry_info_| will be resized appropriately.
|
||||
|
||||
@@ -484,8 +484,9 @@ CdmResponseType CdmSession::AddKeyInternal(const CdmKeyResponse& key_response) {
|
||||
LOGE("CDM does not support secure stop licenses");
|
||||
return ADD_KEY_ERROR;
|
||||
}
|
||||
sts = usage_table_header_->AddEntry(crypto_session_.get(), key_set_id_,
|
||||
key_response, &usage_entry_number_);
|
||||
sts = usage_table_header_->AddEntry(
|
||||
crypto_session_.get(), /* is_persistent */ true, key_set_id_,
|
||||
/* usage_info_filename */ "", key_response, &usage_entry_number_);
|
||||
crypto_metrics_->usage_table_header_add_entry_.Increment(sts);
|
||||
if (sts != NO_ERROR) return sts;
|
||||
provider_session_token_ = std::move(provider_session_token);
|
||||
|
||||
@@ -96,12 +96,17 @@ bool RetrieveOfflineLicense(DeviceFiles* device_files,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EntryIsUsageInfo(const CdmUsageEntryInfo& info) {
|
||||
// Used for stl filters.
|
||||
return info.storage_type == kStorageUsageInfo;
|
||||
}
|
||||
|
||||
bool EntryIsOfflineLicense(const CdmUsageEntryInfo& info) {
|
||||
// Used for stl filters.
|
||||
return info.storage_type == kStorageLicense;
|
||||
}
|
||||
|
||||
bool IsValidCdmSecurityLevelForUsageTable(CdmSecurityLevel security_level) {
|
||||
bool IsValidCdmSecurityLevelForUsageInfo(CdmSecurityLevel security_level) {
|
||||
return security_level == kSecurityLevelL1 ||
|
||||
security_level == kSecurityLevelL3;
|
||||
}
|
||||
@@ -129,7 +134,7 @@ bool UsageTableHeader::Init(CdmSecurityLevel security_level,
|
||||
CdmSecurityLevelToString(security_level));
|
||||
return false;
|
||||
}
|
||||
if (!IsValidCdmSecurityLevelForUsageTable(security_level)) {
|
||||
if (!IsValidCdmSecurityLevelForUsageInfo(security_level)) {
|
||||
LOGE("Invalid security level provided: security_level = %s",
|
||||
CdmSecurityLevelToString(security_level));
|
||||
return false;
|
||||
@@ -221,9 +226,11 @@ bool UsageTableHeader::CreateNewTable(CryptoSession* const crypto_session) {
|
||||
}
|
||||
|
||||
CdmResponseType UsageTableHeader::AddEntry(
|
||||
CryptoSession* crypto_session, const CdmKeySetId& key_set_id,
|
||||
CryptoSession* crypto_session, bool persistent_license,
|
||||
const CdmKeySetId& key_set_id, const std::string& usage_info_file_name,
|
||||
const CdmKeyResponse& license_message, uint32_t* usage_entry_number) {
|
||||
LOGD("key_set_id = %s, current_size = %zu", IdToString(key_set_id),
|
||||
LOGD("key_set_id = %s, type = %s, current_size = %zu", IdToString(key_set_id),
|
||||
persistent_license ? "OfflineLicense" : "Streaming",
|
||||
usage_entry_info_.size());
|
||||
|
||||
metrics::CryptoMetrics* metrics = crypto_session->GetCryptoMetrics();
|
||||
@@ -244,11 +251,15 @@ CdmResponseType UsageTableHeader::AddEntry(
|
||||
status = RelocateNewEntry(crypto_session, usage_entry_number);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
SetOfflineEntryInfo(*usage_entry_number, key_set_id, license_message);
|
||||
if (persistent_license) {
|
||||
SetOfflineEntryInfo(*usage_entry_number, key_set_id, license_message);
|
||||
} else {
|
||||
SetUsageInfoEntryInfo(*usage_entry_number, key_set_id,
|
||||
usage_info_file_name);
|
||||
}
|
||||
|
||||
status = RefitTable(crypto_session);
|
||||
if (status != NO_ERROR) {
|
||||
// Clear new entry on failure.
|
||||
usage_entry_info_[*usage_entry_number].Clear();
|
||||
return status;
|
||||
}
|
||||
@@ -369,6 +380,12 @@ CdmResponseType UsageTableHeader::InvalidateEntryInternal(
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
size_t UsageTableHeader::UsageInfoCount() const {
|
||||
LOGV("Locking to count usage info (streaming license) entries");
|
||||
return std::count_if(usage_entry_info_.cbegin(), usage_entry_info_.cend(),
|
||||
EntryIsUsageInfo);
|
||||
}
|
||||
|
||||
size_t UsageTableHeader::OfflineEntryCount() const {
|
||||
LOGV("Locking to count offline license entries");
|
||||
return std::count_if(usage_entry_info_.cbegin(), usage_entry_info_.cend(),
|
||||
@@ -424,8 +441,8 @@ bool UsageTableHeader::CapacityCheck(CryptoSession* const crypto_session) {
|
||||
}
|
||||
|
||||
uint32_t temporary_usage_entry_number;
|
||||
status = AddEntry(local_crypto_session, kDummyKeySetId, kEmptyString,
|
||||
&temporary_usage_entry_number);
|
||||
status = AddEntry(local_crypto_session, true, kDummyKeySetId, kEmptyString,
|
||||
kEmptyString, &temporary_usage_entry_number);
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to add entry for capacity test: sts = %d",
|
||||
static_cast<int>(status));
|
||||
@@ -579,6 +596,17 @@ void UsageTableHeader::SetOfflineEntryInfo(
|
||||
}
|
||||
}
|
||||
|
||||
void UsageTableHeader::SetUsageInfoEntryInfo(
|
||||
const uint32_t usage_entry_number, const std::string& key_set_id,
|
||||
const std::string& usage_info_file_name) {
|
||||
CdmUsageEntryInfo& entry_info = usage_entry_info_[usage_entry_number];
|
||||
entry_info.Clear();
|
||||
entry_info.storage_type = kStorageUsageInfo;
|
||||
entry_info.key_set_id = key_set_id;
|
||||
entry_info.last_use_time = GetCurrentTime();
|
||||
entry_info.usage_info_file_name = usage_info_file_name;
|
||||
}
|
||||
|
||||
CdmResponseType UsageTableHeader::RefitTable(
|
||||
CryptoSession* const crypto_session) {
|
||||
// Remove all unoccupied entries at end of the table.
|
||||
@@ -679,39 +707,57 @@ CdmResponseType UsageTableHeader::GetEntry(uint32_t usage_entry_number,
|
||||
usage_entry_number < usage_entry_info_.size()
|
||||
? usage_entry_info_[usage_entry_number].storage_type
|
||||
: kStorageTypeUnknown));
|
||||
if (usage_entry_number >= usage_entry_info_.size()) {
|
||||
LOGE("Entry out of bounds: usage_entry_number = %u, table_size = %zu",
|
||||
usage_entry_number, usage_entry_info_.size());
|
||||
return USAGE_GET_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE;
|
||||
uint32_t entry_number;
|
||||
switch (usage_entry_info_[usage_entry_number].storage_type) {
|
||||
case kStorageLicense: {
|
||||
DeviceFiles::CdmLicenseData license_data;
|
||||
DeviceFiles::ResponseType sub_error_code = DeviceFiles::kNoError;
|
||||
if (!device_files->RetrieveLicense(
|
||||
usage_entry_info_[usage_entry_number].key_set_id, &license_data,
|
||||
&sub_error_code)) {
|
||||
LOGE("Failed to retrieve license: status = %d",
|
||||
static_cast<int>(sub_error_code));
|
||||
return USAGE_GET_ENTRY_RETRIEVE_LICENSE_FAILED;
|
||||
}
|
||||
|
||||
entry_number = license_data.usage_entry_number;
|
||||
*usage_entry = std::move(license_data.usage_entry);
|
||||
break;
|
||||
}
|
||||
case kStorageUsageInfo: {
|
||||
std::string provider_session_token;
|
||||
CdmKeyMessage license_request;
|
||||
CdmKeyResponse license;
|
||||
std::string drm_certificate;
|
||||
CryptoWrappedKey wrapped_private_key;
|
||||
|
||||
if (!device_files->RetrieveUsageInfoByKeySetId(
|
||||
usage_entry_info_[usage_entry_number].usage_info_file_name,
|
||||
usage_entry_info_[usage_entry_number].key_set_id,
|
||||
&provider_session_token, &license_request, &license, usage_entry,
|
||||
&entry_number, &drm_certificate, &wrapped_private_key)) {
|
||||
LOGE("Failed to retrieve usage information");
|
||||
return USAGE_GET_ENTRY_RETRIEVE_USAGE_INFO_FAILED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kStorageTypeUnknown:
|
||||
default:
|
||||
LOGE(
|
||||
"Cannot retrieve usage information with unknown storage type: "
|
||||
"storage_type = %d",
|
||||
static_cast<int>(usage_entry_info_[usage_entry_number].storage_type));
|
||||
return USAGE_GET_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE;
|
||||
}
|
||||
CdmUsageEntryInfo& entry_info = usage_entry_info_[usage_entry_number];
|
||||
if (entry_info.storage_type != kStorageLicense) {
|
||||
LOGE(
|
||||
"Cannot retrieve information not associated without a license: "
|
||||
"usage_entry_number = %u",
|
||||
usage_entry_number);
|
||||
return USAGE_GET_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE;
|
||||
}
|
||||
// Retrieve license.
|
||||
DeviceFiles::CdmLicenseData license_data;
|
||||
DeviceFiles::ResponseType sub_error_code = DeviceFiles::kNoError;
|
||||
if (!device_files->RetrieveLicense(
|
||||
usage_entry_info_[usage_entry_number].key_set_id, &license_data,
|
||||
&sub_error_code)) {
|
||||
LOGE("Failed to retrieve license: status = %d",
|
||||
static_cast<int>(sub_error_code));
|
||||
return USAGE_GET_ENTRY_RETRIEVE_LICENSE_FAILED;
|
||||
}
|
||||
// Validate entry number.
|
||||
if (usage_entry_number != license_data.usage_entry_number) {
|
||||
|
||||
if (usage_entry_number != entry_number) {
|
||||
LOGE(
|
||||
"Usage entry number mismatch: expected_usage_entry_number = %u, "
|
||||
"retrieved_usage_entry_number = %u",
|
||||
usage_entry_number, license_data.usage_entry_number);
|
||||
usage_entry_number, entry_number);
|
||||
return USAGE_ENTRY_NUMBER_MISMATCH;
|
||||
}
|
||||
|
||||
*usage_entry = std::move(license_data.usage_entry);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -723,37 +769,66 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number,
|
||||
usage_entry_number < usage_entry_info_.size()
|
||||
? usage_entry_info_[usage_entry_number].storage_type
|
||||
: kStorageTypeUnknown));
|
||||
if (usage_entry_number >= usage_entry_info_.size()) {
|
||||
LOGE("Entry out of bounds: usage_entry_number = %u, table_size = %zu",
|
||||
usage_entry_number, usage_entry_info_.size());
|
||||
return USAGE_STORE_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE;
|
||||
}
|
||||
CdmUsageEntryInfo& entry_info = usage_entry_info_[usage_entry_number];
|
||||
if (entry_info.storage_type != kStorageLicense) {
|
||||
LOGE(
|
||||
"Cannot store information not associated without a license: "
|
||||
"usage_entry_number = %u",
|
||||
usage_entry_number);
|
||||
return USAGE_STORE_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE;
|
||||
}
|
||||
// Retrieve existing.
|
||||
DeviceFiles::CdmLicenseData license_data;
|
||||
DeviceFiles::ResponseType sub_error_code = DeviceFiles::kNoError;
|
||||
if (!device_files->RetrieveLicense(
|
||||
usage_entry_info_[usage_entry_number].key_set_id, &license_data,
|
||||
&sub_error_code)) {
|
||||
LOGE("Failed to retrieve license: status = %s",
|
||||
DeviceFiles::ResponseTypeToString(sub_error_code));
|
||||
return USAGE_STORE_ENTRY_RETRIEVE_LICENSE_FAILED;
|
||||
}
|
||||
// Update.
|
||||
license_data.usage_entry = usage_entry;
|
||||
license_data.usage_entry_number = usage_entry_number;
|
||||
|
||||
if (!device_files->StoreLicense(license_data, &sub_error_code)) {
|
||||
LOGE("Failed to store license: status = %s",
|
||||
DeviceFiles::ResponseTypeToString(sub_error_code));
|
||||
return USAGE_STORE_LICENSE_FAILED;
|
||||
switch (usage_entry_info_[usage_entry_number].storage_type) {
|
||||
case kStorageLicense: {
|
||||
DeviceFiles::CdmLicenseData license_data;
|
||||
DeviceFiles::ResponseType sub_error_code = DeviceFiles::kNoError;
|
||||
|
||||
if (!device_files->RetrieveLicense(
|
||||
usage_entry_info_[usage_entry_number].key_set_id, &license_data,
|
||||
&sub_error_code)) {
|
||||
LOGE("Failed to retrieve license: status = %s",
|
||||
DeviceFiles::ResponseTypeToString(sub_error_code));
|
||||
return USAGE_STORE_ENTRY_RETRIEVE_LICENSE_FAILED;
|
||||
}
|
||||
|
||||
// Update.
|
||||
license_data.usage_entry = usage_entry;
|
||||
license_data.usage_entry_number = usage_entry_number;
|
||||
|
||||
if (!device_files->StoreLicense(license_data, &sub_error_code)) {
|
||||
LOGE("Failed to store license: status = %s",
|
||||
DeviceFiles::ResponseTypeToString(sub_error_code));
|
||||
return USAGE_STORE_LICENSE_FAILED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kStorageUsageInfo: {
|
||||
CdmUsageEntry entry;
|
||||
uint32_t entry_number;
|
||||
std::string provider_session_token, init_data, key_request, key_response,
|
||||
key_renewal_request;
|
||||
std::string drm_certificate;
|
||||
CryptoWrappedKey wrapped_private_key;
|
||||
if (!device_files->RetrieveUsageInfoByKeySetId(
|
||||
usage_entry_info_[usage_entry_number].usage_info_file_name,
|
||||
usage_entry_info_[usage_entry_number].key_set_id,
|
||||
&provider_session_token, &key_request, &key_response, &entry,
|
||||
&entry_number, &drm_certificate, &wrapped_private_key)) {
|
||||
LOGE("Failed to retrieve usage information");
|
||||
return USAGE_STORE_ENTRY_RETRIEVE_USAGE_INFO_FAILED;
|
||||
}
|
||||
device_files->DeleteUsageInfo(
|
||||
usage_entry_info_[usage_entry_number].usage_info_file_name,
|
||||
provider_session_token);
|
||||
if (!device_files->StoreUsageInfo(
|
||||
provider_session_token, key_request, key_response,
|
||||
usage_entry_info_[usage_entry_number].usage_info_file_name,
|
||||
usage_entry_info_[usage_entry_number].key_set_id, usage_entry,
|
||||
usage_entry_number, drm_certificate, wrapped_private_key)) {
|
||||
LOGE("Failed to store usage information");
|
||||
return USAGE_STORE_USAGE_INFO_FAILED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kStorageTypeUnknown:
|
||||
default:
|
||||
LOGE(
|
||||
"Cannot retrieve usage information with unknown storage type: "
|
||||
"storage_type = %d",
|
||||
static_cast<int>(usage_entry_info_[usage_entry_number].storage_type));
|
||||
return USAGE_STORE_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -403,14 +403,30 @@ class MockDeviceFiles : public DeviceFiles {
|
||||
(const CdmUsageTableHeader&,
|
||||
const std::vector<CdmUsageEntryInfo>&),
|
||||
(override));
|
||||
MOCK_METHOD(bool, DeleteUsageInfo, (const std::string&, const std::string&),
|
||||
(override));
|
||||
MOCK_METHOD(bool, RetrieveUsageInfoByKeySetId,
|
||||
(const std::string&, const std::string&, std::string*,
|
||||
CdmKeyMessage*, CdmKeyResponse*, CdmUsageEntry*, uint32_t*,
|
||||
std::string*, CryptoWrappedKey*),
|
||||
(override));
|
||||
MOCK_METHOD(bool, StoreLicense, (const CdmLicenseData&, ResponseType*),
|
||||
(override));
|
||||
MOCK_METHOD(bool, DeleteLicense, (const std::string&), (override));
|
||||
MOCK_METHOD(bool, DeleteAllLicenses, (), (override));
|
||||
MOCK_METHOD(bool, DeleteAllUsageInfo, (), (override));
|
||||
MOCK_METHOD(bool, DeleteUsageTableInfo, (), (override));
|
||||
MOCK_METHOD(bool, StoreUsageInfo,
|
||||
(const std::string&, const CdmKeyMessage&, const CdmKeyResponse&,
|
||||
const std::string&, const std::string&, const CdmUsageEntry&,
|
||||
uint32_t, const std::string&, const CryptoWrappedKey&),
|
||||
(override));
|
||||
MOCK_METHOD(bool, RetrieveUsageInfo,
|
||||
(const std::string&, std::vector<CdmUsageData>*), (override));
|
||||
MOCK_METHOD(bool, ListLicenses, (std::vector<std::string> * key_set_ids),
|
||||
(override));
|
||||
MOCK_METHOD(bool, ListUsageInfoFiles,
|
||||
(std::vector<std::string> * usage_info_files), (override));
|
||||
|
||||
private:
|
||||
wvutil::FileSystem file_system_;
|
||||
@@ -473,15 +489,18 @@ class MockUsageTableHeader : public UsageTableHeader {
|
||||
(uint32_t, bool, DeviceFiles*, metrics::CryptoMetrics*),
|
||||
(override));
|
||||
MOCK_METHOD(CdmResponseType, AddEntry,
|
||||
(CryptoSession*, const CdmKeySetId&, const CdmKeyResponse&,
|
||||
uint32_t*),
|
||||
(CryptoSession*, bool, const CdmKeySetId&, const std::string&,
|
||||
const CdmKeyResponse&, uint32_t*),
|
||||
(override));
|
||||
|
||||
CdmResponseType SuperAddEntry(CryptoSession* crypto_session,
|
||||
bool persistent_license,
|
||||
const CdmKeySetId& key_set_id,
|
||||
const std::string& usage_info_filename,
|
||||
const CdmKeyResponse& license_message,
|
||||
uint32_t* usage_entry_number) {
|
||||
return UsageTableHeader::AddEntry(crypto_session, key_set_id,
|
||||
return UsageTableHeader::AddEntry(crypto_session, persistent_license,
|
||||
key_set_id, usage_info_filename,
|
||||
license_message, usage_entry_number);
|
||||
}
|
||||
};
|
||||
@@ -1043,7 +1062,10 @@ TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailed_UnknownError) {
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_NE(NO_ERROR,
|
||||
usage_table_header_->AddEntry(
|
||||
crypto_session_, kUsageEntryInfoOfflineLicense1.key_set_id,
|
||||
crypto_session_,
|
||||
kUsageEntryInfoOfflineLicense1.storage_type == kStorageLicense,
|
||||
kUsageEntryInfoOfflineLicense1.key_set_id,
|
||||
kUsageEntryInfoOfflineLicense1.usage_info_file_name,
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
}
|
||||
|
||||
@@ -1058,7 +1080,10 @@ TEST_F(UsageTableHeaderTest, AddEntry_UsageEntryTooSmall) {
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_NE(NO_ERROR,
|
||||
usage_table_header_->AddEntry(
|
||||
crypto_session_, kUsageEntryInfoOfflineLicense1.key_set_id,
|
||||
crypto_session_,
|
||||
kUsageEntryInfoOfflineLicense1.storage_type == kStorageLicense,
|
||||
kUsageEntryInfoOfflineLicense1.key_set_id,
|
||||
kUsageEntryInfoOfflineLicense1.usage_info_file_name,
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
}
|
||||
|
||||
@@ -1117,7 +1142,74 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveOfflineUsageEntry) {
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
usage_table_header_->AddEntry(
|
||||
crypto_session_, kUsageEntryInfoOfflineLicense2.key_set_id,
|
||||
crypto_session_,
|
||||
kUsageEntryInfoOfflineLicense2.storage_type == kStorageLicense,
|
||||
kUsageEntryInfoOfflineLicense2.key_set_id,
|
||||
kUsageEntryInfoOfflineLicense2.usage_info_file_name,
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
EXPECT_EQ(final_usage_entry_number, usage_entry_number);
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Table has a few entries, one of which is unoccupied.
|
||||
// 2. An entry-less session requires a new entry.
|
||||
//
|
||||
// Attempting to add an entry will result in:
|
||||
// a. A successful call to OEMCrypto to create an entry
|
||||
// at the end of the current table
|
||||
// b. Moving the new entry to the unoccupied entry index
|
||||
// c. Shrink table to remove the now empty entry slot created in (a)
|
||||
// d. Storing the new updated usage table
|
||||
//
|
||||
// Storage type Usage entries
|
||||
// at start at end
|
||||
// ============= ======== ======
|
||||
// Offline License 1 0 0
|
||||
// Secure Stop 1 1 1
|
||||
// Storage Type Unknown 2 Replaced
|
||||
// Secure Stop 2 DNE 2
|
||||
//
|
||||
// DNE = Does Not Exist
|
||||
//
|
||||
// # of usage entries 3 3
|
||||
TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveSecureStopUsageEntry) {
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||
const uint32_t initial_usage_entry_number =
|
||||
static_cast<uint32_t>(kUsageEntryInfoVector.size());
|
||||
const uint32_t final_usage_entry_number =
|
||||
static_cast<uint32_t>(kUsageEntryInfoVector.size()) - 1;
|
||||
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
|
||||
kUsageEntryInfoVector;
|
||||
expect_usage_entry_info_vector[final_usage_entry_number] =
|
||||
kUsageEntryInfoSecureStop2;
|
||||
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(initial_usage_entry_number),
|
||||
Return(NO_ERROR)));
|
||||
EXPECT_CALL(*crypto_session_, MoveUsageEntry(final_usage_entry_number))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
ShrinkUsageTableHeader(
|
||||
kLevelDefault,
|
||||
static_cast<uint32_t>(expect_usage_entry_info_vector.size()),
|
||||
NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<2>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kYetAnotherUsageTableHeader),
|
||||
Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
StoreUsageTableInfo(kYetAnotherUsageTableHeader,
|
||||
expect_usage_entry_info_vector))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
usage_table_header_->AddEntry(
|
||||
crypto_session_,
|
||||
kUsageEntryInfoSecureStop2.storage_type == kStorageLicense,
|
||||
kUsageEntryInfoSecureStop2.key_set_id,
|
||||
kUsageEntryInfoSecureStop2.usage_info_file_name,
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
EXPECT_EQ(final_usage_entry_number, usage_entry_number);
|
||||
}
|
||||
@@ -1145,7 +1237,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveOfflineUsageEntry) {
|
||||
// Storage Type Unknown DNE Removed (never stored)
|
||||
// Storage Type Unknown DNE Removed (never stored)
|
||||
// Storage Type Unknown DNE Removed (never stored)
|
||||
// Offline License 2 DNE 2
|
||||
// Secure Stop 2 DNE 2
|
||||
//
|
||||
// DNE = Does Not Exist
|
||||
//
|
||||
@@ -1162,7 +1254,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) {
|
||||
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
|
||||
kUsageEntryInfoVector;
|
||||
expect_usage_entry_info_vector[final_usage_entry_number] =
|
||||
kUsageEntryInfoOfflineLicense2;
|
||||
kUsageEntryInfoSecureStop2;
|
||||
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(initial_usage_entry_number),
|
||||
@@ -1187,7 +1279,10 @@ TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) {
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
usage_table_header_->AddEntry(
|
||||
crypto_session_, kUsageEntryInfoOfflineLicense2.key_set_id,
|
||||
crypto_session_,
|
||||
kUsageEntryInfoSecureStop2.storage_type == kStorageLicense,
|
||||
kUsageEntryInfoSecureStop2.key_set_id,
|
||||
kUsageEntryInfoSecureStop2.usage_info_file_name,
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
EXPECT_EQ(final_usage_entry_number, usage_entry_number);
|
||||
}
|
||||
@@ -1209,7 +1304,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) {
|
||||
// Offline License 1 0 0
|
||||
// Secure Stop 1 1 1
|
||||
// Storage Type Unknown 2 2
|
||||
// Offline License 2 DNE 3
|
||||
// Secure Stop 2 DNE 3
|
||||
//
|
||||
// DNE = Does Not Exist
|
||||
//
|
||||
@@ -1222,7 +1317,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_CannotMoveNewEntry) {
|
||||
static_cast<uint32_t>(kUsageEntryInfoVector.size()) - 1;
|
||||
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
|
||||
kUsageEntryInfoVector;
|
||||
expect_usage_entry_info_vector.push_back(kUsageEntryInfoOfflineLicense2);
|
||||
expect_usage_entry_info_vector.push_back(kUsageEntryInfoSecureStop2);
|
||||
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.WillOnce(
|
||||
@@ -1240,7 +1335,10 @@ TEST_F(UsageTableHeaderTest, AddEntry_CannotMoveNewEntry) {
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
usage_table_header_->AddEntry(
|
||||
crypto_session_, kUsageEntryInfoOfflineLicense2.key_set_id,
|
||||
crypto_session_,
|
||||
kUsageEntryInfoSecureStop2.storage_type == kStorageLicense,
|
||||
kUsageEntryInfoSecureStop2.key_set_id,
|
||||
kUsageEntryInfoSecureStop2.usage_info_file_name,
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
EXPECT_EQ(final_usage_entry_number, usage_entry_number);
|
||||
}
|
||||
@@ -1262,7 +1360,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_CannotMoveNewEntry) {
|
||||
// Offline License 1 0 0
|
||||
// Secure Stop 1 1 1
|
||||
// Storage Type Unknown 2 Replaced
|
||||
// Offline License 2 DNE 2
|
||||
// Secure Stop 2 DNE 2
|
||||
// Storage Type Unknown DNE 3 (created when new entry moved)
|
||||
//
|
||||
// DNE = Does Not Exist
|
||||
@@ -1277,7 +1375,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_CannotShinkAfterMove) {
|
||||
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
|
||||
kUsageEntryInfoVector;
|
||||
expect_usage_entry_info_vector[final_usage_entry_number] =
|
||||
kUsageEntryInfoOfflineLicense2;
|
||||
kUsageEntryInfoSecureStop2;
|
||||
expect_usage_entry_info_vector.push_back(kUsageEntryInfoStorageTypeUnknown);
|
||||
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
@@ -1303,7 +1401,10 @@ TEST_F(UsageTableHeaderTest, AddEntry_CannotShinkAfterMove) {
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
usage_table_header_->AddEntry(
|
||||
crypto_session_, kUsageEntryInfoOfflineLicense2.key_set_id,
|
||||
crypto_session_,
|
||||
kUsageEntryInfoSecureStop2.storage_type == kStorageLicense,
|
||||
kUsageEntryInfoSecureStop2.key_set_id,
|
||||
kUsageEntryInfoSecureStop2.usage_info_file_name,
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
EXPECT_EQ(final_usage_entry_number, usage_entry_number);
|
||||
}
|
||||
@@ -1357,7 +1458,10 @@ TEST_F(UsageTableHeaderTest,
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
mock_usage_table_header->SuperAddEntry(
|
||||
crypto_session_, kUsageEntryInfoOfflineLicense6.key_set_id,
|
||||
crypto_session_,
|
||||
kUsageEntryInfoOfflineLicense6.storage_type == kStorageLicense,
|
||||
kUsageEntryInfoOfflineLicense6.key_set_id,
|
||||
kUsageEntryInfoOfflineLicense6.usage_info_file_name,
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
|
||||
// Verify added/deleted usage entry number and entries
|
||||
@@ -1396,7 +1500,9 @@ TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailsEveryTime) {
|
||||
uint32_t usage_entry_number;
|
||||
EXPECT_EQ(INSUFFICIENT_CRYPTO_RESOURCES,
|
||||
mock_usage_table_header->SuperAddEntry(
|
||||
crypto_session_, kUsageEntryInfoOfflineLicense6.key_set_id,
|
||||
crypto_session_, true /* persistent */,
|
||||
kUsageEntryInfoOfflineLicense6.key_set_id,
|
||||
kUsageEntryInfoOfflineLicense6.usage_info_file_name,
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
|
||||
// Verify the number of entries deleted.
|
||||
@@ -1710,6 +1816,76 @@ TEST_F(UsageTableHeaderTest,
|
||||
EXPECT_EQ(expected_size, usage_table_header_->usage_entry_info().size());
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Last few entries are secure stops, but have entries
|
||||
// missing from usage info file in persistent storage.
|
||||
// 2. Usage entry to be deleted precedes those in (1).
|
||||
//
|
||||
// Attempting to delete the entry in (2) will result in:
|
||||
// a. The entry will be marked as kStorageTypeUnknown.
|
||||
// b. While defragging, the last two entries will be selected to
|
||||
// move.
|
||||
// c. Getting the usage entry for the selected entries will fail and
|
||||
// result in them being set as kStorageTypeUnknown.
|
||||
// d. No entries will be moved due to (c).
|
||||
// e. Usage table will be resized to have only one entry.
|
||||
// f. Updated table will be saved.
|
||||
// g. InvalidateEntry() will return NO_ERROR.
|
||||
//
|
||||
// Storage type Usage entries
|
||||
// at start at end
|
||||
// ============= ======== ======
|
||||
// Offline License 1 0 0
|
||||
// Storage Type Unknown 1 Deleted
|
||||
// Secure stop 1 2 Deleted
|
||||
// Secure stop 2 3 Deleted (because missing)
|
||||
// Secure stop 3 4 Deleted (because missing)
|
||||
//
|
||||
// # of usage entries 5 1
|
||||
TEST_F(UsageTableHeaderTest, InvalidateEntry_LastSecureStopEntriesAreMissing) {
|
||||
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
|
||||
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown,
|
||||
kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2,
|
||||
kUsageEntryInfoSecureStop3};
|
||||
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
|
||||
const uint32_t usage_entry_number_to_be_deleted =
|
||||
2; // kUsageEntryInfoSecureStop1
|
||||
metrics::CryptoMetrics metrics;
|
||||
|
||||
// Streaming license 2 and 3 cannot be retrieved.
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageInfoByKeySetId(
|
||||
kUsageEntryInfoSecureStop2.usage_info_file_name,
|
||||
kUsageEntryInfoSecureStop2.key_set_id, NotNull(), NotNull(),
|
||||
NotNull(), NotNull(), NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(Return(false));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageInfoByKeySetId(
|
||||
kUsageEntryInfoSecureStop3.usage_info_file_name,
|
||||
kUsageEntryInfoSecureStop3.key_set_id, NotNull(), NotNull(),
|
||||
NotNull(), NotNull(), NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(Return(false));
|
||||
|
||||
// Shrink to contain only the one valid entry.
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
ShrinkUsageTableHeader(kLevelDefault, 1, NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<2>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(*device_files_,
|
||||
StoreUsageTableInfo(kAnotherUsageTableHeader,
|
||||
ElementsAre(kUsageEntryInfoOfflineLicense1)))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_EQ(NO_ERROR, usage_table_header_->InvalidateEntry(
|
||||
usage_entry_number_to_be_deleted, true, device_files_,
|
||||
&metrics));
|
||||
// Check the end state of the usage table.
|
||||
constexpr size_t expected_size = 1;
|
||||
EXPECT_EQ(expected_size, usage_table_header_->usage_entry_info().size());
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Last few entries are offline licenses, but have incorrect usage
|
||||
// entry number stored in persistent file store.
|
||||
@@ -1811,6 +1987,89 @@ TEST_F(UsageTableHeaderTest,
|
||||
EXPECT_EQ(expected_size, usage_table_header_->usage_entry_info().size());
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Last few entries are secure stops, but have incorrect usage
|
||||
// entry number stored in persistent file store.
|
||||
// 2. Usage entry to be deleted precedes those in (1).
|
||||
//
|
||||
// Attempting to delete the entry in (2) will result in:
|
||||
// a. The entry will be marked as kStorageTypeUnknown.
|
||||
// b. While defragging, the last two entries will be selected to
|
||||
// move.
|
||||
// c. Getting the usage entry for the selected entries will fail due
|
||||
// to a mismatch in usage entry number and result in them being set
|
||||
// as kStorageTypeUnknown.
|
||||
// d. No entries will be moved due to (c).
|
||||
// e. Usage table will be resized to have only one entry.
|
||||
// f. Updated table will be saved.
|
||||
// g. InvalidateEntry() will return NO_ERROR.
|
||||
//
|
||||
// Storage type Usage entries
|
||||
// at start at end
|
||||
// ============= ======== ======
|
||||
// Offline License 1 0 0
|
||||
// Storage Type Unknown 1 Deleted
|
||||
// Secure stop 1 2 Deleted
|
||||
// Secure stop 2 3 Deleted (because incorrect #)
|
||||
// Secure stop 3 4 Deleted (because incorrect #)
|
||||
//
|
||||
// # of usage entries 5 1
|
||||
TEST_F(UsageTableHeaderTest,
|
||||
InvalidateEntry_LastSecureStopEntriesHaveIncorrectUsageEntryNumber) {
|
||||
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
|
||||
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown,
|
||||
kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2,
|
||||
kUsageEntryInfoSecureStop3};
|
||||
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
|
||||
const uint32_t usage_entry_number_to_be_deleted =
|
||||
2; // kUsageEntryInfoSecureStop1
|
||||
metrics::CryptoMetrics metrics;
|
||||
|
||||
// Set streaming license file data with mismatched usage entry numbers.
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageInfoByKeySetId(
|
||||
kUsageEntryInfoSecureStop2.usage_info_file_name,
|
||||
kUsageEntryInfoSecureStop2.key_set_id, NotNull(), NotNull(),
|
||||
NotNull(), NotNull(), NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(
|
||||
SetArgPointee<2>(kProviderSessionToken),
|
||||
SetArgPointee<3>(kKeyRequest), SetArgPointee<4>(kKeyResponse),
|
||||
SetArgPointee<5>(kUsageEntry), SetArgPointee<6>(2) /* Mismatch */,
|
||||
SetArgPointee<7>(kDrmCertificate),
|
||||
SetArgPointee<8>(kCryptoWrappedKey), Return(true)));
|
||||
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageInfoByKeySetId(
|
||||
kUsageEntryInfoSecureStop3.usage_info_file_name,
|
||||
kUsageEntryInfoSecureStop3.key_set_id, NotNull(), NotNull(),
|
||||
NotNull(), NotNull(), NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(
|
||||
SetArgPointee<2>(kProviderSessionToken),
|
||||
SetArgPointee<3>(kKeyRequest), SetArgPointee<4>(kKeyResponse),
|
||||
SetArgPointee<5>(kUsageEntry), SetArgPointee<6>(3) /* Mismatch */,
|
||||
SetArgPointee<7>(kDrmCertificate),
|
||||
SetArgPointee<8>(kCryptoWrappedKey), Return(true)));
|
||||
|
||||
// Shrink to contain only the one valid entry.
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
ShrinkUsageTableHeader(kLevelDefault, 1, NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<2>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(*device_files_,
|
||||
StoreUsageTableInfo(kAnotherUsageTableHeader,
|
||||
ElementsAre(kUsageEntryInfoOfflineLicense1)))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_EQ(NO_ERROR, usage_table_header_->InvalidateEntry(
|
||||
usage_entry_number_to_be_deleted, true, device_files_,
|
||||
&metrics));
|
||||
// Check the end state of the usage table.
|
||||
constexpr size_t expected_size = 1;
|
||||
EXPECT_EQ(expected_size, usage_table_header_->usage_entry_info().size());
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Last few entries are of storage type unknown.
|
||||
// 2. Usage entry to be deleted precedes those in (1).
|
||||
@@ -1999,6 +2258,83 @@ TEST_F(UsageTableHeaderTest,
|
||||
EXPECT_EQ(expected_size, usage_table_header_->usage_entry_info().size());
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Usage entry to be deleted is not last.
|
||||
// 2. Last entry is an secure stop and calling
|
||||
// OEMCrypto_MoveUsageEntry on it will fail.
|
||||
//
|
||||
// Attempting to delete the entry in (1) will result in:
|
||||
// a. The entry will be marked as kStorageTypeUnknown.
|
||||
// b. While defragging, secure stop 3 will be selected to be moved.
|
||||
// c. The selected entry will have the usage entry loaded from device
|
||||
// files.
|
||||
// d. The move process will fail due to the entry being busy, leaving
|
||||
// the entry inplace.
|
||||
// e. Usage table will not be resized.
|
||||
// f. Updated table will be saved.
|
||||
// g. InvalidateEntry() will return NO_ERROR.
|
||||
//
|
||||
// Storage type Usage entries
|
||||
// at start at end
|
||||
// ============= ======== ======
|
||||
// Offline License 1 0 0
|
||||
// Offline License 2 1 1
|
||||
// Secure Stop 1 2 2 (storage type unknown)
|
||||
// Secure Stop 2 3 3
|
||||
// Secure Stop 3 4 4
|
||||
//
|
||||
// # of usage entries 5 5
|
||||
TEST_F(UsageTableHeaderTest,
|
||||
InvalidateEntry_LastEntryIsSecureStop_MoveSecureStopEntryFailed) {
|
||||
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
|
||||
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoOfflineLicense2,
|
||||
kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2,
|
||||
kUsageEntryInfoSecureStop3};
|
||||
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
|
||||
const uint32_t usage_entry_number_to_be_deleted =
|
||||
2; // kUsageEntryInfoSecureStop1
|
||||
metrics::CryptoMetrics metrics;
|
||||
|
||||
// Expect calls for moving secure stop 3 (position 4), but
|
||||
// failure to move will not result in any calls for updating.
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageInfoByKeySetId(
|
||||
kUsageEntryInfoSecureStop3.usage_info_file_name,
|
||||
kUsageEntryInfoSecureStop3.key_set_id, NotNull(), NotNull(),
|
||||
NotNull(), NotNull(), NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(kProviderSessionToken),
|
||||
SetArgPointee<3>(kKeyRequest),
|
||||
SetArgPointee<4>(kKeyResponse),
|
||||
SetArgPointee<5>(kUsageEntry), SetArgPointee<6>(4),
|
||||
SetArgPointee<7>(kDrmCertificate),
|
||||
SetArgPointee<8>(kCryptoWrappedKey), Return(true)));
|
||||
|
||||
// Calls during Move().
|
||||
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(*crypto_session_, LoadUsageEntry(4, kUsageEntry))
|
||||
.WillOnce(Return(LOAD_USAGE_ENTRY_INVALID_SESSION));
|
||||
|
||||
// No calls to shrink are expected.
|
||||
|
||||
// Regardless, the usage table should be updated to reflect the changes
|
||||
// to the usage entry marked as storage type unknown.
|
||||
EXPECT_CALL(*device_files_,
|
||||
StoreUsageTableInfo(kUsageTableHeader,
|
||||
ElementsAre(kUsageEntryInfoOfflineLicense1,
|
||||
kUsageEntryInfoOfflineLicense2,
|
||||
kUsageEntryInfoStorageTypeUnknown,
|
||||
kUsageEntryInfoSecureStop2,
|
||||
kUsageEntryInfoSecureStop3)))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_EQ(NO_ERROR, usage_table_header_->InvalidateEntry(
|
||||
usage_entry_number_to_be_deleted, true, device_files_,
|
||||
&metrics));
|
||||
constexpr size_t expected_size = 5;
|
||||
EXPECT_EQ(expected_size, usage_table_header_->usage_entry_info().size());
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Usage entry to be deleted is not last (Offline license 1)
|
||||
// 2. Last few entries are of storage type unknown.
|
||||
@@ -2124,6 +2460,112 @@ TEST_F(UsageTableHeaderTest,
|
||||
EXPECT_EQ(expected_size, usage_table_header_->usage_entry_info().size());
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Usage entry to be deleted is not last (Secure stop 1)
|
||||
// 2. Last few entries are of storage type unknown.
|
||||
// 3. Entry that precedes those in (2) are secure stops and calling
|
||||
// OEMCrypto_LoadUsageEntry on it will fail.
|
||||
//
|
||||
// Attempting to delete the entry in (1) will result in:
|
||||
// a. The entry will be marked as kStorageTypeUnknown.
|
||||
// b. While defragging, secure stop 2 and 3 will be selected to be
|
||||
// moved.
|
||||
// c. The selected entry will have the usage entry loaded from device
|
||||
// files.
|
||||
// d. The move processes will fail due to the entries being busy, leaving
|
||||
// the entries inplace.
|
||||
// e. Usage table will be resized to remove the last two entries.
|
||||
// f. Updated table will be saved.
|
||||
// g. InvalidateEntry() will return NO_ERROR.
|
||||
//
|
||||
// Storage type Usage entries
|
||||
// at start at end
|
||||
// ============= ======== ======
|
||||
// Offline License 1 0 0
|
||||
// Storage Type unknown 1 1
|
||||
// Secure stop 1 2 2 (storage type unknown)
|
||||
// Secure stop 2 3 3
|
||||
// Secure stop 3 4 4
|
||||
// Storage Type unknown 5 Deleted
|
||||
// Storage Type unknown 6 Deleted
|
||||
//
|
||||
// # of usage entries 7 5
|
||||
TEST_F(
|
||||
UsageTableHeaderTest,
|
||||
InvalidateEntry_LastEntriesAreSecureStopAndUnknown_MoveOfflineEntryFailed) {
|
||||
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
|
||||
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown,
|
||||
kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2,
|
||||
kUsageEntryInfoSecureStop3, kUsageEntryInfoStorageTypeUnknown,
|
||||
kUsageEntryInfoStorageTypeUnknown};
|
||||
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
|
||||
const uint32_t usage_entry_number_to_be_deleted =
|
||||
2; // kUsageEntryInfoSecureStop1
|
||||
metrics::CryptoMetrics metrics;
|
||||
|
||||
EXPECT_CALL(*crypto_session_, Open(kLevelDefault))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(NO_ERROR));
|
||||
|
||||
// Expect calls for moving streaming license 3 (position 4), but
|
||||
// failure to move will not result in any calls for updating.
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageInfoByKeySetId(
|
||||
kUsageEntryInfoSecureStop3.usage_info_file_name,
|
||||
kUsageEntryInfoSecureStop3.key_set_id, NotNull(), NotNull(),
|
||||
NotNull(), NotNull(), NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(kProviderSessionToken),
|
||||
SetArgPointee<3>(kKeyRequest),
|
||||
SetArgPointee<4>(kKeyResponse),
|
||||
SetArgPointee<5>(kUsageEntry), SetArgPointee<6>(4),
|
||||
SetArgPointee<7>(kDrmCertificate),
|
||||
SetArgPointee<8>(kCryptoWrappedKey), Return(true)));
|
||||
EXPECT_CALL(*crypto_session_, LoadUsageEntry(4, kUsageEntry))
|
||||
.WillOnce(Return(LOAD_USAGE_ENTRY_INVALID_SESSION));
|
||||
|
||||
// Expect calls for moving streaming license 2 (position 3), but
|
||||
// failure to move will not result in any calls for updating.
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageInfoByKeySetId(
|
||||
kUsageEntryInfoSecureStop2.usage_info_file_name,
|
||||
kUsageEntryInfoSecureStop2.key_set_id, NotNull(), NotNull(),
|
||||
NotNull(), NotNull(), NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(kProviderSessionToken),
|
||||
SetArgPointee<3>(kKeyRequest),
|
||||
SetArgPointee<4>(kKeyResponse),
|
||||
SetArgPointee<5>(kUsageEntry), SetArgPointee<6>(3),
|
||||
SetArgPointee<7>(kDrmCertificate),
|
||||
SetArgPointee<8>(kCryptoWrappedKey), Return(true)));
|
||||
EXPECT_CALL(*crypto_session_, LoadUsageEntry(3, kUsageEntry))
|
||||
.WillOnce(Return(LOAD_USAGE_ENTRY_INVALID_SESSION));
|
||||
|
||||
// Expect a call to shrink table to cut off only the unknown entries
|
||||
// at the end of the table.
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
ShrinkUsageTableHeader(kLevelDefault, 5, NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<2>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
|
||||
// Update table for the entry now marked storage type unknown and
|
||||
// the entries that were cut off.
|
||||
EXPECT_CALL(*device_files_,
|
||||
StoreUsageTableInfo(kAnotherUsageTableHeader,
|
||||
ElementsAre(kUsageEntryInfoOfflineLicense1,
|
||||
kUsageEntryInfoStorageTypeUnknown,
|
||||
kUsageEntryInfoStorageTypeUnknown,
|
||||
kUsageEntryInfoSecureStop2,
|
||||
kUsageEntryInfoSecureStop3)))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_EQ(NO_ERROR, usage_table_header_->InvalidateEntry(
|
||||
usage_entry_number_to_be_deleted, true, device_files_,
|
||||
&metrics));
|
||||
// Check the end state of the usage table.
|
||||
constexpr size_t expected_size = 5;
|
||||
EXPECT_EQ(expected_size, usage_table_header_->usage_entry_info().size());
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Usage entry to be deleted is not last.
|
||||
// 2. Last entries are valid offline licenses.
|
||||
@@ -2250,6 +2692,125 @@ TEST_F(UsageTableHeaderTest, InvalidateEntry_LastEntryIsOffline) {
|
||||
EXPECT_EQ(expected_size, usage_table_header_->usage_entry_info().size());
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Usage entry to be deleted is not last.
|
||||
// 2. Last entries are valid streaming licenses.
|
||||
//
|
||||
// Attempting to delete the entry in (1) will result in:
|
||||
// a. The entry will be marked as kStorageTypeUnknown.
|
||||
// b. While defragging, secure stop 2 and 3 will be selected to be
|
||||
// moved.
|
||||
// c. The selected entries will be moved.
|
||||
// d. Usage table will be resized.
|
||||
// e. Updated table will be saved.
|
||||
// f. InvalidateEntry() will return NO_ERROR.
|
||||
//
|
||||
// Storage type Usage entries
|
||||
// at start at end
|
||||
// ============= ======== ======
|
||||
// Offline License 1 0 0
|
||||
// Storage Type unknown 1 Deleted
|
||||
// Secure stop 1 2 Deleted
|
||||
// Secure stop 2 3 2 (moved)
|
||||
// Secure stop 3 4 1 (moved)
|
||||
//
|
||||
// # of usage entries 5 3
|
||||
TEST_F(UsageTableHeaderTest, InvalidateEntry_LastEntryIsSecureStop) {
|
||||
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
|
||||
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown,
|
||||
kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2,
|
||||
kUsageEntryInfoSecureStop3};
|
||||
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
|
||||
const uint32_t usage_entry_number_to_be_deleted =
|
||||
2; // kUsageEntryInfoSecureStop1
|
||||
metrics::CryptoMetrics metrics;
|
||||
|
||||
// Expect calls for moving streaming license 3 (position 4) to position 1.
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageInfoByKeySetId(
|
||||
kUsageEntryInfoSecureStop3.usage_info_file_name,
|
||||
kUsageEntryInfoSecureStop3.key_set_id, NotNull(), NotNull(),
|
||||
NotNull(), NotNull(), NotNull(), NotNull(), NotNull()))
|
||||
.Times(2) // First to get entry, second to update.
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(kProviderSessionToken),
|
||||
SetArgPointee<3>(kKeyRequest),
|
||||
SetArgPointee<4>(kKeyResponse),
|
||||
SetArgPointee<5>(kUsageEntry), SetArgPointee<6>(4),
|
||||
SetArgPointee<7>(kDrmCertificate),
|
||||
SetArgPointee<8>(kCryptoWrappedKey), Return(true)));
|
||||
EXPECT_CALL(
|
||||
*device_files_,
|
||||
DeleteUsageInfo(kUsageEntryInfoSecureStop3.usage_info_file_name, _))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(
|
||||
*device_files_,
|
||||
StoreUsageInfo(_, _, _, kUsageEntryInfoSecureStop3.usage_info_file_name,
|
||||
kUsageEntryInfoSecureStop3.key_set_id, _, 1, _, _))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(*crypto_session_, LoadUsageEntry(4, kUsageEntry))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(*crypto_session_, MoveUsageEntry(1));
|
||||
|
||||
// Expect calls for moving streaming license 2 (position 3) to position 2.
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageInfoByKeySetId(
|
||||
kUsageEntryInfoSecureStop2.usage_info_file_name,
|
||||
kUsageEntryInfoSecureStop2.key_set_id, NotNull(), NotNull(),
|
||||
NotNull(), NotNull(), NotNull(), NotNull(), NotNull()))
|
||||
.Times(2) // First to get entry, second to update.
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(kProviderSessionToken),
|
||||
SetArgPointee<3>(kKeyRequest),
|
||||
SetArgPointee<4>(kKeyResponse),
|
||||
SetArgPointee<5>(kUsageEntry), SetArgPointee<6>(3),
|
||||
SetArgPointee<7>(kDrmCertificate),
|
||||
SetArgPointee<8>(kCryptoWrappedKey), Return(true)));
|
||||
EXPECT_CALL(
|
||||
*device_files_,
|
||||
DeleteUsageInfo(kUsageEntryInfoSecureStop2.usage_info_file_name, _))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(
|
||||
*device_files_,
|
||||
StoreUsageInfo(_, _, _, kUsageEntryInfoSecureStop2.usage_info_file_name,
|
||||
kUsageEntryInfoSecureStop2.key_set_id, _, 2, _, _))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(*crypto_session_, LoadUsageEntry(3, kUsageEntry))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(*crypto_session_, MoveUsageEntry(2));
|
||||
|
||||
// Common to both moves.
|
||||
EXPECT_CALL(*crypto_session_, Open(kLevelDefault))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(NO_ERROR));
|
||||
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
|
||||
.Times(2)
|
||||
.WillRepeatedly(DoAll(SetArgPointee<0>(kAnotherUsageTableHeader),
|
||||
SetArgPointee<1>(kAnotherUsageEntry),
|
||||
Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader, _))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
// Shrink to contain the remaining valid entry.
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
ShrinkUsageTableHeader(kLevelDefault, 3, NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<2>(kYetAnotherUsageEntry), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
StoreUsageTableInfo(kYetAnotherUsageEntry,
|
||||
ElementsAre(kUsageEntryInfoOfflineLicense1,
|
||||
kUsageEntryInfoSecureStop3,
|
||||
kUsageEntryInfoSecureStop2)))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_EQ(NO_ERROR, usage_table_header_->InvalidateEntry(
|
||||
usage_entry_number_to_be_deleted, true, device_files_,
|
||||
&metrics));
|
||||
// Check the end state of the usage table.
|
||||
constexpr size_t expected_size = 3;
|
||||
EXPECT_EQ(expected_size, usage_table_header_->usage_entry_info().size());
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Usage entry to be deleted is not last.
|
||||
// 2. Last few entries are of storage type unknown.
|
||||
@@ -2381,6 +2942,130 @@ TEST_F(UsageTableHeaderTest,
|
||||
EXPECT_EQ(expected_size, usage_table_header_->usage_entry_info().size());
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Usage entry to be deleted is not last (Secure stop 1)
|
||||
// 2. Last few entries are of storage type unknown.
|
||||
//
|
||||
// Attempting to delete the entry in (1) will result in:
|
||||
// a. The entry will be marked as kStorageTypeUnknown.
|
||||
// b. While defragging, secure stop 2 and 3 will be selected to be
|
||||
// moved.
|
||||
// c. The selected entries will be moved.
|
||||
// d. Usage table will be resized.
|
||||
// e. Updated table will be saved.
|
||||
// f. InvalidateEntry() will return NO_ERROR.
|
||||
//
|
||||
// Storage type Usage entries
|
||||
// at start at end
|
||||
// ============= ======== ======
|
||||
// Offline License 1 0 0
|
||||
// Storage Type unknown 1 Deleted
|
||||
// Secure stop 1 2 Deleted
|
||||
// Secure stop 2 3 2 (Moved)
|
||||
// Secure stop 3 4 1 (Moved)
|
||||
// Storage Type unknown 5 Deleted
|
||||
// Storage Type unknown 6 Deleted
|
||||
//
|
||||
// # of usage entries 7 3
|
||||
TEST_F(UsageTableHeaderTest,
|
||||
InvalidateEntry_LastEntriesAreSecureStopAndUnknknown) {
|
||||
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
|
||||
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown,
|
||||
kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2,
|
||||
kUsageEntryInfoSecureStop3, kUsageEntryInfoStorageTypeUnknown,
|
||||
kUsageEntryInfoStorageTypeUnknown};
|
||||
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
|
||||
const uint32_t usage_entry_number_to_be_deleted =
|
||||
2; // kUsageEntryInfoSecureStop1
|
||||
metrics::CryptoMetrics metrics;
|
||||
|
||||
// Expect calls for moving streaming license 3 (position 4) to position 1.
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageInfoByKeySetId(
|
||||
kUsageEntryInfoSecureStop3.usage_info_file_name,
|
||||
kUsageEntryInfoSecureStop3.key_set_id, NotNull(), NotNull(),
|
||||
NotNull(), NotNull(), NotNull(), NotNull(), NotNull()))
|
||||
.Times(2) // First to get entry, second to update.
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(kProviderSessionToken),
|
||||
SetArgPointee<3>(kKeyRequest),
|
||||
SetArgPointee<4>(kKeyResponse),
|
||||
SetArgPointee<5>(kUsageEntry), SetArgPointee<6>(4),
|
||||
SetArgPointee<7>(kDrmCertificate),
|
||||
SetArgPointee<8>(kCryptoWrappedKey), Return(true)));
|
||||
EXPECT_CALL(
|
||||
*device_files_,
|
||||
DeleteUsageInfo(kUsageEntryInfoSecureStop3.usage_info_file_name, _))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(
|
||||
*device_files_,
|
||||
StoreUsageInfo(_, _, _, kUsageEntryInfoSecureStop3.usage_info_file_name,
|
||||
kUsageEntryInfoSecureStop3.key_set_id, _, 1, _, _))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(*crypto_session_, LoadUsageEntry(4, kUsageEntry))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(*crypto_session_, MoveUsageEntry(1));
|
||||
|
||||
// Expect calls for moving streaming license 2 (position 3) to position 2.
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageInfoByKeySetId(
|
||||
kUsageEntryInfoSecureStop2.usage_info_file_name,
|
||||
kUsageEntryInfoSecureStop2.key_set_id, NotNull(), NotNull(),
|
||||
NotNull(), NotNull(), NotNull(), NotNull(), NotNull()))
|
||||
.Times(2) // First to get entry, second to update.
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(kProviderSessionToken),
|
||||
SetArgPointee<3>(kKeyRequest),
|
||||
SetArgPointee<4>(kKeyResponse),
|
||||
SetArgPointee<5>(kUsageEntry), SetArgPointee<6>(3),
|
||||
SetArgPointee<7>(kDrmCertificate),
|
||||
SetArgPointee<8>(kCryptoWrappedKey), Return(true)));
|
||||
EXPECT_CALL(
|
||||
*device_files_,
|
||||
DeleteUsageInfo(kUsageEntryInfoSecureStop2.usage_info_file_name, _))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(
|
||||
*device_files_,
|
||||
StoreUsageInfo(_, _, _, kUsageEntryInfoSecureStop2.usage_info_file_name,
|
||||
kUsageEntryInfoSecureStop2.key_set_id, _, 2, _, _))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(*crypto_session_, LoadUsageEntry(3, kUsageEntry))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(*crypto_session_, MoveUsageEntry(2));
|
||||
|
||||
// Common to both moves.
|
||||
EXPECT_CALL(*crypto_session_, Open(kLevelDefault))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(NO_ERROR));
|
||||
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
|
||||
.Times(2)
|
||||
.WillRepeatedly(DoAll(SetArgPointee<0>(kAnotherUsageTableHeader),
|
||||
SetArgPointee<1>(kAnotherUsageEntry),
|
||||
Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader, _))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
// Shrink to contain the remaining valid entry.
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
ShrinkUsageTableHeader(kLevelDefault, 3, NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<2>(kYetAnotherUsageEntry), Return(NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(*device_files_,
|
||||
StoreUsageTableInfo(kYetAnotherUsageEntry,
|
||||
ElementsAre(kUsageEntryInfoOfflineLicense1,
|
||||
kUsageEntryInfoSecureStop3,
|
||||
kUsageEntryInfoSecureStop2)))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_EQ(NO_ERROR, usage_table_header_->InvalidateEntry(
|
||||
usage_entry_number_to_be_deleted, true, device_files_,
|
||||
&metrics));
|
||||
// Check the end state of the usage table.
|
||||
constexpr size_t expected_size = 3;
|
||||
EXPECT_EQ(expected_size, usage_table_header_->usage_entry_info().size());
|
||||
}
|
||||
|
||||
// Initial Test state:
|
||||
// 1. Usage entry to be deleted is not last (Secure stop 1)
|
||||
// 2. All other entries are invalid.
|
||||
@@ -3268,8 +3953,10 @@ TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateLicenseEntry) {
|
||||
// The Call.
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_EQ(NO_ERROR, usage_table_header_->AddEntry(
|
||||
crypto_session_, expected_new_entry.key_set_id,
|
||||
kEmptyString, &usage_entry_number));
|
||||
crypto_session_, true /* persistent_license */,
|
||||
expected_new_entry.key_set_id,
|
||||
/* usage_info_file_name */ kEmptyString, kEmptyString,
|
||||
&usage_entry_number));
|
||||
|
||||
EXPECT_EQ(expected_usage_entry_number, usage_entry_number);
|
||||
EXPECT_EQ(expected_usage_info_list, usage_table_header_->usage_entry_info());
|
||||
|
||||
Reference in New Issue
Block a user