diff --git a/libwvdrmengine/cdm/core/include/license_key_status.h b/libwvdrmengine/cdm/core/include/license_key_status.h index 59689472..e14e3826 100644 --- a/libwvdrmengine/cdm/core/include/license_key_status.h +++ b/libwvdrmengine/cdm/core/include/license_key_status.h @@ -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_; diff --git a/libwvdrmengine/cdm/core/include/policy_engine.h b/libwvdrmengine/cdm/core/include/policy_engine.h index 83214622..f16c0e18 100644 --- a/libwvdrmengine/cdm/core/include/policy_engine.h +++ b/libwvdrmengine/cdm/core/include/policy_engine.h @@ -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. diff --git a/libwvdrmengine/cdm/core/src/license_key_status.cpp b/libwvdrmengine/cdm/core/src/license_key_status.cpp index 0fe19363..6ee38d11 100644 --- a/libwvdrmengine/cdm/core/src/license_key_status.cpp +++ b/libwvdrmengine/cdm/core/src/license_key_status.cpp @@ -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) { diff --git a/libwvdrmengine/cdm/core/src/policy_engine.cpp b/libwvdrmengine/cdm/core/src/policy_engine.cpp index 6caae554..c933605a 100644 --- a/libwvdrmengine/cdm/core/src/policy_engine.cpp +++ b/libwvdrmengine/cdm/core/src/policy_engine.cpp @@ -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); } } diff --git a/libwvdrmengine/cdm/core/test/license_keys_unittest.cpp b/libwvdrmengine/cdm/core/test/license_keys_unittest.cpp index dc645883..f8557a83 100644 --- a/libwvdrmengine/cdm/core/test/license_keys_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/license_keys_unittest.cpp @@ -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); diff --git a/libwvdrmengine/cdm/core/test/policy_engine_constraints_unittest.cpp b/libwvdrmengine/cdm/core/test/policy_engine_constraints_unittest.cpp index 79657c50..99dd6419 100644 --- a/libwvdrmengine/cdm/core/test/policy_engine_constraints_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/policy_engine_constraints_unittest.cpp @@ -1,5 +1,8 @@ // Copyright 2016 Google Inc. All Rights Reserved. +#include +#include + #include #include #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> { protected: virtual void SetUp() { mock_clock_ = new NiceMock(); 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