Merge "Allow license renewals after expiry" into klp-dev

This commit is contained in:
Jeff Tinker
2013-11-07 19:09:50 +00:00
committed by Android (Google) Code Review
5 changed files with 165 additions and 86 deletions

View File

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

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,
&buffer_descriptor, params.subsample_flags);
if (OEMCrypto_ERROR_INSUFFICIENT_RESOURCES == sts) {
return INSUFFICIENT_CRYPTO_RESOURCES;
} else if (OEMCrypto_SUCCESS != sts) {
return UNKNOWN_ERROR;
switch (sts) {
case OEMCrypto_SUCCESS:
break;
case OEMCrypto_ERROR_INSUFFICIENT_RESOURCES:
return INSUFFICIENT_CRYPTO_RESOURCES;
case OEMCrypto_ERROR_KEY_EXPIRED:
return NEED_KEY;
default:
return UNKNOWN_ERROR;
}
return NO_ERROR;
}

View File

@@ -106,95 +106,82 @@ void PolicyEngine::SetLicense(
void PolicyEngine::UpdateLicense(
const video_widevine_server::sdk::License& license) {
if (!license.has_policy() || kLicenseStateExpired == license_state_)
if (!license.has_policy())
return;
policy_.MergeFrom(license.policy());
switch (license_state_) {
case kLicenseStateExpired:
// Ignore policy updates.
if (!policy_.can_play()) {
license_state_ = kLicenseStateExpired;
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;
}
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:
case kLicenseStateInitialPendingUsage:
case kLicenseStateCanPlay:
case kLicenseStateNeedRenewal:
case kLicenseStateWaitingLicenseUpdate:
if (!policy_.can_play()) {
license_state_ = kLicenseStateExpired;
return;
}
// if renewal, discard license if version has not been updated
if (license.id().version() > license_id_.version())
license_id_.CopyFrom(license.id());
else
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;
}
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.
// Update time information
int64_t current_time = clock_->GetCurrentTime();
// 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();
// if renewal, discard license if version has not been updated
if (license.id().version() > license_id_.version())
license_id_.CopyFrom(license.id());
else
return;
}
// Calculate policy_max_duration_seconds_. policy_max_duration_seconds_
// will be set to the minimum of the following policies :
// rental_duration_seconds and license_duration_seconds.
// The value is used to determine when the license expires.
policy_max_duration_seconds_ = 0;
// Update time information
int64_t current_time = clock_->GetCurrentTime();
// 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();
if (policy_.has_rental_duration_seconds())
policy_max_duration_seconds_ = policy_.rental_duration_seconds();
// Calculate policy_max_duration_seconds_. policy_max_duration_seconds_
// will be set to the minimum of the following policies :
// rental_duration_seconds and license_duration_seconds.
// The value is used to determine when the license expires.
policy_max_duration_seconds_ = 0;
if ((policy_.license_duration_seconds() > 0) &&
((policy_.license_duration_seconds() <
policy_max_duration_seconds_) ||
policy_max_duration_seconds_ == 0)) {
policy_max_duration_seconds_ = policy_.license_duration_seconds();
}
if (policy_.has_rental_duration_seconds())
policy_max_duration_seconds_ = policy_.rental_duration_seconds();
if (Properties::begin_license_usage_when_received())
playback_start_time_ = current_time;
if ((policy_.license_duration_seconds() > 0) &&
((policy_.license_duration_seconds() <
policy_max_duration_seconds_) ||
policy_max_duration_seconds_ == 0)) {
policy_max_duration_seconds_ = policy_.license_duration_seconds();
}
if (Properties::begin_license_usage_when_received())
playback_start_time_ = current_time;
// Update state
if (Properties::begin_license_usage_when_received()) {
if (policy_.renew_with_usage()) {
license_state_ = kLicenseStateNeedRenewal;
}
else {
license_state_ = kLicenseStateCanPlay;
can_decrypt_ = true;
}
}
else {
if (license_state_ == kLicenseStateInitial) {
license_state_ = kLicenseStateInitialPendingUsage;
}
else {
license_state_ = kLicenseStateCanPlay;
can_decrypt_ = true;
}
}
break;
// Update state
if (Properties::begin_license_usage_when_received()) {
if (policy_.renew_with_usage()) {
license_state_ = kLicenseStateNeedRenewal;
}
else {
license_state_ = kLicenseStateCanPlay;
can_decrypt_ = true;
}
}
else {
if (license_state_ == kLicenseStateInitial) {
license_state_ = kLicenseStateInitialPendingUsage;
}
else {
license_state_ = kLicenseStateCanPlay;
can_decrypt_ = true;
}
}
}

View File

@@ -438,7 +438,7 @@ TEST_F(PolicyEngineTest, PlaybackFailed_RenewFailedVersionNotUpdated) {
EXPECT_FALSE(policy_engine_->can_decrypt());
}
TEST_F(PolicyEngineTest, PlaybackOk_RepeatedRenewFailures) {
TEST_F(PolicyEngineTest, PlaybackFailed_RepeatedRenewFailures) {
EXPECT_CALL(*mock_clock_, GetCurrentTime())
.WillOnce(Return(license_start_time_ + 1))
.WillOnce(Return(license_start_time_ + license_duration_ -
@@ -496,7 +496,83 @@ TEST_F(PolicyEngineTest, PlaybackOk_RepeatedRenewFailures) {
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())
.WillOnce(Return(license_start_time_ + 1))
.WillOnce(Return(license_start_time_ + license_duration_ -