Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "GMPDecryptorChild.h"
7 : #include "GMPContentChild.h"
8 : #include "GMPChild.h"
9 : #include "base/task.h"
10 : #include "mozilla/TimeStamp.h"
11 : #include "mozilla/Unused.h"
12 : #include "runnable_utils.h"
13 : #include <ctime>
14 :
15 : #define ON_GMP_THREAD() (mPlugin->GMPMessageLoop() == MessageLoop::current())
16 :
17 : #define CALL_ON_GMP_THREAD(_func, ...) \
18 : CallOnGMPThread(&GMPDecryptorChild::_func, __VA_ARGS__)
19 :
20 : namespace mozilla {
21 : namespace gmp {
22 :
23 : static uint32_t sDecryptorCount = 1;
24 :
25 0 : GMPDecryptorChild::GMPDecryptorChild(GMPContentChild* aPlugin)
26 : : mSession(nullptr)
27 : , mPlugin(aPlugin)
28 0 : , mDecryptorId(sDecryptorCount++)
29 : {
30 0 : MOZ_ASSERT(mPlugin);
31 0 : }
32 :
33 0 : GMPDecryptorChild::~GMPDecryptorChild()
34 : {
35 0 : }
36 :
37 : template <typename MethodType, typename... ParamType>
38 : void
39 0 : GMPDecryptorChild::CallMethod(MethodType aMethod, ParamType&&... aParams)
40 : {
41 0 : MOZ_ASSERT(ON_GMP_THREAD());
42 : // Don't send IPC messages after tear-down.
43 0 : if (mSession) {
44 0 : (this->*aMethod)(Forward<ParamType>(aParams)...);
45 : }
46 0 : }
47 :
48 : template<typename T>
49 : struct AddConstReference {
50 : typedef const typename RemoveReference<T>::Type& Type;
51 : };
52 :
53 : template<typename MethodType, typename... ParamType>
54 : void
55 0 : GMPDecryptorChild::CallOnGMPThread(MethodType aMethod, ParamType&&... aParams)
56 : {
57 0 : if (ON_GMP_THREAD()) {
58 : // Use forwarding reference when we can.
59 0 : CallMethod(aMethod, Forward<ParamType>(aParams)...);
60 : } else {
61 : // Use const reference when we have to.
62 0 : auto m = &GMPDecryptorChild::CallMethod<
63 : decltype(aMethod), typename AddConstReference<ParamType>::Type...>;
64 : RefPtr<mozilla::Runnable> t =
65 0 : dont_add_new_uses_of_this::NewRunnableMethod(this, m, aMethod, Forward<ParamType>(aParams)...);
66 0 : mPlugin->GMPMessageLoop()->PostTask(t.forget());
67 : }
68 0 : }
69 :
70 : void
71 0 : GMPDecryptorChild::Init(GMPDecryptor* aSession)
72 : {
73 0 : MOZ_ASSERT(aSession);
74 0 : mSession = aSession;
75 : // The ID of this decryptor is the IPDL actor ID. Note it's unique inside
76 : // the child process, but not necessarily across all gecko processes. However,
77 : // since GMPDecryptors are segregated by node ID/origin, we shouldn't end up
78 : // with clashes in the content process.
79 0 : SendSetDecryptorId(DecryptorId());
80 0 : }
81 :
82 : void
83 0 : GMPDecryptorChild::SetSessionId(uint32_t aCreateSessionToken,
84 : const char* aSessionId,
85 : uint32_t aSessionIdLength)
86 : {
87 0 : CALL_ON_GMP_THREAD(SendSetSessionId,
88 0 : aCreateSessionToken, nsCString(aSessionId, aSessionIdLength));
89 0 : }
90 :
91 : void
92 0 : GMPDecryptorChild::ResolveLoadSessionPromise(uint32_t aPromiseId,
93 : bool aSuccess)
94 : {
95 0 : CALL_ON_GMP_THREAD(SendResolveLoadSessionPromise, aPromiseId, aSuccess);
96 0 : }
97 :
98 : void
99 0 : GMPDecryptorChild::ResolvePromise(uint32_t aPromiseId)
100 : {
101 0 : CALL_ON_GMP_THREAD(SendResolvePromise, aPromiseId);
102 0 : }
103 :
104 : void
105 0 : GMPDecryptorChild::RejectPromise(uint32_t aPromiseId,
106 : GMPDOMException aException,
107 : const char* aMessage,
108 : uint32_t aMessageLength)
109 : {
110 0 : CALL_ON_GMP_THREAD(SendRejectPromise,
111 0 : aPromiseId, aException, nsCString(aMessage, aMessageLength));
112 0 : }
113 :
114 : void
115 0 : GMPDecryptorChild::SessionMessage(const char* aSessionId,
116 : uint32_t aSessionIdLength,
117 : GMPSessionMessageType aMessageType,
118 : const uint8_t* aMessage,
119 : uint32_t aMessageLength)
120 : {
121 0 : nsTArray<uint8_t> msg;
122 0 : msg.AppendElements(aMessage, aMessageLength);
123 0 : CALL_ON_GMP_THREAD(SendSessionMessage,
124 : nsCString(aSessionId, aSessionIdLength),
125 0 : aMessageType, Move(msg));
126 0 : }
127 :
128 : void
129 0 : GMPDecryptorChild::ExpirationChange(const char* aSessionId,
130 : uint32_t aSessionIdLength,
131 : GMPTimestamp aExpiryTime)
132 : {
133 0 : CALL_ON_GMP_THREAD(SendExpirationChange,
134 0 : nsCString(aSessionId, aSessionIdLength), aExpiryTime);
135 0 : }
136 :
137 : void
138 0 : GMPDecryptorChild::SessionClosed(const char* aSessionId,
139 : uint32_t aSessionIdLength)
140 : {
141 0 : CALL_ON_GMP_THREAD(SendSessionClosed,
142 0 : nsCString(aSessionId, aSessionIdLength));
143 0 : }
144 :
145 : void
146 0 : GMPDecryptorChild::SessionError(const char* aSessionId,
147 : uint32_t aSessionIdLength,
148 : GMPDOMException aException,
149 : uint32_t aSystemCode,
150 : const char* aMessage,
151 : uint32_t aMessageLength)
152 : {
153 0 : CALL_ON_GMP_THREAD(SendSessionError,
154 : nsCString(aSessionId, aSessionIdLength),
155 : aException, aSystemCode,
156 0 : nsCString(aMessage, aMessageLength));
157 0 : }
158 :
159 : void
160 0 : GMPDecryptorChild::KeyStatusChanged(const char* aSessionId,
161 : uint32_t aSessionIdLength,
162 : const uint8_t* aKeyId,
163 : uint32_t aKeyIdLength,
164 : GMPMediaKeyStatus aStatus)
165 : {
166 0 : AutoTArray<uint8_t, 16> kid;
167 0 : kid.AppendElements(aKeyId, aKeyIdLength);
168 :
169 0 : nsTArray<GMPKeyInformation> keyInfos;
170 0 : keyInfos.AppendElement(GMPKeyInformation(kid, aStatus));
171 0 : CALL_ON_GMP_THREAD(SendBatchedKeyStatusChanged,
172 : nsCString(aSessionId, aSessionIdLength),
173 0 : keyInfos);
174 0 : }
175 :
176 : void
177 0 : GMPDecryptorChild::BatchedKeyStatusChanged(const char* aSessionId,
178 : uint32_t aSessionIdLength,
179 : const GMPMediaKeyInfo* aKeyInfos,
180 : uint32_t aKeyInfosLength)
181 : {
182 0 : nsTArray<GMPKeyInformation> keyInfos;
183 0 : for (uint32_t i = 0; i < aKeyInfosLength; i++) {
184 0 : nsTArray<uint8_t> keyId;
185 0 : keyId.AppendElements(aKeyInfos[i].keyid, aKeyInfos[i].keyid_size);
186 0 : keyInfos.AppendElement(GMPKeyInformation(keyId, aKeyInfos[i].status));
187 : }
188 0 : CALL_ON_GMP_THREAD(SendBatchedKeyStatusChanged,
189 : nsCString(aSessionId, aSessionIdLength),
190 0 : keyInfos);
191 0 : }
192 :
193 : void
194 0 : GMPDecryptorChild::Decrypted(GMPBuffer* aBuffer, GMPErr aResult)
195 : {
196 0 : if (!ON_GMP_THREAD()) {
197 : // We should run this whole method on the GMP thread since the buffer needs
198 : // to be deleted after the SendDecrypted call.
199 0 : mPlugin->GMPMessageLoop()->PostTask(
200 0 : NewRunnableMethod<GMPBuffer*, GMPErr>("gmp::GMPDecryptorChild::Decrypted",
201 : this,
202 : &GMPDecryptorChild::Decrypted,
203 : aBuffer,
204 0 : aResult));
205 0 : return;
206 : }
207 :
208 0 : if (!aBuffer) {
209 0 : NS_WARNING("GMPDecryptorCallback passed bull GMPBuffer");
210 0 : return;
211 : }
212 :
213 0 : auto buffer = static_cast<GMPBufferImpl*>(aBuffer);
214 0 : if (mSession) {
215 0 : SendDecrypted(buffer->mId, aResult, buffer->mData);
216 : }
217 0 : delete buffer;
218 : }
219 :
220 : void
221 0 : GMPDecryptorChild::SetCapabilities(uint64_t aCaps)
222 : {
223 : // Deprecated.
224 0 : }
225 :
226 : mozilla::ipc::IPCResult
227 0 : GMPDecryptorChild::RecvInit(const bool& aDistinctiveIdentifierRequired,
228 : const bool& aPersistentStateRequired)
229 : {
230 0 : if (!mSession) {
231 0 : return IPC_FAIL_NO_REASON(this);
232 : }
233 0 : mSession->Init(this, aDistinctiveIdentifierRequired, aPersistentStateRequired);
234 0 : return IPC_OK();
235 : }
236 :
237 : mozilla::ipc::IPCResult
238 0 : GMPDecryptorChild::RecvCreateSession(const uint32_t& aCreateSessionToken,
239 : const uint32_t& aPromiseId,
240 : const nsCString& aInitDataType,
241 : InfallibleTArray<uint8_t>&& aInitData,
242 : const GMPSessionType& aSessionType)
243 : {
244 0 : if (!mSession) {
245 0 : return IPC_FAIL_NO_REASON(this);
246 : }
247 :
248 0 : mSession->CreateSession(aCreateSessionToken,
249 : aPromiseId,
250 : aInitDataType.get(),
251 : aInitDataType.Length(),
252 0 : aInitData.Elements(),
253 0 : aInitData.Length(),
254 0 : aSessionType);
255 :
256 0 : return IPC_OK();
257 : }
258 :
259 : mozilla::ipc::IPCResult
260 0 : GMPDecryptorChild::RecvLoadSession(const uint32_t& aPromiseId,
261 : const nsCString& aSessionId)
262 : {
263 0 : if (!mSession) {
264 0 : return IPC_FAIL_NO_REASON(this);
265 : }
266 :
267 0 : mSession->LoadSession(aPromiseId,
268 : aSessionId.get(),
269 0 : aSessionId.Length());
270 :
271 0 : return IPC_OK();
272 : }
273 :
274 : mozilla::ipc::IPCResult
275 0 : GMPDecryptorChild::RecvUpdateSession(const uint32_t& aPromiseId,
276 : const nsCString& aSessionId,
277 : InfallibleTArray<uint8_t>&& aResponse)
278 : {
279 0 : if (!mSession) {
280 0 : return IPC_FAIL_NO_REASON(this);
281 : }
282 :
283 0 : mSession->UpdateSession(aPromiseId,
284 : aSessionId.get(),
285 : aSessionId.Length(),
286 0 : aResponse.Elements(),
287 0 : aResponse.Length());
288 :
289 0 : return IPC_OK();
290 : }
291 :
292 : mozilla::ipc::IPCResult
293 0 : GMPDecryptorChild::RecvCloseSession(const uint32_t& aPromiseId,
294 : const nsCString& aSessionId)
295 : {
296 0 : if (!mSession) {
297 0 : return IPC_FAIL_NO_REASON(this);
298 : }
299 :
300 0 : mSession->CloseSession(aPromiseId,
301 : aSessionId.get(),
302 0 : aSessionId.Length());
303 :
304 0 : return IPC_OK();
305 : }
306 :
307 : mozilla::ipc::IPCResult
308 0 : GMPDecryptorChild::RecvRemoveSession(const uint32_t& aPromiseId,
309 : const nsCString& aSessionId)
310 : {
311 0 : if (!mSession) {
312 0 : return IPC_FAIL_NO_REASON(this);
313 : }
314 :
315 0 : mSession->RemoveSession(aPromiseId,
316 : aSessionId.get(),
317 0 : aSessionId.Length());
318 :
319 0 : return IPC_OK();
320 : }
321 :
322 : mozilla::ipc::IPCResult
323 0 : GMPDecryptorChild::RecvSetServerCertificate(const uint32_t& aPromiseId,
324 : InfallibleTArray<uint8_t>&& aServerCert)
325 : {
326 0 : if (!mSession) {
327 0 : return IPC_FAIL_NO_REASON(this);
328 : }
329 :
330 0 : mSession->SetServerCertificate(aPromiseId,
331 0 : aServerCert.Elements(),
332 0 : aServerCert.Length());
333 :
334 0 : return IPC_OK();
335 : }
336 :
337 : mozilla::ipc::IPCResult
338 0 : GMPDecryptorChild::RecvDecrypt(const uint32_t& aId,
339 : InfallibleTArray<uint8_t>&& aBuffer,
340 : const GMPDecryptionData& aMetadata)
341 : {
342 0 : if (!mSession) {
343 0 : return IPC_FAIL_NO_REASON(this);
344 : }
345 :
346 : // Note: the GMPBufferImpl created here is deleted when the GMP passes
347 : // it back in the Decrypted() callback above.
348 0 : GMPBufferImpl* buffer = new GMPBufferImpl(aId, aBuffer);
349 :
350 : // |metadata| lifetime is managed by |buffer|.
351 0 : GMPEncryptedBufferDataImpl* metadata = new GMPEncryptedBufferDataImpl(aMetadata);
352 0 : buffer->SetMetadata(metadata);
353 :
354 0 : mSession->Decrypt(buffer, metadata);
355 0 : return IPC_OK();
356 : }
357 :
358 : mozilla::ipc::IPCResult
359 0 : GMPDecryptorChild::RecvDecryptingComplete()
360 : {
361 : // Reset |mSession| before calling DecryptingComplete(). We should not send
362 : // any IPC messages during tear-down.
363 0 : auto session = mSession;
364 0 : mSession = nullptr;
365 :
366 0 : if (!session) {
367 0 : return IPC_FAIL_NO_REASON(this);
368 : }
369 :
370 0 : session->DecryptingComplete();
371 :
372 0 : Unused << Send__delete__(this);
373 :
374 0 : return IPC_OK();
375 : }
376 :
377 : } // namespace gmp
378 : } // namespace mozilla
379 :
380 : // avoid redefined macro in unified build
381 : #undef ON_GMP_THREAD
382 : #undef CALL_ON_GMP_THREAD
|