Check for open session when initializing usage table. am: 023b06eded
Original change: https://googleplex-android-review.googlesource.com/c/platform/vendor/widevine/+/14296026 Change-Id: I4b0b46d585f99c492e30e608a0a18708fc40b042
This commit is contained in:
@@ -293,7 +293,7 @@ class CryptoSession {
|
||||
// exist as long as the new CryptoSession exists.
|
||||
explicit CryptoSession(metrics::CryptoMetrics* crypto_metrics);
|
||||
|
||||
int session_count() { return session_count_; }
|
||||
int session_count() const { return session_count_; }
|
||||
|
||||
private:
|
||||
friend class CryptoSessionForTest;
|
||||
@@ -313,6 +313,13 @@ class CryptoSession {
|
||||
}
|
||||
|
||||
void Init();
|
||||
|
||||
// Will set up the UsageTableHeader for this session. This may require
|
||||
// creating a new UsageTableHeader if the global instance has not
|
||||
// been initialized.
|
||||
// Note: This function will lock the global static field lock in write mode.
|
||||
bool SetUpUsageTableHeader(SecurityLevel requested_security_level);
|
||||
|
||||
CdmResponseType GetTokenFromKeybox(std::string* token);
|
||||
CdmResponseType GetTokenFromOemCert(std::string* token);
|
||||
static bool ExtractSystemIdFromOemCert(const std::string& oem_cert,
|
||||
@@ -355,9 +362,15 @@ class CryptoSession {
|
||||
// These methods should be used to take the various CryptoSession mutexes in
|
||||
// preference to taking the mutexes directly.
|
||||
//
|
||||
// A lock should be taken on the Static Field Mutex before accessing any of
|
||||
// CryptoSession's non-atomic static fields. It can be taken as a reader or as
|
||||
// a writer, depending on how you will be accessing the static fields.
|
||||
// A lock should be taken on the Static Field Mutex before accessing
|
||||
// any of CryptoSession's non-atomic static fields with the exception
|
||||
// of the Usage Table Mutex. The Static Field Mutex can be taken as
|
||||
// a reader or as a writer, depending on how you will be accessing
|
||||
// the static fields. The Usage Table Mutex should be taken when
|
||||
// reading and writing to the static usage table fields (creating,
|
||||
// destroying or taking a pointer of the handles). The purpose of
|
||||
// having a separate mutex for usage table is due to the recursive
|
||||
// nature of initializing the global usage table.
|
||||
//
|
||||
// Before calling into OEMCrypto, code must take locks on the OEMCrypto Mutex
|
||||
// and/or the OEMCrypto Session Mutex. Which of them should be taken and how
|
||||
@@ -414,6 +427,9 @@ class CryptoSession {
|
||||
static shared_mutex static_field_mutex_;
|
||||
static shared_mutex oem_crypto_mutex_;
|
||||
std::mutex oem_crypto_session_mutex_;
|
||||
// Usage table mutex used only when performing write operations on
|
||||
// the static usage table pointers.
|
||||
static std::recursive_mutex usage_table_mutex_;
|
||||
|
||||
static bool initialized_;
|
||||
static int session_count_;
|
||||
@@ -446,8 +462,10 @@ class CryptoSession {
|
||||
// Open session-cached result of OEMCrypto_SupportsUsageTable().
|
||||
CachedBooleanProperty has_usage_info_support_ = kBooleanUnset;
|
||||
UsageTableHeader* usage_table_header_ = nullptr;
|
||||
static UsageTableHeader* usage_table_header_l1_;
|
||||
static UsageTableHeader* usage_table_header_l3_;
|
||||
// These fields are protected by |usage_table_mutex_| and not
|
||||
// |static_field_mutex_|.
|
||||
static std::unique_ptr<UsageTableHeader> usage_table_header_l1_;
|
||||
static std::unique_ptr<UsageTableHeader> usage_table_header_l3_;
|
||||
|
||||
std::string request_id_;
|
||||
static std::atomic<uint64_t> request_id_index_source_;
|
||||
|
||||
@@ -53,8 +53,12 @@ class UsageTableHeader {
|
||||
UsageTableHeader();
|
||||
virtual ~UsageTableHeader() {}
|
||||
|
||||
// |crypto_session| is used to create or load a usage master table and
|
||||
// not cached beyound this call.
|
||||
// |crypto_session| is used to create or load a usage master table
|
||||
// and not cached beyound this call.
|
||||
// First attempts to restore the usage table from the device files.
|
||||
// If restoring fails, then a new usage table is created.
|
||||
// Note: No OEMCrypto session for the same security level should be
|
||||
// opened before calling.
|
||||
bool Init(CdmSecurityLevel security_level, CryptoSession* crypto_session);
|
||||
|
||||
// |persistent_license| false indicates usage info record
|
||||
@@ -125,6 +129,32 @@ class UsageTableHeader {
|
||||
}
|
||||
|
||||
private:
|
||||
// == Initialization methods ==
|
||||
// These should only be called during table initialization.
|
||||
// All parameters are assumed valid.
|
||||
|
||||
// Creates a new, empty usage table. Any existing usage table files
|
||||
// will be deleted.
|
||||
bool CreateNewTable(CryptoSession* const crypto_session);
|
||||
// Attempts to restore the usage table from persistent storage, and
|
||||
// loads the usage table header into OEMCrypto.
|
||||
// Note: No other OEMCrypto session should be opened before calling.
|
||||
bool RestoreTable(CryptoSession* const crypto_session);
|
||||
|
||||
// Performs a check that there are no open OEMCrypto sessions for
|
||||
// the current security level of the usage table.
|
||||
bool OpenSessionCheck(CryptoSession* const crypto_session);
|
||||
// Performs a check that the OEMCrypto table can support at least
|
||||
// one more entry if the table is at or near the reported capacity.
|
||||
// If this check fails, a new usage table SHOULD be created.
|
||||
bool CapacityCheck(CryptoSession* const crypto_session);
|
||||
|
||||
// Attempts to determine the capacity of the OEMCrypto usage table.
|
||||
// Sets the result to |potential_table_capacity_|.
|
||||
bool DetermineTableCapacity(CryptoSession* crypto_session);
|
||||
|
||||
// == Table operation methods ==
|
||||
|
||||
CdmResponseType MoveEntry(uint32_t from /* usage entry number */,
|
||||
const CdmUsageEntry& from_usage_entry,
|
||||
uint32_t to /* usage entry number */,
|
||||
@@ -153,8 +183,6 @@ class UsageTableHeader {
|
||||
// evicted.
|
||||
CdmResponseType ReleaseOldestEntry(metrics::CryptoMetrics* metrics);
|
||||
|
||||
virtual bool is_inited() { return is_inited_; }
|
||||
|
||||
// Performs and LRU upgrade on all loaded CdmUsageEntryInfo from a
|
||||
// device file that had not yet been upgraded to use the LRU data.
|
||||
virtual bool LruUpgradeAllUsageEntries();
|
||||
@@ -213,16 +241,15 @@ class UsageTableHeader {
|
||||
// by CdmSession.
|
||||
std::unique_ptr<DeviceFiles> device_files_;
|
||||
std::unique_ptr<FileSystem> file_system_;
|
||||
CdmSecurityLevel security_level_;
|
||||
SecurityLevel requested_security_level_;
|
||||
CdmSecurityLevel security_level_ = kSecurityLevelUninitialized;
|
||||
SecurityLevel requested_security_level_ = kLevelDefault;
|
||||
|
||||
CdmUsageTableHeader usage_table_header_;
|
||||
std::vector<CdmUsageEntryInfo> usage_entry_info_;
|
||||
|
||||
// Lock to ensure that a single object is created for each security level
|
||||
// and data member to represent whether an object has been correctly
|
||||
// initialized.
|
||||
bool is_inited_;
|
||||
// Table is sync with persistent storage and can be used by the CDM
|
||||
// to interact with OEMCrypto.
|
||||
bool is_initialized_ = false;
|
||||
|
||||
// Synchonizes access to the Usage Table Header and bookkeeping
|
||||
// data-structures
|
||||
|
||||
@@ -51,8 +51,9 @@
|
||||
}
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
namespace {
|
||||
using UsageTableLock = std::unique_lock<std::recursive_mutex>;
|
||||
|
||||
constexpr size_t KiB = 1024;
|
||||
constexpr size_t MiB = 1024 * 1024;
|
||||
|
||||
@@ -166,20 +167,22 @@ size_t GenericEncryptionBlockSize(CdmEncryptionAlgorithm algorithm) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// CryptoSession variables allocation.
|
||||
shared_mutex CryptoSession::static_field_mutex_;
|
||||
shared_mutex CryptoSession::oem_crypto_mutex_;
|
||||
bool CryptoSession::initialized_ = false;
|
||||
int CryptoSession::session_count_ = 0;
|
||||
int CryptoSession::termination_counter_ = 0;
|
||||
UsageTableHeader* CryptoSession::usage_table_header_l1_ = nullptr;
|
||||
UsageTableHeader* CryptoSession::usage_table_header_l3_ = nullptr;
|
||||
std::unique_ptr<UsageTableHeader> CryptoSession::usage_table_header_l1_;
|
||||
std::unique_ptr<UsageTableHeader> CryptoSession::usage_table_header_l3_;
|
||||
std::recursive_mutex CryptoSession::usage_table_mutex_;
|
||||
std::atomic<uint64_t> CryptoSession::request_id_index_source_(0);
|
||||
|
||||
size_t GetOffset(std::string message, std::string field) {
|
||||
size_t pos = message.find(field);
|
||||
if (pos == std::string::npos) {
|
||||
LOGE("Cannot find the |field| offset in message: field = %s",
|
||||
field.c_str());
|
||||
IdToString(field));
|
||||
pos = 0;
|
||||
}
|
||||
return pos;
|
||||
@@ -195,7 +198,7 @@ OEMCrypto_Substring GetSubstring(const std::string& message,
|
||||
size_t pos = message.find(field);
|
||||
if (pos == std::string::npos) {
|
||||
LOGW("Cannot find the |field| substring in message: field = %s",
|
||||
field.c_str());
|
||||
IdToString(field));
|
||||
substring.offset = 0;
|
||||
substring.length = 0;
|
||||
} else {
|
||||
@@ -359,7 +362,7 @@ void CryptoSession::Init() {
|
||||
|
||||
bool CryptoSession::TryTerminate() {
|
||||
LOGV("Terminating crypto session");
|
||||
WithStaticFieldWriteLock("TryTerminate", [&] {
|
||||
const bool terminated = WithStaticFieldWriteLock("TryTerminate", [&] {
|
||||
LOGV(
|
||||
"Terminating crypto session: initialized_ = %s, session_count_ = %d, "
|
||||
"termination_counter_ = %d",
|
||||
@@ -371,25 +374,20 @@ bool CryptoSession::TryTerminate() {
|
||||
if (session_count_ > 0 || termination_counter_ > 0 || !initialized_)
|
||||
return false;
|
||||
|
||||
OEMCryptoResult sts;
|
||||
WithOecWriteLock("Terminate", [&] { sts = OEMCrypto_Terminate(); });
|
||||
const OEMCryptoResult sts =
|
||||
WithOecWriteLock("Terminate", [&] { return OEMCrypto_Terminate(); });
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
LOGE("OEMCrypto_Terminate failed: status = %d", static_cast<int>(sts));
|
||||
}
|
||||
|
||||
if (usage_table_header_l1_ != nullptr) {
|
||||
delete usage_table_header_l1_;
|
||||
usage_table_header_l1_ = nullptr;
|
||||
}
|
||||
if (usage_table_header_l3_ != nullptr) {
|
||||
delete usage_table_header_l3_;
|
||||
usage_table_header_l3_ = nullptr;
|
||||
}
|
||||
|
||||
initialized_ = false;
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
if (terminated) {
|
||||
UsageTableLock lock(usage_table_mutex_);
|
||||
usage_table_header_l1_.reset();
|
||||
usage_table_header_l3_.reset();
|
||||
}
|
||||
return terminated;
|
||||
}
|
||||
|
||||
void CryptoSession::DisableDelayedTermination() {
|
||||
@@ -398,7 +396,63 @@ void CryptoSession::DisableDelayedTermination() {
|
||||
[&] { termination_counter_ = 0; });
|
||||
}
|
||||
|
||||
bool CryptoSession::SetUpUsageTableHeader(
|
||||
SecurityLevel requested_security_level) {
|
||||
if (usage_table_header_ != nullptr) {
|
||||
LOGE("Usage table is already set up for the current crypto session");
|
||||
return false;
|
||||
}
|
||||
const CdmSecurityLevel security_level =
|
||||
GetSecurityLevel(requested_security_level);
|
||||
if (security_level != kSecurityLevelL1 &&
|
||||
security_level != kSecurityLevelL3) {
|
||||
LOGD("Unsupported security level for usage support: security_level = %d",
|
||||
static_cast<int>(security_level));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if usage support is available.
|
||||
bool supports_usage_table = false;
|
||||
if (!HasUsageInfoSupport(requested_security_level, &supports_usage_table)) {
|
||||
metrics_->oemcrypto_usage_table_support_.SetError(
|
||||
USAGE_INFORMATION_SUPPORT_FAILED);
|
||||
return false;
|
||||
}
|
||||
metrics_->oemcrypto_usage_table_support_.Record(
|
||||
supports_usage_table ? kUsageEntrySupport : kNonSecureUsageSupport);
|
||||
if (!supports_usage_table) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGV("Usage table lock: SetUpUsageTableHeader()");
|
||||
UsageTableLock auto_lock(usage_table_mutex_);
|
||||
// TODO(b/141350978): Prevent any recursive logic.
|
||||
|
||||
// Manipulate only the usage table for the requested security level.
|
||||
std::unique_ptr<UsageTableHeader>& header = security_level == kSecurityLevelL1
|
||||
? usage_table_header_l1_
|
||||
: usage_table_header_l3_;
|
||||
if (!header) {
|
||||
// This may be called twice within the same thread when the table
|
||||
// is initialized. On the second call |header| will not be null,
|
||||
// causing this block to be skipped.
|
||||
header.reset(new UsageTableHeader());
|
||||
if (!header->Init(security_level, this)) {
|
||||
LOGE("Failed to initialize and sync usage usage table");
|
||||
// Must be cleared globally to prevent the next session to be
|
||||
// opened from using the invalid UsageTableHeader.
|
||||
header.reset();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
usage_table_header_ = header.get();
|
||||
metrics_->usage_table_header_initial_size_.Record(
|
||||
usage_table_header_->size());
|
||||
return true;
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::GetTokenFromKeybox(std::string* token) {
|
||||
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
|
||||
RETURN_IF_NULL(token, PARAMETER_NULL);
|
||||
|
||||
std::string temp_buffer(KEYBOX_KEY_DATA_SIZE, '\0');
|
||||
@@ -422,6 +476,7 @@ CdmResponseType CryptoSession::GetTokenFromKeybox(std::string* token) {
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::GetTokenFromOemCert(std::string* token) {
|
||||
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
|
||||
RETURN_IF_NULL(token, PARAMETER_NULL);
|
||||
|
||||
OEMCryptoResult status;
|
||||
@@ -752,9 +807,16 @@ uint8_t CryptoSession::GetSecurityPatchLevel() {
|
||||
CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
|
||||
LOGD("Opening crypto session: requested_security_level = %s",
|
||||
SecurityLevelToString(requested_security_level));
|
||||
RETURN_IF_UNINITIALIZED(UNKNOWN_ERROR);
|
||||
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
|
||||
if (open_) return NO_ERROR;
|
||||
|
||||
if (!SetUpUsageTableHeader(requested_security_level)) {
|
||||
// Ignore errors since we do not know when a session is opened,
|
||||
// if it is intended to be used for offline/usage session related
|
||||
// or otherwise.
|
||||
LOGW("Session opened without a usage table");
|
||||
}
|
||||
|
||||
CdmResponseType result = GetProvisioningMethod(requested_security_level,
|
||||
&pre_provision_token_type_);
|
||||
if (result != NO_ERROR) return result;
|
||||
@@ -817,70 +879,10 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
|
||||
key_session_.reset(new ContentKeySession(oec_session_id_, metrics_));
|
||||
});
|
||||
|
||||
// Set up Usage Table support
|
||||
//
|
||||
// This MUST be the last thing in the function because it contains the
|
||||
// successful return paths of the function. It will attempt to initialize
|
||||
// usage tables. However, whether they are employed is determined by
|
||||
// information in the license, which will not be received until later. In case
|
||||
// usage tables are not even needed, initialization errors here are ignored by
|
||||
// returning successfully.
|
||||
//
|
||||
// TODO(b/141350978): Refactor this code so that it does not have this
|
||||
// problem.
|
||||
if (!GetApiVersion(&api_version_)) {
|
||||
LOGE("Failed to get API version");
|
||||
return USAGE_SUPPORT_GET_API_FAILED;
|
||||
}
|
||||
|
||||
bool supports_usage_table = false;
|
||||
if (HasUsageInfoSupport(&supports_usage_table)) {
|
||||
metrics_->oemcrypto_usage_table_support_.Record(
|
||||
supports_usage_table ? kUsageEntrySupport : kNonSecureUsageSupport);
|
||||
if (supports_usage_table) {
|
||||
CdmSecurityLevel security_level = GetSecurityLevel();
|
||||
if (security_level == kSecurityLevelL1 ||
|
||||
security_level == kSecurityLevelL3) {
|
||||
// This block cannot use |WithStaticFieldWriteLock| because it needs
|
||||
// to unlock the lock partway through.
|
||||
LOGV("Static field write lock: Open() initializing usage table");
|
||||
std::unique_lock<shared_mutex> auto_lock(static_field_mutex_);
|
||||
|
||||
UsageTableHeader** header = security_level == kSecurityLevelL1
|
||||
? &usage_table_header_l1_
|
||||
: &usage_table_header_l3_;
|
||||
if (*header == nullptr) {
|
||||
*header = new UsageTableHeader();
|
||||
// Ignore errors since we do not know when a session is opened,
|
||||
// if it is intended to be used for offline/usage session related
|
||||
// or otherwise.
|
||||
auto_lock.unlock();
|
||||
bool is_usage_table_header_inited =
|
||||
(*header)->Init(security_level, this);
|
||||
auto_lock.lock();
|
||||
if (!is_usage_table_header_inited) {
|
||||
delete *header;
|
||||
*header = nullptr;
|
||||
usage_table_header_ = nullptr;
|
||||
return NO_ERROR;
|
||||
}
|
||||
}
|
||||
usage_table_header_ = *header;
|
||||
metrics_->usage_table_header_initial_size_.Record((*header)->size());
|
||||
} // End |static_field_mutex_| block.
|
||||
}
|
||||
} else {
|
||||
metrics_->oemcrypto_usage_table_support_.SetError(
|
||||
USAGE_INFORMATION_SUPPORT_FAILED);
|
||||
}
|
||||
|
||||
// Do not add logic after this point as it may never get exercised. In the
|
||||
// event of errors initializing the usage tables, the code will return early,
|
||||
// never reaching this point. See the comment above the "Set up Usage Table
|
||||
// support" section for details.
|
||||
//
|
||||
// TODO(b/139973602): Refactor this code.
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -889,13 +891,13 @@ void CryptoSession::Close() {
|
||||
open_ ? "true" : "false");
|
||||
if (!open_) return;
|
||||
|
||||
OEMCryptoResult close_sts;
|
||||
WithOecWriteLock(
|
||||
"Close", [&] { close_sts = OEMCrypto_CloseSession(oec_session_id_); });
|
||||
const OEMCryptoResult close_sts = WithOecWriteLock(
|
||||
"Close", [&] { return OEMCrypto_CloseSession(oec_session_id_); });
|
||||
metrics_->oemcrypto_close_session_.Increment(close_sts);
|
||||
|
||||
// Clear cached values.
|
||||
has_usage_info_support_ = kBooleanUnset;
|
||||
oem_token_.clear();
|
||||
|
||||
if (close_sts != OEMCrypto_SUCCESS) {
|
||||
LOGW("OEMCrypto_CloseSession failed: status = %d",
|
||||
@@ -905,6 +907,7 @@ void CryptoSession::Close() {
|
||||
case OEMCrypto_SUCCESS:
|
||||
case OEMCrypto_ERROR_INVALID_SESSION:
|
||||
case OEMCrypto_ERROR_SYSTEM_INVALIDATED:
|
||||
usage_table_header_ = nullptr;
|
||||
open_ = false;
|
||||
break;
|
||||
case OEMCrypto_ERROR_CLOSE_SESSION_FAILED:
|
||||
@@ -2488,14 +2491,13 @@ CdmResponseType CryptoSession::LoadUsageTableHeader(
|
||||
LOGV("Loading usage table header: requested_security_level = %s",
|
||||
SecurityLevelToString(requested_security_level));
|
||||
|
||||
OEMCryptoResult result;
|
||||
WithOecWriteLock("LoadUsageTableHeader", [&] {
|
||||
result = OEMCrypto_LoadUsageTableHeader(
|
||||
const OEMCryptoResult result = WithOecWriteLock("LoadUsageTableHeader", [&] {
|
||||
return OEMCrypto_LoadUsageTableHeader(
|
||||
requested_security_level,
|
||||
reinterpret_cast<const uint8_t*>(usage_table_header.data()),
|
||||
usage_table_header.size());
|
||||
metrics_->oemcrypto_load_usage_table_header_.Increment(result);
|
||||
});
|
||||
metrics_->oemcrypto_load_usage_table_header_.Increment(result);
|
||||
|
||||
if (result != OEMCrypto_SUCCESS) {
|
||||
if (result == OEMCrypto_WARNING_GENERATION_SKEW) {
|
||||
|
||||
@@ -15,12 +15,9 @@
|
||||
|
||||
namespace wvcdm {
|
||||
namespace {
|
||||
std::string kEmptyString;
|
||||
wvcdm::CdmKeySetId kDummyKeySetId = "DummyKsid";
|
||||
std::string kOldUsageEntryServerMacKey(wvcdm::MAC_KEY_SIZE, 0);
|
||||
std::string kOldUsageEntryClientMacKey(wvcdm::MAC_KEY_SIZE, 0);
|
||||
std::string kOldUsageEntryPoviderSessionToken =
|
||||
"nahZ6achSheiqua3TohQuei0ahwohv";
|
||||
const std::string kEmptyString;
|
||||
const wvcdm::CdmKeySetId kDummyKeySetId = "DummyKsid";
|
||||
|
||||
constexpr int64_t kDefaultExpireDuration = 33 * 24 * 60 * 60; // 33 Days
|
||||
// Fraction of table capacity of number of unexpired offline licenses
|
||||
// before they are considered to be removed. This could occur if
|
||||
@@ -141,13 +138,19 @@ bool EntryIsOfflineLicense(const CdmUsageEntryInfo& info) {
|
||||
// Used for stl filters.
|
||||
return info.storage_type == kStorageLicense;
|
||||
}
|
||||
|
||||
bool IsValidCdmSecurityLevelForUsageInfo(CdmSecurityLevel security_level) {
|
||||
return security_level == kSecurityLevelL1 ||
|
||||
security_level == kSecurityLevelL3;
|
||||
}
|
||||
|
||||
SecurityLevel CdmSecurityLevelToRequestedLevel(
|
||||
CdmSecurityLevel security_level) {
|
||||
return security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
UsageTableHeader::UsageTableHeader()
|
||||
: security_level_(kSecurityLevelUninitialized),
|
||||
requested_security_level_(kLevelDefault),
|
||||
is_inited_(false),
|
||||
clock_ref_(&clock_) {
|
||||
UsageTableHeader::UsageTableHeader() : clock_ref_(&clock_) {
|
||||
file_system_.reset(new FileSystem());
|
||||
device_files_.reset(new DeviceFiles(file_system_.get()));
|
||||
}
|
||||
@@ -159,152 +162,89 @@ bool UsageTableHeader::Init(CdmSecurityLevel security_level,
|
||||
LOGE("No crypto session provided");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (security_level) {
|
||||
case kSecurityLevelL1:
|
||||
case kSecurityLevelL3:
|
||||
break;
|
||||
default:
|
||||
LOGE("Invalid security level provided: security_level = %d",
|
||||
static_cast<int>(security_level));
|
||||
return false;
|
||||
if (is_initialized_) {
|
||||
LOGE("Cannot reinitialize usage table: security_level = %s",
|
||||
CdmSecurityLevelToString(security_level));
|
||||
return false;
|
||||
}
|
||||
if (!IsValidCdmSecurityLevelForUsageInfo(security_level)) {
|
||||
LOGE("Invalid security level provided: security_level = %d",
|
||||
static_cast<int>(security_level));
|
||||
return false;
|
||||
}
|
||||
|
||||
security_level_ = security_level;
|
||||
requested_security_level_ =
|
||||
security_level_ == kSecurityLevelL3 ? kLevel3 : kLevelDefault;
|
||||
requested_security_level_ = CdmSecurityLevelToRequestedLevel(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 = %s",
|
||||
CdmSecurityLevelToString(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 = %s",
|
||||
potential_table_capacity_, CdmSecurityLevelToString(security_level));
|
||||
if (!OpenSessionCheck(crypto_session)) {
|
||||
return false;
|
||||
}
|
||||
if (!DetermineTableCapacity(crypto_session)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!device_files_->Init(security_level)) {
|
||||
LOGE("Failed to initialize device files");
|
||||
return false;
|
||||
}
|
||||
// Attempt restoring first, if unable to restore, then create a new
|
||||
// table.
|
||||
return RestoreTable(crypto_session) || CreateNewTable(crypto_session);
|
||||
}
|
||||
|
||||
CdmResponseType status = USAGE_INFO_NOT_FOUND;
|
||||
metrics::CryptoMetrics* metrics = crypto_session->GetCryptoMetrics();
|
||||
if (metrics == nullptr) metrics = &alternate_crypto_metrics_;
|
||||
|
||||
bool UsageTableHeader::RestoreTable(CryptoSession* const crypto_session) {
|
||||
bool run_lru_upgrade = false;
|
||||
if (device_files_->RetrieveUsageTableInfo(
|
||||
if (!device_files_->RetrieveUsageTableInfo(
|
||||
&usage_table_header_, &usage_entry_info_, &run_lru_upgrade)) {
|
||||
LOGI("Number of usage entries: %zu", usage_entry_info_.size());
|
||||
status = crypto_session->LoadUsageTableHeader(requested_security_level_,
|
||||
usage_table_header_);
|
||||
LOGW("Could not retrieve usage table");
|
||||
return false;
|
||||
}
|
||||
LOGI("Found usage table to restore: entry_count = %zu",
|
||||
usage_entry_info_.size());
|
||||
|
||||
bool lru_success = true;
|
||||
if (status == NO_ERROR && run_lru_upgrade) {
|
||||
// If the loaded table info does not contain LRU information, then
|
||||
// the information must be added immediately before being used.
|
||||
if (!LruUpgradeAllUsageEntries()) {
|
||||
LOGE(
|
||||
"Unable to init usage table header: "
|
||||
"Failed to perform LRU upgrade to usage entry table");
|
||||
lru_success = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 ((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
|
||||
// try to delete it.
|
||||
CdmResponseType result = NO_ERROR;
|
||||
{
|
||||
// |local_crypto_session| points to an object whose scope is this
|
||||
// method or a test object whose scope is the lifetime of this class
|
||||
std::unique_ptr<CryptoSession> scoped_crypto_session;
|
||||
CryptoSession* local_crypto_session = test_crypto_session_.get();
|
||||
if (local_crypto_session == nullptr) {
|
||||
scoped_crypto_session.reset(
|
||||
CryptoSession::MakeCryptoSession(metrics));
|
||||
local_crypto_session = scoped_crypto_session.get();
|
||||
}
|
||||
|
||||
result = local_crypto_session->Open(requested_security_level_);
|
||||
if (result == NO_ERROR) {
|
||||
result = AddEntry(local_crypto_session, true, kDummyKeySetId,
|
||||
kEmptyString, kEmptyString,
|
||||
&temporary_usage_entry_number);
|
||||
}
|
||||
}
|
||||
if (result == NO_ERROR) {
|
||||
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(
|
||||
"Unable to create/delete new entry, clearing usage entries: "
|
||||
"security_level = %s, usage_entry_count = %zu",
|
||||
CdmSecurityLevelToString(security_level),
|
||||
usage_entry_info_.size());
|
||||
status = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status != NO_ERROR || !lru_success) {
|
||||
LOGE("Failed to load usage table: security_level = %s, status = %d",
|
||||
CdmSecurityLevelToString(security_level), static_cast<int>(status));
|
||||
device_files_->DeleteAllLicenses();
|
||||
device_files_->DeleteAllUsageInfo();
|
||||
device_files_->DeleteUsageTableInfo();
|
||||
usage_entry_info_.clear();
|
||||
usage_table_header_.clear();
|
||||
status = crypto_session->CreateUsageTableHeader(requested_security_level_,
|
||||
&usage_table_header_);
|
||||
if (status != NO_ERROR) return false;
|
||||
StoreTable(device_files_.get());
|
||||
}
|
||||
} else {
|
||||
status = crypto_session->CreateUsageTableHeader(requested_security_level_,
|
||||
&usage_table_header_);
|
||||
if (status != NO_ERROR) return false;
|
||||
StoreTable(device_files_.get());
|
||||
const CdmResponseType status = crypto_session->LoadUsageTableHeader(
|
||||
requested_security_level_, usage_table_header_);
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to load usage table header: sts = %d",
|
||||
static_cast<int>(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
is_inited_ = true;
|
||||
// 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()) {
|
||||
LOGE("Failed to perform LRU upgrade to usage entry table");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CapacityCheck(crypto_session)) {
|
||||
LOGE("Cannot restore table due to failing capacity check");
|
||||
return false;
|
||||
}
|
||||
is_initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UsageTableHeader::CreateNewTable(CryptoSession* const crypto_session) {
|
||||
LOGD("Removing all usage table files");
|
||||
// Existing files need to be deleted to avoid attempts to restore
|
||||
// licenses which no longer have a usage entry.
|
||||
device_files_->DeleteAllLicenses();
|
||||
device_files_->DeleteAllUsageInfo();
|
||||
device_files_->DeleteUsageTableInfo();
|
||||
usage_entry_info_.clear();
|
||||
usage_table_header_.clear();
|
||||
|
||||
const CdmResponseType status = crypto_session->CreateUsageTableHeader(
|
||||
requested_security_level_, &usage_table_header_);
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to create new usage table header");
|
||||
return false;
|
||||
}
|
||||
if (!StoreTable(device_files_.get())) {
|
||||
LOGE("Failed to store new usage table header");
|
||||
return false;
|
||||
}
|
||||
is_initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -395,7 +335,7 @@ CdmResponseType UsageTableHeader::AddEntry(
|
||||
return status;
|
||||
}
|
||||
|
||||
LOGI("New usage entry: usage_entry_number = %u", *usage_entry_number);
|
||||
LOGI("usage_entry_number = %u", *usage_entry_number);
|
||||
StoreTable(device_files_.get());
|
||||
return NO_ERROR;
|
||||
}
|
||||
@@ -508,6 +448,105 @@ size_t UsageTableHeader::OfflineEntryCount() const {
|
||||
EntryIsOfflineLicense);
|
||||
}
|
||||
|
||||
bool UsageTableHeader::OpenSessionCheck(CryptoSession* const crypto_session) {
|
||||
// The UsageTableHeader for the specified |requested_security_level_|
|
||||
// MUST be initialized before any sessions are opened.
|
||||
size_t session_count = 0;
|
||||
const CdmResponseType status = crypto_session->GetNumberOfOpenSessions(
|
||||
requested_security_level_, &session_count);
|
||||
if (status != NO_ERROR || session_count > 0) {
|
||||
LOGE(
|
||||
"Cannot initialize usage table header with open crypto session: "
|
||||
"status = %d, count = %zu",
|
||||
static_cast<int>(status), session_count);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UsageTableHeader::CapacityCheck(CryptoSession* const crypto_session) {
|
||||
// If the table is around capacity or if unlimited and the table is
|
||||
// larger than the minimally required capacity, then a test must be
|
||||
// performed to ensure that the usage table is not in a state which
|
||||
// will prevent create operations.
|
||||
const size_t capacity_threshold = HasUnlimitedTableCapacity()
|
||||
? kMinimumUsageTableEntriesSupported
|
||||
: potential_table_capacity();
|
||||
if (usage_entry_info_.size() <= capacity_threshold) {
|
||||
// No need to perform test if below capacity.
|
||||
return true;
|
||||
}
|
||||
|
||||
metrics::CryptoMetrics* metrics = crypto_session->GetCryptoMetrics();
|
||||
if (metrics == nullptr) metrics = &alternate_crypto_metrics_;
|
||||
// |local_crypto_session| points to an object whose scope is this
|
||||
// method or a test object whose scope is the lifetime of this class
|
||||
CryptoSession* local_crypto_session = test_crypto_session_.get();
|
||||
std::unique_ptr<CryptoSession> scoped_crypto_session;
|
||||
if (local_crypto_session == nullptr) {
|
||||
scoped_crypto_session.reset(CryptoSession::MakeCryptoSession(metrics));
|
||||
local_crypto_session = scoped_crypto_session.get();
|
||||
}
|
||||
|
||||
CdmResponseType status =
|
||||
local_crypto_session->Open(requested_security_level_);
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to open crypto session for capacity test: sts = %d",
|
||||
static_cast<int>(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t temporary_usage_entry_number;
|
||||
status = AddEntry(local_crypto_session, true, kDummyKeySetId, kEmptyString,
|
||||
kEmptyString, &temporary_usage_entry_number);
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to add entry for capacity test: sts = %d",
|
||||
static_cast<int>(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
status =
|
||||
InvalidateEntry(temporary_usage_entry_number,
|
||||
/* defrag_table = */ true, device_files_.get(), metrics);
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to invalidate entry for capacity test: sts = %d",
|
||||
static_cast<int>(status));
|
||||
return false;
|
||||
}
|
||||
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("Failed to shrink table for capacity test");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UsageTableHeader::DetermineTableCapacity(CryptoSession* crypto_session) {
|
||||
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("capacity = unlimited, security_level = %s",
|
||||
CdmSecurityLevelToString(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("capacity = %zu, security_level = %s", potential_table_capacity_,
|
||||
CdmSecurityLevelToString(security_level_));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CdmResponseType UsageTableHeader::MoveEntry(
|
||||
uint32_t from_usage_entry_number, const CdmUsageEntry& from_usage_entry,
|
||||
uint32_t to_usage_entry_number, DeviceFiles* device_files,
|
||||
|
||||
@@ -44,9 +44,7 @@ using ::testing::UnorderedElementsAre;
|
||||
using ::testing::UnorderedElementsAreArray;
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
namespace {
|
||||
|
||||
const std::string kEmptyString;
|
||||
|
||||
constexpr size_t kDefaultTableCapacity = 300;
|
||||
@@ -451,6 +449,8 @@ class MockCryptoSession : public TestCryptoSession {
|
||||
MOCK_METHOD2(UpdateUsageEntry,
|
||||
CdmResponseType(CdmUsageTableHeader*, CdmUsageEntry*));
|
||||
MOCK_METHOD1(MoveUsageEntry, CdmResponseType(uint32_t));
|
||||
MOCK_METHOD2(GetNumberOfOpenSessions,
|
||||
CdmResponseType(SecurityLevel, size_t*));
|
||||
|
||||
// Fake method for testing. Having an EXPECT_CALL causes complexities
|
||||
// for getting table capacity during initialization.
|
||||
@@ -566,6 +566,8 @@ class UsageTableHeaderTest : public WvCdmTestBase {
|
||||
void Init(CdmSecurityLevel security_level,
|
||||
const CdmUsageTableHeader& usage_table_header,
|
||||
const std::vector<CdmUsageEntryInfo>& usage_entry_info_vector) {
|
||||
EXPECT_CALL(*crypto_session_, GetNumberOfOpenSessions(_, NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(usage_table_header),
|
||||
@@ -576,6 +578,12 @@ class UsageTableHeaderTest : public WvCdmTestBase {
|
||||
EXPECT_TRUE(usage_table_header_->Init(security_level, crypto_session_));
|
||||
}
|
||||
|
||||
void ExpectToDeleteUsageTableFiles() {
|
||||
EXPECT_CALL(*device_files_, DeleteAllLicenses()).WillOnce(Return(true));
|
||||
EXPECT_CALL(*device_files_, DeleteAllUsageInfo()).WillOnce(Return(true));
|
||||
EXPECT_CALL(*device_files_, DeleteUsageTableInfo()).WillOnce(Return(true));
|
||||
}
|
||||
|
||||
MockDeviceFiles* device_files_;
|
||||
metrics::CryptoMetrics crypto_metrics_;
|
||||
MockCryptoSession* crypto_session_;
|
||||
@@ -598,70 +606,17 @@ class UsageTableHeaderInitializationTest
|
||||
public ::testing::WithParamInterface<CdmSecurityLevel> {
|
||||
public:
|
||||
static void SetUpTestCase() { InitVectorConstants(); }
|
||||
|
||||
SecurityLevel GetSecurityLevel() const {
|
||||
return (GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(UsageTableHeaderInitializationTest, CreateUsageTableHeader) {
|
||||
const SecurityLevel security_level =
|
||||
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kEmptyUsageTableHeader),
|
||||
SetArgPointee<1>(kEmptyUsageEntryInfoVector),
|
||||
SetArgPointee<2>(false), Return(false)));
|
||||
TEST_P(UsageTableHeaderInitializationTest, RestoreUsageTable_Success) {
|
||||
const SecurityLevel security_level = GetSecurityLevel();
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
CreateUsageTableHeader(security_level, NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<1>(kEmptyUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader,
|
||||
kEmptyUsageEntryInfoVector))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
}
|
||||
|
||||
TEST_P(UsageTableHeaderInitializationTest, Upgrade_UnableToRetrieveLicenses) {
|
||||
const SecurityLevel security_level =
|
||||
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kEmptyUsageTableHeader),
|
||||
SetArgPointee<1>(kEmptyUsageEntryInfoVector),
|
||||
SetArgPointee<2>(false), Return(false)));
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
CreateUsageTableHeader(security_level, NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<1>(kEmptyUsageTableHeader), Return(NO_ERROR)));
|
||||
// TODO: Why not being called?
|
||||
// EXPECT_CALL(*device_files_, DeleteAllLicenses()).WillOnce(Return(true));
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader,
|
||||
kEmptyUsageEntryInfoVector))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
}
|
||||
|
||||
TEST_P(UsageTableHeaderInitializationTest, Upgrade_UnableToRetrieveUsageInfo) {
|
||||
const SecurityLevel security_level =
|
||||
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kEmptyUsageTableHeader),
|
||||
SetArgPointee<1>(kEmptyUsageEntryInfoVector),
|
||||
SetArgPointee<2>(false), Return(false)));
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
CreateUsageTableHeader(security_level, NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<1>(kEmptyUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader,
|
||||
kEmptyUsageEntryInfoVector))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
}
|
||||
|
||||
TEST_P(UsageTableHeaderInitializationTest, UsageTableHeaderExists) {
|
||||
const SecurityLevel security_level =
|
||||
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
|
||||
GetNumberOfOpenSessions(security_level, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||
@@ -670,15 +625,172 @@ TEST_P(UsageTableHeaderInitializationTest, UsageTableHeaderExists) {
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
}
|
||||
|
||||
// First attempt at initializing the table succeeds, however, attempting
|
||||
// to reinitialize the usage table should result in a failure.
|
||||
TEST_P(UsageTableHeaderInitializationTest,
|
||||
RestoreUsageTable_FailureDueToReInit) {
|
||||
const SecurityLevel security_level = GetSecurityLevel();
|
||||
|
||||
// First run, success.
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(security_level, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||
SetArgPointee<1>(kUsageEntryInfoVector),
|
||||
SetArgPointee<2>(false), Return(true)));
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
|
||||
// Second run, failure.
|
||||
EXPECT_FALSE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
}
|
||||
|
||||
// Table MUST not be initialized before another session has been opened.
|
||||
TEST_P(UsageTableHeaderInitializationTest,
|
||||
RestoreUsageTable_FailureDueToExistingSessions) {
|
||||
const SecurityLevel security_level = GetSecurityLevel();
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(security_level, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(1), Return(NO_ERROR)));
|
||||
EXPECT_FALSE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
}
|
||||
|
||||
// No existing usage table in storage, creating a new table succeeds.
|
||||
TEST_P(UsageTableHeaderInitializationTest,
|
||||
RestoreUsageTable_CreateNew_AfterRetrieveFails) {
|
||||
const SecurityLevel security_level = GetSecurityLevel();
|
||||
|
||||
// Expectations for restore:
|
||||
// 1) Fail to retrieve existing table file
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(security_level, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(Return(false));
|
||||
|
||||
// Expectations for create:
|
||||
// 1) Existing table is destroyed (files etc.)
|
||||
// 2) Create new header within OEMCrypto succeeds
|
||||
// 3) Storing the table header succeeds
|
||||
ExpectToDeleteUsageTableFiles();
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
CreateUsageTableHeader(security_level, NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<1>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader,
|
||||
kEmptyUsageEntryInfoVector))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
}
|
||||
|
||||
TEST_P(UsageTableHeaderInitializationTest, UsageEntriesAtCapacity) {
|
||||
// A table exists in storage, but it cannot be loaded due to generation
|
||||
// skew. Creating a new table succeeds.
|
||||
TEST_P(UsageTableHeaderInitializationTest,
|
||||
RestoreUsageTable_CreateNew_AfterLoadFails) {
|
||||
const SecurityLevel security_level = GetSecurityLevel();
|
||||
|
||||
// Expectations for restore:
|
||||
// 1) Existing table file is retrieved
|
||||
// 2) Loading existing header within OEMCrypto fails
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(security_level, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||
SetArgPointee<1>(kUsageEntryInfoVector),
|
||||
SetArgPointee<2>(false), Return(true)));
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
||||
.WillOnce(Return(LOAD_USAGE_HEADER_GENERATION_SKEW));
|
||||
|
||||
// Expectations for create:
|
||||
// 1) Existing table is destroyed (files etc.)
|
||||
// 2) Create new header within OEMCrypto succeeds
|
||||
// 3) Storing the table header succeeds
|
||||
ExpectToDeleteUsageTableFiles();
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
CreateUsageTableHeader(security_level, NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<1>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader,
|
||||
kEmptyUsageEntryInfoVector))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
}
|
||||
|
||||
// No existing table in storage, and attempting to create a new usage
|
||||
// table fails for unknown reason. Initialization MUST fail.
|
||||
TEST_P(UsageTableHeaderInitializationTest,
|
||||
RestoreUsageTable_CreateNew_CreateFails) {
|
||||
const SecurityLevel security_level = GetSecurityLevel();
|
||||
// Expectations for restore:
|
||||
// 1) No table info file exists
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(security_level, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(Return(false));
|
||||
// Expectations for create:
|
||||
// 1) Create new header within OEMCrypto fails
|
||||
ExpectToDeleteUsageTableFiles();
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
CreateUsageTableHeader(security_level, NotNull()))
|
||||
.WillOnce(Return(CREATE_USAGE_TABLE_ERROR));
|
||||
|
||||
EXPECT_FALSE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
}
|
||||
|
||||
// No existing table in storage, attempting to create a new usage
|
||||
// table succeeds; however, storing the new table header fails.
|
||||
// Initialization MUST fail.
|
||||
TEST_P(UsageTableHeaderInitializationTest,
|
||||
RestoreUsageTable_CreateNew_StoreFails) {
|
||||
const SecurityLevel security_level = GetSecurityLevel();
|
||||
// Expectations for restore:
|
||||
// 1) No table info file exists
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(security_level, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(Return(false));
|
||||
// Expectations for create:
|
||||
// 1) Create new header within OEMCrypto succeeds
|
||||
// 2) Storing the table header fails
|
||||
ExpectToDeleteUsageTableFiles();
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
CreateUsageTableHeader(security_level, NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(kUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kUsageTableHeader,
|
||||
kEmptyUsageEntryInfoVector))
|
||||
.WillOnce(Return(false));
|
||||
EXPECT_FALSE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
}
|
||||
|
||||
// Restoring table succeeds, and the current table is at capacity.
|
||||
// No special action needs to be taken.
|
||||
TEST_P(UsageTableHeaderInitializationTest, RestoreUsageTable_AtCapacity) {
|
||||
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
|
||||
usage_entries.resize(kDefaultTableCapacity);
|
||||
const SecurityLevel security_level =
|
||||
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
|
||||
const SecurityLevel security_level = GetSecurityLevel();
|
||||
// Expectations for restore:
|
||||
// 1) Existing table file is retrieved
|
||||
// 2) Loading existing header within OEMCrypto succeeds
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(security_level, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||
@@ -687,18 +799,25 @@ TEST_P(UsageTableHeaderInitializationTest, UsageEntriesAtCapacity) {
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
|
||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
}
|
||||
|
||||
// Restoring table succeeds, OEMCrypto does not specify an absolute
|
||||
// capacity, existing table is under the minimum required capacity.
|
||||
// No special action needs to be taken.
|
||||
TEST_P(UsageTableHeaderInitializationTest,
|
||||
UsageEntries_NoCapacity_UnderMinimum) {
|
||||
RestoreUsageTable_NoCapacity_UnderMinimum) {
|
||||
crypto_session_->SetMaximumUsageTableEntries(0); // Unlimited.
|
||||
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
|
||||
constexpr size_t kHalfMinCapacity = kDefaultTableCapacity / 2;
|
||||
usage_entries.resize(kHalfMinCapacity);
|
||||
const SecurityLevel security_level =
|
||||
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
|
||||
const SecurityLevel security_level = GetSecurityLevel();
|
||||
// Expectations for restore:
|
||||
// 1) Existing table file is retrieved
|
||||
// 2) Loading existing header within OEMCrypto succeeds
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(security_level, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||
@@ -707,136 +826,134 @@ TEST_P(UsageTableHeaderInitializationTest,
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
// No expectations of creating or deleting entries if the number of entries
|
||||
// is less than minimally required capacity.
|
||||
|
||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
}
|
||||
|
||||
TEST_P(UsageTableHeaderInitializationTest, UsageEntries_NoCapacity) {
|
||||
// Restoring table succeeds, OEMCrypto does not specify an absolute
|
||||
// capacity, existing table is above the minimum required capacity.
|
||||
// After restoring, the header class must check that new entries can
|
||||
// be added. This capacity check succeeds.
|
||||
TEST_P(UsageTableHeaderInitializationTest,
|
||||
RestoreUsageTable_NoCapacity_AboveMinimum) {
|
||||
crypto_session_->SetMaximumUsageTableEntries(0); // Unlimited.
|
||||
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
|
||||
usage_entries.resize(kDefaultTableCapacity);
|
||||
const SecurityLevel security_level =
|
||||
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
|
||||
ASSERT_LT(kDefaultTableCapacity, kOverFullUsageEntryInfoVector.size());
|
||||
const size_t kTableStartSize = kOverFullUsageEntryInfoVector.size();
|
||||
const SecurityLevel security_level = GetSecurityLevel();
|
||||
|
||||
// Expectations for restore:
|
||||
// 1) Existing table file is retrieved
|
||||
// 2) Loading existing header within OEMCrypto succeeds
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(security_level, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||
SetArgPointee<1>(usage_entries), SetArgPointee<2>(false),
|
||||
Return(true)));
|
||||
SetArgPointee<1>(kOverFullUsageEntryInfoVector),
|
||||
SetArgPointee<2>(false), Return(true)));
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
|
||||
// Expect an attempt to create a new entry.
|
||||
// Expectations for capacity check:
|
||||
// 1) Open a new crypto session.
|
||||
// 2) Creating a new usage entry within OEMCrypto succeeds
|
||||
// 3) Header and usage entry is updated
|
||||
// 4) Table state is stored
|
||||
// 5) New session is closed
|
||||
// 6) Table is shrunk by 1
|
||||
// 7) Table state is stored
|
||||
EXPECT_CALL(*crypto_session_, Open(security_level))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
const uint32_t expect_usage_entry_number = kDefaultTableCapacity;
|
||||
const uint32_t expect_usage_entry_number = kTableStartSize;
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
StoreUsageTableInfo(kAnotherUsageTableHeader,
|
||||
SizeIs(kDefaultTableCapacity + 1)))
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader,
|
||||
SizeIs(kTableStartSize + 1)))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
// Delete the entry after.
|
||||
EXPECT_CALL(
|
||||
*crypto_session_,
|
||||
ShrinkUsageTableHeader(security_level, kDefaultTableCapacity, NotNull()))
|
||||
EXPECT_CALL(*crypto_session_, ShrinkUsageTableHeader(
|
||||
security_level, kTableStartSize, NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(kYetAnotherUsageTableHeader),
|
||||
Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
StoreUsageTableInfo(kYetAnotherUsageTableHeader,
|
||||
SizeIs(kDefaultTableCapacity)))
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kYetAnotherUsageTableHeader,
|
||||
SizeIs(kTableStartSize)))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
}
|
||||
|
||||
// Restoring table succeeds, OEMCrypto does not specify an absolute
|
||||
// capacity, existing table is above the minimum required capacity.
|
||||
// After restoring, the header class must check that new entries can
|
||||
// be added. This capacity check fails due to adding an entry.
|
||||
// The result is a new usage table.
|
||||
TEST_P(UsageTableHeaderInitializationTest,
|
||||
UsageEntriesOverCapacity_AddEntryFails_UsageTableHeaderRecreated) {
|
||||
RestoreUsageTable_AboveCapacity_AddEntryFails) {
|
||||
ASSERT_LT(kDefaultTableCapacity, kOverFullUsageEntryInfoVector.size());
|
||||
const SecurityLevel security_level = GetSecurityLevel();
|
||||
|
||||
// Expectations for restore:
|
||||
// 1) Existing table file is retrieved
|
||||
// 2) Loading existing header within OEMCrypto succeeds
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(security_level, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||
SetArgPointee<1>(kOverFullUsageEntryInfoVector),
|
||||
SetArgPointee<2>(false), Return(true)));
|
||||
|
||||
const SecurityLevel security_level =
|
||||
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
|
||||
EXPECT_CALL(*crypto_session_, Open(security_level))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
CreateUsageTableHeader(security_level, NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<1>(kEmptyUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_, DeleteAllLicenses()).WillOnce(Return(true));
|
||||
EXPECT_CALL(*device_files_, DeleteAllUsageInfo()).WillOnce(Return(true));
|
||||
EXPECT_CALL(*device_files_, DeleteUsageTableInfo()).WillOnce(Return(true));
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader,
|
||||
kEmptyUsageEntryInfoVector))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
// Expectations for AddEntry
|
||||
const uint32_t expect_usage_entry_number =
|
||||
kOverFullUsageEntryInfoVector.size();
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(expect_usage_entry_number),
|
||||
Return(CREATE_USAGE_ENTRY_UNKNOWN_ERROR)));
|
||||
|
||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
}
|
||||
|
||||
TEST_P(UsageTableHeaderInitializationTest,
|
||||
UsageEntries_NoCapacity_AddEntryFails_UsageTableHeaderRecreated) {
|
||||
crypto_session_->SetMaximumUsageTableEntries(0); // Unlimited.
|
||||
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
|
||||
usage_entries.resize(kDefaultTableCapacity);
|
||||
const SecurityLevel security_level =
|
||||
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||
SetArgPointee<1>(usage_entries), SetArgPointee<2>(false),
|
||||
Return(true)));
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
// Try to create a new entry, and fail.
|
||||
// Expectations for capacity check:
|
||||
// 1) Open a new crypto session.
|
||||
// 2) Creating a new usage entry within OEMCrypto fails
|
||||
EXPECT_CALL(*crypto_session_, Open(security_level))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.WillOnce(Return(CREATE_USAGE_ENTRY_UNKNOWN_ERROR));
|
||||
// Expect clean up.
|
||||
EXPECT_CALL(*device_files_, DeleteAllLicenses()).WillOnce(Return(true));
|
||||
EXPECT_CALL(*device_files_, DeleteAllUsageInfo()).WillOnce(Return(true));
|
||||
EXPECT_CALL(*device_files_, DeleteUsageTableInfo()).WillOnce(Return(true));
|
||||
// Expect recreation of usage table.
|
||||
|
||||
// Expectations for create:
|
||||
// 1) Existing table is destroyed (files etc.)
|
||||
// 2) Create new header within OEMCrypto succeeds
|
||||
// 3) Storing the table header fails
|
||||
ExpectToDeleteUsageTableFiles();
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
CreateUsageTableHeader(security_level, NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<1>(kEmptyUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader,
|
||||
DoAll(SetArgPointee<1>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader,
|
||||
kEmptyUsageEntryInfoVector))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
}
|
||||
|
||||
// Restoring table succeeds, OEMCrypto does not specify an absolute
|
||||
// capacity, existing table is above the minimum required capacity.
|
||||
// After restoring, the header class must check that new entries can
|
||||
// be added. This capacity check fails due to invalidating an entry.
|
||||
// The result is a new usage table.
|
||||
TEST_P(UsageTableHeaderInitializationTest,
|
||||
UsageEntriesOverCapacity_AddInvalidateEntrySucceeds) {
|
||||
// Capacity +2.
|
||||
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
|
||||
usage_entries.push_back(kDummyUsageEntryInfo);
|
||||
|
||||
const SecurityLevel security_level =
|
||||
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
|
||||
RestoreUsageTable_NoCapacity_AboveMinimum_InvalidateEntryFails) {
|
||||
crypto_session_->SetMaximumUsageTableEntries(0); // Unlimited.
|
||||
ASSERT_LT(kDefaultTableCapacity, kOverFullUsageEntryInfoVector.size());
|
||||
const size_t kTableStartSize = kOverFullUsageEntryInfoVector.size();
|
||||
const SecurityLevel security_level = GetSecurityLevel();
|
||||
|
||||
// Expectations for restore:
|
||||
// 1) Existing table file is retrieved
|
||||
// 2) Loading existing header within OEMCrypto succeeds
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(security_level, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||
@@ -846,30 +963,42 @@ TEST_P(UsageTableHeaderInitializationTest,
|
||||
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
|
||||
// Expectations for AddEntry
|
||||
const uint32_t expect_usage_entry_number =
|
||||
kOverFullUsageEntryInfoVector.size();
|
||||
// Expectations for capacity check:
|
||||
// 1) Open a new crypto session.
|
||||
// 2) Creating a new usage entry within OEMCrypto succeeds.
|
||||
// 3) Header and usage entry is updated
|
||||
// 4) Table state is stored
|
||||
// 5) New session is closed
|
||||
// 6) Shrinking table fails
|
||||
EXPECT_CALL(*crypto_session_, Open(security_level))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
const uint32_t expect_usage_entry_number = kTableStartSize;
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
StoreUsageTableInfo(kAnotherUsageTableHeader, usage_entries))
|
||||
.WillOnce(Return(true));
|
||||
// Called twice due to defrag.
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader,
|
||||
SizeIs(kTableStartSize + 1)))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(*crypto_session_, ShrinkUsageTableHeader(
|
||||
security_level, kTableStartSize, NotNull()))
|
||||
.WillOnce(Return(SHRINK_USAGE_TABLE_HEADER_UNKNOWN_ERROR));
|
||||
|
||||
// Expectations for InvalidateEntry, assumes no entry other entry is invalid.
|
||||
EXPECT_CALL(*crypto_session_, Open(security_level))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
// Expectations for create:
|
||||
// 1) Existing table is destroyed (files etc.)
|
||||
// 2) Create new header within OEMCrypto succeeds
|
||||
// 3) Storing the table header succeeds
|
||||
ExpectToDeleteUsageTableFiles();
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
ShrinkUsageTableHeader(security_level, usage_entries.size() - 1,
|
||||
NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(kYetAnotherUsageTableHeader),
|
||||
CreateUsageTableHeader(security_level, NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(kYetAnotherUsageTableHeader),
|
||||
Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
StoreUsageTableInfo(kYetAnotherUsageTableHeader,
|
||||
SizeIs(kOverFullUsageEntryInfoVector.size())))
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kYetAnotherUsageTableHeader,
|
||||
kEmptyUsageEntryInfoVector))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
||||
@@ -880,13 +1009,12 @@ INSTANTIATE_TEST_CASE_P(Cdm, UsageTableHeaderInitializationTest,
|
||||
|
||||
TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailed_UnknownError) {
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||
uint32_t usage_entry_number;
|
||||
uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size();
|
||||
|
||||
const uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size();
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(expect_usage_entry_number),
|
||||
Return(CREATE_USAGE_ENTRY_UNKNOWN_ERROR)));
|
||||
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_NE(NO_ERROR,
|
||||
usage_table_header_->AddEntry(
|
||||
crypto_session_,
|
||||
@@ -898,13 +1026,12 @@ TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailed_UnknownError) {
|
||||
|
||||
TEST_F(UsageTableHeaderTest, AddEntry_UsageEntryTooSmall) {
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||
uint32_t usage_entry_number;
|
||||
uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size() - 1;
|
||||
|
||||
const uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size() - 1;
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
|
||||
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_NE(NO_ERROR,
|
||||
usage_table_header_->AddEntry(
|
||||
crypto_session_,
|
||||
@@ -916,11 +1043,9 @@ TEST_F(UsageTableHeaderTest, AddEntry_UsageEntryTooSmall) {
|
||||
|
||||
TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveOfflineUsageEntry) {
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||
uint32_t usage_entry_number;
|
||||
uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size();
|
||||
const uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size();
|
||||
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
|
||||
kUsageEntryInfoVector;
|
||||
|
||||
expect_usage_entry_info_vector.resize(expect_usage_entry_number + 1);
|
||||
expect_usage_entry_info_vector[expect_usage_entry_number] =
|
||||
kUsageEntryInfoOfflineLicense2;
|
||||
@@ -937,6 +1062,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveOfflineUsageEntry) {
|
||||
UnorderedElementsAreArray(expect_usage_entry_info_vector)))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
usage_table_header_->AddEntry(
|
||||
crypto_session_,
|
||||
@@ -949,8 +1075,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveOfflineUsageEntry) {
|
||||
|
||||
TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveSecureStopUsageEntry) {
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||
uint32_t usage_entry_number;
|
||||
uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size();
|
||||
const uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size();
|
||||
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
|
||||
kUsageEntryInfoVector;
|
||||
|
||||
@@ -970,6 +1095,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveSecureStopUsageEntry) {
|
||||
UnorderedElementsAreArray(expect_usage_entry_info_vector)))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
usage_table_header_->AddEntry(
|
||||
crypto_session_,
|
||||
@@ -982,8 +1108,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveSecureStopUsageEntry) {
|
||||
|
||||
TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) {
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||
uint32_t usage_entry_number;
|
||||
uint32_t next_usage_entry_number = kUsageEntryInfoVector.size();
|
||||
const uint32_t next_usage_entry_number = kUsageEntryInfoVector.size();
|
||||
size_t skip_usage_entries = 3;
|
||||
uint32_t expect_usage_entry_number =
|
||||
next_usage_entry_number + skip_usage_entries;
|
||||
@@ -1006,6 +1131,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) {
|
||||
kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoSecureStop2)))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
uint32_t usage_entry_number = 0;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
usage_table_header_->AddEntry(
|
||||
crypto_session_,
|
||||
@@ -1123,7 +1249,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailsEveryTime) {
|
||||
|
||||
TEST_F(UsageTableHeaderTest, LoadEntry_InvalidEntryNumber) {
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||
uint32_t usage_entry_number = kUsageEntryInfoVector.size() + 3;
|
||||
const uint32_t usage_entry_number = kUsageEntryInfoVector.size() + 3;
|
||||
|
||||
EXPECT_NE(NO_ERROR, usage_table_header_->LoadEntry(
|
||||
crypto_session_, kUsageEntry, usage_entry_number));
|
||||
@@ -1131,7 +1257,7 @@ TEST_F(UsageTableHeaderTest, LoadEntry_InvalidEntryNumber) {
|
||||
|
||||
TEST_F(UsageTableHeaderTest, LoadEntry_CryptoSessionError) {
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||
uint32_t usage_entry_number = 1;
|
||||
const uint32_t usage_entry_number = 1;
|
||||
|
||||
EXPECT_CALL(*crypto_session_, LoadUsageEntry(usage_entry_number, kUsageEntry))
|
||||
.WillOnce(Return(LOAD_USAGE_ENTRY_GENERATION_SKEW));
|
||||
@@ -1142,7 +1268,7 @@ TEST_F(UsageTableHeaderTest, LoadEntry_CryptoSessionError) {
|
||||
|
||||
TEST_F(UsageTableHeaderTest, LoadEntry) {
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||
uint32_t usage_entry_number = 1;
|
||||
const uint32_t usage_entry_number = 1;
|
||||
|
||||
EXPECT_CALL(*crypto_session_, LoadUsageEntry(usage_entry_number, kUsageEntry))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
@@ -1184,7 +1310,7 @@ TEST_F(UsageTableHeaderTest, UpdateEntry) {
|
||||
|
||||
TEST_F(UsageTableHeaderTest, InvalidateEntry_InvalidUsageEntryNumber) {
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||
uint32_t usage_entry_number = kUsageEntryInfoVector.size();
|
||||
const uint32_t usage_entry_number = kUsageEntryInfoVector.size();
|
||||
metrics::CryptoMetrics metrics;
|
||||
|
||||
EXPECT_NE(NO_ERROR, usage_table_header_->InvalidateEntry(
|
||||
@@ -3203,6 +3329,9 @@ TEST_F(UsageTableHeaderTest, StaleHeader) {
|
||||
ToVector(usage_entry_info_vector, usage_entry_info_array,
|
||||
sizeof(usage_entry_info_array));
|
||||
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(kLevelDefault, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||
@@ -3211,14 +3340,12 @@ TEST_F(UsageTableHeaderTest, StaleHeader) {
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
LoadUsageTableHeader(kLevelDefault, kUsageTableHeader))
|
||||
.WillOnce(Return(LOAD_USAGE_HEADER_GENERATION_SKEW));
|
||||
ExpectToDeleteUsageTableFiles();
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
CreateUsageTableHeader(kLevelDefault, NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<1>(kEmptyUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_, DeleteAllLicenses()).WillOnce(Return(true));
|
||||
EXPECT_CALL(*device_files_, DeleteAllUsageInfo()).WillOnce(Return(true));
|
||||
EXPECT_CALL(*device_files_, DeleteUsageTableInfo()).WillOnce(Return(true));
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader,
|
||||
DoAll(SetArgPointee<1>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader,
|
||||
kEmptyUsageEntryInfoVector))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
@@ -3302,6 +3429,9 @@ TEST_F(UsageTableHeaderTest, Shrink_MoreThanTable) {
|
||||
// the table header and entries are configured for LRU.
|
||||
// 2. No upgrading action is taken.
|
||||
TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_NoAction) {
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(kLevelDefault, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUpgradableUsageTableHeader),
|
||||
@@ -3329,6 +3459,9 @@ TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_NoAction) {
|
||||
// 2. The usage table header will load license or usage information to
|
||||
// determine appropriate expiry and last_used times.
|
||||
TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_Succeed) {
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(kLevelDefault, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUpgradableUsageTableHeader),
|
||||
@@ -3395,6 +3528,9 @@ TEST_F(UsageTableHeaderTest,
|
||||
upgraded_usage_entry_info_list[2].storage_type = kStorageTypeUnknown;
|
||||
|
||||
// Load table expectations.
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(kLevelDefault, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUpgradableUsageTableHeader),
|
||||
@@ -3455,6 +3591,9 @@ TEST_F(UsageTableHeaderTest,
|
||||
wrond_typed_usage_entry_info.last_use_time = 0;
|
||||
wrond_typed_usage_entry_info.offline_license_expiry_time = 0;
|
||||
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(kLevelDefault, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUpgradableUsageTableHeader),
|
||||
@@ -3510,6 +3649,9 @@ TEST_F(UsageTableHeaderTest,
|
||||
// that the table has not been configured for upgrade.
|
||||
// 2. None of the entries can have their license info loaded.
|
||||
TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_AllFailure) {
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
GetNumberOfOpenSessions(kLevelDefault, NotNull()))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUpgradableUsageTableHeader),
|
||||
@@ -3539,29 +3681,20 @@ TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_AllFailure) {
|
||||
|
||||
// After failure, these will be called to clear files and create a new
|
||||
// usage table header.
|
||||
EXPECT_CALL(*device_files_, DeleteAllLicenses());
|
||||
EXPECT_CALL(*device_files_, DeleteAllUsageInfo());
|
||||
EXPECT_CALL(*device_files_, DeleteUsageTableInfo());
|
||||
ExpectToDeleteUsageTableFiles();
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
CreateUsageTableHeader(kLevelDefault, NotNull()))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(_, _));
|
||||
.WillOnce(DoAll(SetArgPointee<1>(kUsageTableHeader), Return(NO_ERROR)));
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kUsageTableHeader,
|
||||
kEmptyUsageEntryInfoVector))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_TRUE(usage_table_header_->Init(kSecurityLevelL1, crypto_session_));
|
||||
}
|
||||
|
||||
TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateLicenseEntry) {
|
||||
// General setup.
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUpgradedUsageTableHeader),
|
||||
SetArgPointee<1>(kUpgradedUsageEntryInfoList),
|
||||
SetArgPointee<2>(/* lru_upgrade = */ false),
|
||||
Return(true)));
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
LoadUsageTableHeader(kLevelDefault, kUpgradedUsageTableHeader))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_TRUE(usage_table_header_->Init(kSecurityLevelL1, crypto_session_));
|
||||
Init(kSecurityLevelL1, kUpgradedUsageTableHeader,
|
||||
kUpgradedUsageEntryInfoList);
|
||||
|
||||
// Expected values.
|
||||
const uint32_t expected_usage_entry_number =
|
||||
@@ -3598,17 +3731,8 @@ TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateLicenseEntry) {
|
||||
}
|
||||
|
||||
TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateUsageInfoEntry) {
|
||||
// General setup.
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUpgradedUsageTableHeader),
|
||||
SetArgPointee<1>(kUpgradedUsageEntryInfoList),
|
||||
SetArgPointee<2>(/* lru_upgrade = */ false),
|
||||
Return(true)));
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
LoadUsageTableHeader(kLevelDefault, kUpgradedUsageTableHeader))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_TRUE(usage_table_header_->Init(kSecurityLevelL1, crypto_session_));
|
||||
Init(kSecurityLevelL1, kUpgradedUsageTableHeader,
|
||||
kUpgradedUsageEntryInfoList);
|
||||
|
||||
// Expected values.
|
||||
const uint32_t expected_usage_entry_number =
|
||||
@@ -3646,17 +3770,8 @@ TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateUsageInfoEntry) {
|
||||
}
|
||||
|
||||
TEST_F(UsageTableHeaderTest, LruLastUsedTime_UpdateEntry) {
|
||||
// General setup.
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUpgradedUsageTableHeader),
|
||||
SetArgPointee<1>(kUpgradedUsageEntryInfoList),
|
||||
SetArgPointee<2>(/* lru_upgrade = */ false),
|
||||
Return(true)));
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
LoadUsageTableHeader(kLevelDefault, kUpgradedUsageTableHeader))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_TRUE(usage_table_header_->Init(kSecurityLevelL1, crypto_session_));
|
||||
Init(kSecurityLevelL1, kUpgradedUsageTableHeader,
|
||||
kUpgradedUsageEntryInfoList);
|
||||
|
||||
std::vector<CdmUsageEntryInfo> expected_usage_info_list =
|
||||
kUpgradedUsageEntryInfoList;
|
||||
@@ -3689,17 +3804,8 @@ TEST_F(UsageTableHeaderTest, LruLastUsedTime_UpdateEntry) {
|
||||
}
|
||||
|
||||
TEST_F(UsageTableHeaderTest, LruLastUsedTime_LoadEntry) {
|
||||
// General setup.
|
||||
EXPECT_CALL(*device_files_,
|
||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kUpgradedUsageTableHeader),
|
||||
SetArgPointee<1>(kUpgradedUsageEntryInfoList),
|
||||
SetArgPointee<2>(/* lru_upgrade = */ false),
|
||||
Return(true)));
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
LoadUsageTableHeader(kLevelDefault, kUpgradedUsageTableHeader))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
EXPECT_TRUE(usage_table_header_->Init(kSecurityLevelL1, crypto_session_));
|
||||
Init(kSecurityLevelL1, kUpgradedUsageTableHeader,
|
||||
kUpgradedUsageEntryInfoList);
|
||||
|
||||
std::vector<CdmUsageEntryInfo> expected_usage_info_list =
|
||||
kUpgradedUsageEntryInfoList;
|
||||
@@ -4091,5 +4197,4 @@ TEST_F(UsageTableHeaderTest, PotentialTableCapacity_Available) {
|
||||
EXPECT_EQ(usage_table_header_->potential_table_capacity(), kTableCapacity);
|
||||
EXPECT_FALSE(usage_table_header_->HasUnlimitedTableCapacity());
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
Reference in New Issue
Block a user