Merge "Revert "Core CDM: Removed ability to add secure stop entry.""

This commit is contained in:
Alex Dale
2022-12-01 23:47:43 +00:00
committed by Android (Google) Code Review
4 changed files with 862 additions and 87 deletions

View File

@@ -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.

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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());