Merge changes Ib3f71f19,I2d1fc0d6

* changes:
  Core CDM: Remove secure stop from LRU algorithm.
  Core CDM: Retrieving USAGE_INFO triggers clean-up.
This commit is contained in:
Alex Dale
2022-11-08 22:19:38 +00:00
committed by Android (Google) Code Review
6 changed files with 329 additions and 493 deletions

View File

@@ -277,9 +277,14 @@ class DeviceFiles {
// When retrieving usage table information from the file system; any
// table that has yet to be updated for the LRU attributes will be
// indicated by |lru_upgrade|.
// Tables from earlier CDM releases might contain USAGE_INFO type
// entries. This entries are no long required, by their presence
// requires the usage table to be cleaned up. |has_usage_info_entries|
// is set to true if any are detected.
virtual bool RetrieveUsageTableInfo(
CdmUsageTableHeader* usage_table_header,
std::vector<CdmUsageEntryInfo>* usage_entry_info, bool* lru_upgrade);
std::vector<CdmUsageEntryInfo>* usage_entry_info, bool* lru_upgrade,
bool* has_usage_info_entries);
virtual bool DeleteUsageTableInfo();

View File

@@ -261,10 +261,9 @@ class UsageTableHeader {
int64_t GetCurrentTime() { return clock_ref_->GetCurrentTime(); }
// Sets LRU related metrics based on the provided |staleness| (in
// seconds) and |storage_type| of the entry removed.
// seconds).
void RecordLruEventMetrics(metrics::CryptoMetrics* metrics,
uint64_t staleness,
CdmUsageEntryStorageType storage_type);
uint64_t staleness);
// Uses an LRU-base algorithm to determine which license should be
// removed. This is intended to be used if the usage table is full

View File

@@ -1678,11 +1678,13 @@ bool DeviceFiles::StoreUsageTableInfo(
bool DeviceFiles::RetrieveUsageTableInfo(
CdmUsageTableHeader* usage_table_header,
std::vector<CdmUsageEntryInfo>* usage_entry_info, bool* lru_upgrade) {
std::vector<CdmUsageEntryInfo>* usage_entry_info, bool* lru_upgrade,
bool* has_usage_info_entries) {
RETURN_FALSE_IF_UNINITIALIZED();
RETURN_FALSE_IF_NULL(usage_table_header);
RETURN_FALSE_IF_NULL(usage_entry_info);
RETURN_FALSE_IF_NULL(lru_upgrade);
RETURN_FALSE_IF_NULL(has_usage_info_entries);
video_widevine_client::sdk::File file;
if (RetrieveHashedFile(GetUsageTableFileName(), &file) != kNoError) {
@@ -1712,6 +1714,7 @@ bool DeviceFiles::RetrieveUsageTableInfo(
const UsageTableInfo& usage_table_info = file.usage_table_info();
*lru_upgrade = !usage_table_info.use_lru();
*has_usage_info_entries = false;
*usage_table_header = usage_table_info.usage_table_header();
usage_entry_info->resize(usage_table_info.usage_entry_info_size());
@@ -1727,10 +1730,8 @@ bool DeviceFiles::RetrieveUsageTableInfo(
info.offline_license_expiry_time();
break;
case UsageTableInfo_UsageEntryInfo_UsageEntryStorage_USAGE_INFO:
(*usage_entry_info)[i].storage_type = kStorageUsageInfo;
(*usage_entry_info)[i].usage_info_file_name =
info.usage_info_file_name();
(*usage_entry_info)[i].last_use_time = info.last_use_time();
(*usage_entry_info)[i].storage_type = kStorageTypeUnknown;
*has_usage_info_entries = true;
break;
case UsageTableInfo_UsageEntryInfo_UsageEntryStorage_UNKNOWN:
default:

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;
@@ -194,8 +159,10 @@ bool UsageTableHeader::Init(CdmSecurityLevel security_level,
bool UsageTableHeader::RestoreTable(CryptoSession* const crypto_session) {
bool run_lru_upgrade = false;
bool has_usage_info_entries = false;
if (!device_files_->RetrieveUsageTableInfo(
&usage_table_header_, &usage_entry_info_, &run_lru_upgrade)) {
&usage_table_header_, &usage_entry_info_, &run_lru_upgrade,
&has_usage_info_entries)) {
LOGW("Could not retrieve usage table");
return false;
}
@@ -210,6 +177,15 @@ bool UsageTableHeader::RestoreTable(CryptoSession* const crypto_session) {
return false;
}
// Remove all usage info entries from storage and clear their
// table meta data.
if (has_usage_info_entries) {
LOGI("Removing all usage info entries");
device_files_->DeleteAllUsageInfo();
// Store table to remove usage info entries from storage.
StoreTable();
}
// If the saved usage entries/meta data is missing LRU information,
// then the entries and their meta data must be updated.
if (run_lru_upgrade && !LruUpgradeAllUsageEntries()) {
@@ -1152,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,
@@ -1165,7 +1140,7 @@ CdmResponseType UsageTableHeader::ReleaseOldestEntry(
}
// Record metrics on success.
RecordLruEventMetrics(metrics, staleness, storage_type);
RecordLruEventMetrics(metrics, staleness);
return NO_ERROR;
}
@@ -1198,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);
@@ -1254,7 +1211,6 @@ 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
@@ -1268,9 +1224,6 @@ bool UsageTableHeader::LruUpgradeAllUsageEntries() {
usage_entry_info.offline_license_expiry_time =
license.license_start_time() + policy.license_duration_seconds();
}
} else {
usage_entry_info.offline_license_expiry_time = 0;
}
} // End for loop.
if (bad_license_file_entries.size() == usage_entry_info_.size()) {
@@ -1279,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;
}
@@ -1316,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.
@@ -1348,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();
@@ -1363,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(
@@ -1413,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) {

View File

@@ -3713,8 +3713,7 @@ const UsageTableTestInfo kUsageTableInfoTestData[] = {
};
const CdmUsageEntryInfo kUsageEntriesWithoutLruData[] = {
{kStorageLicense, "ksid0", "", 0, 0},
{kStorageUsageInfo, "", "app_id_1", 0, 0}};
{kStorageLicense, "ksid0", "", 0, 0}, {kStorageTypeUnknown, "", "", 0, 0}};
const std::string kUsageTableWithoutLruData = a2bs_hex(
"0A1F080510013A191209080112056B73696430120C08021A086170705F69645F"
@@ -5815,13 +5814,21 @@ TEST_P(DeviceFilesUsageTableTest, Read) {
std::vector<CdmUsageEntryInfo> usage_entry_info;
CdmUsageTableHeader usage_table_header;
bool lru_upgrade;
bool has_usage_info_entries;
ASSERT_TRUE(device_files.RetrieveUsageTableInfo(
&usage_table_header, &usage_entry_info, &lru_upgrade));
&usage_table_header, &usage_entry_info, &lru_upgrade,
&has_usage_info_entries));
EXPECT_EQ(kUsageTableInfoTestData[index].usage_table_header,
usage_table_header);
EXPECT_EQ(index + 1u, usage_entry_info.size());
for (size_t i = 0; i <= index; ++i) {
// TODO(b/242289743): Update test data to exclude usage info files.
if (kUsageEntriesTestData[i].storage_type == kStorageUsageInfo) {
// Usage info entry types are no longer loaded.
EXPECT_EQ(usage_entry_info[i].storage_type, kStorageTypeUnknown);
continue;
}
EXPECT_EQ(kUsageEntriesTestData[i].storage_type,
usage_entry_info[i].storage_type);
EXPECT_EQ(kUsageEntriesTestData[i].key_set_id,
@@ -5863,8 +5870,10 @@ TEST_F(DeviceFilesUsageTableTest, ReadWithoutLruData) {
std::vector<CdmUsageEntryInfo> usage_entry_info;
CdmUsageTableHeader usage_table_header;
bool lru_upgrade;
bool has_usage_info_entries;
ASSERT_TRUE(device_files.RetrieveUsageTableInfo(
&usage_table_header, &usage_entry_info, &lru_upgrade));
&usage_table_header, &usage_entry_info, &lru_upgrade,
&has_usage_info_entries));
EXPECT_EQ(ArraySize(kUsageEntriesWithoutLruData), usage_entry_info.size());

File diff suppressed because it is too large Load Diff