Merge changes I420fb181,Id0c38b45
* changes: Policy Engine refactoring Update license proto
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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() {
|
||||
|
||||
97
libwvdrmengine/cdm/core/src/policy_timers.cpp
Normal file
97
libwvdrmengine/cdm/core/src/policy_timers.cpp
Normal 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
|
||||
164
libwvdrmengine/cdm/core/src/policy_timers_v15.cpp
Normal file
164
libwvdrmengine/cdm/core/src/policy_timers_v15.cpp
Normal 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
|
||||
Reference in New Issue
Block a user