Merge "Unified State-Changing API for LicenseKeyStatus" into oc-mr1-dev am: cd6178cf82

am: 753f6c6d27

Change-Id: Ic324a0bf46bc0d862de9c95072c5e4d53f157e51
This commit is contained in:
John W. Bruce
2017-09-01 00:52:24 +00:00
committed by android-build-merger
6 changed files with 264 additions and 115 deletions

View File

@@ -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_;

View File

@@ -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.

View File

@@ -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) {

View File

@@ -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(&current_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
&current_resolution_,
&current_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);
}
}

View File

@@ -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);

View File

@@ -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