Merge "Unified State-Changing API for LicenseKeyStatus" into oc-mr1-dev am: cd6178cf82
am: 753f6c6d27
Change-Id: Ic324a0bf46bc0d862de9c95072c5e4d53f157e51
This commit is contained in:
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
static const uint32_t kNoResolution = 0;
|
||||
|
||||
class LicenseKeyStatus;
|
||||
|
||||
// Holds all content and operator session keys for a session.
|
||||
@@ -31,11 +33,17 @@ class LicenseKeys {
|
||||
virtual bool GetAllowedUsage(const KeyId& key_id,
|
||||
CdmKeyAllowedUsage* allowed_usage);
|
||||
|
||||
// Applies a new status to each content key.
|
||||
// Returns true if any statuses changed, and sets new_usable_keys to
|
||||
// true if the status changes resulted in keys becoming usable.
|
||||
virtual bool ApplyStatusChange(CdmKeyStatus new_status,
|
||||
bool* new_usable_keys);
|
||||
// Applies a new status, resolution, and/or HDCP level to each content key,
|
||||
// updating their usability under their constraints. Returns true if any keys
|
||||
// have changed usability, and sets new_usable_keys to true if the status
|
||||
// changes resulted in at least one key becoming usable.
|
||||
//
|
||||
// Pass in NULL for any of the const-pointer arguments to leave that state
|
||||
// unchanged.
|
||||
virtual bool ApplyStatusChange(
|
||||
const CdmKeyStatus* new_status, const uint32_t* new_resolution,
|
||||
const CryptoSession::HdcpCapability* new_hdcp_level,
|
||||
bool* new_usable_keys);
|
||||
|
||||
// Populates the CdmKeyStatusMap with the current content keys.
|
||||
virtual void ExtractKeyStatuses(CdmKeyStatusMap* content_keys);
|
||||
@@ -45,11 +53,6 @@ class LicenseKeys {
|
||||
// to the key, returns true.
|
||||
virtual bool MeetsConstraints(const KeyId& key_id);
|
||||
|
||||
// Applies a resolution and/or hdcp change to each key, updating their
|
||||
// useability under their constraints.
|
||||
virtual void ApplyConstraints(uint32_t new_resolution,
|
||||
CryptoSession::HdcpCapability new_hdcp_level);
|
||||
|
||||
// Extracts the keys from a license and makes them available for
|
||||
// querying usage and constraint settings.
|
||||
virtual void SetFromLicense(
|
||||
@@ -85,21 +88,24 @@ class LicenseKeyStatus {
|
||||
// Returns the current status of the key.
|
||||
virtual CdmKeyStatus GetKeyStatus() const { return key_status_; }
|
||||
|
||||
// Applies a new status to this key.
|
||||
// Returns true if the status changed, and sets new_usable_keys to
|
||||
// true if the status changes resulted in the key becoming usable.
|
||||
virtual bool ApplyStatusChange(CdmKeyStatus new_status,
|
||||
bool* new_usable_keys);
|
||||
// Applies a new status, resolution, and/or HDCP level, updating the key's
|
||||
// usability under its constraints. Returns true if this results in a change
|
||||
// to the key's usability, and sets newly_usable to true if the status
|
||||
// changes resulted in the key becoming usable.
|
||||
//
|
||||
// Pass in NULL for any of the const-pointer arguments to leave that state
|
||||
// unchanged.
|
||||
virtual bool ApplyStatusChange(
|
||||
const CdmKeyStatus* maybe_new_status,
|
||||
const uint32_t* maybe_new_resolution,
|
||||
const CryptoSession::HdcpCapability* maybe_new_hdcp_level,
|
||||
bool* newly_usable);
|
||||
|
||||
// Returns the current constraint status of this key. The result
|
||||
// may change due to calls to ApplyConstraints().
|
||||
// Note: this will return true until the first call to ApplyConstraints().
|
||||
virtual bool MeetsConstraints() const { return meets_constraints_; }
|
||||
|
||||
// Applies the given changes in resolution or HDCP settings.
|
||||
virtual void ApplyConstraints(
|
||||
uint32_t new_resolution, CryptoSession::HdcpCapability new_hdcp_level);
|
||||
|
||||
protected:
|
||||
typedef ::video_widevine::License::KeyContainer KeyContainer;
|
||||
typedef KeyContainer::OperatorSessionKeyPermissions
|
||||
@@ -121,11 +127,14 @@ class LicenseKeyStatus {
|
||||
bool HasConstraints() {
|
||||
return is_content_key_ && constraints_.size() != 0;
|
||||
}
|
||||
|
||||
void SetConstraints(const ConstraintList& constraints);
|
||||
void ApplyConstraints();
|
||||
|
||||
bool is_content_key_;
|
||||
CdmKeyStatus key_status_;
|
||||
uint32_t resolution_;
|
||||
CryptoSession::HdcpCapability hdcp_level_;
|
||||
bool can_check_constraints_;
|
||||
bool meets_constraints_;
|
||||
CdmKeyAllowedUsage allowed_usage_;
|
||||
CryptoSession::HdcpCapability default_hdcp_level_;
|
||||
|
||||
@@ -108,6 +108,10 @@ class PolicyEngine {
|
||||
friend class PolicyEngineConstraintsTest;
|
||||
|
||||
void InitDevice(CryptoSession* crypto_session);
|
||||
// Checks the keys against the current state of the hardware in case the HDCP
|
||||
// level no longer meets their requirements. Will only check once every
|
||||
// |kHdcpCheckInterval| seconds. Calls NotifyIfKeysChanged() to propagate any
|
||||
// resultant changes to the OnKeysChange event.
|
||||
void CheckDevice(int64_t current_time);
|
||||
|
||||
void SetDeviceResolution(uint32_t width, uint32_t height) {
|
||||
@@ -143,9 +147,14 @@ class PolicyEngine {
|
||||
|
||||
void UpdateRenewalRequest(int64_t current_time);
|
||||
|
||||
// Notifies updates in keys information and fire OnKeysChange event if
|
||||
// key changes.
|
||||
void NotifyKeysChange(CdmKeyStatus new_status);
|
||||
|
||||
// Updates the keys' status to |new_status|. Calls NotifyIfKeysChanged() to
|
||||
// propagate any resultant changes to the OnKeysChange event.
|
||||
void UpdateKeyStatus(CdmKeyStatus new_status);
|
||||
|
||||
// Helper method that correctly fires the OnKeysChange event - if needed -
|
||||
// depending on the parameters it is given.
|
||||
void NotifyIfKeysChanged(bool keys_changed, bool new_usable_keys);
|
||||
|
||||
// Notifies updates in expiry time and fire OnExpirationUpdate event if
|
||||
// expiry time changes.
|
||||
|
||||
@@ -86,14 +86,17 @@ bool LicenseKeys::GetAllowedUsage(const KeyId& key_id,
|
||||
}
|
||||
}
|
||||
|
||||
bool LicenseKeys::ApplyStatusChange(CdmKeyStatus new_status,
|
||||
bool* new_usable_keys) {
|
||||
bool LicenseKeys::ApplyStatusChange(
|
||||
const CdmKeyStatus* new_status, const uint32_t* new_resolution,
|
||||
const CryptoSession::HdcpCapability* new_hdcp_level,
|
||||
bool* new_usable_keys) {
|
||||
bool keys_changed = false;
|
||||
bool newly_usable = false;
|
||||
*new_usable_keys = false;
|
||||
for (LicenseKeyStatusIterator it = keys_.begin(); it != keys_.end(); ++it) {
|
||||
bool usable;
|
||||
if (it->second->ApplyStatusChange(new_status, &usable)) {
|
||||
if (it->second->ApplyStatusChange(new_status, new_resolution,
|
||||
new_hdcp_level, &usable)) {
|
||||
newly_usable |= usable;
|
||||
keys_changed = true;
|
||||
}
|
||||
@@ -122,13 +125,6 @@ bool LicenseKeys::MeetsConstraints(const KeyId& key_id) {
|
||||
}
|
||||
}
|
||||
|
||||
void LicenseKeys::ApplyConstraints(
|
||||
uint32_t new_resolution, CryptoSession::HdcpCapability new_hdcp_level) {
|
||||
for (LicenseKeyStatusIterator i = keys_.begin(); i != keys_.end(); ++i) {
|
||||
i->second->ApplyConstraints(new_resolution, new_hdcp_level);
|
||||
}
|
||||
}
|
||||
|
||||
void LicenseKeys::SetFromLicense(
|
||||
const video_widevine::License& license) {
|
||||
this->Clear();
|
||||
@@ -145,6 +141,9 @@ void LicenseKeys::SetFromLicense(
|
||||
LicenseKeyStatus::LicenseKeyStatus(const KeyContainer& key) :
|
||||
is_content_key_(false),
|
||||
key_status_(kKeyStatusInternalError),
|
||||
resolution_(kNoResolution),
|
||||
hdcp_level_(HDCP_NONE),
|
||||
can_check_constraints_(false),
|
||||
meets_constraints_(true),
|
||||
default_hdcp_level_(HDCP_NONE) {
|
||||
|
||||
@@ -221,26 +220,55 @@ bool LicenseKeyStatus::GetAllowedUsage(CdmKeyAllowedUsage* allowed_usage) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LicenseKeyStatus::ApplyStatusChange(CdmKeyStatus new_status,
|
||||
bool* new_usable_key) {
|
||||
*new_usable_key = false;
|
||||
bool LicenseKeyStatus::ApplyStatusChange(
|
||||
const CdmKeyStatus* maybe_new_status, const uint32_t* maybe_new_resolution,
|
||||
const CryptoSession::HdcpCapability* maybe_new_hdcp_level,
|
||||
bool* newly_usable) {
|
||||
*newly_usable = false;
|
||||
if (!is_content_key_) {
|
||||
return false;
|
||||
}
|
||||
CdmKeyStatus updated_status = new_status;
|
||||
if (updated_status == kKeyStatusUsable) {
|
||||
|
||||
// Most of this function is various work to calculate an updated value for
|
||||
// the status. We start at the same value as the current status.
|
||||
CdmKeyStatus updated_status = key_status_;
|
||||
|
||||
// Account for the new status, if provided.
|
||||
if (maybe_new_status != NULL) {
|
||||
const CdmKeyStatus& new_status = *maybe_new_status;
|
||||
can_check_constraints_ = (new_status == kKeyStatusUsable);
|
||||
updated_status = new_status;
|
||||
}
|
||||
|
||||
// Account for the new resolution, if provided.
|
||||
if (maybe_new_resolution != NULL) {
|
||||
resolution_ = *maybe_new_resolution;
|
||||
}
|
||||
|
||||
// Account for the new HDCP level, if provided.
|
||||
if (maybe_new_hdcp_level != NULL) {
|
||||
hdcp_level_ = *maybe_new_hdcp_level;
|
||||
}
|
||||
|
||||
// If we can, check the current state against the constraints and update the
|
||||
// status if needed.
|
||||
if (can_check_constraints_) {
|
||||
ApplyConstraints();
|
||||
if (!MeetsConstraints()) {
|
||||
updated_status = kKeyStatusOutputNotAllowed;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if any of that work changed the key status.
|
||||
if (key_status_ != updated_status) {
|
||||
key_status_ = updated_status;
|
||||
if (updated_status == kKeyStatusUsable) {
|
||||
*new_usable_key = true;
|
||||
*newly_usable = true;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the key has constraints, find the constraint that applies.
|
||||
@@ -250,12 +278,16 @@ bool LicenseKeyStatus::ApplyStatusChange(CdmKeyStatus new_status,
|
||||
// If the key has no constraints, or if the constraint has no HDCP
|
||||
// requirement, use the key's default HDCP setting to check against the
|
||||
// device's current HDCP level.
|
||||
void LicenseKeyStatus::ApplyConstraints(
|
||||
uint32_t new_resolution, CryptoSession::HdcpCapability new_hdcp_level) {
|
||||
void LicenseKeyStatus::ApplyConstraints() {
|
||||
if (resolution_ == kNoResolution) {
|
||||
// Until a resolution has been detected, the constraints cannot be checked.
|
||||
meets_constraints_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
VideoResolutionConstraint* current_constraint = NULL;
|
||||
if (HasConstraints()) {
|
||||
current_constraint = GetConstraintForRes(new_resolution, constraints_);
|
||||
current_constraint = GetConstraintForRes(resolution_, constraints_);
|
||||
if (NULL == current_constraint) {
|
||||
meets_constraints_ = false;
|
||||
return;
|
||||
@@ -270,7 +302,7 @@ void LicenseKeyStatus::ApplyConstraints(
|
||||
desired_hdcp_level = default_hdcp_level_;
|
||||
}
|
||||
|
||||
meets_constraints_ = (new_hdcp_level >= desired_hdcp_level);
|
||||
meets_constraints_ = (hdcp_level_ >= desired_hdcp_level);
|
||||
}
|
||||
|
||||
void LicenseKeyStatus::SetConstraints(const ConstraintList& constraints) {
|
||||
|
||||
@@ -17,7 +17,6 @@ using video_widevine::License;
|
||||
namespace {
|
||||
|
||||
const int64_t kHdcpCheckInterval = 10;
|
||||
const uint32_t kNoResolution = 0;
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -71,7 +70,15 @@ void PolicyEngine::CheckDevice(int64_t current_time) {
|
||||
if (!crypto_session_->GetHdcpCapabilities(¤t_hdcp_level, &ignored)) {
|
||||
current_hdcp_level = HDCP_NONE;
|
||||
}
|
||||
license_keys_->ApplyConstraints(current_resolution_, current_hdcp_level);
|
||||
|
||||
bool new_usable_keys = false;
|
||||
bool keys_changed =
|
||||
license_keys_->ApplyStatusChange(NULL, // new_status
|
||||
¤t_resolution_,
|
||||
¤t_hdcp_level,
|
||||
&new_usable_keys);
|
||||
NotifyIfKeysChanged(keys_changed, new_usable_keys);
|
||||
|
||||
next_device_check_ = current_time + kHdcpCheckInterval;
|
||||
}
|
||||
}
|
||||
@@ -89,21 +96,19 @@ void PolicyEngine::OnTimerEvent() {
|
||||
if (HasLicenseOrPlaybackDurationExpired(current_time) &&
|
||||
license_state_ != kLicenseStateExpired) {
|
||||
license_state_ = kLicenseStateExpired;
|
||||
NotifyKeysChange(kKeyStatusExpired);
|
||||
UpdateKeyStatus(kKeyStatusExpired);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check device conditions that affect playability (HDCP, resolution)
|
||||
CheckDevice(current_time);
|
||||
|
||||
// Test to determine if renewal should be attempted.
|
||||
bool renewal_needed = false;
|
||||
|
||||
// Test to determine if renewal should be attempted.
|
||||
switch (license_state_) {
|
||||
case kLicenseStateCanPlay: {
|
||||
if (HasRenewalDelayExpired(current_time)) renewal_needed = true;
|
||||
// HDCP may change, so force a check.
|
||||
NotifyKeysChange(kKeyStatusUsable);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -120,7 +125,7 @@ void PolicyEngine::OnTimerEvent() {
|
||||
case kLicenseStatePending: {
|
||||
if (current_time >= license_start_time_) {
|
||||
license_state_ = kLicenseStateCanPlay;
|
||||
NotifyKeysChange(kKeyStatusUsable);
|
||||
UpdateKeyStatus(kKeyStatusUsable);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -132,7 +137,7 @@ void PolicyEngine::OnTimerEvent() {
|
||||
|
||||
default: {
|
||||
license_state_ = kLicenseStateExpired;
|
||||
NotifyKeysChange(kKeyStatusInternalError);
|
||||
UpdateKeyStatus(kKeyStatusInternalError);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -157,7 +162,7 @@ void PolicyEngine::SetLicenseForRelease(const License& license) {
|
||||
policy_.Clear();
|
||||
|
||||
// Expire any old keys.
|
||||
NotifyKeysChange(kKeyStatusExpired);
|
||||
UpdateKeyStatus(kKeyStatusExpired);
|
||||
UpdateLicense(license);
|
||||
}
|
||||
|
||||
@@ -190,17 +195,17 @@ void PolicyEngine::UpdateLicense(const License& license) {
|
||||
if (!policy_.can_play() ||
|
||||
HasLicenseOrPlaybackDurationExpired(current_time)) {
|
||||
license_state_ = kLicenseStateExpired;
|
||||
NotifyKeysChange(kKeyStatusExpired);
|
||||
UpdateKeyStatus(kKeyStatusExpired);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update state
|
||||
if (current_time >= license_start_time_) {
|
||||
license_state_ = kLicenseStateCanPlay;
|
||||
NotifyKeysChange(kKeyStatusUsable);
|
||||
UpdateKeyStatus(kKeyStatusUsable);
|
||||
} else {
|
||||
license_state_ = kLicenseStatePending;
|
||||
NotifyKeysChange(kKeyStatusPending);
|
||||
UpdateKeyStatus(kKeyStatusPending);
|
||||
}
|
||||
NotifyExpirationUpdate(current_time);
|
||||
}
|
||||
@@ -240,7 +245,7 @@ void PolicyEngine::NotifyResolution(uint32_t width, uint32_t height) {
|
||||
|
||||
void PolicyEngine::NotifySessionExpiration() {
|
||||
license_state_ = kLicenseStateExpired;
|
||||
NotifyKeysChange(kKeyStatusExpired);
|
||||
UpdateKeyStatus(kKeyStatusExpired);
|
||||
}
|
||||
|
||||
CdmResponseType PolicyEngine::Query(CdmQueryMap* query_response) {
|
||||
@@ -429,16 +434,23 @@ bool PolicyEngine::HasRenewalRetryIntervalExpired(int64_t current_time) {
|
||||
next_renewal_time_ <= current_time;
|
||||
}
|
||||
|
||||
void PolicyEngine::NotifyKeysChange(CdmKeyStatus new_status) {
|
||||
bool keys_changed;
|
||||
bool has_new_usable_key = false;
|
||||
keys_changed = license_keys_->ApplyStatusChange(new_status,
|
||||
&has_new_usable_key);
|
||||
void PolicyEngine::UpdateKeyStatus(CdmKeyStatus new_status) {
|
||||
bool new_usable_keys = false;
|
||||
bool keys_changed =
|
||||
license_keys_->ApplyStatusChange(&new_status,
|
||||
NULL, // new_resolution
|
||||
NULL, // new_hdcp_level
|
||||
&new_usable_keys);
|
||||
NotifyIfKeysChanged(keys_changed, new_usable_keys);
|
||||
}
|
||||
|
||||
void PolicyEngine::NotifyIfKeysChanged(bool keys_changed,
|
||||
bool new_usable_keys) {
|
||||
if (event_listener_ && keys_changed) {
|
||||
CdmKeyStatusMap content_keys;
|
||||
license_keys_->ExtractKeyStatuses(&content_keys);
|
||||
event_listener_->OnSessionKeysChange(session_id_, content_keys,
|
||||
has_new_usable_key);
|
||||
new_usable_keys);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -392,14 +392,16 @@ TEST_F(LicenseKeysTest, CanDecrypt) {
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(os_key));
|
||||
bool new_usable_keys = false;
|
||||
bool any_change = false;
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
CdmKeyStatus status = kKeyStatusUsable;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, NULL, NULL,
|
||||
&new_usable_keys);
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(c_key));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(os_key));
|
||||
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusExpired,
|
||||
status = kKeyStatusExpired;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, NULL, NULL,
|
||||
&new_usable_keys);
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
@@ -505,6 +507,7 @@ TEST_F(LicenseKeysTest, ExtractKeyStatuses) {
|
||||
TEST_F(LicenseKeysTest, KeyStatusChanges) {
|
||||
bool new_usable_keys = false;
|
||||
bool any_change = false;
|
||||
CdmKeyStatus status;
|
||||
CdmKeyStatusMap key_status_map;
|
||||
StageOperatorSessionKeys();
|
||||
StageContentKeys();
|
||||
@@ -514,7 +517,8 @@ TEST_F(LicenseKeysTest, KeyStatusChanges) {
|
||||
ExpectKeyStatusesEqual(key_status_map, kKeyStatusInternalError);
|
||||
|
||||
// change to pending
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusPending,
|
||||
status = kKeyStatusPending;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, NULL, NULL,
|
||||
&new_usable_keys);
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
@@ -526,7 +530,8 @@ TEST_F(LicenseKeysTest, KeyStatusChanges) {
|
||||
ExpectKeyStatusesEqual(key_status_map, kKeyStatusPending);
|
||||
|
||||
// change to pending (again)
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusPending,
|
||||
status = kKeyStatusPending;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, NULL, NULL,
|
||||
&new_usable_keys);
|
||||
EXPECT_FALSE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
@@ -538,7 +543,8 @@ TEST_F(LicenseKeysTest, KeyStatusChanges) {
|
||||
ExpectKeyStatusesEqual(key_status_map, kKeyStatusPending);
|
||||
|
||||
// change to usable
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
status = kKeyStatusUsable;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, NULL, NULL,
|
||||
&new_usable_keys);
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
@@ -550,7 +556,8 @@ TEST_F(LicenseKeysTest, KeyStatusChanges) {
|
||||
ExpectKeyStatusesEqual(key_status_map, kKeyStatusUsable);
|
||||
|
||||
// change to usable (again)
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
status = kKeyStatusUsable;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, NULL, NULL,
|
||||
&new_usable_keys);
|
||||
EXPECT_FALSE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
@@ -562,7 +569,8 @@ TEST_F(LicenseKeysTest, KeyStatusChanges) {
|
||||
ExpectKeyStatusesEqual(key_status_map, kKeyStatusUsable);
|
||||
|
||||
// change to expired
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusExpired,
|
||||
status = kKeyStatusExpired;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, NULL, NULL,
|
||||
&new_usable_keys);
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
@@ -577,10 +585,14 @@ TEST_F(LicenseKeysTest, KeyStatusChanges) {
|
||||
TEST_F(LicenseKeysTest, HdcpChanges) {
|
||||
bool new_usable_keys = false;
|
||||
bool any_change = false;
|
||||
CdmKeyStatus status;
|
||||
uint32_t resolution;
|
||||
CryptoSession::HdcpCapability hdcp_level;
|
||||
CdmKeyStatusMap key_status_map;
|
||||
StageHdcpKeys();
|
||||
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
status = kKeyStatusUsable;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, NULL, NULL,
|
||||
&new_usable_keys);
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
@@ -598,9 +610,11 @@ TEST_F(LicenseKeysTest, HdcpChanges) {
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_sw_crypto_HDCP_NO_OUTPUT));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_hw_secure_HDCP_NO_OUTPUT));
|
||||
|
||||
license_keys_.ApplyConstraints(100, HDCP_NONE);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
status = kKeyStatusUsable;
|
||||
resolution = 100;
|
||||
hdcp_level = HDCP_NONE;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, &resolution,
|
||||
&hdcp_level, &new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
@@ -623,9 +637,11 @@ TEST_F(LicenseKeysTest, HdcpChanges) {
|
||||
ExpectKeyStatusEqual(key_status_map, ck_hw_secure_HDCP_V2_1,
|
||||
kKeyStatusOutputNotAllowed);
|
||||
|
||||
license_keys_.ApplyConstraints(100, HDCP_V1);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
status = kKeyStatusUsable;
|
||||
resolution = 100;
|
||||
hdcp_level = HDCP_V1;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, &resolution,
|
||||
&hdcp_level, &new_usable_keys);
|
||||
|
||||
EXPECT_FALSE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
@@ -648,9 +664,11 @@ TEST_F(LicenseKeysTest, HdcpChanges) {
|
||||
ExpectKeyStatusEqual(key_status_map, ck_sw_crypto_HDCP_V2_1,
|
||||
kKeyStatusOutputNotAllowed);
|
||||
|
||||
license_keys_.ApplyConstraints(100, HDCP_V2_2);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
status = kKeyStatusUsable;
|
||||
resolution = 100;
|
||||
hdcp_level = HDCP_V2_2;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, &resolution,
|
||||
&hdcp_level, &new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
@@ -674,9 +692,11 @@ TEST_F(LicenseKeysTest, HdcpChanges) {
|
||||
ExpectKeyStatusEqual(key_status_map, ck_sw_crypto_HDCP_NO_OUTPUT,
|
||||
kKeyStatusOutputNotAllowed);
|
||||
|
||||
license_keys_.ApplyConstraints(100, HDCP_NO_DIGITAL_OUTPUT);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
status = kKeyStatusUsable;
|
||||
resolution = 100;
|
||||
hdcp_level = HDCP_NO_DIGITAL_OUTPUT;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, &resolution,
|
||||
&hdcp_level, &new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
@@ -700,9 +720,11 @@ TEST_F(LicenseKeysTest, HdcpChanges) {
|
||||
ExpectKeyStatusEqual(key_status_map, ck_hw_secure_HDCP_NO_OUTPUT,
|
||||
kKeyStatusUsable);
|
||||
|
||||
license_keys_.ApplyConstraints(100, HDCP_NONE);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
status = kKeyStatusUsable;
|
||||
resolution = 100;
|
||||
hdcp_level = HDCP_NONE;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, &resolution,
|
||||
&hdcp_level, &new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
@@ -730,11 +752,15 @@ TEST_F(LicenseKeysTest, HdcpChanges) {
|
||||
TEST_F(LicenseKeysTest, ConstraintChanges) {
|
||||
bool new_usable_keys = false;
|
||||
bool any_change = false;
|
||||
CdmKeyStatus status;
|
||||
uint32_t resolution;
|
||||
CryptoSession::HdcpCapability hdcp_level;
|
||||
CdmKeyStatusMap key_status_map;
|
||||
StageConstraintKeys();
|
||||
|
||||
// No constraints set by device
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
status = kKeyStatusUsable;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, NULL, NULL,
|
||||
&new_usable_keys);
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
@@ -749,9 +775,11 @@ TEST_F(LicenseKeysTest, ConstraintChanges) {
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_NO_HDCP_dual_res));
|
||||
|
||||
// Low-res device, no HDCP support
|
||||
license_keys_.ApplyConstraints(dev_lo_res, HDCP_NONE);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
status = kKeyStatusUsable;
|
||||
resolution = dev_lo_res;
|
||||
hdcp_level = HDCP_NONE;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, &resolution,
|
||||
&hdcp_level, &new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
@@ -771,9 +799,11 @@ TEST_F(LicenseKeysTest, ConstraintChanges) {
|
||||
kKeyStatusOutputNotAllowed);
|
||||
|
||||
// Hi-res device, HDCP_V1 support
|
||||
license_keys_.ApplyConstraints(dev_hi_res, HDCP_V1);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
status = kKeyStatusUsable;
|
||||
resolution = dev_hi_res;
|
||||
hdcp_level = HDCP_V1;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, &resolution,
|
||||
&hdcp_level, &new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
@@ -793,9 +823,11 @@ TEST_F(LicenseKeysTest, ConstraintChanges) {
|
||||
kKeyStatusOutputNotAllowed);
|
||||
|
||||
// Lo-res device, HDCP V2.2 support
|
||||
license_keys_.ApplyConstraints(dev_lo_res, HDCP_V2_2);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
status = kKeyStatusUsable;
|
||||
resolution = dev_lo_res;
|
||||
hdcp_level = HDCP_V2_2;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, &resolution,
|
||||
&hdcp_level, &new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
@@ -816,9 +848,11 @@ TEST_F(LicenseKeysTest, ConstraintChanges) {
|
||||
kKeyStatusOutputNotAllowed);
|
||||
|
||||
// Hi-res device, Maximal HDCP support
|
||||
license_keys_.ApplyConstraints(dev_hi_res, HDCP_NO_DIGITAL_OUTPUT);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
status = kKeyStatusUsable;
|
||||
resolution = dev_hi_res;
|
||||
hdcp_level = HDCP_NO_DIGITAL_OUTPUT;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, &resolution,
|
||||
&hdcp_level, &new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
@@ -839,9 +873,11 @@ TEST_F(LicenseKeysTest, ConstraintChanges) {
|
||||
kKeyStatusUsable);
|
||||
|
||||
// Lo-res device, no HDCP support
|
||||
license_keys_.ApplyConstraints(dev_lo_res, HDCP_NONE);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
status = kKeyStatusUsable;
|
||||
resolution = dev_lo_res;
|
||||
hdcp_level = HDCP_NONE;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, &resolution,
|
||||
&hdcp_level, &new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
@@ -862,9 +898,11 @@ TEST_F(LicenseKeysTest, ConstraintChanges) {
|
||||
kKeyStatusOutputNotAllowed);
|
||||
|
||||
// Too-high-res -- all keys rejected
|
||||
license_keys_.ApplyConstraints(dev_top_res, HDCP_NONE);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
status = kKeyStatusUsable;
|
||||
resolution = dev_top_res;
|
||||
hdcp_level = HDCP_NONE;
|
||||
any_change = license_keys_.ApplyStatusChange(&status, &resolution,
|
||||
&hdcp_level, &new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
#include <iostream>
|
||||
#include <tuple>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include "crypto_session.h"
|
||||
@@ -13,6 +16,8 @@
|
||||
// protobuf generated classes.
|
||||
using video_widevine::License;
|
||||
using video_widevine::License_Policy;
|
||||
using video_widevine::LicenseType;
|
||||
using video_widevine::OFFLINE;
|
||||
using video_widevine::STREAMING;
|
||||
|
||||
namespace wvcdm {
|
||||
@@ -75,14 +80,47 @@ class MockCdmEventListener : public WvCdmEventListener {
|
||||
int64_t new_expiry_time_seconds));
|
||||
};
|
||||
|
||||
struct LicenseTypeParam {
|
||||
std::string name;
|
||||
LicenseType license_type;
|
||||
bool can_persist;
|
||||
};
|
||||
|
||||
const LicenseTypeParam kStreamingParam{"Streaming", STREAMING, false};
|
||||
const LicenseTypeParam kOfflineParam{"Offline", OFFLINE, true};
|
||||
|
||||
void PrintTo(const LicenseTypeParam& param, std::ostream* os) {
|
||||
*os << param.name;
|
||||
}
|
||||
|
||||
struct LicenseRenewalParam {
|
||||
std::string name;
|
||||
bool can_renew;
|
||||
int64_t renewal_delay_seconds;
|
||||
};
|
||||
|
||||
const LicenseRenewalParam kNoRenewalParam{"Cannot Renew", false, 0};
|
||||
const LicenseRenewalParam kShortRenewalParam{"Short Renewal Delay", true, 1};
|
||||
const LicenseRenewalParam kLongRenewalParam{"Long Renewal Delay", true, 60};
|
||||
|
||||
void PrintTo(const LicenseRenewalParam& param, std::ostream* os) {
|
||||
*os << param.name;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class PolicyEngineConstraintsTest : public Test {
|
||||
class PolicyEngineConstraintsTest
|
||||
: public TestWithParam<std::tuple<LicenseTypeParam, LicenseRenewalParam>> {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
mock_clock_ = new NiceMock<MockClock>();
|
||||
current_time_ = 0;
|
||||
|
||||
// mock_event_listener_ is a StrictMock, but we don't care about renewal
|
||||
// calls for these tests and want to ignore them.
|
||||
EXPECT_CALL(mock_event_listener_, OnSessionRenewalNeeded(_))
|
||||
.Times(AtLeast(0));
|
||||
|
||||
policy_engine_.reset(new PolicyEngine(kSessionId, &mock_event_listener_,
|
||||
&crypto_session_));
|
||||
InjectMockClock();
|
||||
@@ -108,19 +146,25 @@ class PolicyEngineConstraintsTest : public Test {
|
||||
}
|
||||
|
||||
void SetupLicense() {
|
||||
LicenseTypeParam typeParam;
|
||||
LicenseRenewalParam renewalParam;
|
||||
std::tie(typeParam, renewalParam) = GetParam();
|
||||
|
||||
license_.set_license_start_time(current_time_);
|
||||
|
||||
LicenseIdentification* id = license_.mutable_id();
|
||||
id->set_version(1);
|
||||
id->set_type(STREAMING);
|
||||
id->set_type(typeParam.license_type);
|
||||
|
||||
License_Policy* policy = license_.mutable_policy();
|
||||
policy = license_.mutable_policy();
|
||||
policy->set_can_play(true);
|
||||
policy->set_can_persist(false);
|
||||
policy->set_can_persist(typeParam.can_persist);
|
||||
policy->set_can_renew(renewalParam.can_renew);
|
||||
policy->set_rental_duration_seconds(kRentalDuration);
|
||||
policy->set_playback_duration_seconds(kPlaybackDuration);
|
||||
policy->set_license_duration_seconds(kStreamingLicenseDuration);
|
||||
policy->set_renewal_delay_seconds(renewalParam.renewal_delay_seconds);
|
||||
|
||||
KeyList* keys = license_.mutable_key();
|
||||
|
||||
@@ -211,7 +255,7 @@ class PolicyEngineConstraintsTest : public Test {
|
||||
License license_;
|
||||
};
|
||||
|
||||
TEST_F(PolicyEngineConstraintsTest, IsPermissiveWithoutAResolution) {
|
||||
TEST_P(PolicyEngineConstraintsTest, IsPermissiveWithoutAResolution) {
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime()).Times(2);
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(kSessionId, _));
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
@@ -227,7 +271,7 @@ TEST_F(PolicyEngineConstraintsTest, IsPermissiveWithoutAResolution) {
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId6));
|
||||
}
|
||||
|
||||
TEST_F(PolicyEngineConstraintsTest, HandlesResolutionsBasedOnConstraints) {
|
||||
TEST_P(PolicyEngineConstraintsTest, HandlesResolutionsBasedOnConstraints) {
|
||||
{
|
||||
Sequence time;
|
||||
for (int i=0; i<4; ++i) {
|
||||
@@ -279,7 +323,7 @@ TEST_F(PolicyEngineConstraintsTest, HandlesResolutionsBasedOnConstraints) {
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId6));
|
||||
}
|
||||
|
||||
TEST_F(PolicyEngineConstraintsTest,
|
||||
TEST_P(PolicyEngineConstraintsTest,
|
||||
RequestsHdcpImmediatelyAndOnlyAfterInterval) {
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||
.WillOnce(Return(0))
|
||||
@@ -310,7 +354,7 @@ TEST_F(PolicyEngineConstraintsTest,
|
||||
policy_engine_->OnTimerEvent();
|
||||
}
|
||||
|
||||
TEST_F(PolicyEngineConstraintsTest, DoesNotRequestHdcpWithoutALicense) {
|
||||
TEST_P(PolicyEngineConstraintsTest, DoesNotRequestHdcpWithoutALicense) {
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||
.WillOnce(Return(0));
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _)).Times(0);
|
||||
@@ -318,7 +362,7 @@ TEST_F(PolicyEngineConstraintsTest, DoesNotRequestHdcpWithoutALicense) {
|
||||
policy_engine_->OnTimerEvent();
|
||||
}
|
||||
|
||||
TEST_F(PolicyEngineConstraintsTest, HandlesConstraintOverridingHdcp) {
|
||||
TEST_P(PolicyEngineConstraintsTest, HandlesConstraintOverridingHdcp) {
|
||||
{
|
||||
Sequence time;
|
||||
for (int i=0; i<3; ++i) {
|
||||
@@ -360,7 +404,7 @@ TEST_F(PolicyEngineConstraintsTest, HandlesConstraintOverridingHdcp) {
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId6));
|
||||
}
|
||||
|
||||
TEST_F(PolicyEngineConstraintsTest, HandlesNoHdcp) {
|
||||
TEST_P(PolicyEngineConstraintsTest, HandlesNoHdcp) {
|
||||
{
|
||||
Sequence time;
|
||||
for (int i=0; i<3; ++i) {
|
||||
@@ -407,7 +451,7 @@ TEST_F(PolicyEngineConstraintsTest, HandlesNoHdcp) {
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId6));
|
||||
}
|
||||
|
||||
TEST_F(PolicyEngineConstraintsTest, IgnoresHdcpWithoutAResolution) {
|
||||
TEST_P(PolicyEngineConstraintsTest, IgnoresHdcpWithoutAResolution) {
|
||||
{
|
||||
Sequence time;
|
||||
for (int i=0; i<2; ++i) {
|
||||
@@ -429,4 +473,9 @@ TEST_F(PolicyEngineConstraintsTest, IgnoresHdcpWithoutAResolution) {
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId6));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Default, PolicyEngineConstraintsTest,
|
||||
Combine(
|
||||
Values(kStreamingParam, kOfflineParam),
|
||||
Values(kNoRenewalParam, kShortRenewalParam, kLongRenewalParam)));
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
Reference in New Issue
Block a user