// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine License // Agreement. #ifndef CDM_BASE_WV_CONTENT_DECRYPTION_MODULE_H_ #define CDM_BASE_WV_CONTENT_DECRYPTION_MODULE_H_ #include #include #include #include #include "utils/RefBase.h" #include "cdm_identifier.h" #include "disallow_copy_and_assign.h" #include "file_store.h" #include "timer.h" #include "wv_cdm_types.h" #include "wv_metrics.pb.h" namespace wvcdm { class CdmClientPropertySet; class CdmEngine; class WvCdmEventListener; class WvMetricsSnapshot { public: WvMetricsSnapshot(const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics&& metrics, ::time_t ts); // Acts as a constructor, but uses the current time. static WvMetricsSnapshot MakeSnapshot(const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics&& metrics); WvMetricsSnapshot() = default; WvMetricsSnapshot(const WvMetricsSnapshot&) = default; WvMetricsSnapshot(WvMetricsSnapshot&&) = default; WvMetricsSnapshot& operator=(const WvMetricsSnapshot&) = default; WvMetricsSnapshot& operator=(WvMetricsSnapshot&&) = default; const CdmIdentifier& cdm_id() const { return cdm_id_; } const drm_metrics::WvCdmMetrics& metrics() const { return metrics_; } ::time_t timestamp() const { return timestamp_; } std::string GetFormattedTimestamp() const; private: CdmIdentifier cdm_id_; drm_metrics::WvCdmMetrics metrics_; ::time_t timestamp_ = 0; }; class WvMetricsSnapshotQueue : public android::LightRefBase { public: WvMetricsSnapshotQueue(); explicit WvMetricsSnapshotQueue(size_t capacity) : capacity_(capacity) {} size_t capacity() const { return capacity_; } size_t size() const { return snapshots_.size(); } WvMetricsSnapshotQueue(const WvMetricsSnapshotQueue&) = delete; WvMetricsSnapshotQueue(WvMetricsSnapshotQueue&&) = delete; WvMetricsSnapshotQueue& operator=(const WvMetricsSnapshotQueue&) = delete; WvMetricsSnapshotQueue& operator=(WvMetricsSnapshotQueue&&) = delete; void PushMetrics(WvMetricsSnapshot&& snapshot); void PushMetrics(const WvMetricsSnapshot& snapshot); bool GetAll(std::vector* snapshots) const; void Clear(); private: void ReFit(); const size_t capacity_; mutable std::mutex mutex_; std::deque snapshots_; }; class WvContentDecryptionModule : public android::RefBase, public TimerHandler { public: WvContentDecryptionModule(); explicit WvContentDecryptionModule(WvMetricsSnapshotQueue* metrics_queue); virtual ~WvContentDecryptionModule(); // Static methods static bool IsSupported(const std::string& init_data_type); static bool IsCenc(const std::string& init_data_type); static bool IsWebm(const std::string& init_data_type); static bool IsHls(const std::string& init_data_type); static bool IsAudio(const std::string& init_data_type); // Session related methods virtual CdmResponseType OpenSession(const CdmKeySystem& key_system, CdmClientPropertySet* property_set, const CdmIdentifier& identifier, WvCdmEventListener* event_listener, CdmSessionId* session_id); virtual CdmResponseType CloseSession(const CdmSessionId& session_id); virtual bool IsOpenSession(const CdmSessionId& session_id); // Construct a valid license request. virtual CdmResponseType GenerateKeyRequest( const CdmSessionId& session_id, const CdmKeySetId& key_set_id, const std::string& init_data_type, const CdmInitData& init_data, const CdmLicenseType license_type, CdmAppParameterMap& app_parameters, CdmClientPropertySet* property_set, const CdmIdentifier& identifier, CdmKeyRequest* key_request); // Accept license response and extract key info. virtual CdmResponseType AddKey(const CdmSessionId& session_id, const CdmKeyResponse& key_data, CdmKeySetId* key_set_id); // Setup keys for offline usage which were retrived in an earlier key request virtual CdmResponseType RestoreKey(const CdmSessionId& session_id, const CdmKeySetId& key_set_id); // Cancel session virtual CdmResponseType RemoveKeys(const CdmSessionId& session_id); // Query system information virtual CdmResponseType QueryStatus(RequestedSecurityLevel security_level, const std::string& key, std::string* value); // Query session information virtual CdmResponseType QuerySessionStatus(const CdmSessionId& session_id, CdmQueryMap* key_info); // Query license information virtual CdmResponseType QueryKeyStatus(const CdmSessionId& session_id, CdmQueryMap* key_info); // Query device CSR information for Provisioning 4.0 virtual CdmResponseType QueryDeviceSignedCsrPayload( const std::string& challenge, const std::string& device_info, std::string* value); // Query OEMCrypto session ID virtual CdmResponseType QueryOemCryptoSessionId( const CdmSessionId& session_id, CdmQueryMap* response); // Query security level support static bool IsSecurityLevelSupported(CdmSecurityLevel level); // Provisioning related methods virtual CdmResponseType GetProvisioningRequest( CdmCertificateType cert_type, const std::string& cert_authority, const CdmIdentifier& identifier, const std::string& service_certificate, RequestedSecurityLevel requested_security_level, CdmProvisioningRequest* request, std::string* default_url); virtual CdmResponseType HandleProvisioningResponse( const CdmIdentifier& identifier, const CdmProvisioningResponse& response, RequestedSecurityLevel requested_security_level, std::string* cert, std::string* wrapped_key); virtual CdmResponseType Unprovision(CdmSecurityLevel level, const CdmIdentifier& identifier); virtual bool IsProvisioned(CdmSecurityLevel level, const std::string& origin, const std::string& spoid, bool atsc_mode_enabled); // Secure stop related methods virtual CdmResponseType GetUsageInfo(const std::string& app_id, const CdmIdentifier& identifier, CdmUsageReportList* usage_reports); virtual CdmResponseType GetUsageInfo(const std::string& app_id, const CdmSecureStopId& ssid, const CdmIdentifier& identifier, CdmUsageReport* usage_report); virtual CdmResponseType RemoveAllUsageInfo(const std::string& app_id, const CdmIdentifier& identifier); virtual CdmResponseType RemoveUsageInfo( const std::string& app_id, const CdmIdentifier& identifier, const CdmSecureStopId& secure_stop_id); virtual CdmResponseType ReleaseUsageInfo(const CdmKeyResponse& message, const CdmIdentifier& identifier); virtual CdmResponseType GetSecureStopIds(const std::string& app_id, const CdmIdentifier& identifier, std::vector* ssids); // Accept encrypted buffer and decrypt data. // Decryption parameters that need to be specified are // is_encrypted, is_secure, key_id, encrypt_buffer, encrypt_length, // iv, block_offset, decrypt_buffer, decrypt_buffer_length, // decrypt_buffer_offset and subsample_flags virtual CdmResponseType Decrypt(const CdmSessionId& session_id, bool validate_key_id, const CdmDecryptionParameters& parameters); // Accept encrypted sample and decrypt data. virtual CdmResponseType DecryptV16( const CdmSessionId& session_id, bool validate_key_id, const CdmDecryptionParametersV16& parameters); virtual void NotifyResolution(const CdmSessionId& session_id, uint32_t width, uint32_t height); // Validate a passed-in service certificate virtual bool IsValidServiceCertificate(const std::string& certificate); // Fill the |metrics| parameter with the engine metrics data for the // CdmEngine associated with the given CdmIdentifier. // If the CdmEngine instance does not exist, this will return an error. virtual CdmResponseType GetCurrentMetrics(const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics* metrics); // Fill the |snapshots| parameter wrapped engine metrics for all CdmEngine // instances that currently enabled (actively decrypting or performing // other engine-level operations). // Current metrics snapshots contain the engine identifier, metrics data // and time (roughly current time). // |full_list_returned| will indicate whether all existing enginers were // able to report their metrics successfully. virtual CdmResponseType GetAllCurrentMetricsSnapshots( std::vector* snapshots, bool* full_list_returned); // Fill the |snapshots| parameter wrapped engine metrics for several of // the most recently closed CdmEngine instances. // Saved metrics snapshots contain the engine identifier, metrics data // and time of closing. // The same engine identifier may appear multiple times in the list ( // depending on how the app utilizes the MediaDrm plugin). virtual CdmResponseType GetAllSavedMetricsSnapshots( std::vector* snapshots); // Closes the CdmEngine and sessions associated with the given CdmIdentifier. virtual CdmResponseType CloseCdm(const CdmIdentifier& identifier); // When positive, the keybox will be ignored at initialization and force the // device to request a keybox OTA reprovisioning. virtual CdmResponseType SetDebugIgnoreKeyboxCount(uint32_t count); virtual CdmResponseType SetDecryptHash(const std::string& hash_data, CdmSessionId* session_id); virtual CdmResponseType GetDecryptHashError(const CdmSessionId& session_id, std::string* hash_error_string); // Return the list of key_set_ids stored on the current (origin-specific) // file system. virtual CdmResponseType ListStoredLicenses( CdmSecurityLevel security_level, const CdmIdentifier& identifier, std::vector* key_set_ids); // Retrieve offline license state using key_set_id. virtual CdmResponseType GetOfflineLicenseState( const CdmKeySetId& key_set_id, CdmSecurityLevel security_level, const CdmIdentifier& identifier, CdmOfflineLicenseState* licenseState); // Remove offline license using key_set_id. virtual CdmResponseType RemoveOfflineLicense(const CdmKeySetId& key_set_id, CdmSecurityLevel security_level, const CdmIdentifier& identifier); virtual CdmResponseType SetPlaybackId(const CdmSessionId& session_id, const std::string& playback_id); virtual CdmResponseType GetSessionUserId(const CdmSessionId& session_id, uint32_t* user_id); virtual CdmResponseType StoreAtscLicense( const CdmIdentifier& identifier, RequestedSecurityLevel security_level, const CdmKeySetId& key_set_id, const std::string& serialized_license_data); virtual bool SetDefaultOtaKeyboxFallbackDurationRules(); virtual bool SetFastOtaKeyboxFallbackDurationRules(); // Generic crypto API. virtual CdmResponseType GenericEncrypt(const CdmSessionId& session_id, const KeyId& key_id, const std::string& input, const std::string& iv, CdmEncryptionAlgorithm algorithm, std::string* output); virtual CdmResponseType GenericDecrypt(const CdmSessionId& session_id, const KeyId& key_id, const std::string& input, const std::string& iv, CdmEncryptionAlgorithm algorithm, std::string* output); virtual CdmResponseType GenericSign(const CdmSessionId& session_id, const KeyId& key_id, const std::string& input, CdmSigningAlgorithm algorithm, std::string* signature); virtual CdmResponseType GenericVerify(const CdmSessionId& session_id, const KeyId& key_id, const std::string& input, CdmSigningAlgorithm algorithm, const std::string& signature); private: struct CdmInfo { CdmInfo(); wvutil::FileSystem file_system; std::unique_ptr cdm_engine; }; // Finds the CdmEngine instance for the given identifier, creating one if // needed. CdmEngine* EnsureCdmForIdentifier(const CdmIdentifier& identifier); // Finds the CdmEngine instance for the given session id, returning nullptr // if not found. CdmEngine* GetCdmForSessionId(const std::string& session_id); // Close all of the open CdmEngine instances. This is used when ready to close // the WvContentDecryptionModule instance. void CloseAllCdms(); uint32_t GenerateSessionSharingId(); // Timer related methods to drive policy decisions void EnableTimer(); void DisableTimer(); // Call this method only if invoked from a thread other than the timer thread. // Otherwise this might result in deadlock. void DisableTimerAndWaitForExit(); void OnTimerEvent(); // Fill the |metrics| parameter with the metrics data for the CdmEngine // associated with the given |identifier|. If the CdmEngine instance does // not exist, this will return an error. // This methods assumes that |metrics| is not null and that the |cdms_lock_| // has already been acquired. CdmResponseType GetCurrentMetricsInternal(const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics* metrics); void SaveMetrics(const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics&& metrics); static std::mutex session_sharing_id_generation_lock_; std::mutex timer_lock_; Timer timer_; // instance variables // This manages the lifetime of the CDM instances. std::map cdms_; // This contains weak pointers to the CDM instances contained in |cdms_|. std::map cdm_by_session_id_; // Lock for accessing either |cdms_| or |cdm_by_session_id_|. // This lock should be acquired for any of the following: // 1) Getting a CDM instance from |cdms_| or |cdm_by_session_id_| // - Hold lock while searching, release lock once pointer is acquired // 2) Iterating over |cdms_| or |cdm_by_session_id_| // - Hold lock for the entire duration of iterating over CDMs // - DO NOT release the lock until all operations are complete // - This MUST be done regardless of whether |cdms_| or // |cdm_by_session_id_| is being modified // 3) Creating a new CDM instance with |cdms_| // - Hold lock when creating AND initializing the CDM // - Release once CDM is fully initialized // 4) Linking a session to a CDM with |cdm_by_session_id_| // - Hold lock when mapping a session ID to a CDM, release once set // 5) Unlinking a session from a CDM with |cdm_by_session_id_| // - Hold lock when erasing, release once erased. std::mutex cdms_lock_; // Contains a finite list of histories of different CDM engine instances. // When a CDM engine is closed, its metrics will be saved. // Only used if not null. WvMetricsSnapshotQueue* saved_metrics_snapshots_ = nullptr; CORE_DISALLOW_COPY_AND_ASSIGN(WvContentDecryptionModule); }; } // namespace wvcdm #endif // CDM_BASE_WV_CONTENT_DECRYPTION_MODULE_H_