Merge "New usage entries are moved lower after creation." into sc-dev

This commit is contained in:
Alex Dale
2021-05-26 22:31:03 +00:00
committed by Android (Google) Code Review
3 changed files with 504 additions and 141 deletions

View File

@@ -202,8 +202,16 @@ const DeviceFiles::CdmUsageData kCdmUsageData3 = {
const std::vector<DeviceFiles::CdmUsageData> kEmptyUsageInfoUsageDataList;
const std::vector<CdmUsageEntryInfo> kEmptyUsageEntryInfoVector;
std::vector<CdmUsageEntryInfo> kUsageEntryInfoVector;
std::vector<CdmUsageEntryInfo> k10UsageEntryInfoVector;
const std::vector<CdmUsageEntryInfo> kUsageEntryInfoVector = {
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1,
kUsageEntryInfoStorageTypeUnknown};
const std::vector<CdmUsageEntryInfo> k10UsageEntryInfoVector = {
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1,
kUsageEntryInfoOfflineLicense2, kUsageEntryInfoSecureStop2,
kUsageEntryInfoOfflineLicense3, kUsageEntryInfoSecureStop3,
kUsageEntryInfoOfflineLicense4, kUsageEntryInfoSecureStop4,
kUsageEntryInfoOfflineLicense5, kUsageEntryInfoSecureStop5,
};
std::vector<CdmUsageEntryInfo> kOverFullUsageEntryInfoVector;
const CdmOfflineLicenseState kActiveLicenseState = kLicenseStateActive;
@@ -289,23 +297,6 @@ std::vector<CdmUsageEntryInfo> kUpgradedUsageEntryInfoList;
namespace {
void InitVectorConstants() {
kUsageEntryInfoVector.clear();
kUsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense1);
kUsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop1);
kUsageEntryInfoVector.push_back(kUsageEntryInfoStorageTypeUnknown);
k10UsageEntryInfoVector.clear();
k10UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense1);
k10UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop1);
k10UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense2);
k10UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop2);
k10UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense3);
k10UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop3);
k10UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense4);
k10UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop4);
k10UsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense5);
k10UsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop5);
kOverFullUsageEntryInfoVector.clear();
for (size_t i = 0; i < (kDefaultTableCapacity + 1); ++i) {
switch (i % 4) {
@@ -479,8 +470,9 @@ class MockCryptoSession : public TestCryptoSession {
class MockUsageTableHeader : public UsageTableHeader {
public:
MockUsageTableHeader() : UsageTableHeader() {}
MOCK_METHOD4(InvalidateEntry, CdmResponseType(uint32_t, bool, DeviceFiles*,
metrics::CryptoMetrics*));
MOCK_METHOD4(InvalidateEntryInternal,
CdmResponseType(uint32_t, bool, DeviceFiles*,
metrics::CryptoMetrics*));
MOCK_METHOD6(AddEntry, CdmResponseType(CryptoSession*, bool,
const CdmKeySetId&, const std::string&,
const CdmKeyResponse&, uint32_t*));
@@ -1041,25 +1033,53 @@ TEST_F(UsageTableHeaderTest, AddEntry_UsageEntryTooSmall) {
kEmptyString /* license */, &usage_entry_number));
}
// Initial Test state:
// 1. Table has a few entries, one of which is unoccupied.
// 2. An entry-less session requires a new entry.
//
// Attempting to add an entry will result in:
// a. A successful call to OEMCrypto to create an entry
// at the end of the current table
// b. Moving the new entry to the unoccupied entry index
// c. Shrink table to remove the now empty entry slot created in (a)
// d. Storing the new updated usage table
//
// Storage type Usage entries
// at start at end
// ============= ======== ======
// Offline License 1 0 0
// Secure Stop 1 1 1
// Storage Type Unknown 2 Replaced
// Offline License 2 DNE 2
//
// DNE = Does Not Exist
//
// # of usage entries 3 3
TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveOfflineUsageEntry) {
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
const uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size();
const uint32_t initial_usage_entry_number = kUsageEntryInfoVector.size();
const uint32_t final_usage_entry_number = kUsageEntryInfoVector.size() - 1;
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
kUsageEntryInfoVector;
expect_usage_entry_info_vector.resize(expect_usage_entry_number + 1);
expect_usage_entry_info_vector[expect_usage_entry_number] =
expect_usage_entry_info_vector[final_usage_entry_number] =
kUsageEntryInfoOfflineLicense2;
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(initial_usage_entry_number),
Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, MoveUsageEntry(final_usage_entry_number))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(
*crypto_session_,
ShrinkUsageTableHeader(kLevelDefault,
expect_usage_entry_info_vector.size(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
DoAll(SetArgPointee<2>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
.WillOnce(DoAll(SetArgPointee<0>(kYetAnotherUsageTableHeader),
Return(NO_ERROR)));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(
kAnotherUsageTableHeader,
UnorderedElementsAreArray(expect_usage_entry_info_vector)))
StoreUsageTableInfo(kYetAnotherUsageTableHeader,
expect_usage_entry_info_vector))
.WillOnce(Return(true));
uint32_t usage_entry_number = 0;
@@ -1070,29 +1090,182 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveOfflineUsageEntry) {
kUsageEntryInfoOfflineLicense2.key_set_id,
kUsageEntryInfoOfflineLicense2.usage_info_file_name,
kEmptyString /* license */, &usage_entry_number));
EXPECT_EQ(expect_usage_entry_number, usage_entry_number);
EXPECT_EQ(final_usage_entry_number, usage_entry_number);
}
// Initial Test state:
// 1. Table has a few entries, one of which is unoccupied.
// 2. An entry-less session requires a new entry.
//
// Attempting to add an entry will result in:
// a. A successful call to OEMCrypto to create an entry
// at the end of the current table
// b. Moving the new entry to the unoccupied entry index
// c. Shrink table to remove the now empty entry slot created in (a)
// d. Storing the new updated usage table
//
// Storage type Usage entries
// at start at end
// ============= ======== ======
// Offline License 1 0 0
// Secure Stop 1 1 1
// Storage Type Unknown 2 Replaced
// Secure Stop 2 DNE 2
//
// DNE = Does Not Exist
//
// # of usage entries 3 3
TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveSecureStopUsageEntry) {
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
const uint32_t expect_usage_entry_number = kUsageEntryInfoVector.size();
const uint32_t initial_usage_entry_number = kUsageEntryInfoVector.size();
const uint32_t final_usage_entry_number = kUsageEntryInfoVector.size() - 1;
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
kUsageEntryInfoVector;
expect_usage_entry_info_vector.resize(expect_usage_entry_number + 1);
expect_usage_entry_info_vector[expect_usage_entry_number] =
expect_usage_entry_info_vector[final_usage_entry_number] =
kUsageEntryInfoSecureStop2;
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(initial_usage_entry_number),
Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, MoveUsageEntry(final_usage_entry_number))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(
*crypto_session_,
ShrinkUsageTableHeader(kLevelDefault,
expect_usage_entry_info_vector.size(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
DoAll(SetArgPointee<2>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kYetAnotherUsageTableHeader),
Return(NO_ERROR)));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(kYetAnotherUsageTableHeader,
expect_usage_entry_info_vector))
.WillOnce(Return(true));
uint32_t usage_entry_number = 0;
EXPECT_EQ(NO_ERROR,
usage_table_header_->AddEntry(
crypto_session_,
kUsageEntryInfoSecureStop2.storage_type == kStorageLicense,
kUsageEntryInfoSecureStop2.key_set_id,
kUsageEntryInfoSecureStop2.usage_info_file_name,
kEmptyString /* license */, &usage_entry_number));
EXPECT_EQ(final_usage_entry_number, usage_entry_number);
}
// Initial Test state:
// 1. Table has a few entries, one of which is unoccupied.
// 2. An entry-less session requires a new entry.
//
// Attempting to add an entry will result in:
// a. An odd but successful call to OEMCrypto to create an entry
// beyond the end of the current table
// b. Empty entries will fill the gap between the original table
// and the new entry
// c. Move the new entry to the *lowest* unoccupied entry index
// d. Shrink table to remove the now empty entry slot created in (a)
// and the filler gap entries created in (b)
// e. Storing the new updated usage table
//
// Storage type Usage entries
// at start at end
// ============= ======== ======
// Offline License 1 0 0
// Secure Stop 1 1 1
// Storage Type Unknown 2 Replaced
// Storage Type Unknown DNE Removed (never stored)
// Storage Type Unknown DNE Removed (never stored)
// Storage Type Unknown DNE Removed (never stored)
// Secure Stop 2 DNE 2
//
// DNE = Does Not Exist
//
// # of usage entries 3 3
TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) {
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
const uint32_t next_usage_entry_number = kUsageEntryInfoVector.size();
const size_t skip_usage_entries = 3;
const uint32_t initial_usage_entry_number =
next_usage_entry_number + skip_usage_entries;
const uint32_t final_usage_entry_number = kUsageEntryInfoVector.size() - 1;
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
kUsageEntryInfoVector;
expect_usage_entry_info_vector[final_usage_entry_number] =
kUsageEntryInfoSecureStop2;
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(initial_usage_entry_number),
Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, MoveUsageEntry(final_usage_entry_number))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(
*crypto_session_,
ShrinkUsageTableHeader(kLevelDefault,
expect_usage_entry_info_vector.size(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<2>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kYetAnotherUsageTableHeader),
Return(NO_ERROR)));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(kYetAnotherUsageTableHeader,
expect_usage_entry_info_vector))
.WillOnce(Return(true));
uint32_t usage_entry_number = 0;
EXPECT_EQ(NO_ERROR,
usage_table_header_->AddEntry(
crypto_session_,
kUsageEntryInfoSecureStop2.storage_type == kStorageLicense,
kUsageEntryInfoSecureStop2.key_set_id,
kUsageEntryInfoSecureStop2.usage_info_file_name,
kEmptyString /* license */, &usage_entry_number));
EXPECT_EQ(final_usage_entry_number, usage_entry_number);
}
// Initial Test state:
// 1. Table has a few entries, one of which is unoccupied.
// 2. An entry-less session requires a new entry.
//
// Attempting to add an entry will result in:
// a. A successful call to OEMCrypto to create an entry
// at the end of the current table
// b. Cannot move the new entry to the unoccupied entry index
// due to entry being in use (according to OEMCrypto)
// c. Storing the new updated usage table
//
// Storage type Usage entries
// at start at end
// ============= ======== ======
// Offline License 1 0 0
// Secure Stop 1 1 1
// Storage Type Unknown 2 2
// Secure Stop 2 DNE 3
//
// DNE = Does Not Exist
//
// # of usage entries 3 4
TEST_F(UsageTableHeaderTest, AddEntry_CannotMoveNewEntry) {
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
const uint32_t final_usage_entry_number = kUsageEntryInfoVector.size();
const uint32_t attempted_usage_entry_number =
kUsageEntryInfoVector.size() - 1;
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
kUsageEntryInfoVector;
expect_usage_entry_info_vector.push_back(kUsageEntryInfoSecureStop2);
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(final_usage_entry_number), Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, MoveUsageEntry(attempted_usage_entry_number))
.WillOnce(Return(MOVE_USAGE_ENTRY_DESTINATION_IN_USE));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(
kAnotherUsageTableHeader,
UnorderedElementsAreArray(expect_usage_entry_info_vector)))
StoreUsageTableInfo(kAnotherUsageTableHeader,
expect_usage_entry_info_vector))
.WillOnce(Return(true));
uint32_t usage_entry_number = 0;
@@ -1103,32 +1276,58 @@ TEST_F(UsageTableHeaderTest, AddEntry_NextConsecutiveSecureStopUsageEntry) {
kUsageEntryInfoSecureStop2.key_set_id,
kUsageEntryInfoSecureStop2.usage_info_file_name,
kEmptyString /* license */, &usage_entry_number));
EXPECT_EQ(expect_usage_entry_number, usage_entry_number);
EXPECT_EQ(final_usage_entry_number, usage_entry_number);
}
TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) {
// Initial Test state:
// 1. Table has a few entries, one of which is unoccupied.
// 2. An entry-less session requires a new entry.
//
// Attempting to add an entry will result in:
// a. A successful call to OEMCrypto to create an entry
// at the end of the current table
// b. Moving the new entry to the unoccupied entry index
// c. Fail to shrink table due to occupied entry
// d. Storing the new updated usage table
//
// Storage type Usage entries
// at start at end
// ============= ======== ======
// Offline License 1 0 0
// Secure Stop 1 1 1
// Storage Type Unknown 2 Replaced
// Secure Stop 2 DNE 2
// Storage Type Unknown DNE 3 (created when new entry moved)
//
// DNE = Does Not Exist
//
// # of usage entries 3 4
TEST_F(UsageTableHeaderTest, AddEntry_CannotShinkAfterMove) {
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
const uint32_t next_usage_entry_number = kUsageEntryInfoVector.size();
size_t skip_usage_entries = 3;
uint32_t expect_usage_entry_number =
next_usage_entry_number + skip_usage_entries;
const uint32_t initial_usage_entry_number = kUsageEntryInfoVector.size();
const uint32_t final_usage_entry_number = kUsageEntryInfoVector.size() - 1;
std::vector<CdmUsageEntryInfo> expect_usage_entry_info_vector =
kUsageEntryInfoVector;
expect_usage_entry_info_vector[final_usage_entry_number] =
kUsageEntryInfoSecureStop2;
expect_usage_entry_info_vector.push_back(kUsageEntryInfoStorageTypeUnknown);
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
.WillOnce(DoAll(SetArgPointee<0>(initial_usage_entry_number),
Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, MoveUsageEntry(final_usage_entry_number))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(
*crypto_session_,
ShrinkUsageTableHeader(
kLevelDefault, expect_usage_entry_info_vector.size() - 1, NotNull()))
.WillOnce(Return(SHRINK_USAGE_TABLE_HEADER_ENTRY_IN_USE));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(
*device_files_,
StoreUsageTableInfo(
kAnotherUsageTableHeader,
UnorderedElementsAre(
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1,
kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoSecureStop2)))
EXPECT_CALL(*device_files_,
StoreUsageTableInfo(kAnotherUsageTableHeader,
expect_usage_entry_info_vector))
.WillOnce(Return(true));
uint32_t usage_entry_number = 0;
@@ -1139,9 +1338,21 @@ TEST_F(UsageTableHeaderTest, AddEntry_SkipUsageEntries) {
kUsageEntryInfoSecureStop2.key_set_id,
kUsageEntryInfoSecureStop2.usage_info_file_name,
kEmptyString /* license */, &usage_entry_number));
EXPECT_EQ(expect_usage_entry_number, usage_entry_number);
EXPECT_EQ(final_usage_entry_number, usage_entry_number);
}
// Initial Test state:
// 1. Table is full with entries
// 2. An entry-less session requires a new entry.
//
// Attempting to add an entry will result in:
// a. First call to OEMCrypto to create an entry fails due to
// table being full
// b. One of the existing entries will be removed, shrinking table
// by one
// c. Table will be stored
// d. Second call to OEMCrypto to create an entry will succeed
// e. Storing the new updated usage table
TEST_F(UsageTableHeaderTest,
AddEntry_CreateUsageEntryFailsOnce_SucceedsSecondTime) {
// Initialize and setup
@@ -1150,32 +1361,33 @@ TEST_F(UsageTableHeaderTest,
std::vector<CdmUsageEntryInfo> usage_entry_info_vector_at_start =
k10UsageEntryInfoVector;
uint32_t usage_entry_number_first_to_be_deleted; // randomly chosen
std::vector<CdmUsageEntryInfo> final_usage_entries;
uint32_t invalidated_entry = 0; // Randomly chosen by UsageTableHeader
const uint32_t expected_usage_entry_number =
k10UsageEntryInfoVector.size() - 1;
// Setup expectations
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
// First call fails
.WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES))
// Second call succeeds
.WillOnce(DoAll(SetArgPointee<0>(expected_usage_entry_number),
Return(NO_ERROR)));
// Covers all other expectations.
EXPECT_CALL(*mock_usage_table_header,
InvalidateEntry(_, true, device_files_, NotNull()))
.WillOnce(DoAll(SaveArg<0>(&usage_entry_number_first_to_be_deleted),
InvalidateEntryInternal(_, true, device_files_, NotNull()))
.WillOnce(DoAll(SaveArg<0>(&invalidated_entry),
Invoke(this, &UsageTableHeaderTest::InvalidateEntry),
Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES))
.WillOnce(DoAll(SetArgPointee<0>(expected_usage_entry_number),
Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));
std::vector<CdmUsageEntryInfo> final_usage_entries;
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;
uint32_t usage_entry_number = 0;
EXPECT_EQ(NO_ERROR,
mock_usage_table_header->SuperAddEntry(
crypto_session_,
@@ -1187,17 +1399,15 @@ TEST_F(UsageTableHeaderTest,
// Verify added/deleted usage entry number and entries
EXPECT_EQ(expected_usage_entry_number, usage_entry_number);
EXPECT_LE(0u, usage_entry_number_first_to_be_deleted);
EXPECT_LE(usage_entry_number_first_to_be_deleted,
usage_entry_info_vector_at_start.size() - 1);
EXPECT_LE(0u, invalidated_entry);
EXPECT_LE(invalidated_entry, k10UsageEntryInfoVector.size() - 1);
std::vector<CdmUsageEntryInfo> expected_usage_entries =
usage_entry_info_vector_at_start;
expected_usage_entries[usage_entry_number_first_to_be_deleted] =
expected_usage_entries[expected_usage_entries.size() - 1];
expected_usage_entries.resize(expected_usage_entries.size() - 1);
expected_usage_entries.push_back(kUsageEntryInfoOfflineLicense6);
k10UsageEntryInfoVector;
expected_usage_entries[invalidated_entry] = expected_usage_entries.back();
expected_usage_entries.pop_back();
expected_usage_entries.push_back(kUsageEntryInfoOfflineLicense6);
EXPECT_EQ(expected_usage_entries, final_usage_entries);
}
@@ -1210,7 +1420,7 @@ TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailsEveryTime) {
// Setup expectations
EXPECT_CALL(*mock_usage_table_header,
InvalidateEntry(_, true, device_files_, NotNull()))
InvalidateEntryInternal(_, true, device_files_, NotNull()))
.WillOnce(DoAll(Invoke(this, &UsageTableHeaderTest::InvalidateEntry),
Return(NO_ERROR)));