am 48742bba: am 8e5bc02e: Merge "Allow license renewals after expiry" into klp-dev

* commit '48742bba5bd9b4c39fb41359a62e15a6503f1a5e':
  Allow license renewals after expiry
This commit is contained in:
Jeff Tinker
2013-11-07 15:13:05 -08:00
committed by Android Git Automerger
5 changed files with 165 additions and 86 deletions

View File

@@ -53,6 +53,9 @@ class PolicyEngine {
return license_id_; return license_id_;
} }
bool IsLicenseDurationExpired(int64_t current_time);
bool IsPlaybackDurationExpired(int64_t current_time);
private: private:
typedef enum { typedef enum {
kLicenseStateInitial, kLicenseStateInitial,
@@ -65,8 +68,6 @@ class PolicyEngine {
void Init(Clock* clock); void Init(Clock* clock);
bool IsLicenseDurationExpired(int64_t current_time);
bool IsPlaybackDurationExpired(int64_t current_time);
bool IsRenewalDelayExpired(int64_t current_time); bool IsRenewalDelayExpired(int64_t current_time);
bool IsRenewalRecoveryDurationExpired(int64_t current_time); bool IsRenewalRecoveryDurationExpired(int64_t current_time);
bool IsRenewalRetryIntervalExpired(int64_t current_time); bool IsRenewalRetryIntervalExpired(int64_t current_time);

View File

@@ -303,7 +303,17 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
if (crypto_session_.get() == NULL || !crypto_session_->IsOpen()) if (crypto_session_.get() == NULL || !crypto_session_->IsOpen())
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
return crypto_session_->Decrypt(params); CdmResponseType status = crypto_session_->Decrypt(params);
// TODO(rfrias): Remove after support for OEMCrypto_ERROR_KEY_EXPIRED is in
if (UNKNOWN_ERROR == status) {
Clock clock;
int64_t current_time = clock.GetCurrentTime();
if (policy_engine_.IsLicenseDurationExpired(current_time) ||
policy_engine_.IsPlaybackDurationExpired(current_time)) {
return NEED_KEY;
}
}
return status;
} }
// License renewal // License renewal

13
libwvdrmengine/cdm/core/src/crypto_session.cpp Executable file → Normal file
View File

@@ -588,10 +588,15 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
params.is_encrypted, &(*params.iv).front(), params.block_offset, params.is_encrypted, &(*params.iv).front(), params.block_offset,
&buffer_descriptor, params.subsample_flags); &buffer_descriptor, params.subsample_flags);
if (OEMCrypto_ERROR_INSUFFICIENT_RESOURCES == sts) { switch (sts) {
return INSUFFICIENT_CRYPTO_RESOURCES; case OEMCrypto_SUCCESS:
} else if (OEMCrypto_SUCCESS != sts) { break;
return UNKNOWN_ERROR; case OEMCrypto_ERROR_INSUFFICIENT_RESOURCES:
return INSUFFICIENT_CRYPTO_RESOURCES;
case OEMCrypto_ERROR_KEY_EXPIRED:
return NEED_KEY;
default:
return UNKNOWN_ERROR;
} }
return NO_ERROR; return NO_ERROR;
} }

View File

@@ -106,95 +106,82 @@ void PolicyEngine::SetLicense(
void PolicyEngine::UpdateLicense( void PolicyEngine::UpdateLicense(
const video_widevine_server::sdk::License& license) { const video_widevine_server::sdk::License& license) {
if (!license.has_policy() || kLicenseStateExpired == license_state_) if (!license.has_policy())
return; return;
policy_.MergeFrom(license.policy()); policy_.MergeFrom(license.policy());
switch (license_state_) { if (!policy_.can_play()) {
case kLicenseStateExpired: license_state_ = kLicenseStateExpired;
// Ignore policy updates. return;
}
// some basic license validation
if (license_state_ == kLicenseStateInitial) {
// license start time needs to be present in the initial response
if (!license.has_license_start_time())
return; return;
}
else {
// TODO(edwingwong, rfrias): Check back with Thomas and see if
// we need to enforce that all duration windows are absent if
// license_start_time is not present. This is a TBD.
case kLicenseStateInitial: // if renewal, discard license if version has not been updated
case kLicenseStateInitialPendingUsage: if (license.id().version() > license_id_.version())
case kLicenseStateCanPlay: license_id_.CopyFrom(license.id());
case kLicenseStateNeedRenewal: else
case kLicenseStateWaitingLicenseUpdate: return;
if (!policy_.can_play()) { }
license_state_ = kLicenseStateExpired;
return;
}
// some basic license validation // Update time information
if (license_state_ == kLicenseStateInitial) { int64_t current_time = clock_->GetCurrentTime();
// license start time needs to be present in the initial response // TODO(edwingwong, rfrias): Check back with Thomas and see if
if (!license.has_license_start_time()) // we need to enforce that all duration windows are absent if
return; // license_start_time is not present. This is a TBD.
} if (license.has_license_start_time())
else { license_start_time_ = license.license_start_time();
// TODO(edwingwong, rfrias): Check back with Thomas and see if license_received_time_ = current_time;
// we need to enforce that all duration windows are absent if next_renewal_time_ = current_time +
// license_start_time is not present. This is a TBD. policy_.renewal_delay_seconds();
// if renewal, discard license if version has not been updated // Calculate policy_max_duration_seconds_. policy_max_duration_seconds_
if (license.id().version() > license_id_.version()) // will be set to the minimum of the following policies :
license_id_.CopyFrom(license.id()); // rental_duration_seconds and license_duration_seconds.
else // The value is used to determine when the license expires.
return; policy_max_duration_seconds_ = 0;
}
// Update time information if (policy_.has_rental_duration_seconds())
int64_t current_time = clock_->GetCurrentTime(); policy_max_duration_seconds_ = policy_.rental_duration_seconds();
// TODO(edwingwong, rfrias): Check back with Thomas and see if
// we need to enforce that all duration windows are absent if
// license_start_time is not present. This is a TBD.
if (license.has_license_start_time())
license_start_time_ = license.license_start_time();
license_received_time_ = current_time;
next_renewal_time_ = current_time +
policy_.renewal_delay_seconds();
// Calculate policy_max_duration_seconds_. policy_max_duration_seconds_ if ((policy_.license_duration_seconds() > 0) &&
// will be set to the minimum of the following policies : ((policy_.license_duration_seconds() <
// rental_duration_seconds and license_duration_seconds. policy_max_duration_seconds_) ||
// The value is used to determine when the license expires. policy_max_duration_seconds_ == 0)) {
policy_max_duration_seconds_ = 0; policy_max_duration_seconds_ = policy_.license_duration_seconds();
}
if (policy_.has_rental_duration_seconds()) if (Properties::begin_license_usage_when_received())
policy_max_duration_seconds_ = policy_.rental_duration_seconds(); playback_start_time_ = current_time;
if ((policy_.license_duration_seconds() > 0) && // Update state
((policy_.license_duration_seconds() < if (Properties::begin_license_usage_when_received()) {
policy_max_duration_seconds_) || if (policy_.renew_with_usage()) {
policy_max_duration_seconds_ == 0)) { license_state_ = kLicenseStateNeedRenewal;
policy_max_duration_seconds_ = policy_.license_duration_seconds(); }
} else {
license_state_ = kLicenseStateCanPlay;
if (Properties::begin_license_usage_when_received()) can_decrypt_ = true;
playback_start_time_ = current_time; }
}
// Update state else {
if (Properties::begin_license_usage_when_received()) { if (license_state_ == kLicenseStateInitial) {
if (policy_.renew_with_usage()) { license_state_ = kLicenseStateInitialPendingUsage;
license_state_ = kLicenseStateNeedRenewal; }
} else {
else { license_state_ = kLicenseStateCanPlay;
license_state_ = kLicenseStateCanPlay; can_decrypt_ = true;
can_decrypt_ = true; }
}
}
else {
if (license_state_ == kLicenseStateInitial) {
license_state_ = kLicenseStateInitialPendingUsage;
}
else {
license_state_ = kLicenseStateCanPlay;
can_decrypt_ = true;
}
}
break;
} }
} }

View File

@@ -438,7 +438,7 @@ TEST_F(PolicyEngineTest, PlaybackFailed_RenewFailedVersionNotUpdated) {
EXPECT_FALSE(policy_engine_->can_decrypt()); EXPECT_FALSE(policy_engine_->can_decrypt());
} }
TEST_F(PolicyEngineTest, PlaybackOk_RepeatedRenewFailures) { TEST_F(PolicyEngineTest, PlaybackFailed_RepeatedRenewFailures) {
EXPECT_CALL(*mock_clock_, GetCurrentTime()) EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(license_start_time_ + 1)) .WillOnce(Return(license_start_time_ + 1))
.WillOnce(Return(license_start_time_ + license_duration_ - .WillOnce(Return(license_start_time_ + license_duration_ -
@@ -496,7 +496,83 @@ TEST_F(PolicyEngineTest, PlaybackOk_RepeatedRenewFailures) {
EXPECT_FALSE(policy_engine_->can_decrypt()); EXPECT_FALSE(policy_engine_->can_decrypt());
} }
TEST_F(PolicyEngineTest, PlaybackOk_RenewedSuccessAfterExpiry) { TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccessAfterExpiry) {
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(license_start_time_ + 1))
.WillOnce(Return(license_start_time_ + license_duration_ -
playback_duration_ + 1))
.WillOnce(Return(license_start_time_ + license_renewal_delay_ - 10))
.WillOnce(Return(license_start_time_ + license_renewal_delay_ + 10))
.WillOnce(Return(license_start_time_ + license_renewal_delay_ + 20))
.WillOnce(Return(license_start_time_ + license_renewal_delay_ + 40))
.WillOnce(Return(license_start_time_ + license_renewal_delay_ + 50))
.WillOnce(Return(license_start_time_ + license_renewal_delay_ + 70))
.WillOnce(Return(license_start_time_ + license_renewal_delay_ + 80))
.WillOnce(Return(license_start_time_ + license_duration_ + 10))
.WillOnce(Return(license_start_time_ + license_duration_ + 30))
.WillOnce(Return(license_start_time_ + license_duration_ + 40));
policy_engine_->SetLicense(license_);
policy_engine_->BeginDecryption();
EXPECT_TRUE(policy_engine_->can_decrypt());
bool event_occurred;
CdmEventType event;
policy_engine_->OnTimerEvent(event_occurred, event);
EXPECT_FALSE(event_occurred);
policy_engine_->OnTimerEvent(event_occurred, event);
EXPECT_TRUE(event_occurred);
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
EXPECT_TRUE(policy_engine_->can_decrypt());
policy_engine_->OnTimerEvent(event_occurred, event);
EXPECT_FALSE(event_occurred);
policy_engine_->OnTimerEvent(event_occurred, event);
EXPECT_TRUE(event_occurred);
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
EXPECT_TRUE(policy_engine_->can_decrypt());
policy_engine_->OnTimerEvent(event_occurred, event);
EXPECT_FALSE(event_occurred);
policy_engine_->OnTimerEvent(event_occurred, event);
EXPECT_TRUE(event_occurred);
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
EXPECT_TRUE(policy_engine_->can_decrypt());
policy_engine_->OnTimerEvent(event_occurred, event);
EXPECT_FALSE(event_occurred);
policy_engine_->OnTimerEvent(event_occurred, event);
EXPECT_TRUE(event_occurred);
EXPECT_EQ(LICENSE_EXPIRED_EVENT, event);
EXPECT_FALSE(policy_engine_->can_decrypt());
license_.set_license_start_time(license_start_time_ +
license_duration_ + 20);
LicenseIdentification* id = license_.mutable_id();
id->set_version(2);
License_Policy* policy = license_.mutable_policy();
policy = license_.mutable_policy();
policy->set_playback_duration_seconds(playback_duration_ + 100);
policy->set_license_duration_seconds(license_duration_ + 100);
policy_engine_->UpdateLicense(license_);
policy_engine_->OnTimerEvent(event_occurred, event);
EXPECT_FALSE(event_occurred);
EXPECT_TRUE(policy_engine_->can_decrypt());
}
TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccessAfterFailures) {
EXPECT_CALL(*mock_clock_, GetCurrentTime()) EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(license_start_time_ + 1)) .WillOnce(Return(license_start_time_ + 1))
.WillOnce(Return(license_start_time_ + license_duration_ - .WillOnce(Return(license_start_time_ + license_duration_ -