Merge changes I939e4797,Iefbfe2dd,I002202b4,I09262da0

* changes:
  Core CDM: Remove usage info as a run-time type.
  Core CDM: Do not store/retrieve USAGE_INFO entries.
  Core CDM: Remove usage info API from DeviceFiles.
  Core CDM: Removed ability to add secure stop entry.
This commit is contained in:
Alex Dale
2022-11-10 03:03:27 +00:00
committed by Android (Google) Code Review
10 changed files with 1085 additions and 4136 deletions

View File

@@ -103,17 +103,6 @@ class DeviceFiles {
CryptoWrappedKey wrapped_private_key; CryptoWrappedKey wrapped_private_key;
}; };
struct CdmUsageData {
std::string provider_session_token;
CdmKeyMessage license_request;
CdmKeyResponse license;
std::string key_set_id;
CdmUsageEntry usage_entry;
uint32_t usage_entry_number;
std::string drm_certificate;
CryptoWrappedKey wrapped_private_key;
};
DeviceFiles(wvutil::FileSystem*); DeviceFiles(wvutil::FileSystem*);
virtual ~DeviceFiles(); virtual ~DeviceFiles();
@@ -164,103 +153,10 @@ class DeviceFiles {
virtual bool ReserveLicenseId(const std::string& key_set_id); virtual bool ReserveLicenseId(const std::string& key_set_id);
virtual bool UnreserveLicenseId(const std::string& key_set_id); virtual bool UnreserveLicenseId(const std::string& key_set_id);
// Use this method to create a |usage_info_file_name| from an |app_id| // Usage info has been deprecated, however, these two methods remain
static std::string GetUsageInfoFileName(const std::string& app_id); // for the removal of their storage data.
// The UsageInfo methods have been revised to use |usage_info_file_name|
// rather than |app_id| as a parameter. Use the helper method above to
// translate.
// OEMCrypto API 13 introduced big usage tables which required
// migration from usage tables stored by the TEE to usage table
// header+usage entries stored in unsecured persistent storage. The upgrade
// required creation of reverse lookup tables (CdmUsageEntryInfo).
// |app_id| however was hashed and unextractable, and necessitated the
// switch to |usage_info_file_name|
virtual bool StoreUsageInfo(
const std::string& provider_session_token,
const CdmKeyMessage& key_request, const CdmKeyResponse& key_response,
const std::string& usage_info_file_name, const std::string& key_set_id,
const CdmUsageEntry& usage_entry, uint32_t usage_entry_number,
const std::string& drm_certificate, const CryptoWrappedKey& wrapped_key);
// Retrieve usage identifying information stored on the file system.
// The caller needs to specify at least one of |ksids| or
// |provider_session_tokens|
virtual bool ListUsageIds(const std::string& app_id,
std::vector<std::string>* ksids,
std::vector<std::string>* provider_session_tokens);
// Get the provider session token for the given key_set_id.
virtual bool GetProviderSessionToken(const std::string& app_id,
const std::string& key_set_id,
std::string* provider_session_token);
virtual bool DeleteUsageInfo(const std::string& usage_info_file_name,
const std::string& provider_session_token);
// Deletes a set of provider sessions from the specified usage info.
// Sessions removed are based on the provided |key_set_ids|. If
// there are no remaining sessions associated with the usage info
// then the file will be deleted; otherwise, the remaining sessions
// are written back to the usage info file.
//
// Args:
// usage_info_file_name: name of the file containing the usage info
// message. This name should _not_ be the complete path, just
// the file name.
// key_set_ids: The list of key set IDs to be removed from the
// usage info. Note that any key set ids that are not present
// in the usage info are silently ignored.
// Returns:
// `true` if the file existed, and operations were completed as
// expected. `false` if the file does not exist or if there is an
// issue writing the result back to file.
virtual bool DeleteMultipleUsageInfoByKeySetIds(
const std::string& usage_info_file_name,
const std::vector<std::string>& key_set_ids);
// Delete usage information from the file system. Puts a list of all the
// psts that were deleted from the file into |provider_session_tokens|.
virtual bool DeleteAllUsageInfoForApp(
const std::string& usage_info_file_name,
std::vector<std::string>* provider_session_tokens);
virtual bool DeleteAllUsageInfo(); virtual bool DeleteAllUsageInfo();
// Retrieve the usage info entry specified by |provider_session_token|.
// Returns false if the entry could not be found.
virtual bool RetrieveUsageInfo(const std::string& usage_info_file_name,
const std::string& provider_session_token,
CdmKeyMessage* license_request,
CdmKeyResponse* license_response,
CdmUsageEntry* usage_entry,
uint32_t* usage_entry_number,
std::string* drm_certificate,
CryptoWrappedKey* wrapped_key);
// Retrieve the usage info entry specified by |key_set_id|.
// Returns false if the entry could not be found.
virtual bool RetrieveUsageInfoByKeySetId(
const std::string& usage_info_file_name, const std::string& key_set_id,
std::string* provider_session_token, CdmKeyMessage* license_request,
CdmKeyResponse* license_response, CdmUsageEntry* usage_entry,
uint32_t* usage_entry_number, std::string* drm_certificate,
CryptoWrappedKey* wrapped_key);
// These APIs support upgrading from usage tables to usage tabler header +
// entries introduced in OEMCrypto V13.
virtual bool ListUsageInfoFiles(std::vector<std::string>* usage_file_names); virtual bool ListUsageInfoFiles(std::vector<std::string>* usage_file_names);
virtual bool RetrieveUsageInfo(const std::string& usage_info_file_name,
std::vector<CdmUsageData>* usage_data);
virtual bool RetrieveUsageInfo(const std::string& usage_info_file_name,
const std::string& provider_session_token,
CdmUsageData* usage_data);
// This method overwrites rather than appends data to the usage file
virtual bool StoreUsageInfo(const std::string& usage_info_file_name,
const std::vector<CdmUsageData>& usage_data);
virtual bool UpdateUsageInfo(const std::string& usage_info_file_name,
const std::string& provider_session_token,
const CdmUsageData& usage_data);
virtual bool StoreHlsAttributes(const std::string& key_set_id, virtual bool StoreHlsAttributes(const std::string& key_set_id,
const CdmHlsMethod method, const CdmHlsMethod method,
@@ -272,7 +168,7 @@ class DeviceFiles {
virtual bool StoreUsageTableInfo( virtual bool StoreUsageTableInfo(
const CdmUsageTableHeader& usage_table_header, const CdmUsageTableHeader& usage_table_header,
const std::vector<CdmUsageEntryInfo>& usage_entry_info); const std::vector<CdmUsageEntryInfo>& usage_entry_info_list);
// When retrieving usage table information from the file system; any // When retrieving usage table information from the file system; any
// table that has yet to be updated for the LRU attributes will be // table that has yet to be updated for the LRU attributes will be
@@ -283,7 +179,7 @@ class DeviceFiles {
// is set to true if any are detected. // is set to true if any are detected.
virtual bool RetrieveUsageTableInfo( virtual bool RetrieveUsageTableInfo(
CdmUsageTableHeader* usage_table_header, CdmUsageTableHeader* usage_table_header,
std::vector<CdmUsageEntryInfo>* usage_entry_info, bool* lru_upgrade, std::vector<CdmUsageEntryInfo>* usage_entry_info_list, bool* lru_upgrade,
bool* has_usage_info_entries); bool* has_usage_info_entries);
virtual bool DeleteUsageTableInfo(); virtual bool DeleteUsageTableInfo();
@@ -355,23 +251,16 @@ class DeviceFiles {
FRIEND_TEST(DeviceFilesTest, OkpInfo_FileDoesNotExist); FRIEND_TEST(DeviceFilesTest, OkpInfo_FileDoesNotExist);
FRIEND_TEST(DeviceFilesTest, OkpInfo_DeleteFile); FRIEND_TEST(DeviceFilesTest, OkpInfo_DeleteFile);
FRIEND_TEST(DeviceFilesTest, OkpInfo_StoreAndRetrieve); FRIEND_TEST(DeviceFilesTest, OkpInfo_StoreAndRetrieve);
FRIEND_TEST(DeviceFilesUsageInfoTest, Delete);
FRIEND_TEST(DeviceFilesUsageInfoTest, DeleteAll);
FRIEND_TEST(DeviceFilesUsageInfoTest, Read);
FRIEND_TEST(DeviceFilesUsageInfoTest, Store);
FRIEND_TEST(DeviceFilesUsageTableTest, Read); FRIEND_TEST(DeviceFilesUsageTableTest, Read);
FRIEND_TEST(DeviceFilesUsageTableTest, Store); FRIEND_TEST(DeviceFilesUsageTableTest, Store);
FRIEND_TEST(DeviceFilesUsageTableTest, ReadWithoutLruData); FRIEND_TEST(DeviceFilesUsageTableTest, ReadWithoutLruData);
FRIEND_TEST(DeviceFilesUsageTableTest, ReadWithUsageInfoType);
FRIEND_TEST(RetrieveDefaultCertificateTest, ErrorScenarios); FRIEND_TEST(RetrieveDefaultCertificateTest, ErrorScenarios);
FRIEND_TEST(RetrieveLegacyCertificateTest, ErrorScenarios); FRIEND_TEST(RetrieveLegacyCertificateTest, ErrorScenarios);
FRIEND_TEST(StoreCertificateTest, DefaultAndLegacy); FRIEND_TEST(StoreCertificateTest, DefaultAndLegacy);
FRIEND_TEST(WvCdmRequestLicenseTest, UnprovisionTest); FRIEND_TEST(WvCdmRequestLicenseTest, UnprovisionTest);
FRIEND_TEST(WvCdmRequestLicenseTest, ForceL3Test); FRIEND_TEST(WvCdmRequestLicenseTest, ForceL3Test);
FRIEND_TEST(WvCdmRequestLicenseTest, UsageInfoRetryTest);
FRIEND_TEST(WvCdmRequestLicenseTest, UsageReleaseAllTest); FRIEND_TEST(WvCdmRequestLicenseTest, UsageReleaseAllTest);
FRIEND_TEST(WvCdmUsageInfoTest, UsageInfo);
FRIEND_TEST(WvCdmUsageTest, WithClientId);
FRIEND_TEST(WvCdmExtendedDurationTest, UsageOverflowTest);
#endif #endif
static std::set<std::string> reserved_license_ids_; static std::set<std::string> reserved_license_ids_;

View File

@@ -46,7 +46,7 @@ namespace wvcdm {
// //
// Upgrades from a fixed size usage table (supported by previous // Upgrades from a fixed size usage table (supported by previous
// versions of the OEMCrypto API v9-12) are handled by this class. // versions of the OEMCrypto API v9-12) are handled by this class.
// |usage_entry| and |usage_entry_number|s need to be saved in the license // |usage_entry| and |entry_number|s need to be saved in the license
// and usage info records by the caller. // and usage info records by the caller.
class UsageTableHeader { class UsageTableHeader {
public: public:
@@ -65,36 +65,30 @@ class UsageTableHeader {
// Adds a new entry to the OEMCrypto usage table header, and associates // Adds a new entry to the OEMCrypto usage table header, and associates
// the entry with the provided |crypto_session|. The index of the new // the entry with the provided |crypto_session|. The index of the new
// usage entry will be returned by |usage_entry_number|. // usage entry will be returned by |entry_number|.
// //
// Type of entry depends on the value of |persistent_license|: // Threading: Method takes exclusive use of |table_lock_|.
// false - usage info / secure stop record
// true - offline license
//
// Threading: Method takes exclusive use of |usage_table_header_lock_|.
virtual CdmResponseType AddEntry(CryptoSession* crypto_session, virtual CdmResponseType AddEntry(CryptoSession* crypto_session,
bool persistent_license,
const CdmKeySetId& key_set_id, const CdmKeySetId& key_set_id,
const std::string& usage_info_filename,
const CdmKeyResponse& license_message, const CdmKeyResponse& license_message,
uint32_t* usage_entry_number); uint32_t* entry_number);
// Threading: Method takes exclusive use of |usage_table_header_lock_|. // Threading: Method takes exclusive use of |table_lock_|.
virtual CdmResponseType LoadEntry(CryptoSession* crypto_session, virtual CdmResponseType LoadEntry(CryptoSession* crypto_session,
const CdmUsageEntry& usage_entry, const CdmUsageEntry& usage_entry,
uint32_t usage_entry_number); uint32_t entry_number);
// Threading: Method takes exclusive use of |usage_table_header_lock_|. // Threading: Method takes exclusive use of |table_lock_|.
virtual CdmResponseType UpdateEntry(uint32_t usage_entry_number, virtual CdmResponseType UpdateEntry(uint32_t entry_number,
CryptoSession* crypto_session, CryptoSession* crypto_session,
CdmUsageEntry* usage_entry); CdmUsageEntry* usage_entry);
// The licenses or usage info records specified by |usage_entry_number| // The licenses or usage info records specified by |entry_number|
// should not be in use by any open CryptoSession objects when calls // should not be in use by any open CryptoSession objects when calls
// to InvalidateEntry and MoveEntry are made. // to InvalidateEntry and MoveEntry are made.
// If |defrag_table| is true, the table will be defragmented after // If |defrag_table| is true, the table will be defragmented after
// the entry has been invalidated. // the entry has been invalidated.
// //
// Threading: Method takes exclusive use of |usage_table_header_lock_|. // Threading: Method takes exclusive use of |table_lock_|.
virtual CdmResponseType InvalidateEntry(uint32_t usage_entry_number, virtual CdmResponseType InvalidateEntry(uint32_t entry_number,
bool defrag_table, bool defrag_table,
DeviceFiles* device_files, DeviceFiles* device_files,
metrics::CryptoMetrics* metrics); metrics::CryptoMetrics* metrics);
@@ -107,13 +101,13 @@ class UsageTableHeader {
// for the objects that InvalidateEntry depends on. // for the objects that InvalidateEntry depends on.
// //
// Threading: Method requires care of caller for exclusive access. // Threading: Method requires care of caller for exclusive access.
void InvalidateEntryForTest(uint32_t usage_entry_number); void InvalidateEntryForTest(uint32_t entry_number);
// == Table information methods == // == Table information methods ==
// Threading: None of the following are thread safe. Intended for // Threading: None of the following are thread safe. Intended for
// testing or internal use. // testing or internal use.
size_t size() { return usage_entry_info_.size(); } size_t size() { return entry_info_list_.size(); }
size_t potential_table_capacity() const { return potential_table_capacity_; } size_t potential_table_capacity() const { return potential_table_capacity_; }
@@ -122,14 +116,11 @@ class UsageTableHeader {
} }
// Returns the number of entries currently tracked by the CDM that // Returns the number of entries currently tracked by the CDM that
// are related to usage info (streaming licenses). // are populated (non-empty).
size_t UsageInfoCount() const; size_t OccupiedEntryCount() const;
// Returns the number of entries currently tracked by the CDM that
// are related to offline licenses.
size_t OfflineEntryCount() const;
const std::vector<CdmUsageEntryInfo>& usage_entry_info() const { const std::vector<CdmUsageEntryInfo>& entry_info_list() const {
return usage_entry_info_; return entry_info_list_;
} }
// Set the reference clock used for the method GetCurrentTime(). // Set the reference clock used for the method GetCurrentTime().
@@ -141,10 +132,10 @@ class UsageTableHeader {
} }
static bool DetermineLicenseToRemoveForTesting( static bool DetermineLicenseToRemoveForTesting(
const std::vector<CdmUsageEntryInfo>& usage_entry_info_list, const std::vector<CdmUsageEntryInfo>& entry_info_list,
int64_t current_time, size_t unexpired_threshold, int64_t current_time, size_t unexpired_threshold,
uint32_t* entry_to_remove) { uint32_t* entry_to_remove) {
return DetermineLicenseToRemove(usage_entry_info_list, current_time, return DetermineLicenseToRemove(entry_info_list, current_time,
unexpired_threshold, entry_to_remove); unexpired_threshold, entry_to_remove);
} }
@@ -155,13 +146,13 @@ class UsageTableHeader {
// Creates a new, empty usage table. Any existing usage table files // Creates a new, empty usage table. Any existing usage table files
// will be deleted. // will be deleted.
// Threading: Method takes exclusive use of |usage_table_header_lock_| // Threading: Method takes exclusive use of |table_lock_|
// when required. // when required.
bool CreateNewTable(CryptoSession* const crypto_session); bool CreateNewTable(CryptoSession* const crypto_session);
// Attempts to restore the usage table from persistent storage, and // Attempts to restore the usage table from persistent storage, and
// loads the usage table header into OEMCrypto. // loads the usage table header into OEMCrypto.
// Note: No other OEMCrypto session should be opened before calling. // Note: No other OEMCrypto session should be opened before calling.
// Threading: Method takes exclusive use of |usage_table_header_lock_| // Threading: Method takes exclusive use of |table_lock_|
// when required. // when required.
bool RestoreTable(CryptoSession* const crypto_session); bool RestoreTable(CryptoSession* const crypto_session);
@@ -173,55 +164,52 @@ class UsageTableHeader {
// one more entry if the table is at or near the reported capacity. // one more entry if the table is at or near the reported capacity.
// If this check fails, a new usage table SHOULD be created. // If this check fails, a new usage table SHOULD be created.
// Threading: Method requires caller to take exclusive use of // Threading: Method requires caller to take exclusive use of
// |usage_table_header_lock_|. // |table_lock_|.
bool CapacityCheck(CryptoSession* const crypto_session); bool CapacityCheck(CryptoSession* const crypto_session);
// Attempts to determine the capacity of the OEMCrypto usage table. // Attempts to determine the capacity of the OEMCrypto usage table.
// Sets the result to |potential_table_capacity_|. // Sets the result to |potential_table_capacity_|.
// Threading: Method requires caller to take exclusive use of // Threading: Method requires caller to take exclusive use of
// |usage_table_header_lock_|. // |table_lock_|.
bool DetermineTableCapacity(CryptoSession* crypto_session); bool DetermineTableCapacity(CryptoSession* crypto_session);
// == Table operation methods == // == Table operation methods ==
// Threading: All of the following methods require caller to take // Threading: All of the following methods require caller to take
// exclusive use of |usage_table_header_lock_|. // exclusive use of |table_lock_|.
// Creates a new entry for the provided crypto session. If the // Creates a new entry for the provided crypto session. If the
// entry is created successfully in OEMCrypto, then a new entry // entry is created successfully in OEMCrypto, then a new entry
// info is added to the table's vector of entry info. // info is added to the table's vector of entry info.
CdmResponseType CreateEntry(CryptoSession* const crypto_session, CdmResponseType CreateEntry(CryptoSession* const crypto_session,
uint32_t* usage_entry_number); uint32_t* entry_number);
// Attempts to relocate a newly created usage entry associated with // Attempts to relocate a newly created usage entry associated with
// the provided |crypto_session| to the lowest unoccupied position in // the provided |crypto_session| to the lowest unoccupied position in
// the table. // the table.
// |usage_entry_number| is treated as both an input and output. // |entry_number| is treated as both an input and output.
// Returns NO_ERROR so long as no internal operation fails, // Returns NO_ERROR so long as no internal operation fails,
// regardless of whether the entry was moved or not. // regardless of whether the entry was moved or not.
CdmResponseType RelocateNewEntry(CryptoSession* const crypto_session, CdmResponseType RelocateNewEntry(CryptoSession* const crypto_session,
uint32_t* usage_entry_number); uint32_t* entry_number);
// Checks if the specified |usage_entry_number| is known to be // Checks if the specified |entry_number| is known to be
// unoccupied (released). // unoccupied (released).
bool IsEntryUnoccupied(const uint32_t usage_entry_number) const; bool IsEntryUnoccupied(const uint32_t entry_number) const;
// SetOfflineEntryInfo() and SetUsageInfoEntryInfo() populate the // Populates the entry's meta-data with the required information based
// entry meta-data with the required information based on the type // entry meta-data with the required information based on the type
// of entry. // on the license content.
void SetOfflineEntryInfo(const uint32_t usage_entry_number, void SetOfflineEntryInfo(const uint32_t entry_number,
const std::string& key_set_id, const std::string& key_set_id,
const CdmKeyResponse& license_message); 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. // Shrinks the table, removing all trailing unoccupied entries.
// |usage_entry_info_| will be resized appropriately. // |entry_info_| will be resized appropriately.
// Caller must store the table after a successful call. // Caller must store the table after a successful call.
CdmResponseType RefitTable(CryptoSession* const crypto_session); CdmResponseType RefitTable(CryptoSession* const crypto_session);
virtual CdmResponseType InvalidateEntryInternal( virtual CdmResponseType InvalidateEntryInternal(
uint32_t usage_entry_number, bool defrag_table, DeviceFiles* device_files, uint32_t entry_number, bool defrag_table, DeviceFiles* device_files,
metrics::CryptoMetrics* metrics); metrics::CryptoMetrics* metrics);
CdmResponseType MoveEntry(uint32_t from /* usage entry number */, CdmResponseType MoveEntry(uint32_t from /* usage entry number */,
@@ -230,11 +218,9 @@ class UsageTableHeader {
DeviceFiles* device_files, DeviceFiles* device_files,
metrics::CryptoMetrics* metrics); metrics::CryptoMetrics* metrics);
CdmResponseType GetEntry(uint32_t usage_entry_number, CdmResponseType GetEntry(uint32_t entry_number, DeviceFiles* device_files,
DeviceFiles* device_files,
CdmUsageEntry* usage_entry); CdmUsageEntry* usage_entry);
CdmResponseType StoreEntry(uint32_t usage_entry_number, CdmResponseType StoreEntry(uint32_t entry_number, DeviceFiles* device_files,
DeviceFiles* device_files,
const CdmUsageEntry& usage_entry); const CdmUsageEntry& usage_entry);
// Stores the usage table and it's info. This will increment // Stores the usage table and it's info. This will increment
@@ -285,7 +271,7 @@ class UsageTableHeader {
// types. // types.
// //
// Parameters: // Parameters:
// [in] usage_entry_info_list: The complete list of known usage // [in] entry_info_list: The complete list of known usage
// entries. // entries.
// [in] current_time: The current time to compare expiration times // [in] current_time: The current time to compare expiration times
// against. // against.
@@ -300,20 +286,20 @@ class UsageTableHeader {
// |true| if an entry has been determined to be removed. // |true| if an entry has been determined to be removed.
// Otherwise returns |false|. // Otherwise returns |false|.
static bool DetermineLicenseToRemove( static bool DetermineLicenseToRemove(
const std::vector<CdmUsageEntryInfo>& usage_entry_info_list, const std::vector<CdmUsageEntryInfo>& entry_info_list,
int64_t current_time, size_t unexpired_threshold, int64_t current_time, size_t unexpired_threshold,
uint32_t* entry_to_remove); uint32_t* entry_to_remove);
// This handle and file system is only to be used when accessing // This handle and file system is only to be used when accessing
// usage_table_header. Usage entries should use the file system provided // |table_header|. Usage entries should use the file system provided
// by CdmSession. // by CdmSession.
std::unique_ptr<DeviceFiles> device_files_; std::unique_ptr<DeviceFiles> device_files_;
std::unique_ptr<wvutil::FileSystem> file_system_; std::unique_ptr<wvutil::FileSystem> file_system_;
CdmSecurityLevel security_level_ = kSecurityLevelUninitialized; CdmSecurityLevel security_level_ = kSecurityLevelUninitialized;
RequestedSecurityLevel requested_security_level_ = kLevelDefault; RequestedSecurityLevel requested_security_level_ = kLevelDefault;
CdmUsageTableHeader usage_table_header_; CdmUsageTableHeader table_header_;
std::vector<CdmUsageEntryInfo> usage_entry_info_; std::vector<CdmUsageEntryInfo> entry_info_list_;
// Table is sync with persistent storage and can be used by the CDM // Table is sync with persistent storage and can be used by the CDM
// to interact with OEMCrypto. // to interact with OEMCrypto.
@@ -321,7 +307,7 @@ class UsageTableHeader {
// Synchonizes access to the Usage Table Header and bookkeeping // Synchonizes access to the Usage Table Header and bookkeeping
// data-structures // data-structures
mutable std::mutex usage_table_header_lock_; mutable std::mutex table_lock_;
metrics::CryptoMetrics alternate_crypto_metrics_; metrics::CryptoMetrics alternate_crypto_metrics_;

View File

@@ -537,44 +537,71 @@ enum CdmUsageSupportType : int32_t {
kUnknownUsageSupport, kUnknownUsageSupport,
}; };
enum CdmUsageEntryStorageType : int32_t { class CdmUsageEntryInfo {
kStorageLicense, public:
kStorageUsageInfo, CdmUsageEntryInfo() {}
kStorageTypeUnknown, CdmUsageEntryInfo(const std::string& key_set_id, int64_t last_use_time,
}; int64_t license_expiry_time)
: key_set_id_(key_set_id),
last_use_time_(last_use_time),
license_expiry_time_(license_expiry_time) {
if (key_set_id.empty()) Clear();
}
CdmUsageEntryInfo(const CdmUsageEntryInfo&) = default;
CdmUsageEntryInfo& operator=(const CdmUsageEntryInfo&) = default;
CdmUsageEntryInfo(CdmUsageEntryInfo&&) = default;
CdmUsageEntryInfo& operator=(CdmUsageEntryInfo&&) = default;
bool HasKeySetId() const { return !key_set_id_.empty(); }
bool IsEmpty() const { return key_set_id_.empty(); }
const std::string& key_set_id() const { return key_set_id_; }
void SetKeySetId(const std::string& key_set_id) {
if (key_set_id.empty()) {
Clear();
} else {
key_set_id_ = key_set_id;
}
}
int64_t last_use_time() const { return last_use_time_; }
void SetLastUseTime(int64_t last_use_time) { last_use_time_ = last_use_time; }
// Used for testing.
void IncLastUseTime() { last_use_time_++; }
void DecLastUseTime() { last_use_time_--; }
int64_t license_expiry_time() const { return license_expiry_time_; }
void SetLicenseExpiryTime(int64_t license_expiry_time) {
license_expiry_time_ = license_expiry_time;
}
void Clear() {
key_set_id_.clear();
last_use_time_ = license_expiry_time_ = 0;
}
struct CdmUsageEntryInfo {
CdmUsageEntryStorageType storage_type;
CdmKeySetId key_set_id;
std::string usage_info_file_name;
int64_t last_use_time;
int64_t offline_license_expiry_time; // Only for offline licenses.
bool operator==(const CdmUsageEntryInfo& other) const { bool operator==(const CdmUsageEntryInfo& other) const {
if (this == &other) { if (this == &other) {
return true; return true;
} }
if (storage_type != other.storage_type || key_set_id != other.key_set_id || if (IsEmpty() && other.IsEmpty()) {
last_use_time != other.last_use_time) { // All other fields are ignored if there is no key set ID set.
return true;
}
if (key_set_id_ != other.key_set_id_) {
return false; return false;
} }
// Certain fields only have meaning based on the storage type. return last_use_time_ == other.last_use_time_ &&
if (storage_type == kStorageUsageInfo) { license_expiry_time_ == other.license_expiry_time_;
return usage_info_file_name == other.usage_info_file_name;
}
if (storage_type == kStorageLicense) {
return offline_license_expiry_time == other.offline_license_expiry_time;
}
// else storage_type == kStorageTypeUnknown
return true;
} }
void Clear() { private:
storage_type = kStorageTypeUnknown; // If |key_set_id_| is empty, the other fields are ignored.
key_set_id.clear(); CdmKeySetId key_set_id_ = "";
usage_info_file_name.clear(); int64_t last_use_time_ = 0;
last_use_time = 0; int64_t license_expiry_time_ = 0;
offline_license_expiry_time = 0;
}
}; };
enum CdmKeySecurityLevel : int32_t { enum CdmKeySecurityLevel : int32_t {
@@ -846,7 +873,6 @@ const char* CdmOfflineLicenseStateToString(
CdmOfflineLicenseState license_state); CdmOfflineLicenseState license_state);
const char* CdmResponseTypeToString(int cdm_response_type); const char* CdmResponseTypeToString(int cdm_response_type);
const char* CdmSecurityLevelToString(CdmSecurityLevel security_level); const char* CdmSecurityLevelToString(CdmSecurityLevel security_level);
const char* CdmUsageEntryStorageTypeToString(CdmUsageEntryStorageType type);
const char* RequestedSecurityLevelToString( const char* RequestedSecurityLevelToString(
RequestedSecurityLevel security_level); RequestedSecurityLevel security_level);
const char* CdmWatermarkingSupportToString(CdmWatermarkingSupport support); const char* CdmWatermarkingSupportToString(CdmWatermarkingSupport support);

View File

@@ -484,9 +484,8 @@ CdmResponseType CdmSession::AddKeyInternal(const CdmKeyResponse& key_response) {
LOGE("CDM does not support secure stop licenses"); LOGE("CDM does not support secure stop licenses");
return ADD_KEY_ERROR; return ADD_KEY_ERROR;
} }
sts = usage_table_header_->AddEntry( sts = usage_table_header_->AddEntry(crypto_session_.get(), key_set_id_,
crypto_session_.get(), /* is_persistent */ true, key_set_id_, key_response, &usage_entry_number_);
/* usage_info_filename */ "", key_response, &usage_entry_number_);
crypto_metrics_->usage_table_header_add_entry_.Increment(sts); crypto_metrics_->usage_table_header_add_entry_.Increment(sts);
if (sts != NO_ERROR) return sts; if (sts != NO_ERROR) return sts;
provider_session_token_ = std::move(provider_session_token); provider_session_token_ = std::move(provider_session_token);
@@ -1050,9 +1049,9 @@ bool CdmSession::VerifyOfflineUsageEntry() {
return false; return false;
} }
const CdmUsageEntryInfo& usage_entry_info = const CdmUsageEntryInfo& usage_entry_info =
usage_table_header_->usage_entry_info().at(usage_entry_number_); usage_table_header_->entry_info_list().at(usage_entry_number_);
if (usage_entry_info.storage_type != kStorageLicense || if (usage_entry_info.IsEmpty() ||
usage_entry_info.key_set_id != key_set_id_) { usage_entry_info.key_set_id() != key_set_id_) {
LOGD("License usage entry does not match"); LOGD("License usage entry does not match");
return false; return false;
} }

View File

@@ -32,17 +32,6 @@ using video_widevine_client::sdk::License_LicenseState_ACTIVE;
using video_widevine_client::sdk::License_LicenseState_RELEASING; using video_widevine_client::sdk::License_LicenseState_RELEASING;
using video_widevine_client::sdk::NameValue; using video_widevine_client::sdk::NameValue;
using video_widevine_client::sdk::OemCertificate; using video_widevine_client::sdk::OemCertificate;
using video_widevine_client::sdk::UsageInfo;
using video_widevine_client::sdk::UsageInfo_DrmUsageCertificate;
using video_widevine_client::sdk::UsageInfo_ProviderSession;
using video_widevine_client::sdk::UsageTableInfo;
using video_widevine_client::sdk::UsageTableInfo_UsageEntryInfo;
using video_widevine_client::sdk::
UsageTableInfo_UsageEntryInfo_UsageEntryStorage_LICENSE;
using video_widevine_client::sdk::
UsageTableInfo_UsageEntryInfo_UsageEntryStorage_UNKNOWN;
using video_widevine_client::sdk::
UsageTableInfo_UsageEntryInfo_UsageEntryStorage_USAGE_INFO;
// Stringify turns macro arguments into static C strings. // Stringify turns macro arguments into static C strings.
// Example: STRINGIFY(this_argument) -> "this_argument" // Example: STRINGIFY(this_argument) -> "this_argument"
@@ -184,111 +173,6 @@ bool ExtractFromDeviceCertificate(const DeviceCertificate& device_certificate,
} }
return true; return true;
} }
bool FindOrInsertUsageCertificate(const std::string& drm_certificate,
const CryptoWrappedKey& wrapped_private_key,
UsageInfo* usage_info,
uint32_t* drm_certificate_id) {
RETURN_FALSE_IF_NULL(usage_info);
RETURN_FALSE_IF_NULL(drm_certificate_id);
// Scan |drm_certificate_cache| for |drm_certificate|. If present,
// return the id
std::set<uint32_t> ids;
for (const UsageInfo_DrmUsageCertificate& drm_device_cert :
usage_info->drm_certificate_cache()) {
if (drm_device_cert.drm_certificate().certificate() == drm_certificate) {
*drm_certificate_id = drm_device_cert.drm_certificate_id();
return true;
}
ids.insert(drm_device_cert.drm_certificate_id());
}
uint32_t last_id = 0;
// |drm_certificate| is not in the cache. Find the first non-contiguous
// id number to insert
for (uint32_t id : ids) {
if (id > last_id + 1) {
break;
}
last_id = id;
}
if (ids.empty())
*drm_certificate_id = 0;
else
*drm_certificate_id = last_id + 1;
// Now insert into |drm_certificate_cache|
UsageInfo_DrmUsageCertificate* drm_usage_certificate =
usage_info->add_drm_certificate_cache();
drm_usage_certificate->set_drm_certificate_id(*drm_certificate_id);
return SetDeviceCertificate(drm_certificate, wrapped_private_key,
drm_usage_certificate->mutable_drm_certificate());
}
bool FindUsageCertificate(
uint32_t drm_certificate_id,
const google::protobuf::RepeatedPtrField<UsageInfo_DrmUsageCertificate>&
drm_certificate_cache,
std::string* drm_certificate, CryptoWrappedKey* wrapped_private_key) {
for (const UsageInfo_DrmUsageCertificate& drm_usage_cert :
drm_certificate_cache) {
if (drm_usage_cert.drm_certificate_id() == drm_certificate_id) {
return ExtractFromDeviceCertificate(drm_usage_cert.drm_certificate(),
drm_certificate, wrapped_private_key);
}
}
LOGE("Unable to find any certificate in usage cache for entry: %d",
drm_certificate_id);
return false;
}
bool UsageCertificateCacheCleanUp(UsageInfo* usage_info) {
const google::protobuf::RepeatedPtrField<UsageInfo_ProviderSession>&
provider_sessions = usage_info->sessions();
google::protobuf::RepeatedPtrField<UsageInfo_DrmUsageCertificate>*
drm_certificate_cache = usage_info->mutable_drm_certificate_cache();
// Find all the DRM certificate ids in |drm_certificate_cache|
std::set<uint32_t> ids;
for (const UsageInfo_DrmUsageCertificate& drm_usage_cert :
*drm_certificate_cache) {
ids.insert(drm_usage_cert.drm_certificate_id());
}
// Next find all the DRM certificate ids in |provider_sessions|
std::set<uint32_t> session_ids;
for (const UsageInfo_ProviderSession& session : provider_sessions) {
session_ids.insert(session.drm_certificate_id());
}
// Now find all the entry numbers for DRM certificates in
// |drm_device_certificates| but not in |provider_sessions|. These need to
// be removed.
std::set<uint32_t> ids_to_erase;
std::set_difference(ids.begin(), ids.end(), session_ids.begin(),
session_ids.end(),
std::inserter(ids_to_erase, ids_to_erase.begin()));
const auto is_deletable =
[&ids_to_erase](
const UsageInfo_DrmUsageCertificate& usage_certificate) -> bool {
return std::find(ids_to_erase.cbegin(), ids_to_erase.cend(),
usage_certificate.drm_certificate_id()) !=
ids_to_erase.cend();
};
drm_certificate_cache->erase(
std::remove_if(drm_certificate_cache->begin(),
drm_certificate_cache->end(), is_deletable),
drm_certificate_cache->end());
return true;
}
} // namespace } // namespace
// static // static
@@ -1007,512 +891,12 @@ bool DeviceFiles::UnreserveLicenseId(const std::string& key_set_id) {
return true; return true;
} }
bool DeviceFiles::StoreUsageInfo(
const std::string& provider_session_token, const CdmKeyMessage& key_request,
const CdmKeyResponse& key_response, const std::string& usage_info_file_name,
const std::string& key_set_id, const std::string& usage_entry,
uint32_t usage_entry_number, const std::string& drm_certificate,
const CryptoWrappedKey& wrapped_private_key) {
RETURN_FALSE_IF_UNINITIALIZED();
video_widevine_client::sdk::File file;
if (!FileExists(usage_info_file_name)) {
file.set_type(video_widevine_client::sdk::File::USAGE_INFO);
file.set_version(video_widevine_client::sdk::File::VERSION_1);
} else {
if (RetrieveHashedFile(usage_info_file_name, &file) != kNoError) {
LOGE("Unable to retrieve usage info file");
return false;
}
}
UsageInfo* usage_info = file.mutable_usage_info();
UsageInfo_ProviderSession* provider_session = usage_info->add_sessions();
provider_session->set_token(provider_session_token.data(),
provider_session_token.size());
provider_session->set_license_request(key_request.data(), key_request.size());
provider_session->set_license(key_response.data(), key_response.size());
provider_session->set_key_set_id(key_set_id.data(), key_set_id.size());
provider_session->set_usage_entry(usage_entry);
provider_session->set_usage_entry_number(usage_entry_number);
if (drm_certificate.size() > 0) {
uint32_t drm_certificate_id;
if (!FindOrInsertUsageCertificate(drm_certificate, wrapped_private_key,
usage_info, &drm_certificate_id)) {
LOGE("Unable to insert a certificate in the usage certificate cache");
return false;
}
provider_session->set_drm_certificate_id(drm_certificate_id);
}
std::string serialized_file;
file.SerializeToString(&serialized_file);
return StoreFileWithHash(usage_info_file_name, serialized_file) == kNoError;
}
bool DeviceFiles::ListUsageIds(
const std::string& app_id, std::vector<std::string>* ksids,
std::vector<std::string>* provider_session_tokens) {
RETURN_FALSE_IF_UNINITIALIZED();
if (ksids == nullptr && provider_session_tokens == nullptr) {
LOGE(
"Both output parameters |ksids| and |provider_session_tokens| are "
"not provided");
return false;
}
// Empty or non-existent file == no usage records.
std::string file_name = GetUsageInfoFileName(app_id);
if (!FileExists(file_name) || GetFileSize(file_name) == 0) {
if (ksids != nullptr) ksids->clear();
if (provider_session_tokens != nullptr) provider_session_tokens->clear();
return true;
}
video_widevine_client::sdk::File file;
if (RetrieveHashedFile(file_name, &file) != kNoError) {
LOGE("Unable to retrieve usage info file");
return false;
}
if (ksids != nullptr) ksids->clear();
if (provider_session_tokens != nullptr) provider_session_tokens->clear();
const int num_records = file.usage_info().sessions_size();
for (int i = 0; i < num_records; ++i) {
if ((ksids != nullptr) &&
!file.usage_info().sessions(i).key_set_id().empty()) {
ksids->push_back(file.usage_info().sessions(i).key_set_id());
}
if ((provider_session_tokens != nullptr) &&
!file.usage_info().sessions(i).token().empty()) {
provider_session_tokens->push_back(file.usage_info().sessions(i).token());
}
}
return true;
}
bool DeviceFiles::GetProviderSessionToken(const std::string& app_id,
const std::string& key_set_id,
std::string* provider_session_token) {
RETURN_FALSE_IF_UNINITIALIZED();
RETURN_FALSE_IF_NULL(provider_session_token);
std::string file_name = GetUsageInfoFileName(app_id);
if (!FileExists(file_name) || GetFileSize(file_name) == 0) {
LOGE("Usage info file does not exists or is an empty file");
return false;
}
video_widevine_client::sdk::File file;
if (RetrieveHashedFile(file_name, &file) != kNoError) {
LOGE("Unable to retrieve usage info file");
return false;
}
const int num_records = static_cast<int>(file.usage_info().sessions_size());
for (int i = 0; i < num_records; ++i) {
if (file.usage_info().sessions(i).key_set_id() == key_set_id) {
*provider_session_token = file.usage_info().sessions(i).token();
return true;
}
}
return false;
}
bool DeviceFiles::DeleteUsageInfo(const std::string& usage_info_file_name,
const std::string& provider_session_token) {
RETURN_FALSE_IF_UNINITIALIZED();
video_widevine_client::sdk::File file;
if (RetrieveHashedFile(usage_info_file_name, &file) != kNoError) {
LOGE("Unable to retrieve usage info file");
return false;
}
UsageInfo* usage_info = file.mutable_usage_info();
int index = 0;
bool found = false;
for (; index < usage_info->sessions_size(); ++index) {
if (usage_info->sessions(index).token() == provider_session_token) {
found = true;
break;
}
}
if (!found) {
LOGE("Unable to find provider session token: pst = %s",
wvutil::b2a_hex(provider_session_token).c_str());
return false;
}
google::protobuf::RepeatedPtrField<UsageInfo_ProviderSession>* sessions =
usage_info->mutable_sessions();
if (index < usage_info->sessions_size() - 1) {
sessions->SwapElements(index, usage_info->sessions_size() - 1);
}
sessions->RemoveLast();
UsageCertificateCacheCleanUp(usage_info);
std::string serialized_file;
file.SerializeToString(&serialized_file);
return StoreFileWithHash(usage_info_file_name, serialized_file) == kNoError;
}
bool DeviceFiles::DeleteAllUsageInfoForApp(
const std::string& usage_info_file_name,
std::vector<std::string>* provider_session_tokens) {
RETURN_FALSE_IF_UNINITIALIZED();
RETURN_FALSE_IF_NULL(provider_session_tokens);
provider_session_tokens->clear();
if (!FileExists(usage_info_file_name)) return true;
video_widevine_client::sdk::File file;
if (RetrieveHashedFile(usage_info_file_name, &file) == kNoError) {
for (int i = 0; i < file.usage_info().sessions_size(); ++i) {
provider_session_tokens->push_back(file.usage_info().sessions(i).token());
}
} else {
LOGW("Unable to retrieve usage info file");
}
return RemoveFile(usage_info_file_name);
}
bool DeviceFiles::DeleteMultipleUsageInfoByKeySetIds(
const std::string& usage_info_file_name,
const std::vector<std::string>& key_set_ids) {
if (!FileExists(usage_info_file_name)) return false;
if (key_set_ids.empty()) {
LOGW("No key set IDs provided");
return true;
}
video_widevine_client::sdk::File file;
if (RetrieveHashedFile(usage_info_file_name, &file) != kNoError) {
LOGW("Unable to retrieve usage info file");
return false;
}
const auto is_deletable =
[&key_set_ids](
const video_widevine_client::sdk::UsageInfo::ProviderSession& session)
-> bool {
return std::find(key_set_ids.cbegin(), key_set_ids.cend(),
session.key_set_id()) != key_set_ids.cend();
};
auto sessions = file.mutable_usage_info()->mutable_sessions();
const int initial_size = sessions->size();
sessions->erase(
std::remove_if(sessions->begin(), sessions->end(), is_deletable),
sessions->end());
if (sessions->size() == initial_size) {
// Nothing deleted.
return true;
}
if (sessions->size() > 0) {
UsageCertificateCacheCleanUp(file.mutable_usage_info());
std::string serialized_file;
file.SerializeToString(&serialized_file);
return StoreFileWithHash(usage_info_file_name, serialized_file) == kNoError;
}
return RemoveFile(usage_info_file_name);
}
bool DeviceFiles::DeleteAllUsageInfo() { bool DeviceFiles::DeleteAllUsageInfo() {
RETURN_FALSE_IF_UNINITIALIZED(); RETURN_FALSE_IF_UNINITIALIZED();
return RemoveFile(kUsageInfoFileNamePrefix + std::string(kWildcard) + return RemoveFile(kUsageInfoFileNamePrefix + std::string(kWildcard) +
kUsageInfoFileNameExt); kUsageInfoFileNameExt);
} }
bool DeviceFiles::RetrieveUsageInfo(const std::string& usage_info_file_name,
const std::string& provider_session_token,
CdmKeyMessage* license_request,
CdmKeyResponse* license,
std::string* usage_entry,
uint32_t* usage_entry_number,
std::string* drm_certificate,
CryptoWrappedKey* wrapped_private_key) {
RETURN_FALSE_IF_UNINITIALIZED();
RETURN_FALSE_IF_NULL(license_request);
RETURN_FALSE_IF_NULL(license);
RETURN_FALSE_IF_NULL(usage_entry);
RETURN_FALSE_IF_NULL(usage_entry_number);
RETURN_FALSE_IF_NULL(drm_certificate);
RETURN_FALSE_IF_NULL(wrapped_private_key);
video_widevine_client::sdk::File file;
if (RetrieveHashedFile(usage_info_file_name, &file) != kNoError) {
LOGE("Unable to retrieve usage info file");
return false;
}
int index = 0;
for (; index < file.usage_info().sessions_size(); ++index) {
if (file.usage_info().sessions(index).token() == provider_session_token) {
*license_request = file.usage_info().sessions(index).license_request();
*license = file.usage_info().sessions(index).license();
*usage_entry = file.usage_info().sessions(index).usage_entry();
*usage_entry_number = static_cast<uint32_t>(
file.usage_info().sessions(index).usage_entry_number());
if (!file.usage_info().sessions(index).has_drm_certificate_id()) {
drm_certificate->clear();
wrapped_private_key->Clear();
return true;
}
if (!FindUsageCertificate(
file.usage_info().sessions(index).drm_certificate_id(),
file.usage_info().drm_certificate_cache(), drm_certificate,
wrapped_private_key)) {
LOGE("Unable to find DRM certificate information from usage cache");
return false;
}
return true;
}
}
return false;
}
bool DeviceFiles::RetrieveUsageInfoByKeySetId(
const std::string& usage_info_file_name, const std::string& key_set_id,
std::string* provider_session_token, CdmKeyMessage* license_request,
CdmKeyResponse* license, std::string* usage_entry,
uint32_t* usage_entry_number, std::string* drm_certificate,
CryptoWrappedKey* wrapped_private_key) {
RETURN_FALSE_IF_UNINITIALIZED();
RETURN_FALSE_IF_NULL(license_request);
RETURN_FALSE_IF_NULL(license);
RETURN_FALSE_IF_NULL(usage_entry);
RETURN_FALSE_IF_NULL(usage_entry_number);
RETURN_FALSE_IF_NULL(drm_certificate);
RETURN_FALSE_IF_NULL(wrapped_private_key);
video_widevine_client::sdk::File file;
if (RetrieveHashedFile(usage_info_file_name, &file) != kNoError) {
LOGE("Unable to retrieve usage info file");
return false;
}
int index = 0;
for (; index < file.usage_info().sessions_size(); ++index) {
if (file.usage_info().sessions(index).key_set_id() == key_set_id) {
*provider_session_token = file.usage_info().sessions(index).token();
*license_request = file.usage_info().sessions(index).license_request();
*license = file.usage_info().sessions(index).license();
*usage_entry = file.usage_info().sessions(index).usage_entry();
*usage_entry_number = static_cast<uint32_t>(
file.usage_info().sessions(index).usage_entry_number());
if (!file.usage_info().sessions(index).has_drm_certificate_id()) {
drm_certificate->clear();
wrapped_private_key->Clear();
return true;
}
if (!FindUsageCertificate(
file.usage_info().sessions(index).drm_certificate_id(),
file.usage_info().drm_certificate_cache(), drm_certificate,
wrapped_private_key)) {
LOGE("Unable to find DRM certificate information from usage cache");
return false;
}
return true;
}
}
return false;
}
bool DeviceFiles::StoreUsageInfo(const std::string& usage_info_file_name,
const std::vector<CdmUsageData>& usage_data) {
RETURN_FALSE_IF_UNINITIALIZED();
video_widevine_client::sdk::File file;
file.set_type(video_widevine_client::sdk::File::USAGE_INFO);
file.set_version(video_widevine_client::sdk::File::VERSION_1);
UsageInfo* usage_info = file.mutable_usage_info();
for (size_t i = 0; i < usage_data.size(); ++i) {
UsageInfo_ProviderSession* provider_session = usage_info->add_sessions();
provider_session->set_token(usage_data[i].provider_session_token.data(),
usage_data[i].provider_session_token.size());
provider_session->set_license_request(usage_data[i].license_request.data(),
usage_data[i].license_request.size());
provider_session->set_license(usage_data[i].license.data(),
usage_data[i].license.size());
provider_session->set_key_set_id(usage_data[i].key_set_id.data(),
usage_data[i].key_set_id.size());
provider_session->set_usage_entry(usage_data[i].usage_entry);
provider_session->set_usage_entry_number(usage_data[i].usage_entry_number);
if (usage_data[i].drm_certificate.size() > 0) {
uint32_t drm_certificate_id;
if (!FindOrInsertUsageCertificate(usage_data[i].drm_certificate,
usage_data[i].wrapped_private_key,
usage_info, &drm_certificate_id)) {
LOGE("Unable to insert a certificate in the usage certificate cache");
return false;
}
provider_session->set_drm_certificate_id(drm_certificate_id);
}
}
std::string serialized_file;
file.SerializeToString(&serialized_file);
return StoreFileWithHash(usage_info_file_name, serialized_file) == kNoError;
}
bool DeviceFiles::UpdateUsageInfo(const std::string& usage_info_file_name,
const std::string& provider_session_token,
const CdmUsageData& usage_data) {
RETURN_FALSE_IF_UNINITIALIZED();
video_widevine_client::sdk::File file;
if (!FileExists(usage_info_file_name)) {
LOGE("Usage info file does not exist");
return false;
}
if (RetrieveHashedFile(usage_info_file_name, &file) != kNoError) {
LOGE("Unable to retrieve usage info file");
return false;
}
int index = 0;
for (; index < file.usage_info().sessions_size(); ++index) {
if (file.usage_info().sessions(index).token() == provider_session_token) {
UsageInfo* usage_info = file.mutable_usage_info();
UsageInfo_ProviderSession* provider_session =
usage_info->mutable_sessions(index);
provider_session->set_license_request(usage_data.license_request);
provider_session->set_license(usage_data.license);
provider_session->set_key_set_id(usage_data.key_set_id);
provider_session->set_usage_entry(usage_data.usage_entry);
provider_session->set_usage_entry_number(usage_data.usage_entry_number);
if (usage_data.drm_certificate.size() > 0) {
uint32_t drm_certificate_id;
if (!FindOrInsertUsageCertificate(usage_data.drm_certificate,
usage_data.wrapped_private_key,
usage_info, &drm_certificate_id)) {
LOGE("Unable to find a certificate in to update the usage info");
return false;
}
provider_session->set_drm_certificate_id(drm_certificate_id);
}
std::string serialized_file;
file.SerializeToString(&serialized_file);
return StoreFileWithHash(usage_info_file_name, serialized_file) ==
kNoError;
}
}
return false;
}
bool DeviceFiles::RetrieveUsageInfo(const std::string& usage_info_file_name,
std::vector<CdmUsageData>* usage_data) {
RETURN_FALSE_IF_UNINITIALIZED();
RETURN_FALSE_IF_NULL(usage_data);
if (!FileExists(usage_info_file_name) ||
GetFileSize(usage_info_file_name) == 0) {
usage_data->resize(0);
return true;
}
video_widevine_client::sdk::File file;
if (RetrieveHashedFile(usage_info_file_name, &file) != kNoError) {
LOGE("Unable to retrieve usage info file");
return false;
}
usage_data->resize(file.usage_info().sessions_size());
for (int i = 0; i < file.usage_info().sessions_size(); ++i) {
(*usage_data)[i].provider_session_token =
file.usage_info().sessions(i).token();
(*usage_data)[i].license_request =
file.usage_info().sessions(i).license_request();
(*usage_data)[i].license = file.usage_info().sessions(i).license();
(*usage_data)[i].key_set_id = file.usage_info().sessions(i).key_set_id();
(*usage_data)[i].usage_entry = file.usage_info().sessions(i).usage_entry();
(*usage_data)[i].usage_entry_number = static_cast<uint32_t>(
file.usage_info().sessions(i).usage_entry_number());
if (!file.usage_info().sessions(i).has_drm_certificate_id()) {
(*usage_data)[i].drm_certificate.clear();
(*usage_data)[i].wrapped_private_key.Clear();
} else {
if (!FindUsageCertificate(
file.usage_info().sessions(i).drm_certificate_id(),
file.usage_info().drm_certificate_cache(),
&(*usage_data)[i].drm_certificate,
&(*usage_data)[i].wrapped_private_key)) {
LOGW("Unable to find DRM certificate information from usage cache");
}
}
}
return true;
}
bool DeviceFiles::RetrieveUsageInfo(const std::string& usage_info_file_name,
const std::string& provider_session_token,
CdmUsageData* usage_data) {
RETURN_FALSE_IF_UNINITIALIZED();
RETURN_FALSE_IF_NULL(usage_data);
video_widevine_client::sdk::File file;
if (RetrieveHashedFile(usage_info_file_name, &file) != kNoError) {
LOGE("Unable to retrieve usage info file");
return false;
}
int index = 0;
for (; index < file.usage_info().sessions_size(); ++index) {
if (file.usage_info().sessions(index).token() == provider_session_token) {
usage_data->provider_session_token =
file.usage_info().sessions(index).token();
usage_data->license_request =
file.usage_info().sessions(index).license_request();
usage_data->license = file.usage_info().sessions(index).license();
usage_data->key_set_id = file.usage_info().sessions(index).key_set_id();
usage_data->usage_entry = file.usage_info().sessions(index).usage_entry();
usage_data->usage_entry_number = static_cast<uint32_t>(
file.usage_info().sessions(index).usage_entry_number());
if (!file.usage_info().sessions(index).has_drm_certificate_id()) {
usage_data->drm_certificate.clear();
usage_data->wrapped_private_key.Clear();
return true;
}
if (!FindUsageCertificate(
file.usage_info().sessions(index).drm_certificate_id(),
file.usage_info().drm_certificate_cache(),
&usage_data->drm_certificate, &usage_data->wrapped_private_key)) {
LOGE("Unable to find DRM certificate information from usage cache");
return false;
}
return true;
}
}
return false;
}
bool DeviceFiles::ListUsageInfoFiles( bool DeviceFiles::ListUsageInfoFiles(
std::vector<std::string>* usage_info_file_names) { std::vector<std::string>* usage_info_file_names) {
RETURN_FALSE_IF_UNINITIALIZED(); RETURN_FALSE_IF_UNINITIALIZED();
@@ -1630,8 +1014,10 @@ bool DeviceFiles::DeleteHlsAttributes(const std::string& key_set_id) {
bool DeviceFiles::StoreUsageTableInfo( bool DeviceFiles::StoreUsageTableInfo(
const CdmUsageTableHeader& usage_table_header, const CdmUsageTableHeader& usage_table_header,
const std::vector<CdmUsageEntryInfo>& usage_entry_info) { const std::vector<CdmUsageEntryInfo>& usage_entry_info_list) {
RETURN_FALSE_IF_UNINITIALIZED(); RETURN_FALSE_IF_UNINITIALIZED();
using video_widevine_client::sdk::UsageTableInfo;
using UsageEntryInfo = UsageTableInfo::UsageEntryInfo;
// Fill in file information // Fill in file information
video_widevine_client::sdk::File file; video_widevine_client::sdk::File file;
@@ -1639,35 +1025,22 @@ bool DeviceFiles::StoreUsageTableInfo(
file.set_type(video_widevine_client::sdk::File::USAGE_TABLE_INFO); file.set_type(video_widevine_client::sdk::File::USAGE_TABLE_INFO);
file.set_version(video_widevine_client::sdk::File::VERSION_1); file.set_version(video_widevine_client::sdk::File::VERSION_1);
UsageTableInfo* usage_table_info = file.mutable_usage_table_info(); UsageTableInfo* stored_table_info = file.mutable_usage_table_info();
usage_table_info->set_usage_table_header(usage_table_header); stored_table_info->set_usage_table_header(usage_table_header);
for (size_t i = 0; i < usage_entry_info.size(); ++i) {
UsageTableInfo_UsageEntryInfo* info = for (const auto& entry_info : usage_entry_info_list) {
usage_table_info->add_usage_entry_info(); UsageEntryInfo* stored_info = stored_table_info->add_usage_entry_info();
info->set_key_set_id(usage_entry_info[i].key_set_id); if (entry_info.HasKeySetId()) {
switch (usage_entry_info[i].storage_type) { stored_info->set_storage(UsageEntryInfo::LICENSE);
case kStorageLicense: stored_info->set_key_set_id(entry_info.key_set_id());
info->set_storage( stored_info->set_last_use_time(entry_info.last_use_time());
UsageTableInfo_UsageEntryInfo_UsageEntryStorage_LICENSE); stored_info->set_offline_license_expiry_time(
info->set_last_use_time(usage_entry_info[i].last_use_time); entry_info.license_expiry_time());
info->set_offline_license_expiry_time( } else {
usage_entry_info[i].offline_license_expiry_time); stored_info->set_storage(UsageEntryInfo::UNKNOWN);
break;
case kStorageUsageInfo:
info->set_storage(
UsageTableInfo_UsageEntryInfo_UsageEntryStorage_USAGE_INFO);
info->set_usage_info_file_name(
usage_entry_info[i].usage_info_file_name);
info->set_last_use_time(usage_entry_info[i].last_use_time);
break;
case kStorageTypeUnknown:
default:
info->set_storage(
UsageTableInfo_UsageEntryInfo_UsageEntryStorage_UNKNOWN);
break;
} }
} }
usage_table_info->set_use_lru(true); stored_table_info->set_use_lru(true);
std::string serialized_file; std::string serialized_file;
file.SerializeToString(&serialized_file); file.SerializeToString(&serialized_file);
@@ -1678,13 +1051,15 @@ bool DeviceFiles::StoreUsageTableInfo(
bool DeviceFiles::RetrieveUsageTableInfo( bool DeviceFiles::RetrieveUsageTableInfo(
CdmUsageTableHeader* usage_table_header, CdmUsageTableHeader* usage_table_header,
std::vector<CdmUsageEntryInfo>* usage_entry_info, bool* lru_upgrade, std::vector<CdmUsageEntryInfo>* usage_entry_info_list, bool* lru_upgrade,
bool* has_usage_info_entries) { bool* has_usage_info_entries) {
RETURN_FALSE_IF_UNINITIALIZED(); RETURN_FALSE_IF_UNINITIALIZED();
RETURN_FALSE_IF_NULL(usage_table_header); RETURN_FALSE_IF_NULL(usage_table_header);
RETURN_FALSE_IF_NULL(usage_entry_info); RETURN_FALSE_IF_NULL(usage_entry_info_list);
RETURN_FALSE_IF_NULL(lru_upgrade); RETURN_FALSE_IF_NULL(lru_upgrade);
RETURN_FALSE_IF_NULL(has_usage_info_entries); RETURN_FALSE_IF_NULL(has_usage_info_entries);
using video_widevine_client::sdk::UsageTableInfo;
using UsageEntryInfo = UsageTableInfo::UsageEntryInfo;
video_widevine_client::sdk::File file; video_widevine_client::sdk::File file;
if (RetrieveHashedFile(GetUsageTableFileName(), &file) != kNoError) { if (RetrieveHashedFile(GetUsageTableFileName(), &file) != kNoError) {
@@ -1711,35 +1086,28 @@ bool DeviceFiles::RetrieveUsageTableInfo(
return false; return false;
} }
const UsageTableInfo& usage_table_info = file.usage_table_info(); const UsageTableInfo& stored_table_info = file.usage_table_info();
*lru_upgrade = !usage_table_info.use_lru(); *lru_upgrade = !stored_table_info.use_lru();
*has_usage_info_entries = false; *has_usage_info_entries = false;
*usage_table_header = stored_table_info.usage_table_header();
usage_entry_info_list->clear();
usage_entry_info_list->reserve(stored_table_info.usage_entry_info_size());
*usage_table_header = usage_table_info.usage_table_header(); for (const auto& stored_entry_info : stored_table_info.usage_entry_info()) {
usage_entry_info->resize(usage_table_info.usage_entry_info_size()); CdmUsageEntryInfo entry_info;
for (int i = 0; i < usage_table_info.usage_entry_info_size(); ++i) { entry_info.Clear();
const UsageTableInfo_UsageEntryInfo& info = if (stored_entry_info.storage() == UsageEntryInfo::LICENSE) {
usage_table_info.usage_entry_info(i); entry_info.SetKeySetId(stored_entry_info.key_set_id());
(*usage_entry_info)[i].key_set_id = info.key_set_id(); entry_info.SetLastUseTime(stored_entry_info.last_use_time());
switch (info.storage()) { entry_info.SetLicenseExpiryTime(
case UsageTableInfo_UsageEntryInfo_UsageEntryStorage_LICENSE: stored_entry_info.offline_license_expiry_time());
(*usage_entry_info)[i].storage_type = kStorageLicense; } else if (stored_entry_info.storage() == UsageEntryInfo::USAGE_INFO) {
(*usage_entry_info)[i].last_use_time = info.last_use_time(); // USAGE_INFO are deprecated, do not retrieve this entries.
(*usage_entry_info)[i].offline_license_expiry_time = *has_usage_info_entries = true;
info.offline_license_expiry_time();
break;
case UsageTableInfo_UsageEntryInfo_UsageEntryStorage_USAGE_INFO:
(*usage_entry_info)[i].storage_type = kStorageTypeUnknown;
*has_usage_info_entries = true;
break;
case UsageTableInfo_UsageEntryInfo_UsageEntryStorage_UNKNOWN:
default:
(*usage_entry_info)[i].storage_type = kStorageTypeUnknown;
break;
} }
usage_entry_info_list->emplace_back(std::move(entry_info));
} }
return true; return true;
} }
@@ -2133,14 +1501,6 @@ std::string DeviceFiles::GetLicenseFileNameExtension() {
return kLicenseFileNameExt; return kLicenseFileNameExt;
} }
std::string DeviceFiles::GetUsageInfoFileName(const std::string& app_id) {
std::string hash;
if (app_id != "") {
hash = GetFileNameSafeHash(app_id);
}
return kUsageInfoFileNamePrefix + hash + kUsageInfoFileNameExt;
}
std::string DeviceFiles::GetOkpInfoFileName() { return kOkpInfoFileName; } std::string DeviceFiles::GetOkpInfoFileName() { return kOkpInfoFileName; }
std::string DeviceFiles::GetFileNameSafeHash(const std::string& input) { std::string DeviceFiles::GetFileNameSafeHash(const std::string& input) {

File diff suppressed because it is too large Load Diff

View File

@@ -95,19 +95,6 @@ const char* CdmOfflineLicenseStateToString(
return UnknownValueRep(license_state); return UnknownValueRep(license_state);
} }
const char* CdmUsageEntryStorageTypeToString(CdmUsageEntryStorageType type) {
switch (type) {
case kStorageLicense:
return "License";
case kStorageUsageInfo:
return "UsageInfo";
case kStorageTypeUnknown:
// Special value used to indicate an empty entry.
return "None";
}
return UnknownValueRep(type);
}
const char* RequestedSecurityLevelToString( const char* RequestedSecurityLevelToString(
RequestedSecurityLevel security_level) { RequestedSecurityLevel security_level) {
switch (security_level) { switch (security_level) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -358,8 +358,7 @@ TEST_F(CryptoMetricsTest, AllCryptoMetrics) {
crypto_metrics.usage_table_header_lru_usage_info_count_.Record(150); crypto_metrics.usage_table_header_lru_usage_info_count_.Record(150);
crypto_metrics.usage_table_header_lru_offline_license_count_.Record(50); crypto_metrics.usage_table_header_lru_offline_license_count_.Record(50);
crypto_metrics.usage_table_header_lru_evicted_entry_staleness_.Record(259200); crypto_metrics.usage_table_header_lru_evicted_entry_staleness_.Record(259200);
crypto_metrics.usage_table_header_lru_evicted_entry_type_.Record( crypto_metrics.usage_table_header_lru_evicted_entry_type_.Record(1);
kStorageUsageInfo);
// Oem crypto metrics. // Oem crypto metrics.
crypto_metrics.oemcrypto_api_version_.Record(123); crypto_metrics.oemcrypto_api_version_.Record(123);
@@ -482,8 +481,7 @@ TEST_F(CryptoMetricsTest, AllCryptoMetrics) {
EXPECT_EQ( EXPECT_EQ(
259200, 259200,
actual.usage_table_header_lru_evicted_entry_staleness_s().int_value()); actual.usage_table_header_lru_evicted_entry_staleness_s().int_value());
EXPECT_EQ(kStorageUsageInfo, EXPECT_EQ(1, actual.usage_table_header_lru_evicted_entry_type().int_value());
actual.usage_table_header_lru_evicted_entry_type().int_value());
// Oem crypto metrics. // Oem crypto metrics.
EXPECT_EQ(123, actual.oemcrypto_api_version().int_value()); EXPECT_EQ(123, actual.oemcrypto_api_version().int_value());