Merge "Revert "Core CDM: Remove secure stop from LRU algorithm.""

This commit is contained in:
Alex Dale
2022-12-02 22:41:06 +00:00
committed by Android (Google) Code Review
3 changed files with 427 additions and 202 deletions

View File

@@ -229,9 +229,9 @@ const CdmKeyResponse kKeyRenewalResponse = "key renewal response";
const std::string kReleaseServerUrl = "some url";
const std::string kProviderSessionToken = "provider session token";
const CdmAppParameterMap kEmptyAppParameters;
constexpr int64_t kPlaybackStartTime = 1030005;
constexpr int64_t kPlaybackDuration = 300;
constexpr int64_t kGracePeriodEndTime = 60;
int64_t kPlaybackStartTime = 1030005;
int64_t kPlaybackDuration = 300;
int64_t kGracePeriodEndTime = 60;
// ==== LRU Upgrade Data ====
const CdmUsageTableHeader kUpgradableUsageTableHeader =
@@ -245,9 +245,9 @@ const CdmUsageEntryInfo kUpgradableUsageEntryInfo1 = {
/* last_use_time = */ 0,
/* offline_license_expiry_time = */ 0};
const CdmUsageEntryInfo kUpgradableUsageEntryInfo2 = {
/* storage_type = */ kStorageLicense,
/* key_set_id = */ "offline_key_set_2",
/* usage_info_file_name = */ "",
/* storage_type = */ kStorageUsageInfo,
/* key_set_id = */ "streaming_key_set_2",
/* usage_info_file_name = */ "streaming_license_file_2",
/* last_use_time = */ 0,
/* offline_license_expiry_time = */ 0};
const CdmUsageEntryInfo kUpgradableUsageEntryInfo3 = {
@@ -256,11 +256,7 @@ const CdmUsageEntryInfo kUpgradableUsageEntryInfo3 = {
/* usage_info_file_name = */ "",
/* last_use_time = */ 0,
/* offline_license_expiry_time = */ 0};
const std::vector<CdmUsageEntryInfo> kUpgradableUsageEntryInfoList{
kUpgradableUsageEntryInfo1, kUpgradableUsageEntryInfo2,
kUpgradableUsageEntryInfo3};
const int64_t kLruBaseTime = 1563399000;
std::vector<CdmUsageEntryInfo> kUpgradableUsageEntryInfoList;
// Offline license 1.
// license_start_time = 1563399000
@@ -270,14 +266,11 @@ const int64_t kLruBaseTime = 1563399000;
const CdmKeyResponse kUpgradableLicenseInfo1 = wvutil::a2bs_hex(
"08021214120C2080F5242880A3053080E90F20D8A6BEE9051A20D5F7ACE8D84A166C69BB"
"27523C84C019464B90AA9BF06B8332004839119BFD14");
// Offline license 2.
// Streaming license 2.
// license_start_time = 1563399000
// license_duration_seconds = 259200 (3 days)
// rental_duration_seconds = 0 (unlimited)
// playback_duration_seconds = 0 (unlimited)
const CdmKeyResponse kUpgradableLicenseInfo2 = wvutil::a2bs_hex(
"080212101208200028003080E90F20D8A6BEE9051A20D0611C4AFEF3EC9C67143ED39B44"
"8FAAA67DB6C4DBFDC28A733AF9A2EABDF0B3");
"0802120620D8A6BEE9051A201956F2FD69E5E96DA8C65FDD04A3C294E484F219F2B1A8DD"
"C2B0737F6EF5BD22");
// Offline license 3.
// license_start_time = 1563399000
// license_duration_seconds = 0 (unlimited)
@@ -286,56 +279,26 @@ const CdmKeyResponse kUpgradableLicenseInfo2 = wvutil::a2bs_hex(
const CdmKeyResponse kUpgradableLicenseInfo3 = wvutil::a2bs_hex(
"08021212120A2080F5242880A305300020D8A6BEE9051A207B09896F46C4EE443170E215"
"B2D8D5F072951027B152F4758AC3A339D7C7B4CE");
const std::vector<CdmKeyResponse> kUpgradableLicenseInfoList = {
kUpgradableLicenseInfo1, kUpgradableLicenseInfo2, kUpgradableLicenseInfo3};
std::vector<CdmKeyResponse> kUpgradableLicenseInfoList;
std::vector<DeviceFiles::CdmLicenseData> kUpgradableLicenseDataList;
// Same as Offline license 1, but without signature.
const CdmKeyResponse kUnsignedUpgradableLicenseInfo1 =
wvutil::a2bs_hex("08021214120C2080F5242880A3053080E90F20D8A6BEE905");
// Same as streaming license 2, but message type is certificate, not license.
const CdmKeyResponse kWrongTypedUpgradableLicenseInfo2 = wvutil::a2bs_hex(
"0805120620D8A6BEE9051A201956F2FD69E5E96DA8C65FDD04A3C294E484F219F2B1A8DD"
"C2B0737F6EF5BD22");
const int64_t kLruBaseTime = 1563399000;
const int64_t kUpgradedUsageEntryInfo1LastUsedTime = kLruBaseTime;
const int64_t kUpgradedUsageEntryInfo1ExpireTime = kLruBaseTime + 259200;
const int64_t kUpgradedUsageEntryInfo2LastUsedTime = kLruBaseTime;
const int64_t kUpgradedUsageEntryInfo2ExpireTime = kLruBaseTime + 259200;
const int64_t kUpgradedUsageEntryInfo2ExpireTime = 0; // Unset
const int64_t kUpgradedUsageEntryInfo3LastUsedTime = kLruBaseTime;
const int64_t kUpgradedUsageEntryInfo3ExpireTime =
kLruBaseTime + 604800 + 86400;
const CdmUsageTableHeader kUpgradedUsageTableHeader = "Upgraded Table Header";
const CdmUsageEntryInfo kUpgradedUsageEntryInfo1 = {
/* storage_type = */ kStorageLicense,
/* key_set_id = */ "offline_key_set_1",
/* usage_info_file_name = */ "",
/* last_use_time = */ kUpgradedUsageEntryInfo1LastUsedTime,
/* offline_license_expiry_time = */ kUpgradedUsageEntryInfo1ExpireTime};
const CdmUsageEntryInfo kUpgradedUsageEntryInfo2 = {
/* storage_type = */ kStorageLicense,
/* key_set_id = */ "offline_key_set_2",
/* usage_info_file_name = */ "",
/* last_use_time = */ kUpgradedUsageEntryInfo2LastUsedTime,
/* offline_license_expiry_time = */ kUpgradedUsageEntryInfo2ExpireTime};
const CdmUsageEntryInfo kUpgradedUsageEntryInfo3 = {
/* storage_type = */ kStorageLicense,
/* key_set_id = */ "offline_key_set_3",
/* usage_info_file_name = */ "",
/* last_use_time = */ kUpgradedUsageEntryInfo3LastUsedTime,
/* offline_license_expiry_time = */ kUpgradedUsageEntryInfo3ExpireTime};
const std::vector<CdmUsageEntryInfo> kUpgradedUsageEntryInfoList = {
kUpgradedUsageEntryInfo1, kUpgradedUsageEntryInfo2,
kUpgradedUsageEntryInfo3};
std::vector<DeviceFiles::CdmLicenseData> CreateUpgradableLicenseInfoList() {
std::vector<DeviceFiles::CdmLicenseData> license_data_list;
for (size_t i = 0; i < kUpgradableLicenseInfoList.size(); ++i) {
DeviceFiles::CdmLicenseData license_data;
license_data.key_set_id = kUpgradableUsageEntryInfoList[i].key_set_id;
license_data.state = kActiveLicenseState;
license_data.license = kUpgradableLicenseInfoList[i];
license_data.usage_entry_number = static_cast<uint32_t>(i);
license_data_list.push_back(license_data);
}
return license_data_list;
}
std::vector<CdmUsageEntryInfo> kUpgradedUsageEntryInfoList;
void InitVectorConstants() {
kOverFullUsageEntryInfoVector.clear();
@@ -369,6 +332,40 @@ void InitVectorConstants() {
for (size_t i = 0; i < kLicenseArraySize; i++) {
kLicenseList.push_back(kLicenseArray[i]);
}
// LRU Data.
kUpgradableUsageEntryInfoList.push_back(kUpgradableUsageEntryInfo1);
kUpgradableUsageEntryInfoList.push_back(kUpgradableUsageEntryInfo2);
kUpgradableUsageEntryInfoList.push_back(kUpgradableUsageEntryInfo3);
kUpgradableLicenseInfoList.push_back(kUpgradableLicenseInfo1);
kUpgradableLicenseInfoList.push_back(kUpgradableLicenseInfo2);
kUpgradableLicenseInfoList.push_back(kUpgradableLicenseInfo3);
kUpgradedUsageEntryInfoList.push_back(kUpgradableUsageEntryInfo1);
kUpgradedUsageEntryInfoList.back().last_use_time =
kUpgradedUsageEntryInfo1LastUsedTime;
kUpgradedUsageEntryInfoList.back().offline_license_expiry_time =
kUpgradedUsageEntryInfo1ExpireTime;
kUpgradedUsageEntryInfoList.push_back(kUpgradableUsageEntryInfo2);
kUpgradedUsageEntryInfoList.back().last_use_time =
kUpgradedUsageEntryInfo2LastUsedTime;
kUpgradedUsageEntryInfoList.back().offline_license_expiry_time =
kUpgradedUsageEntryInfo2ExpireTime;
kUpgradedUsageEntryInfoList.push_back(kUpgradableUsageEntryInfo3);
kUpgradedUsageEntryInfoList.back().last_use_time =
kUpgradedUsageEntryInfo3LastUsedTime;
kUpgradedUsageEntryInfoList.back().offline_license_expiry_time =
kUpgradedUsageEntryInfo3ExpireTime;
for (size_t i = 0; i < kUpgradableLicenseInfoList.size(); ++i) {
DeviceFiles::CdmLicenseData license_data;
license_data.key_set_id = kUpgradableUsageEntryInfoList[i].key_set_id;
license_data.state = kActiveLicenseState;
license_data.license = kUpgradableLicenseInfoList[i];
license_data.usage_entry_number = static_cast<uint32_t>(i);
kUpgradableLicenseDataList.push_back(license_data);
}
}
void ToVector(std::vector<CdmUsageEntryInfo>& vec, const CdmUsageEntryInfo* arr,
@@ -405,6 +402,9 @@ class MockDeviceFiles : public DeviceFiles {
(override));
MOCK_METHOD(bool, DeleteUsageInfo, (const std::string&, const std::string&),
(override));
MOCK_METHOD(bool, DeleteMultipleUsageInfoByKeySetIds,
(const std::string&, const std::vector<std::string>&),
(override));
MOCK_METHOD(bool, RetrieveUsageInfoByKeySetId,
(const std::string&, const std::string&, std::string*,
CdmKeyMessage*, CdmKeyResponse*, CdmUsageEntry*, uint32_t*,
@@ -3728,6 +3728,9 @@ TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_NoAction) {
// These function are called specifically by the LRU upgrading system.
EXPECT_CALL(*device_files_, RetrieveLicense(_, _, _)).Times(0);
EXPECT_CALL(*device_files_,
RetrieveUsageInfoByKeySetId(_, _, _, _, _, _, _, _, _))
.Times(0);
EXPECT_TRUE(usage_table_header_->Init(kSecurityLevelL1, crypto_session_));
EXPECT_EQ(usage_table_header_->usage_entry_info(),
@@ -3737,8 +3740,8 @@ TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_NoAction) {
// Initial Test state:
// 1. Table info is load from device files; however, device files reports
// that the table has not been configured for upgrade.
// 2. The usage table header will load offline license to determine
// appropriate expiry and last_used times.
// 2. The usage table header will load license or usage information to
// determine appropriate expiry and last_used times.
TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_Succeed) {
EXPECT_CALL(*crypto_session_,
GetNumberOfOpenSessions(kLevelDefault, NotNull()))
@@ -3753,18 +3756,24 @@ TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_Succeed) {
LoadUsageTableHeader(kLevelDefault, kUpgradableUsageTableHeader))
.WillOnce(Return(NO_ERROR));
const std::vector<DeviceFiles::CdmLicenseData> license_info_list =
CreateUpgradableLicenseInfoList();
for (size_t i = 0; i < kUpgradableUsageEntryInfoList.size(); ++i) {
const CdmUsageEntryInfo& info = kUpgradableUsageEntryInfoList[i];
if (info.storage_type == kStorageLicense) {
// Only offline licenses are supported.
EXPECT_CALL(*device_files_,
RetrieveLicense(info.key_set_id, NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<1>(license_info_list[i]), Return(true)));
.WillOnce(DoAll(SetArgPointee<1>(kUpgradableLicenseDataList[i]),
Return(true)));
} else {
EXPECT_CALL(*device_files_,
RetrieveUsageInfoByKeySetId(info.usage_info_file_name,
info.key_set_id, NotNull(),
NotNull(), NotNull(), NotNull(),
NotNull(), NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<4>(kUpgradableLicenseInfoList[i]),
SetArgPointee<6>(static_cast<uint32_t>(i)),
SetArgPointee<7>(kDrmCertificate),
SetArgPointee<8>(kCryptoWrappedKey), Return(true)));
}
}
@@ -3774,22 +3783,33 @@ TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_Succeed) {
}
// Initial Test state:
// Table info is load from device files and must be upgraded.
// A few entries have the unknown storage type value.
// 1. Table info is load from device files and must be upgraded.
// A few entries have the incorrect storage type value.
// 2. During the LRU upgrade process, any license that cannot be
// validated are cleared, and marked to be deleted.
//
// Entry# Storage type Result info
// ====== ============ ===========
// 0 Offline Upgraded
// 1 Unknown Cleared
// 2 Unknown Cleared
// 2 Invalid (99) Cleared
TEST_F(UsageTableHeaderTest,
LruUsageTableUpgrade_PartialSucceedWithUnknownStorageTypes) {
const std::vector<CdmUsageEntryInfo> upgradable_usage_entry_info_list = {
kUpgradableUsageEntryInfo1, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoStorageTypeUnknown};
const std::vector<CdmUsageEntryInfo> upgraded_usage_entry_info_list = {
kUpgradedUsageEntryInfo1, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoStorageTypeUnknown};
std::vector<CdmUsageEntryInfo> upgradable_usage_entry_info_list =
kUpgradableUsageEntryInfoList;
std::vector<CdmUsageEntryInfo> upgraded_usage_entry_info_list =
kUpgradedUsageEntryInfoList;
// Set the wrong storage type.
upgradable_usage_entry_info_list[1].storage_type = kStorageTypeUnknown;
upgradable_usage_entry_info_list[2].storage_type =
static_cast<CdmUsageEntryStorageType>(99);
// Set the expected output.
upgraded_usage_entry_info_list[1] = CdmUsageEntryInfo{};
upgraded_usage_entry_info_list[1].storage_type = kStorageTypeUnknown;
upgraded_usage_entry_info_list[2] = CdmUsageEntryInfo{};
upgraded_usage_entry_info_list[2].storage_type = kStorageTypeUnknown;
// Load table expectations.
EXPECT_CALL(*crypto_session_,
@@ -3806,12 +3826,11 @@ TEST_F(UsageTableHeaderTest,
.WillOnce(Return(NO_ERROR));
// Expectations of the one successful license.
const std::vector<DeviceFiles::CdmLicenseData> license_info_list =
CreateUpgradableLicenseInfoList();
EXPECT_CALL(*device_files_,
RetrieveLicense(upgradable_usage_entry_info_list[0].key_set_id,
NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<1>(license_info_list[0]), Return(true)));
.WillOnce(
DoAll(SetArgPointee<1>(kUpgradableLicenseDataList[0]), Return(true)));
EXPECT_TRUE(usage_table_header_->Init(kSecurityLevelL1, crypto_session_));
EXPECT_EQ(upgraded_usage_entry_info_list,
@@ -3827,14 +3846,12 @@ TEST_F(UsageTableHeaderTest,
// Entry# Storage type License Issue Result info
// ====== ============ ============= ===========
// 0 Offline No signature Cleared
// 1 Unknown Clear entry Cleared
// 1 Streaming Wrong type Cleared
// 2 Offline Upgraded
TEST_F(UsageTableHeaderTest,
LruUsageTableUpgrade_PartialSucceedWithLicenseParseIssues) {
std::vector<CdmUsageEntryInfo> upgradable_usage_entry_info_list =
kUpgradableUsageEntryInfoList;
std::vector<DeviceFiles::CdmLicenseData> license_data_list =
CreateUpgradableLicenseInfoList();
kUpgradableLicenseDataList;
std::vector<CdmKeyResponse> upgradable_license_info_list =
kUpgradableLicenseInfoList;
std::vector<CdmUsageEntryInfo> upgraded_usage_entry_info_list =
@@ -3842,12 +3859,21 @@ TEST_F(UsageTableHeaderTest,
// Modify entry 0 to be invalid.
license_data_list[0].license = kUnsignedUpgradableLicenseInfo1;
upgraded_usage_entry_info_list[0].Clear();
CdmUsageEntryInfo& unsigned_usage_entry_info =
upgraded_usage_entry_info_list[0];
unsigned_usage_entry_info.storage_type = kStorageTypeUnknown;
unsigned_usage_entry_info.key_set_id.clear();
unsigned_usage_entry_info.last_use_time = 0;
unsigned_usage_entry_info.offline_license_expiry_time = 0;
// Modify entry 1 to be clear.
upgradable_usage_entry_info_list[1].Clear();
upgradable_license_info_list[1].clear();
upgraded_usage_entry_info_list[1].Clear();
// Modify entry 1 to be invalid.
upgradable_license_info_list[1] = kWrongTypedUpgradableLicenseInfo2;
CdmUsageEntryInfo& wrond_typed_usage_entry_info =
upgraded_usage_entry_info_list[1];
wrond_typed_usage_entry_info.storage_type = kStorageTypeUnknown;
wrond_typed_usage_entry_info.key_set_id.clear();
wrond_typed_usage_entry_info.last_use_time = 0;
wrond_typed_usage_entry_info.offline_license_expiry_time = 0;
EXPECT_CALL(*crypto_session_,
GetNumberOfOpenSessions(kLevelDefault, NotNull()))
@@ -3855,27 +3881,46 @@ TEST_F(UsageTableHeaderTest,
EXPECT_CALL(*device_files_, RetrieveUsageTableInfo(NotNull(), NotNull(),
NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kUpgradableUsageTableHeader),
SetArgPointee<1>(upgradable_usage_entry_info_list),
SetArgPointee<1>(kUpgradableUsageEntryInfoList),
SetArgPointee<2>(/* lru_upgrade = */ true),
SetArgPointee<3>(false), Return(true)));
EXPECT_CALL(*crypto_session_,
LoadUsageTableHeader(kLevelDefault, kUpgradableUsageTableHeader))
.WillOnce(Return(NO_ERROR));
for (size_t i = 0; i < upgradable_usage_entry_info_list.size(); ++i) {
const CdmUsageEntryInfo& info = upgradable_usage_entry_info_list[i];
for (size_t i = 0; i < kUpgradableUsageEntryInfoList.size(); ++i) {
const CdmUsageEntryInfo& info = kUpgradableUsageEntryInfoList[i];
if (info.storage_type == kStorageLicense) {
EXPECT_CALL(*device_files_,
RetrieveLicense(info.key_set_id, NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<1>(license_data_list[i]), Return(true)));
} else {
EXPECT_CALL(*device_files_,
RetrieveUsageInfoByKeySetId(info.usage_info_file_name,
info.key_set_id, NotNull(),
NotNull(), NotNull(), NotNull(),
NotNull(), NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<4>(upgradable_license_info_list[i]),
SetArgPointee<6>(static_cast<uint32_t>(i)),
SetArgPointee<7>(kDrmCertificate),
SetArgPointee<8>(kCryptoWrappedKey), Return(true)));
}
}
// For the entries which failed, there should be an attempt to delete the
// files associated with them.
// Offline license.
EXPECT_CALL(*device_files_,
DeleteLicense(upgradable_usage_entry_info_list[0].key_set_id))
DeleteLicense(kUpgradableUsageEntryInfoList[0].key_set_id))
.WillOnce(Return(true));
// Streaming license.
const std::vector<std::string> corrupted_usage_info_key_set_ids = {
kUpgradableUsageEntryInfoList[1].key_set_id};
EXPECT_CALL(*device_files_,
DeleteMultipleUsageInfoByKeySetIds(
kUpgradableUsageEntryInfoList[1].usage_info_file_name,
ContainerEq(corrupted_usage_info_key_set_ids)))
.WillOnce(Return(true));
EXPECT_TRUE(usage_table_header_->Init(kSecurityLevelL1, crypto_session_));
@@ -3908,6 +3953,13 @@ TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_AllFailure) {
EXPECT_CALL(*device_files_,
RetrieveLicense(info.key_set_id, NotNull(), NotNull()))
.WillOnce(Return(false));
} else {
EXPECT_CALL(*device_files_,
RetrieveUsageInfoByKeySetId(info.usage_info_file_name,
info.key_set_id, NotNull(),
NotNull(), NotNull(), NotNull(),
NotNull(), NotNull(), NotNull()))
.WillOnce(Return(false));
}
}
@@ -3955,7 +4007,46 @@ TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateLicenseEntry) {
EXPECT_EQ(NO_ERROR, usage_table_header_->AddEntry(
crypto_session_, true /* persistent_license */,
expected_new_entry.key_set_id,
/* usage_info_file_name */ kEmptyString, kEmptyString,
expected_new_entry.usage_info_file_name, 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());
}
TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateUsageInfoEntry) {
Init(kSecurityLevelL1, kUpgradedUsageTableHeader,
kUpgradedUsageEntryInfoList);
// Expected values.
const uint32_t expected_usage_entry_number =
static_cast<uint32_t>(kUpgradedUsageEntryInfoList.size());
const CdmUsageEntryInfo expected_new_entry = {
kStorageUsageInfo, "secure_stop_key_set_5", "streaming_license_file_4",
kLruBaseTime, 0 /* No set for streaming license. */
};
std::vector<CdmUsageEntryInfo> expected_usage_info_list =
kUpgradedUsageEntryInfoList;
expected_usage_info_list.push_back(expected_new_entry);
// AddKey expectations
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(expected_usage_entry_number),
Return(NO_ERROR)));
MockClock mock_clock;
usage_table_header_->SetClock(&mock_clock);
EXPECT_CALL(mock_clock, GetCurrentTime()).WillOnce(Return(kLruBaseTime));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader, _));
// The Call.
uint32_t usage_entry_number = 0;
EXPECT_EQ(NO_ERROR, usage_table_header_->AddEntry(
crypto_session_, false /* persistent_license */,
expected_new_entry.key_set_id,
expected_new_entry.usage_info_file_name, kEmptyString,
&usage_entry_number));
EXPECT_EQ(expected_usage_entry_number, usage_entry_number);
@@ -4060,7 +4151,6 @@ TEST_F(UsageTableHeaderTest, DetermineLicenseToRemove_BasicPriorities) {
// Unexpired offline license.
CdmUsageEntryInfo unexpired_entry_info;
unexpired_entry_info.storage_type = kStorageLicense;
unexpired_entry_info.key_set_id = "unexpired_key_set_id";
unexpired_entry_info.last_use_time = kLruBaseTime;
unexpired_entry_info.offline_license_expiry_time = kLruBaseTime + 2 * kOneDay;
usage_entry_info_list.push_back(unexpired_entry_info);
@@ -4069,43 +4159,59 @@ TEST_F(UsageTableHeaderTest, DetermineLicenseToRemove_BasicPriorities) {
// Expired offline license.
CdmUsageEntryInfo expired_entry_info;
expired_entry_info.storage_type = kStorageLicense;
expired_entry_info.key_set_id = "expired_key_set_id";
expired_entry_info.last_use_time = kLruBaseTime;
expired_entry_info.offline_license_expiry_time = kLruBaseTime;
usage_entry_info_list.push_back(expired_entry_info);
constexpr uint32_t expired_entry_number = 1;
// Streaming license.
CdmUsageEntryInfo streaming_entry_info;
streaming_entry_info.storage_type = kStorageUsageInfo;
streaming_entry_info.last_use_time = kLruBaseTime;
usage_entry_info_list.push_back(streaming_entry_info);
constexpr uint32_t streaming_entry_number = 2;
// Unknown entry.
CdmUsageEntryInfo unknown_entry_info;
unknown_entry_info.storage_type = kStorageTypeUnknown;
// Should be chosen regardless of |last_use_time|.
unknown_entry_info.last_use_time = kCurrentTime;
usage_entry_info_list.push_back(unknown_entry_info);
constexpr uint32_t unknown_entry_number = 2;
constexpr uint32_t unknown_entry_number = 3;
// Case 1: If there is a clear entry, it should be selected above
// any other entry.
// Case 1: If there is an entry with unknown storage type, it should
// be selected above any other entry.
uint32_t entry_to_remove = kInvalidEntry;
// Expect the clear.
// Expect the unknown entry.
EXPECT_TRUE(UsageTableHeader::DetermineLicenseToRemoveForTesting(
usage_entry_info_list, kCurrentTime,
/* unexpired_threshold = */ 3, &entry_to_remove));
EXPECT_EQ(unknown_entry_number, entry_to_remove);
usage_entry_info_list.pop_back(); // Removing clear entry.
// |usage_entry_info_list| only contains 1 expired and 1 unexpired offline
// license.
usage_entry_info_list.pop_back(); // Removing unknown.
// Case 2a: Threshold not met, all entries are equally stale.
// The expired entry should be selected over the unexpired entry.
// The expired entry should be selected over the streaming license.
entry_to_remove = kInvalidEntry;
EXPECT_TRUE(UsageTableHeader::DetermineLicenseToRemoveForTesting(
usage_entry_info_list, kCurrentTime,
/* unexpired_threshold = */ 3, &entry_to_remove));
EXPECT_EQ(expired_entry_number, entry_to_remove);
// Case 2b: Threshold met, equally stale entries. Expect the expired
// Case 2b: Threshold not met, streaming license is most stale.
usage_entry_info_list[streaming_entry_number].last_use_time--;
entry_to_remove = kInvalidEntry;
EXPECT_TRUE(UsageTableHeader::DetermineLicenseToRemoveForTesting(
usage_entry_info_list, kCurrentTime,
/* unexpired_threshold = */ 3, &entry_to_remove));
EXPECT_EQ(streaming_entry_number, entry_to_remove);
usage_entry_info_list.pop_back(); // Removing streaming.
// |usage_entry_info_list| only contains 1 expired and 1 unexpired offline
// license.
// Case 2c: Threshold met, equally stale entries. Expect the expired
// entry over the unexpired.
entry_to_remove = kInvalidEntry;
EXPECT_TRUE(UsageTableHeader::DetermineLicenseToRemoveForTesting(
@@ -4167,8 +4273,45 @@ TEST_F(UsageTableHeaderTest, DetermineLicenseToRemove_BasicPriorities) {
EXPECT_EQ(unexpired_entry_number, entry_to_remove);
}
// Testing algorithm with unexpired offline and streaming license. The
// sum of offline licenses is below the threshold for consideration.
// Only the streaming license should be considered for removal.
TEST_F(UsageTableHeaderTest,
DetermineLicenseToRemove_NoExpiredAndBelowThreshold) {
constexpr int64_t kOneDay = 24 * 60 * 60;
constexpr uint32_t kInvalidEntry = 9999;
std::vector<CdmUsageEntryInfo> usage_entry_info_list =
kUpgradedUsageEntryInfoList;
const size_t offline_threshold = usage_entry_info_list.size() + 1;
size_t usage_info_count = 0;
for (auto& usage_entry_info : usage_entry_info_list) {
if (usage_entry_info.storage_type == kStorageUsageInfo) {
// Make usage info entries less stale than offline.
usage_entry_info.last_use_time += 100;
++usage_info_count;
} else {
// Make offline licenses unexpired.
usage_entry_info.offline_license_expiry_time =
kLruBaseTime + kOneDay * 30;
}
}
// Must exist at least one streaming license for test to work.
ASSERT_LT(0ull, usage_info_count);
uint32_t entry_to_remove = kInvalidEntry;
EXPECT_TRUE(UsageTableHeader::DetermineLicenseToRemoveForTesting(
usage_entry_info_list, kLruBaseTime, offline_threshold,
&entry_to_remove));
EXPECT_EQ(kStorageUsageInfo,
usage_entry_info_list[entry_to_remove].storage_type);
}
// When the number of unexpired offline licenses are below the
// threshold, only expired offline licenses should be considered.
// threshold, only streaming licenses and expired offline licenses
// should be considered.
// Providing only offline licenses, only the expired license should be
// considered for removal.
TEST_F(UsageTableHeaderTest,
@@ -4187,20 +4330,20 @@ TEST_F(UsageTableHeaderTest,
for (uint32_t i = 0; i < kSetSize; ++i) {
CdmUsageEntryInfo& usage_entry_info = usage_entry_info_list[i];
usage_entry_info.storage_type = kStorageLicense;
usage_entry_info.key_set_id = "unexpired_offline";
usage_entry_info.key_set_id = "nothing_unusual";
usage_entry_info.last_use_time = kLruBaseTime;
usage_entry_info.offline_license_expiry_time =
kCurrentTime + kDefaultExpireDuration;
}
// Mark three licenses as expired.
// Mark 3 as expired.
std::vector<uint32_t> expired_license_numbers;
while (expired_license_numbers.size() < 3) {
const uint32_t i =
static_cast<uint32_t>(wvutil::CdmRandom::RandomInRange(kSetSize - 1));
CdmUsageEntryInfo& usage_entry_info = usage_entry_info_list[i];
// Skip already expired ones
if (usage_entry_info.key_set_id != "unexpired_offline") continue;
if (usage_entry_info.key_set_id != "nothing_unusual") continue;
// Make these less stale than the unexpired licenses.
usage_entry_info.last_use_time = kLruBaseTime + kOneDay;
usage_entry_info.offline_license_expiry_time = kCurrentTime - kOneDay;
@@ -4216,31 +4359,16 @@ TEST_F(UsageTableHeaderTest,
EXPECT_THAT(expired_license_numbers, Contains(entry_to_remove));
}
// This primarily tests the robustness of the algorithm for a full
// set of entries (200). Creates 1 offline license which are more
// stale than the all other licenses.
// This test primarily tests the robustness of the algorithm for a full
// set of entries (200). Creates 1 stale streaming license and 1
// offline licenses which are more stale than the streaming.
//
// All cases: 1 unexpired license is most stale.
// First, with the stale offline licenses unexpired, checks that the
// streaming are always selected, so long as |unexpired_threshold|
// is not met.
//
// Case 1:
// - Unexpired threshold met: No
// - Exists expired license: No
// - Expect most stale license to be selected
//
// Case 2:
// - Unexpired threshold met: Yes
// - Exists expired license: No
// - Expect most stale license to be selected
//
// Case 3:
// - Unexpired threshold met: No
// - Exists expired license: Yes
// - Expect expired license to be selected
//
// Case 4:
// - Unexpired threshold met: Yes
// - Exists expired license: Yes
// - Expect most stale license to be selected
// Second, with the stale offline license marked as expired, checks that
// offline licenses are selected over the streaming.
TEST_F(UsageTableHeaderTest, DetermineLicenseToRemove_LargeMixedSet) {
constexpr int64_t kOneDay = 24 * 60 * 60;
constexpr size_t kLargeSetSize = 200;
@@ -4249,63 +4377,74 @@ TEST_F(UsageTableHeaderTest, DetermineLicenseToRemove_LargeMixedSet) {
std::vector<CdmUsageEntryInfo> usage_entry_info_list;
usage_entry_info_list.resize(kLargeSetSize);
// Create a set of unexpired license entries.
// Create a set of usage entries.
for (uint32_t i = 0; i < kLargeSetSize; ++i) {
CdmUsageEntryInfo& usage_entry_info = usage_entry_info_list[i];
usage_entry_info.storage_type = kStorageLicense;
usage_entry_info.key_set_id = "unexpired_offline";
usage_entry_info.key_set_id = "nothing_unusual";
usage_entry_info.last_use_time = kLruBaseTime + kOneDay;
usage_entry_info.offline_license_expiry_time =
kCurrentTime + kDefaultExpireDuration;
if ((i % 4) == 0) {
// Roughly 25% are offline, the rest are streaming.
usage_entry_info.storage_type = kStorageLicense;
usage_entry_info.offline_license_expiry_time =
kCurrentTime + kDefaultExpireDuration;
} else {
usage_entry_info.storage_type = kStorageUsageInfo;
}
}
// Select a streaming license to be more stale than the rest.
uint32_t modified_usage_info_number = kInvalidEntry;
while (modified_usage_info_number == kInvalidEntry) {
const uint32_t i = static_cast<uint32_t>(
wvutil::CdmRandom::RandomInRange(kLargeSetSize - 1));
CdmUsageEntryInfo& usage_entry_info = usage_entry_info_list[i];
// Skip offline licenses.
if (usage_entry_info.storage_type != kStorageUsageInfo) continue;
usage_entry_info.last_use_time = kLruBaseTime + 10;
usage_entry_info.key_set_id = "stale_streaming";
modified_usage_info_number = i;
}
// Select a offline license to be even more stale, but unexpired.
const uint32_t most_stale_offline_license_number = static_cast<uint32_t>(
wvutil::CdmRandom::RandomInRange(kLargeSetSize - 1));
CdmUsageEntryInfo& usage_entry_info =
usage_entry_info_list[most_stale_offline_license_number];
usage_entry_info.last_use_time = kLruBaseTime;
usage_entry_info.key_set_id = "stale_offline";
uint32_t modified_offline_license_number = kInvalidEntry;
while (modified_offline_license_number == kInvalidEntry) {
const uint32_t i = static_cast<uint32_t>(
wvutil::CdmRandom::RandomInRange(kLargeSetSize - 1));
CdmUsageEntryInfo& usage_entry_info = usage_entry_info_list[i];
// Skip streaming licenses.
if (usage_entry_info.storage_type != kStorageLicense) continue;
usage_entry_info.last_use_time = kLruBaseTime;
usage_entry_info.key_set_id = "stale_offline";
modified_offline_license_number = i;
}
// Case 1: Most stale license is selected.
// Test using only streaming and expired offline licenses
// (which there are none).
uint32_t entry_to_remove = kInvalidEntry;
EXPECT_TRUE(UsageTableHeader::DetermineLicenseToRemoveForTesting(
usage_entry_info_list, kCurrentTime,
/* unexpired_threshold = */ kLargeSetSize, &entry_to_remove));
EXPECT_EQ(most_stale_offline_license_number, entry_to_remove);
EXPECT_EQ(modified_usage_info_number, entry_to_remove);
// Case 2: Most stale license is selected.
// Test where the equality threshold is met, now the stale unexpired
// license should be selected.
entry_to_remove = kInvalidEntry;
EXPECT_TRUE(UsageTableHeader::DetermineLicenseToRemoveForTesting(
usage_entry_info_list, kCurrentTime,
/* unexpired_threshold = */ 0, &entry_to_remove));
EXPECT_EQ(most_stale_offline_license_number, entry_to_remove);
EXPECT_EQ(modified_offline_license_number, entry_to_remove);
// Select a offline license to be marked as expired but not the most
// stale.
uint32_t expired_offline_license_number = kInvalidEntry;
while (expired_offline_license_number == kInvalidEntry) {
const uint32_t i = static_cast<uint32_t>(
wvutil::CdmRandom::RandomInRange(kLargeSetSize - 1));
// Don't modify the stale offline license.
if (usage_entry_info_list[i].key_set_id != "unexpired_offline") continue;
usage_entry_info_list[i].offline_license_expiry_time = kLruBaseTime;
expired_offline_license_number = i;
}
// Make the stale offline license expired.
CdmUsageEntryInfo& offline_usage_entry_info =
usage_entry_info_list[modified_offline_license_number];
offline_usage_entry_info.offline_license_expiry_time = kLruBaseTime;
// Case 3: Expired license is selected.
// Test again, expecting that the expired license should be considered.
entry_to_remove = kInvalidEntry;
EXPECT_TRUE(UsageTableHeader::DetermineLicenseToRemoveForTesting(
usage_entry_info_list, kCurrentTime,
/* unexpired_threshold = */ kLargeSetSize, &entry_to_remove));
EXPECT_EQ(expired_offline_license_number, entry_to_remove);
// Case 4: Most stale license is selected.
entry_to_remove = kInvalidEntry;
EXPECT_TRUE(UsageTableHeader::DetermineLicenseToRemoveForTesting(
usage_entry_info_list, kCurrentTime,
/* unexpired_threshold = */ 0, &entry_to_remove));
EXPECT_EQ(most_stale_offline_license_number, entry_to_remove);
EXPECT_EQ(modified_offline_license_number, entry_to_remove);
}
TEST_F(UsageTableHeaderTest, PotentialTableCapacity_Unavailable) {