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