Merge of usage reporting and license changes from WV CDM repo
* CdmSession unittest and license request time changes b/15914199 Merge of https://widevine-internal-review.googlesource.com/#/c/10597/ * Specify OEMCrypto API version in client capabilities b/15388863 Merge of https://widevine-internal-review.googlesource.com/#/c/10616/ * Report start and last play time in license request b/15995227 Merge of https://widevine-internal-review.googlesource.com/#/c/10617/ * Respect can_play flag b/15330338 Merge of https://widevine-internal-review.googlesource.com/#/c/10619/ * Restore offline session information b/16009274 Merge of https://widevine-internal-review.googlesource.com/#/c/10641/ Change-Id: I17fdc309efbc1d44385a86a368df11b1349b29c2
This commit is contained in:
@@ -53,6 +53,7 @@ adb push $OUT/system/bin/policy_engine_unittest /system/bin
|
||||
adb push $OUT/system/bin/libwvdrmmediacrypto_test /system/bin
|
||||
adb push $OUT/system/bin/libwvdrmdrmplugin_test /system/bin
|
||||
adb push $OUT/system/bin/cdm_engine_test /system/bin
|
||||
adb push $OUT/system/bin/cdm_session_unittest /system/bin
|
||||
adb push $OUT/system/bin/file_store_unittest /system/bin
|
||||
adb push $OUT/system/bin/device_files_unittest /system/bin
|
||||
adb push $OUT/system/bin/timer_unittest /system/bin
|
||||
|
||||
@@ -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(
|
||||
@@ -85,7 +80,7 @@ class CdmSession {
|
||||
virtual bool AttachEventListener(WvCdmEventListener* listener);
|
||||
virtual bool DetachEventListener(WvCdmEventListener* listener);
|
||||
|
||||
virtual void OnTimerEvent();
|
||||
virtual void OnTimerEvent(bool update_usage);
|
||||
virtual void OnKeyReleaseEvent(const CdmKeySetId& key_set_id);
|
||||
|
||||
virtual SecurityLevel GetRequestedSecurityLevel();
|
||||
@@ -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,16 +108,19 @@ 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 is_offline_;
|
||||
bool is_release_;
|
||||
bool is_usage_update_needed_;
|
||||
bool is_initial_decryption_;
|
||||
bool has_decrypted_recently_;
|
||||
CdmSecurityLevel security_level_;
|
||||
|
||||
// information useful for offline and usage scenarios
|
||||
CdmKeyMessage key_request_;
|
||||
@@ -134,6 +137,16 @@ class CdmSession {
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
@@ -18,6 +18,24 @@ typedef std::map<CryptoKeyId, CryptoKey*> CryptoKeyMap;
|
||||
|
||||
class CryptoSession {
|
||||
public:
|
||||
// This enum should be kept in sync with the values specified for
|
||||
// HDCP capabilities in OEMCryptoCENC.h. (See comments for
|
||||
// OEMCrypto_GetHDCPCapability)
|
||||
typedef enum {
|
||||
kOemCryptoHdcpNotSupported = 0,
|
||||
kOemCryptoHdcpVersion1 = 1,
|
||||
kOemCryptoHdcpVersion2 = 2,
|
||||
kOemCryptoHdcpVersion2_1 = 3,
|
||||
kOemCryptoHdcpVersion2_2 = 4,
|
||||
kOemCryptoNoHdcpDeviceAttached = 0xff,
|
||||
} OemCryptoHdcpVersion;
|
||||
|
||||
typedef enum {
|
||||
kUsageDurationsInvalid = 0,
|
||||
kUsageDurationPlaybackNotBegun = 1,
|
||||
kUsageDurationsValid = 2,
|
||||
} UsageDurationStatus;
|
||||
|
||||
CryptoSession();
|
||||
virtual ~CryptoSession();
|
||||
|
||||
@@ -37,7 +55,7 @@ class CryptoSession {
|
||||
virtual CryptoSessionId oec_session_id() { return oec_session_id_; }
|
||||
|
||||
// Key request/response
|
||||
virtual void GenerateRequestId(std::string& req_id_str);
|
||||
virtual bool GenerateRequestId(std::string* req_id_str);
|
||||
virtual bool PrepareRequest(const std::string& key_deriv_message,
|
||||
bool is_provisioning, std::string* signature);
|
||||
virtual bool PrepareRenewalRequest(const std::string& message,
|
||||
@@ -66,13 +84,20 @@ class CryptoSession {
|
||||
// Media data path
|
||||
virtual CdmResponseType Decrypt(const CdmDecryptionParameters& parameters);
|
||||
|
||||
virtual bool UsageInformationSupport(bool* has_support);
|
||||
virtual CdmResponseType UpdateUsageInformation();
|
||||
virtual CdmResponseType DeactivateUsageInformation(
|
||||
const std::string& provider_session_token);
|
||||
virtual CdmResponseType GenerateUsageReport(
|
||||
const std::string& provider_session_token, std::string* usage_report);
|
||||
const std::string& provider_session_token, std::string* usage_report,
|
||||
UsageDurationStatus* usage_duration_status,
|
||||
int64_t* seconds_since_started, int64_t* seconds_since_last_played);
|
||||
virtual CdmResponseType ReleaseUsageInformation(
|
||||
const std::string& message, const std::string& signature,
|
||||
const std::string& provider_session_token);
|
||||
|
||||
virtual bool GetHdcpCapabilities(OemCryptoHdcpVersion* current,
|
||||
OemCryptoHdcpVersion* max);
|
||||
virtual bool GetRandom(size_t data_length, uint8_t* random_data);
|
||||
|
||||
private:
|
||||
|
||||
@@ -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);
|
||||
@@ -39,7 +42,9 @@ class DeviceFiles {
|
||||
const CdmKeyResponse& key_response,
|
||||
const CdmKeyMessage& key_renewal_request,
|
||||
const CdmKeyResponse& key_renewal_response,
|
||||
const std::string& release_server_url);
|
||||
const std::string& release_server_url,
|
||||
int64_t playback_start_time,
|
||||
int64_t last_playback_time);
|
||||
virtual bool RetrieveLicense(const std::string& key_set_id,
|
||||
LicenseState* state,
|
||||
CdmInitData* pssh_data,
|
||||
@@ -47,7 +52,9 @@ class DeviceFiles {
|
||||
CdmKeyResponse* key_response,
|
||||
CdmKeyMessage* key_renewal_request,
|
||||
CdmKeyResponse* key_renewal_response,
|
||||
std::string* release_server_url);
|
||||
std::string* release_server_url,
|
||||
int64_t* playback_start_time,
|
||||
int64_t* last_playback_time);
|
||||
virtual bool DeleteLicense(const std::string& key_set_id);
|
||||
virtual bool DeleteAllFiles();
|
||||
virtual bool DeleteAllLicenses();
|
||||
@@ -93,7 +100,7 @@ class DeviceFiles {
|
||||
FRIEND_TEST(WvCdmUsageInfoTest, DISABLED_UsageInfo);
|
||||
#endif
|
||||
|
||||
File* file_;
|
||||
scoped_ptr<File> file_;
|
||||
CdmSecurityLevel security_level_;
|
||||
bool initialized_;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <set>
|
||||
|
||||
#include "initialization_data.h"
|
||||
#include "scoped_ptr.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace video_widevine_server {
|
||||
@@ -16,14 +17,15 @@ class SignedMessage;
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
class Clock;
|
||||
class CryptoSession;
|
||||
class PolicyEngine;
|
||||
|
||||
class CdmLicense {
|
||||
public:
|
||||
|
||||
CdmLicense() : session_(NULL), initialized_(false) {}
|
||||
virtual ~CdmLicense() {}
|
||||
CdmLicense();
|
||||
virtual ~CdmLicense();
|
||||
|
||||
virtual bool Init(const std::string& token, CryptoSession* session,
|
||||
PolicyEngine* policy_engine);
|
||||
@@ -42,7 +44,9 @@ class CdmLicense {
|
||||
|
||||
virtual bool RestoreOfflineLicense(const CdmKeyMessage& license_request,
|
||||
const CdmKeyResponse& license_response,
|
||||
const CdmKeyResponse& license_renewal_response);
|
||||
const CdmKeyResponse& license_renewal_response,
|
||||
int64_t playback_start_time,
|
||||
int64_t last_playback_time);
|
||||
virtual bool RestoreUsageLicense(const CdmKeyMessage& license_request,
|
||||
const CdmKeyResponse& license_response);
|
||||
virtual bool HasInitData() { return !stored_init_data_.empty(); }
|
||||
@@ -76,6 +80,14 @@ class CdmLicense {
|
||||
// Used for certificate based licensing
|
||||
CdmKeyMessage key_request_;
|
||||
|
||||
scoped_ptr<Clock> clock_;
|
||||
|
||||
// For testing
|
||||
CdmLicense(Clock* clock);
|
||||
#if defined(UNIT_TEST)
|
||||
friend class CdmLicenseTest;
|
||||
#endif
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(CdmLicense);
|
||||
};
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ class PolicyEngine {
|
||||
|
||||
// Call this on first decrypt to set the start of playback.
|
||||
virtual void BeginDecryption(void);
|
||||
virtual void DecryptionEvent(void);
|
||||
|
||||
// UpdateLicense is used in handling a license response for a renewal request.
|
||||
// The response may only contain any policy fields that have changed. In this
|
||||
@@ -60,9 +61,21 @@ class PolicyEngine {
|
||||
bool IsLicenseDurationExpired(int64_t current_time);
|
||||
bool IsPlaybackDurationExpired(int64_t current_time);
|
||||
|
||||
bool GetSecondsSinceStarted(int64_t* seconds_since_started);
|
||||
bool GetSecondsSinceLastPlayed(int64_t* seconds_since_started);
|
||||
|
||||
// for offline save and restore
|
||||
int64_t GetPlaybackStartTime() { return playback_start_time_; }
|
||||
int64_t GetLastPlaybackTime() { return last_playback_time_; }
|
||||
void RestorePlaybackTimes(int64_t playback_start_time,
|
||||
int64_t last_playback_time);
|
||||
|
||||
bool IsLicenseForFuture() { return license_state_ == kLicenseStatePending; }
|
||||
|
||||
private:
|
||||
typedef enum {
|
||||
kLicenseStateInitial,
|
||||
kLicenseStatePending, // if license is issued for sometime in the future
|
||||
kLicenseStateCanPlay,
|
||||
kLicenseStateNeedRenewal,
|
||||
kLicenseStateWaitingLicenseUpdate,
|
||||
@@ -92,18 +105,15 @@ 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_;
|
||||
int64_t last_playback_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_;
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -702,7 +702,7 @@ void CdmEngine::OnTimerEvent() {
|
||||
|
||||
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||
iter != sessions_.end(); ++iter) {
|
||||
iter->second->OnTimerEvent();
|
||||
iter->second->OnTimerEvent(update_usage_information);
|
||||
|
||||
if (update_usage_information && iter->second->is_usage_update_needed()) {
|
||||
// usage is updated for all sessions so this needs to be
|
||||
|
||||
@@ -25,46 +25,96 @@ 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),
|
||||
is_offline_(false),
|
||||
is_release_(false),
|
||||
is_usage_update_needed_(false),
|
||||
is_initial_decryption_(true) {
|
||||
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;
|
||||
has_decrypted_recently_ = false;
|
||||
if (cdm_client_property_set) {
|
||||
Properties::AddSessionPropertySet(session_id_, cdm_client_property_set);
|
||||
}
|
||||
security_level_ = GetRequestedSecurityLevel() == kLevel3
|
||||
? kSecurityLevelL3 : GetSecurityLevel();
|
||||
}
|
||||
|
||||
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;
|
||||
std::string wrapped_key;
|
||||
if (!handle.Init(session.get()->GetSecurityLevel()) ||
|
||||
!handle.RetrieveCertificate(&token, &wrapped_key) ||
|
||||
!session->LoadCertificatePrivateKey(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;
|
||||
is_initial_decryption_ = true;
|
||||
initialized_ = true;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -73,17 +123,21 @@ 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;
|
||||
int64_t playback_start_time;
|
||||
int64_t last_playback_time;
|
||||
|
||||
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_,
|
||||
&playback_start_time,
|
||||
&last_playback_time)) {
|
||||
LOGE("CdmSession::Init failed to retrieve license. key set id = %s",
|
||||
key_set_id.c_str());
|
||||
return UNKNOWN_ERROR;
|
||||
@@ -94,8 +148,10 @@ CdmResponseType CdmSession::RestoreOfflineSession(
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
if (!license_parser_.RestoreOfflineLicense(key_request_, key_response_,
|
||||
offline_key_renewal_response_)) {
|
||||
if (!license_parser_->RestoreOfflineLicense(key_request_, key_response_,
|
||||
offline_key_renewal_response_,
|
||||
playback_start_time,
|
||||
last_playback_time)) {
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
@@ -111,7 +167,8 @@ CdmResponseType CdmSession::RestoreUsageSession(
|
||||
|
||||
key_request_ = key_request;
|
||||
key_response_ = key_response;
|
||||
if (!license_parser_.RestoreUsageLicense(key_request_, key_response_)) {
|
||||
|
||||
if (!license_parser_->RestoreUsageLicense(key_request_, key_response_)) {
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
@@ -155,14 +212,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 (!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;
|
||||
}
|
||||
|
||||
@@ -195,14 +252,14 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response,
|
||||
} 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;
|
||||
}
|
||||
@@ -245,7 +302,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) {
|
||||
@@ -276,27 +333,35 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
|
||||
if (crypto_session_.get() == NULL || !crypto_session_->IsOpen())
|
||||
return UNKNOWN_ERROR;
|
||||
|
||||
if (params.is_encrypted && !policy_engine_->can_decrypt()) {
|
||||
return policy_engine_->IsLicenseForFuture() ? KEY_ERROR : NEED_KEY;
|
||||
}
|
||||
|
||||
CdmResponseType status = crypto_session_->Decrypt(params);
|
||||
|
||||
switch (status) {
|
||||
case NO_ERROR:
|
||||
if (is_initial_decryption_) {
|
||||
policy_engine_.BeginDecryption();
|
||||
policy_engine_->BeginDecryption();
|
||||
is_initial_decryption_ = false;
|
||||
}
|
||||
has_decrypted_recently_ = true;
|
||||
if (!is_usage_update_needed_) {
|
||||
is_usage_update_needed_ =
|
||||
!license_parser_.provider_session_token().empty();
|
||||
!license_parser_->provider_session_token().empty();
|
||||
}
|
||||
break;
|
||||
case UNKNOWN_ERROR:
|
||||
case UNKNOWN_ERROR: {
|
||||
Clock clock;
|
||||
int64_t current_time = clock.GetCurrentTime();
|
||||
if (policy_engine_.IsLicenseDurationExpired(current_time) ||
|
||||
policy_engine_.IsPlaybackDurationExpired(current_time)) {
|
||||
if (policy_engine_->IsLicenseDurationExpired(current_time) ||
|
||||
policy_engine_->IsPlaybackDurationExpired(current_time)) {
|
||||
return NEED_KEY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: //Ignore
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -307,7 +372,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;
|
||||
}
|
||||
@@ -321,7 +387,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_) {
|
||||
@@ -334,7 +400,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
|
||||
@@ -346,19 +412,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 (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() {
|
||||
@@ -375,8 +441,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()) {
|
||||
@@ -386,7 +451,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();
|
||||
}
|
||||
}
|
||||
@@ -414,20 +479,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;
|
||||
}
|
||||
@@ -435,31 +500,31 @@ 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_);
|
||||
offline_key_renewal_response_, offline_release_server_url_,
|
||||
policy_engine_->GetPlaybackStartTime(),
|
||||
policy_engine_->GetLastPlaybackTime());
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -471,11 +536,19 @@ bool CdmSession::DetachEventListener(WvCdmEventListener* listener) {
|
||||
return (listeners_.erase(listener) == 1);
|
||||
}
|
||||
|
||||
void CdmSession::OnTimerEvent() {
|
||||
void CdmSession::OnTimerEvent(bool update_usage) {
|
||||
bool event_occurred = false;
|
||||
CdmEventType event;
|
||||
|
||||
policy_engine_.OnTimerEvent(&event_occurred, &event);
|
||||
if (update_usage && has_decrypted_recently_) {
|
||||
policy_engine_->DecryptionEvent();
|
||||
has_decrypted_recently_ = false;
|
||||
}
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
|
||||
if (is_offline_ && !is_release_) {
|
||||
StoreLicense(DeviceFiles::kLicenseStateActive);
|
||||
}
|
||||
|
||||
if (event_occurred) {
|
||||
for (CdmEventListenerIter iter = listeners_.begin();
|
||||
|
||||
@@ -169,13 +169,8 @@ bool CryptoSession::GetApiVersion(uint32_t* version) {
|
||||
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);
|
||||
*version = OEMCrypto_APIVersion(
|
||||
kSecurityLevelL3 == GetSecurityLevel() ? kLevel3 : kLevelDefault);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -267,13 +262,19 @@ void CryptoSession::Close() {
|
||||
}
|
||||
}
|
||||
|
||||
void CryptoSession::GenerateRequestId(std::string& req_id_str) {
|
||||
bool CryptoSession::GenerateRequestId(std::string* req_id_str) {
|
||||
LOGV("CryptoSession::GenerateRequestId: Lock");
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
req_id_str = HexEncode(reinterpret_cast<uint8_t*>(&request_id_base_),
|
||||
sizeof(request_id_base_)) +
|
||||
HexEncode(reinterpret_cast<uint8_t*>(&request_id_index_),
|
||||
sizeof(request_id_index_));
|
||||
if (!req_id_str) {
|
||||
LOGE("CryptoSession::GenerateRequestId: No output destination provided.");
|
||||
return false;
|
||||
}
|
||||
|
||||
*req_id_str = HexEncode(reinterpret_cast<uint8_t*>(&request_id_base_),
|
||||
sizeof(request_id_base_)) +
|
||||
HexEncode(reinterpret_cast<uint8_t*>(&request_id_index_),
|
||||
sizeof(request_id_index_));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptoSession::PrepareRequest(const std::string& message,
|
||||
@@ -662,19 +663,31 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
|
||||
}
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::UpdateUsageInformation() {
|
||||
return (OEMCrypto_UpdateUsageTable() == OEMCrypto_SUCCESS) ? NO_ERROR
|
||||
: UNKNOWN_ERROR;
|
||||
bool CryptoSession::UsageInformationSupport(bool* has_support) {
|
||||
LOGV("UsageInformationSupport: id=%ld", (uint32_t)oec_session_id_);
|
||||
if (!initialized_) return false;
|
||||
|
||||
*has_support = OEMCrypto_SupportsUsageTable(
|
||||
kSecurityLevelL3 == GetSecurityLevel() ? kLevel3 : kLevelDefault);
|
||||
return true;
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::GenerateUsageReport(
|
||||
const std::string& provider_session_token, std::string* usage_report) {
|
||||
LOGV("GenerateUsageReport: id=%ld", (uint32_t)oec_session_id_);
|
||||
CdmResponseType CryptoSession::UpdateUsageInformation() {
|
||||
LOGV("UpdateUsageInformation: id=%ld", (uint32_t)oec_session_id_);
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
if (!initialized_) return UNKNOWN_ERROR;
|
||||
|
||||
if (NULL == usage_report) {
|
||||
LOGE("usage_report parameter is null");
|
||||
OEMCryptoResult status = OEMCrypto_UpdateUsageTable();
|
||||
if (status != OEMCrypto_SUCCESS) {
|
||||
LOGE("CryptoSession::UsageUsageInformation: error=%ld", status);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::DeactivateUsageInformation(
|
||||
const std::string& provider_session_token) {
|
||||
LOGV("DeactivateUsageInformation: id=%ld", (uint32_t)oec_session_id_);
|
||||
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
uint8_t* pst = reinterpret_cast<uint8_t*>(
|
||||
@@ -684,19 +697,41 @@ CdmResponseType CryptoSession::GenerateUsageReport(
|
||||
OEMCrypto_DeactivateUsageEntry(pst, provider_session_token.length());
|
||||
|
||||
if (OEMCrypto_SUCCESS != status) {
|
||||
LOGE("CryptoSession::GenerateUsageReport: Deactivate Usage Entry error=%ld",
|
||||
status);
|
||||
LOGE("CryptoSession::DeactivateUsageInformation: Deactivate Usage Entry "
|
||||
" error=%ld",
|
||||
status);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::GenerateUsageReport(
|
||||
const std::string& provider_session_token, std::string* usage_report,
|
||||
UsageDurationStatus* usage_duration_status, int64_t* seconds_since_started,
|
||||
int64_t* seconds_since_last_played) {
|
||||
LOGV("GenerateUsageReport: id=%ld", (uint32_t)oec_session_id_);
|
||||
|
||||
if (NULL == usage_report) {
|
||||
LOGE("CryptoSession::GenerateUsageReport: usage_report parameter is null");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
size_t usage_length = 0;
|
||||
status = OEMCrypto_ReportUsage(oec_session_id_, pst,
|
||||
provider_session_token.length(), NULL,
|
||||
&usage_length);
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
uint8_t* pst = reinterpret_cast<uint8_t*>(
|
||||
const_cast<char*>(provider_session_token.data()));
|
||||
|
||||
if (OEMCrypto_ERROR_SHORT_BUFFER != status) {
|
||||
LOGE("CryptoSession::GenerateUsageReport: Report Usage error=%ld", status);
|
||||
return UNKNOWN_ERROR;
|
||||
size_t usage_length = 0;
|
||||
OEMCryptoResult status =
|
||||
OEMCrypto_ReportUsage(oec_session_id_, pst,
|
||||
provider_session_token.length(), NULL,
|
||||
&usage_length);
|
||||
|
||||
if (OEMCrypto_SUCCESS != status) {
|
||||
if (OEMCrypto_ERROR_SHORT_BUFFER != status) {
|
||||
LOGE("CryptoSession::GenerateUsageReport: Report Usage error=%ld",
|
||||
status);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
usage_report->resize(usage_length);
|
||||
@@ -711,10 +746,27 @@ CdmResponseType CryptoSession::GenerateUsageReport(
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
if (usage_length < usage_report->length()) {
|
||||
if (usage_length != usage_report->length()) {
|
||||
usage_report->resize(usage_length);
|
||||
}
|
||||
|
||||
OEMCrypto_PST_Report pst_report;
|
||||
*usage_duration_status = kUsageDurationsInvalid;
|
||||
if (usage_length < sizeof(pst_report)) {
|
||||
LOGE("CryptoSession::GenerateUsageReport: usage report too small=%ld",
|
||||
usage_length);
|
||||
return NO_ERROR; // usage report available but no duration information
|
||||
}
|
||||
|
||||
memcpy(&pst_report, usage_report->data(), sizeof(pst_report));
|
||||
if (kUnused == pst_report.status) {
|
||||
*usage_duration_status = kUsageDurationPlaybackNotBegun;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
*usage_duration_status = kUsageDurationsValid;
|
||||
*seconds_since_started = pst_report.seconds_since_first_decrypt;
|
||||
*seconds_since_last_played = pst_report.seconds_since_last_decrypt;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -822,6 +874,24 @@ bool CryptoSession::RewrapDeviceRSAKey(const std::string& message,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptoSession::GetHdcpCapabilities(
|
||||
OemCryptoHdcpVersion* current_version,
|
||||
OemCryptoHdcpVersion* max_version) {
|
||||
LOGV("GetHdcpCapabilities: id=%ld", (uint32_t)oec_session_id_);
|
||||
if (!initialized_) return UNKNOWN_ERROR;
|
||||
OEMCrypto_HDCP_Capability current, max;
|
||||
OEMCryptoResult status = OEMCrypto_GetHDCPCapability(¤t, &max);
|
||||
|
||||
if (OEMCrypto_SUCCESS != status) {
|
||||
LOGW("OEMCrypto_GetHDCPCapability fails with %d", status);
|
||||
return false;
|
||||
}
|
||||
*current_version = static_cast<OemCryptoHdcpVersion>(current);
|
||||
*max_version = static_cast<OemCryptoHdcpVersion>(max);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptoSession::GetRandom(size_t data_length, uint8_t* random_data) {
|
||||
if (random_data == NULL) {
|
||||
LOGE("CryptoSession::GetRandom: random data destination not provided");
|
||||
|
||||
@@ -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;
|
||||
@@ -148,7 +153,9 @@ bool DeviceFiles::StoreLicense(const std::string& key_set_id,
|
||||
const CdmKeyResponse& license_message,
|
||||
const CdmKeyMessage& license_renewal_request,
|
||||
const CdmKeyResponse& license_renewal,
|
||||
const std::string& release_server_url) {
|
||||
const std::string& release_server_url,
|
||||
int64_t playback_start_time,
|
||||
int64_t last_playback_time) {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::StoreLicense: not initialized");
|
||||
return false;
|
||||
@@ -179,6 +186,8 @@ bool DeviceFiles::StoreLicense(const std::string& key_set_id,
|
||||
license->set_renewal_request(license_renewal_request);
|
||||
license->set_renewal(license_renewal);
|
||||
license->set_release_server_url(release_server_url);
|
||||
license->set_playback_start_time(playback_start_time);
|
||||
license->set_last_playback_time(last_playback_time);
|
||||
|
||||
std::string serialized_file;
|
||||
file.SerializeToString(&serialized_file);
|
||||
@@ -193,7 +202,9 @@ bool DeviceFiles::RetrieveLicense(const std::string& key_set_id,
|
||||
CdmKeyResponse* license_message,
|
||||
CdmKeyMessage* license_renewal_request,
|
||||
CdmKeyResponse* license_renewal,
|
||||
std::string* release_server_url) {
|
||||
std::string* release_server_url,
|
||||
int64_t* playback_start_time,
|
||||
int64_t* last_playback_time) {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::RetrieveLicense: not initialized");
|
||||
return false;
|
||||
@@ -245,6 +256,8 @@ bool DeviceFiles::RetrieveLicense(const std::string& key_set_id,
|
||||
*license_renewal_request = license.renewal_request();
|
||||
*license_renewal = license.renewal();
|
||||
*release_server_url = license.release_server_url();
|
||||
*playback_start_time = license.playback_start_time();
|
||||
*last_playback_time = license.last_playback_time();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -454,7 +467,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;
|
||||
}
|
||||
@@ -514,7 +527,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;
|
||||
}
|
||||
@@ -663,8 +676,7 @@ std::string DeviceFiles::GetUsageInfoFileName() {
|
||||
}
|
||||
|
||||
void DeviceFiles::SetTestFile(File* file) {
|
||||
if (file_) delete file_;
|
||||
file_ = file;
|
||||
file_.reset(file);
|
||||
test_file_ = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ message License {
|
||||
optional bytes renewal_request = 5;
|
||||
optional bytes renewal = 6;
|
||||
optional bytes release_server_url = 7;
|
||||
optional int64 playback_start_time = 8 [default = 0];
|
||||
optional int64 last_playback_time = 9 [default = 0];
|
||||
}
|
||||
|
||||
message UsageInfo {
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
|
||||
#include "license.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "clock.h"
|
||||
#include "crypto_key.h"
|
||||
#include "crypto_session.h"
|
||||
#include "device_files.h"
|
||||
@@ -22,7 +25,6 @@ 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,
|
||||
@@ -80,6 +82,7 @@ namespace wvcdm {
|
||||
|
||||
// Protobuf generated classes.
|
||||
using video_widevine_server::sdk::ClientIdentification;
|
||||
using video_widevine_server::sdk::ClientIdentification_ClientCapabilities;
|
||||
using video_widevine_server::sdk::ClientIdentification_NameValue;
|
||||
using video_widevine_server::sdk::DeviceCertificate;
|
||||
using video_widevine_server::sdk::EncryptedClientIdentification;
|
||||
@@ -140,6 +143,24 @@ static std::vector<CryptoKey> ExtractContentKeys(const License& license) {
|
||||
return key_array;
|
||||
}
|
||||
|
||||
CdmLicense::CdmLicense()
|
||||
: session_(NULL),
|
||||
initialized_(false),
|
||||
clock_(new Clock()) {
|
||||
}
|
||||
|
||||
CdmLicense::CdmLicense(Clock* clock)
|
||||
: session_(NULL),
|
||||
initialized_(false) {
|
||||
if (NULL == clock) {
|
||||
LOGE("CdmLicense::CdmLicense: clock parameter not provided");
|
||||
return;
|
||||
}
|
||||
clock_.reset(clock);
|
||||
}
|
||||
|
||||
CdmLicense::~CdmLicense() {}
|
||||
|
||||
bool CdmLicense::Init(const std::string& token, CryptoSession* session,
|
||||
PolicyEngine* policy_engine) {
|
||||
if (token.size() == 0) {
|
||||
@@ -206,7 +227,7 @@ bool CdmLicense::PrepareKeyRequest(const InitializationData& init_data,
|
||||
}
|
||||
|
||||
std::string request_id;
|
||||
session_->GenerateRequestId(request_id);
|
||||
session_->GenerateRequestId(&request_id);
|
||||
|
||||
LicenseRequest license_request;
|
||||
ClientIdentification* client_id = license_request.mutable_client_id();
|
||||
@@ -260,11 +281,54 @@ bool CdmLicense::PrepareKeyRequest(const InitializationData& init_data,
|
||||
client_info->set_name(kDeviceIdKey);
|
||||
client_info->set_value(value);
|
||||
}
|
||||
|
||||
ClientIdentification_ClientCapabilities* client_capabilities =
|
||||
client_id->mutable_client_capabilities();
|
||||
bool supports_usage_information;
|
||||
if (session_->UsageInformationSupport(&supports_usage_information)) {
|
||||
client_capabilities->set_session_token(supports_usage_information);
|
||||
}
|
||||
|
||||
CryptoSession::OemCryptoHdcpVersion current_version, max_version;
|
||||
if (session_->GetHdcpCapabilities(¤t_version, &max_version)) {
|
||||
switch (max_version) {
|
||||
case CryptoSession::kOemCryptoHdcpNotSupported:
|
||||
client_capabilities->set_max_hdcp_version(
|
||||
video_widevine_server::sdk::
|
||||
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_NONE);
|
||||
break;
|
||||
case CryptoSession::kOemCryptoHdcpVersion1:
|
||||
client_capabilities->set_max_hdcp_version(
|
||||
video_widevine_server::sdk::
|
||||
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V1);
|
||||
break;
|
||||
case CryptoSession::kOemCryptoHdcpVersion2:
|
||||
client_capabilities->set_max_hdcp_version(
|
||||
video_widevine_server::sdk::
|
||||
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2);
|
||||
break;
|
||||
case CryptoSession::kOemCryptoHdcpVersion2_1:
|
||||
client_capabilities->set_max_hdcp_version(
|
||||
video_widevine_server::sdk::
|
||||
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2_1);
|
||||
break;
|
||||
case CryptoSession::kOemCryptoHdcpVersion2_2:
|
||||
client_capabilities->set_max_hdcp_version(
|
||||
video_widevine_server::sdk::
|
||||
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2_2);
|
||||
break;
|
||||
case CryptoSession::kOemCryptoNoHdcpDeviceAttached:
|
||||
default:
|
||||
LOGW(
|
||||
"CdmLicense::PrepareKeyRequest: unexpected HDCP max capability "
|
||||
"version %d",
|
||||
max_version);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
client_capabilities->set_oem_crypto_api_version(version);
|
||||
}
|
||||
|
||||
if (privacy_mode_enabled) {
|
||||
@@ -359,12 +423,10 @@ 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);
|
||||
|
||||
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;
|
||||
@@ -430,21 +492,47 @@ bool CdmLicense::PrepareKeyUpdateRequest(bool is_renewal,
|
||||
else
|
||||
license_request.set_type(LicenseRequest::RELEASE);
|
||||
|
||||
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();
|
||||
current_license->mutable_license_id()->CopyFrom(license_id);
|
||||
|
||||
if (!is_renewal) {
|
||||
if (license_id.has_provider_session_token()) {
|
||||
std::string usage_report;
|
||||
if (NO_ERROR !=
|
||||
session_->GenerateUsageReport(license_id.provider_session_token(),
|
||||
&usage_report)) {
|
||||
int64_t seconds_since_started, seconds_since_last_played;
|
||||
CryptoSession::UsageDurationStatus usage_duration_status =
|
||||
CryptoSession::kUsageDurationsInvalid;
|
||||
if (!provider_session_token_.empty()) {
|
||||
if (!is_renewal) {
|
||||
CdmResponseType status =
|
||||
session_->DeactivateUsageInformation(provider_session_token_);
|
||||
if (NO_ERROR != status)
|
||||
return false;
|
||||
}
|
||||
current_license->set_session_usage_table_entry(usage_report);
|
||||
}
|
||||
|
||||
std::string usage_report;
|
||||
CdmResponseType status =
|
||||
session_->GenerateUsageReport(provider_session_token_,
|
||||
&usage_report, &usage_duration_status,
|
||||
&seconds_since_started,
|
||||
&seconds_since_last_played);
|
||||
if (!is_renewal) {
|
||||
if (NO_ERROR == status)
|
||||
current_license->set_session_usage_table_entry(usage_report);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (CryptoSession::kUsageDurationsValid != usage_duration_status) {
|
||||
if (policy_engine_->GetSecondsSinceStarted(&seconds_since_started) &&
|
||||
policy_engine_->GetSecondsSinceLastPlayed(&seconds_since_last_played))
|
||||
usage_duration_status = CryptoSession::kUsageDurationsValid;
|
||||
}
|
||||
|
||||
if (CryptoSession::kUsageDurationsValid == usage_duration_status) {
|
||||
current_license->set_seconds_since_started(seconds_since_started);
|
||||
current_license->set_seconds_since_last_played(seconds_since_last_played);
|
||||
}
|
||||
|
||||
// Get/set the nonce. This value will be reflected in the Key Control Block
|
||||
@@ -664,7 +752,9 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
||||
bool CdmLicense::RestoreOfflineLicense(
|
||||
const CdmKeyMessage& license_request,
|
||||
const CdmKeyResponse& license_response,
|
||||
const CdmKeyResponse& license_renewal_response) {
|
||||
const CdmKeyResponse& license_renewal_response,
|
||||
int64_t playback_start_time,
|
||||
int64_t last_playback_time) {
|
||||
|
||||
if (license_request.empty() || license_response.empty()) {
|
||||
LOGE(
|
||||
@@ -704,6 +794,36 @@ bool CdmLicense::RestoreOfflineLicense(
|
||||
if (sts != KEY_ADDED) return false;
|
||||
}
|
||||
|
||||
if (!provider_session_token_.empty()) {
|
||||
std::string usage_report;
|
||||
CryptoSession::UsageDurationStatus usage_duration_status =
|
||||
CryptoSession::kUsageDurationsInvalid;
|
||||
int64_t seconds_since_started, seconds_since_last_played;
|
||||
sts = session_->GenerateUsageReport(
|
||||
provider_session_token_, &usage_report, &usage_duration_status,
|
||||
&seconds_since_started, &seconds_since_last_played);
|
||||
|
||||
if (NO_ERROR == sts) {
|
||||
switch (usage_duration_status) {
|
||||
case CryptoSession::kUsageDurationPlaybackNotBegun:
|
||||
playback_start_time = 0;
|
||||
last_playback_time = 0;
|
||||
break;
|
||||
case CryptoSession::kUsageDurationsValid: {
|
||||
int64_t current_time = clock_->GetCurrentTime();
|
||||
if (current_time - seconds_since_started > 0)
|
||||
playback_start_time = current_time - seconds_since_started;
|
||||
if (current_time - last_playback_time > 0)
|
||||
last_playback_time = current_time - seconds_since_last_played;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
policy_engine_->RestorePlaybackTimes(playback_start_time, last_playback_time);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -287,12 +287,6 @@ message SignedMessage {
|
||||
|
||||
// This message is used to pass optional data on initial license issuance.
|
||||
message SessionInit {
|
||||
enum ReplayControl {
|
||||
NO_SESSION_USAGE = 0;
|
||||
NONCE_REQUIRED_AND_NEW_SESSION_USAGE = 1;
|
||||
NONCE_REQUIRED_OR_EXISTING_SESSION_USAGE = 2;
|
||||
}
|
||||
|
||||
optional bytes session_id = 1;
|
||||
optional bytes purchase_id = 2;
|
||||
// master_signing_key should be 128 bits in length.
|
||||
@@ -312,8 +306,6 @@ message SessionInit {
|
||||
// LicenseIdentfication::provider_session_token, and sent back in all
|
||||
// license renewal and release requests for the session thereafter.
|
||||
optional bytes provider_session_token = 7;
|
||||
// Replay control indicator which will be encoded into V9+ KeyControl blocks.
|
||||
optional ReplayControl replay_control = 8 [default = NO_SESSION_USAGE];
|
||||
}
|
||||
|
||||
// This message is used by the server to preserve and restore session state.
|
||||
@@ -415,6 +407,7 @@ message ClientIdentification {
|
||||
optional bool session_token = 2 [default = false];
|
||||
optional bool video_resolution_constraints = 3 [default = false];
|
||||
optional HdcpVersion max_hdcp_version = 4 [default = HDCP_NONE];
|
||||
optional uint32 oem_crypto_api_version = 5;
|
||||
}
|
||||
|
||||
// Type of factory-provisioned device root of trust. Optional.
|
||||
|
||||
@@ -95,7 +95,7 @@ OEMCryptoResult OEMCrypto_GetHDCPCapability(OEMCrypto_HDCP_Capability *current,
|
||||
}
|
||||
|
||||
extern "C" bool OEMCrypto_SupportsUsageTable() {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_UpdateUsageTable() {
|
||||
|
||||
@@ -33,8 +33,8 @@ void PolicyEngine::Init(Clock* clock) {
|
||||
license_state_ = kLicenseStateInitial;
|
||||
can_decrypt_ = false;
|
||||
license_start_time_ = 0;
|
||||
license_received_time_ = 0;
|
||||
playback_start_time_ = 0;
|
||||
last_playback_time_ = 0;
|
||||
next_renewal_time_ = 0;
|
||||
policy_max_duration_seconds_ = 0;
|
||||
clock_ = clock;
|
||||
@@ -76,6 +76,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 +123,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 +135,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 +159,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() {
|
||||
@@ -172,12 +180,14 @@ void PolicyEngine::BeginDecryption() {
|
||||
case kLicenseStateNeedRenewal:
|
||||
case kLicenseStateWaitingLicenseUpdate:
|
||||
playback_start_time_ = clock_->GetCurrentTime();
|
||||
last_playback_time_ = playback_start_time_;
|
||||
|
||||
if (policy_.renew_with_usage()) {
|
||||
license_state_ = kLicenseStateNeedRenewal;
|
||||
}
|
||||
break;
|
||||
case kLicenseStateInitial:
|
||||
case kLicenseStatePending:
|
||||
case kLicenseStateExpired:
|
||||
default:
|
||||
break;
|
||||
@@ -185,6 +195,10 @@ void PolicyEngine::BeginDecryption() {
|
||||
}
|
||||
}
|
||||
|
||||
void PolicyEngine::DecryptionEvent() {
|
||||
last_playback_time_ = clock_->GetCurrentTime();
|
||||
}
|
||||
|
||||
CdmResponseType PolicyEngine::Query(CdmQueryMap* key_info) {
|
||||
std::stringstream ss;
|
||||
int64_t current_time = clock_->GetCurrentTime();
|
||||
@@ -211,6 +225,27 @@ CdmResponseType PolicyEngine::Query(CdmQueryMap* key_info) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
bool PolicyEngine::GetSecondsSinceStarted(int64_t* seconds_since_started) {
|
||||
if (playback_start_time_ == 0) return false;
|
||||
|
||||
*seconds_since_started = clock_->GetCurrentTime() - playback_start_time_;
|
||||
return (*seconds_since_started >= 0) ? true : false;
|
||||
}
|
||||
|
||||
bool PolicyEngine::GetSecondsSinceLastPlayed(
|
||||
int64_t* seconds_since_last_played) {
|
||||
if (last_playback_time_ == 0) return false;
|
||||
|
||||
*seconds_since_last_played = clock_->GetCurrentTime() - last_playback_time_;
|
||||
return (*seconds_since_last_played >= 0) ? true : false;
|
||||
}
|
||||
|
||||
void PolicyEngine::RestorePlaybackTimes(int64_t playback_start_time,
|
||||
int64_t last_playback_time) {
|
||||
playback_start_time_ = (playback_start_time > 0) ? playback_start_time : 0;
|
||||
last_playback_time_ = (last_playback_time > 0) ? last_playback_time : 0;
|
||||
}
|
||||
|
||||
void PolicyEngine::UpdateRenewalRequest(int64_t current_time) {
|
||||
license_state_ = kLicenseStateWaitingLicenseUpdate;
|
||||
next_renewal_time_ = current_time + policy_.renewal_retry_interval_seconds();
|
||||
@@ -221,7 +256,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 +264,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 +294,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 +302,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;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user