Policy Engine refactoring
[ Merge of http://go/wvgerrit/93743 ] Reworks policy engine in preparation for changes to support timer and clock value handling by OEMCrypto core messages in OEMCrypto v16. No major functional changes have yet been introduced. Time and duration evaluation has been devolved to a new policy timer class. Policy specific to licenses that do not support OEMCrypto core messages is handled by a Policy Timer V15 class. This ensures backward compatibility. Backward compatibility may be needed if * OEMCrypto has not been upgraded to v16 * Licenses were persisted before the device was upgraded to v16 * License service does not yet support core messages Some minor changes to when the current time was retrieved required minor modification to test expectations. Bug: 139372190 Test: Android unit/integration tests Change-Id: I420fb181f656ed9a6bfe54f09e8b398c130d23da
This commit is contained in:
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user