Check for open session when initializing usage table. am: 023b06eded
Original change: https://googleplex-android-review.googlesource.com/c/platform/vendor/widevine/+/14296026 Change-Id: I4b0b46d585f99c492e30e608a0a18708fc40b042
This commit is contained in:
@@ -293,7 +293,7 @@ class CryptoSession {
|
|||||||
// exist as long as the new CryptoSession exists.
|
// 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