New usage entries are moved lower after creation.

[ Merge of http://go/wvgerrit/124004 ]

When the CDM creates a new usage entry for an offline or streaming
license, the new entry is immediately moved to the lowest available
entry index that has been marked as vacant (kStorageTypeUnknown).

When a license is released, its meta data that is managed by the CDM
is cleared; however, the usage entry's index is marked vacant, but it
is not released.  This creates wasted entry space in the usage table.
Unfortunately, defragging the table is computationally expensive and
may not be able to actually free up much space depending on when it
is performed.

For a typical user, this will likely not be an issue as the table
can get quite large compared to the number of licenses an app uses
and the table is partially cleaned on each boot.

GTS tests, however, have reached a point where they fill the usage
table before all tests are complete.  This is causing many unexpected
failures for devices.  Most of these tests release their license, but
the CDM never reaches a state where it can clean up the table.

By moving newly created entries to the lowest available index directly
after creating the entries, the table never needs to grow unless all
entries are in use.  Clean up is now almost never required.

Bug: 180639135
Bug: 180638990
Bug: 180638530
Test: MediaDrmTest#testWidevineApi28
Change-Id: I1a68d90d51384094298b27037778747ce7435374
This commit is contained in:
Alex Dale
2021-04-29 11:00:51 -07:00
parent 023b06eded
commit 884550333d
3 changed files with 504 additions and 141 deletions

View File

@@ -154,6 +154,46 @@ class UsageTableHeader {
bool DetermineTableCapacity(CryptoSession* crypto_session);
// == Table operation methods ==
// NOTE: The following "Table operation methods" require
// |usage_table_header_lock_| to be taken before calling.
// Creates a new entry for the provided crypto session. If the
// entry is created successfully in OEMCrypto, then a new entry
// info is added to the table's vector of entry info.
CdmResponseType CreateEntry(CryptoSession* const crypto_session,
uint32_t* usage_entry_number);
// Attempts to relocate a newly created usage entry associated with
// the provided |crypto_session| to the lowest unoccupied position in
// the table.
// |usage_entry_number| is treated as both an input and output.
// Returns NO_ERROR so long as no internal operation fails,
// regardless of whether the entry was moved or not.
CdmResponseType RelocateNewEntry(CryptoSession* const crypto_session,
uint32_t* usage_entry_number);
// Checks if the specified |usage_entry_number| is known to be
// unoccupied (released).
bool IsEntryUnoccupied(const uint32_t usage_entry_number) const;
// SetOfflineEntryInfo() and SetUsageInfoEntryInfo() populate the
// entry meta-data with the required information based on the type
// of entry.
void SetOfflineEntryInfo(const uint32_t usage_entry_number,
const std::string& key_set_id,
const CdmKeyResponse& license_message);
void SetUsageInfoEntryInfo(const uint32_t usage_entry_number,
const std::string& key_set_id,
const std::string& usage_info_file_name);
// Shrinks the table, removing all trailing unoccupied entries.
// |usage_entry_info_| will be resized appropriately.
// Caller must store the table after a successful call.
CdmResponseType RefitTable(CryptoSession* const crypto_session);
virtual CdmResponseType InvalidateEntryInternal(
uint32_t usage_entry_number, bool defrag_table, DeviceFiles* device_files,
metrics::CryptoMetrics* metrics);
CdmResponseType MoveEntry(uint32_t from /* usage entry number */,
const CdmUsageEntry& from_usage_entry,
@@ -279,6 +319,7 @@ class UsageTableHeader {
#if defined(UNIT_TEST)
// Test related declarations
friend class UsageTableHeaderTest;
FRIEND_TEST(UsageTableHeaderTest, Shrink_NoneOfTable);
FRIEND_TEST(UsageTableHeaderTest, Shrink_PartOfTable);
FRIEND_TEST(UsageTableHeaderTest, Shrink_AllOfTable);