Merge "Report key status change"
This commit is contained in:
@@ -128,7 +128,6 @@ class CdmSession {
|
|||||||
// instance variables
|
// instance variables
|
||||||
bool initialized_;
|
bool initialized_;
|
||||||
CdmSessionId session_id_;
|
CdmSessionId session_id_;
|
||||||
WvCdmEventListener* event_listener_;
|
|
||||||
scoped_ptr<CdmLicense> license_parser_;
|
scoped_ptr<CdmLicense> license_parser_;
|
||||||
scoped_ptr<CryptoSession> crypto_session_;
|
scoped_ptr<CryptoSession> crypto_session_;
|
||||||
scoped_ptr<PolicyEngine> policy_engine_;
|
scoped_ptr<PolicyEngine> policy_engine_;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#ifndef WVCDM_CORE_POLICY_ENGINE_H_
|
#ifndef WVCDM_CORE_POLICY_ENGINE_H_
|
||||||
#define WVCDM_CORE_POLICY_ENGINE_H_
|
#define WVCDM_CORE_POLICY_ENGINE_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "license_protocol.pb.h"
|
#include "license_protocol.pb.h"
|
||||||
@@ -59,6 +60,8 @@ class PolicyEngine {
|
|||||||
// Used for notifying the Policy Engine of resolution changes
|
// Used for notifying the Policy Engine of resolution changes
|
||||||
virtual void NotifyResolution(uint32_t width, uint32_t height);
|
virtual void NotifyResolution(uint32_t width, uint32_t height);
|
||||||
|
|
||||||
|
virtual void NotifySessionExpiration();
|
||||||
|
|
||||||
virtual CdmResponseType Query(CdmQueryMap* key_info);
|
virtual CdmResponseType Query(CdmQueryMap* key_info);
|
||||||
|
|
||||||
virtual const LicenseIdentification& license_id() { return license_id_; }
|
virtual const LicenseIdentification& license_id() { return license_id_; }
|
||||||
@@ -105,15 +108,19 @@ class PolicyEngine {
|
|||||||
|
|
||||||
void UpdateRenewalRequest(int64_t current_time);
|
void UpdateRenewalRequest(int64_t current_time);
|
||||||
|
|
||||||
|
// Notifies updates in keys information and fire OnKeysChange event if
|
||||||
|
// key changes.
|
||||||
|
void NotifyKeysChange(CdmKeyStatus new_status);
|
||||||
|
|
||||||
// Notifies updates in expiry time and fire OnExpirationUpdate event if
|
// Notifies updates in expiry time and fire OnExpirationUpdate event if
|
||||||
// expiry time changes.
|
// expiry time changes.
|
||||||
void NotifyExpirationUpdate();
|
void NotifyExpirationUpdate();
|
||||||
|
|
||||||
// These setters are for testing only. Takes ownership of the pointers.
|
// These setters are for testing only. Takes ownership of the pointers.
|
||||||
void set_clock(Clock* clock);
|
void set_clock(Clock* clock);
|
||||||
|
void set_max_res_engine(MaxResEngine* max_res_engine);
|
||||||
|
|
||||||
LicenseState license_state_;
|
LicenseState license_state_;
|
||||||
bool can_decrypt_;
|
|
||||||
|
|
||||||
// This is the current policy information for this license. This gets updated
|
// This is the current policy information for this license. This gets updated
|
||||||
// as license renewals occur.
|
// as license renewals occur.
|
||||||
@@ -142,7 +149,10 @@ class PolicyEngine {
|
|||||||
CdmSessionId session_id_;
|
CdmSessionId session_id_;
|
||||||
WvCdmEventListener* event_listener_;
|
WvCdmEventListener* event_listener_;
|
||||||
|
|
||||||
MaxResEngine max_res_engine_;
|
scoped_ptr<MaxResEngine> max_res_engine_;
|
||||||
|
|
||||||
|
std::map<KeyId, CdmKeyStatus> keys_status_;
|
||||||
|
|
||||||
scoped_ptr<Clock> clock_;
|
scoped_ptr<Clock> clock_;
|
||||||
|
|
||||||
CORE_DISALLOW_COPY_AND_ASSIGN(PolicyEngine);
|
CORE_DISALLOW_COPY_AND_ASSIGN(PolicyEngine);
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ class WvCdmEventListener {
|
|||||||
|
|
||||||
virtual void OnSessionRenewalNeeded(const CdmSessionId& session_id) = 0;
|
virtual void OnSessionRenewalNeeded(const CdmSessionId& session_id) = 0;
|
||||||
virtual void OnSessionExpiration(const CdmSessionId& session_id) = 0;
|
virtual void OnSessionExpiration(const CdmSessionId& session_id) = 0;
|
||||||
|
virtual void OnSessionKeysChange(
|
||||||
|
const CdmSessionId& session_id,
|
||||||
|
const std::vector<CdmKeyInformation>& cdm_keys_info,
|
||||||
|
bool has_new_usable_key) = 0;
|
||||||
virtual void OnExpirationUpdate(const CdmSessionId& session_id,
|
virtual void OnExpirationUpdate(const CdmSessionId& session_id,
|
||||||
int64_t new_expiry_time) = 0;
|
int64_t new_expiry_time) = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,15 @@ enum CdmResponseType {
|
|||||||
INSUFFICIENT_CRYPTO_RESOURCES,
|
INSUFFICIENT_CRYPTO_RESOURCES,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum CdmKeyStatus {
|
||||||
|
kKeyStatusUsable,
|
||||||
|
kKeyStatusInternalError,
|
||||||
|
kKeyStatusExpired,
|
||||||
|
kKeyStatusOutputNotAllowed,
|
||||||
|
kKeyStatusOutputDownscaled,
|
||||||
|
kKeyStatusPending,
|
||||||
|
};
|
||||||
|
|
||||||
#define CORE_DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
#define CORE_DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||||
TypeName(const TypeName&); \
|
TypeName(const TypeName&); \
|
||||||
void operator=(const TypeName&)
|
void operator=(const TypeName&)
|
||||||
@@ -116,6 +125,14 @@ struct CdmDecryptionParameters {
|
|||||||
is_video(true) {}
|
is_video(true) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CdmKeyInformation {
|
||||||
|
CdmKeyInformation(const KeyId& id, CdmKeyStatus status)
|
||||||
|
: key_id(id), key_status(status) {}
|
||||||
|
|
||||||
|
KeyId key_id;
|
||||||
|
CdmKeyStatus key_status;
|
||||||
|
};
|
||||||
|
|
||||||
// forward class references
|
// forward class references
|
||||||
class KeyMessage;
|
class KeyMessage;
|
||||||
class Request;
|
class Request;
|
||||||
|
|||||||
@@ -27,11 +27,10 @@ CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set,
|
|||||||
WvCdmEventListener* event_listener)
|
WvCdmEventListener* event_listener)
|
||||||
: initialized_(false),
|
: initialized_(false),
|
||||||
session_id_(GenerateSessionId()),
|
session_id_(GenerateSessionId()),
|
||||||
event_listener_(event_listener),
|
|
||||||
license_parser_(new CdmLicense),
|
license_parser_(new CdmLicense),
|
||||||
crypto_session_(new CryptoSession),
|
crypto_session_(new CryptoSession),
|
||||||
policy_engine_(new PolicyEngine(session_id_, event_listener_,
|
policy_engine_(
|
||||||
crypto_session_.get())),
|
new PolicyEngine(session_id_, event_listener, crypto_session_.get())),
|
||||||
file_handle_(new DeviceFiles),
|
file_handle_(new DeviceFiles),
|
||||||
license_received_(false),
|
license_received_(false),
|
||||||
is_offline_(false),
|
is_offline_(false),
|
||||||
@@ -532,7 +531,7 @@ void CdmSession::OnTimerEvent(bool update_usage) {
|
|||||||
|
|
||||||
void CdmSession::OnKeyReleaseEvent(const CdmKeySetId& key_set_id) {
|
void CdmSession::OnKeyReleaseEvent(const CdmKeySetId& key_set_id) {
|
||||||
if (key_set_id_ == key_set_id) {
|
if (key_set_id_ == key_set_id) {
|
||||||
if (event_listener_) event_listener_->OnSessionExpiration(session_id_);
|
policy_engine_->NotifySessionExpiration();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,13 +15,14 @@
|
|||||||
#include "wv_cdm_constants.h"
|
#include "wv_cdm_constants.h"
|
||||||
#include "wv_cdm_event_listener.h"
|
#include "wv_cdm_event_listener.h"
|
||||||
|
|
||||||
|
using video_widevine_server::sdk::License;
|
||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
|
|
||||||
PolicyEngine::PolicyEngine(CdmSessionId session_id,
|
PolicyEngine::PolicyEngine(CdmSessionId session_id,
|
||||||
WvCdmEventListener* event_listener,
|
WvCdmEventListener* event_listener,
|
||||||
CryptoSession* crypto_session)
|
CryptoSession* crypto_session)
|
||||||
: license_state_(kLicenseStateInitial),
|
: license_state_(kLicenseStateInitial),
|
||||||
can_decrypt_(false),
|
|
||||||
license_start_time_(0),
|
license_start_time_(0),
|
||||||
playback_start_time_(0),
|
playback_start_time_(0),
|
||||||
last_playback_time_(0),
|
last_playback_time_(0),
|
||||||
@@ -30,13 +31,18 @@ PolicyEngine::PolicyEngine(CdmSessionId session_id,
|
|||||||
policy_max_duration_seconds_(0),
|
policy_max_duration_seconds_(0),
|
||||||
session_id_(session_id),
|
session_id_(session_id),
|
||||||
event_listener_(event_listener),
|
event_listener_(event_listener),
|
||||||
max_res_engine_(crypto_session),
|
max_res_engine_(new MaxResEngine(crypto_session)),
|
||||||
clock_(new Clock) {}
|
clock_(new Clock) {}
|
||||||
|
|
||||||
PolicyEngine::~PolicyEngine() {}
|
PolicyEngine::~PolicyEngine() {}
|
||||||
|
|
||||||
bool PolicyEngine::CanDecrypt(const KeyId& key_id) {
|
bool PolicyEngine::CanDecrypt(const KeyId& key_id) {
|
||||||
return can_decrypt_ && max_res_engine_.CanDecrypt(key_id);
|
if (keys_status_.find(key_id) == keys_status_.end()) {
|
||||||
|
LOGE("PolicyEngine::CanDecrypt Key '%s' not in license.",
|
||||||
|
b2a_hex(key_id).c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return keys_status_[key_id] == kKeyStatusUsable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolicyEngine::OnTimerEvent() {
|
void PolicyEngine::OnTimerEvent() {
|
||||||
@@ -47,17 +53,21 @@ void PolicyEngine::OnTimerEvent() {
|
|||||||
IsPlaybackDurationExpired(current_time)) &&
|
IsPlaybackDurationExpired(current_time)) &&
|
||||||
license_state_ != kLicenseStateExpired) {
|
license_state_ != kLicenseStateExpired) {
|
||||||
license_state_ = kLicenseStateExpired;
|
license_state_ = kLicenseStateExpired;
|
||||||
can_decrypt_ = false;
|
NotifyKeysChange(kKeyStatusExpired);
|
||||||
if (event_listener_) event_listener_->OnSessionExpiration(session_id_);
|
if (event_listener_) event_listener_->OnSessionExpiration(session_id_);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
max_res_engine_->OnTimerEvent();
|
||||||
|
|
||||||
bool renewal_needed = false;
|
bool renewal_needed = false;
|
||||||
|
|
||||||
// Test to determine if renewal should be attempted.
|
// Test to determine if renewal should be attempted.
|
||||||
switch (license_state_) {
|
switch (license_state_) {
|
||||||
case kLicenseStateCanPlay: {
|
case kLicenseStateCanPlay: {
|
||||||
if (IsRenewalDelayExpired(current_time)) renewal_needed = true;
|
if (IsRenewalDelayExpired(current_time)) renewal_needed = true;
|
||||||
|
// HDCP may change, so force a check.
|
||||||
|
NotifyKeysChange(kKeyStatusUsable);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +84,7 @@ void PolicyEngine::OnTimerEvent() {
|
|||||||
case kLicenseStatePending: {
|
case kLicenseStatePending: {
|
||||||
if (current_time >= license_start_time_) {
|
if (current_time >= license_start_time_) {
|
||||||
license_state_ = kLicenseStateCanPlay;
|
license_state_ = kLicenseStateCanPlay;
|
||||||
can_decrypt_ = true;
|
NotifyKeysChange(kKeyStatusUsable);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -86,7 +96,7 @@ void PolicyEngine::OnTimerEvent() {
|
|||||||
|
|
||||||
default: {
|
default: {
|
||||||
license_state_ = kLicenseStateExpired;
|
license_state_ = kLicenseStateExpired;
|
||||||
can_decrypt_ = false;
|
NotifyKeysChange(kKeyStatusInternalError);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,21 +105,26 @@ void PolicyEngine::OnTimerEvent() {
|
|||||||
UpdateRenewalRequest(current_time);
|
UpdateRenewalRequest(current_time);
|
||||||
if (event_listener_) event_listener_->OnSessionRenewalNeeded(session_id_);
|
if (event_listener_) event_listener_->OnSessionRenewalNeeded(session_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
max_res_engine_.OnTimerEvent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolicyEngine::SetLicense(
|
void PolicyEngine::SetLicense(const License& license) {
|
||||||
const video_widevine_server::sdk::License& license) {
|
|
||||||
license_id_.Clear();
|
license_id_.Clear();
|
||||||
license_id_.CopyFrom(license.id());
|
license_id_.CopyFrom(license.id());
|
||||||
policy_.Clear();
|
policy_.Clear();
|
||||||
UpdateLicense(license);
|
|
||||||
max_res_engine_.SetLicense(license);
|
// Extract content key ids.
|
||||||
|
keys_status_.clear();
|
||||||
|
for (int key_index = 0; key_index < license.key_size(); ++key_index) {
|
||||||
|
const License::KeyContainer& key = license.key(key_index);
|
||||||
|
if (key.type() == License::KeyContainer::CONTENT && key.has_id())
|
||||||
|
keys_status_[key.id()] = kKeyStatusInternalError;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolicyEngine::UpdateLicense(
|
UpdateLicense(license);
|
||||||
const video_widevine_server::sdk::License& license) {
|
max_res_engine_->SetLicense(license);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PolicyEngine::UpdateLicense(const License& license) {
|
||||||
if (!license.has_policy()) return;
|
if (!license.has_policy()) return;
|
||||||
|
|
||||||
if (kLicenseStateExpired == license_state_) {
|
if (kLicenseStateExpired == license_state_) {
|
||||||
@@ -153,16 +168,17 @@ void PolicyEngine::UpdateLicense(
|
|||||||
if (!policy_.can_play() || IsLicenseDurationExpired(current_time) ||
|
if (!policy_.can_play() || IsLicenseDurationExpired(current_time) ||
|
||||||
IsPlaybackDurationExpired(current_time)) {
|
IsPlaybackDurationExpired(current_time)) {
|
||||||
license_state_ = kLicenseStateExpired;
|
license_state_ = kLicenseStateExpired;
|
||||||
|
NotifyKeysChange(kKeyStatusExpired);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update state
|
// Update state
|
||||||
if (current_time >= license_start_time_) {
|
if (current_time >= license_start_time_) {
|
||||||
license_state_ = kLicenseStateCanPlay;
|
license_state_ = kLicenseStateCanPlay;
|
||||||
can_decrypt_ = true;
|
NotifyKeysChange(kKeyStatusUsable);
|
||||||
} else {
|
} else {
|
||||||
license_state_ = kLicenseStatePending;
|
license_state_ = kLicenseStatePending;
|
||||||
can_decrypt_ = false;
|
NotifyKeysChange(kKeyStatusPending);
|
||||||
}
|
}
|
||||||
NotifyExpirationUpdate();
|
NotifyExpirationUpdate();
|
||||||
}
|
}
|
||||||
@@ -195,7 +211,13 @@ void PolicyEngine::DecryptionEvent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PolicyEngine::NotifyResolution(uint32_t width, uint32_t height) {
|
void PolicyEngine::NotifyResolution(uint32_t width, uint32_t height) {
|
||||||
max_res_engine_.SetResolution(width, height);
|
max_res_engine_->SetResolution(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PolicyEngine::NotifySessionExpiration() {
|
||||||
|
license_state_ = kLicenseStateExpired;
|
||||||
|
NotifyKeysChange(kKeyStatusExpired);
|
||||||
|
if (event_listener_) event_listener_->OnSessionExpiration(session_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType PolicyEngine::Query(CdmQueryMap* key_info) {
|
CdmResponseType PolicyEngine::Query(CdmQueryMap* key_info) {
|
||||||
@@ -303,6 +325,35 @@ bool PolicyEngine::IsRenewalRetryIntervalExpired(int64_t current_time) {
|
|||||||
next_renewal_time_ <= current_time;
|
next_renewal_time_ <= current_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PolicyEngine::NotifyKeysChange(CdmKeyStatus new_status) {
|
||||||
|
bool keys_changed = false;
|
||||||
|
bool has_new_usable_key = false;
|
||||||
|
for (std::map<KeyId, CdmKeyStatus>::iterator it = keys_status_.begin();
|
||||||
|
it != keys_status_.end(); ++it) {
|
||||||
|
const KeyId key_id = it->first;
|
||||||
|
CdmKeyStatus& key_status = it->second;
|
||||||
|
CdmKeyStatus updated_status = new_status;
|
||||||
|
if (updated_status == kKeyStatusUsable) {
|
||||||
|
if (!max_res_engine_->CanDecrypt(key_id))
|
||||||
|
updated_status = kKeyStatusOutputNotAllowed;
|
||||||
|
}
|
||||||
|
if (key_status != updated_status) {
|
||||||
|
key_status = updated_status;
|
||||||
|
if (updated_status == kKeyStatusUsable) has_new_usable_key = true;
|
||||||
|
keys_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (keys_changed && event_listener_) {
|
||||||
|
std::vector<CdmKeyInformation> keys_info;
|
||||||
|
for (std::map<KeyId, CdmKeyStatus>::iterator it = keys_status_.begin();
|
||||||
|
it != keys_status_.end(); ++it) {
|
||||||
|
keys_info.push_back(CdmKeyInformation(it->first, it->second));
|
||||||
|
}
|
||||||
|
event_listener_->OnSessionKeysChange(session_id_, keys_info,
|
||||||
|
has_new_usable_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PolicyEngine::NotifyExpirationUpdate() {
|
void PolicyEngine::NotifyExpirationUpdate() {
|
||||||
int64_t expiry_time =
|
int64_t expiry_time =
|
||||||
std::min(GetLicenseExpiryTime(), GetPlaybackExpiryTime());
|
std::min(GetLicenseExpiryTime(), GetPlaybackExpiryTime());
|
||||||
@@ -315,4 +366,8 @@ void PolicyEngine::NotifyExpirationUpdate() {
|
|||||||
|
|
||||||
void PolicyEngine::set_clock(Clock* clock) { clock_.reset(clock); }
|
void PolicyEngine::set_clock(Clock* clock) { clock_.reset(clock); }
|
||||||
|
|
||||||
|
void PolicyEngine::set_max_res_engine(MaxResEngine* max_res_engine) {
|
||||||
|
max_res_engine_.reset(max_res_engine);
|
||||||
|
}
|
||||||
|
|
||||||
} // wvcdm
|
} // wvcdm
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ const int64_t kHighDuration =
|
|||||||
const char* kRenewalServerUrl =
|
const char* kRenewalServerUrl =
|
||||||
"https://test.google.com/license/GetCencLicense";
|
"https://test.google.com/license/GetCencLicense";
|
||||||
const wvcdm::KeyId kKeyId = "357adc89f1673433c36c621f1b5c41ee";
|
const wvcdm::KeyId kKeyId = "357adc89f1673433c36c621f1b5c41ee";
|
||||||
|
const wvcdm::KeyId kAnotherKeyId = "another_key_id";
|
||||||
|
const wvcdm::KeyId kSomeRandomKeyId = "some_random_key_id";
|
||||||
const wvcdm::CdmSessionId kSessionId = "mock_session_id";
|
const wvcdm::CdmSessionId kSessionId = "mock_session_id";
|
||||||
|
|
||||||
int64_t GetLicenseRenewalDelay(int64_t license_duration) {
|
int64_t GetLicenseRenewalDelay(int64_t license_duration) {
|
||||||
@@ -58,20 +60,34 @@ using video_widevine_server::sdk::OFFLINE;
|
|||||||
|
|
||||||
// gmock methods
|
// gmock methods
|
||||||
using ::testing::_;
|
using ::testing::_;
|
||||||
|
using ::testing::AllOf;
|
||||||
using ::testing::AtLeast;
|
using ::testing::AtLeast;
|
||||||
|
using ::testing::Field;
|
||||||
using ::testing::InSequence;
|
using ::testing::InSequence;
|
||||||
using ::testing::MockFunction;
|
using ::testing::MockFunction;
|
||||||
using ::testing::Return;
|
using ::testing::Return;
|
||||||
using ::testing::StrictMock;
|
using ::testing::StrictMock;
|
||||||
|
using ::testing::UnorderedElementsAre;
|
||||||
|
|
||||||
class MockCdmEventListener : public WvCdmEventListener {
|
class MockCdmEventListener : public WvCdmEventListener {
|
||||||
public:
|
public:
|
||||||
MOCK_METHOD1(OnSessionRenewalNeeded, void(const CdmSessionId& session_id));
|
MOCK_METHOD1(OnSessionRenewalNeeded, void(const CdmSessionId& session_id));
|
||||||
MOCK_METHOD1(OnSessionExpiration, void(const CdmSessionId& session_id));
|
MOCK_METHOD1(OnSessionExpiration, void(const CdmSessionId& session_id));
|
||||||
|
MOCK_METHOD3(OnSessionKeysChange,
|
||||||
|
void(const CdmSessionId& session_id,
|
||||||
|
const std::vector<CdmKeyInformation>& cdm_keys_info,
|
||||||
|
bool has_new_usable_key));
|
||||||
MOCK_METHOD2(OnExpirationUpdate,
|
MOCK_METHOD2(OnExpirationUpdate,
|
||||||
void(const CdmSessionId& session_id, int64_t new_expiry_time));
|
void(const CdmSessionId& session_id, int64_t new_expiry_time));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MockMaxResEngine : public MaxResEngine {
|
||||||
|
public:
|
||||||
|
MockMaxResEngine() : MaxResEngine(NULL) {}
|
||||||
|
|
||||||
|
MOCK_METHOD1(CanDecrypt, bool(const KeyId& key_id));
|
||||||
|
};
|
||||||
|
|
||||||
class PolicyEngineTest : public ::testing::Test {
|
class PolicyEngineTest : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
@@ -85,6 +101,10 @@ class PolicyEngineTest : public ::testing::Test {
|
|||||||
id->set_version(1);
|
id->set_version(1);
|
||||||
id->set_type(STREAMING);
|
id->set_type(STREAMING);
|
||||||
|
|
||||||
|
License::KeyContainer* key = license_.add_key();
|
||||||
|
key->set_type(License::KeyContainer::CONTENT);
|
||||||
|
key->set_id(kKeyId);
|
||||||
|
|
||||||
License_Policy* policy = license_.mutable_policy();
|
License_Policy* policy = license_.mutable_policy();
|
||||||
policy = license_.mutable_policy();
|
policy = license_.mutable_policy();
|
||||||
policy->set_can_play(true);
|
policy->set_can_play(true);
|
||||||
@@ -120,8 +140,42 @@ class PolicyEngineTest : public ::testing::Test {
|
|||||||
policy_engine_->set_clock(mock_clock_);
|
policy_engine_->set_clock(mock_clock_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InjectMockMaxResEngine() {
|
||||||
|
mock_max_res_engine_ = new MockMaxResEngine();
|
||||||
|
policy_engine_->set_max_res_engine(mock_max_res_engine_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpectSessionKeysChange(CdmKeyStatus expected_key_status,
|
||||||
|
bool expected_has_new_usable_key) {
|
||||||
|
EXPECT_CALL(mock_event_listener_,
|
||||||
|
OnSessionKeysChange(
|
||||||
|
kSessionId,
|
||||||
|
UnorderedElementsAre(
|
||||||
|
AllOf(Field(&CdmKeyInformation::key_id, kKeyId),
|
||||||
|
Field(&CdmKeyInformation::key_status,
|
||||||
|
expected_key_status))),
|
||||||
|
expected_has_new_usable_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpectSessionKeysChange(CdmKeyStatus expected_key1_status,
|
||||||
|
CdmKeyStatus expected_key2_status,
|
||||||
|
bool expected_has_new_usable_key) {
|
||||||
|
EXPECT_CALL(mock_event_listener_,
|
||||||
|
OnSessionKeysChange(
|
||||||
|
kSessionId,
|
||||||
|
UnorderedElementsAre(
|
||||||
|
AllOf(Field(&CdmKeyInformation::key_id, kKeyId),
|
||||||
|
Field(&CdmKeyInformation::key_status,
|
||||||
|
expected_key1_status)),
|
||||||
|
AllOf(Field(&CdmKeyInformation::key_id, kAnotherKeyId),
|
||||||
|
Field(&CdmKeyInformation::key_status,
|
||||||
|
expected_key2_status))),
|
||||||
|
expected_has_new_usable_key));
|
||||||
|
}
|
||||||
|
|
||||||
StrictMock<MockCdmEventListener> mock_event_listener_;
|
StrictMock<MockCdmEventListener> mock_event_listener_;
|
||||||
MockClock* mock_clock_;
|
MockClock* mock_clock_;
|
||||||
|
MockMaxResEngine* mock_max_res_engine_;
|
||||||
scoped_ptr<PolicyEngine> policy_engine_;
|
scoped_ptr<PolicyEngine> policy_engine_;
|
||||||
License license_;
|
License license_;
|
||||||
MockFunction<void(int i)> check_;
|
MockFunction<void(int i)> check_;
|
||||||
@@ -137,6 +191,7 @@ TEST_F(PolicyEngineTest, PlaybackSuccess) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + 5))
|
.WillOnce(Return(kLicenseStartTime + 5))
|
||||||
.WillOnce(Return(kLicenseStartTime + 10));
|
.WillOnce(Return(kLicenseStartTime + 10));
|
||||||
|
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
||||||
|
|
||||||
@@ -146,6 +201,7 @@ TEST_F(PolicyEngineTest, PlaybackSuccess) {
|
|||||||
|
|
||||||
policy_engine_->BeginDecryption();
|
policy_engine_->BeginDecryption();
|
||||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId));
|
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId));
|
||||||
|
EXPECT_FALSE(policy_engine_->CanDecrypt(kSomeRandomKeyId));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PolicyEngineTest, PlaybackFailed_CanPlayFalse) {
|
TEST_F(PolicyEngineTest, PlaybackFailed_CanPlayFalse) {
|
||||||
@@ -156,6 +212,8 @@ TEST_F(PolicyEngineTest, PlaybackFailed_CanPlayFalse) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + 1))
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + 5));
|
.WillOnce(Return(kLicenseStartTime + 5));
|
||||||
|
|
||||||
|
ExpectSessionKeysChange(kKeyStatusExpired, false);
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId));
|
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId));
|
||||||
|
|
||||||
@@ -179,9 +237,11 @@ TEST_F(PolicyEngineTest, PlaybackFails_RentalDurationExpired) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + min_duration));
|
.WillOnce(Return(kLicenseStartTime + min_duration));
|
||||||
|
|
||||||
InSequence s;
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
||||||
EXPECT_CALL(check_, Call(1));
|
EXPECT_CALL(check_, Call(1));
|
||||||
|
ExpectSessionKeysChange(kKeyStatusExpired, false);
|
||||||
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(kSessionId));
|
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(kSessionId));
|
||||||
EXPECT_CALL(check_, Call(2));
|
EXPECT_CALL(check_, Call(2));
|
||||||
|
|
||||||
@@ -211,11 +271,13 @@ TEST_F(PolicyEngineTest, PlaybackFails_PlaybackDurationExpired) {
|
|||||||
.WillOnce(Return(playback_start_time + kPlaybackDuration + 2));
|
.WillOnce(Return(playback_start_time + kPlaybackDuration + 2));
|
||||||
|
|
||||||
InSequence s;
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kHighDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kHighDuration));
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, playback_start_time + kPlaybackDuration));
|
OnExpirationUpdate(_, playback_start_time + kPlaybackDuration));
|
||||||
EXPECT_CALL(check_, Call(1));
|
EXPECT_CALL(check_, Call(1));
|
||||||
|
ExpectSessionKeysChange(kKeyStatusExpired, false);
|
||||||
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
||||||
EXPECT_CALL(check_, Call(2));
|
EXPECT_CALL(check_, Call(2));
|
||||||
|
|
||||||
@@ -244,9 +306,11 @@ TEST_F(PolicyEngineTest, PlaybackFails_LicenseDurationExpired) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + min_duration));
|
.WillOnce(Return(kLicenseStartTime + min_duration));
|
||||||
|
|
||||||
InSequence s;
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
||||||
EXPECT_CALL(check_, Call(1));
|
EXPECT_CALL(check_, Call(1));
|
||||||
|
ExpectSessionKeysChange(kKeyStatusExpired, false);
|
||||||
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
||||||
EXPECT_CALL(check_, Call(2));
|
EXPECT_CALL(check_, Call(2));
|
||||||
|
|
||||||
@@ -275,9 +339,11 @@ TEST_F(PolicyEngineTest, PlaybackFails_ExpiryBeforeRenewalDelay) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + min_duration));
|
.WillOnce(Return(kLicenseStartTime + min_duration));
|
||||||
|
|
||||||
InSequence s;
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
||||||
EXPECT_CALL(check_, Call(1));
|
EXPECT_CALL(check_, Call(1));
|
||||||
|
ExpectSessionKeysChange(kKeyStatusExpired, false);
|
||||||
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
||||||
EXPECT_CALL(check_, Call(2));
|
EXPECT_CALL(check_, Call(2));
|
||||||
|
|
||||||
@@ -309,6 +375,7 @@ TEST_F(PolicyEngineTest, PlaybackOk_RentalDuration0) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration));
|
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration));
|
||||||
|
|
||||||
InSequence s;
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
||||||
EXPECT_CALL(check_, Call(1));
|
EXPECT_CALL(check_, Call(1));
|
||||||
@@ -316,6 +383,7 @@ TEST_F(PolicyEngineTest, PlaybackOk_RentalDuration0) {
|
|||||||
EXPECT_CALL(check_, Call(2));
|
EXPECT_CALL(check_, Call(2));
|
||||||
EXPECT_CALL(mock_event_listener_, OnSessionRenewalNeeded(_));
|
EXPECT_CALL(mock_event_listener_, OnSessionRenewalNeeded(_));
|
||||||
EXPECT_CALL(check_, Call(3));
|
EXPECT_CALL(check_, Call(3));
|
||||||
|
ExpectSessionKeysChange(kKeyStatusExpired, false);
|
||||||
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
||||||
EXPECT_CALL(check_, Call(4));
|
EXPECT_CALL(check_, Call(4));
|
||||||
|
|
||||||
@@ -348,6 +416,7 @@ TEST_F(PolicyEngineTest, PlaybackOk_PlaybackDuration0) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + kHighDuration + 2));
|
.WillOnce(Return(kLicenseStartTime + kHighDuration + 2));
|
||||||
|
|
||||||
InSequence s;
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kHighDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kHighDuration));
|
||||||
EXPECT_CALL(check_, Call(1));
|
EXPECT_CALL(check_, Call(1));
|
||||||
@@ -355,6 +424,7 @@ TEST_F(PolicyEngineTest, PlaybackOk_PlaybackDuration0) {
|
|||||||
EXPECT_CALL(check_, Call(2));
|
EXPECT_CALL(check_, Call(2));
|
||||||
EXPECT_CALL(mock_event_listener_, OnSessionRenewalNeeded(_));
|
EXPECT_CALL(mock_event_listener_, OnSessionRenewalNeeded(_));
|
||||||
EXPECT_CALL(check_, Call(3));
|
EXPECT_CALL(check_, Call(3));
|
||||||
|
ExpectSessionKeysChange(kKeyStatusExpired, false);
|
||||||
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
||||||
EXPECT_CALL(check_, Call(4));
|
EXPECT_CALL(check_, Call(4));
|
||||||
|
|
||||||
@@ -385,9 +455,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_LicenseDuration0) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + min_duration));
|
.WillOnce(Return(kLicenseStartTime + min_duration));
|
||||||
|
|
||||||
InSequence s;
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
||||||
EXPECT_CALL(check_, Call(1));
|
EXPECT_CALL(check_, Call(1));
|
||||||
|
ExpectSessionKeysChange(kKeyStatusExpired, false);
|
||||||
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
||||||
EXPECT_CALL(check_, Call(2));
|
EXPECT_CALL(check_, Call(2));
|
||||||
|
|
||||||
@@ -417,6 +489,7 @@ TEST_F(PolicyEngineTest, PlaybackOk_Durations0) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + kHighDuration - 1))
|
.WillOnce(Return(kLicenseStartTime + kHighDuration - 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + kHighDuration));
|
.WillOnce(Return(kLicenseStartTime + kHighDuration));
|
||||||
|
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(_, kNoExpiration));
|
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(_, kNoExpiration));
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
@@ -437,8 +510,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_LicenseWithFutureStartTime) {
|
|||||||
.WillOnce(Return(kLicenseStartTime))
|
.WillOnce(Return(kLicenseStartTime))
|
||||||
.WillOnce(Return(kLicenseStartTime + 10));
|
.WillOnce(Return(kLicenseStartTime + 10));
|
||||||
|
|
||||||
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusPending, false);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
|
|
||||||
@@ -466,10 +542,12 @@ TEST_F(PolicyEngineTest, PlaybackFailed_CanRenewFalse) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration + 10));
|
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration + 10));
|
||||||
|
|
||||||
InSequence s;
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
||||||
EXPECT_CALL(check_, Call(1));
|
EXPECT_CALL(check_, Call(1));
|
||||||
EXPECT_CALL(check_, Call(2));
|
EXPECT_CALL(check_, Call(2));
|
||||||
|
ExpectSessionKeysChange(kKeyStatusExpired, false);
|
||||||
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
||||||
EXPECT_CALL(check_, Call(3));
|
EXPECT_CALL(check_, Call(3));
|
||||||
|
|
||||||
@@ -502,6 +580,7 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccess) {
|
|||||||
kLicenseRenewalRetryInterval + 10));
|
kLicenseRenewalRetryInterval + 10));
|
||||||
|
|
||||||
InSequence s;
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
||||||
EXPECT_CALL(check_, Call(1));
|
EXPECT_CALL(check_, Call(1));
|
||||||
@@ -550,14 +629,17 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccess_WithFutureStartTime) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 60));
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 60));
|
||||||
|
|
||||||
InSequence s;
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
||||||
EXPECT_CALL(check_, Call(1));
|
EXPECT_CALL(check_, Call(1));
|
||||||
EXPECT_CALL(mock_event_listener_, OnSessionRenewalNeeded(_));
|
EXPECT_CALL(mock_event_listener_, OnSessionRenewalNeeded(_));
|
||||||
EXPECT_CALL(check_, Call(2));
|
EXPECT_CALL(check_, Call(2));
|
||||||
|
ExpectSessionKeysChange(kKeyStatusPending, false);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, new_license_start_time + kLowDuration));
|
OnExpirationUpdate(_, new_license_start_time + kLowDuration));
|
||||||
EXPECT_CALL(check_, Call(3));
|
EXPECT_CALL(check_, Call(3));
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(check_, Call(4));
|
EXPECT_CALL(check_, Call(4));
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
@@ -598,6 +680,7 @@ TEST_F(PolicyEngineTest, PlaybackFailed_RenewFailedVersionNotUpdated) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration + 10));
|
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration + 10));
|
||||||
|
|
||||||
InSequence s;
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
||||||
EXPECT_CALL(check_, Call(1));
|
EXPECT_CALL(check_, Call(1));
|
||||||
@@ -605,6 +688,7 @@ TEST_F(PolicyEngineTest, PlaybackFailed_RenewFailedVersionNotUpdated) {
|
|||||||
EXPECT_CALL(check_, Call(2));
|
EXPECT_CALL(check_, Call(2));
|
||||||
EXPECT_CALL(mock_event_listener_, OnSessionRenewalNeeded(_));
|
EXPECT_CALL(mock_event_listener_, OnSessionRenewalNeeded(_));
|
||||||
EXPECT_CALL(check_, Call(3));
|
EXPECT_CALL(check_, Call(3));
|
||||||
|
ExpectSessionKeysChange(kKeyStatusExpired, false);
|
||||||
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
||||||
EXPECT_CALL(check_, Call(4));
|
EXPECT_CALL(check_, Call(4));
|
||||||
|
|
||||||
@@ -652,6 +736,7 @@ TEST_F(PolicyEngineTest, PlaybackFailed_RepeatedRenewFailures) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration + 15));
|
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration + 15));
|
||||||
|
|
||||||
InSequence s;
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
||||||
EXPECT_CALL(check_, Call(1));
|
EXPECT_CALL(check_, Call(1));
|
||||||
@@ -664,6 +749,7 @@ TEST_F(PolicyEngineTest, PlaybackFailed_RepeatedRenewFailures) {
|
|||||||
EXPECT_CALL(mock_event_listener_, OnSessionRenewalNeeded(_));
|
EXPECT_CALL(mock_event_listener_, OnSessionRenewalNeeded(_));
|
||||||
EXPECT_CALL(check_, Call(6));
|
EXPECT_CALL(check_, Call(6));
|
||||||
EXPECT_CALL(check_, Call(7));
|
EXPECT_CALL(check_, Call(7));
|
||||||
|
ExpectSessionKeysChange(kKeyStatusExpired, false);
|
||||||
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
||||||
EXPECT_CALL(check_, Call(8));
|
EXPECT_CALL(check_, Call(8));
|
||||||
|
|
||||||
@@ -702,6 +788,7 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccessAfterExpiry) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration + 40));
|
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration + 40));
|
||||||
|
|
||||||
InSequence s;
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
||||||
EXPECT_CALL(check_, Call(1));
|
EXPECT_CALL(check_, Call(1));
|
||||||
@@ -714,8 +801,10 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccessAfterExpiry) {
|
|||||||
EXPECT_CALL(mock_event_listener_, OnSessionRenewalNeeded(_));
|
EXPECT_CALL(mock_event_listener_, OnSessionRenewalNeeded(_));
|
||||||
EXPECT_CALL(check_, Call(6));
|
EXPECT_CALL(check_, Call(6));
|
||||||
EXPECT_CALL(check_, Call(7));
|
EXPECT_CALL(check_, Call(7));
|
||||||
|
ExpectSessionKeysChange(kKeyStatusExpired, false);
|
||||||
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
EXPECT_CALL(mock_event_listener_, OnSessionExpiration(_));
|
||||||
EXPECT_CALL(check_, Call(8));
|
EXPECT_CALL(check_, Call(8));
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(
|
EXPECT_CALL(
|
||||||
mock_event_listener_,
|
mock_event_listener_,
|
||||||
OnExpirationUpdate(_, new_license_start_time + new_license_duration));
|
OnExpirationUpdate(_, new_license_start_time + new_license_duration));
|
||||||
@@ -767,6 +856,7 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccessAfterFailures) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 200));
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 200));
|
||||||
|
|
||||||
InSequence s;
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
||||||
EXPECT_CALL(check_, Call(1));
|
EXPECT_CALL(check_, Call(1));
|
||||||
@@ -818,6 +908,7 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewedWithUsage) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + 50));
|
.WillOnce(Return(kLicenseStartTime + 50));
|
||||||
|
|
||||||
InSequence s;
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||||
EXPECT_CALL(mock_event_listener_,
|
EXPECT_CALL(mock_event_listener_,
|
||||||
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
||||||
EXPECT_CALL(check_, Call(1));
|
EXPECT_CALL(check_, Call(1));
|
||||||
@@ -850,6 +941,87 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewedWithUsage) {
|
|||||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId));
|
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(PolicyEngineTest, MultipleKeysInLicense) {
|
||||||
|
const char kSigningKeyId[] = "signing_key";
|
||||||
|
|
||||||
|
license_.clear_key();
|
||||||
|
License::KeyContainer* content_key = license_.add_key();
|
||||||
|
content_key->set_type(License::KeyContainer::CONTENT);
|
||||||
|
content_key->set_id(kKeyId);
|
||||||
|
License::KeyContainer* non_content_key = license_.add_key();
|
||||||
|
non_content_key->set_type(License::KeyContainer::SIGNING);
|
||||||
|
non_content_key->set_id(kSigningKeyId);
|
||||||
|
License::KeyContainer* content_key_without_id = license_.add_key();
|
||||||
|
content_key_without_id->set_type(License::KeyContainer::CONTENT);
|
||||||
|
License::KeyContainer* another_content_key = license_.add_key();
|
||||||
|
another_content_key->set_type(License::KeyContainer::CONTENT);
|
||||||
|
another_content_key->set_id(kAnotherKeyId);
|
||||||
|
|
||||||
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
|
.WillOnce(Return(kLicenseStartTime + 1));
|
||||||
|
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, kKeyStatusUsable, true);
|
||||||
|
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(_, _));
|
||||||
|
|
||||||
|
policy_engine_->SetLicense(license_);
|
||||||
|
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId));
|
||||||
|
EXPECT_TRUE(policy_engine_->CanDecrypt(kAnotherKeyId));
|
||||||
|
EXPECT_FALSE(policy_engine_->CanDecrypt(kSigningKeyId));
|
||||||
|
EXPECT_FALSE(policy_engine_->CanDecrypt(kSomeRandomKeyId));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PolicyEngineTest, KeysOutputNotAllowedByMaxResEngine) {
|
||||||
|
license_.clear_key();
|
||||||
|
License::KeyContainer* content_key = license_.add_key();
|
||||||
|
content_key->set_type(License::KeyContainer::CONTENT);
|
||||||
|
content_key->set_id(kKeyId);
|
||||||
|
License::KeyContainer* another_content_key = license_.add_key();
|
||||||
|
another_content_key->set_type(License::KeyContainer::CONTENT);
|
||||||
|
another_content_key->set_id(kAnotherKeyId);
|
||||||
|
|
||||||
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + 5))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + 8))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + 10));
|
||||||
|
|
||||||
|
InjectMockMaxResEngine();
|
||||||
|
EXPECT_CALL(*mock_max_res_engine_, CanDecrypt(kKeyId))
|
||||||
|
.WillOnce(Return(false))
|
||||||
|
.WillOnce(Return(true))
|
||||||
|
.WillOnce(Return(false))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
EXPECT_CALL(*mock_max_res_engine_, CanDecrypt(kAnotherKeyId))
|
||||||
|
.WillOnce(Return(false))
|
||||||
|
.WillOnce(Return(false))
|
||||||
|
.WillOnce(Return(true))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
|
InSequence s;
|
||||||
|
ExpectSessionKeysChange(kKeyStatusOutputNotAllowed,
|
||||||
|
kKeyStatusOutputNotAllowed, false);
|
||||||
|
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(_, _));
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, kKeyStatusOutputNotAllowed, true);
|
||||||
|
ExpectSessionKeysChange(kKeyStatusOutputNotAllowed, kKeyStatusUsable, true);
|
||||||
|
ExpectSessionKeysChange(kKeyStatusUsable, kKeyStatusUsable, true);
|
||||||
|
|
||||||
|
policy_engine_->SetLicense(license_);
|
||||||
|
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId));
|
||||||
|
EXPECT_FALSE(policy_engine_->CanDecrypt(kAnotherKeyId));
|
||||||
|
|
||||||
|
policy_engine_->OnTimerEvent();
|
||||||
|
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId));
|
||||||
|
EXPECT_FALSE(policy_engine_->CanDecrypt(kAnotherKeyId));
|
||||||
|
|
||||||
|
policy_engine_->OnTimerEvent();
|
||||||
|
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId));
|
||||||
|
EXPECT_TRUE(policy_engine_->CanDecrypt(kAnotherKeyId));
|
||||||
|
|
||||||
|
policy_engine_->OnTimerEvent();
|
||||||
|
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId));
|
||||||
|
EXPECT_TRUE(policy_engine_->CanDecrypt(kAnotherKeyId));
|
||||||
|
}
|
||||||
|
|
||||||
class PolicyEngineQueryTest : public PolicyEngineTest {
|
class PolicyEngineQueryTest : public PolicyEngineTest {
|
||||||
protected:
|
protected:
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
|
|||||||
@@ -23,6 +23,12 @@
|
|||||||
#include "wv_cdm_event_listener.h"
|
#include "wv_cdm_event_listener.h"
|
||||||
#include "wv_content_decryption_module.h"
|
#include "wv_content_decryption_module.h"
|
||||||
|
|
||||||
|
using ::testing::_;
|
||||||
|
using ::testing::AtLeast;
|
||||||
|
using ::testing::Each;
|
||||||
|
using ::testing::Field;
|
||||||
|
using ::testing::StrictMock;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const char kPathDelimiter = '/';
|
const char kPathDelimiter = '/';
|
||||||
|
|
||||||
@@ -444,6 +450,10 @@ class TestWvCdmEventListener : public WvCdmEventListener {
|
|||||||
|
|
||||||
MOCK_METHOD1(OnSessionRenewalNeeded, void(const CdmSessionId& session_id));
|
MOCK_METHOD1(OnSessionRenewalNeeded, void(const CdmSessionId& session_id));
|
||||||
MOCK_METHOD1(OnSessionExpiration, void(const CdmSessionId& session_id));
|
MOCK_METHOD1(OnSessionExpiration, void(const CdmSessionId& session_id));
|
||||||
|
MOCK_METHOD3(OnSessionKeysChange,
|
||||||
|
void(const CdmSessionId& session_id,
|
||||||
|
const std::vector<CdmKeyInformation>& cdm_keys_info,
|
||||||
|
bool has_new_usable_key));
|
||||||
MOCK_METHOD2(OnExpirationUpdate,
|
MOCK_METHOD2(OnExpirationUpdate,
|
||||||
void(const CdmSessionId& session_id, int64_t new_expiry_time));
|
void(const CdmSessionId& session_id, int64_t new_expiry_time));
|
||||||
};
|
};
|
||||||
@@ -1156,10 +1166,15 @@ TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) {
|
|||||||
|
|
||||||
session_id_.clear();
|
session_id_.clear();
|
||||||
key_set_id_.clear();
|
key_set_id_.clear();
|
||||||
::testing::StrictMock<TestWvCdmEventListener> listener;
|
StrictMock<TestWvCdmEventListener> listener;
|
||||||
decryptor_.OpenSession(g_key_system, NULL, &listener, &session_id_);
|
decryptor_.OpenSession(g_key_system, NULL, &listener, &session_id_);
|
||||||
CdmSessionId restore_session_id = session_id_;
|
CdmSessionId restore_session_id = session_id_;
|
||||||
EXPECT_CALL(listener, OnExpirationUpdate(restore_session_id, ::testing::_));
|
EXPECT_CALL(listener,
|
||||||
|
OnSessionKeysChange(restore_session_id,
|
||||||
|
Each(Field(&CdmKeyInformation::key_status,
|
||||||
|
kKeyStatusUsable)),
|
||||||
|
true));
|
||||||
|
EXPECT_CALL(listener, OnExpirationUpdate(restore_session_id, _));
|
||||||
EXPECT_EQ(wvcdm::KEY_ADDED,
|
EXPECT_EQ(wvcdm::KEY_ADDED,
|
||||||
decryptor_.RestoreKey(restore_session_id, key_set_id));
|
decryptor_.RestoreKey(restore_session_id, key_set_id));
|
||||||
|
|
||||||
@@ -1167,7 +1182,12 @@ TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) {
|
|||||||
key_set_id_.clear();
|
key_set_id_.clear();
|
||||||
// Maybe called since VerifyKeyRequestResponse could take some time.
|
// Maybe called since VerifyKeyRequestResponse could take some time.
|
||||||
EXPECT_CALL(listener, OnSessionRenewalNeeded(restore_session_id))
|
EXPECT_CALL(listener, OnSessionRenewalNeeded(restore_session_id))
|
||||||
.Times(::testing::AtLeast(0));
|
.Times(AtLeast(0));
|
||||||
|
EXPECT_CALL(listener,
|
||||||
|
OnSessionKeysChange(restore_session_id,
|
||||||
|
Each(Field(&CdmKeyInformation::key_status,
|
||||||
|
kKeyStatusExpired)),
|
||||||
|
false));
|
||||||
EXPECT_CALL(listener, OnSessionExpiration(restore_session_id));
|
EXPECT_CALL(listener, OnSessionExpiration(restore_session_id));
|
||||||
GenerateKeyRelease(key_set_id);
|
GenerateKeyRelease(key_set_id);
|
||||||
key_set_id_ = key_set_id;
|
key_set_id_ = key_set_id;
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ using android::status_t;
|
|||||||
using android::String8;
|
using android::String8;
|
||||||
using android::Vector;
|
using android::Vector;
|
||||||
using std::map;
|
using std::map;
|
||||||
|
using wvcdm::CdmKeyInformation;
|
||||||
using wvcdm::CdmSessionId;
|
using wvcdm::CdmSessionId;
|
||||||
using wvcdm::CdmResponseType;
|
using wvcdm::CdmResponseType;
|
||||||
using wvcdm::WvContentDecryptionModule;
|
using wvcdm::WvContentDecryptionModule;
|
||||||
@@ -143,6 +144,11 @@ class WVDrmPlugin : public android::DrmPlugin,
|
|||||||
|
|
||||||
virtual void OnSessionExpiration(const CdmSessionId& cdmSessionId);
|
virtual void OnSessionExpiration(const CdmSessionId& cdmSessionId);
|
||||||
|
|
||||||
|
virtual void OnSessionKeysChange(
|
||||||
|
const CdmSessionId& session_id,
|
||||||
|
const std::vector<CdmKeyInformation>& cdm_keys_info,
|
||||||
|
bool has_new_usable_key);
|
||||||
|
|
||||||
virtual void OnExpirationUpdate(const CdmSessionId& cdmSessionId,
|
virtual void OnExpirationUpdate(const CdmSessionId& cdmSessionId,
|
||||||
int64_t new_expiry_time);
|
int64_t new_expiry_time);
|
||||||
|
|
||||||
|
|||||||
@@ -965,6 +965,13 @@ void WVDrmPlugin::OnSessionExpiration(const CdmSessionId& cdmSessionId) {
|
|||||||
sendEvent(kDrmPluginEventKeyExpired, 0, &sessionId, NULL);
|
sendEvent(kDrmPluginEventKeyExpired, 0, &sessionId, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WVDrmPlugin::OnSessionKeysChange(
|
||||||
|
const CdmSessionId& session_id,
|
||||||
|
const std::vector<CdmKeyInformation>& cdm_keys_info,
|
||||||
|
bool has_new_usable_key) {
|
||||||
|
// TODO(kqyang): Glue with DrmPlugin API when it is ready.
|
||||||
|
}
|
||||||
|
|
||||||
void WVDrmPlugin::OnExpirationUpdate(const CdmSessionId& cdmSessionId,
|
void WVDrmPlugin::OnExpirationUpdate(const CdmSessionId& cdmSessionId,
|
||||||
int64_t new_expiry_time) {
|
int64_t new_expiry_time) {
|
||||||
// TODO(kqyang): Glue with DrmPlugin API when it is ready. Note that
|
// TODO(kqyang): Glue with DrmPlugin API when it is ready. Note that
|
||||||
|
|||||||
Reference in New Issue
Block a user