Source release v2.1.4-0-804 + third_party libs

Change-Id: I1db8582efba613fa8a2b91a9c2697c5dfb2a8abf
This commit is contained in:
Joey Parrish
2014-07-02 09:27:29 -07:00
parent 84acd5a15e
commit 334525c8a5
22 changed files with 1090 additions and 271 deletions

View File

@@ -3,15 +3,16 @@
#ifndef WVCDM_CORE_CDM_ENGINE_H_
#define WVCDM_CORE_CDM_ENGINE_H_
#include "cdm_session.h"
#include "certificate_provisioning.h"
#include "initialization_data.h"
#include "oemcrypto_adapter.h"
#include "scoped_ptr.h"
#include "wv_cdm_types.h"
namespace wvcdm {
class CdmClientPropertySet;
class CdmSession;
class CryptoEngine;
class WvCdmEventListener;
@@ -121,8 +122,11 @@ class CdmEngine {
CdmReleaseKeySetMap release_key_sets_;
CertificateProvisioning cert_provisioning_;
SecurityLevel cert_provisioning_requested_security_level_;
CdmSession* usage_session_;
static bool seeded_;
// usage related variables
scoped_ptr<CdmSession> usage_session_;
int64_t last_usage_information_update_time;
CORE_DISALLOW_COPY_AND_ASSIGN(CdmEngine);

View File

@@ -31,11 +31,6 @@ class CdmSession {
virtual CdmResponseType RestoreUsageSession(
const CdmKeyMessage& key_request, const CdmKeyResponse& key_response);
virtual void set_key_system(const CdmKeySystem& ksystem) {
key_system_ = ksystem;
}
virtual const CdmKeySystem& key_system() { return key_system_; }
virtual const CdmSessionId& session_id() { return session_id_; }
virtual CdmResponseType GenerateKeyRequest(
@@ -99,6 +94,11 @@ class CdmSession {
}
private:
// Internal constructor
void Create(CdmLicense* license_parser, CryptoSession* crypto_session,
PolicyEngine* policy_engine, DeviceFiles* file_handle,
const CdmClientPropertySet* cdm_client_property_set);
// Generate unique ID for each new session.
CdmSessionId GenerateSessionId();
bool GenerateKeySetId(CdmKeySetId* key_set_id);
@@ -108,17 +108,18 @@ class CdmSession {
bool DeleteLicense();
// instance variables
const CdmSessionId session_id_;
CdmKeySystem key_system_;
CdmLicense license_parser_;
bool initialized_;
CdmSessionId session_id_;
scoped_ptr<CdmLicense> license_parser_;
scoped_ptr<CryptoSession> crypto_session_;
PolicyEngine policy_engine_;
scoped_ptr<PolicyEngine> policy_engine_;
scoped_ptr<DeviceFiles> file_handle_;
bool license_received_;
bool reinitialize_session_;
bool is_offline_;
bool is_release_;
bool is_usage_update_needed_;
bool is_initial_decryption_;
CdmSecurityLevel security_level_;
// information useful for offline and usage scenarios
CdmKeyMessage key_request_;
@@ -133,12 +134,18 @@ class CdmSession {
// license type release and offline related information
CdmKeySetId key_set_id_;
// Used for certificate based licensing
std::string wrapped_key_;
bool is_certificate_loaded_;
std::set<WvCdmEventListener*> listeners_;
// For testing only
// Takes ownership of license_parser, crypto_session, policy_engine
// and device_files
CdmSession(CdmLicense* license_parser, CryptoSession* crypto_session,
PolicyEngine* policy_engine, DeviceFiles* file_handle,
const CdmClientPropertySet* cdm_client_property_set);
#if defined(UNIT_TEST)
friend class CdmSessionTest;
#endif
CORE_DISALLOW_COPY_AND_ASSIGN(CdmSession);
};

View File

@@ -25,6 +25,7 @@ class CryptoSession {
virtual bool GetToken(std::string* token);
virtual CdmSecurityLevel GetSecurityLevel();
virtual bool GetDeviceUniqueId(std::string* device_id);
virtual bool GetApiVersion(uint32_t* version);
virtual bool GetSystemId(uint32_t* system_id);
virtual bool GetProvisioningId(std::string* provisioning_id);

View File

@@ -3,6 +3,7 @@
#ifndef WVCDM_CORE_DEVICE_FILES_H_
#define WVCDM_CORE_DEVICE_FILES_H_
#include "scoped_ptr.h"
#include "wv_cdm_types.h"
#if defined(UNIT_TEST)
@@ -21,11 +22,13 @@ class DeviceFiles {
kLicenseStateUnknown,
} LicenseState;
DeviceFiles(): file_(NULL), security_level_(kSecurityLevelUninitialized),
initialized_(false), test_file_(false) {}
DeviceFiles();
virtual ~DeviceFiles();
virtual bool Init(CdmSecurityLevel security_level);
virtual bool Reset(CdmSecurityLevel security_level) {
return Init(security_level);
}
virtual bool StoreCertificate(const std::string& certificate,
const std::string& wrapped_private_key);
@@ -93,7 +96,7 @@ class DeviceFiles {
FRIEND_TEST(WvCdmUsageInfoTest, DISABLED_UsageInfo);
#endif
File* file_;
scoped_ptr<File> file_;
CdmSecurityLevel security_level_;
bool initialized_;

View File

@@ -60,6 +60,7 @@ class PolicyEngine {
private:
typedef enum {
kLicenseStateInitial,
kLicenseStatePending, // if license is issued for sometime in the future
kLicenseStateCanPlay,
kLicenseStateNeedRenewal,
kLicenseStateWaitingLicenseUpdate,
@@ -91,18 +92,14 @@ class PolicyEngine {
// from the license server we will get an updated id field.
video_widevine_server::sdk::LicenseIdentification license_id_;
// This is the license start time that gets sent from the server in each
// license request or renewal.
// The server returns the license start time in the license/license renewal
// response based off the request time sent by the client in the
// license request/renewal
int64_t license_start_time_;
// This is the time at which the license was received and playback was
// started. These times are based off the local clock in case there is a
// discrepency between local and server time.
int64_t license_received_time_;
int64_t playback_start_time_;
// This is used as a reference point for policy management. This value
// represents an offset from license_received_time_. This is used to
// represents an offset from license_start_time_. This is used to
// calculate the time where renewal retries should occur.
int64_t next_renewal_time_;
int64_t policy_max_duration_seconds_;

View File

@@ -87,6 +87,14 @@ class Properties {
security_level_path_backward_compatibility_support_ = flag;
}
#if defined(UNIT_TEST)
FRIEND_TEST(CdmSessionTest, InitWithCertificate);
FRIEND_TEST(CdmSessionTest, InitWithKeybox);
FRIEND_TEST(CdmSessionTest, ReInitFail);
FRIEND_TEST(CdmSessionTest, InitFailCryptoError);
FRIEND_TEST(CdmSessionTest, InitNeedsProvisioning);
#endif
private:
static bool oem_crypto_use_secure_buffers_;
static bool oem_crypto_use_fifo_;

View File

@@ -2,6 +2,8 @@
#include "cdm_engine.h"
#include <stdlib.h>
#include <iostream>
#include <sstream>
@@ -18,22 +20,26 @@
namespace {
const uint32_t kUpdateUsageInformationPeriod = 60; // seconds
const size_t kMinNoncesPerSession = 4;
const size_t kUsageReportsPerRequest = 1;
} // unnamed namespace
namespace wvcdm {
bool CdmEngine::seeded_ = false;
CdmEngine::CdmEngine()
: cert_provisioning_requested_security_level_(kLevelDefault),
usage_session_(NULL),
last_usage_information_update_time(0) {
Properties::Init();
if (!seeded_) {
Clock clock;
srand(clock.GetCurrentTime());
seeded_ = true;
}
}
CdmEngine::~CdmEngine() {
if (NULL != usage_session_)
delete usage_session_;
CdmSessionMap::iterator i(sessions_.begin());
for (; i != sessions_.end(); ++i) {
delete i->second;
@@ -505,9 +511,7 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
}
CdmResponseType CdmEngine::GetUsageInfo(CdmUsageInfo* usage_info) {
if (NULL == usage_session_) {
usage_session_ = new CdmSession(NULL);
}
usage_session_.reset(new CdmSession(NULL));
CdmResponseType status = usage_session_->Init();
if (NO_ERROR != status) {
@@ -533,35 +537,32 @@ CdmResponseType CdmEngine::GetUsageInfo(CdmUsageInfo* usage_info) {
}
std::string server_url;
// rate limit secure stop messages based on minimum nonce
// table size per session
usage_info->resize(license_info.size() >= kMinNoncesPerSession - 1
? kMinNoncesPerSession - 1
: license_info.size());
for (size_t i = 0; i < usage_info->size(); ++i) {
status = usage_session_->RestoreUsageSession(license_info[i].first,
license_info[i].second);
if (KEY_ADDED != status) {
LOGE("CdmEngine::GetUsageInfo: restore usage session error: %ld",
status);
usage_info->clear();
return status;
}
status = usage_session_->GenerateReleaseRequest(&(*usage_info)[i],
&server_url);
if (KEY_MESSAGE != status) {
LOGE("CdmEngine::GetUsageInfo: generate release request error: %ld",
status);
usage_info->clear();
return status;
}
usage_info->resize(kUsageReportsPerRequest);
uint32_t index = rand() % license_info.size();
status = usage_session_->RestoreUsageSession(license_info[index].first,
license_info[index].second);
if (KEY_ADDED != status) {
LOGE("CdmEngine::GetUsageInfo: restore usage session (%d) error %ld",
index, status);
usage_info->clear();
return status;
}
status = usage_session_->GenerateReleaseRequest(&(*usage_info)[0], &server_url);
if (KEY_MESSAGE != status) {
LOGE("CdmEngine::GetUsageInfo: generate release request error: %ld",
status);
usage_info->clear();
return status;
}
return KEY_MESSAGE;
}
CdmResponseType CdmEngine::ReleaseUsageInfo(
const CdmUsageInfoReleaseMessage& message) {
if (NULL == usage_session_) {
if (NULL == usage_session_.get()) {
LOGE("CdmEngine::ReleaseUsageInfo: cdm session not initialized");
return UNKNOWN_ERROR;
}
@@ -569,9 +570,8 @@ CdmResponseType CdmEngine::ReleaseUsageInfo(
CdmResponseType status = usage_session_->ReleaseKey(message);
if (NO_ERROR != status) {
LOGE("CdmEngine::ReleaseUsageInfo: release key error: %ld", status);
return UNKNOWN_ERROR;
}
return NO_ERROR;
return status;
}
CdmResponseType CdmEngine::Decrypt(

View File

@@ -7,7 +7,6 @@
#include <stdlib.h>
#include "cdm_engine.h"
#include "clock.h"
#include "crypto_session.h"
#include "device_files.h"
#include "file_store.h"
@@ -25,16 +24,56 @@ namespace wvcdm {
typedef std::set<WvCdmEventListener*>::iterator CdmEventListenerIter;
CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set)
: session_id_(GenerateSessionId()),
crypto_session_(NULL),
license_received_(false),
reinitialize_session_(false),
is_offline_(false),
is_release_(false),
is_usage_update_needed_(false),
is_initial_decryption_(true),
is_certificate_loaded_(false) {
CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set) {
Create(new CdmLicense(), new CryptoSession(), new PolicyEngine(),
new DeviceFiles(), cdm_client_property_set);
}
CdmSession::CdmSession(
CdmLicense* license_parser,
CryptoSession* crypto_session,
PolicyEngine* policy_engine,
DeviceFiles* file_handle,
const CdmClientPropertySet* cdm_client_property_set) {
Create(license_parser, crypto_session, policy_engine, file_handle,
cdm_client_property_set);
}
void CdmSession::Create(
CdmLicense* license_parser,
CryptoSession* crypto_session,
PolicyEngine* policy_engine,
DeviceFiles* file_handle,
const CdmClientPropertySet* cdm_client_property_set) {
// Just return on failures. Failures will be signaled in Init.
if (NULL == license_parser) {
LOGE("CdmSession::Create: License parser not provided");
return;
}
if (NULL == crypto_session) {
LOGE("CdmSession::Create: Crypto session not provided");
return;
}
if (NULL == policy_engine) {
LOGE("CdmSession::Create: Policy engine not provided");
return;
}
if (NULL == file_handle) {
LOGE("CdmSession::Create: Device files not provided");
return;
}
initialized_ = false;
session_id_ = GenerateSessionId();
license_parser_.reset(license_parser);
crypto_session_.reset(crypto_session);
file_handle_.reset(file_handle);
policy_engine_.reset(policy_engine);
license_received_ = false;
is_offline_ = false;
is_release_ = false;
is_usage_update_needed_ = false;
is_initial_decryption_ = true;
security_level_ = crypto_session_.get()->GetSecurityLevel();
if (cdm_client_property_set) {
Properties::AddSessionPropertySet(session_id_, cdm_client_property_set);
}
@@ -43,29 +82,36 @@ CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set)
CdmSession::~CdmSession() { Properties::RemoveSessionPropertySet(session_id_); }
CdmResponseType CdmSession::Init() {
scoped_ptr<CryptoSession> session(new CryptoSession());
CdmResponseType sts = session->Open(GetRequestedSecurityLevel());
if (session_id_.empty()) {
LOGE("CdmSession::Init: Failed, session not properly constructed");
return UNKNOWN_ERROR;
}
if (initialized_) {
LOGE("CdmSession::Init: Failed due to previous initialization");
return UNKNOWN_ERROR;
}
CdmResponseType sts = crypto_session_->Open(GetRequestedSecurityLevel());
if (NO_ERROR != sts) return sts;
std::string token;
if (Properties::use_certificates_as_identification()) {
DeviceFiles handle;
if (!handle.Init(session.get()->GetSecurityLevel()) ||
!handle.RetrieveCertificate(&token, &wrapped_key_)) {
std::string wrapped_key;
if (!file_handle_->Init(security_level_) ||
!file_handle_->RetrieveCertificate(&token, &wrapped_key) ||
!crypto_session_->LoadCertificatePrivateKey(wrapped_key)) {
return NEED_PROVISIONING;
}
} else {
if (!session->GetToken(&token)) return UNKNOWN_ERROR;
if (!crypto_session_->GetToken(&token)) return UNKNOWN_ERROR;
}
if (!license_parser_.Init(token, session.get(), &policy_engine_))
if (!license_parser_->Init(token, crypto_session_.get(),
policy_engine_.get()))
return UNKNOWN_ERROR;
crypto_session_.reset(session.release());
license_received_ = false;
reinitialize_session_ = false;
is_initial_decryption_ = true;
initialized_ = true;
return NO_ERROR;
}
@@ -74,17 +120,17 @@ CdmResponseType CdmSession::RestoreOfflineSession(
key_set_id_ = key_set_id;
// Retrieve license information from persistent store
DeviceFiles handle;
if (!handle.Init(crypto_session_->GetSecurityLevel()))
if (!file_handle_->Reset(security_level_))
return UNKNOWN_ERROR;
DeviceFiles::LicenseState license_state;
if (!handle.RetrieveLicense(key_set_id, &license_state, &offline_init_data_,
&key_request_, &key_response_,
&offline_key_renewal_request_,
&offline_key_renewal_response_,
&offline_release_server_url_)) {
if (!file_handle_->RetrieveLicense(key_set_id, &license_state,
&offline_init_data_,
&key_request_, &key_response_,
&offline_key_renewal_request_,
&offline_key_renewal_response_,
&offline_release_server_url_)) {
LOGE("CdmSession::Init failed to retrieve license. key set id = %s",
key_set_id.c_str());
return UNKNOWN_ERROR;
@@ -95,17 +141,8 @@ CdmResponseType CdmSession::RestoreOfflineSession(
return UNKNOWN_ERROR;
}
if (Properties::use_certificates_as_identification()) {
if (is_certificate_loaded_ ||
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
is_certificate_loaded_ = true;
} else {
return NEED_PROVISIONING;
}
}
if (!license_parser_.RestoreOfflineLicense(key_request_, key_response_,
offline_key_renewal_response_)) {
if (!license_parser_->RestoreOfflineLicense(key_request_, key_response_,
offline_key_renewal_response_)) {
return UNKNOWN_ERROR;
}
@@ -121,16 +158,8 @@ CdmResponseType CdmSession::RestoreUsageSession(
key_request_ = key_request;
key_response_ = key_response;
if (Properties::use_certificates_as_identification()) {
if (is_certificate_loaded_ ||
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
is_certificate_loaded_ = true;
} else {
return NEED_PROVISIONING;
}
}
if (!license_parser_.RestoreUsageLicense(key_request_, key_response_)) {
if (!license_parser_->RestoreUsageLicense(key_request_, key_response_)) {
return UNKNOWN_ERROR;
}
@@ -144,14 +173,6 @@ CdmResponseType CdmSession::GenerateKeyRequest(
const InitializationData& init_data, const CdmLicenseType license_type,
const CdmAppParameterMap& app_parameters, CdmKeyMessage* key_request,
std::string* server_url) {
if (reinitialize_session_) {
CdmResponseType sts = Init();
if (sts != NO_ERROR) {
LOGW("CdmSession::GenerateKeyRequest: Reinitialization failed");
return sts;
}
}
if (crypto_session_.get() == NULL) {
LOGW("CdmSession::GenerateKeyRequest: Invalid crypto session");
return UNKNOWN_ERROR;
@@ -182,24 +203,14 @@ CdmResponseType CdmSession::GenerateKeyRequest(
init_data.type().c_str());
return KEY_ERROR;
}
if (init_data.IsEmpty() && !license_parser_.HasInitData()) {
if (init_data.IsEmpty() && !license_parser_->HasInitData()) {
LOGW("CdmSession::GenerateKeyRequest: init data absent");
return KEY_ERROR;
}
if (Properties::use_certificates_as_identification()) {
if (is_certificate_loaded_ ||
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
is_certificate_loaded_ = true;
} else {
reinitialize_session_ = true;
return NEED_PROVISIONING;
}
}
if (!license_parser_.PrepareKeyRequest(init_data, license_type,
app_parameters, session_id_,
key_request, server_url)) {
if (!license_parser_->PrepareKeyRequest(init_data, license_type,
app_parameters, session_id_,
key_request, server_url)) {
return KEY_ERROR;
}
@@ -227,18 +238,19 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response,
}
if (is_release_) {
return ReleaseKey(key_response);
CdmResponseType sts = ReleaseKey(key_response);
return (NO_ERROR == sts) ? KEY_ADDED : sts;
} else if (license_received_) { // renewal
return RenewKey(key_response);
} else {
CdmResponseType sts = license_parser_.HandleKeyResponse(key_response);
CdmResponseType sts = license_parser_->HandleKeyResponse(key_response);
if (sts != KEY_ADDED) return sts;
license_received_ = true;
key_response_ = key_response;
if (is_offline_ || !license_parser_.provider_session_token().empty()) {
if (is_offline_ || !license_parser_->provider_session_token().empty()) {
sts = StoreLicense();
if (sts != NO_ERROR) return sts;
}
@@ -281,7 +293,7 @@ CdmResponseType CdmSession::QueryStatus(CdmQueryMap* key_info) {
}
CdmResponseType CdmSession::QueryKeyStatus(CdmQueryMap* key_info) {
return policy_engine_.Query(key_info);
return policy_engine_->Query(key_info);
}
CdmResponseType CdmSession::QueryKeyControlInfo(CdmQueryMap* key_info) {
@@ -316,12 +328,12 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
if (NO_ERROR == status) {
if (is_initial_decryption_) {
policy_engine_.BeginDecryption();
policy_engine_->BeginDecryption();
is_initial_decryption_ = false;
}
if (!is_usage_update_needed_) {
is_usage_update_needed_ =
!license_parser_.provider_session_token().empty();
!license_parser_->provider_session_token().empty();
}
}
@@ -333,7 +345,8 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
// session keys.
CdmResponseType CdmSession::GenerateRenewalRequest(CdmKeyMessage* key_request,
std::string* server_url) {
if (!license_parser_.PrepareKeyUpdateRequest(true, key_request, server_url)) {
if (!license_parser_->PrepareKeyUpdateRequest(true, key_request,
server_url)) {
LOGE("CdmSession::GenerateRenewalRequest: ERROR on prepare");
return KEY_ERROR;
}
@@ -347,7 +360,7 @@ CdmResponseType CdmSession::GenerateRenewalRequest(CdmKeyMessage* key_request,
// RenewKey() - Accept renewal response and update key info.
CdmResponseType CdmSession::RenewKey(const CdmKeyResponse& key_response) {
CdmResponseType sts =
license_parser_.HandleKeyUpdateResponse(true, key_response);
license_parser_->HandleKeyUpdateResponse(true, key_response);
if (sts != KEY_ADDED) return sts;
if (is_offline_) {
@@ -360,7 +373,7 @@ CdmResponseType CdmSession::RenewKey(const CdmKeyResponse& key_response) {
CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyMessage* key_request,
std::string* server_url) {
is_release_ = true;
if (!license_parser_.PrepareKeyUpdateRequest(false, key_request, server_url))
if (!license_parser_->PrepareKeyUpdateRequest(false, key_request, server_url))
return UNKNOWN_ERROR;
if (is_offline_) { // Mark license as being released
@@ -372,19 +385,19 @@ CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyMessage* key_request,
// ReleaseKey() - Accept release response and release license.
CdmResponseType CdmSession::ReleaseKey(const CdmKeyResponse& key_response) {
CdmResponseType sts = license_parser_.HandleKeyUpdateResponse(false,
CdmResponseType sts = license_parser_->HandleKeyUpdateResponse(false,
key_response);
if (NO_ERROR != sts)
if (KEY_ADDED != sts)
return sts;
if (is_offline_ || !license_parser_.provider_session_token().empty()) {
if (is_offline_ || !license_parser_->provider_session_token().empty()) {
DeleteLicense();
}
return NO_ERROR;
}
bool CdmSession::IsKeyLoaded(const KeyId& key_id) {
return license_parser_.IsKeyLoaded(key_id);
return license_parser_->IsKeyLoaded(key_id);
}
CdmSessionId CdmSession::GenerateSessionId() {
@@ -401,8 +414,7 @@ bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) {
std::vector<uint8_t> random_data(
(kKeySetIdLength - sizeof(KEY_SET_ID_PREFIX)) / 2, 0);
DeviceFiles handle;
if (!handle.Init(crypto_session_->GetSecurityLevel()))
if (!file_handle_->Reset(security_level_))
return false;
while (key_set_id->empty()) {
@@ -412,7 +424,7 @@ bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) {
*key_set_id = KEY_SET_ID_PREFIX + b2a_hex(random_data);
// key set collision
if (handle.LicenseExists(*key_set_id)) {
if (file_handle_->LicenseExists(*key_set_id)) {
key_set_id->clear();
}
}
@@ -440,20 +452,20 @@ CdmResponseType CdmSession::StoreLicense() {
return NO_ERROR;
}
std::string provider_session_token = license_parser_.provider_session_token();
std::string provider_session_token =
license_parser_->provider_session_token();
if (provider_session_token.empty()) {
LOGE("CdmSession::StoreLicense: No provider session token and not offline");
return UNKNOWN_ERROR;
}
DeviceFiles handle;
if (!handle.Init(crypto_session_->GetSecurityLevel())) {
if (!file_handle_->Reset(security_level_)) {
LOGE("CdmSession::StoreLicense: Unable to initialize device files");
return UNKNOWN_ERROR;
}
if (!handle.StoreUsageInfo(provider_session_token, key_request_,
key_response_)) {
if (!file_handle_->StoreUsageInfo(provider_session_token, key_request_,
key_response_)) {
LOGE("CdmSession::StoreLicense: Unable to store usage info");
return UNKNOWN_ERROR;
}
@@ -461,31 +473,29 @@ CdmResponseType CdmSession::StoreLicense() {
}
bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) {
DeviceFiles handle;
if (!handle.Init(crypto_session_->GetSecurityLevel()))
if (!file_handle_->Reset(security_level_))
return false;
return handle.StoreLicense(
return file_handle_->StoreLicense(
key_set_id_, state, offline_init_data_, key_request_,
key_response_, offline_key_renewal_request_,
offline_key_renewal_response_, offline_release_server_url_);
}
bool CdmSession::DeleteLicense() {
if (!is_offline_ && license_parser_.provider_session_token().empty())
if (!is_offline_ && license_parser_->provider_session_token().empty())
return false;
DeviceFiles handle;
if (!handle.Init(crypto_session_->GetSecurityLevel())) {
if (!file_handle_->Reset(security_level_)) {
LOGE("CdmSession::DeleteLicense: Unable to initialize device files");
return false;
}
if (is_offline_)
return handle.DeleteLicense(key_set_id_);
return file_handle_->DeleteLicense(key_set_id_);
else
return handle.DeleteUsageInfo(
license_parser_.provider_session_token());
return file_handle_->DeleteUsageInfo(
license_parser_->provider_session_token());
}
bool CdmSession::AttachEventListener(WvCdmEventListener* listener) {
@@ -501,7 +511,7 @@ void CdmSession::OnTimerEvent() {
bool event_occurred = false;
CdmEventType event;
policy_engine_.OnTimerEvent(&event_occurred, &event);
policy_engine_->OnTimerEvent(&event_occurred, &event);
if (event_occurred) {
for (CdmEventListenerIter iter = listeners_.begin();

View File

@@ -159,6 +159,25 @@ bool CryptoSession::GetDeviceUniqueId(std::string* device_id) {
return true;
}
bool CryptoSession::GetApiVersion(uint32_t* version) {
if (!version) {
LOGE("CryptoSession::GetApiVersion: No buffer passed to method.");
return false;
}
if (!initialized_) {
return false;
}
CdmSecurityLevel level = GetSecurityLevel();
SecurityLevel security_level = kLevelDefault;
if (kSecurityLevelL3 == level) security_level = kLevel3;
LOGV("CryptoSession::GetApiVersion: Lock");
AutoLock auto_lock(crypto_lock_);
*version = OEMCrypto_APIVersion(security_level);
return true;
}
bool CryptoSession::GetSystemId(uint32_t* system_id) {
if (!system_id) {
LOGE("CryptoSession::GetSystemId : No buffer passed to method.");

View File

@@ -55,8 +55,13 @@ bool Hash(const std::string& data, std::string* hash) {
namespace wvcdm {
DeviceFiles::DeviceFiles()
: file_(NULL), security_level_(kSecurityLevelUninitialized),
initialized_(false), test_file_(false) {
}
DeviceFiles::~DeviceFiles() {
if (!file_ && !test_file_) delete file_;
if (test_file_) file_.release();
}
bool DeviceFiles::Init(CdmSecurityLevel security_level) {
@@ -69,7 +74,7 @@ bool DeviceFiles::Init(CdmSecurityLevel security_level) {
LOGW("DeviceFiles::Init: Unsupported security level %d", security_level);
return false;
}
file_ = new File();
if (!test_file_) file_.reset(new File());
security_level_ = security_level;
initialized_ = true;
return true;
@@ -363,18 +368,13 @@ bool DeviceFiles::DeleteUsageInfo(const std::string& provider_session_token) {
return false;
}
UsageInfo* updated_info = file.mutable_usage_info();
UsageInfo info(*(const_cast<const UsageInfo*>(updated_info)));
updated_info->clear_sessions();
UsageInfo* usage_info = file.mutable_usage_info();
int index = 0;
bool found = false;
for (int i = 0; i < info.sessions_size(); ++i) {
if (info.sessions(i).token().compare(provider_session_token) == 0) {
for (; index < usage_info->sessions_size(); ++index) {
if (usage_info->sessions(index).token().compare(provider_session_token) == 0) {
found = true;
} else {
updated_info->add_sessions()->set_token(info.sessions(i).token());
updated_info->add_sessions()->set_license_request(
info.sessions(i).license_request());
updated_info->add_sessions()->set_license(info.sessions(i).license());
break;
}
}
@@ -384,6 +384,13 @@ bool DeviceFiles::DeleteUsageInfo(const std::string& provider_session_token) {
return false;
}
google::protobuf::RepeatedPtrField<UsageInfo_ProviderSession>* sessions =
usage_info->mutable_sessions();
if (index < usage_info->sessions_size() - 1) {
sessions->SwapElements(index, usage_info->sessions_size() - 1);
}
sessions->RemoveLast();
file.SerializeToString(&serialized_file);
return StoreFile(kUsageInfoFileName, serialized_file);
}
@@ -452,7 +459,7 @@ bool DeviceFiles::RetrieveUsageInfo(std::vector<
bool DeviceFiles::StoreFile(const char* name,
const std::string& serialized_file) {
if (!file_) {
if (!file_.get()) {
LOGW("DeviceFiles::StoreFile: Invalid file handle");
return false;
}
@@ -512,7 +519,7 @@ bool DeviceFiles::StoreFile(const char* name,
}
bool DeviceFiles::RetrieveFile(const char* name, std::string* serialized_file) {
if (!file_) {
if (!file_.get()) {
LOGW("DeviceFiles::RetrieveFile: Invalid file handle");
return false;
}
@@ -661,8 +668,7 @@ std::string DeviceFiles::GetUsageInfoFileName() {
}
void DeviceFiles::SetTestFile(File* file) {
if (file_) delete file_;
file_ = file;
file_.reset(file);
test_file_ = true;
}

View File

@@ -4,6 +4,7 @@
#include <vector>
#include "clock.h"
#include "crypto_key.h"
#include "crypto_session.h"
#include "device_files.h"
@@ -22,6 +23,7 @@ std::string kDeviceNameKey = "device_name";
std::string kProductNameKey = "product_name";
std::string kBuildInfoKey = "build_info";
std::string kDeviceIdKey = "device_id";
std::string kOemCryptoApiVersion = "oemcrypto_api_version";
const unsigned char kServiceCertificateCAPublicKey[] = {
0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81,
0x00, 0xb4, 0xfe, 0x39, 0xc3, 0x65, 0x90, 0x03,
@@ -254,12 +256,17 @@ bool CdmLicense::PrepareKeyRequest(const InitializationData& init_data,
client_info->set_name(kBuildInfoKey);
client_info->set_value(value);
}
if (session_->GetDeviceUniqueId(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kDeviceIdKey);
client_info->set_value(value);
}
uint32_t version = 0;
if (session_->GetApiVersion(&version)) {
client_info = client_id->add_client_info();
client_info->set_name(kOemCryptoApiVersion);
client_info->set_value(UintToString(version));
}
if (privacy_mode_enabled) {
EncryptedClientIdentification* encrypted_client_id =
@@ -353,12 +360,11 @@ bool CdmLicense::PrepareKeyRequest(const InitializationData& init_data,
return false;
}
// The time field will be updated once the cdm wrapper
// has been updated to pass us in the time.
license_request.set_request_time(0);
license_request.set_type(LicenseRequest::NEW);
Clock clock;
license_request.set_request_time(clock.GetCurrentTime());
// Get/set the nonce. This value will be reflected in the Key Control Block
// of the license response.
uint32_t nonce;
@@ -424,6 +430,9 @@ bool CdmLicense::PrepareKeyUpdateRequest(bool is_renewal,
else
license_request.set_type(LicenseRequest::RELEASE);
Clock clock;
license_request.set_request_time(clock.GetCurrentTime());
LicenseRequest_ContentIdentification_ExistingLicense* current_license =
license_request.mutable_content_id()->mutable_license();
LicenseIdentification license_id = policy_engine_->license_id();
@@ -432,8 +441,9 @@ bool CdmLicense::PrepareKeyUpdateRequest(bool is_renewal,
if (!is_renewal) {
if (license_id.has_provider_session_token()) {
std::string usage_report;
if (!session_->GenerateUsageReport(license_id.provider_session_token(),
&usage_report)) {
if (NO_ERROR !=
session_->GenerateUsageReport(license_id.provider_session_token(),
&usage_report)) {
return false;
}
current_license->set_session_usage_table_entry(usage_report);
@@ -560,7 +570,6 @@ CdmResponseType CdmLicense::HandleKeyResponse(
return KEY_ERROR;
}
std::string provider_session_token;
if (license.id().has_provider_session_token())
provider_session_token_ = license.id().provider_session_token();
@@ -575,7 +584,7 @@ CdmResponseType CdmLicense::HandleKeyResponse(
mac_key_iv,
mac_key,
key_array,
provider_session_token);
provider_session_token_);
if (KEY_ADDED == resp) {
loaded_keys_.clear();
@@ -627,24 +636,23 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
return KEY_ERROR;
}
if (is_renewal) {
if (license.policy().has_renewal_server_url() &&
license.policy().renewal_server_url().size() > 0) {
server_url_ = license.policy().renewal_server_url();
}
}
else {
if (license.id().has_provider_session_token()) {
provider_session_token_ = license.id().provider_session_token();
session_->ReleaseUsageInformation(signed_response.msg(),
signed_response.signature(),
provider_session_token_);
}
}
policy_engine_->UpdateLicense(license);
if (!is_renewal) return KEY_ADDED;
if (!is_renewal) {
if (!license.id().has_provider_session_token()) return KEY_ADDED;
provider_session_token_ = license.id().provider_session_token();
CdmResponseType status =
session_->ReleaseUsageInformation(signed_response.msg(),
signed_response.signature(),
provider_session_token_);
return (NO_ERROR == status) ? KEY_ADDED : status;
}
if (license.policy().has_renewal_server_url() &&
license.policy().renewal_server_url().size() > 0) {
server_url_ = license.policy().renewal_server_url();
}
std::vector<CryptoKey> key_array = ExtractContentKeys(license);

View File

@@ -33,7 +33,6 @@ void PolicyEngine::Init(Clock* clock) {
license_state_ = kLicenseStateInitial;
can_decrypt_ = false;
license_start_time_ = 0;
license_received_time_ = 0;
playback_start_time_ = 0;
next_renewal_time_ = 0;
policy_max_duration_seconds_ = 0;
@@ -76,6 +75,14 @@ void PolicyEngine::OnTimerEvent(bool* event_occurred, CdmEventType* event) {
break;
}
case kLicenseStatePending: {
if (current_time >= license_start_time_) {
license_state_ = kLicenseStateCanPlay;
can_decrypt_ = true;
}
break;
}
case kLicenseStateInitial:
case kLicenseStateExpired: {
break;
@@ -115,13 +122,11 @@ void PolicyEngine::UpdateLicense(
policy_.MergeFrom(license.policy());
// some basic license validation
if (license_state_ == kLicenseStateInitial) {
// license start time needs to be present in the initial response
if (!license.has_license_start_time())
return;
}
else {
// if renewal, discard license if version has not been updated
// license start time needs to be specified in the initial response
if (!license.has_license_start_time()) return;
// if renewal, discard license if version has not been updated
if (license_state_ != kLicenseStateInitial) {
if (license.id().version() > license_id_.version())
license_id_.CopyFrom(license.id());
else
@@ -129,12 +134,8 @@ void PolicyEngine::UpdateLicense(
}
// Update time information
int64_t current_time = clock_->GetCurrentTime();
if (license.has_license_start_time())
license_start_time_ = license.license_start_time();
license_received_time_ = current_time;
next_renewal_time_ = current_time +
policy_.renewal_delay_seconds();
license_start_time_ = license.license_start_time();
next_renewal_time_ = license_start_time_ + policy_.renewal_delay_seconds();
// Calculate policy_max_duration_seconds_. policy_max_duration_seconds_
// will be set to the minimum of the following policies :
@@ -157,12 +158,18 @@ void PolicyEngine::UpdateLicense(
return;
}
int64_t current_time = clock_->GetCurrentTime();
if (IsLicenseDurationExpired(current_time)) return;
if (IsPlaybackDurationExpired(current_time)) return;
// Update state
license_state_ = kLicenseStateCanPlay;
can_decrypt_ = true;
if (current_time >= license_start_time_) {
license_state_ = kLicenseStateCanPlay;
can_decrypt_ = true;
} else {
license_state_ = kLicenseStatePending;
can_decrypt_ = false;
}
}
void PolicyEngine::BeginDecryption() {
@@ -178,6 +185,7 @@ void PolicyEngine::BeginDecryption() {
}
break;
case kLicenseStateInitial:
case kLicenseStatePending:
case kLicenseStateExpired:
default:
break;
@@ -221,7 +229,7 @@ void PolicyEngine::UpdateRenewalRequest(int64_t current_time) {
// will always return false if the value is 0.
bool PolicyEngine::IsLicenseDurationExpired(int64_t current_time) {
return policy_max_duration_seconds_ &&
license_received_time_ + policy_max_duration_seconds_ <=
license_start_time_ + policy_max_duration_seconds_ <=
current_time;
}
@@ -229,9 +237,12 @@ int64_t PolicyEngine::GetLicenseDurationRemaining(int64_t current_time) {
if (0 == policy_max_duration_seconds_) return LLONG_MAX;
int64_t remaining_time = policy_max_duration_seconds_
+ license_received_time_ - current_time;
+ license_start_time_ - current_time;
if (remaining_time < 0) remaining_time = 0;
if (remaining_time < 0)
remaining_time = 0;
else if (remaining_time > policy_max_duration_seconds_)
remaining_time = policy_max_duration_seconds_;
return remaining_time;
}
@@ -256,7 +267,7 @@ int64_t PolicyEngine::GetPlaybackDurationRemaining(int64_t current_time) {
bool PolicyEngine::IsRenewalDelayExpired(int64_t current_time) {
return policy_.can_renew() &&
(policy_.renewal_delay_seconds() > 0) &&
license_received_time_ + policy_.renewal_delay_seconds() <=
license_start_time_ + policy_.renewal_delay_seconds() <=
current_time;
}
@@ -264,7 +275,7 @@ bool PolicyEngine::IsRenewalRecoveryDurationExpired(
int64_t current_time) {
// NOTE: Renewal Recovery Duration is currently not used.
return (policy_.renewal_recovery_duration_seconds() > 0) &&
license_received_time_ + policy_.renewal_recovery_duration_seconds() <=
license_start_time_ + policy_.renewal_recovery_duration_seconds() <=
current_time;
}

View File

@@ -0,0 +1,239 @@
// Copyright 2014 Google Inc. All Rights Reserved.
#include "cdm_session.h"
#include "crypto_key.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "properties.h"
#include "string_conversions.h"
namespace {
const std::string kToken = wvcdm::a2bs_hex(
"0AAE02080212107E0A892DEEB021E7AF696B938BB1D5B1188B85AD9D05228E023082010A02"
"82010100DBEDF2BFB0EC98213766E65049B9AB176FA4B1FBFBB2A0C96C87D9F2B895E0ED77"
"93BDA057E6BC3E0CA2348BC6831E03609445CA4D418CB98EAC98FFC87AB2364CE76BA26BEE"
"CDB0C45BD2A6FE9FD38CC5A1C26303AEEB7E9C3CAFAB0D10E46C07E50BEDAB42BF21F40BD2"
"E055DB0B455191D6B4CEEB11B3F1AFA42B5C0CE4C96B75A5283C0E3AE049AA7CF86D1C4EF6"
"6A9088B53BCF320ABC9B98A22C219DC109014EFEA72DA5FF2ED5D655DE7AE06EAC6C6B4191"
"523B2CD2DC1EBFF5F08B11CFE056F2826C1323F12704EC7EBBC1AF935129E5543804492AF9"
"23B848F4AF47B4BFB131C39DDDC99DBAEEE0F30AD2ADBBC63E60793D0876E37391008BB4DB"
"F7020301000128DD22128002A9E571776EA9D22A1BD14248DA88E12FD859989F613360B8D2"
"DA40AF31CC071C7A138466F0EB745E3FD664C0E1A5E4F01098B8D56C34A0158DF9916D192F"
"841ADCA17FD630E1C0CBE652CAC6A52B6A1581BE4029CE6FAE0E04D2D2C7861187AF8299D8"
"3E008DB9A2789672CA1DED903773D7E82B234CE2C799EB73CF80600C08F17EEDDDF369D2B8"
"4A08292F22D1F18FE89521905E713BA674F2217881DBD7711B8C48D5FDCE6FAB51F935E293"
"CB29191AB012B115FD2F5F23164B063D0A929C3E254BF0F4FA60051EB6B3498ED99FF77C19"
"68E8CD83A35CEB054D05433FD0EA6AAE43C87DDA377591D1DCC1831EE130BFFF6D139A5ADA"
"738B0F257CCE2649E71AB4050AAE020801121017DCBC27D11341D497135442A188DAA6188F"
"89809105228E023082010A0282010100D21ADD7549D2748B3494526A9C3FB86C79376BBE8C"
"8856F601B8D10461F77ACC7331B10DEBF365120056CDB5662D25907B74F12382F0F4A0CA47"
"5EEA9562815C6228F6F698ADA27879D8890F2A2D96A746DDEF5316301C003519C2A2250354"
"674169FDDA41CE14D3C52BEA7A20384515012D5952B38AA19E15E8563CC7AAA81C2122880A"
"A370A64FEA23C53FB83AC3DB5753214730A349E07F64BF32BE7EAD30D02612AF110BB44FB0"
"8E1D308173B327EF64D40C41639542B2D1A73C98A6607EC6C683B513A58470514106EF87AE"
"1E7B9C695B93A104DF7437BFC4167789748A43ED208F2C1FA710793C688885EAE732A8BFDF"
"5B423B23D75B88FC0ADC8FBDB5020301000128DD2212800372D2FB88098BA3B85B6B4354E0"
"3767DBE2D7724663FB0A62ABF7704EA910E01F221349EE16D0152C769384050CE78520668C"
"06CCFD3D789AF3EB69FF163615CD609169FDBE2E15A029D34AD2605625BC81844C9D1E2CE0"
"519039F3799ADAEF86641E20B033DC16DF2E5B9A1A2A417B8BB3B7A4D9AD1A99367448587D"
"A13DDE05A3ED9D62FA42078973B4AA40263D7BFA23F1072E94CDF323FA45F78408823E55C4"
"F4C5C723819CF44CE6D98E50C04EC24D93B1AAB8877B9108B9CA391308E1A3645EBB0E7CAC"
"BB40B5451560ED799421873BFB5ABB917FA60DB9C77CB8606AF7E3142626F5EA40E5CB8AA0"
"89D8E7D6A9361935C426A4450EA8BC2E57290D3BF0A0962991D2A91B752FC80C3E7E4E5503"
"3D71C94B325307A68815F026448F56A2741CEBEFC18E8C142F5F62BFAA67A291517DDE982D"
"8CD5A9DF6E3D3A99B806F6D60991358C5BE77117D4F3168F3348E9A048539F892F4D783152"
"C7A8095224AA56B78C5CF7BD1AB1B179C0C0D11E3C3BAC84C141A00191321E3ACC17242E68"
"3C");
const std::string kWrappedKey = wvcdm::a2bs_hex(
"3B84252DD84F1A710365014A114507FFFA3DD404625D61D1EEC7C3A39D72CB8D9318ADE9DA"
"05D69F9776DAFDA49A97BC30E84CA275925DFD98CA04F7DB23465103A224852192DE232902"
"99FF82024F5CCA7716ACA9BE0B56348BA16B9E3136D73789C842CB2ECA4820DDAAF59CCB9B"
"FCF2B4B0E2E5199FDCEC8DEBFFE50BB03041D8E767EA3FE6834C2E79E261ABF17B68EA66E1"
"45AD0A6B056F39C06531A9038C996BADD524E57AE7D5339F13C574E7A398C03D65FD730BAC"
"36F25347350DD2AD69EFA4DC040DC2D9DD4F53A729839FA3496CF580F2CBD51C3522DD67BC"
"BA4A91E89E2BD70449F28E026638920A6DF7B9A0B2C977ACC65AE845E76EF81CADAA746DAF"
"51D4D6FCBC083BE50DA1874D6EB1A30579B23C30881D94A8E5181FE20BF8F8C5F2522B1E7D"
"092B1E20BDE5373F40286DE15267247F88C564BD4EBF4F69B889A03C9892584DC340D87EE1"
"DFF2942D1B7E7EBD846349575F2DE6FDEF71BB005CFBEA845D87937BEBCAFEAC785A092C0A"
"76CE7F7A4FE2F8E43045DED5202A2A55F547BA5DE67AF9E6B2B7DC89EFAD34AC0B40BF4B8F"
"F82F8706B9A88FB9C7A0972E4A4B6CA970BF4F086573D595E5DB8ED0FDA4F9446ACD4B119C"
"1E949C194B042A5CFFC13043FF79F049068A67CC1EB671A10EF7DA927753C4D149E9D0000D"
"4307008BA0AED576ACCADF0CE6758F683087F26C2E38297B8C7D78DC3F1E8F24D7B3A0BED9"
"C066F8348FD19CDB54A92C4E944EE11E11B3B44344E0DB0E1B4BD6CF9295AB66C05454776A"
"8FE33AF659F67718AB43ACB52E83F8C29129DCE9654E8F1EBF9DAB9E933955E24389A37DBE"
"17BA89AC8C750B025CB2F65D5C8BF32FED87EF368F15751AA2114159B6C9C6C814D0720DA4"
"6E885BBB764ADC250D05F70306C3190991C31439BF273A33B6D1773E4FD089F32E753FA3C7"
"7B5ED7DB28407D87396F1F8C83B58176EDFE1F923BDB7DA0ADE58CA2BCD6E76F9463BE7A5A"
"909BE2731241BF1436F3E6A639FC7C717445D89AA5812E4532405B0FB368FE736E22D10FFD"
"15FACCF69FAC468B5552C7887763B96578038CCF154F333E2095BBFF71D5C1235E032174FB"
"44EAB4A753E7A917666A400EBE4F3D2C90100155C27F4B30C8ACFEDA6EFC763EF3556874E5"
"8A5AB0AEBBF39990F79EF4D65EC4697D7BBEEF4F32AE8C4A8A94814A9BE532B5AC902BC0C5"
"FB0A3E661AFF5961B6E79C82CC32FA7B7B48297347503FD58B110B93208167CC1FB96AD822"
"42F60B9D2BF9CCEE8E778A3D3A3302303FB4E33F607D46AACE49D3546A993EDC6FBEE6E19D"
"36831D85877013C57FE335F38D5CD9C3E09C1CEE28BC92C53A364663A7C031DF43B89BAAB4"
"AA8176900FD483AD70E3844BD15EE4F01D8BE72186BBF9E019FCEE5961166696854D1A901F"
"9D71B69B05F75FF233DB3C37F18DCADA640F68C4386F2E528CD77B93521A4574EF399375CD"
"2BE7B9FDC0AE62249717B7E0022BF55C0D023669DD09355EAA90E9DF9BEA309DF7561423BF"
"1DAD177F07A442E1591553924C0F67C2E86774009825490322A6B74319B4C77AA6195CA393"
"03A311F762FB0FD445278D9ACF26A9049C5031BE91F2C4A6BE994CA5A3CEBC2ACCF93AB1EB"
"993A6AA6DEB152DE8C9BB0E6B37B478393B50D1AAE99C086A0ED6D93BA7DD2DEEAB58EE34B"
"C5EE06BE238E8DE6CB44211097C5C90D5C04857918856F86B7036986C20A43153892ED9093"
"33EF70621A98184DDAB5E14BC971CF98CF6C91A37FFA83B00AD3BCABBAAB2DEF1C52F43003"
"E74C92B44F9205D22262FB47948654229DE1920F8EDF96A19A88A1CA1552F8856FB4CBF83B"
"AA3348419159D207F65FCE9C1A500C6818");
} // namespace
namespace wvcdm {
// gmock methods
using ::testing::_;
using ::testing::Eq;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::StrEq;
class MockDeviceFiles : public DeviceFiles {
public:
MOCK_METHOD1(Init, bool(CdmSecurityLevel));
MOCK_METHOD2(RetrieveCertificate, bool(std::string*, std::string*));
};
class MockCryptoSession : public CryptoSession {
public:
MOCK_METHOD1(GetToken, bool(std::string*));
MOCK_METHOD0(GetSecurityLevel, CdmSecurityLevel());
MOCK_METHOD0(Open, CdmResponseType());
MOCK_METHOD1(Open, CdmResponseType(SecurityLevel));
MOCK_METHOD1(LoadCertificatePrivateKey, bool(std::string&));
};
class MockPolicyEngine : public PolicyEngine {
public:
// Leaving a place holder for when PolicyEngine methods need to be mocked
};
class MockCdmLicense : public CdmLicense {
public:
MOCK_METHOD3(Init, bool(const std::string&, CryptoSession*, PolicyEngine*));
};
class CdmSessionTest : public ::testing::Test {
protected:
virtual void SetUp() {
license_parser_ = new MockCdmLicense();
crypto_session_ = new MockCryptoSession();
policy_engine_ = new MockPolicyEngine();
file_handle_ = new MockDeviceFiles();
}
virtual void TearDown() {
if (cdm_session_) delete cdm_session_;
}
void CreateSession() {
cdm_session_ = new CdmSession(license_parser_, crypto_session_,
policy_engine_, file_handle_, NULL);
}
void CreateSession(const CdmClientPropertySet* cdm_client_property_set) {
cdm_session_ =
new CdmSession(license_parser_, crypto_session_, policy_engine_,
file_handle_, cdm_client_property_set);
}
CdmSession* cdm_session_;
MockCdmLicense* license_parser_;
MockCryptoSession* crypto_session_;
MockPolicyEngine* policy_engine_;
MockDeviceFiles* file_handle_;
};
TEST_F(CdmSessionTest, InitWithCertificate) {
CdmSecurityLevel level = kSecurityLevelL1;
EXPECT_CALL(*crypto_session_, GetSecurityLevel()).WillOnce(Return(level));
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
EXPECT_CALL(*file_handle_, RetrieveCertificate(NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey),
Return(true)));
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey)))
.WillOnce(Return(true));
EXPECT_CALL(*license_parser_,
Init(Eq(kToken), Eq(crypto_session_), Eq(policy_engine_)))
.WillOnce(Return(true));
Properties::set_use_certificates_as_identification(true);
CreateSession();
ASSERT_EQ(NO_ERROR, cdm_session_->Init());
}
TEST_F(CdmSessionTest, InitWithKeybox) {
CdmSecurityLevel level = kSecurityLevelL1;
EXPECT_CALL(*crypto_session_, GetSecurityLevel()).WillOnce(Return(level));
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*crypto_session_, GetToken(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kToken), Return(true)));
EXPECT_CALL(*license_parser_,
Init(Eq(kToken), Eq(crypto_session_), Eq(policy_engine_)))
.WillOnce(Return(true));
Properties::set_use_certificates_as_identification(false);
CreateSession();
ASSERT_EQ(NO_ERROR, cdm_session_->Init());
}
TEST_F(CdmSessionTest, ReInitFail) {
CdmSecurityLevel level = kSecurityLevelL1;
EXPECT_CALL(*crypto_session_, GetSecurityLevel()).WillOnce(Return(level));
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
EXPECT_CALL(*file_handle_, RetrieveCertificate(NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey),
Return(true)));
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey)))
.WillOnce(Return(true));
EXPECT_CALL(*license_parser_,
Init(Eq(kToken), Eq(crypto_session_), Eq(policy_engine_)))
.WillOnce(Return(true));
Properties::set_use_certificates_as_identification(true);
CreateSession();
ASSERT_EQ(NO_ERROR, cdm_session_->Init());
ASSERT_EQ(UNKNOWN_ERROR, cdm_session_->Init());
}
TEST_F(CdmSessionTest, InitFailCryptoError) {
CdmSecurityLevel level = kSecurityLevelL1;
EXPECT_CALL(*crypto_session_, GetSecurityLevel()).WillOnce(Return(level));
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
.WillOnce(Return(UNKNOWN_ERROR));
Properties::set_use_certificates_as_identification(true);
CreateSession();
ASSERT_EQ(UNKNOWN_ERROR, cdm_session_->Init());
}
TEST_F(CdmSessionTest, InitNeedsProvisioning) {
CdmSecurityLevel level = kSecurityLevelL1;
EXPECT_CALL(*crypto_session_, GetSecurityLevel()).WillOnce(Return(level));
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
EXPECT_CALL(*file_handle_, RetrieveCertificate(NotNull(), NotNull()))
.WillOnce(Return(false));
Properties::set_use_certificates_as_identification(true);
CreateSession();
ASSERT_EQ(NEED_PROVISIONING, cdm_session_->Init());
}
} // wvcdm

View File

@@ -138,8 +138,7 @@ TEST_F(PolicyEngineTest, PlaybackFailed_CanPlayFalse) {
policy->set_can_play(false);
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime + 1))
.WillOnce(Return(kLicenseStartTime + 5));
.WillOnce(Return(kLicenseStartTime + 1));
policy_engine_->SetLicense(license_);
EXPECT_FALSE(policy_engine_->can_decrypt());
@@ -163,8 +162,8 @@ TEST_F(PolicyEngineTest, PlaybackFails_RentalDurationExpired) {
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime + 1))
.WillOnce(Return(kLicenseStartTime + 5))
.WillOnce(Return(kLicenseStartTime + min_duration))
.WillOnce(Return(kLicenseStartTime + min_duration + 1));
.WillOnce(Return(kLicenseStartTime + min_duration - 1))
.WillOnce(Return(kLicenseStartTime + min_duration));
policy_engine_->SetLicense(license_);
@@ -220,8 +219,8 @@ TEST_F(PolicyEngineTest, PlaybackFails_LicenseDurationExpired) {
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime + 1))
.WillOnce(Return(kLicenseStartTime + 5))
.WillOnce(Return(kLicenseStartTime + min_duration))
.WillOnce(Return(kLicenseStartTime + 1 + min_duration));
.WillOnce(Return(kLicenseStartTime + min_duration - 1))
.WillOnce(Return(kLicenseStartTime + min_duration));
policy_engine_->SetLicense(license_);
@@ -248,8 +247,8 @@ TEST_F(PolicyEngineTest, PlaybackFails_ExpiryBeforeRenewalDelay) {
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime + 1))
.WillOnce(Return(kLicenseStartTime + 5))
.WillOnce(Return(kLicenseStartTime + min_duration))
.WillOnce(Return(kLicenseStartTime + 1 + min_duration));
.WillOnce(Return(kLicenseStartTime + min_duration - 1))
.WillOnce(Return(kLicenseStartTime + min_duration));
policy_engine_->SetLicense(license_);
@@ -277,10 +276,10 @@ TEST_F(PolicyEngineTest, PlaybackOk_RentalDuration0) {
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime + 1))
.WillOnce(Return(kLicenseStartTime + 5))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay - 1))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay))
.WillOnce(Return(kLicenseStartTime + 1 + license_renewal_delay))
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration))
.WillOnce(Return(kLicenseStartTime + 1 + kStreamingLicenseDuration));
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration - 1))
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration));
policy_engine_->SetLicense(license_);
@@ -357,8 +356,8 @@ TEST_F(PolicyEngineTest, PlaybackOk_LicenseDuration0) {
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime + 1))
.WillOnce(Return(kLicenseStartTime + 5))
.WillOnce(Return(kLicenseStartTime + min_duration))
.WillOnce(Return(kLicenseStartTime + 1 + min_duration));
.WillOnce(Return(kLicenseStartTime + min_duration - 1))
.WillOnce(Return(kLicenseStartTime + min_duration));
policy_engine_->SetLicense(license_);
@@ -387,8 +386,8 @@ TEST_F(PolicyEngineTest, PlaybackOk_Durations0) {
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime + 1))
.WillOnce(Return(kLicenseStartTime + 5))
.WillOnce(Return(kLicenseStartTime + kHighDuration))
.WillOnce(Return(kLicenseStartTime + kHighDuration + 10));
.WillOnce(Return(kLicenseStartTime + kHighDuration - 1))
.WillOnce(Return(kLicenseStartTime + kHighDuration));
policy_engine_->SetLicense(license_);
@@ -406,6 +405,29 @@ TEST_F(PolicyEngineTest, PlaybackOk_Durations0) {
EXPECT_TRUE(policy_engine_->can_decrypt());
}
TEST_F(PolicyEngineTest, PlaybackOk_LicenseWithFutureStartTime) {
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime - 100))
.WillOnce(Return(kLicenseStartTime - 50))
.WillOnce(Return(kLicenseStartTime))
.WillOnce(Return(kLicenseStartTime + 10));
policy_engine_->SetLicense(license_);
bool event_occurred;
CdmEventType event;
policy_engine_->OnTimerEvent(&event_occurred, &event);
EXPECT_FALSE(event_occurred);
EXPECT_FALSE(policy_engine_->can_decrypt());
policy_engine_->OnTimerEvent(&event_occurred, &event);
EXPECT_FALSE(event_occurred);
EXPECT_TRUE(policy_engine_->can_decrypt());
policy_engine_->BeginDecryption();
EXPECT_TRUE(policy_engine_->can_decrypt());
}
TEST_F(PolicyEngineTest, PlaybackFailed_CanRenewFalse) {
License_Policy* policy = license_.mutable_policy();
policy->set_can_renew(false);
@@ -480,6 +502,49 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccess) {
EXPECT_TRUE(policy_engine_->can_decrypt());
}
TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccess_WithFutureStartTime) {
int64_t license_renewal_delay =
GetLicenseRenewalDelay(kStreamingLicenseDuration);
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime + 1))
.WillOnce(Return(kLicenseStartTime + 5))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay - 15))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 10))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 20))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 30))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 60));
policy_engine_->SetLicense(license_);
policy_engine_->BeginDecryption();
EXPECT_TRUE(policy_engine_->can_decrypt());
bool event_occurred;
CdmEventType event;
policy_engine_->OnTimerEvent(&event_occurred, &event);
EXPECT_FALSE(event_occurred);
policy_engine_->OnTimerEvent(&event_occurred, &event);
EXPECT_TRUE(event_occurred);
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
EXPECT_TRUE(policy_engine_->can_decrypt());
license_.set_license_start_time(kLicenseStartTime + license_renewal_delay +
50);
LicenseIdentification* id = license_.mutable_id();
id->set_version(2);
policy_engine_->UpdateLicense(license_);
policy_engine_->OnTimerEvent(&event_occurred, &event);
EXPECT_FALSE(event_occurred);
EXPECT_FALSE(policy_engine_->can_decrypt());
policy_engine_->OnTimerEvent(&event_occurred, &event);
EXPECT_FALSE(event_occurred);
EXPECT_TRUE(policy_engine_->can_decrypt());
}
TEST_F(PolicyEngineTest, PlaybackFailed_RenewFailedVersionNotUpdated) {
int64_t license_renewal_delay =
GetLicenseRenewalDelay(kStreamingLicenseDuration);
@@ -790,7 +855,7 @@ TEST_F(PolicyEngineTest, QuerySuccess) {
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
ss >> remaining_time;
ss.clear();
EXPECT_EQ(kStreamingLicenseDuration - 99, remaining_time);
EXPECT_EQ(kStreamingLicenseDuration - 100, remaining_time);
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kPlaybackDuration, remaining_time);
@@ -816,7 +881,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_PlaybackNotBegun) {
std::istringstream ss;
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kStreamingLicenseDuration - 99, remaining_time);
EXPECT_EQ(kStreamingLicenseDuration - 100, remaining_time);
ss.clear();
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
ss >> remaining_time;
@@ -832,7 +897,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_PlaybackNotBegun) {
ss.clear();
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kStreamingLicenseDuration - 199, remaining_time);
EXPECT_EQ(kStreamingLicenseDuration - 200, remaining_time);
ss.clear();
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
ss >> remaining_time;
@@ -861,7 +926,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_PlaybackBegun) {
std::istringstream ss;
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kStreamingLicenseDuration - 49, remaining_time);
EXPECT_EQ(kStreamingLicenseDuration - 50, remaining_time);
ss.clear();
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
ss >> remaining_time;
@@ -885,7 +950,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_PlaybackBegun) {
ss.clear();
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kStreamingLicenseDuration - 199, remaining_time);
EXPECT_EQ(kStreamingLicenseDuration - 200, remaining_time);
ss.clear();
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
ss >> remaining_time;
@@ -931,7 +996,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_Offline) {
std::istringstream ss;
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kOfflineLicenseDuration - 299, remaining_time);
EXPECT_EQ(kOfflineLicenseDuration - 300, remaining_time);
ss.clear();
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
ss >> remaining_time;
@@ -952,8 +1017,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_CanPlayFalse) {
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime + 1))
.WillOnce(Return(kLicenseStartTime + 100))
.WillOnce(Return(kLicenseStartTime + 200));
.WillOnce(Return(kLicenseStartTime + 100));
policy_engine_->SetLicense(license_);
EXPECT_FALSE(policy_engine_->can_decrypt());
@@ -977,7 +1041,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_CanPlayFalse) {
std::istringstream ss;
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kOfflineLicenseDuration - 199, remaining_time);
EXPECT_EQ(kOfflineLicenseDuration - 100, remaining_time);
ss.clear();
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
ss >> remaining_time;
@@ -995,8 +1059,8 @@ TEST_F(PolicyEngineTest, QuerySuccess_RentalDurationExpired) {
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime + 1))
.WillOnce(Return(kLicenseStartTime + 5))
.WillOnce(Return(kLicenseStartTime + min_duration - 1))
.WillOnce(Return(kLicenseStartTime + min_duration))
.WillOnce(Return(kLicenseStartTime + min_duration + 1))
.WillOnce(Return(kLicenseStartTime + min_duration + 5));
policy_engine_->SetLicense(license_);
@@ -1076,7 +1140,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_PlaybackDurationExpired) {
std::istringstream ss;
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kHighDuration - 10004 - min_duration, remaining_time);
EXPECT_EQ(kHighDuration - 10005 - min_duration, remaining_time);
ss.clear();
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
ss >> remaining_time;
@@ -1092,9 +1156,9 @@ TEST_F(PolicyEngineTest, QuerySuccess_LicenseDurationExpired) {
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime + 1))
.WillOnce(Return(kLicenseStartTime + 5))
.WillOnce(Return(kLicenseStartTime + min_duration - 1))
.WillOnce(Return(kLicenseStartTime + min_duration))
.WillOnce(Return(kLicenseStartTime + 1 + min_duration))
.WillOnce(Return(kLicenseStartTime + 5 + min_duration));
.WillOnce(Return(kLicenseStartTime + min_duration + 5));
policy_engine_->SetLicense(license_);
@@ -1140,11 +1204,11 @@ TEST_F(PolicyEngineTest, QuerySuccess_RentalDuration0) {
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime + 1))
.WillOnce(Return(kLicenseStartTime + 5))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay - 1))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay))
.WillOnce(Return(kLicenseStartTime + 1 + license_renewal_delay))
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration - 1))
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration))
.WillOnce(Return(kLicenseStartTime + 1 + kStreamingLicenseDuration))
.WillOnce(Return(kLicenseStartTime + 5 + kStreamingLicenseDuration));
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration + 5));
policy_engine_->SetLicense(license_);
@@ -1275,9 +1339,9 @@ TEST_F(PolicyEngineTest, QuerySuccess_LicenseDuration0) {
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime + 1))
.WillOnce(Return(kLicenseStartTime + 5))
.WillOnce(Return(kLicenseStartTime + min_duration - 1))
.WillOnce(Return(kLicenseStartTime + min_duration))
.WillOnce(Return(kLicenseStartTime + 1 + min_duration))
.WillOnce(Return(kLicenseStartTime + 5 + min_duration));
.WillOnce(Return(kLicenseStartTime + min_duration + 5));
policy_engine_->SetLicense(license_);
@@ -1325,7 +1389,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_Durations0) {
.WillOnce(Return(kLicenseStartTime + 1))
.WillOnce(Return(kLicenseStartTime + 5))
.WillOnce(Return(kLicenseStartTime + kHighDuration))
.WillOnce(Return(kLicenseStartTime + kHighDuration + 10))
.WillOnce(Return(kLicenseStartTime + kHighDuration + 9))
.WillOnce(Return(kLicenseStartTime + kHighDuration + 15));
policy_engine_->SetLicense(license_);
@@ -1361,4 +1425,213 @@ TEST_F(PolicyEngineTest, QuerySuccess_Durations0) {
EXPECT_EQ(LLONG_MAX, remaining_time);
EXPECT_EQ(kRenewalServerUrl, query_info[QUERY_KEY_RENEWAL_SERVER_URL]);
}
TEST_F(PolicyEngineTest, QuerySuccess_LicenseWithFutureStartTime) {
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime - 100))
.WillOnce(Return(kLicenseStartTime - 50))
.WillOnce(Return(kLicenseStartTime - 10))
.WillOnce(Return(kLicenseStartTime))
.WillOnce(Return(kLicenseStartTime + 10))
.WillOnce(Return(kLicenseStartTime + 25));
policy_engine_->SetLicense(license_);
bool event_occurred;
CdmEventType event;
policy_engine_->OnTimerEvent(&event_occurred, &event);
EXPECT_FALSE(event_occurred);
EXPECT_FALSE(policy_engine_->can_decrypt());
CdmQueryMap query_info;
EXPECT_EQ(NO_ERROR, policy_engine_->Query(&query_info));
EXPECT_EQ(QUERY_VALUE_STREAMING, query_info[QUERY_KEY_LICENSE_TYPE]);
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_PLAY_ALLOWED]);
EXPECT_EQ(QUERY_VALUE_FALSE, query_info[QUERY_KEY_PERSIST_ALLOWED]);
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_RENEW_ALLOWED]);
int64_t remaining_time;
std::istringstream ss;
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kStreamingLicenseDuration, remaining_time);
ss.clear();
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kPlaybackDuration, remaining_time);
EXPECT_EQ(kRenewalServerUrl, query_info[QUERY_KEY_RENEWAL_SERVER_URL]);
EXPECT_FALSE(policy_engine_->can_decrypt());
policy_engine_->OnTimerEvent(&event_occurred, &event);
EXPECT_FALSE(event_occurred);
EXPECT_TRUE(policy_engine_->can_decrypt());
policy_engine_->BeginDecryption();
EXPECT_EQ(NO_ERROR, policy_engine_->Query(&query_info));
EXPECT_EQ(QUERY_VALUE_STREAMING, query_info[QUERY_KEY_LICENSE_TYPE]);
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_PLAY_ALLOWED]);
EXPECT_EQ(QUERY_VALUE_FALSE, query_info[QUERY_KEY_PERSIST_ALLOWED]);
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_RENEW_ALLOWED]);
ss.clear();
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kStreamingLicenseDuration - 25, remaining_time);
ss.clear();
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kPlaybackDuration - 15, remaining_time);
EXPECT_EQ(kRenewalServerUrl, query_info[QUERY_KEY_RENEWAL_SERVER_URL]);
}
TEST_F(PolicyEngineTest, QuerySuccess_Renew) {
int64_t license_renewal_delay =
GetLicenseRenewalDelay(kStreamingLicenseDuration);
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime + 1))
.WillOnce(Return(kLicenseStartTime + 5))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay - 25))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 10))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 20))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay +
kLicenseRenewalRetryInterval + 10))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay +
kLicenseRenewalRetryInterval + 15));
policy_engine_->SetLicense(license_);
policy_engine_->BeginDecryption();
EXPECT_TRUE(policy_engine_->can_decrypt());
bool event_occurred;
CdmEventType event;
policy_engine_->OnTimerEvent(&event_occurred, &event);
EXPECT_FALSE(event_occurred);
policy_engine_->OnTimerEvent(&event_occurred, &event);
EXPECT_TRUE(event_occurred);
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
EXPECT_TRUE(policy_engine_->can_decrypt());
license_.set_license_start_time(kLicenseStartTime + license_renewal_delay +
15);
LicenseIdentification* id = license_.mutable_id();
id->set_version(2);
policy_engine_->UpdateLicense(license_);
policy_engine_->OnTimerEvent(&event_occurred, &event);
EXPECT_FALSE(event_occurred);
EXPECT_TRUE(policy_engine_->can_decrypt());
CdmQueryMap query_info;
EXPECT_EQ(NO_ERROR, policy_engine_->Query(&query_info));
EXPECT_EQ(QUERY_VALUE_STREAMING, query_info[QUERY_KEY_LICENSE_TYPE]);
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_PLAY_ALLOWED]);
EXPECT_EQ(QUERY_VALUE_FALSE, query_info[QUERY_KEY_PERSIST_ALLOWED]);
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_RENEW_ALLOWED]);
int64_t remaining_time;
std::istringstream ss;
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kStreamingLicenseDuration - kLicenseRenewalRetryInterval,
remaining_time);
ss.clear();
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kPlaybackDuration + 5 - license_renewal_delay -
kLicenseRenewalRetryInterval - 15,
remaining_time);
EXPECT_EQ(kRenewalServerUrl, query_info[QUERY_KEY_RENEWAL_SERVER_URL]);
}
TEST_F(PolicyEngineTest, QuerySuccess_RenewWithFutureStartTime) {
int64_t license_renewal_delay =
GetLicenseRenewalDelay(kStreamingLicenseDuration);
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(kLicenseStartTime + 1))
.WillOnce(Return(kLicenseStartTime + 5))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay - 25))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 10))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 20))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay +
kLicenseRenewalRetryInterval + 10))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay +
kLicenseRenewalRetryInterval + 20))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay +
kLicenseRenewalRetryInterval + 30))
.WillOnce(Return(kLicenseStartTime + license_renewal_delay +
kLicenseRenewalRetryInterval + 40));
policy_engine_->SetLicense(license_);
policy_engine_->BeginDecryption();
EXPECT_TRUE(policy_engine_->can_decrypt());
bool event_occurred;
CdmEventType event;
policy_engine_->OnTimerEvent(&event_occurred, &event);
EXPECT_FALSE(event_occurred);
policy_engine_->OnTimerEvent(&event_occurred, &event);
EXPECT_TRUE(event_occurred);
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
EXPECT_TRUE(policy_engine_->can_decrypt());
license_.set_license_start_time(kLicenseStartTime + license_renewal_delay +
kLicenseRenewalRetryInterval + 20);
LicenseIdentification* id = license_.mutable_id();
id->set_version(2);
policy_engine_->UpdateLicense(license_);
policy_engine_->OnTimerEvent(&event_occurred, &event);
EXPECT_FALSE(event_occurred);
EXPECT_FALSE(policy_engine_->can_decrypt());
CdmQueryMap query_info;
EXPECT_EQ(NO_ERROR, policy_engine_->Query(&query_info));
EXPECT_EQ(QUERY_VALUE_STREAMING, query_info[QUERY_KEY_LICENSE_TYPE]);
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_PLAY_ALLOWED]);
EXPECT_EQ(QUERY_VALUE_FALSE, query_info[QUERY_KEY_PERSIST_ALLOWED]);
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_RENEW_ALLOWED]);
int64_t remaining_time;
std::istringstream ss;
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kStreamingLicenseDuration, remaining_time);
ss.clear();
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kPlaybackDuration + 5 - license_renewal_delay -
kLicenseRenewalRetryInterval - 20,
remaining_time);
EXPECT_EQ(kRenewalServerUrl, query_info[QUERY_KEY_RENEWAL_SERVER_URL]);
policy_engine_->OnTimerEvent(&event_occurred, &event);
EXPECT_FALSE(event_occurred);
EXPECT_TRUE(policy_engine_->can_decrypt());
EXPECT_EQ(NO_ERROR, policy_engine_->Query(&query_info));
EXPECT_EQ(QUERY_VALUE_STREAMING, query_info[QUERY_KEY_LICENSE_TYPE]);
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_PLAY_ALLOWED]);
EXPECT_EQ(QUERY_VALUE_FALSE, query_info[QUERY_KEY_PERSIST_ALLOWED]);
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_RENEW_ALLOWED]);
ss.clear();
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kStreamingLicenseDuration - 20, remaining_time);
ss.clear();
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
ss >> remaining_time;
EXPECT_EQ(kPlaybackDuration + 5 - license_renewal_delay -
kLicenseRenewalRetryInterval - 40,
remaining_time);
EXPECT_EQ(kRenewalServerUrl, query_info[QUERY_KEY_RENEWAL_SERVER_URL]);
}
} // wvcdm