Handle unlimited usage table capacity.
[ Merge of http://go/wvgerrit/102945 ] The OEMCrypto method for usage table capacity can return zero to indicate that the usage table size is not explicitly limited. The CDM must handle this case with regard to the CDM's usage table management and information querying. The usage table initialization tests are extended to include cases where the table does not have a defined limit. AddEntry() was missing call to update the usage table header after creating a new usage entry. This call is now included and required additional changes to the usage table unit tests. Bug: 160560364 Test: Android unit tests Change-Id: Ica5d181092d2938d24deba5005a211ca883cb0f0
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
@@ -696,6 +697,12 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
LOGW("GetMaxUsageTableEntries failed");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
if (max_number_of_usage_entries == 0) {
|
||||
// Zero indicates that the table is dynamically allocated and does
|
||||
// not have a defined limit. Setting to max value of int32_t to
|
||||
// be able to fit into a Java int.
|
||||
max_number_of_usage_entries = std::numeric_limits<int32_t>::max();
|
||||
}
|
||||
*query_response = std::to_string(max_number_of_usage_entries);
|
||||
return NO_ERROR;
|
||||
} else if (query_token == QUERY_KEY_OEMCRYPTO_API_MINOR_VERSION) {
|
||||
|
||||
@@ -2008,6 +2008,11 @@ bool CryptoSession::GetMaximumUsageTableEntries(SecurityLevel security_level,
|
||||
metrics_->oemcrypto_maximum_usage_table_header_size_.Record(
|
||||
*number_of_entries);
|
||||
|
||||
if (*number_of_entries == 0) {
|
||||
// Special value, indicating that the table size is not directly
|
||||
// limited.
|
||||
return true;
|
||||
}
|
||||
return *number_of_entries >= kMinimumUsageTableEntriesSupported;
|
||||
}
|
||||
|
||||
|
||||
@@ -176,13 +176,23 @@ bool UsageTableHeader::Init(CdmSecurityLevel security_level,
|
||||
|
||||
if (!crypto_session->GetMaximumUsageTableEntries(
|
||||
requested_security_level_, &potential_table_capacity_)) {
|
||||
LOGW(
|
||||
"Could not determine usage table capacity, assuming default: "
|
||||
"default = %zu",
|
||||
kMinimumUsageTableEntriesSupported);
|
||||
potential_table_capacity_ = kMinimumUsageTableEntriesSupported;
|
||||
} else if (potential_table_capacity_ == 0) {
|
||||
LOGD("Usage table capacity is unlimited: security_level = %d",
|
||||
static_cast<int>(security_level));
|
||||
} else if (potential_table_capacity_ < kMinimumUsageTableEntriesSupported) {
|
||||
LOGW(
|
||||
"Reported usage table capacity is smaller than minimally required: "
|
||||
"capacity = %zu, minimum = %zu",
|
||||
potential_table_capacity_, kMinimumUsageTableEntriesSupported);
|
||||
potential_table_capacity_ = kMinimumUsageTableEntriesSupported;
|
||||
} else {
|
||||
LOGD("Usage table capacity: %zu, security_level = %d",
|
||||
potential_table_capacity_, static_cast<int>(security_level));
|
||||
}
|
||||
|
||||
if (!device_files_->Init(security_level)) {
|
||||
@@ -213,11 +223,21 @@ bool UsageTableHeader::Init(CdmSecurityLevel security_level,
|
||||
}
|
||||
}
|
||||
|
||||
// If the usage table header has been successfully loaded, and is at
|
||||
// minimum capacity (>200), we need to make sure we can still add and
|
||||
// remove entries. If not, clear files/data and recreate usage header table.
|
||||
// If the usage table header has been successfully loaded, and is
|
||||
// at minimum capacity (>200) or the table size does not have a
|
||||
// hard limit, we need to make sure we can still add and remove
|
||||
// entries. If not, clear files/data and recreate usage header
|
||||
// table.
|
||||
if (status == NO_ERROR && lru_success) {
|
||||
if (usage_entry_info_.size() > potential_table_capacity()) {
|
||||
if ((HasUnlimitedTableCapacity() &&
|
||||
usage_entry_info_.size() > kMinimumUsageTableEntriesSupported) ||
|
||||
(!HasUnlimitedTableCapacity() &&
|
||||
usage_entry_info_.size() > potential_table_capacity())) {
|
||||
LOGD("Checking if new entry can be added: size = %zu, capacity = %s",
|
||||
usage_entry_info_.size(),
|
||||
HasUnlimitedTableCapacity()
|
||||
? "unlimited"
|
||||
: std::to_string(potential_table_capacity()).c_str());
|
||||
uint32_t temporary_usage_entry_number;
|
||||
|
||||
// Create a new temporary usage entry, close the session and then
|
||||
@@ -359,6 +379,18 @@ CdmResponseType UsageTableHeader::AddEntry(
|
||||
}
|
||||
}
|
||||
|
||||
// Call to update the usage table header, but don't store the usage
|
||||
// entry. If the entry is used by the CDM, the CDM session will make
|
||||
// subsequent calls to update the usage entry and store that entry.
|
||||
std::string usage_entry;
|
||||
status = crypto_session->UpdateUsageEntry(&usage_table_header_, &usage_entry);
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to update new usage entry: usage_entry_number = %u",
|
||||
*usage_entry_number);
|
||||
usage_entry_info_[*usage_entry_number].Clear();
|
||||
return status;
|
||||
}
|
||||
|
||||
LOGI("New usage entry: usage_entry_number = %u", *usage_entry_number);
|
||||
StoreTable(device_files_.get());
|
||||
return NO_ERROR;
|
||||
@@ -1115,7 +1147,9 @@ bool UsageTableHeader::GetRemovalCandidate(uint32_t* entry_to_remove) {
|
||||
LOGI("Locking to determine removal candidates");
|
||||
std::unique_lock<std::mutex> auto_lock(usage_table_header_lock_);
|
||||
const size_t lru_unexpired_threshold =
|
||||
kLruUnexpiredThresholdFraction * potential_table_capacity();
|
||||
HasUnlimitedTableCapacity()
|
||||
? kLruUnexpiredThresholdFraction * size()
|
||||
: kLruUnexpiredThresholdFraction * potential_table_capacity();
|
||||
return DetermineLicenseToRemove(usage_entry_info_, GetCurrentTime(),
|
||||
lru_unexpired_threshold, entry_to_remove);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user