* Add CE test for incomplete remove() [ Merge of http://go/wvgerrit/14658 ] This depends on I064c053dd986a432865163aed5c9c3493f14340b to get PolicyEngine to implement the EME semantics expressed in this test. This also excludes another error code from causing an error log in CdmEngine::AddKey, because this is actually an expected, handled error in the CE CDM and it causes some confusing noise during testing and development. * Drop CdmEngine test main [ Merge of http://go/wvgerrit/14693 ] The command-line arguments are no longer in use anywhere, and dropping the CdmEngine test's main allows me to add those tests to the CE test suite. * Add PolicyEngine::SetLicenseForRelease() [ Merge of http://go/wvgerrit/14651 ] In order to implement the EME-specified behaviors for load() & remove(), some small changes are required in PolicyEngine. According to EME, you should be able to remove() an active session. This means that releasing a persistent session is not a separate load operation. EME also states that the keys should be expired when this is done. Remove() is implemented using GenerateKeyRequest(type=release). This leads to CdmLicense::RestoreLicenseForRelease, which in turn calls PolicyEngine::SetLicense. When removing an active session, the policy engine will have keys already loaded. The old behavior would cause these keys to be reloaded. We need them to be expired, instead. Once a remove() has been started, the keys should never be loadable again. If a release confirmation is not received by the CDM, the session should still be loadable. EME states that once a session has had remove() called, then is loaded again later, there should be no keys. Not that they should be expired, but not present. The old behavior would cause these keys to be reloaded as usable. This new method allows EME remove() and load() behaviors to be faithfully implemented in the CE CDM. When removing an active session, the old keys become expired. When removing a partially- removed, newly-loaded session, no keys will be loaded at all. This change does not affect any existing tests in core/. New tests have been added in PolicyEngineTest to cover the behavior of the new method. Change-Id: Idd61487c277c9eadb4a044cb2a563e151442a548
168 lines
5.9 KiB
C++
168 lines
5.9 KiB
C++
// Copyright 2013 Google Inc. All Rights Reserved.
|
|
|
|
#ifndef WVCDM_CORE_POLICY_ENGINE_H_
|
|
#define WVCDM_CORE_POLICY_ENGINE_H_
|
|
|
|
#include <map>
|
|
#include <string>
|
|
|
|
#include "license_protocol.pb.h"
|
|
#include "max_res_engine.h"
|
|
#include "scoped_ptr.h"
|
|
#include "wv_cdm_types.h"
|
|
|
|
namespace wvcdm {
|
|
|
|
using video_widevine_server::sdk::LicenseIdentification;
|
|
|
|
class Clock;
|
|
class CryptoSession;
|
|
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 CanDecrypt(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.
|
|
// The license state transitions to kLicenseStateCanPlay if the license
|
|
// permits playback.
|
|
virtual void SetLicense(const video_widevine_server::sdk::License& license);
|
|
|
|
// 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_server::sdk::License& license);
|
|
|
|
// Call this on first decrypt to set the start of playback.
|
|
virtual void BeginDecryption(void);
|
|
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. The license will transition to
|
|
// kLicenseStateCanPlay if the license permits playback.
|
|
virtual void UpdateLicense(
|
|
const video_widevine_server::sdk::License& license);
|
|
|
|
// 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* key_info);
|
|
|
|
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() { return playback_start_time_; }
|
|
int64_t GetLastPlaybackTime() { return last_playback_time_; }
|
|
void RestorePlaybackTimes(int64_t playback_start_time,
|
|
int64_t last_playback_time);
|
|
|
|
bool IsLicenseForFuture() { return license_state_ == kLicenseStatePending; }
|
|
bool IsPlaybackStarted() { return playback_start_time_ > 0; }
|
|
|
|
bool IsLicenseOrPlaybackDurationExpired(int64_t current_time);
|
|
|
|
bool CanRenew() { return policy_.can_renew(); }
|
|
|
|
private:
|
|
friend class PolicyEngineTest;
|
|
|
|
typedef enum {
|
|
kLicenseStateInitial,
|
|
kLicenseStatePending, // if license is issued for sometime in the future
|
|
kLicenseStateCanPlay,
|
|
kLicenseStateNeedRenewal,
|
|
kLicenseStateWaitingLicenseUpdate,
|
|
kLicenseStateExpired
|
|
} LicenseState;
|
|
|
|
int64_t GetLicenseExpiryTime();
|
|
int64_t GetPlaybackExpiryTime();
|
|
|
|
int64_t GetLicenseDurationRemaining(int64_t current_time);
|
|
int64_t GetPlaybackDurationRemaining(int64_t current_time);
|
|
|
|
bool IsRenewalDelayExpired(int64_t current_time);
|
|
bool IsRenewalRecoveryDurationExpired(int64_t current_time);
|
|
bool IsRenewalRetryIntervalExpired(int64_t current_time);
|
|
|
|
void UpdateRenewalRequest(int64_t current_time);
|
|
|
|
// 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();
|
|
|
|
// These setters are for testing only. Takes ownership of the pointers.
|
|
void set_clock(Clock* clock);
|
|
void set_max_res_engine(MaxResEngine* max_res_engine);
|
|
|
|
LicenseState license_state_;
|
|
|
|
// This is the current policy information for this license. This gets updated
|
|
// as license renewals occur.
|
|
video_widevine_server::sdk::License::Policy policy_;
|
|
|
|
// 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_server::sdk::LicenseIdentification license_id_;
|
|
|
|
// The server returns the license start time in the license/license renewal
|
|
// response based off the request time sent by the client in the
|
|
// license request/renewal
|
|
int64_t license_start_time_;
|
|
int64_t playback_start_time_;
|
|
int64_t last_playback_time_;
|
|
int64_t last_expiry_time_;
|
|
bool last_expiry_time_set_;
|
|
|
|
// This is used as a reference point for policy management. This value
|
|
// represents an offset from license_start_time_. This is used to
|
|
// calculate the time where renewal retries should occur.
|
|
int64_t next_renewal_time_;
|
|
int64_t policy_max_duration_seconds_;
|
|
|
|
// Used to dispatch CDM events.
|
|
CdmSessionId session_id_;
|
|
WvCdmEventListener* event_listener_;
|
|
|
|
scoped_ptr<MaxResEngine> max_res_engine_;
|
|
|
|
std::map<KeyId, CdmKeyStatus> keys_status_;
|
|
|
|
scoped_ptr<Clock> clock_;
|
|
|
|
CORE_DISALLOW_COPY_AND_ASSIGN(PolicyEngine);
|
|
};
|
|
|
|
} // wvcdm
|
|
|
|
#endif // WVCDM_CORE_POLICY_ENGINE_H_
|