Check for open session when initializing usage table.
[ Merge of http://go/wvgerrit/122984 ] There was an issue encountered by some vendors with how the usage table was initialized on some devices. Previously, the CDM would open an OEMCrypto session first, then initialize the usage table (loading existing or creating a new one). On these devices, OEMCrypto_CreateUsageTableHeader() and OEMCrypto_LoadUsageTableHeader() would fail if there were any open sessions. This CL changes the initialization process to create/load the usage table before opening an OEMCrypto session. This change also lays the ground work for another usage table fix to address GTS tests failure. In the process, several of the functions for the usage table have been split up into smaller chunks of code. This required additional changes to the usage table unittest to keep them up to date. Bug: 169195093 Bug: 180639135 Test: Linux unittests and MediaDrmTest Change-Id: Ifbf35f5d8cff5b89fea9b16edb998c84803f4fbe
This commit is contained in:
@@ -293,7 +293,7 @@ class CryptoSession {
|
|||||||
// exist as long as the new CryptoSession exists.
|
// exist as long as the new CryptoSession exists.
|
||||||
explicit CryptoSession(metrics::CryptoMetrics* crypto_metrics);
|
explicit CryptoSession(metrics::CryptoMetrics* crypto_metrics);
|
||||||
|
|
||||||
int session_count() { return session_count_; }
|
int session_count() const { return session_count_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class CryptoSessionForTest;
|
friend class CryptoSessionForTest;
|
||||||
@@ -313,6 +313,13 @@ class CryptoSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Init();
|
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 GetTokenFromKeybox(std::string* token);
|
||||||
CdmResponseType GetTokenFromOemCert(std::string* token);
|
CdmResponseType GetTokenFromOemCert(std::string* token);
|
||||||
static bool ExtractSystemIdFromOemCert(const std::string& oem_cert,
|
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
|
// These methods should be used to take the various CryptoSession mutexes in
|
||||||
// preference to taking the mutexes directly.
|
// preference to taking the mutexes directly.
|
||||||
//
|
//
|
||||||
// A lock should be taken on the Static Field Mutex before accessing any of
|
// A lock should be taken on the Static Field Mutex before accessing
|
||||||
// CryptoSession's non-atomic static fields. It can be taken as a reader or as
|
// any of CryptoSession's non-atomic static fields with the exception
|
||||||
// a writer, depending on how you will be accessing the static fields.
|
// 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
|
// 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
|
// 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 static_field_mutex_;
|
||||||
static shared_mutex oem_crypto_mutex_;
|
static shared_mutex oem_crypto_mutex_;
|
||||||
std::mutex oem_crypto_session_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 bool initialized_;
|
||||||
static int session_count_;
|
static int session_count_;
|
||||||
@@ -446,8 +462,10 @@ class CryptoSession {
|
|||||||
// Open session-cached result of OEMCrypto_SupportsUsageTable().
|
// Open session-cached result of OEMCrypto_SupportsUsageTable().
|
||||||
CachedBooleanProperty has_usage_info_support_ = kBooleanUnset;
|
CachedBooleanProperty has_usage_info_support_ = kBooleanUnset;
|
||||||
UsageTableHeader* usage_table_header_ = nullptr;
|
UsageTableHeader* usage_table_header_ = nullptr;
|
||||||
static UsageTableHeader* usage_table_header_l1_;
|
// These fields are protected by |usage_table_mutex_| and not
|
||||||
static UsageTableHeader* usage_table_header_l3_;
|
// |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_;
|
std::string request_id_;
|
||||||
static std::atomic<uint64_t> request_id_index_source_;
|
static std::atomic<uint64_t> request_id_index_source_;
|
||||||
|
|||||||
@@ -53,8 +53,12 @@ class UsageTableHeader {
|
|||||||
UsageTableHeader();
|
UsageTableHeader();
|
||||||
virtual ~UsageTableHeader() {}
|
virtual ~UsageTableHeader() {}
|
||||||
|
|
||||||
// |crypto_session| is used to create or load a usage master table and
|
// |crypto_session| is used to create or load a usage master table
|
||||||
// not cached beyound this call.
|
// 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);
|
bool Init(CdmSecurityLevel security_level, CryptoSession* crypto_session);
|
||||||
|
|
||||||
// |persistent_license| false indicates usage info record
|
// |persistent_license| false indicates usage info record
|
||||||
@@ -125,6 +129,32 @@ class UsageTableHeader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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 */,
|
CdmResponseType MoveEntry(uint32_t from /* usage entry number */,
|
||||||
const CdmUsageEntry& from_usage_entry,
|
const CdmUsageEntry& from_usage_entry,
|
||||||
uint32_t to /* usage entry number */,
|
uint32_t to /* usage entry number */,
|
||||||
@@ -153,8 +183,6 @@ class UsageTableHeader {
|
|||||||
// evicted.
|
// evicted.
|
||||||
CdmResponseType ReleaseOldestEntry(metrics::CryptoMetrics* metrics);
|
CdmResponseType ReleaseOldestEntry(metrics::CryptoMetrics* metrics);
|
||||||
|
|
||||||
virtual bool is_inited() { return is_inited_; }
|
|
||||||
|
|
||||||
// Performs and LRU upgrade on all loaded CdmUsageEntryInfo from a
|
// Performs and LRU upgrade on all loaded CdmUsageEntryInfo from a
|
||||||
// device file that had not yet been upgraded to use the LRU data.
|
// device file that had not yet been upgraded to use the LRU data.
|
||||||
virtual bool LruUpgradeAllUsageEntries();
|
virtual bool LruUpgradeAllUsageEntries();
|
||||||
@@ -213,16 +241,15 @@ class UsageTableHeader {
|
|||||||
// by CdmSession.
|
// by CdmSession.
|
||||||
std::unique_ptr<DeviceFiles> device_files_;
|
std::unique_ptr<DeviceFiles> device_files_;
|
||||||
std::unique_ptr<FileSystem> file_system_;
|
std::unique_ptr<FileSystem> file_system_;
|
||||||
CdmSecurityLevel security_level_;
|
CdmSecurityLevel security_level_ = kSecurityLevelUninitialized;
|
||||||
SecurityLevel requested_security_level_;
|
SecurityLevel requested_security_level_ = kLevelDefault;
|
||||||
|
|
||||||
CdmUsageTableHeader usage_table_header_;
|
CdmUsageTableHeader usage_table_header_;
|
||||||
std::vector<CdmUsageEntryInfo> usage_entry_info_;
|
std::vector<CdmUsageEntryInfo> usage_entry_info_;
|
||||||
|
|
||||||
// Lock to ensure that a single object is created for each security level
|
// Table is sync with persistent storage and can be used by the CDM
|
||||||
// and data member to represent whether an object has been correctly
|
// to interact with OEMCrypto.
|
||||||
// initialized.
|
bool is_initialized_ = false;
|
||||||
bool is_inited_;
|
|
||||||
|
|
||||||
// Synchonizes access to the Usage Table Header and bookkeeping
|
// Synchonizes access to the Usage Table Header and bookkeeping
|
||||||
// data-structures
|
// data-structures
|
||||||
|
|||||||
@@ -51,8 +51,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
using UsageTableLock = std::unique_lock<std::recursive_mutex>;
|
||||||
|
|
||||||
constexpr size_t KiB = 1024;
|
constexpr size_t KiB = 1024;
|
||||||
constexpr size_t MiB = 1024 * 1024;
|
constexpr size_t MiB = 1024 * 1024;
|
||||||
|
|
||||||
@@ -166,20 +167,22 @@ size_t GenericEncryptionBlockSize(CdmEncryptionAlgorithm algorithm) {
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
// CryptoSession variables allocation.
|
||||||
shared_mutex CryptoSession::static_field_mutex_;
|
shared_mutex CryptoSession::static_field_mutex_;
|
||||||
shared_mutex CryptoSession::oem_crypto_mutex_;
|
shared_mutex CryptoSession::oem_crypto_mutex_;
|
||||||
bool CryptoSession::initialized_ = false;
|
bool CryptoSession::initialized_ = false;
|
||||||
int CryptoSession::session_count_ = 0;
|
int CryptoSession::session_count_ = 0;
|
||||||
int CryptoSession::termination_counter_ = 0;
|
int CryptoSession::termination_counter_ = 0;
|
||||||
UsageTableHeader* CryptoSession::usage_table_header_l1_ = nullptr;
|
std::unique_ptr<UsageTableHeader> CryptoSession::usage_table_header_l1_;
|
||||||
UsageTableHeader* CryptoSession::usage_table_header_l3_ = nullptr;
|
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);
|
std::atomic<uint64_t> CryptoSession::request_id_index_source_(0);
|
||||||
|
|
||||||
size_t GetOffset(std::string message, std::string field) {
|
size_t GetOffset(std::string message, std::string field) {
|
||||||
size_t pos = message.find(field);
|
size_t pos = message.find(field);
|
||||||
if (pos == std::string::npos) {
|
if (pos == std::string::npos) {
|
||||||
LOGE("Cannot find the |field| offset in message: field = %s",
|
LOGE("Cannot find the |field| offset in message: field = %s",
|
||||||
field.c_str());
|
IdToString(field));
|
||||||
pos = 0;
|
pos = 0;
|
||||||
}
|
}
|
||||||
return pos;
|
return pos;
|
||||||
@@ -195,7 +198,7 @@ OEMCrypto_Substring GetSubstring(const std::string& message,
|
|||||||
size_t pos = message.find(field);
|
size_t pos = message.find(field);
|
||||||
if (pos == std::string::npos) {
|
if (pos == std::string::npos) {
|
||||||
LOGW("Cannot find the |field| substring in message: field = %s",
|
LOGW("Cannot find the |field| substring in message: field = %s",
|
||||||
field.c_str());
|
IdToString(field));
|
||||||
substring.offset = 0;
|
substring.offset = 0;
|
||||||
substring.length = 0;
|
substring.length = 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -359,7 +362,7 @@ void CryptoSession::Init() {
|
|||||||
|
|
||||||
bool CryptoSession::TryTerminate() {
|
bool CryptoSession::TryTerminate() {
|
||||||
LOGV("Terminating crypto session");
|
LOGV("Terminating crypto session");
|
||||||
WithStaticFieldWriteLock("TryTerminate", [&] {
|
const bool terminated = WithStaticFieldWriteLock("TryTerminate", [&] {
|
||||||
LOGV(
|
LOGV(
|
||||||
"Terminating crypto session: initialized_ = %s, session_count_ = %d, "
|
"Terminating crypto session: initialized_ = %s, session_count_ = %d, "
|
||||||
"termination_counter_ = %d",
|
"termination_counter_ = %d",
|
||||||
@@ -371,25 +374,20 @@ bool CryptoSession::TryTerminate() {
|
|||||||
if (session_count_ > 0 || termination_counter_ > 0 || !initialized_)
|
if (session_count_ > 0 || termination_counter_ > 0 || !initialized_)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
OEMCryptoResult sts;
|
const OEMCryptoResult sts =
|
||||||
WithOecWriteLock("Terminate", [&] { sts = OEMCrypto_Terminate(); });
|
WithOecWriteLock("Terminate", [&] { return OEMCrypto_Terminate(); });
|
||||||
if (OEMCrypto_SUCCESS != sts) {
|
if (OEMCrypto_SUCCESS != sts) {
|
||||||
LOGE("OEMCrypto_Terminate failed: status = %d", static_cast<int>(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;
|
initialized_ = false;
|
||||||
return true;
|
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() {
|
void CryptoSession::DisableDelayedTermination() {
|
||||||
@@ -398,7 +396,63 @@ void CryptoSession::DisableDelayedTermination() {
|
|||||||
[&] { termination_counter_ = 0; });
|
[&] { 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) {
|
CdmResponseType CryptoSession::GetTokenFromKeybox(std::string* token) {
|
||||||
|
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
|
||||||
RETURN_IF_NULL(token, PARAMETER_NULL);
|
RETURN_IF_NULL(token, PARAMETER_NULL);
|
||||||
|
|
||||||
std::string temp_buffer(KEYBOX_KEY_DATA_SIZE, '\0');
|
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) {
|
CdmResponseType CryptoSession::GetTokenFromOemCert(std::string* token) {
|
||||||
|
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
|
||||||
RETURN_IF_NULL(token, PARAMETER_NULL);
|
RETURN_IF_NULL(token, PARAMETER_NULL);
|
||||||
|
|
||||||
OEMCryptoResult status;
|
OEMCryptoResult status;
|
||||||
@@ -752,9 +807,16 @@ uint8_t CryptoSession::GetSecurityPatchLevel() {
|
|||||||
CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
|
CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
|
||||||
LOGD("Opening crypto session: requested_security_level = %s",
|
LOGD("Opening crypto session: requested_security_level = %s",
|
||||||
SecurityLevelToString(requested_security_level));
|
SecurityLevelToString(requested_security_level));
|
||||||
RETURN_IF_UNINITIALIZED(UNKNOWN_ERROR);
|
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
|
||||||
if (open_) return NO_ERROR;
|
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,
|
CdmResponseType result = GetProvisioningMethod(requested_security_level,
|
||||||
&pre_provision_token_type_);
|
&pre_provision_token_type_);
|
||||||
if (result != NO_ERROR) return result;
|
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_));
|
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_)) {
|
if (!GetApiVersion(&api_version_)) {
|
||||||
LOGE("Failed to get API version");
|
LOGE("Failed to get API version");
|
||||||
return USAGE_SUPPORT_GET_API_FAILED;
|
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;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -889,13 +891,13 @@ void CryptoSession::Close() {
|
|||||||
open_ ? "true" : "false");
|
open_ ? "true" : "false");
|
||||||
if (!open_) return;
|
if (!open_) return;
|
||||||
|
|
||||||
OEMCryptoResult close_sts;
|
const OEMCryptoResult close_sts = WithOecWriteLock(
|
||||||
WithOecWriteLock(
|
"Close", [&] { return OEMCrypto_CloseSession(oec_session_id_); });
|
||||||
"Close", [&] { close_sts = OEMCrypto_CloseSession(oec_session_id_); });
|
|
||||||
metrics_->oemcrypto_close_session_.Increment(close_sts);
|
metrics_->oemcrypto_close_session_.Increment(close_sts);
|
||||||
|
|
||||||
// Clear cached values.
|
// Clear cached values.
|
||||||
has_usage_info_support_ = kBooleanUnset;
|
has_usage_info_support_ = kBooleanUnset;
|
||||||
|
oem_token_.clear();
|
||||||
|
|
||||||
if (close_sts != OEMCrypto_SUCCESS) {
|
if (close_sts != OEMCrypto_SUCCESS) {
|
||||||
LOGW("OEMCrypto_CloseSession failed: status = %d",
|
LOGW("OEMCrypto_CloseSession failed: status = %d",
|
||||||
@@ -905,6 +907,7 @@ void CryptoSession::Close() {
|
|||||||
case OEMCrypto_SUCCESS:
|
case OEMCrypto_SUCCESS:
|
||||||
case OEMCrypto_ERROR_INVALID_SESSION:
|
case OEMCrypto_ERROR_INVALID_SESSION:
|
||||||
case OEMCrypto_ERROR_SYSTEM_INVALIDATED:
|
case OEMCrypto_ERROR_SYSTEM_INVALIDATED:
|
||||||
|
usage_table_header_ = nullptr;
|
||||||
open_ = false;
|
open_ = false;
|
||||||
break;
|
break;
|
||||||
case OEMCrypto_ERROR_CLOSE_SESSION_FAILED:
|
case OEMCrypto_ERROR_CLOSE_SESSION_FAILED:
|
||||||
@@ -2488,14 +2491,13 @@ CdmResponseType CryptoSession::LoadUsageTableHeader(
|
|||||||
LOGV("Loading usage table header: requested_security_level = %s",
|
LOGV("Loading usage table header: requested_security_level = %s",
|
||||||
SecurityLevelToString(requested_security_level));
|
SecurityLevelToString(requested_security_level));
|
||||||
|
|
||||||
OEMCryptoResult result;
|
const OEMCryptoResult result = WithOecWriteLock("LoadUsageTableHeader", [&] {
|
||||||
WithOecWriteLock("LoadUsageTableHeader", [&] {
|
return OEMCrypto_LoadUsageTableHeader(
|
||||||
result = OEMCrypto_LoadUsageTableHeader(
|
|
||||||
requested_security_level,
|
requested_security_level,
|
||||||
reinterpret_cast<const uint8_t*>(usage_table_header.data()),
|
reinterpret_cast<const uint8_t*>(usage_table_header.data()),
|
||||||
usage_table_header.size());
|
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_SUCCESS) {
|
||||||
if (result == OEMCrypto_WARNING_GENERATION_SKEW) {
|
if (result == OEMCrypto_WARNING_GENERATION_SKEW) {
|
||||||
|
|||||||
@@ -15,12 +15,9 @@
|
|||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
namespace {
|
namespace {
|
||||||
std::string kEmptyString;
|
const std::string kEmptyString;
|
||||||
wvcdm::CdmKeySetId kDummyKeySetId = "DummyKsid";
|
const wvcdm::CdmKeySetId kDummyKeySetId = "DummyKsid";
|
||||||
std::string kOldUsageEntryServerMacKey(wvcdm::MAC_KEY_SIZE, 0);
|
|
||||||
std::string kOldUsageEntryClientMacKey(wvcdm::MAC_KEY_SIZE, 0);
|
|
||||||
std::string kOldUsageEntryPoviderSessionToken =
|
|
||||||
"nahZ6achSheiqua3TohQuei0ahwohv";
|
|
||||||
constexpr int64_t kDefaultExpireDuration = 33 * 24 * 60 * 60; // 33 Days
|
constexpr int64_t kDefaultExpireDuration = 33 * 24 * 60 * 60; // 33 Days
|
||||||
// Fraction of table capacity of number of unexpired offline licenses
|
// Fraction of table capacity of number of unexpired offline licenses
|
||||||
// before they are considered to be removed. This could occur if
|
// before they are considered to be removed. This could occur if
|
||||||
@@ -141,13 +138,19 @@ bool EntryIsOfflineLicense(const CdmUsageEntryInfo& info) {
|
|||||||
// Used for stl filters.
|
// Used for stl filters.
|
||||||
return info.storage_type == kStorageLicense;
|
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
|
} // namespace
|
||||||
|
|
||||||
UsageTableHeader::UsageTableHeader()
|
UsageTableHeader::UsageTableHeader() : clock_ref_(&clock_) {
|
||||||
: security_level_(kSecurityLevelUninitialized),
|
|
||||||
requested_security_level_(kLevelDefault),
|
|
||||||
is_inited_(false),
|
|
||||||
clock_ref_(&clock_) {
|
|
||||||
file_system_.reset(new FileSystem());
|
file_system_.reset(new FileSystem());
|
||||||
device_files_.reset(new DeviceFiles(file_system_.get()));
|
device_files_.reset(new DeviceFiles(file_system_.get()));
|
||||||
}
|
}
|
||||||
@@ -159,152 +162,89 @@ bool UsageTableHeader::Init(CdmSecurityLevel security_level,
|
|||||||
LOGE("No crypto session provided");
|
LOGE("No crypto session provided");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (is_initialized_) {
|
||||||
switch (security_level) {
|
LOGE("Cannot reinitialize usage table: security_level = %s",
|
||||||
case kSecurityLevelL1:
|
CdmSecurityLevelToString(security_level));
|
||||||
case kSecurityLevelL3:
|
return false;
|
||||||
break;
|
}
|
||||||
default:
|
if (!IsValidCdmSecurityLevelForUsageInfo(security_level)) {
|
||||||
LOGE("Invalid security level provided: security_level = %d",
|
LOGE("Invalid security level provided: security_level = %d",
|
||||||
static_cast<int>(security_level));
|
static_cast<int>(security_level));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
security_level_ = security_level;
|
security_level_ = security_level;
|
||||||
requested_security_level_ =
|
requested_security_level_ = CdmSecurityLevelToRequestedLevel(security_level);
|
||||||
security_level_ == kSecurityLevelL3 ? kLevel3 : kLevelDefault;
|
|
||||||
|
|
||||||
if (!crypto_session->GetMaximumUsageTableEntries(
|
if (!OpenSessionCheck(crypto_session)) {
|
||||||
requested_security_level_, &potential_table_capacity_)) {
|
return false;
|
||||||
LOGW(
|
}
|
||||||
"Could not determine usage table capacity, assuming default: "
|
if (!DetermineTableCapacity(crypto_session)) {
|
||||||
"default = %zu",
|
return false;
|
||||||
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 (!device_files_->Init(security_level)) {
|
if (!device_files_->Init(security_level)) {
|
||||||
LOGE("Failed to initialize device files");
|
LOGE("Failed to initialize device files");
|
||||||
return false;
|
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;
|
bool UsageTableHeader::RestoreTable(CryptoSession* const crypto_session) {
|
||||||
metrics::CryptoMetrics* metrics = crypto_session->GetCryptoMetrics();
|
|
||||||
if (metrics == nullptr) metrics = &alternate_crypto_metrics_;
|
|
||||||
|
|
||||||
bool run_lru_upgrade = false;
|
bool run_lru_upgrade = false;
|
||||||
if (device_files_->RetrieveUsageTableInfo(
|
if (!device_files_->RetrieveUsageTableInfo(
|
||||||
&usage_table_header_, &usage_entry_info_, &run_lru_upgrade)) {
|
&usage_table_header_, &usage_entry_info_, &run_lru_upgrade)) {
|
||||||
LOGI("Number of usage entries: %zu", usage_entry_info_.size());
|
LOGW("Could not retrieve usage table");
|
||||||
status = crypto_session->LoadUsageTableHeader(requested_security_level_,
|
return false;
|
||||||
usage_table_header_);
|
}
|
||||||
|
LOGI("Found usage table to restore: entry_count = %zu",
|
||||||
|
usage_entry_info_.size());
|
||||||
|
|
||||||
bool lru_success = true;
|
const CdmResponseType status = crypto_session->LoadUsageTableHeader(
|
||||||
if (status == NO_ERROR && run_lru_upgrade) {
|
requested_security_level_, usage_table_header_);
|
||||||
// If the loaded table info does not contain LRU information, then
|
if (status != NO_ERROR) {
|
||||||
// the information must be added immediately before being used.
|
LOGE("Failed to load usage table header: sts = %d",
|
||||||
if (!LruUpgradeAllUsageEntries()) {
|
static_cast<int>(status));
|
||||||
LOGE(
|
return false;
|
||||||
"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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +335,7 @@ CdmResponseType UsageTableHeader::AddEntry(
|
|||||||
return status;
|
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());
|
StoreTable(device_files_.get());
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
@@ -508,6 +448,105 @@ size_t UsageTableHeader::OfflineEntryCount() const {
|
|||||||
EntryIsOfflineLicense);
|
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(
|
CdmResponseType UsageTableHeader::MoveEntry(
|
||||||
uint32_t from_usage_entry_number, const CdmUsageEntry& from_usage_entry,
|
uint32_t from_usage_entry_number, const CdmUsageEntry& from_usage_entry,
|
||||||
uint32_t to_usage_entry_number, DeviceFiles* device_files,
|
uint32_t to_usage_entry_number, DeviceFiles* device_files,
|
||||||
|
|||||||
@@ -44,9 +44,7 @@ using ::testing::UnorderedElementsAre;
|
|||||||
using ::testing::UnorderedElementsAreArray;
|
using ::testing::UnorderedElementsAreArray;
|
||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const std::string kEmptyString;
|
const std::string kEmptyString;
|
||||||
|
|
||||||
constexpr size_t kDefaultTableCapacity = 300;
|
constexpr size_t kDefaultTableCapacity = 300;
|
||||||
@@ -451,6 +449,8 @@ class MockCryptoSession : public TestCryptoSession {
|
|||||||
MOCK_METHOD2(UpdateUsageEntry,
|
MOCK_METHOD2(UpdateUsageEntry,
|
||||||
CdmResponseType(CdmUsageTableHeader*, CdmUsageEntry*));
|
CdmResponseType(CdmUsageTableHeader*, CdmUsageEntry*));
|
||||||
MOCK_METHOD1(MoveUsageEntry, CdmResponseType(uint32_t));
|
MOCK_METHOD1(MoveUsageEntry, CdmResponseType(uint32_t));
|
||||||
|
MOCK_METHOD2(GetNumberOfOpenSessions,
|
||||||
|
CdmResponseType(SecurityLevel, size_t*));
|
||||||
|
|
||||||
// Fake method for testing. Having an EXPECT_CALL causes complexities
|
// Fake method for testing. Having an EXPECT_CALL causes complexities
|
||||||
// for getting table capacity during initialization.
|
// for getting table capacity during initialization.
|
||||||
@@ -566,6 +566,8 @@ class UsageTableHeaderTest : public WvCdmTestBase {
|
|||||||
void Init(CdmSecurityLevel security_level,
|
void Init(CdmSecurityLevel security_level,
|
||||||
const CdmUsageTableHeader& usage_table_header,
|
const CdmUsageTableHeader& usage_table_header,
|
||||||
const std::vector<CdmUsageEntryInfo>& usage_entry_info_vector) {
|
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_,
|
EXPECT_CALL(*device_files_,
|
||||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(usage_table_header),
|
.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_));
|
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_;
|
MockDeviceFiles* device_files_;
|
||||||
metrics::CryptoMetrics crypto_metrics_;
|
metrics::CryptoMetrics crypto_metrics_;
|
||||||
MockCryptoSession* crypto_session_;
|
MockCryptoSession* crypto_session_;
|
||||||
@@ -598,70 +606,17 @@ class UsageTableHeaderInitializationTest
|
|||||||
public ::testing::WithParamInterface<CdmSecurityLevel> {
|
public ::testing::WithParamInterface<CdmSecurityLevel> {
|
||||||
public:
|
public:
|
||||||
static void SetUpTestCase() { InitVectorConstants(); }
|
static void SetUpTestCase() { InitVectorConstants(); }
|
||||||
|
|
||||||
|
SecurityLevel GetSecurityLevel() const {
|
||||||
|
return (GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_P(UsageTableHeaderInitializationTest, CreateUsageTableHeader) {
|
TEST_P(UsageTableHeaderInitializationTest, RestoreUsageTable_Success) {
|
||||||
const SecurityLevel security_level =
|
const SecurityLevel security_level = GetSecurityLevel();
|
||||||
(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_,
|
EXPECT_CALL(*crypto_session_,
|
||||||
CreateUsageTableHeader(security_level, NotNull()))
|
GetNumberOfOpenSessions(security_level, NotNull()))
|
||||||
.WillOnce(
|
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||||
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;
|
|
||||||
EXPECT_CALL(*device_files_,
|
EXPECT_CALL(*device_files_,
|
||||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||||
@@ -670,15 +625,172 @@ TEST_P(UsageTableHeaderInitializationTest, UsageTableHeaderExists) {
|
|||||||
EXPECT_CALL(*crypto_session_,
|
EXPECT_CALL(*crypto_session_,
|
||||||
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
||||||
.WillOnce(Return(NO_ERROR));
|
.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_));
|
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;
|
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
|
||||||
usage_entries.resize(kDefaultTableCapacity);
|
usage_entries.resize(kDefaultTableCapacity);
|
||||||
const SecurityLevel security_level =
|
const SecurityLevel security_level = GetSecurityLevel();
|
||||||
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
|
// 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_,
|
EXPECT_CALL(*device_files_,
|
||||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||||
@@ -687,18 +799,25 @@ TEST_P(UsageTableHeaderInitializationTest, UsageEntriesAtCapacity) {
|
|||||||
EXPECT_CALL(*crypto_session_,
|
EXPECT_CALL(*crypto_session_,
|
||||||
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
||||||
.WillOnce(Return(NO_ERROR));
|
.WillOnce(Return(NO_ERROR));
|
||||||
|
|
||||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
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,
|
TEST_P(UsageTableHeaderInitializationTest,
|
||||||
UsageEntries_NoCapacity_UnderMinimum) {
|
RestoreUsageTable_NoCapacity_UnderMinimum) {
|
||||||
crypto_session_->SetMaximumUsageTableEntries(0); // Unlimited.
|
crypto_session_->SetMaximumUsageTableEntries(0); // Unlimited.
|
||||||
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
|
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
|
||||||
constexpr size_t kHalfMinCapacity = kDefaultTableCapacity / 2;
|
constexpr size_t kHalfMinCapacity = kDefaultTableCapacity / 2;
|
||||||
usage_entries.resize(kHalfMinCapacity);
|
usage_entries.resize(kHalfMinCapacity);
|
||||||
const SecurityLevel security_level =
|
const SecurityLevel security_level = GetSecurityLevel();
|
||||||
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
|
// 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_,
|
EXPECT_CALL(*device_files_,
|
||||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||||
@@ -707,136 +826,134 @@ TEST_P(UsageTableHeaderInitializationTest,
|
|||||||
EXPECT_CALL(*crypto_session_,
|
EXPECT_CALL(*crypto_session_,
|
||||||
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
||||||
.WillOnce(Return(NO_ERROR));
|
.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_));
|
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.
|
crypto_session_->SetMaximumUsageTableEntries(0); // Unlimited.
|
||||||
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
|
ASSERT_LT(kDefaultTableCapacity, kOverFullUsageEntryInfoVector.size());
|
||||||
usage_entries.resize(kDefaultTableCapacity);
|
const size_t kTableStartSize = kOverFullUsageEntryInfoVector.size();
|
||||||
const SecurityLevel security_level =
|
const SecurityLevel security_level = GetSecurityLevel();
|
||||||
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
|
|
||||||
|
// 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_,
|
EXPECT_CALL(*device_files_,
|
||||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||||
SetArgPointee<1>(usage_entries), SetArgPointee<2>(false),
|
SetArgPointee<1>(kOverFullUsageEntryInfoVector),
|
||||||
Return(true)));
|
SetArgPointee<2>(false), Return(true)));
|
||||||
EXPECT_CALL(*crypto_session_,
|
EXPECT_CALL(*crypto_session_,
|
||||||
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
||||||
.WillOnce(Return(NO_ERROR));
|
.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))
|
EXPECT_CALL(*crypto_session_, Open(security_level))
|
||||||
.WillOnce(Return(NO_ERROR));
|
.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()))
|
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||||
.WillOnce(
|
.WillOnce(
|
||||||
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
|
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
|
||||||
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
|
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
|
||||||
.WillOnce(
|
.WillOnce(
|
||||||
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||||
EXPECT_CALL(*device_files_,
|
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader,
|
||||||
StoreUsageTableInfo(kAnotherUsageTableHeader,
|
SizeIs(kTableStartSize + 1)))
|
||||||
SizeIs(kDefaultTableCapacity + 1)))
|
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
|
EXPECT_CALL(*crypto_session_, ShrinkUsageTableHeader(
|
||||||
// Delete the entry after.
|
security_level, kTableStartSize, NotNull()))
|
||||||
EXPECT_CALL(
|
|
||||||
*crypto_session_,
|
|
||||||
ShrinkUsageTableHeader(security_level, kDefaultTableCapacity, NotNull()))
|
|
||||||
.WillOnce(DoAll(SetArgPointee<2>(kYetAnotherUsageTableHeader),
|
.WillOnce(DoAll(SetArgPointee<2>(kYetAnotherUsageTableHeader),
|
||||||
Return(NO_ERROR)));
|
Return(NO_ERROR)));
|
||||||
EXPECT_CALL(*device_files_,
|
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kYetAnotherUsageTableHeader,
|
||||||
StoreUsageTableInfo(kYetAnotherUsageTableHeader,
|
SizeIs(kTableStartSize)))
|
||||||
SizeIs(kDefaultTableCapacity)))
|
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
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,
|
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_,
|
EXPECT_CALL(*device_files_,
|
||||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||||
SetArgPointee<1>(kOverFullUsageEntryInfoVector),
|
SetArgPointee<1>(kOverFullUsageEntryInfoVector),
|
||||||
SetArgPointee<2>(false), Return(true)));
|
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_,
|
EXPECT_CALL(*crypto_session_,
|
||||||
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
||||||
.WillOnce(Return(NO_ERROR));
|
.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
|
// Expectations for capacity check:
|
||||||
const uint32_t expect_usage_entry_number =
|
// 1) Open a new crypto session.
|
||||||
kOverFullUsageEntryInfoVector.size();
|
// 2) Creating a new usage entry within OEMCrypto fails
|
||||||
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.
|
|
||||||
EXPECT_CALL(*crypto_session_, Open(security_level))
|
EXPECT_CALL(*crypto_session_, Open(security_level))
|
||||||
.WillOnce(Return(NO_ERROR));
|
.WillOnce(Return(NO_ERROR));
|
||||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||||
.WillOnce(Return(CREATE_USAGE_ENTRY_UNKNOWN_ERROR));
|
.WillOnce(Return(CREATE_USAGE_ENTRY_UNKNOWN_ERROR));
|
||||||
// Expect clean up.
|
|
||||||
EXPECT_CALL(*device_files_, DeleteAllLicenses()).WillOnce(Return(true));
|
// Expectations for create:
|
||||||
EXPECT_CALL(*device_files_, DeleteAllUsageInfo()).WillOnce(Return(true));
|
// 1) Existing table is destroyed (files etc.)
|
||||||
EXPECT_CALL(*device_files_, DeleteUsageTableInfo()).WillOnce(Return(true));
|
// 2) Create new header within OEMCrypto succeeds
|
||||||
// Expect recreation of usage table.
|
// 3) Storing the table header fails
|
||||||
|
ExpectToDeleteUsageTableFiles();
|
||||||
EXPECT_CALL(*crypto_session_,
|
EXPECT_CALL(*crypto_session_,
|
||||||
CreateUsageTableHeader(security_level, NotNull()))
|
CreateUsageTableHeader(security_level, NotNull()))
|
||||||
.WillOnce(
|
.WillOnce(
|
||||||
DoAll(SetArgPointee<1>(kEmptyUsageTableHeader), Return(NO_ERROR)));
|
DoAll(SetArgPointee<1>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader,
|
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader,
|
||||||
kEmptyUsageEntryInfoVector))
|
kEmptyUsageEntryInfoVector))
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
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,
|
TEST_P(UsageTableHeaderInitializationTest,
|
||||||
UsageEntriesOverCapacity_AddInvalidateEntrySucceeds) {
|
RestoreUsageTable_NoCapacity_AboveMinimum_InvalidateEntryFails) {
|
||||||
// Capacity +2.
|
crypto_session_->SetMaximumUsageTableEntries(0); // Unlimited.
|
||||||
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
|
ASSERT_LT(kDefaultTableCapacity, kOverFullUsageEntryInfoVector.size());
|
||||||
usage_entries.push_back(kDummyUsageEntryInfo);
|
const size_t kTableStartSize = kOverFullUsageEntryInfoVector.size();
|
||||||
|
const SecurityLevel security_level = GetSecurityLevel();
|
||||||
const SecurityLevel security_level =
|
|
||||||
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
|
|
||||||
|
|
||||||
|
// 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_,
|
EXPECT_CALL(*device_files_,
|
||||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||||
@@ -846,30 +963,42 @@ TEST_P(UsageTableHeaderInitializationTest,
|
|||||||
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
LoadUsageTableHeader(security_level, kUsageTableHeader))
|
||||||
.WillOnce(Return(NO_ERROR));
|
.WillOnce(Return(NO_ERROR));
|
||||||
|
|
||||||
// Expectations for AddEntry
|
// Expectations for capacity check:
|
||||||
const uint32_t expect_usage_entry_number =
|
// 1) Open a new crypto session.
|
||||||
kOverFullUsageEntryInfoVector.size();
|
// 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()))
|
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||||
.WillOnce(
|
.WillOnce(
|
||||||
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
|
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
|
||||||
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
|
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
|
||||||
.WillOnce(
|
.WillOnce(
|
||||||
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||||
EXPECT_CALL(*device_files_,
|
// Called twice due to defrag.
|
||||||
StoreUsageTableInfo(kAnotherUsageTableHeader, usage_entries))
|
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader,
|
||||||
.WillOnce(Return(true));
|
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.
|
// Expectations for create:
|
||||||
EXPECT_CALL(*crypto_session_, Open(security_level))
|
// 1) Existing table is destroyed (files etc.)
|
||||||
.WillOnce(Return(NO_ERROR));
|
// 2) Create new header within OEMCrypto succeeds
|
||||||
|
// 3) Storing the table header succeeds
|
||||||
|
ExpectToDeleteUsageTableFiles();
|
||||||
EXPECT_CALL(*crypto_session_,
|
EXPECT_CALL(*crypto_session_,
|
||||||
ShrinkUsageTableHeader(security_level, usage_entries.size() - 1,
|
CreateUsageTableHeader(security_level, NotNull()))
|
||||||
NotNull()))
|
.WillOnce(DoAll(SetArgPointee<1>(kYetAnotherUsageTableHeader),
|
||||||
.WillOnce(DoAll(SetArgPointee<2>(kYetAnotherUsageTableHeader),
|
|
||||||
Return(NO_ERROR)));
|
Return(NO_ERROR)));
|
||||||
EXPECT_CALL(*device_files_,
|
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kYetAnotherUsageTableHeader,
|
||||||
StoreUsageTableInfo(kYetAnotherUsageTableHeader,
|
kEmptyUsageEntryInfoVector))
|
||||||
SizeIs(kOverFullUsageEntryInfoVector.size())))
|
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
|
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) {
|
TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailed_UnknownError) {
|
||||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||||
uint32_t usage_entry_number;
|
const uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size();
|
||||||
uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size();
|
|
||||||
|
|
||||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(expect_usage_entry_number),
|
.WillOnce(DoAll(SetArgPointee<0>(expect_usage_entry_number),
|
||||||
Return(CREATE_USAGE_ENTRY_UNKNOWN_ERROR)));
|
Return(CREATE_USAGE_ENTRY_UNKNOWN_ERROR)));
|
||||||
|
|
||||||
|
uint32_t usage_entry_number = 0;
|
||||||
EXPECT_NE(NO_ERROR,
|
EXPECT_NE(NO_ERROR,
|
||||||
usage_table_header_->AddEntry(
|
usage_table_header_->AddEntry(
|
||||||
crypto_session_,
|
crypto_session_,
|
||||||
@@ -898,13 +1026,12 @@ TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailed_UnknownError) {
|
|||||||
|
|
||||||
TEST_F(UsageTableHeaderTest, AddEntry_UsageEntryTooSmall) {
|
TEST_F(UsageTableHeaderTest, AddEntry_UsageEntryTooSmall) {
|
||||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||||
uint32_t usage_entry_number;
|
const uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size() - 1;
|
||||||
uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size() - 1;
|
|
||||||
|
|
||||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||||
.WillOnce(
|
.WillOnce(
|
||||||
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
|
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
|
||||||
|
|
||||||
|
uint32_t usage_entry_number = 0;
|
||||||
EXPECT_NE(NO_ERROR,
|
EXPECT_NE(NO_ERROR,
|
||||||
usage_table_header_->AddEntry(
|
usage_table_header_->AddEntry(
|
||||||
crypto_session_,
|
crypto_session_,
|
||||||
@@ -916,11 +1043,9 @@ TEST_F(UsageTableHeaderTest, AddEntry_UsageEntryTooSmall) {
|
|||||||
|
|
||||||
TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveOfflineUsageEntry) {
|
TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveOfflineUsageEntry) {
|
||||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||||
uint32_t usage_entry_number;
|
const uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size();
|
||||||
uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size();
|
|
||||||
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
|
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
|
||||||
kUsageEntryInfoVector;
|
kUsageEntryInfoVector;
|
||||||
|
|
||||||
expect_usage_entry_info_vector.resize(expect_usage_entry_number + 1);
|
expect_usage_entry_info_vector.resize(expect_usage_entry_number + 1);
|
||||||
expect_usage_entry_info_vector[expect_usage_entry_number] =
|
expect_usage_entry_info_vector[expect_usage_entry_number] =
|
||||||
kUsageEntryInfoOfflineLicense2;
|
kUsageEntryInfoOfflineLicense2;
|
||||||
@@ -937,6 +1062,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveOfflineUsageEntry) {
|
|||||||
UnorderedElementsAreArray(expect_usage_entry_info_vector)))
|
UnorderedElementsAreArray(expect_usage_entry_info_vector)))
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
|
uint32_t usage_entry_number = 0;
|
||||||
EXPECT_EQ(NO_ERROR,
|
EXPECT_EQ(NO_ERROR,
|
||||||
usage_table_header_->AddEntry(
|
usage_table_header_->AddEntry(
|
||||||
crypto_session_,
|
crypto_session_,
|
||||||
@@ -949,8 +1075,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveOfflineUsageEntry) {
|
|||||||
|
|
||||||
TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveSecureStopUsageEntry) {
|
TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveSecureStopUsageEntry) {
|
||||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||||
uint32_t usage_entry_number;
|
const uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size();
|
||||||
uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size();
|
|
||||||
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
|
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
|
||||||
kUsageEntryInfoVector;
|
kUsageEntryInfoVector;
|
||||||
|
|
||||||
@@ -970,6 +1095,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveSecureStopUsageEntry) {
|
|||||||
UnorderedElementsAreArray(expect_usage_entry_info_vector)))
|
UnorderedElementsAreArray(expect_usage_entry_info_vector)))
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
|
uint32_t usage_entry_number = 0;
|
||||||
EXPECT_EQ(NO_ERROR,
|
EXPECT_EQ(NO_ERROR,
|
||||||
usage_table_header_->AddEntry(
|
usage_table_header_->AddEntry(
|
||||||
crypto_session_,
|
crypto_session_,
|
||||||
@@ -982,8 +1108,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveSecureStopUsageEntry) {
|
|||||||
|
|
||||||
TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) {
|
TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) {
|
||||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||||
uint32_t usage_entry_number;
|
const uint32_t next_usage_entry_number = kUsageEntryInfoVector.size();
|
||||||
uint32_t next_usage_entry_number = kUsageEntryInfoVector.size();
|
|
||||||
size_t skip_usage_entries = 3;
|
size_t skip_usage_entries = 3;
|
||||||
uint32_t expect_usage_entry_number =
|
uint32_t expect_usage_entry_number =
|
||||||
next_usage_entry_number + skip_usage_entries;
|
next_usage_entry_number + skip_usage_entries;
|
||||||
@@ -1006,6 +1131,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) {
|
|||||||
kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoSecureStop2)))
|
kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoSecureStop2)))
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
|
uint32_t usage_entry_number = 0;
|
||||||
EXPECT_EQ(NO_ERROR,
|
EXPECT_EQ(NO_ERROR,
|
||||||
usage_table_header_->AddEntry(
|
usage_table_header_->AddEntry(
|
||||||
crypto_session_,
|
crypto_session_,
|
||||||
@@ -1123,7 +1249,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailsEveryTime) {
|
|||||||
|
|
||||||
TEST_F(UsageTableHeaderTest, LoadEntry_InvalidEntryNumber) {
|
TEST_F(UsageTableHeaderTest, LoadEntry_InvalidEntryNumber) {
|
||||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
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(
|
EXPECT_NE(NO_ERROR, usage_table_header_->LoadEntry(
|
||||||
crypto_session_, kUsageEntry, usage_entry_number));
|
crypto_session_, kUsageEntry, usage_entry_number));
|
||||||
@@ -1131,7 +1257,7 @@ TEST_F(UsageTableHeaderTest, LoadEntry_InvalidEntryNumber) {
|
|||||||
|
|
||||||
TEST_F(UsageTableHeaderTest, LoadEntry_CryptoSessionError) {
|
TEST_F(UsageTableHeaderTest, LoadEntry_CryptoSessionError) {
|
||||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
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))
|
EXPECT_CALL(*crypto_session_, LoadUsageEntry(usage_entry_number, kUsageEntry))
|
||||||
.WillOnce(Return(LOAD_USAGE_ENTRY_GENERATION_SKEW));
|
.WillOnce(Return(LOAD_USAGE_ENTRY_GENERATION_SKEW));
|
||||||
@@ -1142,7 +1268,7 @@ TEST_F(UsageTableHeaderTest, LoadEntry_CryptoSessionError) {
|
|||||||
|
|
||||||
TEST_F(UsageTableHeaderTest, LoadEntry) {
|
TEST_F(UsageTableHeaderTest, LoadEntry) {
|
||||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
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))
|
EXPECT_CALL(*crypto_session_, LoadUsageEntry(usage_entry_number, kUsageEntry))
|
||||||
.WillOnce(Return(NO_ERROR));
|
.WillOnce(Return(NO_ERROR));
|
||||||
@@ -1184,7 +1310,7 @@ TEST_F(UsageTableHeaderTest, UpdateEntry) {
|
|||||||
|
|
||||||
TEST_F(UsageTableHeaderTest, InvalidateEntry_InvalidUsageEntryNumber) {
|
TEST_F(UsageTableHeaderTest, InvalidateEntry_InvalidUsageEntryNumber) {
|
||||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||||
uint32_t usage_entry_number = kUsageEntryInfoVector.size();
|
const uint32_t usage_entry_number = kUsageEntryInfoVector.size();
|
||||||
metrics::CryptoMetrics metrics;
|
metrics::CryptoMetrics metrics;
|
||||||
|
|
||||||
EXPECT_NE(NO_ERROR, usage_table_header_->InvalidateEntry(
|
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,
|
ToVector(usage_entry_info_vector, usage_entry_info_array,
|
||||||
sizeof(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_,
|
EXPECT_CALL(*device_files_,
|
||||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
|
||||||
@@ -3211,14 +3340,12 @@ TEST_F(UsageTableHeaderTest, StaleHeader) {
|
|||||||
EXPECT_CALL(*crypto_session_,
|
EXPECT_CALL(*crypto_session_,
|
||||||
LoadUsageTableHeader(kLevelDefault, kUsageTableHeader))
|
LoadUsageTableHeader(kLevelDefault, kUsageTableHeader))
|
||||||
.WillOnce(Return(LOAD_USAGE_HEADER_GENERATION_SKEW));
|
.WillOnce(Return(LOAD_USAGE_HEADER_GENERATION_SKEW));
|
||||||
|
ExpectToDeleteUsageTableFiles();
|
||||||
EXPECT_CALL(*crypto_session_,
|
EXPECT_CALL(*crypto_session_,
|
||||||
CreateUsageTableHeader(kLevelDefault, NotNull()))
|
CreateUsageTableHeader(kLevelDefault, NotNull()))
|
||||||
.WillOnce(
|
.WillOnce(
|
||||||
DoAll(SetArgPointee<1>(kEmptyUsageTableHeader), Return(NO_ERROR)));
|
DoAll(SetArgPointee<1>(kAnotherUsageTableHeader), Return(NO_ERROR)));
|
||||||
EXPECT_CALL(*device_files_, DeleteAllLicenses()).WillOnce(Return(true));
|
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader,
|
||||||
EXPECT_CALL(*device_files_, DeleteAllUsageInfo()).WillOnce(Return(true));
|
|
||||||
EXPECT_CALL(*device_files_, DeleteUsageTableInfo()).WillOnce(Return(true));
|
|
||||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader,
|
|
||||||
kEmptyUsageEntryInfoVector))
|
kEmptyUsageEntryInfoVector))
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
@@ -3302,6 +3429,9 @@ TEST_F(UsageTableHeaderTest, Shrink_MoreThanTable) {
|
|||||||
// the table header and entries are configured for LRU.
|
// the table header and entries are configured for LRU.
|
||||||
// 2. No upgrading action is taken.
|
// 2. No upgrading action is taken.
|
||||||
TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_NoAction) {
|
TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_NoAction) {
|
||||||
|
EXPECT_CALL(*crypto_session_,
|
||||||
|
GetNumberOfOpenSessions(kLevelDefault, NotNull()))
|
||||||
|
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||||
EXPECT_CALL(*device_files_,
|
EXPECT_CALL(*device_files_,
|
||||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(kUpgradableUsageTableHeader),
|
.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
|
// 2. The usage table header will load license or usage information to
|
||||||
// determine appropriate expiry and last_used times.
|
// determine appropriate expiry and last_used times.
|
||||||
TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_Succeed) {
|
TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_Succeed) {
|
||||||
|
EXPECT_CALL(*crypto_session_,
|
||||||
|
GetNumberOfOpenSessions(kLevelDefault, NotNull()))
|
||||||
|
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||||
EXPECT_CALL(*device_files_,
|
EXPECT_CALL(*device_files_,
|
||||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(kUpgradableUsageTableHeader),
|
.WillOnce(DoAll(SetArgPointee<0>(kUpgradableUsageTableHeader),
|
||||||
@@ -3395,6 +3528,9 @@ TEST_F(UsageTableHeaderTest,
|
|||||||
upgraded_usage_entry_info_list[2].storage_type = kStorageTypeUnknown;
|
upgraded_usage_entry_info_list[2].storage_type = kStorageTypeUnknown;
|
||||||
|
|
||||||
// Load table expectations.
|
// Load table expectations.
|
||||||
|
EXPECT_CALL(*crypto_session_,
|
||||||
|
GetNumberOfOpenSessions(kLevelDefault, NotNull()))
|
||||||
|
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||||
EXPECT_CALL(*device_files_,
|
EXPECT_CALL(*device_files_,
|
||||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(kUpgradableUsageTableHeader),
|
.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.last_use_time = 0;
|
||||||
wrond_typed_usage_entry_info.offline_license_expiry_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_,
|
EXPECT_CALL(*device_files_,
|
||||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(kUpgradableUsageTableHeader),
|
.WillOnce(DoAll(SetArgPointee<0>(kUpgradableUsageTableHeader),
|
||||||
@@ -3510,6 +3649,9 @@ TEST_F(UsageTableHeaderTest,
|
|||||||
// that the table has not been configured for upgrade.
|
// that the table has not been configured for upgrade.
|
||||||
// 2. None of the entries can have their license info loaded.
|
// 2. None of the entries can have their license info loaded.
|
||||||
TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_AllFailure) {
|
TEST_F(UsageTableHeaderTest, LruUsageTableUpgrade_AllFailure) {
|
||||||
|
EXPECT_CALL(*crypto_session_,
|
||||||
|
GetNumberOfOpenSessions(kLevelDefault, NotNull()))
|
||||||
|
.WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
|
||||||
EXPECT_CALL(*device_files_,
|
EXPECT_CALL(*device_files_,
|
||||||
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(kUpgradableUsageTableHeader),
|
.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
|
// After failure, these will be called to clear files and create a new
|
||||||
// usage table header.
|
// usage table header.
|
||||||
EXPECT_CALL(*device_files_, DeleteAllLicenses());
|
ExpectToDeleteUsageTableFiles();
|
||||||
EXPECT_CALL(*device_files_, DeleteAllUsageInfo());
|
|
||||||
EXPECT_CALL(*device_files_, DeleteUsageTableInfo());
|
|
||||||
EXPECT_CALL(*crypto_session_,
|
EXPECT_CALL(*crypto_session_,
|
||||||
CreateUsageTableHeader(kLevelDefault, NotNull()))
|
CreateUsageTableHeader(kLevelDefault, NotNull()))
|
||||||
.WillOnce(Return(NO_ERROR));
|
.WillOnce(DoAll(SetArgPointee<1>(kUsageTableHeader), Return(NO_ERROR)));
|
||||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(_, _));
|
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kUsageTableHeader,
|
||||||
|
kEmptyUsageEntryInfoVector))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
EXPECT_TRUE(usage_table_header_->Init(kSecurityLevelL1, crypto_session_));
|
EXPECT_TRUE(usage_table_header_->Init(kSecurityLevelL1, crypto_session_));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateLicenseEntry) {
|
TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateLicenseEntry) {
|
||||||
// General setup.
|
Init(kSecurityLevelL1, kUpgradedUsageTableHeader,
|
||||||
EXPECT_CALL(*device_files_,
|
kUpgradedUsageEntryInfoList);
|
||||||
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_));
|
|
||||||
|
|
||||||
// Expected values.
|
// Expected values.
|
||||||
const uint32_t expected_usage_entry_number =
|
const uint32_t expected_usage_entry_number =
|
||||||
@@ -3598,17 +3731,8 @@ TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateLicenseEntry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateUsageInfoEntry) {
|
TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateUsageInfoEntry) {
|
||||||
// General setup.
|
Init(kSecurityLevelL1, kUpgradedUsageTableHeader,
|
||||||
EXPECT_CALL(*device_files_,
|
kUpgradedUsageEntryInfoList);
|
||||||
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_));
|
|
||||||
|
|
||||||
// Expected values.
|
// Expected values.
|
||||||
const uint32_t expected_usage_entry_number =
|
const uint32_t expected_usage_entry_number =
|
||||||
@@ -3646,17 +3770,8 @@ TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateUsageInfoEntry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(UsageTableHeaderTest, LruLastUsedTime_UpdateEntry) {
|
TEST_F(UsageTableHeaderTest, LruLastUsedTime_UpdateEntry) {
|
||||||
// General setup.
|
Init(kSecurityLevelL1, kUpgradedUsageTableHeader,
|
||||||
EXPECT_CALL(*device_files_,
|
kUpgradedUsageEntryInfoList);
|
||||||
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_));
|
|
||||||
|
|
||||||
std::vector<CdmUsageEntryInfo> expected_usage_info_list =
|
std::vector<CdmUsageEntryInfo> expected_usage_info_list =
|
||||||
kUpgradedUsageEntryInfoList;
|
kUpgradedUsageEntryInfoList;
|
||||||
@@ -3689,17 +3804,8 @@ TEST_F(UsageTableHeaderTest, LruLastUsedTime_UpdateEntry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(UsageTableHeaderTest, LruLastUsedTime_LoadEntry) {
|
TEST_F(UsageTableHeaderTest, LruLastUsedTime_LoadEntry) {
|
||||||
// General setup.
|
Init(kSecurityLevelL1, kUpgradedUsageTableHeader,
|
||||||
EXPECT_CALL(*device_files_,
|
kUpgradedUsageEntryInfoList);
|
||||||
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_));
|
|
||||||
|
|
||||||
std::vector<CdmUsageEntryInfo> expected_usage_info_list =
|
std::vector<CdmUsageEntryInfo> expected_usage_info_list =
|
||||||
kUpgradedUsageEntryInfoList;
|
kUpgradedUsageEntryInfoList;
|
||||||
@@ -4091,5 +4197,4 @@ TEST_F(UsageTableHeaderTest, PotentialTableCapacity_Available) {
|
|||||||
EXPECT_EQ(usage_table_header_->potential_table_capacity(), kTableCapacity);
|
EXPECT_EQ(usage_table_header_->potential_table_capacity(), kTableCapacity);
|
||||||
EXPECT_FALSE(usage_table_header_->HasUnlimitedTableCapacity());
|
EXPECT_FALSE(usage_table_header_->HasUnlimitedTableCapacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace wvcdm
|
} // namespace wvcdm
|
||||||
|
|||||||
Reference in New Issue
Block a user