Update AddEntry() for usage table changes.
[ Merge of http://go/wvgerrit/96071 ] Changes to how the usage table method InvalidateEntry() behaves required additional changes to CDM code that uses this method. This involved some refactoring to AddEntry(), moving the LRU related code to its own function. A few unittests had to be changed / removed as the moving multiple entries changes expectations of several existing tests. Several additional helper methods have been created to improve readability. These include getters for information about the usage table, a method for releasing stale entries, and a method of recording LRU metrics. Bug: 150890014 Bug: 150887808 Bug: 154269671 Test: Linux unit tests and Android unit tests Change-Id: I11a98f9a2dea9b2ae57b37d7d4483a37be721763
This commit is contained in:
@@ -350,28 +350,6 @@ void ToVector(std::vector<CdmUsageEntryInfo>& vec,
|
||||
}
|
||||
}
|
||||
|
||||
// Used to quickly populate a vector of CdmUsageEntryInfo structs with LRU
|
||||
// information. This is intended to allow tests which are not concerned with
|
||||
// the LRU replacement policy of the UsageTableHeader, but are affected by its
|
||||
// presents.
|
||||
void GenericLruUpgrade(std::vector<CdmUsageEntryInfo>* usage_entry_info_list,
|
||||
int64_t last_use_time = kLruBaseTime,
|
||||
int64_t offline_license_expiry_time =
|
||||
kLruBaseTime + kDefaultExpireDuration) {
|
||||
if (usage_entry_info_list == nullptr) {
|
||||
return;
|
||||
}
|
||||
for (auto& usage_entry_info : *usage_entry_info_list) {
|
||||
usage_entry_info.last_use_time = last_use_time;
|
||||
if (usage_entry_info.storage_type == kStorageLicense) {
|
||||
usage_entry_info.offline_license_expiry_time =
|
||||
offline_license_expiry_time;
|
||||
} else {
|
||||
usage_entry_info.offline_license_expiry_time = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
|
||||
class MockDeviceFiles : public DeviceFiles {
|
||||
@@ -484,6 +462,7 @@ using ::testing::ElementsAre;
|
||||
using ::testing::ElementsAreArray;
|
||||
using ::testing::Ge;
|
||||
using ::testing::Invoke;
|
||||
using ::testing::InvokeWithoutArgs;
|
||||
using ::testing::Lt;
|
||||
using ::testing::NotNull;
|
||||
using ::testing::Return;
|
||||
@@ -751,7 +730,7 @@ TEST_P(UsageTableHeaderInitializationTest,
|
||||
usage_entries_202))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
// Expectations for InvalidateEntry
|
||||
// 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_,
|
||||
@@ -914,7 +893,8 @@ TEST_F(UsageTableHeaderTest,
|
||||
uint32_t usage_entry_number_first_to_be_deleted; // randomly chosen
|
||||
std::vector<CdmUsageEntryInfo> final_usage_entries;
|
||||
|
||||
uint32_t expected_usage_entry_number = k10UsageEntryInfoVector.size() - 1;
|
||||
const uint32_t expected_usage_entry_number =
|
||||
k10UsageEntryInfoVector.size() - 1;
|
||||
|
||||
// Setup expectations
|
||||
EXPECT_CALL(*mock_usage_table_header,
|
||||
@@ -959,123 +939,50 @@ TEST_F(UsageTableHeaderTest,
|
||||
EXPECT_EQ(expected_usage_entries, final_usage_entries);
|
||||
}
|
||||
|
||||
TEST_F(UsageTableHeaderTest,
|
||||
AddEntry_CreateUsageEntryFailsTwice_SucceedsThirdTime) {
|
||||
// Initialize and setup
|
||||
MockUsageTableHeader* mock_usage_table_header = SetUpMock();
|
||||
std::vector<CdmUsageEntryInfo> usage_entry_info_vector_at_start =
|
||||
k10UsageEntryInfoVector;
|
||||
GenericLruUpgrade(&usage_entry_info_vector_at_start);
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector_at_start);
|
||||
|
||||
uint32_t usage_entry_number_first_to_be_deleted; // randomly chosen
|
||||
uint32_t usage_entry_number_second_to_be_deleted; // randomly chosen
|
||||
std::vector<CdmUsageEntryInfo> final_usage_entries;
|
||||
|
||||
uint32_t expected_usage_entry_number = k10UsageEntryInfoVector.size() - 2;
|
||||
|
||||
// Setup expectations
|
||||
EXPECT_CALL(*mock_usage_table_header,
|
||||
InvalidateEntry(_, true, device_files_, NotNull()))
|
||||
.WillOnce(DoAll(SaveArg<0>(&usage_entry_number_first_to_be_deleted),
|
||||
Invoke(this, &UsageTableHeaderTest::InvalidateEntry),
|
||||
Return(NO_ERROR)))
|
||||
.WillOnce(DoAll(SaveArg<0>(&usage_entry_number_second_to_be_deleted),
|
||||
Invoke(this, &UsageTableHeaderTest::InvalidateEntry),
|
||||
Return(NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES_3))
|
||||
.WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES_3))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(expected_usage_entry_number),
|
||||
Return(NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kUsageTableHeader, _))
|
||||
.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(
|
||||
crypto_session_,
|
||||
kUsageEntryInfoOfflineLicense6.storage_type == kStorageLicense,
|
||||
kUsageEntryInfoOfflineLicense6.key_set_id,
|
||||
kUsageEntryInfoOfflineLicense6.usage_info_file_name,
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
|
||||
// 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, usage_entry_number_second_to_be_deleted);
|
||||
EXPECT_LE(usage_entry_number_second_to_be_deleted,
|
||||
usage_entry_info_vector_at_start.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[usage_entry_number_second_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);
|
||||
|
||||
EXPECT_EQ(expected_usage_entries, final_usage_entries);
|
||||
}
|
||||
|
||||
TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailsThrice) {
|
||||
// The usage table should only delete/invalidate a single entry.
|
||||
// After which, it should fail.
|
||||
TEST_F(UsageTableHeaderTest, AddEntry_CreateUsageEntryFailsEveryTime) {
|
||||
// Initialize and setup
|
||||
MockUsageTableHeader* mock_usage_table_header = SetUpMock();
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, k10UsageEntryInfoVector);
|
||||
std::vector<CdmUsageEntryInfo> usage_entry_info_vector_at_start =
|
||||
k10UsageEntryInfoVector;
|
||||
|
||||
uint32_t usage_entry_number_first_to_be_deleted; // randomly chosen
|
||||
uint32_t usage_entry_number_second_to_be_deleted; // randomly chosen
|
||||
uint32_t usage_entry_number_third_to_be_deleted; // randomly chosen
|
||||
std::vector<CdmUsageEntryInfo> final_usage_entries;
|
||||
|
||||
// Setup expectations
|
||||
EXPECT_CALL(*mock_usage_table_header,
|
||||
InvalidateEntry(_, true, device_files_, NotNull()))
|
||||
.WillOnce(DoAll(SaveArg<0>(&usage_entry_number_first_to_be_deleted),
|
||||
Invoke(this, &UsageTableHeaderTest::InvalidateEntry),
|
||||
Return(NO_ERROR)))
|
||||
.WillOnce(DoAll(SaveArg<0>(&usage_entry_number_second_to_be_deleted),
|
||||
Invoke(this, &UsageTableHeaderTest::InvalidateEntry),
|
||||
Return(NO_ERROR)))
|
||||
.WillOnce(DoAll(SaveArg<0>(&usage_entry_number_third_to_be_deleted),
|
||||
Invoke(this, &UsageTableHeaderTest::InvalidateEntry),
|
||||
.WillOnce(DoAll(Invoke(this, &UsageTableHeaderTest::InvalidateEntry),
|
||||
Return(NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
|
||||
.Times(4)
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(INSUFFICIENT_CRYPTO_RESOURCES_3));
|
||||
|
||||
// Now invoke the method under test
|
||||
uint32_t usage_entry_number;
|
||||
EXPECT_EQ(INSUFFICIENT_CRYPTO_RESOURCES_3,
|
||||
mock_usage_table_header->AddEntry(
|
||||
crypto_session_,
|
||||
kUsageEntryInfoOfflineLicense6.storage_type == kStorageLicense,
|
||||
crypto_session_, true /* persistent */,
|
||||
kUsageEntryInfoOfflineLicense6.key_set_id,
|
||||
kUsageEntryInfoOfflineLicense6.usage_info_file_name,
|
||||
kEmptyString /* license */, &usage_entry_number));
|
||||
|
||||
// Verify deleted usage entry number and entries
|
||||
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, usage_entry_number_second_to_be_deleted);
|
||||
EXPECT_LE(usage_entry_number_second_to_be_deleted,
|
||||
usage_entry_info_vector_at_start.size() - 1);
|
||||
EXPECT_LE(0u, usage_entry_number_third_to_be_deleted);
|
||||
EXPECT_LE(usage_entry_number_third_to_be_deleted,
|
||||
usage_entry_info_vector_at_start.size() - 1);
|
||||
// Verify the number of entries deleted.
|
||||
constexpr uint32_t kExpectedEntriesDeleted = 1;
|
||||
|
||||
const std::vector<CdmUsageEntryInfo>& final_usage_entries =
|
||||
mock_usage_table_header->usage_entry_info();
|
||||
uint32_t invalid_entries = 0;
|
||||
for (const CdmUsageEntryInfo& usage_entry_info : final_usage_entries) {
|
||||
if (usage_entry_info.storage_type == kStorageTypeUnknown) {
|
||||
++invalid_entries;
|
||||
}
|
||||
}
|
||||
// Number of entries deleted is equal to the number of entries
|
||||
// marked as invalid plus the number of fewer entries in the table
|
||||
// at the end of the call.
|
||||
const uint32_t entries_deleted =
|
||||
invalid_entries +
|
||||
(k10UsageEntryInfoVector.size() - final_usage_entries.size());
|
||||
EXPECT_EQ(kExpectedEntriesDeleted, entries_deleted);
|
||||
}
|
||||
|
||||
TEST_F(UsageTableHeaderTest, LoadEntry_InvalidEntryNumber) {
|
||||
@@ -1139,106 +1046,6 @@ TEST_F(UsageTableHeaderTest, UpdateEntry) {
|
||||
usage_table_header_->UpdateEntry(0, crypto_session_, &usage_entry));
|
||||
}
|
||||
|
||||
TEST_F(UsageTableHeaderTest,
|
||||
LoadEntry_LoadUsageEntryFailsOnce_SucceedsSecondTime) {
|
||||
// Initialize and setup
|
||||
MockUsageTableHeader* mock_usage_table_header = SetUpMock();
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, k10UsageEntryInfoVector);
|
||||
|
||||
// We try to load a usage entry from the first 9 entries, since
|
||||
// InvalidateEntry can't delete an entry if the last one is in use.
|
||||
|
||||
uint32_t usage_entry_number_to_load =
|
||||
CdmRandom::RandomInRange(k10UsageEntryInfoVector.size() - 2);
|
||||
CdmUsageEntry usage_entry_to_load = kUsageEntry;
|
||||
|
||||
// Setup expectations
|
||||
EXPECT_CALL(*mock_usage_table_header,
|
||||
InvalidateEntry(_, true, device_files_, NotNull()))
|
||||
.Times(1)
|
||||
.WillRepeatedly(
|
||||
DoAll(Invoke(this, &UsageTableHeaderTest::InvalidateEntry),
|
||||
Return(NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
LoadUsageEntry(usage_entry_number_to_load, usage_entry_to_load))
|
||||
.WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES_3))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
|
||||
// Now invoke the method under test
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
mock_usage_table_header->LoadEntry(
|
||||
crypto_session_,
|
||||
usage_entry_to_load,
|
||||
usage_entry_number_to_load));
|
||||
}
|
||||
|
||||
TEST_F(UsageTableHeaderTest,
|
||||
LoadEntry_LoadUsageEntryFailsTwice_SucceedsThirdTime) {
|
||||
// Initialize and setup
|
||||
MockUsageTableHeader* mock_usage_table_header = SetUpMock();
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, k10UsageEntryInfoVector);
|
||||
|
||||
// We try to load a usage entry from the first 8 entries, since
|
||||
// InvalidateEntry can't delete an entry if the last one is in use.
|
||||
uint32_t usage_entry_number_to_load =
|
||||
CdmRandom::RandomInRange(k10UsageEntryInfoVector.size() - 3);
|
||||
CdmUsageEntry usage_entry_to_load = kUsageEntry;
|
||||
|
||||
// Setup expectations
|
||||
EXPECT_CALL(*mock_usage_table_header,
|
||||
InvalidateEntry(_, true, device_files_, NotNull()))
|
||||
.Times(2)
|
||||
.WillRepeatedly(
|
||||
DoAll(Invoke(this, &UsageTableHeaderTest::InvalidateEntry),
|
||||
Return(NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
LoadUsageEntry(usage_entry_number_to_load, usage_entry_to_load))
|
||||
.WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES_3))
|
||||
.WillOnce(Return(INSUFFICIENT_CRYPTO_RESOURCES_3))
|
||||
.WillOnce(Return(NO_ERROR));
|
||||
|
||||
// Now invoke the method under test
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
mock_usage_table_header->LoadEntry(
|
||||
crypto_session_,
|
||||
usage_entry_to_load,
|
||||
usage_entry_number_to_load));
|
||||
}
|
||||
|
||||
TEST_F(UsageTableHeaderTest, LoadEntry_LoadUsageEntryFailsThrice) {
|
||||
// Initialize and setup
|
||||
MockUsageTableHeader* mock_usage_table_header = SetUpMock();
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, k10UsageEntryInfoVector);
|
||||
|
||||
// We try to load a usage entry from the first 7 entries, since
|
||||
// InvalidateEntry can't delete an entry if the last one is in use.
|
||||
uint32_t usage_entry_number_to_load =
|
||||
CdmRandom::RandomInRange(k10UsageEntryInfoVector.size() - 4);
|
||||
CdmUsageEntry usage_entry_to_load = kUsageEntry;
|
||||
|
||||
// Setup expectations
|
||||
EXPECT_CALL(*mock_usage_table_header,
|
||||
InvalidateEntry(_, true, device_files_, NotNull()))
|
||||
.Times(3)
|
||||
.WillRepeatedly(
|
||||
DoAll(Invoke(this, &UsageTableHeaderTest::InvalidateEntry),
|
||||
Return(NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
LoadUsageEntry(usage_entry_number_to_load, usage_entry_to_load))
|
||||
.Times(4)
|
||||
.WillRepeatedly(Return(INSUFFICIENT_CRYPTO_RESOURCES_3));
|
||||
|
||||
// Now invoke the method under test
|
||||
EXPECT_EQ(INSUFFICIENT_CRYPTO_RESOURCES_3,
|
||||
mock_usage_table_header->LoadEntry(
|
||||
crypto_session_,
|
||||
usage_entry_to_load,
|
||||
usage_entry_number_to_load));
|
||||
}
|
||||
|
||||
TEST_F(UsageTableHeaderTest, InvalidateEntry_InvalidUsageEntryNumber) {
|
||||
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
|
||||
uint32_t usage_entry_number = kUsageEntryInfoVector.size();
|
||||
|
||||
Reference in New Issue
Block a user