Merge changes I420fb181,Id0c38b45

* changes:
  Policy Engine refactoring
  Update license proto
This commit is contained in:
Rahul Frias
2020-02-14 01:47:59 +00:00
committed by Android (Google) Code Review
13 changed files with 607 additions and 280 deletions

View File

@@ -37,9 +37,6 @@ const std::string kEmptyString;
namespace wvcdm {
// Protobuf generated classes.
using video_widevine::ClientIdentification_ClientCapabilities;
using video_widevine::ClientIdentification_NameValue;
using video_widevine::DrmDeviceCertificate;
using video_widevine::EncryptedClientIdentification;
using video_widevine::License;
using video_widevine::License_KeyContainer;
@@ -47,10 +44,9 @@ using video_widevine::LicenseError;
using video_widevine::LicenseIdentification;
using video_widevine::LicenseRequest;
using video_widevine::LicenseRequest_ContentIdentification;
using video_widevine::LicenseRequest_ContentIdentification_CencDeprecated;
using video_widevine::LicenseRequest_ContentIdentification_ExistingLicense;
using video_widevine::LicenseRequest_ContentIdentification_WebmDeprecated;
using video_widevine::SignedDrmDeviceCertificate;
using video_widevine::LicenseRequest_ContentIdentification_WebmKeyId;
using video_widevine::LicenseRequest_ContentIdentification_WidevinePsshData;
using video_widevine::SignedMessage;
namespace {
@@ -1052,31 +1048,31 @@ CdmResponseType CdmLicense::PrepareContentId(
license_request->mutable_content_id();
if (init_data.is_cenc() || init_data.is_hls()) {
LicenseRequest_ContentIdentification_CencDeprecated* cenc_content_id =
content_id->mutable_cenc_id_deprecated();
LicenseRequest_ContentIdentification_WidevinePsshData* widevine_pssh_data =
content_id->mutable_widevine_pssh_data();
if (!init_data.IsEmpty()) {
cenc_content_id->add_pssh(init_data.data());
widevine_pssh_data->add_pssh_data(init_data.data());
} else {
LOGE("ISO-CENC init data not available");
return CENC_INIT_DATA_UNAVAILABLE;
}
if (!SetTypeAndId(license_type, request_id, cenc_content_id)) {
if (!SetTypeAndId(license_type, request_id, widevine_pssh_data)) {
return PREPARE_CENC_CONTENT_ID_FAILED;
}
} else if (init_data.is_webm()) {
LicenseRequest_ContentIdentification_WebmDeprecated* webm_content_id =
content_id->mutable_webm_id_deprecated();
LicenseRequest_ContentIdentification_WebmKeyId* webm_key_id =
content_id->mutable_webm_key_id();
if (!init_data.IsEmpty()) {
webm_content_id->set_header(init_data.data());
webm_key_id->set_header(init_data.data());
} else {
LOGE("WebM init data not available");
return WEBM_INIT_DATA_UNAVAILABLE;
}
if (!SetTypeAndId(license_type, request_id, webm_content_id)) {
if (!SetTypeAndId(license_type, request_id, webm_key_id)) {
return PREPARE_WEBM_CONTENT_ID_FAILED;
}
} else {

View File

@@ -42,6 +42,8 @@ message RemoteAttestation {
enum LicenseType {
STREAMING = 1;
OFFLINE = 2;
// License type decision is left to provider.
AUTOMATIC = 3;
}
enum PlatformVerificationStatus {
@@ -131,15 +133,23 @@ message License {
// 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];
// Enables "soft enforcement" of rental_duration_seconds. Initial playback
// must always start before rental duration expires. In order to allow
// subsequent playbacks to start after the rental duration expires,
// soft_enforce_playback_duration must be true. Otherwise, subsequent
// playbacks will not be allowed once rental duration expires. Optional.
optional bool soft_enforce_rental_duration = 15 [default = true];
}
message KeyContainer {
enum KeyType {
SIGNING = 1; // Exactly one key of this type must appear.
CONTENT = 2; // Content key.
KEY_CONTROL = 3; // Key control block for license renewals. No key.
SIGNING = 1; // Exactly one key of this type must appear.
CONTENT = 2; // Content key.
KEY_CONTROL = 3; // Key control block for license renewals. No key.
OPERATOR_SESSION = 4; // wrapped keys for auxiliary crypto operations.
ENTITLEMENT = 5; // Entitlement keys.
ENTITLEMENT = 5; // Entitlement keys.
OEM_CONTENT = 6; // Partner-specific content key.
}
// The SecurityLevel enumeration allows the server to communicate the level
@@ -291,7 +301,6 @@ message License {
[default = PLATFORM_NO_VERIFICATION];
// IDs of the groups for which keys are delivered in this license, if any.
repeated bytes group_ids = 11;
}
enum ProtocolVersion {
@@ -302,13 +311,13 @@ enum ProtocolVersion {
message LicenseRequest {
message ContentIdentification {
message CencDeprecated {
repeated bytes pssh = 1;
message WidevinePsshData {
repeated bytes pssh_data = 1;
optional LicenseType license_type = 2;
optional bytes request_id = 3; // Opaque, client-specified.
}
message WebmDeprecated {
message WebmKeyId {
optional bytes header = 1;
optional LicenseType license_type = 2;
optional bytes request_id = 3; // Opaque, client-specified.
@@ -335,8 +344,8 @@ message LicenseRequest {
oneof content_id_variant {
// Exactly one of these must be present.
CencDeprecated cenc_id_deprecated = 1;
WebmDeprecated webm_id_deprecated = 2;
WidevinePsshData widevine_pssh_data = 1;
WebmKeyId webm_key_id = 2;
ExistingLicense existing_license = 3;
InitData init_data = 4;
}
@@ -431,7 +440,6 @@ message SignedMessage {
WRAPPED_AES_KEY = 1;
EPHERMERAL_ECC_PUBLIC_KEY = 2;
}
optional MessageType type = 1;
optional bytes msg = 2;
// Required field that contains the signature of the bytes of msg.

View File

@@ -4,12 +4,11 @@
#include "policy_engine.h"
#include <limits.h>
#include <string>
#include "clock.h"
#include "log.h"
#include "policy_timers_v15.h"
#include "properties.h"
#include "string_conversions.h"
#include "wv_cdm_constants.h"
@@ -30,18 +29,11 @@ PolicyEngine::PolicyEngine(CdmSessionId session_id,
WvCdmEventListener* event_listener,
CryptoSession* crypto_session)
: license_state_(kLicenseStateInitial),
license_start_time_(0),
playback_start_time_(0),
last_playback_time_(0),
last_expiry_time_(0),
grace_period_end_time_(0),
last_expiry_time_set_(false),
was_expired_on_load_(false),
next_renewal_time_(0),
last_recorded_current_time_(0),
session_id_(session_id),
event_listener_(event_listener),
license_keys_(new LicenseKeys(crypto_session->GetSecurityLevel())),
policy_timers(new PolicyTimersV15),
clock_(new Clock) {
InitDevice(crypto_session);
}
@@ -95,16 +87,15 @@ void PolicyEngine::CheckDeviceHdcpStatus() {
void PolicyEngine::OnTimerEvent() {
last_recorded_current_time_ += kCdmPolicyTimerDurationSeconds;
int64_t current_time = GetCurrentTime();
const int64_t current_time = GetCurrentTime();
// If we have passed the grace period, the expiration will update.
if (grace_period_end_time_ == 0 && HasPlaybackStarted(current_time)) {
grace_period_end_time_ = playback_start_time_;
if (policy_timers->HasPassedGracePeriod(current_time)) {
NotifyExpirationUpdate(current_time);
}
// License expiration trumps all.
if (HasLicenseOrPlaybackDurationExpired(current_time) &&
if (policy_timers->HasLicenseOrPlaybackDurationExpired(current_time) &&
license_state_ != kLicenseStateExpired) {
license_state_ = kLicenseStateExpired;
NotifyKeysChange(kKeyStatusExpired);
@@ -119,7 +110,7 @@ void PolicyEngine::OnTimerEvent() {
// Test to determine if renewal should be attempted.
switch (license_state_) {
case kLicenseStateCanPlay: {
if (HasRenewalDelayExpired(current_time)) {
if (policy_timers->HasRenewalDelayExpired(current_time)) {
renewal_needed = true;
}
// HDCP may change, so force a check.
@@ -133,14 +124,14 @@ void PolicyEngine::OnTimerEvent() {
}
case kLicenseStateWaitingLicenseUpdate: {
if (HasRenewalRetryIntervalExpired(current_time)) {
if (policy_timers->HasRenewalRetryIntervalExpired(current_time)) {
renewal_needed = true;
}
break;
}
case kLicenseStatePending: {
if (current_time >= license_start_time_) {
if (!policy_timers->IsLicenseForFuture(current_time)) {
license_state_ = kLicenseStateCanPlay;
NotifyKeysChange(kKeyStatusUsable);
}
@@ -168,8 +159,8 @@ void PolicyEngine::OnTimerEvent() {
void PolicyEngine::SetLicense(const License& license) {
license_id_.Clear();
license_id_.CopyFrom(license.id());
policy_.Clear();
license_keys_->SetFromLicense(license);
policy_timers->SetLicense(license);
UpdateLicense(license);
}
@@ -181,10 +172,10 @@ void PolicyEngine::SetEntitledLicenseKeys(
void PolicyEngine::SetLicenseForRelease(const License& license) {
license_id_.Clear();
license_id_.CopyFrom(license.id());
policy_.Clear();
// Expire any old keys.
NotifyKeysChange(kKeyStatusExpired);
policy_timers->SetLicense(license);
UpdateLicense(license);
}
@@ -195,8 +186,6 @@ void PolicyEngine::UpdateLicense(const License& license) {
LOGD("Updating an expired license");
}
policy_.MergeFrom(license.policy());
// some basic license validation
// license start time needs to be specified in the initial response
if (!license.has_license_start_time()) return;
@@ -209,20 +198,19 @@ void PolicyEngine::UpdateLicense(const License& license) {
return;
}
// Update time information
license_start_time_ = license.license_start_time();
next_renewal_time_ = license_start_time_ + policy_.renewal_delay_seconds();
const int64_t current_time = GetCurrentTime();
policy_timers->UpdateLicense(current_time, license);
int64_t current_time = GetCurrentTime();
if (!policy_.can_play() ||
HasLicenseOrPlaybackDurationExpired(current_time)) {
// Update time information
if (!policy_timers->get_policy().can_play() ||
policy_timers->HasLicenseOrPlaybackDurationExpired(current_time)) {
license_state_ = kLicenseStateExpired;
NotifyKeysChange(kKeyStatusExpired);
return;
}
// Update state
if (current_time >= license_start_time_) {
if (!policy_timers->IsLicenseForFuture(current_time)) {
license_state_ = kLicenseStateCanPlay;
NotifyKeysChange(kKeyStatusUsable);
} else {
@@ -233,20 +221,18 @@ void PolicyEngine::UpdateLicense(const License& license) {
}
bool PolicyEngine::BeginDecryption() {
if (playback_start_time_ == 0) {
const int64_t current_time = GetCurrentTime();
if (!policy_timers->HasPlaybackStarted(current_time)) {
switch (license_state_) {
case kLicenseStateCanPlay:
case kLicenseStateNeedRenewal:
case kLicenseStateWaitingLicenseUpdate:
playback_start_time_ = GetCurrentTime();
last_playback_time_ = playback_start_time_;
if (policy_.play_start_grace_period_seconds() == 0)
grace_period_end_time_ = playback_start_time_;
policy_timers->BeginDecryption(current_time);
if (policy_.renew_with_usage()) {
if (policy_timers->get_policy().renew_with_usage()) {
license_state_ = kLicenseStateNeedRenewal;
}
NotifyExpirationUpdate(playback_start_time_);
NotifyExpirationUpdate(current_time);
return true;
case kLicenseStateInitial:
case kLicenseStatePending:
@@ -259,7 +245,9 @@ bool PolicyEngine::BeginDecryption() {
}
}
void PolicyEngine::DecryptionEvent() { last_playback_time_ = GetCurrentTime(); }
void PolicyEngine::DecryptionEvent() {
policy_timers->DecryptionEvent(GetCurrentTime());
}
void PolicyEngine::NotifyResolution(uint32_t width, uint32_t height) {
SetDeviceResolution(width, height);
@@ -271,7 +259,7 @@ void PolicyEngine::NotifySessionExpiration() {
}
CdmResponseType PolicyEngine::Query(CdmQueryMap* query_response) {
int64_t current_time = GetCurrentTime();
const int64_t current_time = GetCurrentTime();
if (license_state_ == kLicenseStateInitial) {
query_response->clear();
@@ -282,17 +270,20 @@ CdmResponseType PolicyEngine::Query(CdmQueryMap* query_response) {
license_id_.type() == video_widevine::STREAMING ? QUERY_VALUE_STREAMING
: QUERY_VALUE_OFFLINE;
(*query_response)[QUERY_KEY_PLAY_ALLOWED] =
policy_.can_play() ? QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
policy_timers->get_policy().can_play() ? QUERY_VALUE_TRUE
: QUERY_VALUE_FALSE;
(*query_response)[QUERY_KEY_PERSIST_ALLOWED] =
policy_.can_persist() ? QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
policy_timers->get_policy().can_persist() ? QUERY_VALUE_TRUE
: QUERY_VALUE_FALSE;
(*query_response)[QUERY_KEY_RENEW_ALLOWED] =
policy_.can_renew() ? QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
(*query_response)[QUERY_KEY_LICENSE_DURATION_REMAINING] =
std::to_string(GetLicenseOrRentalDurationRemaining(current_time));
policy_timers->get_policy().can_renew() ? QUERY_VALUE_TRUE
: QUERY_VALUE_FALSE;
(*query_response)[QUERY_KEY_LICENSE_DURATION_REMAINING] = std::to_string(
policy_timers->GetLicenseOrRentalDurationRemaining(current_time));
(*query_response)[QUERY_KEY_PLAYBACK_DURATION_REMAINING] =
std::to_string(GetPlaybackDurationRemaining(current_time));
std::to_string(policy_timers->GetPlaybackDurationRemaining(current_time));
(*query_response)[QUERY_KEY_RENEWAL_SERVER_URL] =
policy_.renewal_server_url();
policy_timers->get_policy().renewal_server_url();
return NO_ERROR;
}
@@ -314,148 +305,54 @@ bool PolicyEngine::CanUseKeyForSecurityLevel(const KeyId& key_id) {
}
bool PolicyEngine::GetSecondsSinceStarted(int64_t* seconds_since_started) {
if (playback_start_time_ == 0) return false;
*seconds_since_started = GetCurrentTime() - playback_start_time_;
return (*seconds_since_started >= 0) ? true : false;
return policy_timers->GetSecondsSinceStarted(GetCurrentTime(),
seconds_since_started);
}
bool PolicyEngine::GetSecondsSinceLastPlayed(
int64_t* seconds_since_last_played) {
if (last_playback_time_ == 0) return false;
*seconds_since_last_played = GetCurrentTime() - last_playback_time_;
return (*seconds_since_last_played >= 0) ? true : false;
return policy_timers->GetSecondsSinceLastPlayed(GetCurrentTime(),
seconds_since_last_played);
}
int64_t PolicyEngine::GetLicenseOrPlaybackDurationRemaining() {
const int64_t current_time = GetCurrentTime();
const int64_t expiry_time =
GetExpiryTime(current_time,
/* 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;
return policy_timers->GetLicenseOrPlaybackDurationRemaining(GetCurrentTime());
}
bool PolicyEngine::CanRenew() const {
return policy_timers->get_policy().can_renew();
}
int64_t PolicyEngine::GetPlaybackStartTime() {
return policy_timers->GetPlaybackStartTime();
}
int64_t PolicyEngine::GetLastPlaybackTime() {
return policy_timers->GetLastPlaybackTime();
}
int64_t PolicyEngine::GetGracePeriodEndTime() {
return policy_timers->GetGracePeriodEndTime();
}
void PolicyEngine::RestorePlaybackTimes(int64_t playback_start_time,
int64_t last_playback_time,
int64_t grace_period_end_time) {
playback_start_time_ = (playback_start_time > 0) ? playback_start_time : 0;
last_playback_time_ = (last_playback_time > 0) ? last_playback_time : 0;
grace_period_end_time_ = grace_period_end_time;
if (policy_.play_start_grace_period_seconds() != 0) {
// If we are using grace period, we may need to override some of the values
// given to us by OEMCrypto. |grace_period_end_time| will be 0 if the grace
// period has not expired (effectively playback has not begun). Otherwise,
// |grace_period_end_time| contains the playback start time we should use.
playback_start_time_ = grace_period_end_time;
}
const int64_t current_time = GetCurrentTime();
const int64_t expiry_time =
GetExpiryTime(current_time,
/* ignore_soft_enforce_playback_duration */ true);
was_expired_on_load_ =
expiry_time != NEVER_EXPIRES && expiry_time < current_time;
policy_timers->RestorePlaybackTimes(current_time, playback_start_time,
last_playback_time,
grace_period_end_time);
NotifyExpirationUpdate(current_time);
}
void PolicyEngine::UpdateRenewalRequest(int64_t current_time) {
license_state_ = kLicenseStateWaitingLicenseUpdate;
next_renewal_time_ = current_time + policy_.renewal_retry_interval_seconds();
policy_timers->UpdateRenewalRequest(current_time);
}
bool PolicyEngine::HasLicenseOrPlaybackDurationExpired(int64_t current_time) {
const int64_t expiry_time =
GetExpiryTime(current_time,
/* 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
// indicates that there is no limit to the duration. If the fields are zero
// (including the hard limit) then these methods will return NEVER_EXPIRES.
int64_t PolicyEngine::GetHardLicenseExpiryTime() {
return policy_.license_duration_seconds() > 0
? license_start_time_ + policy_.license_duration_seconds()
: NEVER_EXPIRES;
}
int64_t PolicyEngine::GetRentalExpiryTime() {
const int64_t hard_limit = GetHardLicenseExpiryTime();
if (policy_.rental_duration_seconds() == 0) return hard_limit;
const int64_t expiry_time =
license_start_time_ + policy_.rental_duration_seconds();
if (hard_limit == NEVER_EXPIRES) return expiry_time;
return std::min(hard_limit, expiry_time);
}
int64_t PolicyEngine::GetExpiryTime(
int64_t current_time, bool ignore_soft_enforce_playback_duration) {
if (!HasPlaybackStarted(current_time)) 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();
if (hard_limit == NEVER_EXPIRES) return expiry_time;
return std::min(hard_limit, expiry_time);
}
int64_t PolicyEngine::GetLicenseOrRentalDurationRemaining(
int64_t current_time) {
// This is only used in Query. This should return the time remaining on
// license_duration_seconds for streaming licenses and rental_duration_seconds
// for offline licenses.
if (HasLicenseOrPlaybackDurationExpired(current_time)) return 0;
const int64_t license_expiry_time = GetRentalExpiryTime();
if (license_expiry_time == NEVER_EXPIRES) return LLONG_MAX;
if (license_expiry_time < current_time) return 0;
const int64_t policy_license_duration = policy_.license_duration_seconds();
if (policy_license_duration == NEVER_EXPIRES)
return license_expiry_time - current_time;
return std::min(license_expiry_time - current_time, policy_license_duration);
}
int64_t PolicyEngine::GetPlaybackDurationRemaining(int64_t current_time) {
// This is only used in Query. This should return playback_duration_seconds,
// or the time remaining on it if playing.
const int64_t playback_duration = policy_.playback_duration_seconds();
if (playback_duration == 0) return LLONG_MAX;
if (playback_start_time_ == 0) return playback_duration;
const int64_t playback_expiry_time = playback_duration + playback_start_time_;
if (playback_expiry_time < current_time) return 0;
const int64_t policy_playback_duration = policy_.playback_duration_seconds();
return std::min(playback_expiry_time - current_time,
policy_playback_duration);
}
bool PolicyEngine::HasRenewalDelayExpired(int64_t current_time) {
return policy_.can_renew() && (policy_.renewal_delay_seconds() > 0) &&
license_start_time_ + policy_.renewal_delay_seconds() <= current_time;
}
bool PolicyEngine::HasRenewalRecoveryDurationExpired(int64_t current_time) {
// NOTE: Renewal Recovery Duration is currently not used.
return (policy_.renewal_recovery_duration_seconds() > 0) &&
license_start_time_ + policy_.renewal_recovery_duration_seconds() <=
current_time;
}
bool PolicyEngine::HasRenewalRetryIntervalExpired(int64_t current_time) {
return policy_.can_renew() &&
(policy_.renewal_retry_interval_seconds() > 0) &&
next_renewal_time_ <= current_time;
return policy_timers->HasLicenseOrPlaybackDurationExpired(current_time);
}
// Apply a key status to the current keys.
@@ -479,15 +376,11 @@ void PolicyEngine::NotifyKeysChange(CdmKeyStatus new_status) {
}
void PolicyEngine::NotifyExpirationUpdate(int64_t current_time) {
const int64_t expiry_time =
GetExpiryTime(current_time,
/* ignore_soft_enforce_playback_duration */ false);
if (!last_expiry_time_set_ || expiry_time != last_expiry_time_) {
last_expiry_time_ = expiry_time;
int64_t expiry_time;
if (policy_timers->UpdateExpirationTime(current_time, &expiry_time)) {
if (event_listener_)
event_listener_->OnExpirationUpdate(session_id_, expiry_time);
}
last_expiry_time_set_ = true;
}
int64_t PolicyEngine::GetCurrentTime() {

View File

@@ -0,0 +1,97 @@
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "policy_timers.h"
#include <limits.h>
#include <string>
#include "log.h"
using video_widevine::License;
namespace wvcdm {
void PolicyTimers::SetLicense(const video_widevine::License& license) {
policy_.Clear();
license_start_time_ = license.license_start_time();
}
void PolicyTimers::DecryptionEvent(int64_t current_time) {
last_playback_time_ = current_time;
}
bool PolicyTimers::GetSecondsSinceStarted(int64_t current_time,
int64_t* seconds_since_started) {
if (seconds_since_started == nullptr) {
LOGE("|seconds_since_started| not provided");
return false;
}
if (playback_start_time_ == 0) return false;
*seconds_since_started = current_time - playback_start_time_;
return (*seconds_since_started >= 0) ? true : false;
}
bool PolicyTimers::GetSecondsSinceLastPlayed(
int64_t current_time, int64_t* seconds_since_last_played) {
if (seconds_since_last_played == nullptr) {
LOGE("|seconds_since_last_played| not provided");
return false;
}
if (last_playback_time_ == 0) return false;
*seconds_since_last_played = current_time - last_playback_time_;
return (*seconds_since_last_played >= 0) ? true : false;
}
bool PolicyTimers::IsLicenseForFuture(int64_t current_time) {
return current_time < license_start_time_;
}
bool PolicyTimers::UpdateExpirationTime(int64_t current_time,
int64_t* expiry_time) {
if (expiry_time == nullptr) {
LOGE("|expiry_time| mot provided");
return false;
}
*expiry_time =
GetExpiryTime(current_time,
/* ignore_soft_enforce_playback_duration */ false);
const bool has_expiry_time_been_updated =
!last_expiry_time_set_ || *expiry_time != last_expiry_time_;
if (has_expiry_time_been_updated) last_expiry_time_ = *expiry_time;
last_expiry_time_set_ = true;
return has_expiry_time_been_updated;
}
bool PolicyTimers::HasRenewalDelayExpired(int64_t current_time) {
return policy_.can_renew() && (policy_.renewal_delay_seconds() > 0) &&
(license_start_time_ + policy_.renewal_delay_seconds() <=
current_time);
}
bool PolicyTimers::HasRenewalRetryIntervalExpired(int64_t current_time) {
return policy_.can_renew() &&
(policy_.renewal_retry_interval_seconds() > 0) &&
(next_renewal_time_ <= current_time);
}
void PolicyTimers::UpdateRenewalRequest(int64_t current_time) {
next_renewal_time_ = current_time + policy_.renewal_retry_interval_seconds();
}
bool PolicyTimers::HasRenewalRecoveryDurationExpired(int64_t current_time) {
return (policy_.renewal_recovery_duration_seconds() > 0) &&
(license_start_time_ + policy_.renewal_recovery_duration_seconds() <=
current_time);
}
} // namespace wvcdm

View File

@@ -0,0 +1,164 @@
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "policy_timers_v15.h"
#include <algorithm>
#include <string>
#include "log.h"
#include "wv_cdm_constants.h"
using video_widevine::License;
namespace {
const int64_t kTimeZero = 0;
} // namespace
namespace wvcdm {
bool PolicyTimersV15::UpdateLicense(int64_t current_time,
const License& license) {
if (!license.has_policy()) return false;
policy_.MergeFrom(license.policy());
// some basic license validation
// license start time needs to be specified in the initial response
if (!license.has_license_start_time()) return false;
// Update time information
license_start_time_ = license.license_start_time();
next_renewal_time_ = license_start_time_ + policy_.renewal_delay_seconds();
if (!policy_.can_play() || HasLicenseOrPlaybackDurationExpired(current_time))
return false;
return true;
}
void PolicyTimersV15::BeginDecryption(int64_t current_time) {
if (playback_start_time_ == 0) {
playback_start_time_ = current_time;
last_playback_time_ = current_time;
if (policy_.play_start_grace_period_seconds() == 0)
grace_period_end_time_ = current_time;
}
}
void PolicyTimersV15::RestorePlaybackTimes(int64_t current_time,
int64_t playback_start_time,
int64_t last_playback_time,
int64_t grace_period_end_time) {
playback_start_time_ = std::max(playback_start_time, kTimeZero);
last_playback_time_ = std::max(last_playback_time, kTimeZero);
grace_period_end_time_ = grace_period_end_time;
if (policy_.play_start_grace_period_seconds() != 0) {
// If we are using grace period, we may need to override some of the values
// given to us by OEMCrypto. |grace_period_end_time| will be 0 if the grace
// period has not expired (effectively playback has not begun). Otherwise,
// |grace_period_end_time| contains the playback start time we should use.
playback_start_time_ = grace_period_end_time;
}
const int64_t expiry_time = GetExpiryTime(
current_time, /* ignore_soft_enforce_playback_duration */ true);
was_expired_on_load_ =
expiry_time != NEVER_EXPIRES && expiry_time < current_time;
}
bool PolicyTimersV15::HasPlaybackStarted(int64_t current_time) {
if (playback_start_time_ == 0) return false;
const int64_t playback_time = current_time - playback_start_time_;
return playback_time >= policy_.play_start_grace_period_seconds();
}
bool PolicyTimersV15::HasLicenseOrPlaybackDurationExpired(
int64_t current_time) {
const int64_t expiry_time = GetExpiryTime(
current_time, /* ignore_soft_enforce_playback_duration */ false);
return expiry_time != NEVER_EXPIRES && expiry_time <= current_time;
}
bool PolicyTimersV15::HasPassedGracePeriod(int64_t current_time) {
if (grace_period_end_time_ == 0 && HasPlaybackStarted(current_time)) {
grace_period_end_time_ = playback_start_time_;
return true;
}
return false;
}
int64_t PolicyTimersV15::GetLicenseOrPlaybackDurationRemaining(
int64_t current_time) {
const int64_t expiry_time = GetExpiryTime(
current_time, /* 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;
}
int64_t PolicyTimersV15::GetLicenseOrRentalDurationRemaining(
int64_t current_time) {
if (HasLicenseOrPlaybackDurationExpired(current_time)) return 0;
const int64_t license_expiry_time = GetRentalExpiryTime();
if (license_expiry_time == NEVER_EXPIRES) return LLONG_MAX;
if (license_expiry_time < current_time) return 0;
const int64_t policy_license_duration = policy_.license_duration_seconds();
if (policy_license_duration == NEVER_EXPIRES)
return license_expiry_time - current_time;
return std::min(license_expiry_time - current_time, policy_license_duration);
}
int64_t PolicyTimersV15::GetPlaybackDurationRemaining(int64_t current_time) {
const int64_t playback_duration = policy_.playback_duration_seconds();
if (playback_duration == 0) return LLONG_MAX;
if (playback_start_time_ == 0) return playback_duration;
const int64_t playback_expiry_time = playback_duration + playback_start_time_;
if (playback_expiry_time < current_time) return 0;
const int64_t policy_playback_duration = policy_.playback_duration_seconds();
return std::min(playback_expiry_time - current_time,
policy_playback_duration);
}
// For the policy time fields checked in the following methods, a value of 0
// indicates that there is no limit to the duration. If the fields are zero
// (including the hard limit) then these methods will return NEVER_EXPIRES.
int64_t PolicyTimersV15::GetHardLicenseExpiryTime() {
return policy_.license_duration_seconds() > 0
? license_start_time_ + policy_.license_duration_seconds()
: NEVER_EXPIRES;
}
int64_t PolicyTimersV15::GetRentalExpiryTime() {
const int64_t hard_limit = GetHardLicenseExpiryTime();
if (policy_.rental_duration_seconds() == 0) return hard_limit;
const int64_t expiry_time =
license_start_time_ + policy_.rental_duration_seconds();
if (hard_limit == NEVER_EXPIRES) return expiry_time;
return std::min(hard_limit, expiry_time);
}
int64_t PolicyTimersV15::GetExpiryTime(
int64_t current_time, bool ignore_soft_enforce_playback_duration) {
if (!HasPlaybackStarted(current_time)) 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();
if (hard_limit == NEVER_EXPIRES) return expiry_time;
return std::min(hard_limit, expiry_time);
}
} // namespace wvcdm