Core CDM: Remove secure stop from LRU algorithm.

[ Merge of http://go/wvgerrit/158877 ]

The UsageTableHeader's LRU algorithm for determining which entry to
evict when full uses special considerations based on the type of
entry (offline or secure stop).

This CL removes all secure-stop-specific considerations, and instead
treats secure stop's the same as an unused entry.  Secure stop entries
will always be selected for removal before offline licenses (expired
or not).

Additionally, LRU table upgrading will ignore secure-stop entries.
This has no effect in practice as DeviceFiles will not load secure
stop usage entries when UsageTableHeader is initialized on a real
file system.

Bug: 242289743
Test: run_x86_64_tests and request_license_test
Change-Id: Ib3f71f191aed94aad62951667426911e4e202068
This commit is contained in:
Alex Dale
2022-10-13 15:29:58 -07:00
parent da9ba6c3ba
commit 7a34c1748c
3 changed files with 202 additions and 427 deletions

View File

@@ -96,41 +96,6 @@ bool RetrieveOfflineLicense(DeviceFiles* device_files,
return true;
}
bool RetrieveUsageInfoLicense(DeviceFiles* device_files,
const std::string& usage_info_file_name,
const std::string& key_set_id,
CdmKeyResponse* license_message,
uint32_t* usage_entry_number) {
if (device_files == nullptr) {
LOGE("DeviceFiles handle is null");
return false;
}
if (license_message == nullptr) {
LOGE("Output parameter |license_message| is null");
return false;
}
if (usage_entry_number == nullptr) {
LOGE("Output parameter |usage_entry_number| is null");
return false;
}
CdmUsageEntry usage_entry;
std::string provider_session_token;
CdmKeyMessage license_request;
std::string drm_certificate;
CryptoWrappedKey wrapped_private_key;
if (!device_files->RetrieveUsageInfoByKeySetId(
usage_info_file_name, key_set_id, &provider_session_token,
&license_request, license_message, &usage_entry, usage_entry_number,
&drm_certificate, &wrapped_private_key)) {
LOGW(
"Failed to retrieve usage information: "
"key_set_id = %s, usage_info_file_name = %s",
IdToString(key_set_id), IdToString(usage_info_file_name));
return false;
}
return true;
}
bool EntryIsUsageInfo(const CdmUsageEntryInfo& info) {
// Used for stl filters.
return info.storage_type == kStorageUsageInfo;
@@ -1163,7 +1128,6 @@ CdmResponseType UsageTableHeader::ReleaseOldestEntry(
// Capture metric values now, as the |usage_entry_info| reference will
// change after the call to invalidate.
const int64_t staleness = current_time - usage_entry_info.last_use_time;
const CdmUsageEntryStorageType storage_type = usage_entry_info.storage_type;
const CdmResponseType status =
InvalidateEntryInternal(entry_number_to_delete, /* defrag_table = */ true,
@@ -1176,7 +1140,7 @@ CdmResponseType UsageTableHeader::ReleaseOldestEntry(
}
// Record metrics on success.
RecordLruEventMetrics(metrics, staleness, storage_type);
RecordLruEventMetrics(metrics, staleness);
return NO_ERROR;
}
@@ -1209,34 +1173,16 @@ bool UsageTableHeader::LruUpgradeAllUsageEntries() {
usage_entry_number < usage_entry_info_.size(); ++usage_entry_number) {
CdmUsageEntryInfo& usage_entry_info = usage_entry_info_[usage_entry_number];
if (usage_entry_info.storage_type != kStorageLicense) {
bad_license_file_entries.push_back(usage_entry_number);
continue;
}
uint32_t retrieved_entry_number;
CdmKeyResponse license_message;
bool retrieve_response = false;
switch (usage_entry_info.storage_type) {
case kStorageLicense: {
retrieve_response = RetrieveOfflineLicense(
device_files_.get(), usage_entry_info.key_set_id, &license_message,
&retrieved_entry_number);
break;
}
case kStorageUsageInfo: {
retrieve_response = RetrieveUsageInfoLicense(
device_files_.get(), usage_entry_info.usage_info_file_name,
usage_entry_info.key_set_id, &license_message,
&retrieved_entry_number);
break;
}
case kStorageTypeUnknown:
bad_license_file_entries.push_back(usage_entry_number);
continue;
default: {
LOGW("Unknown usage entry storage type: %d, usage_entry_number = %u",
static_cast<int>(usage_entry_info.storage_type),
usage_entry_number);
bad_license_file_entries.push_back(usage_entry_number);
continue;
}
}
const bool retrieve_response =
RetrieveOfflineLicense(device_files_.get(), usage_entry_info.key_set_id,
&license_message, &retrieved_entry_number);
if (!retrieve_response) {
LOGW("Could not retrieve license message: usage_entry_number = %u",
usage_entry_number);
@@ -1265,22 +1211,18 @@ bool UsageTableHeader::LruUpgradeAllUsageEntries() {
// for replacement above all others.
usage_entry_info.last_use_time = license.license_start_time();
if (usage_entry_info.storage_type == kStorageLicense) {
// Only offline licenses need |offline_license_expiry_time| set.
const video_widevine::License::Policy& policy = license.policy();
// TODO(b/139372190): Change how these fields are set once feature is
// implemented.
if (policy.license_duration_seconds() == 0) {
// Zero implies unlimited license duration.
usage_entry_info.offline_license_expiry_time =
license.license_start_time() + policy.rental_duration_seconds() +
policy.playback_duration_seconds();
} else {
usage_entry_info.offline_license_expiry_time =
license.license_start_time() + policy.license_duration_seconds();
}
// Only offline licenses need |offline_license_expiry_time| set.
const video_widevine::License::Policy& policy = license.policy();
// TODO(b/139372190): Change how these fields are set once feature is
// implemented.
if (policy.license_duration_seconds() == 0) {
// Zero implies unlimited license duration.
usage_entry_info.offline_license_expiry_time =
license.license_start_time() + policy.rental_duration_seconds() +
policy.playback_duration_seconds();
} else {
usage_entry_info.offline_license_expiry_time = 0;
usage_entry_info.offline_license_expiry_time =
license.license_start_time() + policy.license_duration_seconds();
}
} // End for loop.
@@ -1290,31 +1232,14 @@ bool UsageTableHeader::LruUpgradeAllUsageEntries() {
return false;
}
// Maps <usage_info_file_name> -> [<key_set_id>].
std::map<std::string, std::vector<std::string>> usage_info_clean_up;
for (size_t usage_entry_number : bad_license_file_entries) {
CdmUsageEntryInfo& usage_entry_info = usage_entry_info_[usage_entry_number];
if (usage_entry_info.storage_type == kStorageLicense) {
device_files_->DeleteLicense(usage_entry_info.key_set_id);
} else if (usage_entry_info.storage_type == kStorageUsageInfo) {
// To reduce write cycles, the deletion of usage info will be done
// in bulk.
auto it = usage_info_clean_up.find(usage_entry_info.usage_info_file_name);
if (it == usage_info_clean_up.end()) {
it = usage_info_clean_up
.emplace(usage_entry_info.usage_info_file_name,
std::vector<std::string>())
.first;
}
it->second.push_back(usage_entry_info.key_set_id);
} // else kStorageUnknown { Nothing special }.
}
usage_entry_info.Clear();
}
for (const auto& p : usage_info_clean_up) {
device_files_->DeleteMultipleUsageInfoByKeySetIds(p.first, p.second);
}
return true;
}
@@ -1327,16 +1252,18 @@ bool UsageTableHeader::GetRemovalCandidate(uint32_t* entry_to_remove) {
lru_unexpired_threshold, entry_to_remove);
}
void UsageTableHeader::RecordLruEventMetrics(
metrics::CryptoMetrics* metrics, uint64_t staleness,
CdmUsageEntryStorageType storage_type) {
void UsageTableHeader::RecordLruEventMetrics(metrics::CryptoMetrics* metrics,
uint64_t staleness) {
if (metrics == nullptr) return;
metrics->usage_table_header_lru_usage_info_count_.Record(UsageInfoCount());
// Usage info are deprecated, always record 0.
metrics->usage_table_header_lru_usage_info_count_.Record(0);
metrics->usage_table_header_lru_offline_license_count_.Record(
OfflineEntryCount());
metrics->usage_table_header_lru_evicted_entry_staleness_.Record(staleness);
// Can be assumed that only offline licenses are removed.
constexpr int kDefaultEntryType = 0;
metrics->usage_table_header_lru_evicted_entry_type_.Record(
static_cast<int>(storage_type));
static_cast<int>(kDefaultEntryType));
}
// Static.
@@ -1359,14 +1286,13 @@ bool UsageTableHeader::DetermineLicenseToRemove(
usage_entry_info_list[j].last_use_time;
};
// Find the most stale expired offline / streaming license and the
// Find the most stale expired offline license and the
// most stale unexpired offline entry. Count the number of unexpired
// entries. If any entry is of storage type unknown, then it should
// entries. If any entry is not of storage type license, then it should
// be removed.
constexpr uint32_t kNoEntry = std::numeric_limits<uint32_t>::max();
uint32_t stalest_expired_offline_license = kNoEntry;
uint32_t stalest_unexpired_offline_license = kNoEntry;
uint32_t stalest_streaming_license = kNoEntry;
size_t unexpired_license_count = 0;
for (uint32_t entry_number = 0; entry_number < usage_entry_info_list.size();
@@ -1374,37 +1300,28 @@ bool UsageTableHeader::DetermineLicenseToRemove(
const CdmUsageEntryInfo& usage_entry_info =
usage_entry_info_list[entry_number];
if (usage_entry_info.storage_type != kStorageLicense &&
usage_entry_info.storage_type != kStorageUsageInfo) {
// Unknown storage type entries. Remove this entry.
if (usage_entry_info.storage_type != kStorageLicense) {
// Non-license storage type entries. Remove this entry.
*entry_to_remove = entry_number;
return true;
}
if (usage_entry_info.storage_type == kStorageLicense &&
usage_entry_info.offline_license_expiry_time > current_time) {
if (usage_entry_info.offline_license_expiry_time > current_time) {
// Unexpired offline.
++unexpired_license_count;
if (stalest_unexpired_offline_license == kNoEntry ||
is_more_stale(entry_number, stalest_unexpired_offline_license)) {
stalest_unexpired_offline_license = entry_number;
}
} else if (usage_entry_info.storage_type == kStorageLicense) {
} else {
// Expired offline.
if (stalest_expired_offline_license == kNoEntry ||
is_more_stale(entry_number, stalest_expired_offline_license)) {
stalest_expired_offline_license = entry_number;
}
} else {
// Streaming.
if (stalest_streaming_license == kNoEntry ||
is_more_stale(entry_number, stalest_streaming_license)) {
stalest_streaming_license = entry_number;
}
}
}
if (stalest_expired_offline_license == kNoEntry &&
stalest_streaming_license == kNoEntry &&
unexpired_license_count <= unexpired_threshold) {
// Unexpected situation, could be an issue with the threshold.
LOGW(
@@ -1424,12 +1341,10 @@ bool UsageTableHeader::DetermineLicenseToRemove(
// Only consider an unexpired entry if the threshold is reached.
if (unexpired_license_count > unexpired_threshold) {
const uint32_t temp = select_most_stale(stalest_unexpired_offline_license,
stalest_streaming_license);
*entry_to_remove = select_most_stale(temp, stalest_expired_offline_license);
} else {
*entry_to_remove = select_most_stale(stalest_streaming_license,
*entry_to_remove = select_most_stale(stalest_unexpired_offline_license,
stalest_expired_offline_license);
} else {
*entry_to_remove = stalest_expired_offline_license;
}
if (*entry_to_remove == kNoEntry) {