Merges to android Pi release (part 5)

These are a set of CLs merged from the wv cdm repo to the android repo.

* Change build options for make protobuf host tools

  Author: Gene Morgan <gmorgan@google.com>

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

  Also revert local change to protobuf/extension_set.cc
  This builds after adding -Wno-return-type and -Wno-unused flags.

* OEMCrypto v13 stub

  Author: Rintaro Kuroiwa <rkuroiwa@google.com>

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

* Remove merge conflict tags

  Author: Edwin Wong <edwinwong@google.com>

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

  Remove merge conflict tags for http://go/wvgerrit/29880

* Added Android Things ARM provisioning key to L3

  Author: Srujan Gaddam <srujzs@google.com>

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

  BUG: 63443584

BUG: 71650075
Test: Not currently passing. Will be addressed in a subsequent
      commit in the chain.

Change-Id: Ifd867b491dfda5d67d2e225695535b5af9e18260
This commit is contained in:
Rahul Frias
2018-01-09 18:03:56 -08:00
parent 169d0b6cb6
commit b7c9ad57c9
24 changed files with 1852 additions and 1129 deletions

View File

@@ -43,9 +43,6 @@ LOCAL_SHARED_LIBRARIES := \
libwvhidl \
libbinder \
LOCAL_HEADER_LIBRARIES := \
libstagefright_foundation_headers
LOCAL_MODULE := android.hardware.drm@1.0-service.widevine
LOCAL_INIT_RC := src_hidl/android.hardware.drm@1.0-service.widevine.rc
LOCAL_REQUIRED_MODULES := move_widevine_data.sh
@@ -66,21 +63,14 @@ include $(CLEAR_VARS)
LOCAL_MODULE := libcdm_utils
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
LOCAL_PROPRIETARY_MODULE := true
LOCAL_STATIC_LIBRARIES := libcrypto
LOCAL_STATIC_LIBRARIES := libcrypto_static
LOCAL_C_INCLUDES := \
vendor/widevine/libwvdrmengine/cdm/core/include \
vendor/widevine/libwvdrmengine/cdm/include \
vendor/widevine/libwvdrmengine/oemcrypto/include \
LOCAL_HEADER_LIBRARIES := \
libutils_headers \
LOCAL_SHARED_LIBRARIES := \
liblog
SRC_DIR := cdm/src
CORE_SRC_DIR := cdm/core/src
LOCAL_SRC_FILES := \
@@ -104,10 +94,8 @@ include $(CLEAR_VARS)
LOCAL_MODULE := libcdm_protos
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
LOCAL_PROPRIETARY_MODULE := true
CORE_PROTO_SRC_FILES := $(call all-proto-files-under, cdm/core/src)
LOCAL_SRC_FILES := $(CORE_PROTO_SRC_FILES) $(METRICS_PROTO_SRC_FILES)
LOCAL_SRC_FILES := $(call all-proto-files-under, cdm/core/src)
generated_sources_dir := $(call local-generated-sources-dir)
@@ -170,7 +158,7 @@ LOCAL_STATIC_LIBRARIES := \
libcdm \
libcdm_protos \
libcdm_utils \
libcrypto \
libcrypto_static \
libjsmn \
libwvdrmcryptoplugin \
libwvdrmdrmplugin \
@@ -184,10 +172,6 @@ LOCAL_SHARED_LIBRARIES := \
libstagefright_foundation \
libutils \
LOCAL_HEADER_LIBRARIES := \
libutils_headers \
libstagefright_headers
LOCAL_MODULE := libwvdrmengine
LOCAL_MODULE_RELATIVE_PATH := mediadrm
@@ -230,7 +214,7 @@ LOCAL_STATIC_LIBRARIES := \
libcdm \
libcdm_protos \
libcdm_utils \
libcrypto \
libcrypto_static \
libjsmn \
libwvdrmcryptoplugin_hidl \
libwvdrmdrmplugin_hidl \

View File

@@ -104,7 +104,26 @@ class CdmEngine {
const CdmSessionId& session_id, const CdmKeySetId& key_set_id,
const InitializationData& init_data, const CdmLicenseType license_type,
CdmAppParameterMap& app_parameters, CdmKeyRequest* key_request);
// Accept license response and extract key info.
// This API may
// (a) accept license response, extract key info and load keys.
// (b) accept a renewal response and update license policy information.
// (c) accept a release response and release an offline license or secure
// stop.
// (d) accept a service certificate and cache that information for the
// the lifetime of the session.
//
// |session_id| identifies the session that generated the request and can
// process the response. Should be empty if a release response.
// |key_data| is the license, renewal, release response or service
// certificate response.
// |key_set_id| should be non-null and specified if license release.
// If offline license or streaming license associated with
// a secure stop, |key_set_id| should be non-null and will
// be filled in on return. Use the |key_set_id| with
// RestoreKeys (to reload offline session) or
// GenerateKeyRequest (to release offline session/secure stop).
// |key_set_id| will be cleared if release or streaming
// (not associated with a secure stop).
virtual CdmResponseType AddKey(const CdmSessionId& session_id,
const CdmKeyResponse& key_data,
CdmKeySetId* key_set_id);

View File

@@ -87,8 +87,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();
@@ -122,6 +121,10 @@ class CdmSession {
virtual bool is_offline() { return is_offline_; }
virtual bool is_temporary() { return is_temporary_; }
virtual bool license_received() { return license_received_; }
virtual bool has_provider_session_token() {
return (license_parser_.get() != NULL &&
license_parser_->provider_session_token().size() > 0);
}
virtual CdmUsageSupportType get_usage_support_type()
{ return usage_support_type_; }

View File

@@ -17,6 +17,8 @@
namespace wvcdm {
class CryptoKey;
class UsageTableHeader;
typedef std::map<CryptoKeyId, CryptoKey*> CryptoKeyMap;
class CryptoSession {
@@ -145,6 +147,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);
@@ -230,7 +235,11 @@ class CryptoSession {
KeyId cached_key_id_;
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 @@ class Clock;
class CryptoSession;
class PolicyEngine;
class ServiceCertificate;
class CdmSession;
class CdmLicense {
public:
@@ -38,7 +39,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,6 +7,7 @@
#include <vector>
#include "device_files.h"
#include "file_store.h"
#include "lock.h"
#include "metrics_group.h"
#include "scoped_ptr.h"
@@ -15,28 +16,40 @@
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| 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.
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,56 +66,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();
// Indicates whether one of more license/usage records failed to be upgraded.
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

@@ -64,6 +64,10 @@ static const std::string QUERY_KEY_MAX_NUMBER_OF_SESSIONS =
"MaxNumberOfSessions";
static const std::string QUERY_KEY_OEMCRYPTO_API_VERSION =
"OemCryptoApiVersion";
static const std::string QUERY_KEY_CURRENT_SRM_VERSION = "CurrentSRMVersion";
static const std::string QUERY_KEY_SRM_UPDATE_SUPPORT = "SRMUpdateSupport";
// whether OEM supports SRM update
static const std::string QUERY_KEY_WVCDM_VERSION = "WidevineCdmVersion";
static const std::string QUERY_VALUE_TRUE = "True";
static const std::string QUERY_VALUE_FALSE = "False";

View File

@@ -407,13 +407,19 @@ enum CdmUsageSupportType {
enum CdmUsageEntryStorageType {
kStorageLicense,
kStorageUsageInfo,
kStorageUnknown,
kStorageTypeUnknown,
};
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

@@ -409,7 +409,12 @@ CdmResponseType CdmEngine::AddKey(const CdmSessionId& session_id,
CdmResponseType sts = session->AddKey(key_data);
if (key_set_id) {
*key_set_id = session->key_set_id();
if ((session->is_offline() ||
session->has_provider_session_token()) && !license_type_release) {
*key_set_id = session->key_set_id();
} else {
key_set_id->clear();
}
}
switch (sts) {
@@ -681,6 +686,28 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
std::ostringstream api_version_stream;
api_version_stream << api_version;
*query_response = api_version_stream.str();
} else if (query_token == QUERY_KEY_CURRENT_SRM_VERSION) {
uint16_t current_srm_version;
if (!crypto_session.GetSrmVersion(&current_srm_version)) {
LOGW("CdmEngine::QueryStatus: GetCurrentSRMVersion failed");
return UNKNOWN_ERROR;
}
std::ostringstream current_srm_version_stream;
current_srm_version_stream << current_srm_version;
*query_response = current_srm_version_stream.str();
} else if (query_token == QUERY_KEY_SRM_UPDATE_SUPPORT) {
bool is_srm_update_supported = crypto_session.IsSrmUpdateSupported();
*query_response =
is_srm_update_supported ? QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
} else if (query_token == QUERY_KEY_WVCDM_VERSION) {
std::string cdm_version;
if (!Properties::GetWVCdmVersion(&cdm_version)) {
LOGW("CdmEngine::QueryStatus: GetWVCdmVersion failed");
return UNKNOWN_ERROR;
}
*query_response = cdm_version;
} else {
LOGW("CdmEngine::QueryStatus: Unknown status requested, token = %s",
query_token.c_str());
@@ -1261,42 +1288,47 @@ CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) {
usage_session_.reset(new CdmSession(file_system_));
usage_session_->Init(usage_property_set_.get());
if (usage_session_->get_usage_support_type() == kUsageEntrySupport) {
std::vector<DeviceFiles::CdmUsageData> usage_data;
if (!handle.RetrieveUsageInfo(
DeviceFiles::GetUsageInfoFileName(app_id),
&usage_data)) {
status = RELEASE_ALL_USAGE_INFO_ERROR_4;
} else {
for (size_t k = 0; k < usage_data.size(); ++k) {
CdmResponseType status2 =
usage_session_->DeleteUsageEntry(usage_data[k]);
if (status == NO_ERROR && status2 != NO_ERROR)
status = status2;
switch (usage_session_->get_usage_support_type()) {
case kUsageEntrySupport: {
std::vector<DeviceFiles::CdmUsageData> usage_data;
if (!handle.RetrieveUsageInfo(
DeviceFiles::GetUsageInfoFileName(app_id), &usage_data)) {
status = RELEASE_ALL_USAGE_INFO_ERROR_4;
} else {
for (size_t k = 0; k < usage_data.size(); ++k) {
CdmResponseType status2 = usage_session_->DeleteUsageEntry(
usage_data[k].usage_entry_number);
if (status == NO_ERROR && status2 != NO_ERROR)
status = status2;
}
}
}
std::vector<std::string> provider_session_tokens;
if (!handle.DeleteAllUsageInfoForApp(
DeviceFiles::GetUsageInfoFileName(app_id),
&provider_session_tokens)) {
status = RELEASE_ALL_USAGE_INFO_ERROR_5;
}
} else if (usage_session_->get_usage_support_type()
== kUsageTableSupport) {
std::vector<std::string> provider_session_tokens;
if (!handle.DeleteAllUsageInfoForApp(
DeviceFiles::GetUsageInfoFileName(app_id),
&provider_session_tokens)) {
LOGE("CdmEngine::ReleaseAllUsageInfo: failed to delete L%d secure"
"stops", j);
status = RELEASE_ALL_USAGE_INFO_ERROR_1;
} else {
CdmResponseType status2 = usage_session_->
DeleteMultipleUsageInformation(provider_session_tokens);
if (status2 != NO_ERROR) {
status = status2;
std::vector<std::string> provider_session_tokens;
if (!handle.DeleteAllUsageInfoForApp(
DeviceFiles::GetUsageInfoFileName(app_id),
&provider_session_tokens)) {
status = RELEASE_ALL_USAGE_INFO_ERROR_5;
}
break;
}
case kUsageTableSupport: {
std::vector<std::string> provider_session_tokens;
if (!handle.DeleteAllUsageInfoForApp(
DeviceFiles::GetUsageInfoFileName(app_id),
&provider_session_tokens)) {
LOGE("CdmEngine::ReleaseAllUsageInfo: failed to delete %d secure"
"stops", j);
status = RELEASE_ALL_USAGE_INFO_ERROR_1;
} else {
CdmResponseType status2 = usage_session_->
DeleteMultipleUsageInformation(provider_session_tokens);
if (status2 != NO_ERROR) status = status2;
}
break;
}
default:
// Ignore
break;
}
} else {
LOGE("CdmEngine::ReleaseAllUsageInfo: failed to initialize L%d device"
@@ -1611,25 +1643,25 @@ void CdmEngine::OnTimerEvent() {
for (CdmSessionList::iterator iter = sessions.begin();
iter != sessions.end(); ++iter) {
(*iter)->reset_usage_flags();
if ((*iter)->get_usage_support_type() == kUsageEntrySupport)
(*iter)->UpdateUsageEntryInformation();
if (!has_usage_been_updated) {
// usage is updated for all sessions so this needs to be
// called only once per update usage information period
if ((*iter)->get_usage_support_type() == kUsageTableSupport) {
CdmResponseType status;
M_TIME(
status = (*iter)->UpdateUsageTableInformation(),
(*iter)->GetMetrics(),
crypto_session_update_usage_information_,
status);
if (NO_ERROR != status) {
LOGW("Update usage information failed: %d", status);
} else {
has_usage_been_updated = true;
switch ((*iter)->get_usage_support_type()) {
case kUsageEntrySupport:
(*iter)->UpdateUsageEntryInformation();
break;
case kUsageTableSupport:
if (!has_usage_been_updated) {
// usage is updated for all sessions so this needs to be
// called only once per update usage information period
CdmResponseType status = (*iter)->UpdateUsageTableInformation();
if (NO_ERROR != status) {
LOGW("Update usage information failed: %d", status);
} else {
has_usage_been_updated = true;
}
}
}
break;
default:
// Ignore
break;
}
}
}

View File

@@ -45,15 +45,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();
}
@@ -106,6 +97,13 @@ CdmResponseType CdmSession::Init(
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.
@@ -195,6 +193,9 @@ CdmResponseType CdmSession::Init(
CdmResponseType CdmSession::RestoreOfflineSession(
const CdmKeySetId& key_set_id, const CdmLicenseType license_type) {
if (!key_set_id_.empty()) {
file_handle_->UnreserveLicenseId(key_set_id_);
}
key_set_id_ = key_set_id;
DeviceFiles::LicenseState license_state;
@@ -430,7 +431,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);
}
@@ -446,7 +448,7 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response) {
license_parser_->provider_session_token().size(),
license_parser_->provider_session_token().c_str());
if (is_offline_ || !license_parser_->provider_session_token().empty()) {
if (is_offline_ || has_provider_session_token()) {
if (usage_support_type_ == kUsageEntrySupport)
usage_table_header_->UpdateEntry(crypto_session_.get(), &usage_entry_);
@@ -556,8 +558,7 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
}
has_decrypted_since_last_report_ = true;
if (!is_usage_update_needed_) {
is_usage_update_needed_ =
!license_parser_->provider_session_token().empty();
is_usage_update_needed_ = has_provider_session_token();
}
} else {
Clock clock;
@@ -576,7 +577,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;
@@ -606,8 +607,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;
@@ -641,38 +642,53 @@ CdmResponseType CdmSession::ReleaseKey(const CdmKeyResponse& key_response) {
license_parser_->HandleKeyUpdateResponse(false, key_response);
if (sts != KEY_ADDED) return (sts == KEY_ERROR) ? RELEASE_KEY_ERROR : sts;
if (is_offline_ || !license_parser_->provider_session_token().empty()) {
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) {
@@ -775,7 +791,7 @@ CdmResponseType CdmSession::ReleaseCrypto() {
}
bool CdmSession::DeleteLicense() {
if (!is_offline_ && license_parser_->provider_session_token().empty())
if (!is_offline_ && !has_provider_session_token())
return false;
if (is_offline_) {

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),
@@ -48,7 +51,9 @@ CryptoSession::CryptoSession(metrics::MetricsGroup* metrics)
update_usage_table_after_close_session_(false),
is_destination_buffer_type_valid_(false),
requested_security_level_(kLevelDefault),
usage_support_type_(kUnknownUsageSupport),
is_usage_support_type_valid_(false),
usage_support_type_(kNonSecureUsageSupport),
usage_table_header_(NULL),
request_id_base_(0),
cipher_mode_(kCipherModeCtr) {
Init();
@@ -121,6 +126,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;
}
@@ -217,8 +232,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;
}
@@ -430,7 +444,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;
@@ -470,8 +485,35 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
random_sts,
metrics::Pow2Bucket(sizeof(request_id_base_)));
++request_id_index_;
CdmUsageSupportType usage_support_type;
GetUsageSupportType(&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;
}
@@ -1108,6 +1150,11 @@ CdmResponseType CryptoSession::UpdateUsageInformation() {
AutoLock auto_lock(crypto_lock_);
if (!initialized_) return UNKNOWN_ERROR;
if (usage_table_header_ != NULL) {
LOGV("UpdateUsageInformation: deprecated for OEMCrypto v13+");
return NO_ERROR;
}
OEMCryptoResult status;
M_TIME(
status = OEMCrypto_UpdateUsageTable(),
@@ -1264,6 +1311,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

@@ -858,6 +858,11 @@ bool DeviceFiles::ListUsageInfoFiles(
return false;
}
if (usage_info_file_names == NULL) {
LOGW("DeviceFiles::ListUsageInfoFiles: usage_info_file_names not provided");
return false;
}
// Get list of filenames
std::vector<std::string> filenames;
if (!ListFiles(&filenames)) {
@@ -982,7 +987,7 @@ bool DeviceFiles::StoreUsageTableInfo(
const CdmUsageTableHeader& usage_table_header,
const std::vector<CdmUsageEntryInfo>& usage_entry_info) {
if (!initialized_) {
LOGW("DeviceFiles::StoreUsageTableHeader: not initialized");
LOGW("DeviceFiles::StoreUsageTableInfo: not initialized");
return false;
}
@@ -1009,7 +1014,7 @@ bool DeviceFiles::StoreUsageTableInfo(
info->set_usage_info_file_name(
usage_entry_info[i].usage_info_file_name);
break;
case kStorageUnknown:
case kStorageTypeUnknown:
default:
info->set_storage(
UsageTableInfo_UsageEntryInfo_UsageEntryStorage_UNKNOWN);
@@ -1081,7 +1086,7 @@ bool DeviceFiles::RetrieveUsageTableInfo(
break;
case UsageTableInfo_UsageEntryInfo_UsageEntryStorage_UNKNOWN:
default:
(*usage_entry_info)[i].storage_type = kStorageUnknown;
(*usage_entry_info)[i].storage_type = kStorageTypeUnknown;
break;
}
}

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"
@@ -274,7 +275,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;
@@ -330,6 +332,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

@@ -29,14 +29,15 @@ RSA* GetKey(const std::string& serialized_key) {
return NULL;
}
RSA* key = d2i_RSAPublicKey_bio(bio, NULL);
BIO_free(bio);
if (key == NULL) {
LOGE("GetKey: RSA key deserialization failure: %s",
ERR_error_string(ERR_get_error(), NULL));
BIO_free(bio);
return NULL;
}
BIO_free(bio);
return key;
}

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,65 @@ 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_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);
@@ -101,7 +89,7 @@ CdmResponseType UsageTableHeader::AddEntry(
size_t number_of_entries = usage_entry_info_.size();
usage_entry_info_.resize(*usage_entry_number + 1);
for (size_t i = number_of_entries; i < usage_entry_info_.size() - 1; ++i) {
usage_entry_info_[i].storage_type = kStorageUnknown;
usage_entry_info_[i].storage_type = kStorageTypeUnknown;
usage_entry_info_[i].key_set_id.clear();
usage_entry_info_[i].usage_info_file_name.clear();
}
@@ -120,15 +108,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 +126,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,50 +150,67 @@ 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;
}
case kStorageUnknown:
case kStorageTypeUnknown:
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 = kStorageTypeUnknown;
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 +218,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 +230,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 +240,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 +256,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 +272,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,
@@ -274,7 +283,7 @@ CdmResponseType UsageTableHeader::GetEntry(uint32_t usage_entry_number,
}
break;
}
case kStorageUnknown:
case kStorageTypeUnknown:
default:
LOGE(
"UsageTableHeader::GetEntry: Attempting to retrieve usage "
@@ -293,6 +302,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 +313,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 +322,7 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number,
LOGE("UsageTableHeader::StoreEntry: Failed to retrieve license");
return USAGE_STORE_ENTRY_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 +337,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 +347,10 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number,
"information");
return USAGE_STORE_ENTRY_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,
@@ -350,7 +360,7 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number,
}
break;
}
case kStorageUnknown:
case kStorageTypeUnknown:
default:
LOGE(
"UsageTableHeader::GetUsageEntry: Attempting to retrieve usage "
@@ -361,41 +371,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
@@ -403,18 +428,14 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable() {
// * update the usage header table and entry numbers
// * save the usage table header and store the usage entry number and
// usage entry along with the license to persistent memory
// On errors, continue to the next license, but indicate on return that not
// all licenses may have been upgraded.
std::vector<std::string> key_set_ids;
if (file_handle_->ListLicenses(&key_set_ids)) {
LOGE(
if (handle->ListLicenses(&key_set_ids)) {
LOGW(
"UpgradeUsageTableHeader::UpgradeLicensesFromUsageTable: unable to "
"retrieve list of licenses");
return false;
}
bool result = true;
for (size_t i = 0; i < key_set_ids.size(); ++i) {
DeviceFiles::LicenseState license_state;
std::string init_data, key_request, key_response, key_renewal_request;
@@ -423,7 +444,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,
@@ -432,7 +453,6 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable() {
LOGW(
"UsageTableHeader::UpgradeLicensesFromUsageTable: Failed to "
"retrieve license");
result = false;
continue;
}
@@ -442,37 +462,26 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable() {
LOGW(
"UsageTableHeader::UpgradeLicensesFromUsageTable: Failed to "
"retrieve provider session token");
result = false;
continue;
}
if (provider_session_token.empty()) {
result = false;
continue;
}
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) {
result = false;
continue;
}
if (status != NO_ERROR) continue;
status = AddEntry(&crypto_session, true /* persistent license */,
key_set_ids[i], kEmptyString, &usage_entry_number);
if (status != NO_ERROR) {
result = false;
continue;
}
if (status != NO_ERROR) continue;
status = crypto_session.CopyOldUsageEntry(provider_session_token);
if (status != NO_ERROR) {
crypto_session.Close();
DeleteLastEntry();
result = false;
Shrink(metrics, 1);
continue;
}
@@ -480,26 +489,27 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable() {
if (status != NO_ERROR) {
crypto_session.Close();
DeleteLastEntry();
result = false;
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)) {
LOGW("UsageTableHeader::StoreEntry: Failed to store license");
result = false;
LOGE(
"UsageTableHeader::UpgradeLicensesFromUsageTable: Failed to store "
"license");
continue;
}
}
return result;
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
@@ -509,27 +519,21 @@ bool UsageTableHeader::UpgradeUsageInfoFromUsageTable() {
// * once done processing all the usage records from a file, save the usage
// information to persistent memory along with usage entry number and usage
// entry.
// On errors, continue to the next usage record, but indicate on return
// that not all usage records may have been upgraded.
std::vector<std::string> usage_info_file_names;
if (file_handle_->ListUsageInfoFiles(&usage_info_file_names)) {
LOGE(
if (handle->ListUsageInfoFiles(&usage_info_file_names)) {
LOGW(
"UpgradeUsageTableHeader::UpgradeUsageInfoFromUsageTable: Unable to "
"retrieve list of usage info file names");
return false;
}
bool result = true;
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",
usage_info_file_names[i].c_str());
result = false;
continue;
}
@@ -538,17 +542,13 @@ bool UsageTableHeader::UpgradeUsageInfoFromUsageTable() {
LOGW(
"UsageTableHeader::UpgradeUsageInfoFromUsageTable: Provider "
"session id empty");
result = false;
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) {
result = false;
continue;
}
if (status != NO_ERROR) continue;
// TODO(rfrias): We need to fill in the app id, but it is hashed
// and we have no way to extract. Use the hased filename instead?
@@ -556,18 +556,14 @@ bool UsageTableHeader::UpgradeUsageInfoFromUsageTable() {
usage_data[j].key_set_id, kEmptyString,
&(usage_data[i].usage_entry_number));
if (status != NO_ERROR) {
result = false;
continue;
}
if (status != NO_ERROR) continue;
status = crypto_session.CopyOldUsageEntry(
usage_data[i].provider_session_token);
if (status != NO_ERROR) {
crypto_session.Close();
DeleteLastEntry();
result = false;
Shrink(metrics, 1);
continue;
}
@@ -575,23 +571,21 @@ bool UsageTableHeader::UpgradeUsageInfoFromUsageTable() {
if (status != NO_ERROR) {
crypto_session.Close();
DeleteLastEntry();
result = false;
Shrink(metrics, 1);
continue;
}
}
if (!file_handle_->StoreUsageInfo(usage_info_file_names[i], usage_data)) {
LOGW(
if (!handle->StoreUsageInfo(usage_info_file_names[i], usage_data)) {
LOGE(
"UsageTableHeader::StoreUsageInfo: Failed to store usage records to "
"%s",
usage_info_file_names[i].c_str());
result = false;
continue;
}
}
return result;
return NO_ERROR;
}
} // namespace wvcdm

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,9 @@
// Copyright 2017 Google Inc. All Rights Reserved.
#include "usage_table_header.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <string>
#include "crypto_session.h"
#include "device_files.h"
#include "file_store.h"
@@ -52,58 +50,10 @@ const CdmUsageEntryInfo kUsageEntryInfoStorageTypeUnknown = {
.storage_type = kStorageTypeUnknown,
.key_set_id = "",
.usage_info_file_name = ""};
const std::vector<std::string> kEmptyLicenseList;
const std::string kLicenseArray[] = {
kUsageEntryInfoOfflineLicense1.key_set_id,
kUsageEntryInfoOfflineLicense2.key_set_id,
kUsageEntryInfoOfflineLicense3.key_set_id,
};
const size_t kLicenseArraySize = sizeof(kLicenseArray)/
sizeof(kLicenseArray[0]);
std::vector<std::string> kLicenseList;
const std::vector<std::string> kEmptyUsageInfoFilesList;
const std::string kUsageInfoFileArray[] = {
kUsageEntryInfoSecureStop1.usage_info_file_name,
kUsageEntryInfoSecureStop2.usage_info_file_name,
kUsageEntryInfoSecureStop3.usage_info_file_name,
};
const size_t kUsageInfoFileArraySize = sizeof(kUsageInfoFileArray)/
sizeof(kUsageInfoFileArray[0]);
std::vector<std::string> kUsageInfoFileList;
const DeviceFiles::CdmUsageData kCdmUsageData1 = {
.provider_session_token = "provider_session_token_1",
.license_request = "license_request_1",
.license = "license_1",
.key_set_id = "key_set_id_1",
.usage_entry = "usage_entry_1",
.usage_entry_number = 0,
};
const DeviceFiles::CdmUsageData kCdmUsageData2 = {
.provider_session_token = "provider_session_token_2",
.license_request = "license_request_2",
.license = "license_2",
.key_set_id = "key_set_id_2",
.usage_entry = "usage_entry_2",
.usage_entry_number = 0,
};
const DeviceFiles::CdmUsageData kCdmUsageData3 = {
.provider_session_token = "provider_session_token_3",
.license_request = "license_request_3",
.license = "license_3",
.key_set_id = "key_set_id_3",
.usage_entry = "usage_entry_3",
.usage_entry_number = 0,
};
const std::vector<DeviceFiles::CdmUsageData> kEmptyUsageInfoUsageDataList;
const std::vector<CdmUsageEntryInfo> kEmptyUsageEntryInfoVector;
std::vector<CdmUsageEntryInfo> kUsageEntryInfoVector;
const std::vector<CdmUsageEntryInfo> kUsageEntryInfoVector = {
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1,
kUsageEntryInfoStorageTypeUnknown};
const DeviceFiles::LicenseState kActiveLicenseState =
DeviceFiles::kLicenseStateActive;
const CdmInitData kPsshData = "pssh data";
@@ -118,36 +68,6 @@ int64_t kPlaybackStartTime = 1030005;
int64_t kPlaybackDuration = 300;
int64_t kGracePeriodEndTime = 60;
namespace {
void InitVectorConstants() {
kUsageEntryInfoVector.clear();
kUsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense1);
kUsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop1);
kUsageEntryInfoVector.push_back(kUsageEntryInfoStorageTypeUnknown);
kUsageInfoFileList.clear();
for (size_t i = 0; i < kUsageInfoFileArraySize; i++) {
kUsageInfoFileList.push_back(kUsageInfoFileArray[i]);
}
kLicenseList.clear();
for (size_t i = 0; i < kLicenseArraySize; i++) {
kLicenseList.push_back(kLicenseArray[i]);
}
}
void ToVector(std::vector<CdmUsageEntryInfo>& vec,
const CdmUsageEntryInfo* arr, size_t total_size) {
size_t max = total_size / sizeof(CdmUsageEntryInfo);
vec.clear();
for (size_t i = 0; i < max; i++) {
vec.push_back(arr[i]);
}
}
}; // namespace
class MockDeviceFiles : public DeviceFiles {
public:
MockDeviceFiles() : DeviceFiles(&file_system_) { Init(kSecurityLevelL1); }
@@ -162,17 +82,12 @@ class MockDeviceFiles : public DeviceFiles {
bool(const std::string&, const std::string&, std::string*,
CdmKeyMessage*, CdmKeyResponse*, CdmUsageEntry*,
uint32_t*));
MOCK_METHOD0(DeleteAllLicenses, bool());
MOCK_METHOD7(StoreUsageInfo,
bool(const std::string&, const CdmKeyMessage&,
const CdmKeyResponse&, const std::string&,
const std::string&, const CdmUsageEntry&, uint32_t));
MOCK_METHOD2(RetrieveUsageInfo,
bool(const std::string&, std::vector<CdmUsageData>*));
MOCK_METHOD1(ListLicenses,
bool(std::vector<std::string>* key_set_ids));
MOCK_METHOD1(ListUsageInfoFiles,
bool(std::vector<std::string>* usage_info_files));
private:
FileSystem file_system_;
@@ -180,8 +95,7 @@ class MockDeviceFiles : public DeviceFiles {
class MockCryptoSession : public CryptoSession {
public:
MockCryptoSession(metrics::CryptoMetrics* metrics)
: CryptoSession(metrics) {}
MockCryptoSession() : CryptoSession(NULL) {}
MOCK_METHOD1(Open, CdmResponseType(SecurityLevel));
MOCK_METHOD1(LoadUsageTableHeader,
CdmResponseType(const CdmUsageTableHeader&));
@@ -207,16 +121,11 @@ using ::testing::UnorderedElementsAre;
using ::testing::UnorderedElementsAreArray;
class UsageTableHeaderTest : public ::testing::Test {
public:
static void SetUpTestCase() {
InitVectorConstants();
}
protected:
virtual void SetUp() {
// UsageTableHeader will take ownership of the pointer
device_files_ = new MockDeviceFiles();
crypto_session_ = new MockCryptoSession(&crypto_metrics_);
crypto_session_ = new MockCryptoSession();
usage_table_header_ = new UsageTableHeader();
// usage_table_header_ object takes ownership of these objects
@@ -242,7 +151,6 @@ class UsageTableHeaderTest : public ::testing::Test {
}
MockDeviceFiles* device_files_;
metrics::CryptoMetrics crypto_metrics_;
MockCryptoSession* crypto_session_;
UsageTableHeader* usage_table_header_;
};
@@ -259,86 +167,21 @@ TEST_F(UsageTableHeaderTest, InitError) {
class UsageTableHeaderInitializationTest
: public UsageTableHeaderTest,
public ::testing::WithParamInterface<CdmSecurityLevel> {
public:
static void SetUpTestCase() {
InitVectorConstants();
}
};
public ::testing::WithParamInterface<CdmSecurityLevel> {};
TEST_P(UsageTableHeaderInitializationTest, CreateUsageTableHeader) {
std::vector<CdmUsageEntryInfo> empty_usage_entry_info;
EXPECT_CALL(*device_files_, RetrieveUsageTableInfo(NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kEmptyUsageTableHeader),
SetArgPointee<1>(kEmptyUsageEntryInfoVector),
Return(false)));
EXPECT_CALL(*device_files_, ListLicenses(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kEmptyLicenseList),
Return(false)));
EXPECT_CALL(*device_files_, ListUsageInfoFiles(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kEmptyUsageInfoFilesList),
Return(false)));
EXPECT_CALL(*crypto_session_, CreateUsageTableHeader(NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kEmptyUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader,
kEmptyUsageEntryInfoVector))
.Times(2)
.WillRepeatedly(Return(true));
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
}
TEST_P(UsageTableHeaderInitializationTest, Upgrade_UnableToRetrieveLicenses) {
EXPECT_CALL(*device_files_, RetrieveUsageTableInfo(NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kEmptyUsageTableHeader),
SetArgPointee<1>(kEmptyUsageEntryInfoVector),
Return(false)));
EXPECT_CALL(*device_files_, ListLicenses(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kLicenseList),
Return(true)));
EXPECT_CALL(*device_files_, ListUsageInfoFiles(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kEmptyUsageInfoFilesList),
Return(false)));
EXPECT_CALL(*crypto_session_, CreateUsageTableHeader(NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kEmptyUsageTableHeader), Return(NO_ERROR)));
// TODO: Why not being called?
//EXPECT_CALL(*device_files_, DeleteAllLicenses()).WillOnce(Return(true));
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader,
kEmptyUsageEntryInfoVector))
.Times(2)
.WillRepeatedly(Return(true));
for (size_t i = 0; i < kLicenseList.size(); ++i)
device_files_->DeleteLicense(kLicenseList[i]);
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
}
TEST_P(UsageTableHeaderInitializationTest, Upgrade_UnableToRetrieveUsageInfo) {
EXPECT_CALL(*device_files_, RetrieveUsageTableInfo(NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kEmptyUsageTableHeader),
SetArgPointee<1>(kEmptyUsageEntryInfoVector),
Return(false)));
EXPECT_CALL(*device_files_, ListLicenses(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kEmptyLicenseList),
Return(false)));
EXPECT_CALL(*device_files_, ListUsageInfoFiles(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kUsageInfoFileList),
Return(true)));
EXPECT_CALL(*crypto_session_, CreateUsageTableHeader(NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kEmptyUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader,
kEmptyUsageEntryInfoVector))
.Times(2)
.WillRepeatedly(Return(true));
for (size_t i = 0; i < kUsageInfoFileList.size(); ++i) {
EXPECT_CALL(*device_files_,
RetrieveUsageInfo(kUsageInfoFileList[i], NotNull()))
.WillOnce(DoAll(SetArgPointee<1>(kEmptyUsageInfoUsageDataList),
Return(false)));
}
.WillOnce(Return(true));
EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_));
}
@@ -552,7 +395,7 @@ TEST_F(UsageTableHeaderTest, UpdateEntry) {
TEST_F(UsageTableHeaderTest, DeleteEntry_InvalidUsageEntryNumber) {
Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector);
uint32_t usage_entry_number = kUsageEntryInfoVector.size();
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
EXPECT_NE(NO_ERROR, usage_table_header_->DeleteEntry(
usage_entry_number, device_files_, &metrics));
@@ -576,17 +419,14 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_InvalidUsageEntryNumber) {
//
// # of usage entries 4 4
TEST_F(UsageTableHeaderTest, DeleteEntry_CryptoSessionError) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1,
kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoOfflineLicense2};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 1; // kUsageEntryInfoOfflineLicense2
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(
@@ -615,17 +455,14 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_CryptoSessionError) {
//
// # of usage entries 4 3
TEST_F(UsageTableHeaderTest, DeleteEntry_LastOfflineEntry) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1,
kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoOfflineLicense2};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 1; // kUsageEntryInfoOfflineLicense2
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(
@@ -663,17 +500,14 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastOfflineEntry) {
//
// # of usage entries 4 3
TEST_F(UsageTableHeaderTest, DeleteEntry_LastSecureStopEntry) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1,
kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoSecureStop2};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 1; // kUsageEntryInfoSecureStop2
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(
@@ -716,19 +550,17 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastSecureStopEntry) {
// # of usage entries 5 2
TEST_F(UsageTableHeaderTest,
DeleteEntry_LastOfflineEntriesHaveMissingLicenses) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
kUsageEntryInfoSecureStop1, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoOfflineLicense2,
kUsageEntryInfoOfflineLicense3};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense1
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
device_files_->DeleteAllLicenses();
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(
*crypto_session_,
@@ -768,18 +600,15 @@ TEST_F(UsageTableHeaderTest,
//
// # of usage entries 5 2
TEST_F(UsageTableHeaderTest, DeleteEntry_LastSecureStopEntriesAreMissing) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2,
kUsageEntryInfoSecureStop3};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoSecureStop1
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(
@@ -834,18 +663,15 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastSecureStopEntriesAreMissing) {
// # of usage entries 5 2
TEST_F(UsageTableHeaderTest,
DeleteEntry_LastOfflineEntriesHaveIncorrectUsageEntryNumber) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
kUsageEntryInfoSecureStop1, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoOfflineLicense2,
kUsageEntryInfoOfflineLicense3};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense1
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
EXPECT_TRUE(device_files_->StoreLicense(
usage_entry_info_vector[usage_entry_info_vector.size() - 1].key_set_id,
@@ -903,20 +729,17 @@ TEST_F(UsageTableHeaderTest,
// # of usage entries 5 2
TEST_F(UsageTableHeaderTest,
DeleteEntry_LastSecureStopEntriesHaveIncorrectUsageEntryNumber) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2,
kUsageEntryInfoSecureStop3};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoSecureStop1
uint32_t usage_entry_number_after_deleted_entry =
usage_entry_number_to_be_deleted + 1;
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(
@@ -981,18 +804,15 @@ TEST_F(UsageTableHeaderTest,
//
// # of usage entries 7 4
TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreStorageTypeUnknown) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
kUsageEntryInfoSecureStop1, kUsageEntryInfoOfflineLicense1,
kUsageEntryInfoOfflineLicense2, kUsageEntryInfoOfflineLicense3,
kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoStorageTypeUnknown};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense3
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(
@@ -1037,20 +857,17 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreStorageTypeUnknown) {
// # of usage entries 5 5
TEST_F(UsageTableHeaderTest,
DeleteEntry_LastEntryIsOffline_MoveOfflineEntryFailed) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
kUsageEntryInfoSecureStop1, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoOfflineLicense2,
kUsageEntryInfoOfflineLicense3};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense1
uint32_t last_usage_entry_number =
usage_entry_info_vector.size() - 1; // kUsageEntryInfoOfflineLicense3
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
EXPECT_TRUE(device_files_->StoreLicense(
usage_entry_info_vector[last_usage_entry_number].key_set_id,
@@ -1106,20 +923,17 @@ TEST_F(UsageTableHeaderTest,
// # of usage entries 5 5
TEST_F(UsageTableHeaderTest,
DeleteEntry_LastEntryIsSecureStop_MoveSecureStopEntryFailed) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2,
kUsageEntryInfoSecureStop3};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoSecureStop1
uint32_t last_usage_entry_number =
usage_entry_info_vector.size() - 1; // kUsageEntryInfoSecureStop3
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(*crypto_session_,
@@ -1182,21 +996,18 @@ TEST_F(UsageTableHeaderTest,
// # of usage entries 7 5
TEST_F(UsageTableHeaderTest,
DeleteEntry_LastEntriesAreOfflineAndUnknown_MoveOfflineEntryFailed) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
kUsageEntryInfoSecureStop1, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoOfflineLicense2,
kUsageEntryInfoOfflineLicense3, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoStorageTypeUnknown};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 5; // kUsageEntryInfoOfflineLicense1
uint32_t last_valid_usage_entry_number =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense3
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
EXPECT_TRUE(device_files_->StoreLicense(
usage_entry_info_vector[last_valid_usage_entry_number].key_set_id,
@@ -1263,21 +1074,18 @@ TEST_F(UsageTableHeaderTest,
// # of usage entries 7 5
TEST_F(UsageTableHeaderTest,
DeleteEntry_LastEntriesAreSecureStopAndUnknown_MoveOfflineEntryFailed) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2,
kUsageEntryInfoSecureStop3, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoStorageTypeUnknown};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 5; // kUsageEntryInfoOfflineLicense1
uint32_t last_valid_usage_entry_number =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense3
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault))
.Times(2)
@@ -1339,20 +1147,17 @@ TEST_F(UsageTableHeaderTest,
//
// # of usage entries 5 4
TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntryIsOffline) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
kUsageEntryInfoSecureStop1, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoOfflineLicense2,
kUsageEntryInfoOfflineLicense3};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense1
uint32_t last_usage_entry_number =
usage_entry_info_vector.size() - 1; // kUsageEntryInfoOfflineLicense3
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
EXPECT_TRUE(device_files_->StoreLicense(
usage_entry_info_vector[last_usage_entry_number].key_set_id,
@@ -1456,20 +1261,17 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntryIsOffline) {
//
// # of usage entries 5 4
TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntryIsSecureStop) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2,
kUsageEntryInfoSecureStop3};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoSecureStop1
uint32_t last_usage_entry_number =
usage_entry_info_vector.size() - 1; // kUsageEntryInfoSecureStop3
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault))
.Times(2)
@@ -1558,21 +1360,18 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntryIsSecureStop) {
//
// # of usage entries 7 4
TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreOfflineAndUnknknown) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
kUsageEntryInfoSecureStop1, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoOfflineLicense2,
kUsageEntryInfoOfflineLicense3, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoStorageTypeUnknown};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 5; // kUsageEntryInfoOfflineLicense1
uint32_t last_valid_usage_entry_number =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense3
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
EXPECT_TRUE(device_files_->StoreLicense(
usage_entry_info_vector[last_valid_usage_entry_number].key_set_id,
@@ -1680,21 +1479,18 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreOfflineAndUnknknown) {
//
// # of usage entries 7 4
TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreSecureStopAndUnknknown) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
const std::vector<CdmUsageEntryInfo> usage_entry_info_vector = {
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2,
kUsageEntryInfoSecureStop3, kUsageEntryInfoStorageTypeUnknown,
kUsageEntryInfoStorageTypeUnknown};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector);
uint32_t usage_entry_number_to_be_deleted =
usage_entry_info_vector.size() - 5; // kUsageEntryInfoSecureStop1
uint32_t last_valid_usage_entry_number =
usage_entry_info_vector.size() - 3; // kUsageEntryInfoSecureStop3
metrics::CryptoMetrics metrics;
metrics::MetricsGroup metrics;
EXPECT_CALL(*crypto_session_, Open(kLevelDefault))
.Times(2)
@@ -1762,30 +1558,4 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreSecureStopAndUnknknown) {
device_files_, &metrics));
}
// If the crypto session says the usage table header is stale, init should fail.
TEST_F(UsageTableHeaderTest, StaleHeader) {
std::vector<CdmUsageEntryInfo> usage_entry_info_vector;
const CdmUsageEntryInfo usage_entry_info_array[] = {
kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1,
kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoOfflineLicense2};
ToVector(usage_entry_info_vector, usage_entry_info_array,
sizeof(usage_entry_info_array));
EXPECT_CALL(*device_files_, RetrieveUsageTableInfo(NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader),
SetArgPointee<1>(usage_entry_info_vector),
Return(true)));
EXPECT_CALL(*crypto_session_, LoadUsageTableHeader(kUsageTableHeader))
.WillOnce(Return(LOAD_USAGE_HEADER_GENERATION_SKEW));
EXPECT_CALL(*crypto_session_, CreateUsageTableHeader(NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kEmptyUsageTableHeader), Return(NO_ERROR)));
EXPECT_CALL(*device_files_, DeleteAllLicenses()).WillOnce(Return(true));
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader,
kEmptyUsageEntryInfoVector))
.WillOnce(Return(true));
EXPECT_TRUE(usage_table_header_->Init(kSecurityLevelL1, crypto_session_));
}
} // namespace wvcdm

View File

@@ -160,6 +160,11 @@ CdmResponseType WvContentDecryptionModule::AddKey(
CdmEngine* cdm_engine = session_id.empty() ? GetCdmForSessionId(*key_set_id)
: GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_3;
// Save key_set_id, as CDM will return an empty key_set_id on release
CdmKeySetId release_key_set_id;
if (session_id.empty() && key_set_id != NULL) {
release_key_set_id = *key_set_id;
}
CdmResponseType sts;
M_TIME(
sts = cdm_engine->AddKey(
@@ -170,8 +175,8 @@ CdmResponseType WvContentDecryptionModule::AddKey(
cdm_engine_add_key_,
sts);
if (sts == KEY_ADDED && session_id.empty()) { // license type release
cdm_engine->CloseKeySetSession(*key_set_id);
cdm_by_session_id_.erase(*key_set_id);
cdm_engine->CloseKeySetSession(release_key_set_id);
cdm_by_session_id_.erase(release_key_set_id);
}
return sts;
}
@@ -377,7 +382,10 @@ CdmResponseType WvContentDecryptionModule::Decrypt(
cdm_engine->GetMetrics(),
cdm_engine_find_session_for_key_,
status);
if (!status) return KEY_NOT_FOUND_IN_SESSION;
if (!status && parameters.is_encrypted) {
LOGE("WvContentDecryptionModule::Decrypt: unable to find session");
return KEY_NOT_FOUND_IN_SESSION;
}
}
CdmResponseType sts;
M_TIME(

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

@@ -983,6 +983,142 @@ TEST_F(WvCdmExtendedDurationTest, UsageOverflowTest) {
}
}
// This test verifies that sessions allocated internally during key release
// message generation are deallocated after their time to live period expires
// by timer events (if other sessions are open).
TEST_F(WvCdmExtendedDurationTest, AutomatedOfflineSessionReleaseOnTimerEvent) {
Unprovision();
Provision();
// Leave session open to run the CDM timer
CdmSessionId streaming_session_id;
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&streaming_session_id);
// override default settings unless configured through the command line
std::string key_id;
std::string client_auth;
GetOfflineConfiguration(&key_id, &client_auth);
uint32_t initial_open_sessions =
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS);
uint32_t max_sessions =
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_MAX_NUMBER_OF_SESSIONS);
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(kOfflineClip4, kLicenseTypeOffline);
VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false);
EXPECT_FALSE(key_set_id_.empty());
decryptor_.CloseSession(session_id_);
CdmKeySetId key_set_id = key_set_id_;
session_id_.clear();
key_set_id_.clear();
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id));
decryptor_.CloseSession(session_id_);
session_id_.clear();
GenerateKeyRelease(key_set_id);
uint32_t open_sessions =
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS);
EXPECT_GT(open_sessions, initial_open_sessions);
sleep(kMinute + kClockTolerance);
open_sessions =
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS);
EXPECT_EQ(open_sessions, initial_open_sessions);
session_id_.clear();
GenerateKeyRelease(key_set_id);
key_set_id_ = key_set_id;
VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false);
decryptor_.CloseSession(streaming_session_id);
}
// This test verifies that sessions allocated internally during key release
// message generation are deallocated after their time to live period expires
// when a new session is opened.
TEST_F(WvCdmExtendedDurationTest, AutomatedOfflineSessionReleaseOnOpenSession) {
Unprovision();
Provision();
// override default settings unless configured through the command line
std::string key_id;
std::string client_auth;
GetOfflineConfiguration(&key_id, &client_auth);
uint32_t initial_open_sessions =
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS);
uint32_t max_sessions =
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_MAX_NUMBER_OF_SESSIONS);
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(kOfflineClip4, kLicenseTypeOffline);
VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false);
EXPECT_FALSE(key_set_id_.empty());
decryptor_.CloseSession(session_id_);
CdmKeySetId key_set_id = key_set_id_;
session_id_.clear();
key_set_id_.clear();
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id));
decryptor_.CloseSession(session_id_);
session_id_.clear();
GenerateKeyRelease(key_set_id);
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
EXPECT_GT(
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS),
initial_open_sessions);
decryptor_.CloseSession(session_id_);
EXPECT_GT(
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS),
initial_open_sessions);
sleep(kMinute + kClockTolerance);
EXPECT_GT(
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS),
initial_open_sessions);
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
EXPECT_GT(
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS),
initial_open_sessions);
decryptor_.CloseSession(session_id_);
EXPECT_EQ(
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS),
initial_open_sessions);
session_id_.clear();
GenerateKeyRelease(key_set_id);
key_set_id_ = key_set_id;
VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false);
}
// This test verifies that sessions allocated internally during
// key release message generation are deallocated after their
// time to live period expires.

View File

@@ -986,7 +986,7 @@ class TestWvCdmHlsEventListener : public WvCdmEventListener {
class WvCdmRequestLicenseTest : public WvCdmTestBase {
public:
WvCdmRequestLicenseTest() {}
WvCdmRequestLicenseTest() : license_type_(kLicenseTypeStreaming) {}
~WvCdmRequestLicenseTest() {}
protected:
@@ -1032,6 +1032,7 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
CdmClientPropertySet* property_set) {
CdmKeyRequest key_request;
std::string key_set_id;
license_type_ = license_type;
EXPECT_EQ(expected_response,
decryptor_.GenerateKeyRequest(
session_id_, key_set_id, init_data_type, init_data,
@@ -1075,6 +1076,7 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
void GenerateKeyRelease(CdmKeySetId key_set_id,
CdmClientPropertySet* property_set,
CdmKeyMessage* key_msg) {
license_type_ = kLicenseTypeRelease;
CdmSessionId session_id;
CdmInitData init_data;
wvcdm::CdmAppParameterMap app_parameters;
@@ -1168,26 +1170,34 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
}
void VerifyKeyRequestResponse(const std::string& server_url,
const std::string& client_auth,
bool is_renewal) {
const std::string& client_auth) {
std::string response;
VerifyKeyRequestResponse(server_url, client_auth, is_renewal, &response);
VerifyKeyRequestResponse(server_url, client_auth, false);
}
void VerifyUsageKeyRequestResponse(const std::string& server_url,
const std::string& client_auth) {
std::string response;
VerifyKeyRequestResponse(server_url, client_auth, true);
}
void VerifyKeyRequestResponse(const std::string& server_url,
const std::string& client_auth, bool is_renewal,
const std::string& client_auth,
bool is_usage) {
std::string response;
VerifyKeyRequestResponse(server_url, client_auth, is_usage, &response);
}
void VerifyKeyRequestResponse(const std::string& server_url,
const std::string& client_auth,
bool is_usage,
std::string* response) {
*response = GetKeyRequestResponse(server_url, client_auth);
if (is_renewal) {
// TODO application makes a license request, CDM will renew the license
// when appropriate
EXPECT_EQ(decryptor_.AddKey(session_id_, *response, &key_set_id_),
wvcdm::KEY_ADDED);
} else {
EXPECT_EQ(decryptor_.AddKey(session_id_, *response, &key_set_id_),
wvcdm::KEY_ADDED);
}
EXPECT_EQ(decryptor_.AddKey(session_id_, *response, &key_set_id_),
wvcdm::KEY_ADDED);
EXPECT_EQ(is_usage || license_type_ == kLicenseTypeOffline,
key_set_id_.size() > 0);
}
void Unprovision() {
@@ -1295,6 +1305,7 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
CdmKeyMessage key_msg_;
CdmSessionId session_id_;
CdmKeySetId key_set_id_;
CdmLicenseType license_type_;
};
TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
@@ -1608,7 +1619,7 @@ TEST_F(WvCdmRequestLicenseTest, ForceL3Test) {
kDefaultCdmIdentifier, NULL,
&session_id_));
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
decryptor_.CloseSession(session_id_);
}
@@ -1624,7 +1635,7 @@ TEST_F(WvCdmRequestLicenseTest, PrivacyModeTest) {
EXPECT_EQ(decryptor_.AddKey(session_id_, resp, &key_set_id_),
wvcdm::NEED_KEY);
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
decryptor_.CloseSession(session_id_);
}
@@ -1637,7 +1648,7 @@ TEST_F(WvCdmRequestLicenseTest, PrivacyModeWithServiceCertificateTest) {
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
NULL, &session_id_);
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
decryptor_.CloseSession(session_id_);
}
@@ -1682,7 +1693,7 @@ TEST_F(WvCdmRequestLicenseTest, AddStreamingKeyTest) {
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
decryptor_.CloseSession(session_id_);
}
@@ -1698,7 +1709,7 @@ TEST_F(WvCdmRequestLicenseTest, AddKeyOfflineTest) {
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
decryptor_.CloseSession(session_id_);
}
@@ -1714,7 +1725,7 @@ TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeyTest) {
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
CdmKeySetId key_set_id = key_set_id_;
EXPECT_FALSE(key_set_id_.empty());
@@ -1739,7 +1750,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeyTest) {
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
CdmKeySetId key_set_id = key_set_id_;
EXPECT_FALSE(key_set_id_.empty());
@@ -1756,7 +1767,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeyTest) {
key_set_id_.clear();
GenerateKeyRelease(key_set_id);
key_set_id_ = key_set_id;
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
}
TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeySessionUsageDisabledTest) {
@@ -1775,7 +1786,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeySessionUsageDisabledTest) {
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
CdmKeySetId key_set_id = key_set_id_;
EXPECT_FALSE(key_set_id_.empty());
@@ -1793,7 +1804,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeySessionUsageDisabledTest) {
CdmKeyMessage key_msg;
GenerateKeyRelease(key_set_id, NULL, &key_msg);
key_set_id_ = key_set_id;
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
SignedMessage signed_message;
EXPECT_TRUE(signed_message.ParseFromString(key_msg));
@@ -1830,7 +1841,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryOfflineKeyTest) {
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
CdmKeySetId key_set_id = key_set_id_;
EXPECT_FALSE(key_set_id_.empty());
@@ -1858,7 +1869,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryOfflineKeyTest) {
key_set_id_.clear();
GenerateKeyRelease(key_set_id);
key_set_id_ = key_set_id;
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
}
TEST_F(WvCdmRequestLicenseTest, ReleaseRetryL3OfflineKeyTest) {
@@ -1900,7 +1911,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryL3OfflineKeyTest) {
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
NULL, &session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline, &property_set);
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
CdmKeySetId key_set_id = key_set_id_;
EXPECT_FALSE(key_set_id_.empty());
@@ -1928,7 +1939,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryL3OfflineKeyTest) {
key_set_id_.clear();
GenerateKeyRelease(key_set_id, &property_set, NULL);
key_set_id_ = key_set_id;
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
}
TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) {
@@ -1943,7 +1954,7 @@ TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) {
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
CdmKeySetId key_set_id = key_set_id_;
EXPECT_FALSE(key_set_id_.empty());
@@ -1976,7 +1987,7 @@ TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) {
AllOf(Each(Pair(_, kKeyStatusExpired)), Not(IsEmpty())), false));
GenerateKeyRelease(key_set_id);
key_set_id_ = key_set_id;
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
decryptor_.CloseSession(restore_session_id);
}
@@ -1995,7 +2006,7 @@ TEST_F(WvCdmRequestLicenseTest, AutomatedOfflineSessionReleaseTest) {
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
CdmKeySetId key_set_id = key_set_id_;
EXPECT_FALSE(key_set_id_.empty());
@@ -2029,7 +2040,7 @@ TEST_F(WvCdmRequestLicenseTest, AutomatedOfflineSessionReleaseTest) {
open_sessions,
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS));
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
EXPECT_EQ(
--open_sessions,
@@ -2040,12 +2051,12 @@ TEST_F(WvCdmRequestLicenseTest, StreamingLicenseRenewal) {
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
std::string license_server;
GenerateRenewalRequest(kLicenseTypeStreaming, &license_server);
if (license_server.empty()) license_server = g_license_server;
VerifyKeyRequestResponse(license_server, g_client_auth, true);
VerifyKeyRequestResponse(license_server, g_client_auth);
decryptor_.CloseSession(session_id_);
}
@@ -2058,7 +2069,7 @@ TEST_F(WvCdmRequestLicenseTest, StreamingLicenseRenewalProhibited) {
"08011a0d7769646576696e655f746573" // pssh data
"74221073747265616d696e675f636c69703131");
GenerateKeyRequest(key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
std::string init_data;
wvcdm::CdmAppParameterMap app_parameters;
@@ -2084,12 +2095,12 @@ TEST_F(WvCdmRequestLicenseTest, OfflineLicenseRenewal) {
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
std::string license_server;
GenerateRenewalRequest(kLicenseTypeOffline, &license_server);
if (license_server.empty()) license_server = g_license_server;
VerifyKeyRequestResponse(license_server, client_auth, true);
VerifyKeyRequestResponse(license_server, client_auth);
decryptor_.CloseSession(session_id_);
}
@@ -2098,7 +2109,7 @@ TEST_F(WvCdmRequestLicenseTest, RemoveKeys) {
kDefaultCdmIdentifier, NULL,
&session_id_));
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
ASSERT_EQ(NO_ERROR, decryptor_.RemoveKeys(session_id_));
ASSERT_EQ(NO_ERROR, decryptor_.CloseSession(session_id_));
}
@@ -2217,7 +2228,7 @@ TEST_P(WvCdmStreamingLicenseRenewalTest, WithClientId) {
0u, license_renewal.encrypted_client_id().encrypted_client_id().size());
}
VerifyKeyRequestResponse(license_server, g_client_auth, true);
VerifyKeyRequestResponse(license_server, g_client_auth);
decryptor_.CloseSession(session_id_);
}
@@ -2359,7 +2370,7 @@ TEST_P(WvCdmOfflineLicenseReleaseTest, WithClientId) {
0u, license_release.encrypted_client_id().encrypted_client_id().size());
}
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
decryptor_.CloseSession(session_id_);
}
@@ -2414,7 +2425,7 @@ TEST_P(WvCdmUsageTest, WithClientId) {
&property_set);
std::string key_response;
VerifyKeyRequestResponse(g_license_server, g_client_auth, false,
VerifyKeyRequestResponse(g_license_server, g_client_auth, true,
&key_response);
// Validate signed license
@@ -2519,7 +2530,7 @@ TEST_F(WvCdmRequestLicenseTest, UsageInfoRetryTest) {
"747265616d696e675f636c697033");
GenerateKeyRequest(key_id, kLicenseTypeStreaming, NULL);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyUsageKeyRequestResponse(g_license_server, g_client_auth);
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
CdmDecryptionParameters decryption_parameters(
@@ -2611,7 +2622,12 @@ TEST_P(WvCdmUsageInfoTest, UsageInfo) {
key_id.append(1, ch);
GenerateKeyRequest(key_id, kLicenseTypeStreaming, property_set);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
// 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(
@@ -2691,7 +2707,12 @@ TEST_F(WvCdmRequestLicenseTest, UsageReleaseAllTest) {
key_id.append(1, ch);
GenerateKeyRequest(key_id, kLicenseTypeStreaming, &property_set);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
// 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(
@@ -2779,7 +2800,7 @@ TEST_F(WvCdmRequestLicenseTest, QueryKeyStatus) {
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
CdmQueryMap query_info;
CdmQueryMap::iterator itr;
@@ -3013,7 +3034,7 @@ TEST_F(WvCdmRequestLicenseTest, QueryOemCryptoSessionId) {
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
CdmQueryMap query_info;
CdmQueryMap::iterator itr;
@@ -3101,7 +3122,7 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) {
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
CdmKeySetId key_set_id = key_set_id_;
EXPECT_FALSE(key_set_id_.empty());
decryptor_.CloseSession(session_id_);
@@ -3140,7 +3161,7 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) {
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
decryptor_.CloseSession(session_id_);
if (security_level != kSecurityLevelL1) return;
@@ -3165,7 +3186,7 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) {
kDefaultCdmIdentifier, NULL,
&session_id_));
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, client_auth, false);
VerifyKeyRequestResponse(g_license_server, client_auth);
decryptor_.CloseSession(session_id_);
}
@@ -3173,7 +3194,7 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_OfflineLicenseDecryptionTest) {
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(g_key_id, kLicenseTypeOffline);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
/*
// key 1, encrypted, 256b
@@ -3227,7 +3248,7 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_RestoreOfflineLicenseDecryptionTest) {
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
&session_id_);
GenerateKeyRequest(g_key_id, kLicenseTypeOffline);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
CdmKeySetId key_set_id = key_set_id_;
EXPECT_FALSE(key_set_id_.empty());
decryptor_.CloseSession(session_id_);
@@ -3289,7 +3310,7 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_RestoreOfflineLicenseDecryptionTest) {
TEST_F(WvCdmRequestLicenseTest, KeyControlBlockDecryptionTest) {
decryptor_.OpenSession(g_key_system, &session_id_);
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
DecryptionData data;
@@ -3355,7 +3376,7 @@ TEST_P(WvCdmSessionSharingTest, SessionSharingTest) {
NULL, &session_id_);
CdmSessionId gp_session_id_1 = session_id_;
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
// TODO(rfrias): Move content information to ConfigTestEnv
std::string gp_client_auth2 =
@@ -3369,7 +3390,7 @@ TEST_P(WvCdmSessionSharingTest, SessionSharingTest) {
NULL, &session_id_);
CdmSessionId gp_session_id_2 = session_id_;
GenerateKeyRequest(gp_key_id2, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, gp_client_auth2, false);
VerifyKeyRequestResponse(g_license_server, gp_client_auth2);
SubSampleInfo* data = session_sharing_info->sub_sample;
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
@@ -3414,7 +3435,7 @@ TEST_F(WvCdmRequestLicenseTest, SessionSharingTest) {
NULL, &session_id_);
CdmSessionId session_id1 = session_id_;
GenerateKeyRequest(init_data1, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
// TODO(rfrias): Move content information to ConfigTestEnv
std::string gp_client_auth2 =
@@ -3428,7 +3449,7 @@ TEST_F(WvCdmRequestLicenseTest, SessionSharingTest) {
NULL, &session_id_);
CdmSessionId session_id2 = session_id_;
GenerateKeyRequest(init_data2, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, gp_client_auth2, false);
VerifyKeyRequestResponse(g_license_server, gp_client_auth2);
SubSampleInfo* data = &single_encrypted_sub_sample_short_expiry;
@@ -3450,7 +3471,7 @@ TEST_F(WvCdmRequestLicenseTest, SessionSharingTest) {
NULL, &session_id_);
CdmSessionId session_id3 = session_id_;
GenerateKeyRequest(init_data1, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id1, data->validate_key_id,
decryption_parameters));
@@ -3475,7 +3496,7 @@ TEST_F(WvCdmRequestLicenseTest, DecryptionKeyExpiredTest) {
&session_id_);
if (data->retrieve_key) {
GenerateKeyRequest(kCpKeyId, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
}
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
@@ -3516,7 +3537,7 @@ TEST_F(WvCdmRequestLicenseTest, SessionKeyChangeNotificationTest) {
"0801121030313233343536373839616263646566"); // pssh data
GenerateKeyRequest(kCpKeyId, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
decryptor_.CloseSession(session_id_);
}
@@ -3531,7 +3552,7 @@ TEST_P(WvCdmDecryptionTest, DecryptionTest) {
&session_id_);
if (data->retrieve_key) {
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
}
uint32_t decrypt_sample_buffer_size = 0;
@@ -3574,6 +3595,59 @@ INSTANTIATE_TEST_CASE_P(Cdm, WvCdmDecryptionTest,
&switch_key_encrypted_sub_samples[0],
&partial_encrypted_sub_samples[0]));
class WvCdmSessionSharingNoKeyTest
: public WvCdmRequestLicenseTest,
public ::testing::WithParamInterface<SubSampleInfo*> {};
TEST_P(WvCdmSessionSharingNoKeyTest, DecryptionTest) {
SubSampleInfo* data = GetParam();
TestWvCdmClientPropertySet property_set;
property_set.set_session_sharing_mode(true);
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
NULL, &session_id_);
CdmSessionId gp_session_id_1 = session_id_;
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
// TODO(rfrias): Move content information to ConfigTestEnv
std::string gp_client_auth2 =
"?source=YOUTUBE&video_id=z3S_NhwueaM&oauth=ya.gtsqawidevine";
std::string gp_key_id2 = wvcdm::a2bs_hex(
"000000347073736800000000" // blob size and pssh
"edef8ba979d64acea3c827dcd51d21ed00000014" // Widevine system id
"08011210bdf1cb4fffc6506b8b7945b0bd2917fb"); // pssh data
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
NULL, &session_id_);
CdmSessionId gp_session_id_2 = session_id_;
GenerateKeyRequest(gp_key_id2, kLicenseTypeStreaming);
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
CdmDecryptionParameters decryption_parameters(
&data->key_id, &data->encrypt_data.front(), data->encrypt_data.size(),
&data->iv, data->block_offset, &decrypt_buffer[0]);
decryption_parameters.is_encrypted = data->is_encrypted;
decryption_parameters.is_secure = data->is_secure;
decryption_parameters.subsample_flags = data->subsample_flags;
EXPECT_EQ(data->is_encrypted ? KEY_NOT_FOUND_IN_SESSION : NO_ERROR,
decryptor_.Decrypt(gp_session_id_2, data->validate_key_id,
decryption_parameters));
if (!data->is_encrypted) {
EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
decrypt_buffer.begin()));
}
decryptor_.CloseSession(gp_session_id_1);
decryptor_.CloseSession(gp_session_id_2);
}
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmSessionSharingNoKeyTest,
::testing::Values(&clear_sub_sample,
&clear_sub_sample_no_key,
&single_encrypted_sub_sample));
TEST(VersionNumberTest, VersionNumberChangeCanary) {
char release_number[PROPERTY_VALUE_MAX];
ASSERT_GT(property_get("ro.build.version.release", release_number, "Unknown"),
@@ -3599,7 +3673,7 @@ TEST_F(WvCdmRequestLicenseTest, AddHlsStreamingKeyTest) {
kLicenseTypeStreaming, NULL);
//TODO(rfrias): Remove once we switch to git-on-borg
std::string license_server = "https://proxy.uat.widevine.com/proxy";
VerifyKeyRequestResponse(license_server, g_client_auth, false);
VerifyKeyRequestResponse(license_server, g_client_auth);
decryptor_.CloseSession(session_id_);
}
@@ -3643,7 +3717,7 @@ TEST_P(WvHlsDecryptionTest, HlsDecryptionTest) {
kLicenseTypeStreaming, NULL);
//TODO(rfrias): Remove once we switch to git-on-borg
std::string license_server = "https://proxy.uat.widevine.com/proxy";
VerifyKeyRequestResponse(license_server, g_client_auth, false);
VerifyKeyRequestResponse(license_server, g_client_auth);
CdmKeyStatusMap key_status_map = listener.GetKeyStatusMap();
EXPECT_EQ(1u, key_status_map.size());
KeyId key_id = key_status_map.begin()->first;
@@ -3697,7 +3771,7 @@ TEST_P(WvHlsFourCCBackwardCompatibilityTest, HlsDecryptionTest) {
kLicenseTypeStreaming, NULL);
//TODO(rfrias): Remove once we switch to git-on-borg
std::string license_server = "https://proxy.uat.widevine.com/proxy";
VerifyKeyRequestResponse(license_server, g_client_auth, false);
VerifyKeyRequestResponse(license_server, g_client_auth);
CdmKeyStatusMap key_status_map = listener.GetKeyStatusMap();
EXPECT_EQ(1u, key_status_map.size());
KeyId key_id = key_status_map.begin()->first;

View File

@@ -476,7 +476,7 @@ status_t WVDrmPlugin::getPropertyString(const String8& name,
if (name == "vendor") {
value = "Google";
} else if (name == "version") {
value = "1.0";
return queryProperty(QUERY_KEY_WVCDM_VERSION, value);
} else if (name == "description") {
value = "Widevine CDM";
} else if (name == "algorithms") {
@@ -519,6 +519,10 @@ status_t WVDrmPlugin::getPropertyString(const String8& name,
value = mPropertySet.app_id().c_str();
} else if (name == "origin") {
value = mCdmIdentifier.origin.c_str();
} else if (name == "CurrentSRMVersion") {
return queryProperty(QUERY_KEY_CURRENT_SRM_VERSION, value);
} else if (name == "SRMUpdateSupport") {
return queryProperty(QUERY_KEY_SRM_UPDATE_SUPPORT, value);
} else {
ALOGE("App requested unknown string property %s", name.string());
return android::ERROR_DRM_CANNOT_HANDLE;
@@ -1005,6 +1009,11 @@ status_t WVDrmPlugin::mapOEMCryptoResult(OEMCryptoResult res) {
bool WVDrmPlugin::initDataResemblesPSSH(const Vector<uint8_t>& initData) {
const uint8_t* const initDataArray = initData.array();
if (sizeof(uint32_t) + kPsshTag.size() > initData.size()) {
// The init data is so small that it couldn't contain a size and PSSH tag.
return false;
}
// Extract the size field
const uint8_t* const sizeField = &initDataArray[0];
uint32_t nboSize;

View File

@@ -93,6 +93,7 @@ using wvcdm::KEY_ID_SIZE;
using wvcdm::KEY_IV_SIZE;
using wvcdm::KEY_SET_ID_PREFIX;
using wvcdm::NEVER_EXPIRES;
using wvcdm::QUERY_KEY_CURRENT_SRM_VERSION;
using wvcdm::QUERY_KEY_DEVICE_ID;
using wvcdm::QUERY_KEY_MAX_NUMBER_OF_SESSIONS;
using wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS;
@@ -100,7 +101,9 @@ using wvcdm::QUERY_KEY_OEMCRYPTO_API_VERSION;
using wvcdm::QUERY_KEY_OEMCRYPTO_SESSION_ID;
using wvcdm::QUERY_KEY_PROVISIONING_ID;
using wvcdm::QUERY_KEY_SECURITY_LEVEL;
using wvcdm::QUERY_KEY_SRM_UPDATE_SUPPORT;
using wvcdm::QUERY_KEY_SYSTEM_ID;
using wvcdm::QUERY_KEY_WVCDM_VERSION;
using wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1;
using wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3;
using wvcdm::SecurityLevel;
@@ -1045,6 +1048,11 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
static const std::string maxSessions = "54";
static const std::string oemCryptoApiVersion = "13";
static const std::string currentSRMVersion = "1";
static const std::string cdmVersion = "Infinity Minus 1";
std::string serializedMetrics(
kSerializedMetrics, kSerializedMetrics + sizeof(kSerializedMetrics));
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _))
.WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1),
testing::Return(wvcdm::NO_ERROR)))
@@ -1075,6 +1083,21 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
.WillOnce(DoAll(SetArgPointee<2>(oemCryptoApiVersion),
testing::Return(wvcdm::NO_ERROR)));
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SRM_UPDATE_SUPPORT, _))
.WillOnce(DoAll(SetArgPointee<2>("True"),
testing::Return(wvcdm::NO_ERROR)));
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_CURRENT_SRM_VERSION, _))
.WillOnce(DoAll(SetArgPointee<2>(currentSRMVersion),
testing::Return(wvcdm::NO_ERROR)));
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_WVCDM_VERSION, _))
.WillOnce(DoAll(SetArgPointee<2>(cdmVersion),
testing::Return(wvcdm::NO_ERROR)));
EXPECT_CALL(*cdm, GetSerializedMetrics(_))
.WillOnce(SetArgPointee<0>(serializedMetrics));
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false);
std::string stringResult;
std::vector<uint8_t> vectorResult;
@@ -1088,7 +1111,7 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
plugin.getPropertyString(
hidl_string("version"), [&](Status status, hidl_string stringResult) {
ASSERT_EQ(Status::OK, status);
EXPECT_STREQ("1.0", stringResult.c_str());
EXPECT_STREQ(cdmVersion.c_str(), stringResult.c_str());
});
plugin.getPropertyString(
@@ -1159,7 +1182,21 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
hidl_string("oemCryptoApiVersion"),
[&](Status status, hidl_string stringResult) {
ASSERT_EQ(Status::OK, status);
EXPECT_EQ(oemCryptoApiVersion, stringResult.c_str());
EXPECT_STREQ(oemCryptoApiVersion.c_str(), stringResult.c_str());
});
plugin.getPropertyString(
hidl_string("SRMUpdateSupport"),
[&](Status status, hidl_string stringResult) {
ASSERT_EQ(Status::OK, status);
EXPECT_STREQ("True", stringResult.c_str());
});
plugin.getPropertyString(
hidl_string("CurrentSRMVersion"),
[&](Status status, hidl_string stringResult) {
ASSERT_EQ(Status::OK, status);
EXPECT_STREQ(currentSRMVersion.c_str(), stringResult.c_str());
});
}

View File

@@ -838,6 +838,11 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
static const string maxSessions = "18";
static const string oemCryptoApiVersion = "10";
static const string currentSRMVersion = "1";
static const string cdmVersion = "Infinity Minus 1";
string serializedMetrics(kSerializedMetrics,
kSerializedMetrics + sizeof(kSerializedMetrics));
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _))
.WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1),
Return(wvcdm::NO_ERROR)))
@@ -868,6 +873,21 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
.WillOnce(DoAll(SetArgPointee<2>(oemCryptoApiVersion),
Return(wvcdm::NO_ERROR)));
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SRM_UPDATE_SUPPORT, _))
.WillOnce(DoAll(SetArgPointee<2>("True"),
testing::Return(wvcdm::NO_ERROR)));
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_CURRENT_SRM_VERSION, _))
.WillOnce(DoAll(SetArgPointee<2>(currentSRMVersion),
testing::Return(wvcdm::NO_ERROR)));
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_WVCDM_VERSION, _))
.WillOnce(DoAll(SetArgPointee<2>(cdmVersion),
Return(wvcdm::NO_ERROR)));
EXPECT_CALL(*cdm, GetSerializedMetrics(_))
.WillOnce(SetArgPointee<0>(serializedMetrics));
String8 stringResult;
Vector<uint8_t> vectorResult;
@@ -877,7 +897,7 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
res = plugin.getPropertyString(String8("version"), stringResult);
ASSERT_EQ(OK, res);
EXPECT_STREQ("1.0", stringResult.string());
EXPECT_STREQ(cdmVersion.c_str(), stringResult.string());
res = plugin.getPropertyString(String8("description"), stringResult);
ASSERT_EQ(OK, res);
@@ -918,7 +938,22 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
res = plugin.getPropertyString(String8("oemCryptoApiVersion"), stringResult);
ASSERT_EQ(OK, res);
EXPECT_EQ(oemCryptoApiVersion, stringResult.string());
EXPECT_STREQ(oemCryptoApiVersion.c_str(), stringResult.string());
res = plugin.getPropertyString(String8("SRMUpdateSupport"), stringResult);
ASSERT_EQ(OK, res);
EXPECT_STREQ("True", stringResult.string());
res = plugin.getPropertyString(String8("CurrentSRMVersion"), stringResult);
ASSERT_EQ(OK, res);
EXPECT_STREQ(currentSRMVersion.c_str(), stringResult.string());
vectorResult.clear();
res = plugin.getPropertyByteArray(String8("metrics"), vectorResult);
ASSERT_EQ(OK, res);
EXPECT_THAT(vectorResult, ElementsAreArray(serializedMetrics.data(),
serializedMetrics.size()));
}
TEST_F(WVDrmPluginTest, DoesNotGetUnknownProperties) {