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:
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user