From 4ba59828eb92f0f8ff343a0bdbc578ab8b9a2b00 Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Fri, 13 Jan 2017 19:20:30 -0800 Subject: [PATCH] Add License::Policy::soft_enforce_playback_duration [ Merge of http://go/wvgerrit/22564 ] b/34211676 Test: All unittests other than some oemcrypto, request_license_test passed. Those tests failed with or without this CL. Change-Id: I20474339aa1777da2db3677c10f186726505ecc8 --- .../cdm/core/include/policy_engine.h | 3 +- .../cdm/core/src/license_protocol.proto | 4 + libwvdrmengine/cdm/core/src/policy_engine.cpp | 26 ++++-- .../cdm/core/test/policy_engine_unittest.cpp | 83 +++++++++++++++++++ 4 files changed, 110 insertions(+), 6 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/policy_engine.h b/libwvdrmengine/cdm/core/include/policy_engine.h index 47921b54..812b84d1 100644 --- a/libwvdrmengine/cdm/core/include/policy_engine.h +++ b/libwvdrmengine/cdm/core/include/policy_engine.h @@ -119,7 +119,7 @@ class PolicyEngine { int64_t GetRentalExpiryTime(); // Gets the clock time that the license expires based on whether we have // started playing. This takes into account GetHardLicenseExpiryTime. - int64_t GetExpiryTime(); + int64_t GetExpiryTime(bool ignore_soft_enforce_playback_duration); int64_t GetLicenseOrRentalDurationRemaining(int64_t current_time); int64_t GetPlaybackDurationRemaining(int64_t current_time); @@ -161,6 +161,7 @@ class PolicyEngine { int64_t last_playback_time_; int64_t last_expiry_time_; bool last_expiry_time_set_; + bool was_expired_on_load_; // This is used as a reference point for policy management. This value // represents an offset from license_start_time_. This is used to diff --git a/libwvdrmengine/cdm/core/src/license_protocol.proto b/libwvdrmengine/cdm/core/src/license_protocol.proto index f411b6b6..9877430e 100644 --- a/libwvdrmengine/cdm/core/src/license_protocol.proto +++ b/libwvdrmengine/cdm/core/src/license_protocol.proto @@ -82,6 +82,10 @@ message License { // Indicates to client that license renewal and release requests ought to // include ClientIdentification (client_id). optional bool renew_with_client_id = 12 [default = false]; + + // Enables "soft enforcement" of playback_duration_seconds, letting the user + // finish playback even if short window expires. Optional. + optional bool soft_enforce_playback_duration = 14 [default = false]; } message KeyContainer { diff --git a/libwvdrmengine/cdm/core/src/policy_engine.cpp b/libwvdrmengine/cdm/core/src/policy_engine.cpp index ba30cef4..416ead89 100644 --- a/libwvdrmengine/cdm/core/src/policy_engine.cpp +++ b/libwvdrmengine/cdm/core/src/policy_engine.cpp @@ -32,6 +32,7 @@ PolicyEngine::PolicyEngine(CdmSessionId session_id, last_playback_time_(0), last_expiry_time_(0), last_expiry_time_set_(false), + was_expired_on_load_(false), next_renewal_time_(0), session_id_(session_id), event_listener_(event_listener), @@ -290,7 +291,8 @@ bool PolicyEngine::GetSecondsSinceLastPlayed( int64_t PolicyEngine::GetLicenseOrPlaybackDurationRemaining() { int64_t current_time = clock_->GetCurrentTime(); - const int64_t expiry_time = GetExpiryTime(); + const int64_t expiry_time = + GetExpiryTime(/* ignore_soft_enforce_playback_duration */ false); if (expiry_time == NEVER_EXPIRES) return LLONG_MAX; if (expiry_time < current_time) return 0; return expiry_time - current_time; @@ -300,6 +302,13 @@ void PolicyEngine::RestorePlaybackTimes(int64_t playback_start_time, int64_t last_playback_time) { playback_start_time_ = (playback_start_time > 0) ? playback_start_time : 0; last_playback_time_ = (last_playback_time > 0) ? last_playback_time : 0; + + const int64_t current_time = clock_->GetCurrentTime(); + const int64_t expiry_time = + GetExpiryTime(/* ignore_soft_enforce_playback_duration */ true); + was_expired_on_load_ = + expiry_time != NEVER_EXPIRES && expiry_time < current_time; + NotifyExpirationUpdate(); } @@ -309,8 +318,9 @@ void PolicyEngine::UpdateRenewalRequest(int64_t current_time) { } bool PolicyEngine::HasLicenseOrPlaybackDurationExpired(int64_t current_time) { - const int64_t expiry_time = GetExpiryTime(); - return (expiry_time == NEVER_EXPIRES) ? false : (expiry_time <= current_time); + const int64_t expiry_time = + GetExpiryTime(/* ignore_soft_enforce_playback_duration */ false); + return (expiry_time != NEVER_EXPIRES) && expiry_time <= current_time; } // For the policy time fields checked in the following methods, a value of 0 @@ -332,12 +342,17 @@ int64_t PolicyEngine::GetRentalExpiryTime() { return std::min(hard_limit, expiry_time); } -int64_t PolicyEngine::GetExpiryTime() { +int64_t PolicyEngine::GetExpiryTime( + bool ignore_soft_enforce_playback_duration) { if (!HasPlaybackStarted()) return GetRentalExpiryTime(); const int64_t hard_limit = GetHardLicenseExpiryTime(); if (policy_.playback_duration_seconds() == 0) return hard_limit; + if (!ignore_soft_enforce_playback_duration && !was_expired_on_load_ && + policy_.soft_enforce_playback_duration()) { + return hard_limit; + } const int64_t expiry_time = playback_start_time_ + policy_.playback_duration_seconds(); @@ -404,7 +419,8 @@ void PolicyEngine::NotifyKeysChange(CdmKeyStatus new_status) { } void PolicyEngine::NotifyExpirationUpdate() { - const int64_t expiry_time = GetExpiryTime(); + const int64_t expiry_time = + GetExpiryTime(/* ignore_soft_enforce_playback_duration */ false); if (!last_expiry_time_set_ || expiry_time != last_expiry_time_) { last_expiry_time_ = expiry_time; if (event_listener_) diff --git a/libwvdrmengine/cdm/core/test/policy_engine_unittest.cpp b/libwvdrmengine/cdm/core/test/policy_engine_unittest.cpp index fad677d3..54253a78 100644 --- a/libwvdrmengine/cdm/core/test/policy_engine_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/policy_engine_unittest.cpp @@ -1040,6 +1040,89 @@ TEST_F(PolicyEngineTest, MultipleKeysInLicense) { EXPECT_FALSE(policy_engine_->CanDecryptContent(kSomeRandomKeyId)); } +TEST_F(PolicyEngineTest, PlaybackOk_SoftEnforcePlaybackDuration) { + License_Policy* policy = license_.mutable_policy(); + policy->set_soft_enforce_playback_duration(true); + + EXPECT_CALL(*mock_clock_, GetCurrentTime()) + .WillOnce(Return(kLicenseStartTime + 1)) + .WillOnce(Return(kPlaybackStartTime)) + .WillOnce(Return(kPlaybackStartTime + kPlaybackDuration - 5)) + .WillOnce(Return(kPlaybackStartTime + kPlaybackDuration + 5)) + .WillOnce(Return(kLicenseStartTime + kLicenseDuration - 5)) + .WillOnce(Return(kLicenseStartTime + kLicenseDuration + 5)); + + InSequence seq; + ExpectSessionKeysChange(kKeyStatusUsable, true); + EXPECT_CALL(mock_event_listener_, + OnExpirationUpdate(_, kLicenseStartTime + kRentalDuration)); + EXPECT_CALL(mock_event_listener_, + OnExpirationUpdate(_, kLicenseStartTime + kLicenseDuration)); + EXPECT_CALL(check_, Call(1)); + EXPECT_CALL(check_, Call(2)); + EXPECT_CALL(check_, Call(3)); + ExpectSessionKeysChange(kKeyStatusExpired, false); + EXPECT_CALL(check_, Call(4)); + + policy_engine_->SetLicense(license_); + policy_engine_->BeginDecryption(); + + for (int i = 1; i <= 4; ++i) { + EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId)); + policy_engine_->OnTimerEvent(); + check_.Call(i); + } + + EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId)); +} + +TEST_F(PolicyEngineTest, LicenseExpired_SoftEnforceLoadBeforeExpire) { + License_Policy* policy = license_.mutable_policy(); + policy->set_soft_enforce_playback_duration(true); + + EXPECT_CALL(*mock_clock_, GetCurrentTime()) + .WillOnce(Return(kLicenseStartTime + 1)) + .WillOnce(Return(kPlaybackStartTime + kPlaybackDuration - 5)) + .WillOnce(Return(kPlaybackStartTime + kPlaybackDuration + 10)); + + InSequence seq; + ExpectSessionKeysChange(kKeyStatusUsable, true); + EXPECT_CALL(mock_event_listener_, + OnExpirationUpdate(_, kLicenseStartTime + kRentalDuration)); + EXPECT_CALL(mock_event_listener_, + OnExpirationUpdate(_, kLicenseStartTime + kLicenseDuration)); + + policy_engine_->SetLicense(license_); + policy_engine_->RestorePlaybackTimes(kPlaybackStartTime, kPlaybackStartTime); + policy_engine_->OnTimerEvent(); + + EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId)); +} + +TEST_F(PolicyEngineTest, LicenseExpired_SoftEnforceLoadAfterExpire) { + License_Policy* policy = license_.mutable_policy(); + policy->set_soft_enforce_playback_duration(true); + + EXPECT_CALL(*mock_clock_, GetCurrentTime()) + .WillOnce(Return(kLicenseStartTime + 1)) + .WillOnce(Return(kPlaybackStartTime + kPlaybackDuration + 5)) + .WillOnce(Return(kPlaybackStartTime + kPlaybackDuration + 10)); + + InSequence seq; + ExpectSessionKeysChange(kKeyStatusUsable, true); + EXPECT_CALL(mock_event_listener_, + OnExpirationUpdate(_, kLicenseStartTime + kRentalDuration)); + EXPECT_CALL(mock_event_listener_, + OnExpirationUpdate(_, kPlaybackStartTime + kPlaybackDuration)); + ExpectSessionKeysChange(kKeyStatusExpired, false); + + policy_engine_->SetLicense(license_); + policy_engine_->RestorePlaybackTimes(kPlaybackStartTime, kPlaybackStartTime); + policy_engine_->OnTimerEvent(); + + EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId)); +} + class PolicyEngineKeyAllowedUsageTest : public PolicyEngineTest { protected: enum KeyFlag {