DO NOT MERGE Handle unlimited usage table capacity. am: 99335a6aa8

Original change: https://googleplex-android-review.googlesource.com/c/platform/vendor/widevine/+/12266132

Change-Id: I25cb6ad05f466357fa4e2485a093ae8598bd5b51
This commit is contained in:
Alex Dale
2020-08-17 19:19:36 +00:00
committed by Automerger Merge Worker
6 changed files with 275 additions and 87 deletions

View File

@@ -93,6 +93,10 @@ class UsageTableHeader {
size_t potential_table_capacity() const { return potential_table_capacity_; }
bool HasUnlimitedTableCapacity() const {
return potential_table_capacity_ == 0;
}
// Returns the number of entries currently tracked by the CDM that
// are related to usage info (streaming licenses).
size_t UsageInfoCount() const;

View File

@@ -8,6 +8,7 @@
#include <stdlib.h>
#include <iostream>
#include <limits>
#include <list>
#include <memory>
#include <sstream>
@@ -696,6 +697,12 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
LOGW("GetMaxUsageTableEntries failed");
return UNKNOWN_ERROR;
}
if (max_number_of_usage_entries == 0) {
// Zero indicates that the table is dynamically allocated and does
// not have a defined limit. Setting to max value of int32_t to
// be able to fit into a Java int.
max_number_of_usage_entries = std::numeric_limits<int32_t>::max();
}
*query_response = std::to_string(max_number_of_usage_entries);
return NO_ERROR;
} else if (query_token == QUERY_KEY_OEMCRYPTO_API_MINOR_VERSION) {

View File

@@ -2002,6 +2002,11 @@ bool CryptoSession::GetMaximumUsageTableEntries(SecurityLevel security_level,
metrics_->oemcrypto_maximum_usage_table_header_size_.Record(
*number_of_entries);
if (*number_of_entries == 0) {
// Special value, indicating that the table size is not directly
// limited.
return true;
}
return *number_of_entries >= kMinimumUsageTableEntriesSupported;
}

View File

@@ -178,13 +178,23 @@ bool UsageTableHeader::Init(CdmSecurityLevel security_level,
if (!crypto_session->GetMaximumUsageTableEntries(
requested_security_level_, &potential_table_capacity_)) {
LOGW(
"Could not determine usage table capacity, assuming default: "
"default = %zu",
kMinimumUsageTableEntriesSupported);
potential_table_capacity_ = kMinimumUsageTableEntriesSupported;
} else if (potential_table_capacity_ == 0) {
LOGD("Usage table capacity is unlimited: security_level = %d",
static_cast<int>(security_level));
} else if (potential_table_capacity_ < kMinimumUsageTableEntriesSupported) {
LOGW(
"Reported usage table capacity is smaller than minimally required: "
"capacity = %zu, minimum = %zu",
potential_table_capacity_, kMinimumUsageTableEntriesSupported);
potential_table_capacity_ = kMinimumUsageTableEntriesSupported;
} else {
LOGD("Usage table capacity: %zu, security_level = %d",
potential_table_capacity_, static_cast<int>(security_level));
}
if (!device_files_->Init(security_level)) {
@@ -215,11 +225,21 @@ bool UsageTableHeader::Init(CdmSecurityLevel security_level,
}
}
// If the usage table header has been successfully loaded, and is at
// minimum capacity (>200), we need to make sure we can still add and
// remove entries. If not, clear files/data and recreate usage header table.
// If the usage table header has been successfully loaded, and is
// at minimum capacity (>200) or the table size does not have a
// hard limit, we need to make sure we can still add and remove
// entries. If not, clear files/data and recreate usage header
// table.
if (status == NO_ERROR && lru_success) {
if (usage_entry_info_.size() > potential_table_capacity()) {
if ((HasUnlimitedTableCapacity() &&
usage_entry_info_.size() > kMinimumUsageTableEntriesSupported) ||
(!HasUnlimitedTableCapacity() &&
usage_entry_info_.size() > potential_table_capacity())) {
LOGD("Checking if new entry can be added: size = %zu, capacity = %s",
usage_entry_info_.size(),
HasUnlimitedTableCapacity()
? "unlimited"
: std::to_string(potential_table_capacity()).c_str());
uint32_t temporary_usage_entry_number;
// Create a new temporary usage entry, close the session and then
@@ -361,6 +381,18 @@ CdmResponseType UsageTableHeader::AddEntry(
}
}
// Call to update the usage table header, but don't store the usage
// entry. If the entry is used by the CDM, the CDM session will make
// subsequent calls to update the usage entry and store that entry.
std::string usage_entry;
status = crypto_session->UpdateUsageEntry(&usage_table_header_, &usage_entry);
if (status != NO_ERROR) {
LOGE("Failed to update new usage entry: usage_entry_number = %u",
*usage_entry_number);
usage_entry_info_[*usage_entry_number].Clear();
return status;
}
LOGI("New usage entry: usage_entry_number = %u", *usage_entry_number);
StoreTable(device_files_.get());
return NO_ERROR;
@@ -1120,7 +1152,9 @@ bool UsageTableHeader::GetRemovalCandidates(
LOGI("Locking to determine removal candidates");
std::unique_lock<std::mutex> auto_lock(usage_table_header_lock_);
const size_t lru_unexpired_threshold =
kLruUnexpiredThresholdFraction * potential_table_capacity();
HasUnlimitedTableCapacity()
? kLruUnexpiredThresholdFraction * size()
: kLruUnexpiredThresholdFraction * potential_table_capacity();
return DetermineLicenseToRemove(usage_entry_info_, GetCurrentTime(),
lru_unexpired_threshold, kLruRemovalSetSize,
removal_candidates);

View File

@@ -316,8 +316,6 @@ TEST_F(CryptoSessionMetricsTest, OpenSessionValidMetrics) {
EXPECT_EQ(OEMCrypto_Keybox,
metrics_proto.oemcrypto_provisioning_method().int_value());
EXPECT_EQ(1, metrics_proto.oemcrypto_get_key_data_time_us().size());
EXPECT_EQ(
1u, metrics_proto.oemcrypto_get_key_data_time_us(0).operation_count());
} else if (token_type == kClientTokenOemCert) {
// Recent devices all have a system id between 1k and 6 or 7k. Errors
// we are trying to catch are 0, byte swapped 32 bit numbers, or
@@ -365,8 +363,6 @@ TEST_F(CryptoSessionMetricsTest, GetProvisioningTokenValidMetrics) {
uint32_t system_id = FindKeyboxSystemID();
EXPECT_EQ(system_id, metrics_proto.crypto_session_system_id().int_value());
EXPECT_EQ(1, metrics_proto.oemcrypto_get_key_data_time_us().size());
EXPECT_EQ(
2u, metrics_proto.oemcrypto_get_key_data_time_us(0).operation_count());
} else if (token_type == kClientTokenOemCert) {
// Recent devices all have a system id between 1k and 6 or 7k. Errors
// we are trying to catch are 0, byte swapped 32 bit numbers, or

View File

@@ -21,12 +21,36 @@
#include "wv_cdm_constants.h"
#include "wv_cdm_types.h"
// gmock methods
using ::testing::_;
using ::testing::AllOf;
using ::testing::AtMost;
using ::testing::ContainerEq;
using ::testing::Contains;
using ::testing::DoAll;
using ::testing::ElementsAre;
using ::testing::ElementsAreArray;
using ::testing::Ge;
using ::testing::Invoke;
using ::testing::InvokeWithoutArgs;
using ::testing::Lt;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
using ::testing::SizeIs;
using ::testing::StrEq;
using ::testing::UnorderedElementsAre;
using ::testing::UnorderedElementsAreArray;
namespace wvcdm {
namespace {
const std::string kEmptyString;
constexpr size_t kDefaultTableCapacity = 300;
constexpr int64_t kDefaultExpireDuration = 33 * 24 * 60 * 60; // 33 Days
const CdmUsageTableHeader kEmptyUsageTableHeader;
@@ -172,7 +196,7 @@ const std::vector<DeviceFiles::CdmUsageData> kEmptyUsageInfoUsageDataList;
const std::vector<CdmUsageEntryInfo> kEmptyUsageEntryInfoVector;
std::vector<CdmUsageEntryInfo> kUsageEntryInfoVector;
std::vector<CdmUsageEntryInfo> k10UsageEntryInfoVector;
std::vector<CdmUsageEntryInfo> k201UsageEntryInfoVector;
std::vector<CdmUsageEntryInfo> kOverFullUsageEntryInfoVector;
const DeviceFiles::LicenseState kActiveLicenseState =
DeviceFiles::kLicenseStateActive;
@@ -275,23 +299,24 @@ void InitVectorConstants() {
k10UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense5);
k10UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop5);
k201UsageEntryInfoVector.clear();
for (size_t i = 0; i < 201; ++i) {
kOverFullUsageEntryInfoVector.clear();
for (size_t i = 0; i < (kDefaultTableCapacity + 1); ++i) {
switch (i % 4) {
case 0:
k201UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense1);
kOverFullUsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense1);
break;
case 1:
k201UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop1);
kOverFullUsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop1);
break;
case 2:
k201UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense2);
kOverFullUsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense2);
break;
case 3:
k201UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop2);
kOverFullUsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop2);
break;
default:
k201UsageEntryInfoVector.push_back(kUsageEntryInfoStorageTypeUnknown);
kOverFullUsageEntryInfoVector.push_back(
kUsageEntryInfoStorageTypeUnknown);
break;
}
}
@@ -436,8 +461,8 @@ class MockCryptoSession : public TestCryptoSession {
}
private:
size_t maximum_usage_table_entries_ = 0;
bool maximum_usage_table_entries_set_ = false;
size_t maximum_usage_table_entries_ = kDefaultTableCapacity;
bool maximum_usage_table_entries_set_ = true;
};
// Partial mock of the UsageTableHeader. This is to test when dependency
@@ -447,32 +472,25 @@ class MockUsageTableHeader : public UsageTableHeader {
MockUsageTableHeader() : UsageTableHeader() {}
MOCK_METHOD4(InvalidateEntry, CdmResponseType(uint32_t, bool, DeviceFiles*,
metrics::CryptoMetrics*));
MOCK_METHOD6(AddEntry,
CdmResponseType(CryptoSession*, bool, const CdmKeySetId&,
const std::string&, const CdmKeyResponse&,
uint32_t*));
CdmResponseType SuperAddEntry(CryptoSession* crypto_session,
bool persistent_license,
const CdmKeySetId& key_set_id,
const std::string& usage_info_filename,
const CdmKeyResponse& license_message,
uint32_t* usage_entry_number) {
return UsageTableHeader::AddEntry(crypto_session, persistent_license,
key_set_id, usage_info_filename,
license_message, usage_entry_number);
}
};
} // namespace
// gmock methods
using ::testing::_;
using ::testing::AllOf;
using ::testing::AtMost;
using ::testing::ContainerEq;
using ::testing::Contains;
using ::testing::DoAll;
using ::testing::ElementsAre;
using ::testing::ElementsAreArray;
using ::testing::Ge;
using ::testing::Invoke;
using ::testing::InvokeWithoutArgs;
using ::testing::Lt;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
using ::testing::SizeIs;
using ::testing::StrEq;
using ::testing::UnorderedElementsAre;
using ::testing::UnorderedElementsAreArray;
class UsageTableHeaderTest : public WvCdmTestBase {
public:
static void SetUpTestCase() {
@@ -523,6 +541,7 @@ class UsageTableHeaderTest : public WvCdmTestBase {
// Create new mock objects if using MockUsageTableHeader
device_files_ = new MockDeviceFiles();
crypto_session_ = new MockCryptoSession(&crypto_metrics_);
MockUsageTableHeader* mock_usage_table_header = new MockUsageTableHeader();
// mock_usage_table_header_ object takes ownership of these objects
@@ -652,16 +671,16 @@ TEST_P(UsageTableHeaderInitializationTest, UsageTableHeaderExists) {
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
}
TEST_P(UsageTableHeaderInitializationTest, 200UsageEntries) {
std::vector<CdmUsageEntryInfo> usage_entries_200 = k201UsageEntryInfoVector;
usage_entries_200.resize(200);
TEST_P(UsageTableHeaderInitializationTest, UsageEntriesAtCapacity) {
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_200),
SetArgPointee<2>(false), Return(true)));
SetArgPointee<1>(usage_entries), SetArgPointee<2>(false),
Return(true)));
EXPECT_CALL(*crypto_session_,
LoadUsageTableHeader(security_level, kUsageTableHeader))
.WillOnce(Return(NO_ERROR));
@@ -670,11 +689,76 @@ TEST_P(UsageTableHeaderInitializationTest, 200UsageEntries) {
}
TEST_P(UsageTableHeaderInitializationTest,
201UsageEntries_AddEntryFails_UsageTableHeaderRecreated) {
UsageEntries_NoCapacity_UnderMinimum) {
crypto_session_->SetMaximumUsageTableEntries(0); // Unlimited.
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
constexpr size_t kHalfMinCapacity = kDefaultTableCapacity / 2;
usage_entries.resize(kHalfMinCapacity);
const SecurityLevel security_level =
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
EXPECT_CALL(*device_files_,
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
SetArgPointee<1>(k201UsageEntryInfoVector),
SetArgPointee<1>(usage_entries), SetArgPointee<2>(false),
Return(true)));
EXPECT_CALL(*crypto_session_,
LoadUsageTableHeader(security_level, kUsageTableHeader))
.WillOnce(Return(NO_ERROR));
// No expectations of creating or deleting entries if the number of entries
// is less than minimally required capacity.
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
}
TEST_P(UsageTableHeaderInitializationTest, UsageEntries_NoCapacity) {
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));
// Expect an attempt to create a new entry.
EXPECT_CALL(*crypto_session_, Open(security_level))
.WillOnce(Return(NO_ERROR));
const uint32_t expect_usage_entry_number = kDefaultTableCapacity;
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(kAnotherUsageTableHeader,
SizeIs(kDefaultTableCapacity + 1)))
.WillOnce(Return(true));
// Delete the entry after.
EXPECT_CALL(
*crypto_session_,
ShrinkUsageTableHeader(security_level, kDefaultTableCapacity, NotNull()))
.WillOnce(DoAll(SetArgPointee<2>(kYetAnotherUsageTableHeader),
Return(NO_ERROR)));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(kYetAnotherUsageTableHeader,
SizeIs(kDefaultTableCapacity)))
.WillOnce(Return(true));
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
}
TEST_P(UsageTableHeaderInitializationTest,
UsageEntriesOverCapacity_AddEntryFails_UsageTableHeaderRecreated) {
EXPECT_CALL(*device_files_,
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
SetArgPointee<1>(kOverFullUsageEntryInfoVector),
SetArgPointee<2>(false), Return(true)));
const SecurityLevel security_level =
@@ -696,7 +780,8 @@ TEST_P(UsageTableHeaderInitializationTest,
.WillOnce(Return(true));
// Expectations for AddEntry
const uint32_t expect_usage_entry_number = k201UsageEntryInfoVector.size();
const uint32_t expect_usage_entry_number =
kOverFullUsageEntryInfoVector.size();
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(expect_usage_entry_number),
Return(CREATE_USAGE_ENTRY_UNKNOWN_ERROR)));
@@ -705,9 +790,46 @@ TEST_P(UsageTableHeaderInitializationTest,
}
TEST_P(UsageTableHeaderInitializationTest,
201UsageEntries_AddInvalidateEntrySucceeds) {
std::vector<CdmUsageEntryInfo> usage_entries_202 = k201UsageEntryInfoVector;
usage_entries_202.push_back(kDummyUsageEntryInfo);
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))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(Return(CREATE_USAGE_ENTRY_UNKNOWN_ERROR));
// Expect clean up.
EXPECT_CALL(*device_files_, DeleteAllLicenses()).WillOnce(Return(true));
EXPECT_CALL(*device_files_, DeleteAllUsageInfo()).WillOnce(Return(true));
EXPECT_CALL(*device_files_, DeleteUsageTableInfo()).WillOnce(Return(true));
// Expect recreation of usage table.
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,
UsageEntriesOverCapacity_AddInvalidateEntrySucceeds) {
// Capacity +2.
std::vector<CdmUsageEntryInfo> usage_entries = kOverFullUsageEntryInfoVector;
usage_entries.push_back(kDummyUsageEntryInfo);
const SecurityLevel security_level =
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
@@ -715,33 +837,36 @@ TEST_P(UsageTableHeaderInitializationTest,
EXPECT_CALL(*device_files_,
RetrieveUsageTableInfo(NotNull(), NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
SetArgPointee<1>(k201UsageEntryInfoVector),
SetArgPointee<1>(kOverFullUsageEntryInfoVector),
SetArgPointee<2>(false), Return(true)));
EXPECT_CALL(*crypto_session_,
LoadUsageTableHeader(security_level, kUsageTableHeader))
.WillOnce(Return(NO_ERROR));
// Expectations for AddEntry
const uint32_t expect_usage_entry_number = k201UsageEntryInfoVector.size();
const uint32_t expect_usage_entry_number =
kOverFullUsageEntryInfoVector.size();
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(expect_usage_entry_number),
Return(NO_ERROR)));
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kUsageTableHeader,
usage_entries_202))
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(kAnotherUsageTableHeader, usage_entries))
.WillOnce(Return(true));
// Expectations for InvalidateEntry, assumes no entry other entry is invalid.
EXPECT_CALL(*crypto_session_, Open(security_level))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*crypto_session_,
ShrinkUsageTableHeader(security_level,
usage_entries_202.size() - 1, NotNull()))
.WillOnce(
DoAll(SetArgPointee<2>(kAnotherUsageTableHeader), Return(NO_ERROR)));
ShrinkUsageTableHeader(security_level, usage_entries.size() - 1,
NotNull()))
.WillOnce(DoAll(SetArgPointee<2>(kYetAnotherUsageTableHeader),
Return(NO_ERROR)));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(
kAnotherUsageTableHeader,
SizeIs(k201UsageEntryInfoVector.size())))
StoreUsageTableInfo(kYetAnotherUsageTableHeader,
SizeIs(kOverFullUsageEntryInfoVector.size())))
.WillOnce(Return(true));
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
@@ -800,10 +925,12 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveOfflineUsageEntry) {
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(
kUsageTableHeader,
kAnotherUsageTableHeader,
UnorderedElementsAreArray(expect_usage_entry_info_vector)))
.WillOnce(Return(true));
@@ -831,10 +958,12 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveSecureStopUsageEntry) {
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(
kUsageTableHeader,
kAnotherUsageTableHeader,
UnorderedElementsAreArray(expect_usage_entry_info_vector)))
.WillOnce(Return(true));
@@ -859,11 +988,13 @@ TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) {
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(
*device_files_,
StoreUsageTableInfo(
kUsageTableHeader,
kAnotherUsageTableHeader,
UnorderedElementsAre(
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1,
kUsageEntryInfoStorageTypeUnknown,
@@ -905,17 +1036,19 @@ TEST_F(UsageTableHeaderTest,
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES_3))
.WillOnce(DoAll(SetArgPointee<0>(expected_usage_entry_number),
Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(expected_usage_entry_number),
Return(NO_ERROR)));
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kUsageTableHeader, _))
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader, _))
.WillOnce(DoAll(SaveArg<1>(&final_usage_entries), Return(true)));
// Now invoke the method under test
uint32_t usage_entry_number;
EXPECT_EQ(NO_ERROR,
mock_usage_table_header->AddEntry(
mock_usage_table_header->SuperAddEntry(
crypto_session_,
kUsageEntryInfoOfflineLicense6.storage_type == kStorageLicense,
kUsageEntryInfoOfflineLicense6.key_set_id,
@@ -959,7 +1092,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailsEveryTime) {
// Now invoke the method under test
uint32_t usage_entry_number;
EXPECT_EQ(INSUFFICIENT_CRYPTO_RESOURCES_3,
mock_usage_table_header->AddEntry(
mock_usage_table_header->SuperAddEntry(
crypto_session_, true /* persistent */,
kUsageEntryInfoOfflineLicense6.key_set_id,
kUsageEntryInfoOfflineLicense6.usage_info_file_name,
@@ -3390,8 +3523,10 @@ TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateLicenseEntry) {
MockClock mock_clock;
usage_table_header_->SetClock(&mock_clock);
EXPECT_CALL(mock_clock, GetCurrentTime()).WillOnce(Return(kLruBaseTime));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(kUpgradedUsageTableHeader, _));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader, _));
// The Call.
uint32_t usage_entry_number = 0;
@@ -3436,8 +3571,10 @@ TEST_F(UsageTableHeaderTest, LruLastUsedTime_CreateUsageInfoEntry) {
MockClock mock_clock;
usage_table_header_->SetClock(&mock_clock);
EXPECT_CALL(mock_clock, GetCurrentTime()).WillOnce(Return(kLruBaseTime));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(kUpgradedUsageTableHeader, _));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kAnotherUsageTableHeader, _));
// The Call.
uint32_t usage_entry_number = 0;
@@ -3970,15 +4107,7 @@ TEST_F(UsageTableHeaderTest, PotentialTableCapacity_Unavailable) {
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
EXPECT_EQ(usage_table_header_->potential_table_capacity(),
kMinimumUsageTableEntriesSupported);
}
TEST_F(UsageTableHeaderTest, PotentialTableCapacity_Zero) {
// This will issue a warning about the reported capacity is unexpected,
// and will default to the version's required minimum.
crypto_session_->SetMaximumUsageTableEntries(0u);
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
EXPECT_EQ(usage_table_header_->potential_table_capacity(),
kMinimumUsageTableEntriesSupported);
EXPECT_FALSE(usage_table_header_->HasUnlimitedTableCapacity());
}
TEST_F(UsageTableHeaderTest, PotentialTableCapacity_TooSmall) {
@@ -3989,6 +4118,18 @@ TEST_F(UsageTableHeaderTest, PotentialTableCapacity_TooSmall) {
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
EXPECT_EQ(usage_table_header_->potential_table_capacity(),
kMinimumUsageTableEntriesSupported);
EXPECT_FALSE(usage_table_header_->HasUnlimitedTableCapacity());
}
TEST_F(UsageTableHeaderTest, PotentialTableCapacity_Unlimited) {
MockUsageTableHeader* mock_usage_table_header = SetUpMock();
// Zero indicates that the table size is unlimited.
crypto_session_->SetMaximumUsageTableEntries(0u);
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
constexpr size_t kZero = 0u;
EXPECT_EQ(mock_usage_table_header->potential_table_capacity(), kZero);
EXPECT_TRUE(mock_usage_table_header->HasUnlimitedTableCapacity());
}
TEST_F(UsageTableHeaderTest, PotentialTableCapacity_Available) {
@@ -3996,6 +4137,7 @@ TEST_F(UsageTableHeaderTest, PotentialTableCapacity_Available) {
crypto_session_->SetMaximumUsageTableEntries(kTableCapacity);
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
EXPECT_EQ(usage_table_header_->potential_table_capacity(), kTableCapacity);
EXPECT_FALSE(usage_table_header_->HasUnlimitedTableCapacity());
}
} // namespace wvcdm