Bug 1352924 - Block creation of new GMPs once parent process begins shutdown. r=gerald draft
authorChris Pearce <cpearce@mozilla.com>
Mon, 03 Apr 2017 11:08:06 +1200
changeset 554930 674f3c4ddcb5bb93dd775a861b425d25510871e9
parent 554929 f4ad3c6df0e14c88db1199fbe6281d67f98590ae
child 554931 b9cbbb9f4c22016284a8d49cddaea0d96666acf9
push id52098
push userbmo:cpearce@mozilla.com
push dateMon, 03 Apr 2017 10:40:05 +0000
reviewersgerald
bugs1352924
milestone55.0a1
Bug 1352924 - Block creation of new GMPs once parent process begins shutdown. r=gerald This ensures that when we've started shutdown we don't try to start up new GMPs. Doing so would create more connections from the content process to the main process, and the main process can't shutdown until all such connections are shut down. MozReview-Commit-ID: KE8nCoLXjdd
dom/media/gmp/GMPServiceChild.cpp
dom/media/gmp/GMPServiceChild.h
dom/media/gmp/GMPServiceParent.cpp
dom/media/gmp/PGMPService.ipdl
--- a/dom/media/gmp/GMPServiceChild.cpp
+++ b/dom/media/gmp/GMPServiceChild.cpp
@@ -288,16 +288,23 @@ GeckoMediaPluginServiceChild::UpdateGMPC
   // requests waiting on a CDM to download will retry.
   nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
   MOZ_ASSERT(obsService);
   if (obsService) {
     obsService->NotifyObservers(nullptr, "gmp-changed", nullptr);
   }
 }
 
+void
+GeckoMediaPluginServiceChild::BeginShutdown()
+{
+  MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
+  mShuttingDownOnGMPThread = true;
+}
+
 NS_IMETHODIMP
 GeckoMediaPluginServiceChild::HasPluginForAPI(const nsACString& aAPI,
                                               nsTArray<nsCString>* aTags,
                                               bool* aHasPlugin)
 {
   StaticMutexAutoLock lock(sGMPCapabilitiesMutex);
   if (!sGMPCapabilities) {
     *aHasPlugin = false;
@@ -369,16 +376,23 @@ GeckoMediaPluginServiceChild::Observe(ns
 }
 
 RefPtr<GeckoMediaPluginServiceChild::GetServiceChildPromise>
 GeckoMediaPluginServiceChild::GetServiceChild()
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
 
   if (!mServiceChild) {
+    if (mShuttingDownOnGMPThread) {
+      // We have begun shutdown. Don't allow a new connection to the main
+      // process to be instantiated. This also prevents new plugins being
+      // instantiated.
+      return GetServiceChildPromise::CreateAndReject(NS_ERROR_FAILURE,
+                                                     __func__);
+    }
     dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
     if (!contentChild) {
       return GetServiceChildPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
     }
     MozPromiseHolder<GetServiceChildPromise>* holder = mGetServiceChildPromises.AppendElement();
     RefPtr<GetServiceChildPromise> promise = holder->Ensure(__func__);
     if (mGetServiceChildPromises.Length() == 1) {
       nsCOMPtr<nsIRunnable> r = WrapRunnable(
@@ -510,10 +524,28 @@ GMPServiceChild::Create(Endpoint<PGMPSer
   NS_ENSURE_SUCCESS(rv, false);
 
   rv = gmpThread->Dispatch(new OpenPGMPServiceChild(Move(serviceChild),
                                                     Move(aGMPService)),
                            NS_DISPATCH_NORMAL);
   return NS_SUCCEEDED(rv);
 }
 
+ipc::IPCResult
+GMPServiceChild::RecvBeginShutdown()
+{
+  RefPtr<GeckoMediaPluginServiceChild> service =
+    GeckoMediaPluginServiceChild::GetSingleton();
+  MOZ_ASSERT(service && service->mServiceChild.get() == this);
+  if (service) {
+    service->BeginShutdown();
+  }
+  return IPC_OK();
+}
+
+bool
+GMPServiceChild::HaveContentParents() const
+{
+  return mContentParents.Count() > 0;
+}
+
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gmp/GMPServiceChild.h
+++ b/dom/media/gmp/GMPServiceChild.h
@@ -37,16 +37,18 @@ public:
   NS_DECL_NSIOBSERVER
 
   void SetServiceChild(UniquePtr<GMPServiceChild>&& aServiceChild);
 
   void RemoveGMPContentParent(GMPContentParent* aGMPContentParent);
 
   static void UpdateGMPCapabilities(nsTArray<mozilla::dom::GMPCapabilityData>&& aCapabilities);
 
+  void BeginShutdown();
+
 protected:
   void InitializePlugins(AbstractThread*) override
   {
     // Nothing to do here.
   }
 
   virtual RefPtr<GetGMPContentParentPromise> GetContentParent(
     GMPCrashHelper* aHelper,
@@ -80,16 +82,20 @@ public:
                                                                 ipc::Endpoint<PGMPContentParent>&& endpoint);
 
   void RemoveGMPContentParent(GMPContentParent* aGMPContentParent);
 
   void GetAlreadyBridgedTo(nsTArray<ProcessId>& aAlreadyBridgedTo);
 
   static bool Create(Endpoint<PGMPServiceChild>&& aGMPService);
 
+  ipc::IPCResult RecvBeginShutdown() override;
+
+  bool HaveContentParents() const;
+
 private:
   nsRefPtrHashtable<nsUint64HashKey, GMPContentParent> mContentParents;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPServiceChild_h_
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -463,16 +463,20 @@ GeckoMediaPluginServiceParent::UnloadPlu
   mShuttingDownOnGMPThread = true;
 
   nsTArray<RefPtr<GMPParent>> plugins;
   {
     MutexAutoLock lock(mMutex);
     // Move all plugins references to a local array. This way mMutex won't be
     // locked when calling CloseActive (to avoid inter-locking).
     Swap(plugins, mPlugins);
+
+    for (GMPServiceParent* parent : mServiceParents) {
+      Unused << parent->SendBeginShutdown();
+    }
   }
 
   LOGD(("%s::%s plugins:%" PRIuSIZE, __CLASS__, __FUNCTION__,
         plugins.Length()));
 #ifdef DEBUG
   for (const auto& plugin : plugins) {
     LOGD(("%s::%s plugin: '%s'", __CLASS__, __FUNCTION__,
           plugin->GetDisplayName().get()));
--- a/dom/media/gmp/PGMPService.ipdl
+++ b/dom/media/gmp/PGMPService.ipdl
@@ -31,12 +31,14 @@ parent:
     returns (uint32_t pluginId,
              ProcessId id,
              nsCString displayName,
              Endpoint<PGMPContentParent> endpoint,
              nsresult aResult);
 
   sync GetGMPNodeId(nsString origin, nsString topLevelOrigin, nsString gmpName)
     returns (nsCString id);
+child:
+  async BeginShutdown();
 };
 
 } // namespace gmp
 } // namespace mozilla