Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/gmp/GMPServiceChild.cpp
Line
Count
Source (jump to first uncovered line)
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 "GMPServiceChild.h"
7
#include "mozilla/dom/ContentChild.h"
8
#include "mozilla/ClearOnShutdown.h"
9
#include "mozilla/StaticPtr.h"
10
#include "mozIGeckoMediaPluginService.h"
11
#include "mozIGeckoMediaPluginChromeService.h"
12
#include "nsCOMPtr.h"
13
#include "GMPParent.h"
14
#include "GMPContentParent.h"
15
#include "nsXPCOMPrivate.h"
16
#include "mozilla/SyncRunnable.h"
17
#include "mozilla/StaticMutex.h"
18
#include "runnable_utils.h"
19
#include "base/task.h"
20
#include "nsIObserverService.h"
21
#include "nsComponentManagerUtils.h"
22
#include "mozilla/SystemGroup.h"
23
24
namespace mozilla {
25
26
#ifdef LOG
27
#undef LOG
28
#endif
29
30
0
#define LOGD(msg) MOZ_LOG(GetGMPLog(), mozilla::LogLevel::Debug, msg)
31
#define LOG(level, msg) MOZ_LOG(GetGMPLog(), (level), msg)
32
33
#ifdef __CLASS__
34
#undef __CLASS__
35
#endif
36
#define __CLASS__ "GMPService"
37
38
namespace gmp {
39
40
already_AddRefed<GeckoMediaPluginServiceChild>
41
GeckoMediaPluginServiceChild::GetSingleton()
42
0
{
43
0
  MOZ_ASSERT(!XRE_IsParentProcess());
44
0
  RefPtr<GeckoMediaPluginService> service(
45
0
    GeckoMediaPluginService::GetGeckoMediaPluginService());
46
#ifdef DEBUG
47
  if (service) {
48
    nsCOMPtr<mozIGeckoMediaPluginChromeService> chromeService;
49
    CallQueryInterface(service.get(), getter_AddRefs(chromeService));
50
    MOZ_ASSERT(!chromeService);
51
  }
52
#endif
53
  return service.forget().downcast<GeckoMediaPluginServiceChild>();
54
0
}
55
56
RefPtr<GetGMPContentParentPromise>
57
GeckoMediaPluginServiceChild::GetContentParent(GMPCrashHelper* aHelper,
58
                                               const nsACString& aNodeIdString,
59
                                               const nsCString& aAPI,
60
                                               const nsTArray<nsCString>& aTags)
61
0
{
62
0
  MOZ_ASSERT(mGMPThread->EventTarget()->IsOnCurrentThread());
63
0
64
0
  MozPromiseHolder<GetGMPContentParentPromise>* rawHolder = new MozPromiseHolder<GetGMPContentParentPromise>();
65
0
  RefPtr<GetGMPContentParentPromise> promise = rawHolder->Ensure(__func__);
66
0
  RefPtr<AbstractThread> thread(GetAbstractGMPThread());
67
0
68
0
  nsCString nodeIdString(aNodeIdString);
69
0
  nsCString api(aAPI);
70
0
  nsTArray<nsCString> tags(aTags);
71
0
  RefPtr<GMPCrashHelper> helper(aHelper);
72
0
  RefPtr<GeckoMediaPluginServiceChild> self(this);
73
0
  GetServiceChild()->Then(
74
0
    thread,
75
0
    __func__,
76
0
    [self, nodeIdString, api, tags, helper, rawHolder](GMPServiceChild* child) {
77
0
      UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>> holder(rawHolder);
78
0
      nsresult rv;
79
0
80
0
      nsTArray<base::ProcessId> alreadyBridgedTo;
81
0
      child->GetAlreadyBridgedTo(alreadyBridgedTo);
82
0
83
0
      base::ProcessId otherProcess;
84
0
      nsCString displayName;
85
0
      uint32_t pluginId = 0;
86
0
      ipc::Endpoint<PGMPContentParent> endpoint;
87
0
      nsCString errorDescription = NS_LITERAL_CSTRING("");
88
0
89
0
      bool ok = child->SendLaunchGMP(nodeIdString,
90
0
                                     api,
91
0
                                     tags,
92
0
                                     alreadyBridgedTo,
93
0
                                     &pluginId,
94
0
                                     &otherProcess,
95
0
                                     &displayName,
96
0
                                     &endpoint,
97
0
                                     &rv,
98
0
                                     &errorDescription);
99
0
      if (helper && pluginId) {
100
0
        // Note: Even if the launch failed, we need to connect the crash
101
0
        // helper so that if the launch failed due to the plugin crashing,
102
0
        // we can report the crash via the crash reporter. The crash
103
0
        // handling notification will arrive shortly if the launch failed
104
0
        // due to the plugin crashing.
105
0
        self->ConnectCrashHelper(pluginId, helper);
106
0
      }
107
0
108
0
      if (!ok || NS_FAILED(rv)) {
109
0
        MediaResult error(
110
0
          rv,
111
0
          nsPrintfCString("GeckoMediaPluginServiceChild::GetContentParent "
112
0
                          "SendLaunchGMPForNodeId failed with description (%s)",
113
0
                          errorDescription.get()));
114
0
115
0
        LOGD(("%s", error.Description().get()));
116
0
        holder->Reject(error, __func__);
117
0
        return;
118
0
      }
119
0
120
0
      RefPtr<GMPContentParent> parent =
121
0
        child->GetBridgedGMPContentParent(otherProcess, std::move(endpoint));
122
0
      if (!alreadyBridgedTo.Contains(otherProcess)) {
123
0
        parent->SetDisplayName(displayName);
124
0
        parent->SetPluginId(pluginId);
125
0
      }
126
0
      RefPtr<GMPContentParent::CloseBlocker> blocker(
127
0
        new GMPContentParent::CloseBlocker(parent));
128
0
      holder->Resolve(blocker, __func__);
129
0
    },
130
0
    [rawHolder](MediaResult result) {
131
0
      UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>> holder(rawHolder);
132
0
      holder->Reject(result, __func__);
133
0
    });
134
0
135
0
  return promise;
136
0
}
137
138
RefPtr<GetGMPContentParentPromise>
139
GeckoMediaPluginServiceChild::GetContentParent(GMPCrashHelper* aHelper,
140
                                               const NodeId& aNodeId,
141
                                               const nsCString& aAPI,
142
                                               const nsTArray<nsCString>& aTags)
143
0
{
144
0
  MOZ_ASSERT(mGMPThread->EventTarget()->IsOnCurrentThread());
145
0
146
0
  MozPromiseHolder<GetGMPContentParentPromise>* rawHolder =
147
0
    new MozPromiseHolder<GetGMPContentParentPromise>();
148
0
  RefPtr<GetGMPContentParentPromise> promise = rawHolder->Ensure(__func__);
149
0
  RefPtr<AbstractThread> thread(GetAbstractGMPThread());
150
0
151
0
  NodeIdData nodeId(aNodeId.mOrigin, aNodeId.mTopLevelOrigin, aNodeId.mGMPName);
152
0
  nsCString api(aAPI);
153
0
  nsTArray<nsCString> tags(aTags);
154
0
  RefPtr<GMPCrashHelper> helper(aHelper);
155
0
  RefPtr<GeckoMediaPluginServiceChild> self(this);
156
0
  GetServiceChild()->Then(
157
0
    thread,
158
0
    __func__,
159
0
    [self, nodeId, api, tags, helper, rawHolder](GMPServiceChild* child) {
160
0
      UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>> holder(rawHolder);
161
0
      nsresult rv;
162
0
163
0
      nsTArray<base::ProcessId> alreadyBridgedTo;
164
0
      child->GetAlreadyBridgedTo(alreadyBridgedTo);
165
0
166
0
      base::ProcessId otherProcess;
167
0
      nsCString displayName;
168
0
      uint32_t pluginId = 0;
169
0
      ipc::Endpoint<PGMPContentParent> endpoint;
170
0
      nsCString errorDescription = NS_LITERAL_CSTRING("");
171
0
172
0
      bool ok = child->SendLaunchGMPForNodeId(nodeId,
173
0
                                              api,
174
0
                                              tags,
175
0
                                              alreadyBridgedTo,
176
0
                                              &pluginId,
177
0
                                              &otherProcess,
178
0
                                              &displayName,
179
0
                                              &endpoint,
180
0
                                              &rv,
181
0
                                              &errorDescription);
182
0
183
0
      if (helper && pluginId) {
184
0
        // Note: Even if the launch failed, we need to connect the crash
185
0
        // helper so that if the launch failed due to the plugin crashing,
186
0
        // we can report the crash via the crash reporter. The crash
187
0
        // handling notification will arrive shortly if the launch failed
188
0
        // due to the plugin crashing.
189
0
        self->ConnectCrashHelper(pluginId, helper);
190
0
      }
191
0
192
0
      if (!ok || NS_FAILED(rv)) {
193
0
        MediaResult error(
194
0
          rv,
195
0
          nsPrintfCString("GeckoMediaPluginServiceChild::GetContentParent "
196
0
                          "SendLaunchGMPForNodeId failed with description (%s)",
197
0
                          errorDescription.get()));
198
0
199
0
        LOGD(("%s", error.Description().get()));
200
0
        holder->Reject(error, __func__);
201
0
        return;
202
0
      }
203
0
204
0
      RefPtr<GMPContentParent> parent = child->GetBridgedGMPContentParent(otherProcess,
205
0
                                                                          std::move(endpoint));
206
0
      if (!alreadyBridgedTo.Contains(otherProcess)) {
207
0
        parent->SetDisplayName(displayName);
208
0
        parent->SetPluginId(pluginId);
209
0
      }
210
0
211
0
      RefPtr<GMPContentParent::CloseBlocker> blocker(new GMPContentParent::CloseBlocker(parent));
212
0
      holder->Resolve(blocker, __func__);
213
0
    },
214
0
    [rawHolder](MediaResult result) {
215
0
      UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>> holder(rawHolder);
216
0
      holder->Reject(result, __func__);
217
0
    });
218
0
219
0
  return promise;
220
0
}
221
222
typedef mozilla::dom::GMPCapabilityData GMPCapabilityData;
223
typedef mozilla::dom::GMPAPITags GMPAPITags;
224
225
struct GMPCapabilityAndVersion
226
{
227
  explicit GMPCapabilityAndVersion(const GMPCapabilityData& aCapabilities)
228
    : mName(aCapabilities.name())
229
    , mVersion(aCapabilities.version())
230
0
  {
231
0
    for (const GMPAPITags& tags : aCapabilities.capabilities()) {
232
0
      GMPCapability cap;
233
0
      cap.mAPIName = tags.api();
234
0
      for (const nsCString& tag : tags.tags()) {
235
0
        cap.mAPITags.AppendElement(tag);
236
0
      }
237
0
      mCapabilities.AppendElement(std::move(cap));
238
0
    }
239
0
  }
240
241
  nsCString ToString() const
242
0
  {
243
0
    nsCString s;
244
0
    s.Append(mName);
245
0
    s.AppendLiteral(" version=");
246
0
    s.Append(mVersion);
247
0
    s.AppendLiteral(" tags=[");
248
0
    nsCString tags;
249
0
    for (const GMPCapability& cap : mCapabilities) {
250
0
      if (!tags.IsEmpty()) {
251
0
        tags.AppendLiteral(" ");
252
0
      }
253
0
      tags.Append(cap.mAPIName);
254
0
      for (const nsCString& tag : cap.mAPITags) {
255
0
        tags.AppendLiteral(":");
256
0
        tags.Append(tag);
257
0
      }
258
0
    }
259
0
    s.Append(tags);
260
0
    s.AppendLiteral("]");
261
0
    return s;
262
0
  }
263
264
  nsCString mName;
265
  nsCString mVersion;
266
  nsTArray<GMPCapability> mCapabilities;
267
};
268
269
StaticMutex sGMPCapabilitiesMutex;
270
StaticAutoPtr<nsTArray<GMPCapabilityAndVersion>> sGMPCapabilities;
271
272
static nsCString
273
GMPCapabilitiesToString()
274
0
{
275
0
  nsCString s;
276
0
  for (const GMPCapabilityAndVersion& gmp : *sGMPCapabilities) {
277
0
    if (!s.IsEmpty()) {
278
0
      s.AppendLiteral(", ");
279
0
    }
280
0
    s.Append(gmp.ToString());
281
0
  }
282
0
  return s;
283
0
}
284
285
/* static */
286
void
287
GeckoMediaPluginServiceChild::UpdateGMPCapabilities(nsTArray<GMPCapabilityData>&& aCapabilities)
288
0
{
289
0
  {
290
0
    // The mutex should unlock before sending the "gmp-changed" observer service notification.
291
0
    StaticMutexAutoLock lock(sGMPCapabilitiesMutex);
292
0
    if (!sGMPCapabilities) {
293
0
      sGMPCapabilities = new nsTArray<GMPCapabilityAndVersion>();
294
0
      ClearOnShutdown(&sGMPCapabilities);
295
0
    }
296
0
    sGMPCapabilities->Clear();
297
0
    for (const GMPCapabilityData& plugin : aCapabilities) {
298
0
      sGMPCapabilities->AppendElement(GMPCapabilityAndVersion(plugin));
299
0
    }
300
0
301
0
    LOGD(("UpdateGMPCapabilities {%s}", GMPCapabilitiesToString().get()));
302
0
  }
303
0
304
0
  // Fire a notification so that any MediaKeySystemAccess
305
0
  // requests waiting on a CDM to download will retry.
306
0
  nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
307
0
  MOZ_ASSERT(obsService);
308
0
  if (obsService) {
309
0
    obsService->NotifyObservers(nullptr, "gmp-changed", nullptr);
310
0
  }
311
0
}
312
313
void
314
GeckoMediaPluginServiceChild::BeginShutdown()
315
0
{
316
0
  MOZ_ASSERT(mGMPThread->EventTarget()->IsOnCurrentThread());
317
0
  mShuttingDownOnGMPThread = true;
318
0
}
319
320
NS_IMETHODIMP
321
GeckoMediaPluginServiceChild::HasPluginForAPI(const nsACString& aAPI,
322
                                              nsTArray<nsCString>* aTags,
323
                                              bool* aHasPlugin)
324
0
{
325
0
  StaticMutexAutoLock lock(sGMPCapabilitiesMutex);
326
0
  if (!sGMPCapabilities) {
327
0
    *aHasPlugin = false;
328
0
    return NS_OK;
329
0
  }
330
0
331
0
  nsCString api(aAPI);
332
0
  for (const GMPCapabilityAndVersion& plugin : *sGMPCapabilities) {
333
0
    if (GMPCapability::Supports(plugin.mCapabilities, api, *aTags)) {
334
0
      *aHasPlugin = true;
335
0
      return NS_OK;
336
0
    }
337
0
  }
338
0
339
0
  *aHasPlugin = false;
340
0
  return NS_OK;
341
0
}
342
343
NS_IMETHODIMP
344
GeckoMediaPluginServiceChild::GetNodeId(const nsAString& aOrigin,
345
                                        const nsAString& aTopLevelOrigin,
346
                                        const nsAString& aGMPName,
347
                                        UniquePtr<GetNodeIdCallback>&& aCallback)
348
0
{
349
0
  MOZ_ASSERT(mGMPThread->EventTarget()->IsOnCurrentThread());
350
0
351
0
  GetNodeIdCallback* rawCallback = aCallback.release();
352
0
  RefPtr<AbstractThread> thread(GetAbstractGMPThread());
353
0
  nsString origin(aOrigin);
354
0
  nsString topLevelOrigin(aTopLevelOrigin);
355
0
  nsString gmpName(aGMPName);
356
0
  GetServiceChild()->Then(thread, __func__,
357
0
    [rawCallback, origin, topLevelOrigin, gmpName](GMPServiceChild* child) {
358
0
      UniquePtr<GetNodeIdCallback> callback(rawCallback);
359
0
      nsCString outId;
360
0
      if (!child->SendGetGMPNodeId(origin, topLevelOrigin,
361
0
                                   gmpName, &outId)) {
362
0
        callback->Done(NS_ERROR_FAILURE, EmptyCString());
363
0
        return;
364
0
      }
365
0
366
0
      callback->Done(NS_OK, outId);
367
0
    },
368
0
    [rawCallback](nsresult rv) {
369
0
      UniquePtr<GetNodeIdCallback> callback(rawCallback);
370
0
      callback->Done(NS_ERROR_FAILURE, EmptyCString());
371
0
    });
372
0
373
0
  return NS_OK;
374
0
}
375
376
NS_IMETHODIMP
377
GeckoMediaPluginServiceChild::Observe(nsISupports* aSubject,
378
                                      const char* aTopic,
379
                                      const char16_t* aSomeData)
380
0
{
381
0
  LOGD(("%s::%s: %s", __CLASS__, __FUNCTION__, aTopic));
382
0
  if (!strcmp(NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, aTopic)) {
383
0
    if (mServiceChild) {
384
0
      mozilla::SyncRunnable::DispatchToThread(mGMPThread,
385
0
                                              WrapRunnable(mServiceChild.get(),
386
0
                                                           &PGMPServiceChild::Close));
387
0
      mServiceChild = nullptr;
388
0
    }
389
0
    ShutdownGMPThread();
390
0
  } else if (!strcmp(NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, aTopic)) {
391
0
    mXPCOMWillShutdown = true;
392
0
  }
393
0
394
0
  return NS_OK;
395
0
}
396
397
RefPtr<GeckoMediaPluginServiceChild::GetServiceChildPromise>
398
GeckoMediaPluginServiceChild::GetServiceChild()
399
0
{
400
0
  MOZ_ASSERT(mGMPThread->EventTarget()->IsOnCurrentThread());
401
0
402
0
  if (!mServiceChild) {
403
0
    if (mShuttingDownOnGMPThread) {
404
0
      // We have begun shutdown. Don't allow a new connection to the main
405
0
      // process to be instantiated. This also prevents new plugins being
406
0
      // instantiated.
407
0
      return GetServiceChildPromise::CreateAndReject(NS_ERROR_FAILURE,
408
0
                                                     __func__);
409
0
    }
410
0
    dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
411
0
    if (!contentChild) {
412
0
      return GetServiceChildPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
413
0
    }
414
0
    MozPromiseHolder<GetServiceChildPromise>* holder = mGetServiceChildPromises.AppendElement();
415
0
    RefPtr<GetServiceChildPromise> promise = holder->Ensure(__func__);
416
0
    if (mGetServiceChildPromises.Length() == 1) {
417
0
      nsCOMPtr<nsIRunnable> r = WrapRunnable(
418
0
        contentChild, &dom::ContentChild::SendCreateGMPService);
419
0
      SystemGroup::Dispatch(TaskCategory::Other, r.forget());
420
0
    }
421
0
    return promise;
422
0
  }
423
0
  return GetServiceChildPromise::CreateAndResolve(mServiceChild.get(), __func__);
424
0
}
425
426
void
427
GeckoMediaPluginServiceChild::SetServiceChild(UniquePtr<GMPServiceChild>&& aServiceChild)
428
0
{
429
0
  MOZ_ASSERT(mGMPThread->EventTarget()->IsOnCurrentThread());
430
0
431
0
  mServiceChild = std::move(aServiceChild);
432
0
433
0
  nsTArray<MozPromiseHolder<GetServiceChildPromise>> holders;
434
0
  holders.SwapElements(mGetServiceChildPromises);
435
0
  for (MozPromiseHolder<GetServiceChildPromise>& holder : holders) {
436
0
    holder.Resolve(mServiceChild.get(), __func__);
437
0
  }
438
0
}
439
440
void
441
GeckoMediaPluginServiceChild::RemoveGMPContentParent(GMPContentParent* aGMPContentParent)
442
0
{
443
0
  MOZ_ASSERT(mGMPThread->EventTarget()->IsOnCurrentThread());
444
0
445
0
  if (mServiceChild) {
446
0
    mServiceChild->RemoveGMPContentParent(aGMPContentParent);
447
0
    if (mShuttingDownOnGMPThread && !mServiceChild->HaveContentParents()) {
448
0
      mServiceChild->Close();
449
0
      mServiceChild = nullptr;
450
0
    }
451
0
  }
452
0
}
453
454
GMPServiceChild::GMPServiceChild()
455
0
{
456
0
}
457
458
GMPServiceChild::~GMPServiceChild()
459
0
{
460
0
}
461
462
already_AddRefed<GMPContentParent>
463
GMPServiceChild::GetBridgedGMPContentParent(ProcessId aOtherPid,
464
                                            ipc::Endpoint<PGMPContentParent>&& endpoint)
465
0
{
466
0
  RefPtr<GMPContentParent> parent;
467
0
  mContentParents.Get(aOtherPid, getter_AddRefs(parent));
468
0
469
0
  if (parent) {
470
0
    return parent.forget();
471
0
  }
472
0
473
0
  MOZ_ASSERT(aOtherPid == endpoint.OtherPid());
474
0
475
0
  parent = new GMPContentParent();
476
0
477
0
  DebugOnly<bool> ok = endpoint.Bind(parent);
478
0
  MOZ_ASSERT(ok);
479
0
480
0
  mContentParents.Put(aOtherPid, parent);
481
0
482
0
  return parent.forget();
483
0
}
484
485
void
486
GMPServiceChild::RemoveGMPContentParent(GMPContentParent* aGMPContentParent)
487
0
{
488
0
  for (auto iter = mContentParents.Iter(); !iter.Done(); iter.Next()) {
489
0
    RefPtr<GMPContentParent>& parent = iter.Data();
490
0
    if (parent == aGMPContentParent) {
491
0
      iter.Remove();
492
0
      break;
493
0
    }
494
0
  }
495
0
}
496
497
void
498
GMPServiceChild::GetAlreadyBridgedTo(nsTArray<base::ProcessId>& aAlreadyBridgedTo)
499
0
{
500
0
  aAlreadyBridgedTo.SetCapacity(mContentParents.Count());
501
0
  for (auto iter = mContentParents.Iter(); !iter.Done(); iter.Next()) {
502
0
    const uint64_t& id = iter.Key();
503
0
    aAlreadyBridgedTo.AppendElement(id);
504
0
  }
505
0
}
506
507
class OpenPGMPServiceChild : public mozilla::Runnable
508
{
509
public:
510
  OpenPGMPServiceChild(UniquePtr<GMPServiceChild>&& aGMPServiceChild,
511
                       ipc::Endpoint<PGMPServiceChild>&& aEndpoint)
512
    : Runnable("gmp::OpenPGMPServiceChild")
513
    , mGMPServiceChild(std::move(aGMPServiceChild))
514
    , mEndpoint(std::move(aEndpoint))
515
0
  {
516
0
  }
517
518
  NS_IMETHOD Run() override
519
0
  {
520
0
    RefPtr<GeckoMediaPluginServiceChild> gmp =
521
0
      GeckoMediaPluginServiceChild::GetSingleton();
522
0
    MOZ_ASSERT(!gmp->mServiceChild);
523
0
    if (mEndpoint.Bind(mGMPServiceChild.get())) {
524
0
      gmp->SetServiceChild(std::move(mGMPServiceChild));
525
0
    } else {
526
0
      gmp->SetServiceChild(nullptr);
527
0
    }
528
0
    return NS_OK;
529
0
  }
530
531
private:
532
  UniquePtr<GMPServiceChild> mGMPServiceChild;
533
  ipc::Endpoint<PGMPServiceChild> mEndpoint;
534
};
535
536
/* static */
537
bool
538
GMPServiceChild::Create(Endpoint<PGMPServiceChild>&& aGMPService)
539
0
{
540
0
  RefPtr<GeckoMediaPluginServiceChild> gmp =
541
0
    GeckoMediaPluginServiceChild::GetSingleton();
542
0
  MOZ_ASSERT(!gmp->mServiceChild);
543
0
544
0
  UniquePtr<GMPServiceChild> serviceChild(new GMPServiceChild());
545
0
546
0
  nsCOMPtr<nsIThread> gmpThread;
547
0
  nsresult rv = gmp->GetThread(getter_AddRefs(gmpThread));
548
0
  NS_ENSURE_SUCCESS(rv, false);
549
0
550
0
  rv = gmpThread->Dispatch(new OpenPGMPServiceChild(std::move(serviceChild),
551
0
                                                    std::move(aGMPService)),
552
0
                           NS_DISPATCH_NORMAL);
553
0
  return NS_SUCCEEDED(rv);
554
0
}
555
556
ipc::IPCResult
557
GMPServiceChild::RecvBeginShutdown()
558
0
{
559
0
  RefPtr<GeckoMediaPluginServiceChild> service =
560
0
    GeckoMediaPluginServiceChild::GetSingleton();
561
0
  MOZ_ASSERT(service && service->mServiceChild.get() == this);
562
0
  if (service) {
563
0
    service->BeginShutdown();
564
0
  }
565
0
  return IPC_OK();
566
0
}
567
568
bool
569
GMPServiceChild::HaveContentParents() const
570
0
{
571
0
  return mContentParents.Count() > 0;
572
0
}
573
574
} // namespace gmp
575
} // namespace mozilla