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.
--- 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