[ Merge of http://go/wvgerrit/106325 and http://go/ag/12644840 ] When offline licenses are restored, licenses and any renewals are processed. License state evaluation occurs and notifications are sent to listeners. If the license is expired, which is likely if a renewal is present, the license state will transition to expired. Transitions out of expired state are not allowed and the renewal has no effect. If we work around this by allowing transitions out of expired state, listeners will get notifications that keys have expired and then that are usable soon after. To avoid delivering erroneous notifications we delay evaluation of license state while the license and renewal are being processed. Evaluation occurs at the last stage of license restoration when playback information from the usage table is being restored. This only need to occur for when licenses are being restored. In other cases when a license or renewal is received, license state evaluation and event listener notification needs to occur immediately. Bug: 166131956 Test: WV unit/integration tests, GtsMediaTestCases tests Change-Id: Ic8ade25316c5e20cc88de9225c43c24b28f21ac4
206 lines
7.5 KiB
C++
206 lines
7.5 KiB
C++
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
|
// source code may only be used and distributed under the Widevine Master
|
|
// License Agreement.
|
|
|
|
#ifndef WVCDM_CORE_POLICY_ENGINE_H_
|
|
#define WVCDM_CORE_POLICY_ENGINE_H_
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
#include "clock.h"
|
|
#include "disallow_copy_and_assign.h"
|
|
#include "license_key_status.h"
|
|
#include "license_protocol.pb.h"
|
|
#include "wv_cdm_types.h"
|
|
|
|
namespace wvcdm {
|
|
|
|
using video_widevine::LicenseIdentification;
|
|
using video_widevine::WidevinePsshData_EntitledKey;
|
|
|
|
class Clock;
|
|
class CryptoSession;
|
|
class PolicyTimers;
|
|
class WvCdmEventListener;
|
|
|
|
// This acts as an oracle that basically says "Yes(true) you may still decrypt
|
|
// or no(false) you may not decrypt this data anymore."
|
|
class PolicyEngine {
|
|
public:
|
|
PolicyEngine(CdmSessionId session_id, WvCdmEventListener* event_listener,
|
|
CryptoSession* crypto_session);
|
|
virtual ~PolicyEngine();
|
|
|
|
// The value returned should be taken as a hint rather than an absolute
|
|
// status. It is computed during the last call to either SetLicense/
|
|
// UpdateLicense/OnTimerEvent/BeginDecryption and may be out of sync
|
|
// depending on the amount of time elapsed. The current decryption
|
|
// status is not calculated to avoid overhead in the decryption path.
|
|
virtual bool CanDecryptContent(const KeyId& key_id);
|
|
|
|
// Returns the current CdmKeyStatus for the given key, or
|
|
// kKeyStatusKeyUnknown if the key is not found. This is useful for finding
|
|
// out why a key is not usable.
|
|
virtual CdmKeyStatus GetKeyStatus(const KeyId& key_id);
|
|
|
|
// Verifies whether the policy allows use of the specified key of
|
|
// a given security level for content decryption.
|
|
virtual bool CanUseKeyForSecurityLevel(const KeyId& key_id);
|
|
|
|
// OnTimerEvent is called when a timer fires. It notifies the Policy Engine
|
|
// that the timer has fired and dispatches the relevant events through
|
|
// |event_listener_|.
|
|
virtual void OnTimerEvent();
|
|
|
|
// SetLicense is used in handling the initial license response. It stores
|
|
// an exact copy of the policy information stored in the license.
|
|
// License state transitions and notifications may occur if
|
|
// |defer_license_state_update| is not set. If set, the license is likely
|
|
// being restored and transitions and notifications will be deferred until
|
|
// stored playback times are restored.
|
|
virtual void SetLicense(const video_widevine::License& license,
|
|
bool supports_core_messages,
|
|
bool defer_license_state_update);
|
|
|
|
// Used to update the currently loaded entitled content keys.
|
|
virtual void SetEntitledLicenseKeys(
|
|
const std::vector<WidevinePsshData_EntitledKey>& entitled_keys);
|
|
|
|
// SetLicenseForRelease is used when releasing a license. The keys in this
|
|
// license will be ignored, and any old keys will be expired.
|
|
virtual void SetLicenseForRelease(const video_widevine::License& license,
|
|
bool supports_core_messages);
|
|
|
|
// Call this on first decrypt to set the start of playback.
|
|
virtual bool BeginDecryption(void);
|
|
// Call this periodically to update the most recent playback time.
|
|
virtual void DecryptionEvent(void);
|
|
|
|
// UpdateLicense is used in handling a license response for a renewal request.
|
|
// The response may only contain any policy fields that have changed. In this
|
|
// case an exact copy is not what we want to happen. We also will receive an
|
|
// updated license_start_time from the server.
|
|
// License state transitions and notifications may occur if
|
|
// |defer_license_state_update| is not set. If set, the license is likely
|
|
// being restored and transitions and notifications will be deferred until
|
|
// stored playback times are restored.
|
|
virtual void UpdateLicense(const video_widevine::License& license,
|
|
bool defer_license_state_update);
|
|
|
|
// This method updates license state and sends appropriate notifications
|
|
// to event listeners.
|
|
virtual void UpdateLicenseState(int64_t current_time);
|
|
|
|
// Used for notifying the Policy Engine of resolution changes
|
|
virtual void NotifyResolution(uint32_t width, uint32_t height);
|
|
|
|
virtual void NotifySessionExpiration();
|
|
|
|
virtual CdmResponseType Query(CdmQueryMap* query_response);
|
|
|
|
virtual CdmResponseType QueryKeyAllowedUsage(const KeyId& key_id,
|
|
CdmKeyAllowedUsage* key_usage);
|
|
|
|
virtual const LicenseIdentification& license_id() { return license_id_; }
|
|
|
|
bool GetSecondsSinceStarted(int64_t* seconds_since_started);
|
|
bool GetSecondsSinceLastPlayed(int64_t* seconds_since_started);
|
|
|
|
// For offline save and restore
|
|
int64_t GetPlaybackStartTime();
|
|
int64_t GetLastPlaybackTime();
|
|
int64_t GetGracePeriodEndTime();
|
|
|
|
// This method will also update license state and sends appropriate
|
|
// notifications to event listeners.
|
|
void RestorePlaybackTimes(int64_t playback_start_time,
|
|
int64_t last_playback_time,
|
|
int64_t grace_period_end_time);
|
|
|
|
bool IsLicenseForFuture() { return license_state_ == kLicenseStatePending; }
|
|
|
|
bool HasLicenseOrRentalOrPlaybackDurationExpired(int64_t current_time);
|
|
int64_t GetLicenseOrRentalOrPlaybackDurationRemaining();
|
|
|
|
bool CanRenew() const;
|
|
|
|
bool IsSufficientOutputProtection(const KeyId& key_id) {
|
|
return license_keys_->MeetsConstraints(key_id);
|
|
}
|
|
|
|
private:
|
|
friend class PolicyEngineTest;
|
|
friend class PolicyEngineConstraintsTest;
|
|
|
|
void InitDevice(CryptoSession* crypto_session);
|
|
void SetDeviceResolution(uint32_t width, uint32_t height);
|
|
void CheckDeviceHdcpStatusOnTimer(int64_t current_time);
|
|
void CheckDeviceHdcpStatus();
|
|
|
|
typedef enum {
|
|
kLicenseStateInitial,
|
|
kLicenseStatePending, // if license is issued for sometime in the future
|
|
kLicenseStateCanPlay,
|
|
kLicenseStateNeedRenewal,
|
|
kLicenseStateWaitingLicenseUpdate,
|
|
kLicenseStateExpired
|
|
} LicenseState;
|
|
|
|
// Notifies updates in keys information and fire OnKeysChange event if
|
|
// key changes.
|
|
void NotifyKeysChange(CdmKeyStatus new_status);
|
|
|
|
// Notifies updates in expiry time and fire OnExpirationUpdate event if
|
|
// expiry time changes.
|
|
void NotifyExpirationUpdate(int64_t current_time);
|
|
|
|
void UpdateRenewalRequest(int64_t current_time);
|
|
|
|
int64_t GetCurrentTime();
|
|
|
|
// Test only methods
|
|
// set_clock alters ownership of the passed-in pointer.
|
|
void set_clock(Clock* clock);
|
|
|
|
void SetSecurityLevelForTest(CdmSecurityLevel security_level);
|
|
|
|
LicenseState license_state_;
|
|
int64_t license_state_update_deadline_;
|
|
|
|
// This is the license id field from server response. This data gets passed
|
|
// back to the server in each renewal request. When we get a renewal response
|
|
// from the license server we will get an updated id field.
|
|
video_widevine::LicenseIdentification license_id_;
|
|
|
|
// to assist in clock rollback checks
|
|
int64_t last_recorded_current_time_;
|
|
|
|
// Used to dispatch CDM events.
|
|
CdmSessionId session_id_;
|
|
WvCdmEventListener* event_listener_;
|
|
|
|
// Keys associated with license - holds allowed usage, usage constraints,
|
|
// and current status (CdmKeyStatus)
|
|
std::unique_ptr<LicenseKeys> license_keys_;
|
|
|
|
// This is the current policy information for this license. This gets updated
|
|
// as license renewals occur.
|
|
video_widevine::License::Policy policy_;
|
|
|
|
// Device checks
|
|
int64_t next_device_check_;
|
|
uint32_t current_resolution_;
|
|
CryptoSession* crypto_session_;
|
|
|
|
std::unique_ptr<PolicyTimers> policy_timers_;
|
|
std::unique_ptr<Clock> clock_;
|
|
|
|
CORE_DISALLOW_COPY_AND_ASSIGN(PolicyEngine);
|
|
};
|
|
|
|
} // namespace wvcdm
|
|
|
|
#endif // WVCDM_CORE_POLICY_ENGINE_H_
|