Merge "Corrections for big usage table support in L3" into oc-dev

am: 9edaf2ab39

Change-Id: I4651713271f53d0aca77d8ecaaae57f3ab855471
This commit is contained in:
Rahul Frias
2017-05-31 21:31:03 +00:00
committed by android-build-merger
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/initialization_data_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/timer_unittest
try_adb_push $OUT/vendor/bin/libwvdrmengine_test

View File

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

View File

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

View File

@@ -21,6 +21,7 @@ namespace wvcdm {
class Clock;
class CryptoSession;
class PolicyEngine;
class CdmSession;
class CdmLicense {
public:
@@ -37,7 +38,8 @@ class CdmLicense {
std::string* server_url);
virtual CdmResponseType PrepareKeyUpdateRequest(
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(
const CdmKeyResponse& license_response);
virtual CdmResponseType HandleKeyUpdateResponse(

View File

@@ -7,36 +7,48 @@
#include <vector>
#include "device_files.h"
#include "file_store.h"
#include "lock.h"
#include "metrics_group.h"
#include "scoped_ptr.h"
#include "timer_metric.h"
#include "wv_cdm_types.h"
namespace wvcdm {
class FileSystem;
class CryptoSession;
// The UsageTableHeader class is a singleton that CDM sessions will share.
// A separate object will be created for each security level.
// The class synchronizes access to usage table header and associated
// data-structures and controls when they are read in or written out to
// non-secure persistent storage.
// Offline licenses/secure stops may be securely tracked using usage
// tables (OEMCrypto v9-12) or usage table headers+usage entries
// (OEMCrypto v13+). This class assists with the latter, synchronizing
// access to usage table header and associated data-structures and controlling
// 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
// 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
// and usage info records by the caller.
class UsageTableHeader {
public:
// This methods instantiates or retrieves a usage table header singleton of
// appropriate security level as specified by the |crypto_session|
// object.
UsageTableHeader();
virtual ~UsageTableHeader() {}
// |crypto_session| is used to create or load a usage master table and
// not cached beyound this call.
static UsageTableHeader* GetInstance(FileSystem* file_system,
CryptoSession* crypto_session_);
virtual ~UsageTableHeader() {}
bool Init(CdmSecurityLevel security_level, CryptoSession* crypto_session);
// |persistent_license| false indicates usage info record
CdmResponseType AddEntry(CryptoSession* crypto_session,
@@ -53,54 +65,67 @@ class UsageTableHeader {
// The licenses or usage info records specified by |usage_entry_number|
// should not be in use by any open CryptoSession objects when calls
// to DeleteEntry and MoveEntry are made.
CdmResponseType DeleteEntry(uint32_t usage_entry_number);
CdmResponseType MoveEntry(uint32_t from_usage_entry_number,
const CdmUsageEntry& from_usage_entry,
uint32_t to_usage_entry_number);
CdmResponseType DeleteEntry(uint32_t usage_entry_number, DeviceFiles* handle,
metrics::MetricsGroup* metrics);
private:
UsageTableHeader(FileSystem* file_system, CryptoSession* crypto_session,
CdmSecurityLevel security_level);
CdmResponseType MoveEntry(uint32_t from /* usage entry number */,
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);
CdmResponseType StoreEntry(uint32_t usage_entry_number,
CdmResponseType StoreEntry(uint32_t usage_entry_number, DeviceFiles* handle,
const CdmUsageEntry& usage_entry);
bool DeleteLastEntry();
CdmResponseType Shrink(metrics::MetricsGroup* metrics,
uint32_t number_of_usage_entries_to_delete);
CdmResponseType UpgradeFromUsageTable();
bool UpgradeLicensesFromUsageTable();
bool UpgradeUsageInfoFromUsageTable();
CdmResponseType UpgradeFromUsageTable(DeviceFiles* handle,
metrics::MetricsGroup* metrics);
bool UpgradeLicensesFromUsageTable(DeviceFiles* handle,
metrics::MetricsGroup* metrics);
bool UpgradeUsageInfoFromUsageTable(DeviceFiles* handle,
metrics::MetricsGroup* metrics);
virtual bool is_inited() { return is_inited_; }
SecurityLevel GetSecurityLevel() {
return security_level_ == kSecurityLevelL3 ? kLevel3 : kLevelDefault;
}
static UsageTableHeader* usage_table_header_l1_;
static UsageTableHeader* usage_table_header_l3_;
// This handle and file system is only to be used when accessing
// usage_table_header. Usage entries should use the file system provided
// by CdmSession.
scoped_ptr<DeviceFiles> file_handle_;
scoped_ptr<FileSystem> file_system_;
CdmSecurityLevel security_level_;
SecurityLevel requested_security_level_;
CdmUsageTableHeader usage_table_header_;
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
// and data member to represent whether an object has been correctly
// initialized.
bool is_inited_;
static Lock initialization_lock_;
// Synchonizes access to the Usage Table Header and bookkeeping
// data-structures
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);
};

View File

@@ -297,6 +297,7 @@ enum CdmResponseType {
INCORRECT_USAGE_SUPPORT_TYPE_2,
KEY_PROHIBITED_FOR_SECURITY_LEVEL, /* 255 */
KEY_NOT_FOUND_IN_SESSION,
NO_USAGE_ENTRIES,
};
enum CdmKeyStatus {
@@ -392,6 +393,12 @@ struct CdmUsageEntryInfo {
CdmUsageEntryStorageType storage_type;
CdmKeySetId key_set_id;
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 {

View File

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

View File

@@ -44,15 +44,6 @@ CdmSession::CdmSession(FileSystem* file_system) :
usage_entry_number_(0),
mock_license_parser_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();
}
@@ -104,6 +95,13 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
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.
// If not using certificates, then Keybox is client token for license
// requests.
@@ -447,7 +445,8 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response) {
!provider_session_token.empty()) {
if (sts != KEY_ADDED) {
CdmResponseType sts =
usage_table_header_->DeleteEntry(usage_entry_number_);
usage_table_header_->DeleteEntry(usage_entry_number_,
file_handle_.get(), &metrics_);
if (sts != NO_ERROR) {
LOGW("CdmSession::AddKey: Delete usage entry failed = %d", sts);
}
@@ -589,7 +588,7 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
CdmResponseType CdmSession::GenerateRenewalRequest(
CdmKeyRequest* key_request) {
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;
@@ -619,8 +618,8 @@ CdmResponseType CdmSession::GenerateReleaseRequest(
CdmKeyRequest* key_request) {
is_release_ = true;
CdmResponseType status = license_parser_->PrepareKeyUpdateRequest(
false, app_parameters_, &key_request->message,
&key_request->url);
false, app_parameters_, usage_table_header_ == NULL ? NULL : this,
&key_request->message, &key_request->url);
key_request->type = kKeyRequestTypeRelease;
@@ -657,34 +656,50 @@ CdmResponseType CdmSession::ReleaseKey(const CdmKeyResponse& key_response) {
if (is_offline_ || has_provider_session_token()) {
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) {
crypto_session_->Close();
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_);
sts = DeleteUsageEntry(usage_entry_number_);
if (NO_ERROR != sts) return sts;
}
}
return NO_ERROR;
}
CdmResponseType CdmSession::DeleteUsageEntry(
const DeviceFiles::CdmUsageData& usage_data) {
CdmResponseType CdmSession::DeleteUsageEntry(uint32_t usage_entry_number) {
if (usage_support_type_ != kUsageEntrySupport) {
LOGE("CdmSession::DeleteUsageEntry: Unexpected usage type supported: %d",
usage_support_type_);
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) {

View File

@@ -17,6 +17,7 @@
#include "properties.h"
#include "pst_report.h"
#include "string_conversions.h"
#include "usage_table_header.h"
#include "wv_cdm_constants.h"
namespace {
@@ -41,6 +42,8 @@ Lock CryptoSession::crypto_lock_;
bool CryptoSession::initialized_ = false;
int CryptoSession::session_count_ = 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)
: metrics_(metrics),
@@ -50,6 +53,7 @@ CryptoSession::CryptoSession(metrics::MetricsGroup* metrics)
requested_security_level_(kLevelDefault),
is_usage_support_type_valid_(false),
usage_support_type_(kNonSecureUsageSupport),
usage_table_header_(NULL),
request_id_base_(0),
cipher_mode_(kCipherModeCtr) {
Init();
@@ -120,6 +124,16 @@ void CryptoSession::Terminate() {
if (OEMCrypto_SUCCESS != 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;
}
@@ -210,8 +224,7 @@ bool CryptoSession::GetProvisioningToken(std::string* token) {
}
CdmSecurityLevel CryptoSession::GetSecurityLevel() {
LOGV("CryptoSession::GetSecurityLevel: Lock");
AutoLock auto_lock(crypto_lock_);
LOGV("CryptoSession::GetSecurityLevel");
if (!initialized_) {
return kSecurityLevelUninitialized;
}
@@ -421,7 +434,8 @@ uint8_t CryptoSession::GetSecurityPatchLevel() {
}
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_);
if (!initialized_) return UNKNOWN_ERROR;
if (open_) return NO_ERROR;
@@ -461,6 +475,35 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
random_sts,
metrics::Pow2Bucket(sizeof(request_id_base_)));
++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;
}
@@ -1085,9 +1128,7 @@ CdmResponseType CryptoSession::UpdateUsageInformation() {
AutoLock auto_lock(crypto_lock_);
if (!initialized_) return UNKNOWN_ERROR;
CdmUsageSupportType usage_support_type;
if (GetUsageSupportType(&usage_support_type) == NO_ERROR &&
usage_support_type == kUsageEntrySupport) {
if (usage_table_header_ != NULL) {
LOGV("UpdateUsageInformation: deprecated for OEMCrypto v13+");
return NO_ERROR;
}
@@ -1248,6 +1289,11 @@ CdmResponseType CryptoSession::ReleaseUsageInformation(
LOGV("ReleaseUsageInformation: id=%ld", (uint32_t)oec_session_id_);
{
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* sig = reinterpret_cast<const uint8_t*>(signature.data());
const uint8_t* pst = msg + GetOffset(message, provider_session_token);

View File

@@ -7,6 +7,7 @@
#include <vector>
#include "clock.h"
#include "cdm_session.h"
#include "crypto_key.h"
#include "crypto_session.h"
#include "device_files.h"
@@ -287,7 +288,8 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
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_) {
LOGE("CdmLicense::PrepareKeyUpdateRequest: not initialized");
return LICENSE_PARSER_NOT_INITIALIZED_1;
@@ -346,6 +348,12 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
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;
CdmResponseType status = crypto_session_->GenerateUsageReport(
provider_session_token_, &usage_report, &usage_duration_status,

View File

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

View File

@@ -574,6 +574,9 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
case KEY_NOT_FOUND_IN_SESSION:
*os << "KEY_NOT_FOUND_IN_SESSION";
break;
case NO_USAGE_ENTRIES:
*os << "NO_USAGE_ENTRIES";
break;
default:
*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 := .
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_src_dir := ../metrics/test
include $(LOCAL_PATH)/unit-test.mk

View File

@@ -2617,7 +2617,12 @@ TEST_P(WvCdmUsageInfoTest, UsageInfo) {
key_id.append(1, ch);
GenerateKeyRequest(key_id, kLicenseTypeStreaming, property_set);
VerifyUsageKeyRequestResponse(g_license_server, g_client_auth);
// 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);
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
CdmDecryptionParameters decryption_parameters(
@@ -2693,7 +2698,11 @@ TEST_F(WvCdmRequestLicenseTest, UsageReleaseAllTest) {
key_id.append(1, ch);
GenerateKeyRequest(key_id, kLicenseTypeStreaming, &property_set);
VerifyUsageKeyRequestResponse(g_license_server, g_client_auth);
// 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);
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
CdmDecryptionParameters decryption_parameters(

View File

@@ -259,10 +259,11 @@ enum {
kReleaseUsageInfoFailed = ERROR_DRM_VENDOR_MIN + 246,
kIncorrectUsageSupportType1 = ERROR_DRM_VENDOR_MIN + 247,
kIncorrectUsageSupportType2 = ERROR_DRM_VENDOR_MIN + 248,
kNoUsageEntries = ERROR_DRM_VENDOR_MIN + 249,
// This should always follow the last error code.
// 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
kErrorTestMode = ERROR_DRM_VENDOR_MAX,

View File

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

View File

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