Corrections for big usage table support in L3

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

* Corrects usage_table_header lifetime management. Earlier the
  UsageTableHeader class was a singleton tied to the CdmEngine lifetime.
  With SPOIDs there might be multiple concurrent CdmEngine objects.
  The UsageTableHeader class is now associated with OEMCrypto
  lifetime. There are two UsageTableHeader objects one for each L1 and L3.
  These get allocated/deallocated on OEMCrypto Initialization/Termination
  respectively.
* UsageTableHeader requires OEMCrypto, file read/writes and
  metric gathering to perform its required functionality. Because of the
  lifetime changes, CryptoSession, DeviceFiles and MetricsGroup objects
  need to passed to the methods rather than at Creation time.
* Miscellaneous fixes, when moving or deleteing entries.
* Adds usage_table_header_unittests.
* Addresses failures with request_license_test with secure stop in L3.

b/36858906
b/36855557
b/36048120
b/38341136
b/37100505
b/35946047

Test: Verified by unit and integration tests. Added new
      usage_table_header_unittests

Change-Id: I20e396ab2c0afbd14372dd93b969e5b0f1ccd291
This commit is contained in:
Rahul Frias
2017-05-22 13:33:20 -07:00
parent 45c98e47f2
commit 5da8da58f6
18 changed files with 1937 additions and 214 deletions

View File

@@ -88,6 +88,7 @@ try_adb_push $OUT/vendor/bin/license_unittest
try_adb_push $OUT/vendor/bin/license_keys_unittest try_adb_push $OUT/vendor/bin/license_keys_unittest
try_adb_push $OUT/vendor/bin/initialization_data_unittest try_adb_push $OUT/vendor/bin/initialization_data_unittest
try_adb_push $OUT/vendor/bin/device_files_unittest try_adb_push $OUT/vendor/bin/device_files_unittest
try_adb_push $OUT/vendor/bin/usage_table_header_unittest
try_adb_push $OUT/vendor/bin/service_certificate_unittest try_adb_push $OUT/vendor/bin/service_certificate_unittest
try_adb_push $OUT/vendor/bin/timer_unittest try_adb_push $OUT/vendor/bin/timer_unittest
try_adb_push $OUT/vendor/bin/libwvdrmengine_test try_adb_push $OUT/vendor/bin/libwvdrmengine_test

View File

@@ -82,8 +82,7 @@ class CdmSession {
// ReleaseKey() - Accept response and release key. // ReleaseKey() - Accept response and release key.
virtual CdmResponseType ReleaseKey(const CdmKeyResponse& key_response); virtual CdmResponseType ReleaseKey(const CdmKeyResponse& key_response);
virtual CdmResponseType DeleteUsageEntry( virtual CdmResponseType DeleteUsageEntry(uint32_t usage_entry_number);
const DeviceFiles::CdmUsageData& usage_data);
virtual bool IsKeyLoaded(const KeyId& key_id); virtual bool IsKeyLoaded(const KeyId& key_id);
virtual int64_t GetDurationRemaining(); virtual int64_t GetDurationRemaining();

View File

@@ -17,6 +17,8 @@
namespace wvcdm { namespace wvcdm {
class CryptoKey; class CryptoKey;
class UsageTableHeader;
typedef std::map<CryptoKeyId, CryptoKey*> CryptoKeyMap; typedef std::map<CryptoKeyId, CryptoKey*> CryptoKeyMap;
class CryptoSession { class CryptoSession {
@@ -142,6 +144,9 @@ class CryptoSession {
const std::string& signature); const std::string& signature);
// Usage table header and usage entry related methods // Usage table header and usage entry related methods
virtual UsageTableHeader* GetUsageTableHeader() {
return usage_table_header_;
}
virtual CdmResponseType GetUsageSupportType(CdmUsageSupportType* type); virtual CdmResponseType GetUsageSupportType(CdmUsageSupportType* type);
virtual CdmResponseType CreateUsageTableHeader( virtual CdmResponseType CreateUsageTableHeader(
CdmUsageTableHeader* usage_table_header); CdmUsageTableHeader* usage_table_header);
@@ -217,6 +222,9 @@ class CryptoSession {
bool is_usage_support_type_valid_; bool is_usage_support_type_valid_;
CdmUsageSupportType usage_support_type_; CdmUsageSupportType usage_support_type_;
UsageTableHeader* usage_table_header_;
static UsageTableHeader* usage_table_header_l1_;
static UsageTableHeader* usage_table_header_l3_;
uint64_t request_id_base_; uint64_t request_id_base_;
static uint64_t request_id_index_; static uint64_t request_id_index_;

View File

@@ -21,6 +21,7 @@ namespace wvcdm {
class Clock; class Clock;
class CryptoSession; class CryptoSession;
class PolicyEngine; class PolicyEngine;
class CdmSession;
class CdmLicense { class CdmLicense {
public: public:
@@ -37,7 +38,8 @@ class CdmLicense {
std::string* server_url); std::string* server_url);
virtual CdmResponseType PrepareKeyUpdateRequest( virtual CdmResponseType PrepareKeyUpdateRequest(
bool is_renewal, const CdmAppParameterMap& app_parameters, bool is_renewal, const CdmAppParameterMap& app_parameters,
CdmKeyMessage* signed_request, std::string* server_url); CdmSession* cdm_session, CdmKeyMessage* signed_request,
std::string* server_url);
virtual CdmResponseType HandleKeyResponse( virtual CdmResponseType HandleKeyResponse(
const CdmKeyResponse& license_response); const CdmKeyResponse& license_response);
virtual CdmResponseType HandleKeyUpdateResponse( virtual CdmResponseType HandleKeyUpdateResponse(

View File

@@ -7,36 +7,48 @@
#include <vector> #include <vector>
#include "device_files.h" #include "device_files.h"
#include "file_store.h"
#include "lock.h" #include "lock.h"
#include "metrics_group.h" #include "metrics_group.h"
#include "scoped_ptr.h" #include "scoped_ptr.h"
#include "timer_metric.h"
#include "wv_cdm_types.h" #include "wv_cdm_types.h"
namespace wvcdm { namespace wvcdm {
class FileSystem;
class CryptoSession; class CryptoSession;
// The UsageTableHeader class is a singleton that CDM sessions will share. // Offline licenses/secure stops may be securely tracked using usage
// A separate object will be created for each security level. // tables (OEMCrypto v9-12) or usage table headers+usage entries
// The class synchronizes access to usage table header and associated // (OEMCrypto v13+). This class assists with the latter, synchronizing
// data-structures and controls when they are read in or written out to // access to usage table header and associated data-structures and controlling
// non-secure persistent storage. // when they are read in or written out to non-secure persistent storage.
//
// Each OEMCrypto (for each security level) will maintain its own usage table
// header. Each license will have an associated usage entry that is also
// stored in persistent memory and is noted in the usage table header.
// Usage entry information will be verified when licenses are loaded.
//
// OEMCrypto for each security level have their own usage table
// headers. They are loaded on initialization and written out periodically.
// The lifecycle of this class is tied to when OEMCrypto is
// initialized/terminated.
//
// Sessions and licenses are however handled by CdmSession and so most
// calls to maniplate the usage table header related to usage entries
// are by CdmSession.
//
// 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 |usage_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:
// This methods instantiates or retrieves a usage table header singleton of UsageTableHeader();
// appropriate security level as specified by the |crypto_session| virtual ~UsageTableHeader() {}
// object.
// |crypto_session| is used to create or load a usage master table and // |crypto_session| is used to create or load a usage master table and
// not cached beyound this call. // not cached beyound this call.
static UsageTableHeader* GetInstance(FileSystem* file_system, bool Init(CdmSecurityLevel security_level, CryptoSession* crypto_session);
CryptoSession* crypto_session_);
virtual ~UsageTableHeader() {}
// |persistent_license| false indicates usage info record // |persistent_license| false indicates usage info record
CdmResponseType AddEntry(CryptoSession* crypto_session, CdmResponseType AddEntry(CryptoSession* crypto_session,
@@ -53,54 +65,67 @@ class UsageTableHeader {
// The licenses or usage info records specified by |usage_entry_number| // The licenses or usage info records specified by |usage_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 DeleteEntry and MoveEntry are made. // to DeleteEntry and MoveEntry are made.
CdmResponseType DeleteEntry(uint32_t usage_entry_number); CdmResponseType DeleteEntry(uint32_t usage_entry_number, DeviceFiles* handle,
CdmResponseType MoveEntry(uint32_t from_usage_entry_number, metrics::MetricsGroup* metrics);
const CdmUsageEntry& from_usage_entry,
uint32_t to_usage_entry_number);
private: private:
UsageTableHeader(FileSystem* file_system, CryptoSession* crypto_session, CdmResponseType MoveEntry(uint32_t from /* usage entry number */,
CdmSecurityLevel security_level); const CdmUsageEntry& from_usage_entry,
uint32_t to /* usage entry number */,
DeviceFiles* handle,
metrics::MetricsGroup* metrics);
CdmResponseType GetEntry(uint32_t usage_entry_number, CdmResponseType GetEntry(uint32_t usage_entry_number, DeviceFiles* handle,
CdmUsageEntry* usage_entry); CdmUsageEntry* usage_entry);
CdmResponseType StoreEntry(uint32_t usage_entry_number, CdmResponseType StoreEntry(uint32_t usage_entry_number, DeviceFiles* handle,
const CdmUsageEntry& usage_entry); const CdmUsageEntry& usage_entry);
bool DeleteLastEntry(); CdmResponseType Shrink(metrics::MetricsGroup* metrics,
uint32_t number_of_usage_entries_to_delete);
CdmResponseType UpgradeFromUsageTable(); CdmResponseType UpgradeFromUsageTable(DeviceFiles* handle,
bool UpgradeLicensesFromUsageTable(); metrics::MetricsGroup* metrics);
bool UpgradeUsageInfoFromUsageTable(); bool UpgradeLicensesFromUsageTable(DeviceFiles* handle,
metrics::MetricsGroup* metrics);
bool UpgradeUsageInfoFromUsageTable(DeviceFiles* handle,
metrics::MetricsGroup* metrics);
virtual bool is_inited() { return is_inited_; } virtual bool is_inited() { return is_inited_; }
SecurityLevel GetSecurityLevel() { // This handle and file system is only to be used when accessing
return security_level_ == kSecurityLevelL3 ? kLevel3 : kLevelDefault; // usage_table_header. Usage entries should use the file system provided
} // by CdmSession.
static UsageTableHeader* usage_table_header_l1_;
static UsageTableHeader* usage_table_header_l3_;
scoped_ptr<DeviceFiles> file_handle_; scoped_ptr<DeviceFiles> file_handle_;
scoped_ptr<FileSystem> file_system_;
CdmSecurityLevel security_level_; CdmSecurityLevel security_level_;
SecurityLevel requested_security_level_;
CdmUsageTableHeader usage_table_header_; CdmUsageTableHeader usage_table_header_;
std::vector<CdmUsageEntryInfo> usage_entry_info_; std::vector<CdmUsageEntryInfo> usage_entry_info_;
metrics::MetricsGroup metrics_;
metrics::TimerMetric life_span_;
// Lock to ensure that a single object is created for each security level // Lock to ensure that a single object is created for each security level
// and data member to represent whether an object has been correctly // and data member to represent whether an object has been correctly
// initialized. // initialized.
bool is_inited_; bool is_inited_;
static Lock initialization_lock_;
// Synchonizes access to the Usage Table Header and bookkeeping // Synchonizes access to the Usage Table Header and bookkeeping
// data-structures // data-structures
Lock usage_table_header_lock_; Lock usage_table_header_lock_;
// Test related declarations
friend class UsageTableHeaderTest;
// These setters are for testing only. Takes ownership of the pointers.
void SetDeviceFiles(DeviceFiles* device_files) {
file_handle_.reset(device_files);
}
void SetCryptoSession(CryptoSession* crypto_session) {
test_crypto_session_.reset(crypto_session);
}
// Test related data members
scoped_ptr<CryptoSession> test_crypto_session_;
CORE_DISALLOW_COPY_AND_ASSIGN(UsageTableHeader); CORE_DISALLOW_COPY_AND_ASSIGN(UsageTableHeader);
}; };

View File

@@ -297,6 +297,7 @@ enum CdmResponseType {
INCORRECT_USAGE_SUPPORT_TYPE_2, INCORRECT_USAGE_SUPPORT_TYPE_2,
KEY_PROHIBITED_FOR_SECURITY_LEVEL, /* 255 */ KEY_PROHIBITED_FOR_SECURITY_LEVEL, /* 255 */
KEY_NOT_FOUND_IN_SESSION, KEY_NOT_FOUND_IN_SESSION,
NO_USAGE_ENTRIES,
}; };
enum CdmKeyStatus { enum CdmKeyStatus {
@@ -392,6 +393,12 @@ struct CdmUsageEntryInfo {
CdmUsageEntryStorageType storage_type; CdmUsageEntryStorageType storage_type;
CdmKeySetId key_set_id; CdmKeySetId key_set_id;
std::string usage_info_file_name; std::string usage_info_file_name;
bool operator==(const CdmUsageEntryInfo& other) const {
return storage_type == other.storage_type &&
key_set_id == other.key_set_id &&
(storage_type != kStorageUsageInfo ||
usage_info_file_name == other.usage_info_file_name);
}
}; };
class CdmKeyAllowedUsage { class CdmKeyAllowedUsage {

View File

@@ -1132,7 +1132,8 @@ CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) {
} else { } else {
for (size_t k = 0; k < usage_data.size(); ++k) { for (size_t k = 0; k < usage_data.size(); ++k) {
CdmResponseType status2 = CdmResponseType status2 =
usage_session_->DeleteUsageEntry(usage_data[k]); usage_session_->DeleteUsageEntry(
usage_data[k].usage_entry_number);
if (status == NO_ERROR && status2 != NO_ERROR) if (status == NO_ERROR && status2 != NO_ERROR)
status = status2; status = status2;
} }

View File

@@ -44,15 +44,6 @@ CdmSession::CdmSession(FileSystem* file_system) :
usage_entry_number_(0), usage_entry_number_(0),
mock_license_parser_in_use_(false), mock_license_parser_in_use_(false),
mock_policy_engine_in_use_(false) { mock_policy_engine_in_use_(false) {
CdmResponseType sts =
crypto_session_->GetUsageSupportType(&usage_support_type_);
if (sts != NO_ERROR) {
LOGW("CdmSession::CdmSession: Failed to get usage support type");
}
if (usage_support_type_ == kUsageEntrySupport)
usage_table_header_ = UsageTableHeader::GetInstance(file_system,
crypto_session_.get());
life_span_.Start(); life_span_.Start();
} }
@@ -104,6 +95,13 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
return SESSION_FILE_HANDLE_INIT_ERROR; return SESSION_FILE_HANDLE_INIT_ERROR;
} }
if (crypto_session_->GetUsageSupportType(&usage_support_type_) == NO_ERROR) {
if (usage_support_type_ == kUsageEntrySupport)
usage_table_header_ = crypto_session_->GetUsageTableHeader();
} else {
usage_support_type_ = kNonSecureUsageSupport;
}
// Device Provisioning state is not yet known. // Device Provisioning state is not yet known.
// If not using certificates, then Keybox is client token for license // If not using certificates, then Keybox is client token for license
// requests. // requests.
@@ -447,7 +445,8 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response) {
!provider_session_token.empty()) { !provider_session_token.empty()) {
if (sts != KEY_ADDED) { if (sts != KEY_ADDED) {
CdmResponseType sts = CdmResponseType sts =
usage_table_header_->DeleteEntry(usage_entry_number_); usage_table_header_->DeleteEntry(usage_entry_number_,
file_handle_.get(), &metrics_);
if (sts != NO_ERROR) { if (sts != NO_ERROR) {
LOGW("CdmSession::AddKey: Delete usage entry failed = %d", sts); LOGW("CdmSession::AddKey: Delete usage entry failed = %d", sts);
} }
@@ -589,7 +588,7 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
CdmResponseType CdmSession::GenerateRenewalRequest( CdmResponseType CdmSession::GenerateRenewalRequest(
CdmKeyRequest* key_request) { CdmKeyRequest* key_request) {
CdmResponseType status = license_parser_->PrepareKeyUpdateRequest( CdmResponseType status = license_parser_->PrepareKeyUpdateRequest(
true, app_parameters_, &key_request->message, &key_request->url); true, app_parameters_, NULL, &key_request->message, &key_request->url);
key_request->type = kKeyRequestTypeRenewal; key_request->type = kKeyRequestTypeRenewal;
@@ -619,8 +618,8 @@ CdmResponseType CdmSession::GenerateReleaseRequest(
CdmKeyRequest* key_request) { CdmKeyRequest* key_request) {
is_release_ = true; is_release_ = true;
CdmResponseType status = license_parser_->PrepareKeyUpdateRequest( CdmResponseType status = license_parser_->PrepareKeyUpdateRequest(
false, app_parameters_, &key_request->message, false, app_parameters_, usage_table_header_ == NULL ? NULL : this,
&key_request->url); &key_request->message, &key_request->url);
key_request->type = kKeyRequestTypeRelease; key_request->type = kKeyRequestTypeRelease;
@@ -657,34 +656,50 @@ CdmResponseType CdmSession::ReleaseKey(const CdmKeyResponse& key_response) {
if (is_offline_ || has_provider_session_token()) { if (is_offline_ || has_provider_session_token()) {
DeleteLicense(); DeleteLicense();
// Deletion of usage entry cannot occur while in use by a crypto session.
// So close and reopen after deletion.
if (usage_support_type_ == kUsageEntrySupport) { if (usage_support_type_ == kUsageEntrySupport) {
crypto_session_->Close(); sts = DeleteUsageEntry(usage_entry_number_);
CdmResponseType sts = usage_table_header_->DeleteEntry(usage_entry_number_);
if (sts != NO_ERROR) return sts;
M_TIME(
sts = crypto_session_->Open(requested_security_level_),
&metrics_,
crypto_session_open_,
sts,
requested_security_level_);
if (NO_ERROR != sts) return sts; if (NO_ERROR != sts) return sts;
} }
} }
return NO_ERROR; return NO_ERROR;
} }
CdmResponseType CdmSession::DeleteUsageEntry( CdmResponseType CdmSession::DeleteUsageEntry(uint32_t usage_entry_number) {
const DeviceFiles::CdmUsageData& usage_data) {
if (usage_support_type_ != kUsageEntrySupport) { if (usage_support_type_ != kUsageEntrySupport) {
LOGE("CdmSession::DeleteUsageEntry: Unexpected usage type supported: %d", LOGE("CdmSession::DeleteUsageEntry: Unexpected usage type supported: %d",
usage_support_type_); usage_support_type_);
return INCORRECT_USAGE_SUPPORT_TYPE_1; return INCORRECT_USAGE_SUPPORT_TYPE_1;
} }
return usage_table_header_->DeleteEntry(usage_data.usage_entry_number); // The usage entry cannot be deleted if it has a crypto session handling
// it, so close and reopen session.
CdmResponseType sts;
crypto_session_->Close();
crypto_session_.reset(new CryptoSession(&metrics_));
M_TIME(
sts = crypto_session_->Open(requested_security_level_),
&metrics_,
crypto_session_open_,
sts,
requested_security_level_);
if (sts != NO_ERROR) return sts;
usage_table_header_ = NULL;
if (crypto_session_->GetUsageSupportType(&usage_support_type_) == NO_ERROR) {
if (usage_support_type_ == kUsageEntrySupport)
usage_table_header_ = crypto_session_->GetUsageTableHeader();
} else {
usage_support_type_ = kNonSecureUsageSupport;
}
if (usage_table_header_ == NULL) {
LOGE("CdmSession::DeleteUsageEntry: Usage table header unavailable");
return INCORRECT_USAGE_SUPPORT_TYPE_1;
}
return usage_table_header_->DeleteEntry(usage_entry_number,
file_handle_.get(),
&metrics_);
} }
bool CdmSession::IsKeyLoaded(const KeyId& key_id) { bool CdmSession::IsKeyLoaded(const KeyId& key_id) {

View File

@@ -17,6 +17,7 @@
#include "properties.h" #include "properties.h"
#include "pst_report.h" #include "pst_report.h"
#include "string_conversions.h" #include "string_conversions.h"
#include "usage_table_header.h"
#include "wv_cdm_constants.h" #include "wv_cdm_constants.h"
namespace { namespace {
@@ -41,6 +42,8 @@ Lock CryptoSession::crypto_lock_;
bool CryptoSession::initialized_ = false; bool CryptoSession::initialized_ = false;
int CryptoSession::session_count_ = 0; int CryptoSession::session_count_ = 0;
uint64_t CryptoSession::request_id_index_ = 0; uint64_t CryptoSession::request_id_index_ = 0;
UsageTableHeader* CryptoSession::usage_table_header_l1_ = NULL;
UsageTableHeader* CryptoSession::usage_table_header_l3_ = NULL;
CryptoSession::CryptoSession(metrics::MetricsGroup* metrics) CryptoSession::CryptoSession(metrics::MetricsGroup* metrics)
: metrics_(metrics), : metrics_(metrics),
@@ -50,6 +53,7 @@ CryptoSession::CryptoSession(metrics::MetricsGroup* metrics)
requested_security_level_(kLevelDefault), requested_security_level_(kLevelDefault),
is_usage_support_type_valid_(false), is_usage_support_type_valid_(false),
usage_support_type_(kNonSecureUsageSupport), usage_support_type_(kNonSecureUsageSupport),
usage_table_header_(NULL),
request_id_base_(0), request_id_base_(0),
cipher_mode_(kCipherModeCtr) { cipher_mode_(kCipherModeCtr) {
Init(); Init();
@@ -120,6 +124,16 @@ void CryptoSession::Terminate() {
if (OEMCrypto_SUCCESS != sts) { if (OEMCrypto_SUCCESS != sts) {
LOGE("OEMCrypto_Terminate failed: %d", sts); LOGE("OEMCrypto_Terminate failed: %d", sts);
} }
if (usage_table_header_l1_ != NULL) {
delete usage_table_header_l1_;
usage_table_header_l1_ = NULL;
}
if (usage_table_header_l3_ != NULL) {
delete usage_table_header_l3_;
usage_table_header_l3_ = NULL;
}
initialized_ = false; initialized_ = false;
} }
@@ -210,8 +224,7 @@ bool CryptoSession::GetProvisioningToken(std::string* token) {
} }
CdmSecurityLevel CryptoSession::GetSecurityLevel() { CdmSecurityLevel CryptoSession::GetSecurityLevel() {
LOGV("CryptoSession::GetSecurityLevel: Lock"); LOGV("CryptoSession::GetSecurityLevel");
AutoLock auto_lock(crypto_lock_);
if (!initialized_) { if (!initialized_) {
return kSecurityLevelUninitialized; return kSecurityLevelUninitialized;
} }
@@ -421,7 +434,8 @@ uint8_t CryptoSession::GetSecurityPatchLevel() {
} }
CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) { CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
LOGV("CryptoSession::Open: Lock"); LOGV("CryptoSession::Open: Lock: requested_security_level: %d",
requested_security_level);
AutoLock auto_lock(crypto_lock_); AutoLock auto_lock(crypto_lock_);
if (!initialized_) return UNKNOWN_ERROR; if (!initialized_) return UNKNOWN_ERROR;
if (open_) return NO_ERROR; if (open_) return NO_ERROR;
@@ -461,6 +475,35 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
random_sts, random_sts,
metrics::Pow2Bucket(sizeof(request_id_base_))); metrics::Pow2Bucket(sizeof(request_id_base_)));
++request_id_index_; ++request_id_index_;
CdmUsageSupportType usage_support_type;
if (GetUsageSupportType(&usage_support_type) == NO_ERROR) {
if (usage_support_type == kUsageEntrySupport) {
CdmSecurityLevel security_level = GetSecurityLevel();
if (security_level == kSecurityLevelL1 ||
security_level == kSecurityLevelL3) {
UsageTableHeader* header = security_level == kSecurityLevelL1 ?
usage_table_header_l1_ : usage_table_header_l3_;
if (header == NULL) {
header = new UsageTableHeader();
// Ignore errors since we do not know when a session is opened,
// if it is intended to be used for offline/usage session related
// or otherwise.
if (!header->Init(security_level, this)) {
delete header;
usage_table_header_ = NULL;
return NO_ERROR;
}
if (security_level == kSecurityLevelL1)
usage_table_header_l1_ = header;
else
usage_table_header_l3_ = header;
}
usage_table_header_ = header;
}
}
}
return NO_ERROR; return NO_ERROR;
} }
@@ -1085,9 +1128,7 @@ CdmResponseType CryptoSession::UpdateUsageInformation() {
AutoLock auto_lock(crypto_lock_); AutoLock auto_lock(crypto_lock_);
if (!initialized_) return UNKNOWN_ERROR; if (!initialized_) return UNKNOWN_ERROR;
CdmUsageSupportType usage_support_type; if (usage_table_header_ != NULL) {
if (GetUsageSupportType(&usage_support_type) == NO_ERROR &&
usage_support_type == kUsageEntrySupport) {
LOGV("UpdateUsageInformation: deprecated for OEMCrypto v13+"); LOGV("UpdateUsageInformation: deprecated for OEMCrypto v13+");
return NO_ERROR; return NO_ERROR;
} }
@@ -1248,6 +1289,11 @@ CdmResponseType CryptoSession::ReleaseUsageInformation(
LOGV("ReleaseUsageInformation: id=%ld", (uint32_t)oec_session_id_); LOGV("ReleaseUsageInformation: id=%ld", (uint32_t)oec_session_id_);
{ {
AutoLock auto_lock(crypto_lock_); AutoLock auto_lock(crypto_lock_);
if (usage_table_header_ != NULL) {
LOGW("ReleaseUsageInformation: deprecated for OEMCrypto v13+");
return NO_ERROR;
}
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data()); const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
const uint8_t* sig = reinterpret_cast<const uint8_t*>(signature.data()); const uint8_t* sig = reinterpret_cast<const uint8_t*>(signature.data());
const uint8_t* pst = msg + GetOffset(message, provider_session_token); const uint8_t* pst = msg + GetOffset(message, provider_session_token);

View File

@@ -7,6 +7,7 @@
#include <vector> #include <vector>
#include "clock.h" #include "clock.h"
#include "cdm_session.h"
#include "crypto_key.h" #include "crypto_key.h"
#include "crypto_session.h" #include "crypto_session.h"
#include "device_files.h" #include "device_files.h"
@@ -287,7 +288,8 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
CdmResponseType CdmLicense::PrepareKeyUpdateRequest( CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
bool is_renewal, const CdmAppParameterMap& app_parameters, bool is_renewal, const CdmAppParameterMap& app_parameters,
CdmKeyMessage* signed_request, std::string* server_url) { CdmSession* cdm_session, CdmKeyMessage* signed_request,
std::string* server_url) {
if (!initialized_) { if (!initialized_) {
LOGE("CdmLicense::PrepareKeyUpdateRequest: not initialized"); LOGE("CdmLicense::PrepareKeyUpdateRequest: not initialized");
return LICENSE_PARSER_NOT_INITIALIZED_1; return LICENSE_PARSER_NOT_INITIALIZED_1;
@@ -346,6 +348,12 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
if (NO_ERROR != status) return status; if (NO_ERROR != status) return status;
} }
// TODO(rfrias): Refactor to avoid needing to call CdmSession
if (cdm_session) {
CdmResponseType status = cdm_session->UpdateUsageEntryInformation();
if (NO_ERROR != status) return status;
}
std::string usage_report; std::string usage_report;
CdmResponseType status = crypto_session_->GenerateUsageReport( CdmResponseType status = crypto_session_->GenerateUsageReport(
provider_session_token_, &usage_report, &usage_duration_status, provider_session_token_, &usage_report, &usage_duration_status,

View File

@@ -5,6 +5,7 @@
#include "crypto_session.h" #include "crypto_session.h"
#include "license.h" #include "license.h"
#include "log.h" #include "log.h"
#include "metrics_group.h"
namespace { namespace {
std::string kEmptyString; std::string kEmptyString;
@@ -12,78 +13,66 @@ std::string kEmptyString;
namespace wvcdm { namespace wvcdm {
UsageTableHeader* UsageTableHeader::usage_table_header_l1_ = NULL; UsageTableHeader::UsageTableHeader()
UsageTableHeader* UsageTableHeader::usage_table_header_l3_ = NULL; : security_level_(kSecurityLevelUninitialized),
requested_security_level_(kLevelDefault),
is_inited_(false) {
file_system_.reset(new FileSystem());
file_handle_.reset(new DeviceFiles(file_system_.get()));
}
Lock UsageTableHeader::initialization_lock_; bool UsageTableHeader::Init(CdmSecurityLevel security_level,
UsageTableHeader* UsageTableHeader::GetInstance(FileSystem* file_system,
CryptoSession* crypto_session) { CryptoSession* crypto_session) {
LOGV("UsageTableHeader::GetInstance"); LOGV("UsageTableHeader::Init: security level: %d", security_level);
AutoLock auto_lock(initialization_lock_); if (crypto_session == NULL) {
CdmSecurityLevel security_level = crypto_session->GetSecurityLevel(); LOGE("UsageTableHeader::Init: no crypto session provided");
return false;
}
switch (security_level) { switch (security_level) {
case kSecurityLevelL1: case kSecurityLevelL1:
if (usage_table_header_l1_ != NULL)
return usage_table_header_l1_;
break;
case kSecurityLevelL3: case kSecurityLevelL3:
if (usage_table_header_l3_ != NULL)
return usage_table_header_l3_;
break; break;
default: default:
LOGE("UsageTableHeader::GetInstance: unsupported security level: %d", LOGE("UsageTableHeader::Init: invalid security level provided: %d",
security_level); security_level);
return NULL; return false;
} }
UsageTableHeader* header = security_level_ = security_level;
new UsageTableHeader(file_system, crypto_session, security_level);
if (!header->is_inited()) {
delete header;
return NULL;
}
if (security_level == kSecurityLevelL1) if (!file_handle_->Init(security_level)) {
usage_table_header_l1_ = header; LOGE("UsageTableHeader::Init: device files initialization failed");
else return false;
usage_table_header_l3_ = header;
return header;
} }
UsageTableHeader::UsageTableHeader(FileSystem* file_system,
CryptoSession* crypto_session,
CdmSecurityLevel security_level)
: file_handle_(new DeviceFiles(file_system)),
security_level_(security_level),
is_inited_(false) {
LOGV("UsageTableHeader::UsageTablerHeader: security level: %d",
security_level);
if (!file_handle_->RetrieveUsageTableInfo(&usage_table_header_, if (!file_handle_->RetrieveUsageTableInfo(&usage_table_header_,
&usage_entry_info_)) { &usage_entry_info_)) {
CdmResponseType status = CdmResponseType status =
crypto_session->CreateUsageTableHeader(&usage_table_header_); crypto_session->CreateUsageTableHeader(&usage_table_header_);
if (status != NO_ERROR) return; if (status != NO_ERROR) return false;
file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_);
} else { } else {
CdmResponseType status = CdmResponseType status =
crypto_session->LoadUsageTableHeader(usage_table_header_); crypto_session->LoadUsageTableHeader(usage_table_header_);
if (status != NO_ERROR) { if (status != NO_ERROR) {
LOGE( LOGE(
"UsageTableHeader::UsageTablerHeader: load usage table failed, " "UsageTableHeader::Init: load usage table failed, security level: %d",
"security level: %d",
security_level); security_level);
return; return false;
} }
} }
requested_security_level_ =
security_level_ == kSecurityLevelL3 ? kLevel3 : kLevelDefault;
is_inited_ = true; is_inited_ = true;
return true;
} }
CdmResponseType UsageTableHeader::AddEntry( CdmResponseType UsageTableHeader::AddEntry(
CryptoSession* crypto_session, bool persistent_license, CryptoSession* crypto_session, bool persistent_license,
const CdmKeySetId& key_set_id, const std::string& usage_info_file_name, const CdmKeySetId& key_set_id, const std::string& usage_info_file_name,
uint32_t* usage_entry_number) { uint32_t* usage_entry_number) {
LOGV("UsageTableHeader::AddEntry"); LOGV("UsageTableHeader::AddEntry: Lock");
AutoLock auto_lock(usage_table_header_lock_); AutoLock auto_lock(usage_table_header_lock_);
CdmResponseType status = crypto_session->CreateUsageEntry(usage_entry_number); CdmResponseType status = crypto_session->CreateUsageEntry(usage_entry_number);
@@ -120,14 +109,16 @@ CdmResponseType UsageTableHeader::AddEntry(
return NO_ERROR; return NO_ERROR;
} }
CdmResponseType UsageTableHeader::LoadEntry( CdmResponseType UsageTableHeader::LoadEntry(CryptoSession* crypto_session,
CryptoSession* crypto_session, const CdmUsageEntry& usage_entry, const CdmUsageEntry& usage_entry,
uint32_t usage_entry_number) { uint32_t usage_entry_number) {
LOGV("UsageTableHeader::LoadEntry"); LOGV("UsageTableHeader::LoadEntry: Lock");
AutoLock auto_lock(usage_table_header_lock_); AutoLock auto_lock(usage_table_header_lock_);
if (usage_entry_number >= usage_entry_info_.size()) { if (usage_entry_number >= usage_entry_info_.size()) {
LOGE("UsageTableHeader::LoadEntry: usage entry number %d larger than table size: %d", LOGE(
"UsageTableHeader::LoadEntry: usage entry number %d larger than table "
"size: %d",
usage_entry_number, usage_entry_info_.size()); usage_entry_number, usage_entry_info_.size());
return USAGE_INVALID_LOAD_ENTRY; return USAGE_INVALID_LOAD_ENTRY;
} }
@@ -136,20 +127,21 @@ CdmResponseType UsageTableHeader::LoadEntry(
CdmResponseType UsageTableHeader::UpdateEntry(CryptoSession* crypto_session, CdmResponseType UsageTableHeader::UpdateEntry(CryptoSession* crypto_session,
CdmUsageEntry* usage_entry) { CdmUsageEntry* usage_entry) {
LOGV("UsageTableHeader::UpdateEntry"); LOGV("UsageTableHeader::UpdateEntryL: Lock");
AutoLock auto_lock(usage_table_header_lock_); AutoLock auto_lock(usage_table_header_lock_);
CdmUsageTableHeader usage_table_header;
CdmResponseType status = CdmResponseType status =
crypto_session->UpdateUsageEntry(&usage_table_header_, usage_entry); crypto_session->UpdateUsageEntry(&usage_table_header_, usage_entry);
if (status != NO_ERROR) return status; if (status != NO_ERROR) return status;
file_handle_->StoreUsageTableInfo(usage_table_header, usage_entry_info_); file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_);
return NO_ERROR; return NO_ERROR;
} }
CdmResponseType UsageTableHeader::DeleteEntry(uint32_t usage_entry_number) { CdmResponseType UsageTableHeader::DeleteEntry(uint32_t usage_entry_number,
LOGV("UsageTableHeader::DeleteEntry"); DeviceFiles* handle,
metrics::MetricsGroup* metrics) {
LOGV("UsageTableHeader::DeleteEntry: Lock");
AutoLock auto_lock(usage_table_header_lock_); AutoLock auto_lock(usage_table_header_lock_);
if (usage_entry_number >= usage_entry_info_.size()) if (usage_entry_number >= usage_entry_info_.size())
return USAGE_INVALID_PARAMETERS_1; return USAGE_INVALID_PARAMETERS_1;
@@ -159,12 +151,12 @@ CdmResponseType UsageTableHeader::DeleteEntry(uint32_t usage_entry_number) {
CdmUsageEntry swap_usage_entry; CdmUsageEntry swap_usage_entry;
bool swap_usage_entry_valid = false; bool swap_usage_entry_valid = false;
for (; !swap_usage_entry_valid && swap_entry_number > usage_entry_number; while (!swap_usage_entry_valid && swap_entry_number > usage_entry_number) {
--swap_entry_number) {
switch (usage_entry_info_[swap_entry_number].storage_type) { switch (usage_entry_info_[swap_entry_number].storage_type) {
case kStorageLicense: case kStorageLicense:
case kStorageUsageInfo: { case kStorageUsageInfo: {
CdmResponseType status = GetEntry(swap_entry_number, &swap_usage_entry); CdmResponseType status =
GetEntry(swap_entry_number, handle, &swap_usage_entry);
if (status == NO_ERROR) swap_usage_entry_valid = true; if (status == NO_ERROR) swap_usage_entry_valid = true;
break; break;
} }
@@ -172,37 +164,54 @@ CdmResponseType UsageTableHeader::DeleteEntry(uint32_t usage_entry_number) {
default: default:
break; break;
} }
if (!swap_usage_entry_valid) --swap_entry_number;
} }
uint32_t new_usage_table_size = 0; uint32_t number_of_entries_to_be_deleted =
usage_entry_info_.size() - usage_entry_number;
if (swap_usage_entry_valid) { if (swap_usage_entry_valid) {
MoveEntry(swap_entry_number, swap_usage_entry, usage_entry_number); CdmResponseType status = MoveEntry(swap_entry_number, swap_usage_entry,
new_usage_table_size = swap_entry_number; usage_entry_number, handle, metrics);
// If unable to move entry, unset storage type of entry to be deleted and
// resize |usage_entry_info_| so that swap usage entry is the last entry.
if (status != NO_ERROR) {
usage_entry_info_[usage_entry_number].storage_type = kStorageUnknown;
usage_entry_info_[usage_entry_number].key_set_id.clear();
if (usage_entry_info_.size() - 1 == swap_entry_number) {
file_handle_->StoreUsageTableInfo(usage_table_header_,
usage_entry_info_);
} else { } else {
// No valid usage entries before entry to be deleted Shrink(metrics, usage_entry_info_.size() - swap_entry_number - 1);
new_usage_table_size = usage_entry_number;
} }
usage_entry_info_.resize(new_usage_table_size);
CryptoSession crypto_session(&metrics_);
crypto_session.Open(GetSecurityLevel());
crypto_session.ShrinkUsageTableHeader(new_usage_table_size,
&usage_table_header_);
file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_);
return NO_ERROR; return NO_ERROR;
} }
number_of_entries_to_be_deleted =
usage_entry_info_.size() - swap_entry_number;
}
return Shrink(metrics, number_of_entries_to_be_deleted);
}
CdmResponseType UsageTableHeader::MoveEntry( CdmResponseType UsageTableHeader::MoveEntry(
uint32_t from_usage_entry_number, const CdmUsageEntry& from_usage_entry, uint32_t from_usage_entry_number, const CdmUsageEntry& from_usage_entry,
uint32_t to_usage_entry_number) { uint32_t to_usage_entry_number, DeviceFiles* handle,
metrics::MetricsGroup* metrics) {
LOGV("UsageTableHeader::MoveEntry"); LOGV("UsageTableHeader::MoveEntry");
AutoLock auto_lock(usage_table_header_lock_);
CryptoSession crypto_session(&metrics_); // crypto_session points to an object whose scope is this method or a test
crypto_session.Open(GetSecurityLevel()); // object whose scope is the lifetime of this class
scoped_ptr<CryptoSession> scoped_crypto_session;
CryptoSession* crypto_session = test_crypto_session_.get();
if (crypto_session == NULL) {
scoped_crypto_session.reset((new CryptoSession(metrics)));
crypto_session = scoped_crypto_session.get();
}
crypto_session->Open(requested_security_level_);
CdmResponseType status = CdmResponseType status =
crypto_session.LoadUsageEntry(from_usage_entry_number, from_usage_entry); crypto_session->LoadUsageEntry(from_usage_entry_number, from_usage_entry);
if (status != NO_ERROR) { if (status != NO_ERROR) {
LOGE("UsageTableHeader::MoveEntry: Failed to load usage entry: %d", LOGE("UsageTableHeader::MoveEntry: Failed to load usage entry: %d",
@@ -210,7 +219,7 @@ CdmResponseType UsageTableHeader::MoveEntry(
return status; return status;
} }
status = crypto_session.MoveUsageEntry(to_usage_entry_number); status = crypto_session->MoveUsageEntry(to_usage_entry_number);
if (status != NO_ERROR) { if (status != NO_ERROR) {
LOGE("UsageTableHeader::MoveEntry: Failed to move usage entry: %d->%d", LOGE("UsageTableHeader::MoveEntry: Failed to move usage entry: %d->%d",
@@ -222,7 +231,7 @@ CdmResponseType UsageTableHeader::MoveEntry(
usage_entry_info_[from_usage_entry_number]; usage_entry_info_[from_usage_entry_number];
CdmUsageEntry usage_entry; CdmUsageEntry usage_entry;
status = crypto_session.UpdateUsageEntry(&usage_table_header_, &usage_entry); status = crypto_session->UpdateUsageEntry(&usage_table_header_, &usage_entry);
if (status != NO_ERROR) { if (status != NO_ERROR) {
LOGE("UsageTableHeader::MoveEntry: Failed to update usage entry: %d", LOGE("UsageTableHeader::MoveEntry: Failed to update usage entry: %d",
@@ -232,12 +241,13 @@ CdmResponseType UsageTableHeader::MoveEntry(
file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_); file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_);
StoreEntry(to_usage_entry_number, usage_entry); StoreEntry(to_usage_entry_number, handle, usage_entry);
return NO_ERROR; return NO_ERROR;
} }
CdmResponseType UsageTableHeader::GetEntry(uint32_t usage_entry_number, CdmResponseType UsageTableHeader::GetEntry(uint32_t usage_entry_number,
DeviceFiles* handle,
CdmUsageEntry* usage_entry) { CdmUsageEntry* usage_entry) {
uint32_t entry_number; uint32_t entry_number;
switch (usage_entry_info_[usage_entry_number].storage_type) { switch (usage_entry_info_[usage_entry_number].storage_type) {
@@ -247,7 +257,7 @@ CdmResponseType UsageTableHeader::GetEntry(uint32_t usage_entry_number,
std::string key_renewal_response, release_server_url; std::string key_renewal_response, release_server_url;
int64_t playback_start_time, last_playback_time, grace_period_end_time; int64_t playback_start_time, last_playback_time, grace_period_end_time;
CdmAppParameterMap app_parameters; CdmAppParameterMap app_parameters;
if (!file_handle_->RetrieveLicense( if (!handle->RetrieveLicense(
usage_entry_info_[usage_entry_number].key_set_id, &license_state, usage_entry_info_[usage_entry_number].key_set_id, &license_state,
&init_data, &key_request, &key_response, &key_renewal_request, &init_data, &key_request, &key_response, &key_renewal_request,
&key_renewal_response, &release_server_url, &playback_start_time, &key_renewal_response, &release_server_url, &playback_start_time,
@@ -263,7 +273,7 @@ CdmResponseType UsageTableHeader::GetEntry(uint32_t usage_entry_number,
CdmKeyMessage license_request; CdmKeyMessage license_request;
CdmKeyResponse license_response; CdmKeyResponse license_response;
if (!file_handle_->RetrieveUsageInfoByKeySetId( if (!handle->RetrieveUsageInfoByKeySetId(
usage_entry_info_[usage_entry_number].usage_info_file_name, usage_entry_info_[usage_entry_number].usage_info_file_name,
usage_entry_info_[usage_entry_number].key_set_id, usage_entry_info_[usage_entry_number].key_set_id,
&provider_session_token, &license_request, &license_response, &provider_session_token, &license_request, &license_response,
@@ -293,6 +303,7 @@ CdmResponseType UsageTableHeader::GetEntry(uint32_t usage_entry_number,
} }
CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number, CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number,
DeviceFiles* handle,
const CdmUsageEntry& usage_entry) { const CdmUsageEntry& usage_entry) {
uint32_t entry_number; uint32_t entry_number;
switch (usage_entry_info_[usage_entry_number].storage_type) { switch (usage_entry_info_[usage_entry_number].storage_type) {
@@ -303,7 +314,7 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number,
int64_t playback_start_time, last_playback_time, grace_period_end_time; int64_t playback_start_time, last_playback_time, grace_period_end_time;
CdmAppParameterMap app_parameters; CdmAppParameterMap app_parameters;
CdmUsageEntry entry; CdmUsageEntry entry;
if (!file_handle_->RetrieveLicense( if (!handle->RetrieveLicense(
usage_entry_info_[usage_entry_number].key_set_id, &license_state, usage_entry_info_[usage_entry_number].key_set_id, &license_state,
&init_data, &key_request, &key_response, &key_renewal_request, &init_data, &key_request, &key_response, &key_renewal_request,
&key_renewal_response, &release_server_url, &playback_start_time, &key_renewal_response, &release_server_url, &playback_start_time,
@@ -312,7 +323,7 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number,
LOGE("UsageTableHeader::StoreEntry: Failed to retrieve license"); LOGE("UsageTableHeader::StoreEntry: Failed to retrieve license");
return USAGE_RETRIEVE_LICENSE_FAILED; return USAGE_RETRIEVE_LICENSE_FAILED;
} }
if (!file_handle_->StoreLicense( if (!handle->StoreLicense(
usage_entry_info_[usage_entry_number].key_set_id, license_state, usage_entry_info_[usage_entry_number].key_set_id, license_state,
init_data, key_request, key_response, key_renewal_request, init_data, key_request, key_response, key_renewal_request,
key_renewal_response, release_server_url, playback_start_time, key_renewal_response, release_server_url, playback_start_time,
@@ -327,7 +338,7 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number,
CdmUsageEntry entry; CdmUsageEntry entry;
std::string provider_session_token, init_data, key_request, key_response, std::string provider_session_token, init_data, key_request, key_response,
key_renewal_request; key_renewal_request;
if (!file_handle_->RetrieveUsageInfoByKeySetId( if (!handle->RetrieveUsageInfoByKeySetId(
usage_entry_info_[usage_entry_number].usage_info_file_name, usage_entry_info_[usage_entry_number].usage_info_file_name,
usage_entry_info_[usage_entry_number].key_set_id, usage_entry_info_[usage_entry_number].key_set_id,
&provider_session_token, &key_request, &key_response, &entry, &provider_session_token, &key_request, &key_response, &entry,
@@ -337,10 +348,10 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number,
"information"); "information");
return USAGE_RETRIEVE_USAGE_INFO_FAILED; return USAGE_RETRIEVE_USAGE_INFO_FAILED;
} }
file_handle_->DeleteUsageInfo( handle->DeleteUsageInfo(
usage_entry_info_[usage_entry_number].usage_info_file_name, usage_entry_info_[usage_entry_number].usage_info_file_name,
provider_session_token); provider_session_token);
if (!file_handle_->StoreUsageInfo( if (!handle->StoreUsageInfo(
provider_session_token, key_request, key_response, provider_session_token, key_request, key_response,
usage_entry_info_[usage_entry_number].usage_info_file_name, usage_entry_info_[usage_entry_number].usage_info_file_name,
usage_entry_info_[usage_entry_number].key_set_id, usage_entry, usage_entry_info_[usage_entry_number].key_set_id, usage_entry,
@@ -361,41 +372,56 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number,
return NO_ERROR; return NO_ERROR;
} }
bool UsageTableHeader::DeleteLastEntry() { CdmResponseType UsageTableHeader::Shrink(
metrics::MetricsGroup* metrics,
uint32_t number_of_usage_entries_to_delete) {
if (usage_entry_info_.empty()) { if (usage_entry_info_.empty()) {
LOGE("UsageTableHeader::Shrink: usage entry info table unexpectedly empty");
return NO_USAGE_ENTRIES;
}
if (usage_entry_info_.size() < number_of_usage_entries_to_delete) {
LOGW( LOGW(
"UsageTableHeader::DeleteLastEntry: usage entry info table " "UsageTableHeader::Shrink: cannot delete %d entries when usage entry "
"unexpectedly empty"); "table size is %d", number_of_usage_entries_to_delete,
return false; usage_entry_info_.size());
}
usage_entry_info_.resize(usage_entry_info_.size() - 1);
CryptoSession crypto_session(&metrics_);
crypto_session.Open(GetSecurityLevel());
crypto_session.ShrinkUsageTableHeader(usage_entry_info_.size(),
&usage_table_header_);
file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_);
return true;
}
CdmResponseType UsageTableHeader::UpgradeFromUsageTable() {
CryptoSession crypto_session(&metrics_);
CdmResponseType status = crypto_session.Open(GetSecurityLevel());
if (status != NO_ERROR) return status;
status = crypto_session.CreateUsageTableHeader(&usage_table_header_);
if (status != NO_ERROR) return status;
crypto_session.Close();
UpgradeLicensesFromUsageTable();
UpgradeUsageInfoFromUsageTable();
return NO_ERROR; return NO_ERROR;
} }
bool UsageTableHeader::UpgradeLicensesFromUsageTable() { if (number_of_usage_entries_to_delete == 0) return NO_ERROR;
usage_entry_info_.resize(usage_entry_info_.size() -
number_of_usage_entries_to_delete);
// crypto_session points to an object whose scope is this method or a test
// object whose scope is the lifetime of this class
scoped_ptr<CryptoSession> scoped_crypto_session;
CryptoSession* crypto_session = test_crypto_session_.get();
if (crypto_session == NULL) {
scoped_crypto_session.reset((new CryptoSession(metrics)));
crypto_session = scoped_crypto_session.get();
}
CdmResponseType status = crypto_session->Open(requested_security_level_);
if (status != NO_ERROR) return status;
status = crypto_session->ShrinkUsageTableHeader(usage_entry_info_.size(),
&usage_table_header_);
if (status != NO_ERROR) return status;
file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_);
return NO_ERROR;
}
CdmResponseType UsageTableHeader::UpgradeFromUsageTable(
DeviceFiles* handle, metrics::MetricsGroup* metrics) {
UpgradeLicensesFromUsageTable(handle, metrics);
UpgradeUsageInfoFromUsageTable(handle, metrics);
return NO_ERROR;
}
bool UsageTableHeader::UpgradeLicensesFromUsageTable(
DeviceFiles* handle, metrics::MetricsGroup* metrics) {
// Fetch the key set IDs for each offline license. For each license // Fetch the key set IDs for each offline license. For each license
// * retrieve the provider session token, // * retrieve the provider session token,
// * create a new usage entry // * create a new usage entry
@@ -404,7 +430,7 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable() {
// * save the usage table header and store the usage entry number and // * save the usage table header and store the usage entry number and
// usage entry along with the license to persistent memory // usage entry along with the license to persistent memory
std::vector<std::string> key_set_ids; std::vector<std::string> key_set_ids;
if (file_handle_->ListLicenses(&key_set_ids)) { if (handle->ListLicenses(&key_set_ids)) {
LOGW( LOGW(
"UpgradeUsageTableHeader::UpgradeLicensesFromUsageTable: unable to " "UpgradeUsageTableHeader::UpgradeLicensesFromUsageTable: unable to "
"retrieve list of licenses"); "retrieve list of licenses");
@@ -419,7 +445,7 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable() {
CdmAppParameterMap app_parameters; CdmAppParameterMap app_parameters;
CdmUsageEntry usage_entry; CdmUsageEntry usage_entry;
uint32_t usage_entry_number; uint32_t usage_entry_number;
if (!file_handle_->RetrieveLicense( if (!handle->RetrieveLicense(
key_set_ids[i], &license_state, &init_data, &key_request, key_set_ids[i], &license_state, &init_data, &key_request,
&key_response, &key_renewal_request, &key_renewal_response, &key_response, &key_renewal_request, &key_renewal_response,
&release_server_url, &playback_start_time, &last_playback_time, &release_server_url, &playback_start_time, &last_playback_time,
@@ -442,8 +468,8 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable() {
if (provider_session_token.empty()) continue; if (provider_session_token.empty()) continue;
CryptoSession crypto_session(&metrics_); CryptoSession crypto_session(metrics);
CdmResponseType status = crypto_session.Open(GetSecurityLevel()); CdmResponseType status = crypto_session.Open(requested_security_level_);
if (status != NO_ERROR) continue; if (status != NO_ERROR) continue;
@@ -456,7 +482,7 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable() {
if (status != NO_ERROR) { if (status != NO_ERROR) {
crypto_session.Close(); crypto_session.Close();
DeleteLastEntry(); Shrink(metrics, 1);
continue; continue;
} }
@@ -464,16 +490,18 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable() {
if (status != NO_ERROR) { if (status != NO_ERROR) {
crypto_session.Close(); crypto_session.Close();
DeleteLastEntry(); Shrink(metrics, 1);
continue; continue;
} }
if (!file_handle_->StoreLicense( if (!handle->StoreLicense(
key_set_ids[i], license_state, init_data, key_request, key_response, key_set_ids[i], license_state, init_data, key_request, key_response,
key_renewal_request, key_renewal_response, release_server_url, key_renewal_request, key_renewal_response, release_server_url,
playback_start_time, last_playback_time, grace_period_end_time, playback_start_time, last_playback_time, grace_period_end_time,
app_parameters, usage_entry, usage_entry_number)) { app_parameters, usage_entry, usage_entry_number)) {
LOGE("UsageTableHeader::StoreEntry: Failed to store license"); LOGE(
"UsageTableHeader::UpgradeLicensesFromUsageTable: Failed to store "
"license");
continue; continue;
} }
} }
@@ -481,7 +509,8 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable() {
return NO_ERROR; return NO_ERROR;
} }
bool UsageTableHeader::UpgradeUsageInfoFromUsageTable() { bool UsageTableHeader::UpgradeUsageInfoFromUsageTable(
DeviceFiles* handle, metrics::MetricsGroup* metrics) {
// Fetch all usage files. For each file retrieve all the usage info records // Fetch all usage files. For each file retrieve all the usage info records
// within the file. For each piece of usage information // within the file. For each piece of usage information
// * create a new usage entry // * create a new usage entry
@@ -492,7 +521,7 @@ bool UsageTableHeader::UpgradeUsageInfoFromUsageTable() {
// information to persistent memory along with usage entry number and usage // information to persistent memory along with usage entry number and usage
// entry. // entry.
std::vector<std::string> usage_info_file_names; std::vector<std::string> usage_info_file_names;
if (file_handle_->ListUsageInfoFiles(&usage_info_file_names)) { if (handle->ListUsageInfoFiles(&usage_info_file_names)) {
LOGW( LOGW(
"UpgradeUsageTableHeader::UpgradeUsageInfoFromUsageTable: Unable to " "UpgradeUsageTableHeader::UpgradeUsageInfoFromUsageTable: Unable to "
"retrieve list of usage info file names"); "retrieve list of usage info file names");
@@ -501,8 +530,7 @@ bool UsageTableHeader::UpgradeUsageInfoFromUsageTable() {
for (size_t i = 0; i < usage_info_file_names.size(); ++i) { for (size_t i = 0; i < usage_info_file_names.size(); ++i) {
std::vector<DeviceFiles::CdmUsageData> usage_data; std::vector<DeviceFiles::CdmUsageData> usage_data;
if (!file_handle_->RetrieveUsageInfo(usage_info_file_names[i], if (!handle->RetrieveUsageInfo(usage_info_file_names[i], &usage_data)) {
&usage_data)) {
LOGW( LOGW(
"UsageTableHeader::UpgradeUsageInfoFromUsageTable: Failed to " "UsageTableHeader::UpgradeUsageInfoFromUsageTable: Failed to "
"retrieve usage records from %s", "retrieve usage records from %s",
@@ -518,8 +546,8 @@ bool UsageTableHeader::UpgradeUsageInfoFromUsageTable() {
continue; continue;
} }
CryptoSession crypto_session(&metrics_); CryptoSession crypto_session(metrics);
CdmResponseType status = crypto_session.Open(GetSecurityLevel()); CdmResponseType status = crypto_session.Open(requested_security_level_);
if (status != NO_ERROR) continue; if (status != NO_ERROR) continue;
@@ -536,7 +564,7 @@ bool UsageTableHeader::UpgradeUsageInfoFromUsageTable() {
if (status != NO_ERROR) { if (status != NO_ERROR) {
crypto_session.Close(); crypto_session.Close();
DeleteLastEntry(); Shrink(metrics, 1);
continue; continue;
} }
@@ -544,12 +572,12 @@ bool UsageTableHeader::UpgradeUsageInfoFromUsageTable() {
if (status != NO_ERROR) { if (status != NO_ERROR) {
crypto_session.Close(); crypto_session.Close();
DeleteLastEntry(); Shrink(metrics, 1);
continue; continue;
} }
} }
if (!file_handle_->StoreUsageInfo(usage_info_file_names[i], usage_data)) { if (!handle->StoreUsageInfo(usage_info_file_names[i], usage_data)) {
LOGE( LOGE(
"UsageTableHeader::StoreUsageInfo: Failed to store usage records to " "UsageTableHeader::StoreUsageInfo: Failed to store usage records to "
"%s", "%s",

View File

@@ -574,6 +574,9 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
case KEY_NOT_FOUND_IN_SESSION: case KEY_NOT_FOUND_IN_SESSION:
*os << "KEY_NOT_FOUND_IN_SESSION"; *os << "KEY_NOT_FOUND_IN_SESSION";
break; break;
case NO_USAGE_ENTRIES:
*os << "NO_USAGE_ENTRIES";
break;
default: default:
*os << "Unknown CdmResponseType"; *os << "Unknown CdmResponseType";

File diff suppressed because it is too large Load Diff

View File

@@ -71,6 +71,10 @@ test_name := timer_unittest
test_src_dir := . test_src_dir := .
include $(LOCAL_PATH)/unit-test.mk include $(LOCAL_PATH)/unit-test.mk
test_name := usage_table_header_unittest
test_src_dir := ../core/test
include $(LOCAL_PATH)/unit-test.mk
test_name := distribution_test test_name := distribution_test
test_src_dir := ../metrics/test test_src_dir := ../metrics/test
include $(LOCAL_PATH)/unit-test.mk include $(LOCAL_PATH)/unit-test.mk

View File

@@ -2617,6 +2617,11 @@ TEST_P(WvCdmUsageInfoTest, UsageInfo) {
key_id.append(1, ch); key_id.append(1, ch);
GenerateKeyRequest(key_id, kLicenseTypeStreaming, property_set); GenerateKeyRequest(key_id, kLicenseTypeStreaming, property_set);
// TODO(rfrias): streaming_clip6 is a streaming license without a pst
if (ch == '6')
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
else
VerifyUsageKeyRequestResponse(g_license_server, g_client_auth); VerifyUsageKeyRequestResponse(g_license_server, g_client_auth);
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size()); std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
@@ -2693,6 +2698,10 @@ TEST_F(WvCdmRequestLicenseTest, UsageReleaseAllTest) {
key_id.append(1, ch); key_id.append(1, ch);
GenerateKeyRequest(key_id, kLicenseTypeStreaming, &property_set); GenerateKeyRequest(key_id, kLicenseTypeStreaming, &property_set);
// TODO(rfrias): streaming_clip6 is a streaming license without a pst
if (ch == '6')
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
else
VerifyUsageKeyRequestResponse(g_license_server, g_client_auth); VerifyUsageKeyRequestResponse(g_license_server, g_client_auth);
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size()); std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());

View File

@@ -259,10 +259,11 @@ enum {
kReleaseUsageInfoFailed = ERROR_DRM_VENDOR_MIN + 246, kReleaseUsageInfoFailed = ERROR_DRM_VENDOR_MIN + 246,
kIncorrectUsageSupportType1 = ERROR_DRM_VENDOR_MIN + 247, kIncorrectUsageSupportType1 = ERROR_DRM_VENDOR_MIN + 247,
kIncorrectUsageSupportType2 = ERROR_DRM_VENDOR_MIN + 248, kIncorrectUsageSupportType2 = ERROR_DRM_VENDOR_MIN + 248,
kNoUsageEntries = ERROR_DRM_VENDOR_MIN + 249,
// This should always follow the last error code. // This should always follow the last error code.
// The offset value should be updated each time a new error code is added. // The offset value should be updated each time a new error code is added.
kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 248, kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 249,
// Used by crypto test mode // Used by crypto test mode
kErrorTestMode = ERROR_DRM_VENDOR_MAX, kErrorTestMode = ERROR_DRM_VENDOR_MAX,

View File

@@ -503,6 +503,8 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) {
return kIncorrectUsageSupportType1; return kIncorrectUsageSupportType1;
case wvcdm::INCORRECT_USAGE_SUPPORT_TYPE_2: case wvcdm::INCORRECT_USAGE_SUPPORT_TYPE_2:
return kIncorrectUsageSupportType2; return kIncorrectUsageSupportType2;
case wvcdm::NO_USAGE_ENTRIES:
return kNoUsageEntries;
case wvcdm::UNUSED_1: case wvcdm::UNUSED_1:
case wvcdm::UNUSED_2: case wvcdm::UNUSED_2:

View File

@@ -82,6 +82,7 @@ adb_shell_run license_unittest
adb_shell_run license_keys_unittest adb_shell_run license_keys_unittest
adb_shell_run initialization_data_unittest adb_shell_run initialization_data_unittest
adb_shell_run device_files_unittest adb_shell_run device_files_unittest
adb_shell_run usage_table_header_unittest
adb_shell_run service_certificate_unittest adb_shell_run service_certificate_unittest
adb_shell_run timer_unittest adb_shell_run timer_unittest
adb_shell_run buffer_reader_test adb_shell_run buffer_reader_test