Update AddEntry() for usage table changes. am: 66e3d69300 am: 4c97abd57a am: c15d453a9d am: 7c56669a4f
Change-Id: Ic2cb6b4ead661ec1be3aabcf82c28cad2f7d37a5
This commit is contained in:
@@ -16,7 +16,6 @@ namespace wvcdm {
|
||||
|
||||
namespace {
|
||||
std::string kEmptyString;
|
||||
size_t kMaxCryptoRetries = 3;
|
||||
wvcdm::CdmKeySetId kDummyKeySetId = "DummyKsid";
|
||||
std::string kOldUsageEntryServerMacKey(wvcdm::MAC_KEY_SIZE, 0);
|
||||
std::string kOldUsageEntryClientMacKey(wvcdm::MAC_KEY_SIZE, 0);
|
||||
@@ -24,6 +23,7 @@ std::string kOldUsageEntryPoviderSessionToken =
|
||||
"nahZ6achSheiqua3TohQuei0ahwohv";
|
||||
constexpr int64_t kDefaultExpireDuration = 33 * 24 * 60 * 60; // 33 Days
|
||||
// Number of elements to be considered for removal using the LRU algorithm.
|
||||
// TODO(b/155230578): Remove this constant.
|
||||
constexpr size_t kLruRemovalSetSize = 3;
|
||||
// Fraction of table capacity of number of unexpired offline licenses
|
||||
// before they are considered to be removed. This could occur if
|
||||
@@ -132,6 +132,16 @@ bool RetrieveUsageInfoLicense(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;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
UsageTableHeader::UsageTableHeader()
|
||||
@@ -237,6 +247,13 @@ bool UsageTableHeader::Init(CdmSecurityLevel security_level,
|
||||
result = InvalidateEntry(temporary_usage_entry_number,
|
||||
/* defrag_table = */ true,
|
||||
device_files_.get(), metrics);
|
||||
if (usage_entry_info_.size() > temporary_usage_entry_number) {
|
||||
// The entry should have been deleted from the usage table,
|
||||
// not just marked as type unknown. Failure to call
|
||||
// Shrink() may be an indicator of other issues.
|
||||
LOGE("Temporary entry was not deleted");
|
||||
result = UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
if (result != NO_ERROR) {
|
||||
LOGE(
|
||||
@@ -284,66 +301,11 @@ CdmResponseType UsageTableHeader::AddEntry(
|
||||
CdmResponseType status = crypto_session->CreateUsageEntry(usage_entry_number);
|
||||
|
||||
if (status == INSUFFICIENT_CRYPTO_RESOURCES_3) {
|
||||
// If usage entry creation fails due to insufficient resources, release an
|
||||
// entry based on LRU.
|
||||
std::vector<uint32_t> removal_candidates;
|
||||
if (!GetRemovalCandidates(&removal_candidates)) {
|
||||
LOGE("Could not determine which license to remove");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Variables for metrics.
|
||||
const size_t usage_info_count =
|
||||
std::count_if(usage_entry_info_.cbegin(), usage_entry_info_.cend(),
|
||||
[](const CdmUsageEntryInfo& usage_entry) {
|
||||
return usage_entry.storage_type == kStorageUsageInfo;
|
||||
});
|
||||
const size_t license_count =
|
||||
std::count_if(usage_entry_info_.cbegin(), usage_entry_info_.cend(),
|
||||
[](const CdmUsageEntryInfo& usage_entry) {
|
||||
return usage_entry.storage_type == kStorageLicense;
|
||||
});
|
||||
int64_t staleness_of_removed;
|
||||
CdmUsageEntryStorageType storage_type_of_removed;
|
||||
const int64_t current_time = GetCurrentTime();
|
||||
|
||||
for (size_t i = 0; i < removal_candidates.size() &&
|
||||
status == INSUFFICIENT_CRYPTO_RESOURCES_3;
|
||||
++i) {
|
||||
const uint32_t entry_number_to_invalidate = removal_candidates[i];
|
||||
// Calculate metric values.
|
||||
staleness_of_removed =
|
||||
current_time -
|
||||
usage_entry_info_[entry_number_to_invalidate].last_use_time;
|
||||
storage_type_of_removed =
|
||||
usage_entry_info_[entry_number_to_invalidate].storage_type;
|
||||
|
||||
if (InvalidateEntry(entry_number_to_invalidate,
|
||||
/* defrag_table = */ true, device_files_.get(),
|
||||
metrics) == NO_ERROR) {
|
||||
// If the entry was deleted, it is still possible for the create new
|
||||
// entry to fail. If so, we must ensure that the previously last
|
||||
// entry was not in the |removal_candidates| as it has now been swapped
|
||||
// with the deleted entry.
|
||||
for (uint32_t& entry_number : removal_candidates) {
|
||||
if (entry_number == usage_entry_info_.size()) {
|
||||
entry_number = entry_number_to_invalidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOGW("Usage table may be full, releasing oldest entry: size = %zu",
|
||||
usage_entry_info_.size());
|
||||
status = ReleaseOldestEntry(metrics);
|
||||
if (status == NO_ERROR) {
|
||||
status = crypto_session->CreateUsageEntry(usage_entry_number);
|
||||
|
||||
// Record metrics on success.
|
||||
if (status == NO_ERROR) {
|
||||
metrics->usage_table_header_lru_usage_info_count_.Record(
|
||||
usage_info_count);
|
||||
metrics->usage_table_header_lru_offline_license_count_.Record(
|
||||
license_count);
|
||||
metrics->usage_table_header_lru_evicted_entry_staleness_.Record(
|
||||
staleness_of_removed);
|
||||
metrics->usage_table_header_lru_evicted_entry_type_.Record(
|
||||
static_cast<int>(storage_type_of_removed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,28 +384,9 @@ CdmResponseType UsageTableHeader::LoadEntry(CryptoSession* crypto_session,
|
||||
metrics::CryptoMetrics* metrics = crypto_session->GetCryptoMetrics();
|
||||
if (metrics == nullptr) metrics = &alternate_crypto_metrics_;
|
||||
|
||||
CdmResponseType status =
|
||||
const CdmResponseType status =
|
||||
crypto_session->LoadUsageEntry(usage_entry_number, usage_entry);
|
||||
|
||||
// If loading a usage entry fails due to insufficient resources, release a
|
||||
// random entry different from |usage_entry_number| and try again. If there
|
||||
// are no more entries to release, we fail.
|
||||
for (uint32_t retry_count = 0; retry_count < kMaxCryptoRetries &&
|
||||
status == INSUFFICIENT_CRYPTO_RESOURCES_3;
|
||||
++retry_count) {
|
||||
if (usage_entry_info_.size() <= 1) break;
|
||||
// Get a random entry from the other entries.
|
||||
uint32_t entry_number_to_invalidate =
|
||||
CdmRandom::RandomInRange(usage_entry_info_.size() - 2);
|
||||
if (entry_number_to_invalidate >= usage_entry_number) {
|
||||
// Exclude |usage_entry_number|.
|
||||
++entry_number_to_invalidate;
|
||||
}
|
||||
InvalidateEntry(entry_number_to_invalidate, /* defrag_table = */ true,
|
||||
device_files_.get(), metrics);
|
||||
status = crypto_session->LoadUsageEntry(usage_entry_number, usage_entry);
|
||||
}
|
||||
|
||||
if (status == NO_ERROR) {
|
||||
usage_entry_info_[usage_entry_number].last_use_time = GetCurrentTime();
|
||||
}
|
||||
@@ -518,6 +461,20 @@ CdmResponseType UsageTableHeader::InvalidateEntry(
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
size_t UsageTableHeader::UsageInfoCount() const {
|
||||
LOGI("Locking to count usage info (streaming license) entries");
|
||||
std::unique_lock<std::mutex> auto_lock(usage_table_header_lock_);
|
||||
return std::count_if(usage_entry_info_.cbegin(), usage_entry_info_.cend(),
|
||||
EntryIsUsageInfo);
|
||||
}
|
||||
|
||||
size_t UsageTableHeader::OfflineEntryCount() const {
|
||||
LOGI("Locking to count offline license entries");
|
||||
std::unique_lock<std::mutex> auto_lock(usage_table_header_lock_);
|
||||
return std::count_if(usage_entry_info_.cbegin(), usage_entry_info_.cend(),
|
||||
EntryIsOfflineLicense);
|
||||
}
|
||||
|
||||
CdmResponseType UsageTableHeader::MoveEntry(
|
||||
uint32_t from_usage_entry_number, const CdmUsageEntry& from_usage_entry,
|
||||
uint32_t to_usage_entry_number, DeviceFiles* device_files,
|
||||
@@ -986,6 +943,40 @@ CdmResponseType UsageTableHeader::DefragTable(DeviceFiles* device_files,
|
||||
return Shrink(metrics, to_remove);
|
||||
} // End Defrag().
|
||||
|
||||
CdmResponseType UsageTableHeader::ReleaseOldestEntry(
|
||||
metrics::CryptoMetrics* metrics) {
|
||||
LOGV("Releasing oldest entry");
|
||||
std::vector<uint32_t> removal_candidates;
|
||||
if (!GetRemovalCandidates(&removal_candidates)) {
|
||||
LOGE("Could not determine which license to remove");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
// Only release one entry.
|
||||
const uint32_t entry_number_to_delete = removal_candidates.front();
|
||||
const CdmUsageEntryInfo& usage_entry_info =
|
||||
usage_entry_info_[entry_number_to_delete];
|
||||
|
||||
const int64_t current_time = GetCurrentTime();
|
||||
// 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 =
|
||||
InvalidateEntry(entry_number_to_delete, /* defrag_table = */ true,
|
||||
device_files_.get(), metrics);
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to invalidate oldest entry: status = %d",
|
||||
static_cast<int>(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
// Record metrics on success.
|
||||
RecordLruEventMetrics(metrics, staleness, storage_type);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// Test only method.
|
||||
void UsageTableHeader::InvalidateEntryForTest(uint32_t usage_entry_number) {
|
||||
LOGV("Deleting entry for test: usage_entry_number = %u", usage_entry_number);
|
||||
@@ -1135,7 +1126,20 @@ bool UsageTableHeader::GetRemovalCandidates(
|
||||
removal_candidates);
|
||||
}
|
||||
|
||||
void UsageTableHeader::RecordLruEventMetrics(
|
||||
metrics::CryptoMetrics* metrics, uint64_t staleness,
|
||||
CdmUsageEntryStorageType storage_type) {
|
||||
if (metrics == nullptr) return;
|
||||
metrics->usage_table_header_lru_usage_info_count_.Record(UsageInfoCount());
|
||||
metrics->usage_table_header_lru_offline_license_count_.Record(
|
||||
OfflineEntryCount());
|
||||
metrics->usage_table_header_lru_evicted_entry_staleness_.Record(staleness);
|
||||
metrics->usage_table_header_lru_evicted_entry_type_.Record(
|
||||
static_cast<int>(storage_type));
|
||||
}
|
||||
|
||||
// Static.
|
||||
// TODO(b/155230578): Change this function to only return 1 entry.
|
||||
bool UsageTableHeader::DetermineLicenseToRemove(
|
||||
const std::vector<CdmUsageEntryInfo>& usage_entry_info_list,
|
||||
int64_t current_time, size_t unexpired_threshold, size_t removal_count,
|
||||
|
||||
Reference in New Issue
Block a user