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 
102   // Main thread only.
103   // Uses the CDM to create a key session.
104   // Calls MediaKeys::OnSessionActivated() when session is created.
105   // Assumes ownership of (std::move()s) aInitData's contents.
106   virtual void CreateSession(uint32_t aCreateSessionToken,
107                              MediaKeySessionType aSessionType,
108                              PromiseId aPromiseId,
109                              const nsAString& aInitDataType,
110                              nsTArray<uint8_t>& aInitData) = 0;
111 
112   // Main thread only.
113   // Uses the CDM to load a presistent session stored on disk.
114   // Calls MediaKeys::OnSessionActivated() when session is loaded.
115   virtual void LoadSession(PromiseId aPromiseId,
116                            dom::MediaKeySessionType aSessionType,
117                            const nsAString& aSessionId) = 0;
118 
119   // Main thread only.
120   // Sends a new certificate to the CDM.
121   // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has
122   // processed the request.
123   // Assumes ownership of (std::move()s) aCert's contents.
124   virtual void SetServerCertificate(PromiseId aPromiseId,
125                                     nsTArray<uint8_t>& aCert) = 0;
126 
127   // Main thread only.
128   // Sends an update to the CDM.
129   // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has
130   // processed the request.
131   // Assumes ownership of (std::move()s) aResponse's contents.
132   virtual void UpdateSession(const nsAString& aSessionId, PromiseId aPromiseId,
133                              nsTArray<uint8_t>& aResponse) = 0;
134 
135   // Main thread only.
136   // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has
137   // processed the request.
138   // If processing this operation results in the session actually closing,
139   // we also call MediaKeySession::OnClosed(), which in turn calls
140   // MediaKeys::OnSessionClosed().
141   virtual void CloseSession(const nsAString& aSessionId,
142                             PromiseId aPromiseId) = 0;
143 
144   // Main thread only.
145   // Removes all data for a persisent session.
146   // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has
147   // processed the request.
148   virtual void RemoveSession(const nsAString& aSessionId,
149                              PromiseId aPromiseId) = 0;
150 
151   // Main thread only.
152   // Called to signal a request for output protection information from the CDM.
153   // This should forward the call up the stack where the query should be
154   // performed and then responded to via `NotifyOutputProtectionStatus`.
155   virtual void QueryOutputProtectionStatus() = 0;
156 
157   // NotifyOutputProtectionStatus enums. Explicit values are specified to make
158   // it easy to match values in logs.
159   enum class OutputProtectionCheckStatus : uint8_t {
160     CheckFailed = 0,
161     CheckSuccessful = 1,
162   };
163 
164   enum class OutputProtectionCaptureStatus : uint8_t {
165     CapturePossilbe = 0,
166     CaptureNotPossible = 1,
167     Unused = 2,
168   };
169   // End NotifyOutputProtectionStatus enums
170 
171   // Main thread only.
172   // Notifies this proxy of the protection status for the media the CDM is
173   // associated with. This can be called in response to
174   // `QueryOutputProtectionStatus`, but can also be called without an
175   // associated query. In both cases the information will be forwarded to
176   // the CDM host machinery and used to handle requests from the CDM.
177   // @param aCheckStatus did the check succeed or not.
178   // @param aCaptureStatus if the check succeeded, this reflects if capture
179   // of media could take place. This doesn't mean capture is taking place.
180   // Callers should be conservative with this value such that it's okay to pass
181   // CapturePossilbe even if capture is not happening, but should never pass
182   // CaptureNotPossible if it could happen. If the check failed, this value is
183   // not used, and callers should pass Unused to indicate this.
184   virtual void NotifyOutputProtectionStatus(
185       OutputProtectionCheckStatus aCheckStatus,
186       OutputProtectionCaptureStatus aCaptureStatus) = 0;
187 
188   // Main thread only.
189   virtual void Shutdown() = 0;
190 
191   // Main thread only.
192   virtual void Terminated() = 0;
193 
194   // Threadsafe.
195   virtual const nsCString& GetNodeId() const = 0;
196 
197   // Main thread only.
198   virtual void OnSetSessionId(uint32_t aCreateSessionToken,
199                               const nsAString& aSessionId) = 0;
200 
201   // Main thread only.
202   virtual void OnResolveLoadSessionPromise(uint32_t aPromiseId,
203                                            bool aSuccess) = 0;
204 
205   // Main thread only.
206   virtual void OnSessionMessage(const nsAString& aSessionId,
207                                 dom::MediaKeyMessageType aMessageType,
208                                 const nsTArray<uint8_t>& aMessage) = 0;
209 
210   // Main thread only.
211   virtual void OnExpirationChange(const nsAString& aSessionId,
212                                   UnixTime aExpiryTime) = 0;
213 
214   // Main thread only.
215   virtual void OnSessionClosed(const nsAString& aSessionId) = 0;
216 
217   // Main thread only.
218   virtual void OnSessionError(const nsAString& aSessionId, nsresult aException,
219                               uint32_t aSystemCode, const nsAString& aMsg) = 0;
220 
221   // Main thread only.
222   virtual void OnRejectPromise(uint32_t aPromiseId, ErrorResult&& aException,
223                                const nsCString& aMsg) = 0;
224 
225   virtual RefPtr<DecryptPromise> Decrypt(MediaRawData* aSample) = 0;
226 
227   // Owner thread only.
228   virtual void OnDecrypted(uint32_t aId, DecryptStatus aResult,
229                            const nsTArray<uint8_t>& aDecryptedData) = 0;
230 
231   // Reject promise with the given ErrorResult.
232   //
233   // Can be called from any thread.
234   virtual void RejectPromise(PromiseId aId, ErrorResult&& aException,
235                              const nsCString& aReason) = 0;
236 
237   // Resolves promise with "undefined".
238   // Can be called from any thread.
239   virtual void ResolvePromise(PromiseId aId) = 0;
240 
241   // Threadsafe.
242   virtual const nsString& KeySystem() const = 0;
243 
244   virtual DataMutex<CDMCaps>& Capabilites() = 0;
245 
246   // Main thread only.
247   virtual void OnKeyStatusesChange(const nsAString& aSessionId) = 0;
248 
249   // Main thread only.
250   // Calls MediaKeys->ResolvePromiseWithKeyStatus(aPromiseId, aKeyStatus) after
251   // the CDM has processed the request.
252   virtual void GetStatusForPolicy(PromiseId aPromiseId,
253                                   const nsAString& aMinHdcpVersion) = 0;
254 
255 #ifdef DEBUG
256   virtual bool IsOnOwnerThread() = 0;
257 #endif
258 
AsChromiumCDMProxy()259   virtual ChromiumCDMProxy* AsChromiumCDMProxy() { return nullptr; }
260 
261  protected:
~CDMProxy()262   virtual ~CDMProxy() {}
263 
264   // Helper to enforce that a raw pointer is only accessed on the main thread.
265   template <class Type>
266   class MainThreadOnlyRawPtr {
267    public:
MainThreadOnlyRawPtr(Type * aPtr)268     explicit MainThreadOnlyRawPtr(Type* aPtr) : mPtr(aPtr) {
269       MOZ_ASSERT(NS_IsMainThread());
270     }
271 
IsNull()272     bool IsNull() const {
273       MOZ_ASSERT(NS_IsMainThread());
274       return !mPtr;
275     }
276 
Clear()277     void Clear() {
278       MOZ_ASSERT(NS_IsMainThread());
279       mPtr = nullptr;
280     }
281 
282     Type* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
283       MOZ_ASSERT(NS_IsMainThread());
284       return mPtr;
285     }
286 
287    private:
288     Type* mPtr;
289   };
290 
291   // Our reference back to the MediaKeys object.
292   // WARNING: This is a non-owning reference that is cleared by MediaKeys
293   // destructor. only use on main thread, and always nullcheck before using!
294   MainThreadOnlyRawPtr<dom::MediaKeys> mKeys;
295 
296   const nsString mKeySystem;
297 
298   // Onwer specified thread. e.g. Gecko Media Plugin thread.
299   // All interactions with the out-of-process EME plugin must come from this
300   // thread.
301   RefPtr<nsIThread> mOwnerThread;
302 
303   nsCString mNodeId;
304 
305   DataMutex<CDMCaps> mCapabilites;
306 
307   const bool mDistinctiveIdentifierRequired;
308   const bool mPersistentStateRequired;
309 
310   // The main thread associated with the root document.
311   const nsCOMPtr<nsISerialEventTarget> mMainThread;
312 };
313 
314 }  // namespace mozilla
315 
316 #endif  // CDMProxy_h_
317