tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CDMProxy.h (11344B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef CDMProxy_h_
      8 #define CDMProxy_h_
      9 
     10 #include "mozilla/CDMCaps.h"
     11 #include "mozilla/DataMutex.h"
     12 #include "mozilla/MozPromise.h"
     13 #include "mozilla/dom/MediaKeyMessageEvent.h"
     14 #include "mozilla/dom/MediaKeySessionBinding.h"
     15 #include "mozilla/dom/MediaKeys.h"
     16 #include "nsIThread.h"
     17 
     18 namespace mozilla {
     19 class ErrorResult;
     20 class MediaRawData;
     21 class ChromiumCDMProxy;
     22 class RemoteCDMChild;
     23 #ifdef MOZ_WMF_CDM
     24 class WMFCDMProxy;
     25 #endif
     26 
     27 namespace eme {
     28 enum DecryptStatus {
     29  Ok = 0,
     30  GenericErr = 1,
     31  NoKeyErr = 2,
     32  AbortedErr = 3,
     33 };
     34 }
     35 
     36 using eme::DecryptStatus;
     37 
     38 struct DecryptResult {
     39  DecryptResult(DecryptStatus aStatus, MediaRawData* aSample)
     40      : mStatus(aStatus), mSample(aSample) {}
     41  DecryptStatus mStatus;
     42  RefPtr<MediaRawData> mSample;
     43 };
     44 
     45 typedef MozPromise<DecryptResult, DecryptResult, /* IsExclusive = */ true>
     46    DecryptPromise;
     47 
     48 class CDMKeyInfo {
     49 public:
     50  explicit CDMKeyInfo(const nsTArray<uint8_t>& aKeyId)
     51      : mKeyId(aKeyId.Clone()), mStatus() {}
     52 
     53  CDMKeyInfo(const nsTArray<uint8_t>& aKeyId,
     54             const dom::Optional<dom::MediaKeyStatus>& aStatus)
     55      : mKeyId(aKeyId.Clone()), mStatus(aStatus.Value()) {}
     56 
     57  // The copy-ctor and copy-assignment operator for Optional<T> are declared as
     58  // delete, so override CDMKeyInfo copy-ctor for nsTArray operations.
     59  CDMKeyInfo(const CDMKeyInfo& aKeyInfo) {
     60    mKeyId = aKeyInfo.mKeyId.Clone();
     61    if (aKeyInfo.mStatus.WasPassed()) {
     62      mStatus.Construct(aKeyInfo.mStatus.Value());
     63    }
     64  }
     65 
     66  CDMKeyInfo() = default;
     67 
     68  nsTArray<uint8_t> mKeyId;
     69  dom::Optional<dom::MediaKeyStatus> mStatus;
     70 };
     71 
     72 // Time is defined as the number of milliseconds since the
     73 // Epoch (00:00:00 UTC, January 1, 1970).
     74 typedef int64_t UnixTime;
     75 
     76 // Proxies calls CDM, and proxies calls back.
     77 // Note: Promises are passed in via a PromiseId, so that the ID can be
     78 // passed via IPC to the CDM, which can then signal when to reject or
     79 // resolve the promise using its PromiseId.
     80 class CDMProxy {
     81 protected:
     82  typedef dom::PromiseId PromiseId;
     83 
     84 public:
     85  NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
     86 
     87  // Main thread only.
     88  // Loads the CDM corresponding to mKeySystem.
     89  // Calls MediaKeys::OnCDMCreated() when the CDM is created.
     90  virtual void Init(PromiseId aPromiseId, const nsAString& aOrigin,
     91                    const nsAString& aTopLevelOrigin,
     92                    const nsAString& aName) = 0;
     93 
     94  // Main thread only.
     95  // Uses the CDM to create a key session.
     96  // Calls MediaKeys::OnSessionActivated() when session is created.
     97  // Assumes ownership of (std::move()s) aInitData's contents.
     98  virtual void CreateSession(uint32_t aCreateSessionToken,
     99                             dom::MediaKeySessionType aSessionType,
    100                             PromiseId aPromiseId,
    101                             const nsAString& aInitDataType,
    102                             nsTArray<uint8_t>& aInitData) = 0;
    103 
    104  // Main thread only.
    105  // Uses the CDM to load a presistent session stored on disk.
    106  // Calls MediaKeys::OnSessionActivated() when session is loaded.
    107  virtual void LoadSession(PromiseId aPromiseId,
    108                           dom::MediaKeySessionType aSessionType,
    109                           const nsAString& aSessionId) = 0;
    110 
    111  // Main thread only.
    112  // Sends a new certificate to the CDM.
    113  // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has
    114  // processed the request.
    115  // Assumes ownership of (std::move()s) aCert's contents.
    116  virtual void SetServerCertificate(PromiseId aPromiseId,
    117                                    nsTArray<uint8_t>& aCert) = 0;
    118 
    119  // Main thread only.
    120  // Sends an update to the CDM.
    121  // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has
    122  // processed the request.
    123  // Assumes ownership of (std::move()s) aResponse's contents.
    124  virtual void UpdateSession(const nsAString& aSessionId, PromiseId aPromiseId,
    125                             nsTArray<uint8_t>& aResponse) = 0;
    126 
    127  // Main thread only.
    128  // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has
    129  // processed the request.
    130  // If processing this operation results in the session actually closing,
    131  // we also call MediaKeySession::OnClosed(), which in turn calls
    132  // MediaKeys::OnSessionClosed().
    133  virtual void CloseSession(const nsAString& aSessionId,
    134                            PromiseId aPromiseId) = 0;
    135 
    136  // Main thread only.
    137  // Removes all data for a persisent session.
    138  // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has
    139  // processed the request.
    140  virtual void RemoveSession(const nsAString& aSessionId,
    141                             PromiseId aPromiseId) = 0;
    142 
    143  // Main thread only.
    144  // Called to signal a request for output protection information from the CDM.
    145  // This should forward the call up the stack where the query should be
    146  // performed and then responded to via `NotifyOutputProtectionStatus`.
    147  virtual void QueryOutputProtectionStatus() = 0;
    148 
    149  // NotifyOutputProtectionStatus enums. Explicit values are specified to make
    150  // it easy to match values in logs.
    151  enum class OutputProtectionCheckStatus : uint8_t {
    152    CheckFailed = 0,
    153    CheckSuccessful = 1,
    154  };
    155 
    156  enum class OutputProtectionCaptureStatus : uint8_t {
    157    CapturePossilbe = 0,
    158    CaptureNotPossible = 1,
    159    Unused = 2,
    160  };
    161  // End NotifyOutputProtectionStatus enums
    162 
    163  // Main thread only.
    164  // Notifies this proxy of the protection status for the media the CDM is
    165  // associated with. This can be called in response to
    166  // `QueryOutputProtectionStatus`, but can also be called without an
    167  // associated query. In both cases the information will be forwarded to
    168  // the CDM host machinery and used to handle requests from the CDM.
    169  // @param aCheckStatus did the check succeed or not.
    170  // @param aCaptureStatus if the check succeeded, this reflects if capture
    171  // of media could take place. This doesn't mean capture is taking place.
    172  // Callers should be conservative with this value such that it's okay to pass
    173  // CapturePossilbe even if capture is not happening, but should never pass
    174  // CaptureNotPossible if it could happen. If the check failed, this value is
    175  // not used, and callers should pass Unused to indicate this.
    176  virtual void NotifyOutputProtectionStatus(
    177      OutputProtectionCheckStatus aCheckStatus,
    178      OutputProtectionCaptureStatus aCaptureStatus) = 0;
    179 
    180  // Main thread only.
    181  virtual void Shutdown() = 0;
    182 
    183  // Main thread only.
    184  virtual void Terminated() = 0;
    185 
    186  // Threadsafe.
    187  const nsCString& GetNodeId() const { return mNodeId; };
    188 
    189  // Main thread only.
    190  virtual void OnSetSessionId(uint32_t aCreateSessionToken,
    191                              const nsAString& aSessionId) = 0;
    192 
    193  // Main thread only.
    194  virtual void OnResolveLoadSessionPromise(uint32_t aPromiseId,
    195                                           bool aSuccess) = 0;
    196 
    197  // Main thread only.
    198  virtual void OnSessionMessage(const nsAString& aSessionId,
    199                                dom::MediaKeyMessageType aMessageType,
    200                                const nsTArray<uint8_t>& aMessage) = 0;
    201 
    202  // Main thread only.
    203  virtual void OnExpirationChange(const nsAString& aSessionId,
    204                                  UnixTime aExpiryTime) = 0;
    205 
    206  // Main thread only.
    207  virtual void OnSessionClosed(const nsAString& aSessionId,
    208                               dom::MediaKeySessionClosedReason aReason) = 0;
    209 
    210  // Main thread only.
    211  virtual void OnSessionError(const nsAString& aSessionId, nsresult aException,
    212                              uint32_t aSystemCode, const nsAString& aMsg) = 0;
    213 
    214  // Main thread only.
    215  virtual void OnRejectPromise(uint32_t aPromiseId, ErrorResult&& aException,
    216                               const nsCString& aMsg) = 0;
    217 
    218  virtual RefPtr<DecryptPromise> Decrypt(MediaRawData* aSample) = 0;
    219 
    220  // Owner thread only.
    221  virtual void OnDecrypted(uint32_t aId, DecryptStatus aResult,
    222                           const nsTArray<uint8_t>& aDecryptedData) = 0;
    223 
    224  // Reject promise with the given ErrorResult.
    225  //
    226  // Can be called from any thread.
    227  virtual void RejectPromise(PromiseId aId, ErrorResult&& aException,
    228                             const nsCString& aReason) = 0;
    229 
    230  // Resolves promise with "undefined".
    231  // Can be called from any thread.
    232  virtual void ResolvePromise(PromiseId aId) = 0;
    233 
    234  // Threadsafe.
    235  const nsString& KeySystem() const { return mKeySystem; };
    236 
    237  DataMutex<CDMCaps>& Capabilites() { return mCapabilites; };
    238 
    239  // Main thread only.
    240  virtual void OnKeyStatusesChange(const nsAString& aSessionId) = 0;
    241 
    242  // Main thread only.
    243  // Calls MediaKeys->ResolvePromiseWithKeyStatus(aPromiseId, aKeyStatus) after
    244  // the CDM has processed the request.
    245  virtual void GetStatusForPolicy(PromiseId aPromiseId,
    246                                  const dom::HDCPVersion& aMinHdcpVersion) = 0;
    247 
    248 #ifdef DEBUG
    249  virtual bool IsOnOwnerThread() = 0;
    250 #endif
    251 
    252  virtual ChromiumCDMProxy* AsChromiumCDMProxy() { return nullptr; }
    253 
    254 #ifdef MOZ_WMF_CDM
    255  virtual WMFCDMProxy* AsWMFCDMProxy() { return nullptr; }
    256 #endif
    257 
    258  virtual RemoteCDMChild* AsRemoteCDMChild() { return nullptr; }
    259 
    260  virtual bool IsHardwareDecryptionSupported() const { return false; }
    261 
    262 protected:
    263  // Main thread only.
    264  CDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem,
    265           bool aDistinctiveIdentifierRequired, bool aPersistentStateRequired)
    266      : mKeys(aKeys),
    267        mKeySystem(aKeySystem),
    268        mCapabilites("CDMProxy::mCDMCaps"),
    269        mDistinctiveIdentifierRequired(aDistinctiveIdentifierRequired),
    270        mPersistentStateRequired(aPersistentStateRequired),
    271        mMainThread(GetMainThreadSerialEventTarget()) {
    272    MOZ_ASSERT(NS_IsMainThread());
    273  }
    274 
    275  virtual ~CDMProxy() {}
    276 
    277  // Helper to enforce that a raw pointer is only accessed on the main thread.
    278  template <class Type>
    279  class MainThreadOnlyRawPtr {
    280   public:
    281    explicit MainThreadOnlyRawPtr(Type* aPtr) : mPtr(aPtr) {
    282      MOZ_ASSERT(NS_IsMainThread());
    283    }
    284 
    285    bool IsNull() const {
    286      MOZ_ASSERT(NS_IsMainThread());
    287      return !mPtr;
    288    }
    289 
    290    void Clear() {
    291      MOZ_ASSERT(NS_IsMainThread());
    292      mPtr = nullptr;
    293    }
    294 
    295    Type* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
    296      MOZ_ASSERT(NS_IsMainThread());
    297      return mPtr;
    298    }
    299 
    300   private:
    301    Type* mPtr;
    302  };
    303 
    304  // Our reference back to the MediaKeys object.
    305  // WARNING: This is a non-owning reference that is cleared by MediaKeys
    306  // destructor. only use on main thread, and always nullcheck before using!
    307  MainThreadOnlyRawPtr<dom::MediaKeys> mKeys;
    308 
    309  const nsString mKeySystem;
    310 
    311  // Onwer specified thread. e.g. Gecko Media Plugin thread.
    312  // All interactions with the out-of-process EME plugin must come from this
    313  // thread.
    314  RefPtr<nsIThread> mOwnerThread;
    315 
    316  nsCString mNodeId;
    317 
    318  DataMutex<CDMCaps> mCapabilites;
    319 
    320  const bool mDistinctiveIdentifierRequired;
    321  const bool mPersistentStateRequired;
    322 
    323  // The main thread associated with the root document.
    324  const nsCOMPtr<nsISerialEventTarget> mMainThread;
    325 };
    326 
    327 }  // namespace mozilla
    328 
    329 #endif  // CDMProxy_h_