GMPServiceChild.cpp (22151B)
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 8 #include "GMPLog.h" 9 #include "GMPParent.h" 10 #include "base/task.h" 11 #include "mozIGeckoMediaPluginChromeService.h" 12 #include "mozilla/ClearOnShutdown.h" 13 #include "mozilla/SchedulerGroup.h" 14 #include "mozilla/StaticMutex.h" 15 #include "mozilla/StaticPtr.h" 16 #include "mozilla/SyncRunnable.h" 17 #include "mozilla/dom/ContentChild.h" 18 #include "mozilla/ipc/Endpoint.h" 19 #include "nsCOMPtr.h" 20 #include "nsComponentManagerUtils.h" 21 #include "nsFmtString.h" 22 #include "nsIObserverService.h" 23 #include "nsReadableUtils.h" 24 #include "nsXPCOMPrivate.h" 25 #include "runnable_utils.h" 26 27 namespace mozilla::gmp { 28 29 #ifdef __CLASS__ 30 # undef __CLASS__ 31 #endif 32 #define __CLASS__ "GMPServiceChild" 33 34 already_AddRefed<GeckoMediaPluginServiceChild> 35 GeckoMediaPluginServiceChild::GetSingleton() { 36 MOZ_ASSERT(!XRE_IsParentProcess()); 37 RefPtr<GeckoMediaPluginService> service( 38 GeckoMediaPluginService::GetGeckoMediaPluginService()); 39 #ifdef DEBUG 40 if (service) { 41 nsCOMPtr<mozIGeckoMediaPluginChromeService> chromeService; 42 CallQueryInterface(service.get(), getter_AddRefs(chromeService)); 43 MOZ_ASSERT(!chromeService); 44 } 45 #endif 46 return service.forget().downcast<GeckoMediaPluginServiceChild>(); 47 } 48 49 nsresult GeckoMediaPluginServiceChild::Init() { 50 MOZ_ASSERT(NS_IsMainThread()); 51 GMP_LOG_DEBUG("%s::%s", __CLASS__, __FUNCTION__); 52 53 nsresult rv = AddShutdownBlocker(); 54 if (NS_FAILED(rv)) { 55 MOZ_ASSERT_UNREACHABLE( 56 "We expect xpcom to be live when calling this, so we should be able to " 57 "add a blocker"); 58 GMP_LOG_DEBUG("%s::%s failed to add shutdown blocker!", __CLASS__, 59 __FUNCTION__); 60 return rv; 61 } 62 63 return GeckoMediaPluginService::Init(); 64 } 65 66 NS_IMPL_ISUPPORTS_INHERITED0(GeckoMediaPluginServiceChild, 67 GeckoMediaPluginService) 68 69 GeckoMediaPluginServiceChild::~GeckoMediaPluginServiceChild() { 70 MOZ_ASSERT(!mServiceChild); 71 } 72 73 RefPtr<GetGMPContentParentPromise> 74 GeckoMediaPluginServiceChild::GetContentParent( 75 GMPCrashHelper* aHelper, const NodeIdVariant& aNodeIdVariant, 76 const nsACString& aAPI, const nsTArray<nsCString>& aTags) { 77 AssertOnGMPThread(); 78 MOZ_ASSERT(!mShuttingDownOnGMPThread, 79 "Should not be called if GMPThread is shutting down!"); 80 81 MozPromiseHolder<GetGMPContentParentPromise>* rawHolder = 82 new MozPromiseHolder<GetGMPContentParentPromise>(); 83 RefPtr<GetGMPContentParentPromise> promise = rawHolder->Ensure(__func__); 84 nsCOMPtr<nsISerialEventTarget> thread(GetGMPThread()); 85 86 nsCString api(aAPI); 87 RefPtr<GMPCrashHelper> helper(aHelper); 88 RefPtr<GeckoMediaPluginServiceChild> self(this); 89 90 mPendingGetContentParents += 1; 91 92 GetServiceChild()->Then( 93 thread, __func__, 94 [nodeIdVariant = aNodeIdVariant, self, api, tags = aTags.Clone(), helper, 95 rawHolder](GMPServiceChild* child) { 96 nsTArray<base::ProcessId> alreadyBridgedTo; 97 98 // We want to force the content process to keep all of our 99 // GMPContentParent IPDL objects alive while we wait to resolve which 100 // process can satisfy our request. This avoids a race condition where 101 // the last dependency is released before we can acquire our own. 102 auto* rawBlockers = 103 new nsTArray<RefPtr<GMPContentParentCloseBlocker>>(); 104 child->GetAndBlockAlreadyBridgedTo(alreadyBridgedTo, *rawBlockers); 105 106 child->SendLaunchGMP( 107 nodeIdVariant, api, tags, alreadyBridgedTo, 108 [rawHolder, self, helper, rawBlockers, 109 child = RefPtr{child}](GMPLaunchResult&& aResult) { 110 UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>> holder( 111 rawHolder); 112 UniquePtr<nsTArray<RefPtr<GMPContentParentCloseBlocker>>> 113 blockers(rawBlockers); 114 if (helper && aResult.pluginId()) { 115 // Note: Even if the launch failed, we need to connect the crash 116 // helper so that if the launch failed due to the plugin 117 // crashing, we can report the crash via the crash reporter. The 118 // crash handling notification will arrive shortly if the launch 119 // failed due to the plugin crashing. 120 self->ConnectCrashHelper(aResult.pluginId(), helper); 121 } 122 123 if (NS_WARN_IF(NS_FAILED(aResult.result()))) { 124 MediaResult error( 125 aResult.result(), 126 nsPrintfCString( 127 "GeckoMediaPluginServiceChild::GetContentParent " 128 "SendLaunchGMPForNodeId failed with description (%s)", 129 aResult.errorDescription().get())); 130 131 GMP_LOG_DEBUG("%s failed to launch GMP with error: %s", 132 __CLASS__, aResult.errorDescription().get()); 133 self->mPendingGetContentParents -= 1; 134 self->RemoveShutdownBlockerIfNeeded(); 135 136 holder->Reject(error, __func__); 137 return; 138 } 139 140 // If we didn't explicitly fail, we should have been told about a 141 // process running. 142 MOZ_ASSERT(aResult.pid() != base::kInvalidProcessId); 143 144 // It is possible the GMP process may have terminated before we 145 // were able to process this result. In that case, we should just 146 // fail as normal as the initialization of the IPDL objects would 147 // have just failed anyways and produced the same result. 148 bool contains = child->HasAlreadyBridgedTo(aResult.pid()); 149 if (NS_WARN_IF(!contains && !aResult.endpoint().IsValid())) { 150 MediaResult error( 151 aResult.result(), 152 "GeckoMediaPluginServiceChild::GetContentParent " 153 "SendLaunchGMPForNodeId failed with process exit"_ns); 154 155 GMP_LOG_DEBUG("%s failed to launch GMP with process exit", 156 __CLASS__); 157 self->mPendingGetContentParents -= 1; 158 self->RemoveShutdownBlockerIfNeeded(); 159 160 holder->Reject(error, __func__); 161 return; 162 } 163 164 RefPtr<GMPContentParent> parent = 165 child->GetBridgedGMPContentParent( 166 aResult.pid(), std::move(aResult.endpoint())); 167 if (!contains) { 168 parent->SetDisplayName(aResult.displayName()); 169 parent->SetPluginId(aResult.pluginId()); 170 parent->SetPluginType(aResult.pluginType()); 171 } 172 173 // The content parent is no longer pending. 174 self->mPendingGetContentParents -= 1; 175 MOZ_ASSERT(child->HaveContentParents(), 176 "We should have at least one content parent!"); 177 // We don't check if we need to remove the shutdown blocker here 178 // as we should always have at least one live content parent. 179 180 RefPtr<GMPContentParentCloseBlocker> blocker( 181 new GMPContentParentCloseBlocker(parent)); 182 holder->Resolve(blocker, __func__); 183 }, 184 [rawHolder, self, helper, 185 rawBlockers](const ipc::ResponseRejectReason&) { 186 UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>> holder( 187 rawHolder); 188 UniquePtr<nsTArray<RefPtr<GMPContentParentCloseBlocker>>> 189 blockers(rawBlockers); 190 MediaResult error( 191 NS_ERROR_FAILURE, 192 "GeckoMediaPluginServiceChild::GetContentParent " 193 "SendLaunchGMPForNodeId failed with IPC error"_ns); 194 195 GMP_LOG_DEBUG("%s failed to launch GMP with IPC error", 196 __CLASS__); 197 self->mPendingGetContentParents -= 1; 198 self->RemoveShutdownBlockerIfNeeded(); 199 200 holder->Reject(error, __func__); 201 }); 202 }, 203 [self, rawHolder](MediaResult result) { 204 self->mPendingGetContentParents -= 1; 205 self->RemoveShutdownBlockerIfNeeded(); 206 UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>> holder( 207 rawHolder); 208 holder->Reject(result, __func__); 209 }); 210 211 return promise; 212 } 213 214 typedef mozilla::dom::GMPCapabilityData GMPCapabilityData; 215 typedef mozilla::dom::GMPAPITags GMPAPITags; 216 217 struct GMPCapabilityAndVersion { 218 explicit GMPCapabilityAndVersion(const GMPCapabilityData& aCapabilities) 219 : mName(aCapabilities.name()), mVersion(aCapabilities.version()) { 220 for (const GMPAPITags& tags : aCapabilities.capabilities()) { 221 GMPCapability cap; 222 cap.mAPIName = tags.api(); 223 for (const nsACString& tag : tags.tags()) { 224 cap.mAPITags.AppendElement(tag); 225 } 226 mCapabilities.AppendElement(std::move(cap)); 227 } 228 } 229 230 nsCString ToString() const { 231 nsCString s; 232 s.Append(mName); 233 s.AppendLiteral(" version="); 234 s.Append(mVersion); 235 s.AppendLiteral(" tags=["); 236 StringJoinAppend(s, " "_ns, mCapabilities, 237 [](auto& tags, const GMPCapability& cap) { 238 tags.Append(cap.mAPIName); 239 for (const nsACString& tag : cap.mAPITags) { 240 tags.AppendLiteral(":"); 241 tags.Append(tag); 242 } 243 }); 244 s.AppendLiteral("]"); 245 return s; 246 } 247 248 nsCString mName; 249 nsCString mVersion; 250 nsTArray<GMPCapability> mCapabilities; 251 }; 252 253 StaticMutex sGMPCapabilitiesMutex; 254 StaticAutoPtr<nsTArray<GMPCapabilityAndVersion>> sGMPCapabilities; 255 256 static auto GMPCapabilitiesToString() { 257 return StringJoin(", "_ns, *sGMPCapabilities, 258 [](nsACString& dest, const GMPCapabilityAndVersion& gmp) { 259 dest.Append(gmp.ToString()); 260 }); 261 } 262 263 /* static */ 264 void GeckoMediaPluginServiceChild::UpdateGMPCapabilities( 265 nsTArray<GMPCapabilityData>&& aCapabilities) { 266 { 267 // The mutex should unlock before sending the "gmp-changed" observer 268 // service notification. 269 StaticMutexAutoLock lock(sGMPCapabilitiesMutex); 270 if (!sGMPCapabilities) { 271 sGMPCapabilities = new nsTArray<GMPCapabilityAndVersion>(); 272 ClearOnShutdown(&sGMPCapabilities); 273 } 274 sGMPCapabilities->Clear(); 275 for (const GMPCapabilityData& plugin : aCapabilities) { 276 sGMPCapabilities->AppendElement(GMPCapabilityAndVersion(plugin)); 277 } 278 279 GMP_LOG_DEBUG("%s::%s {%s}", __CLASS__, __FUNCTION__, 280 GMPCapabilitiesToString().get()); 281 } 282 283 // Fire a notification so that any MediaKeySystemAccess 284 // requests waiting on a CDM to download will retry. 285 nsCOMPtr<nsIObserverService> obsService = 286 mozilla::services::GetObserverService(); 287 MOZ_ASSERT(obsService); 288 if (obsService) { 289 obsService->NotifyObservers(nullptr, "gmp-changed", nullptr); 290 } 291 } 292 293 void GeckoMediaPluginServiceChild::BeginShutdown() { 294 AssertOnGMPThread(); 295 GMP_LOG_DEBUG("%s::%s: mServiceChild=%p,", __CLASS__, __FUNCTION__, 296 mServiceChild.get()); 297 // It's possible this gets called twice if the parent sends us a message to 298 // shutdown and we block shutdown in content in close proximity. 299 mShuttingDownOnGMPThread = true; 300 RemoveShutdownBlockerIfNeeded(); 301 } 302 303 NS_IMETHODIMP 304 GeckoMediaPluginServiceChild::HasPluginForAPI(const nsACString& aAPI, 305 const nsTArray<nsCString>& aTags, 306 bool* aHasPlugin) { 307 StaticMutexAutoLock lock(sGMPCapabilitiesMutex); 308 if (!sGMPCapabilities) { 309 *aHasPlugin = false; 310 return NS_OK; 311 } 312 313 nsCString api(aAPI); 314 for (const GMPCapabilityAndVersion& plugin : *sGMPCapabilities) { 315 if (GMPCapability::Supports(plugin.mCapabilities, api, aTags)) { 316 *aHasPlugin = true; 317 return NS_OK; 318 } 319 } 320 321 *aHasPlugin = false; 322 return NS_OK; 323 } 324 325 NS_IMETHODIMP 326 GeckoMediaPluginServiceChild::FindPluginDirectoryForAPI( 327 const nsACString& aAPI, const nsTArray<nsCString>& aTags, 328 nsIFile** aDirectory) { 329 return NS_ERROR_NOT_IMPLEMENTED; 330 } 331 332 NS_IMETHODIMP 333 GeckoMediaPluginServiceChild::GetNodeId( 334 const nsAString& aOrigin, const nsAString& aTopLevelOrigin, 335 const nsAString& aGMPName, UniquePtr<GetNodeIdCallback>&& aCallback) { 336 AssertOnGMPThread(); 337 338 GetNodeIdCallback* rawCallback = aCallback.release(); 339 nsCOMPtr<nsISerialEventTarget> thread(GetGMPThread()); 340 nsString origin(aOrigin); 341 nsString topLevelOrigin(aTopLevelOrigin); 342 nsString gmpName(aGMPName); 343 GetServiceChild()->Then( 344 thread, __func__, 345 [rawCallback, origin, topLevelOrigin, gmpName](GMPServiceChild* child) { 346 child->SendGetGMPNodeId( 347 origin, topLevelOrigin, gmpName, 348 [rawCallback](nsCString&& aId) { 349 UniquePtr<GetNodeIdCallback> callback(rawCallback); 350 callback->Done(NS_OK, aId); 351 }, 352 [rawCallback](const ipc::ResponseRejectReason&) { 353 UniquePtr<GetNodeIdCallback> callback(rawCallback); 354 callback->Done(NS_ERROR_FAILURE, ""_ns); 355 }); 356 }, 357 [rawCallback](nsresult rv) { 358 UniquePtr<GetNodeIdCallback> callback(rawCallback); 359 callback->Done(NS_ERROR_FAILURE, ""_ns); 360 }); 361 362 return NS_OK; 363 } 364 365 NS_IMETHODIMP 366 GeckoMediaPluginServiceChild::Observe(nsISupports* aSubject, const char* aTopic, 367 const char16_t* aSomeData) { 368 MOZ_ASSERT(NS_IsMainThread()); 369 GMP_LOG_DEBUG("%s::%s: aTopic=%s", __CLASS__, __FUNCTION__, aTopic); 370 if (!strcmp(NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, aTopic)) { 371 if (mServiceChild) { 372 MutexAutoLock lock(mMutex); 373 mozilla::SyncRunnable::DispatchToThread( 374 mGMPThread, 375 WrapRunnable(mServiceChild.get(), &PGMPServiceChild::Close)); 376 mServiceChild = nullptr; 377 } 378 ShutdownGMPThread(); 379 } 380 381 return NS_OK; 382 } 383 384 RefPtr<GeckoMediaPluginServiceChild::GetServiceChildPromise> 385 GeckoMediaPluginServiceChild::GetServiceChild() { 386 AssertOnGMPThread(); 387 388 if (!mServiceChild) { 389 if (mShuttingDownOnGMPThread) { 390 // We have begun shutdown. Don't allow a new connection to the main 391 // process to be instantiated. This also prevents new plugins being 392 // instantiated. 393 return GetServiceChildPromise::CreateAndReject(NS_ERROR_FAILURE, 394 __func__); 395 } 396 dom::ContentChild* contentChild = dom::ContentChild::GetSingleton(); 397 if (!contentChild) { 398 return GetServiceChildPromise::CreateAndReject(NS_ERROR_FAILURE, 399 __func__); 400 } 401 MozPromiseHolder<GetServiceChildPromise>* holder = 402 mGetServiceChildPromises.AppendElement(); 403 RefPtr<GetServiceChildPromise> promise = holder->Ensure(__func__); 404 if (mGetServiceChildPromises.Length() == 1) { 405 nsCOMPtr<nsIRunnable> r = 406 WrapRunnable(contentChild, &dom::ContentChild::SendCreateGMPService); 407 SchedulerGroup::Dispatch(r.forget()); 408 } 409 return promise; 410 } 411 return GetServiceChildPromise::CreateAndResolve(mServiceChild.get(), 412 __func__); 413 } 414 415 void GeckoMediaPluginServiceChild::SetServiceChild( 416 RefPtr<GMPServiceChild>&& aServiceChild) { 417 AssertOnGMPThread(); 418 MOZ_ASSERT(!mServiceChild, "Should not already have service child!"); 419 GMP_LOG_DEBUG("%s::%s: aServiceChild=%p", __CLASS__, __FUNCTION__, 420 aServiceChild.get()); 421 422 mServiceChild = std::move(aServiceChild); 423 424 nsTArray<MozPromiseHolder<GetServiceChildPromise>> holders = 425 std::move(mGetServiceChildPromises); 426 for (MozPromiseHolder<GetServiceChildPromise>& holder : holders) { 427 holder.Resolve(mServiceChild.get(), __func__); 428 } 429 } 430 431 void GeckoMediaPluginServiceChild::RemoveGMPContentParent( 432 GMPContentParent* aGMPContentParent) { 433 AssertOnGMPThread(); 434 GMP_LOG_DEBUG( 435 "%s::%s: aGMPContentParent=%p, mServiceChild=%p, " 436 "mShuttingDownOnGMPThread=%s", 437 __CLASS__, __FUNCTION__, aGMPContentParent, mServiceChild.get(), 438 mShuttingDownOnGMPThread ? "true" : "false"); 439 440 if (mServiceChild) { 441 mServiceChild->RemoveGMPContentParent(aGMPContentParent); 442 GMP_LOG_DEBUG( 443 "%s::%s: aGMPContentParent removed, " 444 "mServiceChild->HaveContentParents()=%s", 445 __CLASS__, __FUNCTION__, 446 mServiceChild->HaveContentParents() ? "true" : "false"); 447 RemoveShutdownBlockerIfNeeded(); 448 } 449 } 450 451 nsresult GeckoMediaPluginServiceChild::AddShutdownBlocker() { 452 MOZ_ASSERT(NS_IsMainThread()); 453 MOZ_ASSERT(!mShuttingDownOnGMPThread, 454 "No call paths should add blockers once we're shutting down!"); 455 MOZ_ASSERT(!mShutdownBlocker, "Should only add blocker once!"); 456 GMP_LOG_DEBUG("%s::%s ", __CLASS__, __FUNCTION__); 457 458 nsFmtString name(u"GeckoMediaPluginServiceChild {}", 459 static_cast<void*>(this)); 460 mShutdownBlocker = media::ShutdownBlockingTicket::Create( 461 name, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__); 462 if (mShutdownBlocker) { 463 mShutdownBlocker->ShutdownPromise()->Then( 464 mMainThread, __func__, [this, self = RefPtr(this), name]() { 465 GMP_LOG_DEBUG("GMPServiceChild::BlockShutdown: %s", 466 NS_ConvertUTF16toUTF8(name).get()); 467 mXPCOMWillShutdown = true; 468 nsCOMPtr gmpThread = GetGMPThread(); 469 gmpThread->Dispatch( 470 NewRunnableMethod("GMPServiceChild::BeginShutdown", this, 471 &GeckoMediaPluginServiceChild::BeginShutdown)); 472 }); 473 return NS_OK; 474 } 475 476 return NS_ERROR_FAILURE; 477 } 478 479 void GeckoMediaPluginServiceChild::RemoveShutdownBlocker() { 480 AssertOnGMPThread(); 481 MOZ_ASSERT(mShuttingDownOnGMPThread, 482 "We should only remove blockers once we're " 483 "shutting down!"); 484 GMP_LOG_DEBUG("%s::%s ", __CLASS__, __FUNCTION__); 485 mShutdownBlocker = nullptr; 486 } 487 488 void GeckoMediaPluginServiceChild::RemoveShutdownBlockerIfNeeded() { 489 AssertOnGMPThread(); 490 GMP_LOG_DEBUG( 491 "%s::%s mPendingGetContentParents=%" PRIu32 492 " mServiceChild->HaveContentParents()=%s " 493 "mShuttingDownOnGMPThread=%s", 494 __CLASS__, __FUNCTION__, mPendingGetContentParents, 495 mServiceChild && mServiceChild->HaveContentParents() ? "true" : "false", 496 mShuttingDownOnGMPThread ? "true" : "false"); 497 498 bool haveOneOrMoreContentParents = 499 mPendingGetContentParents > 0 || 500 (mServiceChild && mServiceChild->HaveContentParents()); 501 502 if (!mShuttingDownOnGMPThread || haveOneOrMoreContentParents) { 503 return; 504 } 505 RemoveShutdownBlocker(); 506 } 507 508 already_AddRefed<GMPContentParent> GMPServiceChild::GetBridgedGMPContentParent( 509 ProcessId aOtherPid, ipc::Endpoint<PGMPContentParent>&& endpoint) { 510 return do_AddRef(mContentParents.LookupOrInsertWith(aOtherPid, [&] { 511 MOZ_ASSERT(aOtherPid == endpoint.OtherPid()); 512 513 auto parent = MakeRefPtr<GMPContentParent>(); 514 515 DebugOnly<bool> ok = endpoint.Bind(parent); 516 MOZ_ASSERT(ok); 517 518 return parent; 519 })); 520 } 521 522 void GMPServiceChild::RemoveGMPContentParent( 523 GMPContentParent* aGMPContentParent) { 524 for (auto iter = mContentParents.Iter(); !iter.Done(); iter.Next()) { 525 RefPtr<GMPContentParent>& parent = iter.Data(); 526 if (parent == aGMPContentParent) { 527 iter.Remove(); 528 break; 529 } 530 } 531 } 532 533 bool GMPServiceChild::HasAlreadyBridgedTo(base::ProcessId aPid) const { 534 return mContentParents.Contains(aPid); 535 } 536 537 void GMPServiceChild::GetAndBlockAlreadyBridgedTo( 538 nsTArray<base::ProcessId>& aAlreadyBridgedTo, 539 nsTArray<RefPtr<GMPContentParentCloseBlocker>>& aBlockers) { 540 aAlreadyBridgedTo.SetCapacity(mContentParents.Count()); 541 aBlockers.SetCapacity(mContentParents.Count()); 542 for (auto iter = mContentParents.Iter(); !iter.Done(); iter.Next()) { 543 aAlreadyBridgedTo.AppendElement(iter.Key()); 544 aBlockers.AppendElement(new GMPContentParentCloseBlocker(iter.UserData())); 545 } 546 } 547 548 class OpenPGMPServiceChild : public mozilla::Runnable { 549 public: 550 OpenPGMPServiceChild(RefPtr<GMPServiceChild>&& aGMPServiceChild, 551 ipc::Endpoint<PGMPServiceChild>&& aEndpoint) 552 : Runnable("gmp::OpenPGMPServiceChild"), 553 mGMPServiceChild(std::move(aGMPServiceChild)), 554 mEndpoint(std::move(aEndpoint)) {} 555 556 NS_IMETHOD Run() override { 557 RefPtr<GeckoMediaPluginServiceChild> gmp = 558 GeckoMediaPluginServiceChild::GetSingleton(); 559 MOZ_RELEASE_ASSERT(gmp); 560 MOZ_ASSERT(!gmp->mServiceChild); 561 if (mEndpoint.Bind(mGMPServiceChild.get())) { 562 gmp->SetServiceChild(std::move(mGMPServiceChild)); 563 } else { 564 gmp->SetServiceChild(nullptr); 565 } 566 return NS_OK; 567 } 568 569 private: 570 RefPtr<GMPServiceChild> mGMPServiceChild; 571 ipc::Endpoint<PGMPServiceChild> mEndpoint; 572 }; 573 574 /* static */ 575 bool GMPServiceChild::Create(Endpoint<PGMPServiceChild>&& aGMPService) { 576 RefPtr<GeckoMediaPluginServiceChild> gmp = 577 GeckoMediaPluginServiceChild::GetSingleton(); 578 if (NS_WARN_IF(!gmp)) { 579 return false; 580 } 581 582 MOZ_ASSERT(!gmp->mServiceChild); 583 584 RefPtr<GMPServiceChild> serviceChild(new GMPServiceChild()); 585 586 nsCOMPtr<nsIThread> gmpThread; 587 nsresult rv = gmp->GetThread(getter_AddRefs(gmpThread)); 588 NS_ENSURE_SUCCESS(rv, false); 589 590 rv = gmpThread->Dispatch( 591 new OpenPGMPServiceChild(std::move(serviceChild), std::move(aGMPService)), 592 NS_DISPATCH_NORMAL); 593 return NS_SUCCEEDED(rv); 594 } 595 596 ipc::IPCResult GMPServiceChild::RecvBeginShutdown() { 597 RefPtr<GeckoMediaPluginServiceChild> service = 598 GeckoMediaPluginServiceChild::GetSingleton(); 599 MOZ_ASSERT(service && service->mServiceChild.get() == this); 600 if (service) { 601 service->BeginShutdown(); 602 } 603 return IPC_OK(); 604 } 605 606 bool GMPServiceChild::HaveContentParents() const { 607 return mContentParents.Count() > 0; 608 } 609 610 } // namespace mozilla::gmp 611 612 #undef __CLASS__