Bug 1321871, part 1 - Replace use of opens and bridges in GMP protocols with endpoints. r=peterv draft
authorAndrew McCreight <continuation@gmail.com>
Thu, 05 Jan 2017 12:55:27 -0800
changeset 465409 3f0264a9d078353d3c24b4ab637eefac61f7a00a
parent 464990 5a4412474c63e1d9e66036d603ac42e9cb2b9150
child 465410 e395972b467063f85d3b390b3b42e39b1ac25185
push id42584
push userbmo:continuation@gmail.com
push dateTue, 24 Jan 2017 00:38:38 +0000
reviewerspeterv
bugs1321871
milestone54.0a1
Bug 1321871, part 1 - Replace use of opens and bridges in GMP protocols with endpoints. r=peterv This removes the open of PGMPContent from PGMP, the bridge of PGMPService and PGMP from PGMPContent, and the spawn of PGMP from PGMPService. I did these changes all at once because the way the bridges works it was hard to split it up.
dom/ipc/PContent.ipdl
dom/media/gmp/GMPChild.cpp
dom/media/gmp/GMPChild.h
dom/media/gmp/GMPParent.cpp
dom/media/gmp/GMPParent.h
dom/media/gmp/GMPServiceChild.cpp
dom/media/gmp/GMPServiceChild.h
dom/media/gmp/GMPServiceParent.cpp
dom/media/gmp/GMPServiceParent.h
dom/media/gmp/PGMP.ipdl
dom/media/gmp/PGMPContent.ipdl
dom/media/gmp/PGMPService.ipdl
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -19,21 +19,16 @@ include protocol PDeviceStorageRequest;
 include protocol PFileDescriptorSet;
 include protocol PHal;
 include protocol PHeapSnapshotTempFileHelper;
 include protocol PProcessHangMonitor;
 include protocol PImageBridge;
 include protocol PMedia;
 include protocol PMemoryReportRequest;
 include protocol PNecko;
-// FIXME This is pretty ridiculous, but we have to keep the order of the
-//       following 4 includes, or the parser is confused about PGMPContent
-//       bridging PContent and PGMP. As soon as it registers the bridge between
-//       PContent and PPluginModule it seems to think that PContent's parent and
-//       child live in the same process!
 include protocol PGMPContent;
 include protocol PGMPService;
 include protocol PPluginModule;
 include protocol PGMP;
 include protocol PPrinting;
 include protocol PSendStream;
 include protocol POfflineCacheUpdate;
 include protocol PRenderFrame;
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -510,25 +510,23 @@ mozilla::ipc::IPCResult
 GMPChild::RecvCloseActive()
 {
   for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) {
     mGMPContentChildren[i - 1]->CloseActive();
   }
   return IPC_OK();
 }
 
-PGMPContentChild*
-GMPChild::AllocPGMPContentChild(Transport* aTransport,
-                                ProcessId aOtherPid)
+mozilla::ipc::IPCResult
+GMPChild::RecvInitGMPContentChild(Endpoint<PGMPContentChild>&& aEndpoint)
 {
   GMPContentChild* child =
     mGMPContentChildren.AppendElement(new GMPContentChild(this))->get();
-  child->Open(aTransport, aOtherPid, XRE_GetIOMessageLoop(), ipc::ChildSide);
-
-  return child;
+  aEndpoint.Bind(child);
+  return IPC_OK();
 }
 
 void
 GMPChild::GMPContentChildActorDestroy(GMPContentChild* aGMPContentChild)
 {
   for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) {
     UniquePtr<GMPContentChild>& toDestroy = mGMPContentChildren[i - 1];
     if (toDestroy.get() == aGMPContentChild) {
--- a/dom/media/gmp/GMPChild.h
+++ b/dom/media/gmp/GMPChild.h
@@ -51,23 +51,23 @@ private:
   bool DeallocPCrashReporterChild(PCrashReporterChild*) override;
 
   PGMPTimerChild* AllocPGMPTimerChild() override;
   bool DeallocPGMPTimerChild(PGMPTimerChild* aActor) override;
 
   PGMPStorageChild* AllocPGMPStorageChild() override;
   bool DeallocPGMPStorageChild(PGMPStorageChild* aActor) override;
 
-  PGMPContentChild* AllocPGMPContentChild(Transport* aTransport,
-                                          ProcessId aOtherPid) override;
   void GMPContentChildActorDestroy(GMPContentChild* aGMPContentChild);
 
   mozilla::ipc::IPCResult RecvCrashPluginNow() override;
   mozilla::ipc::IPCResult RecvCloseActive() override;
 
+  mozilla::ipc::IPCResult RecvInitGMPContentChild(Endpoint<PGMPContentChild>&& aEndpoint) override;
+
   void ActorDestroy(ActorDestroyReason aWhy) override;
   void ProcessingError(Result aCode, const char* aReason) override;
 
   GMPErr GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI, uint32_t aDecryptorId = 0);
 
   nsTArray<UniquePtr<GMPContentChild>> mGMPContentChildren;
 
   RefPtr<GMPTimerChild> mTimerChild;
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -872,29 +872,42 @@ GMPParent::ResolveGetContentParentPromis
   promises.SwapElements(mGetContentParentPromises);
   MOZ_ASSERT(mGetContentParentPromises.IsEmpty());
   RefPtr<GMPContentParent::CloseBlocker> blocker(new GMPContentParent::CloseBlocker(mGMPContentParent));
   for (auto& holder : promises) {
     holder->Resolve(blocker, __func__);
   }
 }
 
-PGMPContentParent*
-GMPParent::AllocPGMPContentParent(Transport* aTransport, ProcessId aOtherPid)
+bool
+GMPParent::OpenPGMPContent()
 {
   MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
   MOZ_ASSERT(!mGMPContentParent);
 
+  Endpoint<PGMPContentParent> parent;
+  Endpoint<PGMPContentChild> child;
+  if (NS_FAILED(PGMPContent::CreateEndpoints(base::GetCurrentProcId(),
+                                             OtherPid(), &parent, &child))) {
+    return false;
+  }
+
   mGMPContentParent = new GMPContentParent(this);
-  mGMPContentParent->Open(aTransport, aOtherPid, XRE_GetIOMessageLoop(),
-                          ipc::ParentSide);
+
+  if (!parent.Bind(mGMPContentParent)) {
+    return false;
+  }
+
+  if (!SendInitGMPContentChild(Move(child))) {
+    return false;
+  }
 
   ResolveGetContentParentPromises();
 
-  return mGMPContentParent;
+  return true;
 }
 
 void
 GMPParent::RejectGetContentParentPromises()
 {
   nsTArray<UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>>> promises;
   promises.SwapElements(mGetContentParentPromises);
   MOZ_ASSERT(mGetContentParentPromises.IsEmpty());
@@ -915,17 +928,17 @@ GMPParent::GetGMPContentParent(UniquePtr
   } else {
     mGetContentParentPromises.AppendElement(Move(aPromiseHolder));
     // If we don't have a GMPContentParent and we try to get one for the first
     // time (mGetContentParentPromises.Length() == 1) then call PGMPContent::Open. If more
     // calls to GetGMPContentParent happen before mGMPContentParent has been
     // set then we should just store them, so that they get called when we set
     // mGMPContentParent as a result of the PGMPContent::Open call.
     if (mGetContentParentPromises.Length() == 1) {
-      if (!EnsureProcessLoaded() || !PGMPContent::Open(this)) {
+      if (!EnsureProcessLoaded() || !OpenPGMPContent()) {
         RejectGetContentParentPromises();
         return;
       }
       // We want to increment this as soon as possible, to avoid that we'd try
       // to shut down the GMP process while we're still trying to get a
       // PGMPContentParent actor.
       ++mGMPContentChildCount;
     }
@@ -944,24 +957,20 @@ GMPParent::EnsureProcessLoaded(base::Pro
 {
   if (!EnsureProcessLoaded()) {
     return false;
   }
   *aID = OtherPid();
   return true;
 }
 
-bool
-GMPParent::Bridge(GMPServiceParent* aGMPServiceParent)
+void
+GMPParent::IncrementGMPContentChildCount()
 {
-  if (NS_FAILED(PGMPContent::Bridge(aGMPServiceParent, this))) {
-    return false;
-  }
   ++mGMPContentChildCount;
-  return true;
 }
 
 nsString
 GMPParent::GetPluginBaseName() const
 {
   return NS_LITERAL_STRING("gmp-") + mName;
 }
 
--- a/dom/media/gmp/GMPParent.h
+++ b/dom/media/gmp/GMPParent.h
@@ -139,22 +139,24 @@ public:
     return nsCOMPtr<nsIFile>(mDirectory).forget();
   }
 
   void AbortAsyncShutdown();
 
   // Called when the child process has died.
   void ChildTerminated();
 
+  bool OpenPGMPContent();
+
   void GetGMPContentParent(UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>>&& aPromiseHolder);
   already_AddRefed<GMPContentParent> ForgetGMPContentParent();
 
   bool EnsureProcessLoaded(base::ProcessId* aID);
 
-  bool Bridge(GMPServiceParent* aGMPServiceParent);
+  void IncrementGMPContentChildCount();
 
   const nsTArray<GMPCapability>& GetCapabilities() const { return mCapabilities; }
 
 private:
   ~GMPParent();
 
   RefPtr<GeckoMediaPluginServiceParent> mService;
   bool EnsureProcessLoaded();
@@ -170,19 +172,16 @@ private:
 
   PCrashReporterParent* AllocPCrashReporterParent(const NativeThreadId& aThread) override;
   bool DeallocPCrashReporterParent(PCrashReporterParent* aCrashReporter) override;
 
   mozilla::ipc::IPCResult RecvPGMPStorageConstructor(PGMPStorageParent* actor) override;
   PGMPStorageParent* AllocPGMPStorageParent() override;
   bool DeallocPGMPStorageParent(PGMPStorageParent* aActor) override;
 
-  PGMPContentParent* AllocPGMPContentParent(Transport* aTransport,
-                                            ProcessId aOtherPid) override;
-
   mozilla::ipc::IPCResult RecvPGMPTimerConstructor(PGMPTimerParent* actor) override;
   PGMPTimerParent* AllocPGMPTimerParent() override;
   bool DeallocPGMPTimerParent(PGMPTimerParent* aActor) override;
 
   mozilla::ipc::IPCResult RecvPGMPContentChildDestroyed() override;
   bool IsUsed()
   {
     return mGMPContentChildCount > 0 ||
--- a/dom/media/gmp/GMPServiceChild.cpp
+++ b/dom/media/gmp/GMPServiceChild.cpp
@@ -75,45 +75,50 @@ GeckoMediaPluginServiceChild::GetContent
       nsresult rv;
 
       nsTArray<base::ProcessId> alreadyBridgedTo;
       child->GetAlreadyBridgedTo(alreadyBridgedTo);
 
       base::ProcessId otherProcess;
       nsCString displayName;
       uint32_t pluginId = 0;
+      ipc::Endpoint<PGMPContentParent> endpoint;
+
       bool ok = child->SendLaunchGMP(nodeId,
                                      api,
                                      tags,
                                      alreadyBridgedTo,
                                      &pluginId,
                                      &otherProcess,
                                      &displayName,
+                                     &endpoint,
                                      &rv);
+
       if (helper && pluginId) {
         // Note: Even if the launch failed, we need to connect the crash
         // helper so that if the launch failed due to the plugin crashing,
         // we can report the crash via the crash reporter. The crash
         // handling notification will arrive shortly if the launch failed
         // due to the plugin crashing.
         self->ConnectCrashHelper(pluginId, helper);
       }
 
       if (!ok || NS_FAILED(rv)) {
         LOGD(("GeckoMediaPluginServiceChild::GetContentParent SendLaunchGMP failed rv=%d", rv));
         holder->Reject(rv, __func__);
         return;
       }
 
-      RefPtr<GMPContentParent> parent;
-      child->GetBridgedGMPContentParent(otherProcess, getter_AddRefs(parent));
+      RefPtr<GMPContentParent> parent = child->GetBridgedGMPContentParent(otherProcess,
+                                                                          Move(endpoint));
       if (!alreadyBridgedTo.Contains(otherProcess)) {
         parent->SetDisplayName(displayName);
         parent->SetPluginId(pluginId);
       }
+
       RefPtr<GMPContentParent::CloseBlocker> blocker(new GMPContentParent::CloseBlocker(parent));
       holder->Resolve(blocker, __func__);
     },
     [rawHolder](nsresult rv) {
       UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>> holder(rawHolder);
       holder->Reject(rv, __func__);
     });
 
@@ -334,41 +339,40 @@ GeckoMediaPluginServiceChild::RemoveGMPC
 GMPServiceChild::GMPServiceChild()
 {
 }
 
 GMPServiceChild::~GMPServiceChild()
 {
 }
 
-PGMPContentParent*
-GMPServiceChild::AllocPGMPContentParent(Transport* aTransport,
-                                        ProcessId aOtherPid)
+already_AddRefed<GMPContentParent>
+GMPServiceChild::GetBridgedGMPContentParent(ProcessId aOtherPid,
+                                            ipc::Endpoint<PGMPContentParent>&& endpoint)
 {
-  MOZ_ASSERT(!mContentParents.GetWeak(aOtherPid));
+  RefPtr<GMPContentParent> parent;
+  mContentParents.Get(aOtherPid, getter_AddRefs(parent));
+
+  if (parent) {
+    return parent.forget();
+  }
+
+  MOZ_ASSERT(aOtherPid == endpoint.OtherPid());
 
   nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
   MOZ_ASSERT(mainThread);
 
-  RefPtr<GMPContentParent> parent = new GMPContentParent();
+  parent = new GMPContentParent();
 
-  DebugOnly<bool> ok = parent->Open(aTransport, aOtherPid,
-                                    XRE_GetIOMessageLoop(),
-                                    mozilla::ipc::ParentSide);
+  DebugOnly<bool> ok = endpoint.Bind(parent);
   MOZ_ASSERT(ok);
 
   mContentParents.Put(aOtherPid, parent);
-  return parent;
-}
 
-void
-GMPServiceChild::GetBridgedGMPContentParent(ProcessId aOtherPid,
-                                            GMPContentParent** aGMPContentParent)
-{
-  mContentParents.Get(aOtherPid, aGMPContentParent);
+  return parent.forget();
 }
 
 void
 GMPServiceChild::RemoveGMPContentParent(GMPContentParent* aGMPContentParent)
 {
   for (auto iter = mContentParents.Iter(); !iter.Done(); iter.Next()) {
     RefPtr<GMPContentParent>& parent = iter.Data();
     if (parent == aGMPContentParent) {
--- a/dom/media/gmp/GMPServiceChild.h
+++ b/dom/media/gmp/GMPServiceChild.h
@@ -65,21 +65,19 @@ private:
 };
 
 class GMPServiceChild : public PGMPServiceChild
 {
 public:
   explicit GMPServiceChild();
   virtual ~GMPServiceChild();
 
-  PGMPContentParent* AllocPGMPContentParent(Transport* aTransport,
-                                            ProcessId aOtherPid) override;
+  already_AddRefed<GMPContentParent> GetBridgedGMPContentParent(ProcessId aOtherPid,
+                                                                ipc::Endpoint<PGMPContentParent>&& endpoint);
 
-  void GetBridgedGMPContentParent(ProcessId aOtherPid,
-                                  GMPContentParent** aGMPContentParent);
   void RemoveGMPContentParent(GMPContentParent* aGMPContentParent);
 
   void GetAlreadyBridgedTo(nsTArray<ProcessId>& aAlreadyBridgedTo);
 
   static PGMPServiceChild* Create(Transport* aTransport, ProcessId aOtherPid);
 
 private:
   nsRefPtrHashtable<nsUint64HashKey, GMPContentParent> mContentParents;
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -1670,16 +1670,17 @@ GMPServiceParent::~GMPServiceParent()
 mozilla::ipc::IPCResult
 GMPServiceParent::RecvLaunchGMP(const nsCString& aNodeId,
                                 const nsCString& aAPI,
                                 nsTArray<nsCString>&& aTags,
                                 nsTArray<ProcessId>&& aAlreadyBridgedTo,
                                 uint32_t* aOutPluginId,
                                 ProcessId* aOutProcessId,
                                 nsCString* aOutDisplayName,
+                                Endpoint<PGMPContentParent>* aOutEndpoint,
                                 nsresult* aOutRv)
 {
   if (mService->IsShuttingDown()) {
     *aOutRv = NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
     return IPC_OK();
   }
 
   RefPtr<GMPParent> gmp = mService->SelectPluginForAPI(aNodeId, aAPI, aTags);
@@ -1693,21 +1694,38 @@ GMPServiceParent::RecvLaunchGMP(const ns
 
   if (!gmp->EnsureProcessLoaded(aOutProcessId)) {
     *aOutRv = NS_ERROR_FAILURE;
     return IPC_OK();
   }
 
   *aOutDisplayName = gmp->GetDisplayName();
 
-  if (!(aAlreadyBridgedTo.Contains(*aOutProcessId) || gmp->Bridge(this))) {
+  if (aAlreadyBridgedTo.Contains(*aOutProcessId)) {
+    *aOutRv = NS_OK;
+    return IPC_OK();
+  }
+
+  Endpoint<PGMPContentParent> parent;
+  Endpoint<PGMPContentChild> child;
+  if (NS_FAILED(PGMPContent::CreateEndpoints(OtherPid(), *aOutProcessId,
+                                             &parent, &child))) {
     *aOutRv = NS_ERROR_FAILURE;
     return IPC_OK();
   }
 
+  *aOutEndpoint = Move(parent);
+
+  if (!gmp->SendInitGMPContentChild(Move(child))) {
+    *aOutRv = NS_ERROR_FAILURE;
+    return IPC_OK();
+  }
+
+  gmp->IncrementGMPContentChildCount();
+
   *aOutRv = NS_OK;
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 GMPServiceParent::RecvGetGMPNodeId(const nsString& aOrigin,
                                    const nsString& aTopLevelOrigin,
                                    const nsString& aGMPName,
--- a/dom/media/gmp/GMPServiceParent.h
+++ b/dom/media/gmp/GMPServiceParent.h
@@ -229,16 +229,17 @@ public:
 
   mozilla::ipc::IPCResult RecvLaunchGMP(const nsCString& aNodeId,
                                         const nsCString& aAPI,
                                         nsTArray<nsCString>&& aTags,
                                         nsTArray<ProcessId>&& aAlreadyBridgedTo,
                                         uint32_t* aOutPluginId,
                                         ProcessId* aOutID,
                                         nsCString* aOutDisplayName,
+                                        Endpoint<PGMPContentParent>* aOutEndpoint,
                                         nsresult* aOutRv) override;
 
 private:
   void CloseTransport(Monitor* aSyncMonitor, bool* aCompleted);
 
   RefPtr<GeckoMediaPluginServiceParent> mService;
 };
 
--- a/dom/media/gmp/PGMP.ipdl
+++ b/dom/media/gmp/PGMP.ipdl
@@ -10,18 +10,16 @@ include protocol PGMPStorage;
 
 using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 
 namespace mozilla {
 namespace gmp {
 
 intr protocol PGMP
 {
-  parent opens PGMPContent;
-
   manages PCrashReporter;
   manages PGMPTimer;
   manages PGMPStorage;
 
 parent:
   async PCrashReporter(NativeThreadId tid);
   async PGMPTimer();
   async PGMPStorage();
@@ -29,12 +27,13 @@ parent:
   async PGMPContentChildDestroyed();
 
 child:
   async CrashPluginNow();
   intr StartPlugin(nsString adapter);
   async SetNodeId(nsCString nodeId);
   async PreloadLibs(nsCString libs);
   async CloseActive();
+  async InitGMPContentChild(Endpoint<PGMPContentChild> endpoint);
 };
 
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gmp/PGMPContent.ipdl
+++ b/dom/media/gmp/PGMPContent.ipdl
@@ -1,26 +1,22 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-include protocol PGMP;
-include protocol PGMPService;
 include protocol PGMPVideoDecoder;
 include protocol PGMPVideoEncoder;
 include protocol PGMPDecryptor;
 
 namespace mozilla {
 namespace gmp {
 
 intr protocol PGMPContent
 {
-  bridges PGMPService, PGMP;
-
   manages PGMPDecryptor;
   manages PGMPVideoDecoder;
   manages PGMPVideoEncoder;
 
 child:
   async PGMPDecryptor();
   async PGMPVideoDecoder(uint32_t aDecryptorId);
   async PGMPVideoEncoder();
--- a/dom/media/gmp/PGMPService.ipdl
+++ b/dom/media/gmp/PGMPService.ipdl
@@ -1,30 +1,31 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-include protocol PGMP;
+include protocol PGMPContent;
 
 using base::ProcessId from "base/process.h";
 
 namespace mozilla {
 namespace gmp {
 
 sync protocol PGMPService
 {
-  parent spawns PGMP as child;
-
 parent:
-
   sync LaunchGMP(nsCString nodeId,
                  nsCString api,
                  nsCString[] tags,
                  ProcessId[] alreadyBridgedTo)
-    returns (uint32_t pluginId, ProcessId id, nsCString displayName, nsresult aResult);
+    returns (uint32_t pluginId,
+             ProcessId id,
+             nsCString displayName,
+             Endpoint<PGMPContentParent> endpoint,
+             nsresult aResult);
 
   sync GetGMPNodeId(nsString origin, nsString topLevelOrigin, nsString gmpName)
     returns (nsCString id);
 };
 
 } // namespace gmp
 } // namespace mozilla