Bug 1315850 - Add GMPService::GetContentChild() with unresolved NodeId. r=gerald
We currently do two sync IPCs to launch a GMP; one from content to main process
to get the nodeId and a second to get a GMPContentParent for that nodeId.
We use the nodeIds to ensure that the GMPVideoDecoder and GMPDecryptor actors
correspond to the same CDM instance/process. However once we switch to having
one protocol that encompasses both decryption and decoding, we don't need to
worry about making sure our decoder and decryptor actors match up, as we only
have one underlying connection to the CDM instance.
So we can merge the get nodeId and get GMPContentParent operations into a
single operation that does both. To do this, we just need to pass the
parameters used to calculate the nodeId in the LaunchGMP message.
Once we've switched EME over to using the CDM via a single actor, we can remove
the nodeId nsCString from our media code and from GMPVideoDecoder and
GMPVideoEncoder.
MozReview-Commit-ID: 7GXlJ37fOTZ
--- a/dom/media/gmp/GMPService.h
+++ b/dom/media/gmp/GMPService.h
@@ -30,16 +30,23 @@ template <class> struct already_AddRefed
namespace mozilla {
class GMPCrashHelper;
extern LogModule* GetGMPLog();
namespace gmp {
+struct NodeId
+{
+ nsString mOrigin;
+ nsString mTopLevelOrigin;
+ nsString mGMPName;
+};
+
typedef MozPromise<RefPtr<GMPContentParent::CloseBlocker>, nsresult, /* IsExclusive = */ true> GetGMPContentParentPromise;
class GeckoMediaPluginService : public mozIGeckoMediaPluginService
, public nsIObserver
{
public:
static already_AddRefed<GeckoMediaPluginService> GetGeckoMediaPluginService();
@@ -85,21 +92,27 @@ public:
void DisconnectCrashHelper(GMPCrashHelper* aHelper);
protected:
GeckoMediaPluginService();
virtual ~GeckoMediaPluginService();
virtual void InitializePlugins(AbstractThread* aAbstractGMPThread) = 0;
- virtual RefPtr<GetGMPContentParentPromise>
- GetContentParent(GMPCrashHelper* aHelper,
- const nsACString& aNodeId,
- const nsCString& aAPI,
- const nsTArray<nsCString>& aTags) = 0;
+ virtual RefPtr<GetGMPContentParentPromise> GetContentParent(
+ GMPCrashHelper* aHelper,
+ const nsACString& aNodeIdString,
+ const nsCString& aAPI,
+ const nsTArray<nsCString>& aTags) = 0;
+
+ virtual RefPtr<GetGMPContentParentPromise> GetContentParent(
+ GMPCrashHelper* aHelper,
+ const NodeId& aNodeId,
+ const nsCString& aAPI,
+ const nsTArray<nsCString>& aTags) = 0;
nsresult GMPDispatch(nsIRunnable* event, uint32_t flags = NS_DISPATCH_NORMAL);
nsresult GMPDispatch(already_AddRefed<nsIRunnable> event, uint32_t flags = NS_DISPATCH_NORMAL);
void ShutdownGMPThread();
Mutex mMutex; // Protects mGMPThread, mAbstractGMPThread, mPluginCrashHelpers,
// mGMPThreadShutdown and some members in derived classes.
nsCOMPtr<nsIThread> mGMPThread;
--- a/dom/media/gmp/GMPServiceChild.cpp
+++ b/dom/media/gmp/GMPServiceChild.cpp
@@ -49,27 +49,103 @@ GeckoMediaPluginServiceChild::GetSinglet
MOZ_ASSERT(!chromeService);
}
#endif
return service.forget().downcast<GeckoMediaPluginServiceChild>();
}
RefPtr<GetGMPContentParentPromise>
GeckoMediaPluginServiceChild::GetContentParent(GMPCrashHelper* aHelper,
- const nsACString& aNodeId,
+ const nsACString& aNodeIdString,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
MozPromiseHolder<GetGMPContentParentPromise>* rawHolder = new MozPromiseHolder<GetGMPContentParentPromise>();
RefPtr<GetGMPContentParentPromise> promise = rawHolder->Ensure(__func__);
RefPtr<AbstractThread> thread(GetAbstractGMPThread());
- nsCString nodeId(aNodeId);
+ nsCString nodeIdString(aNodeIdString);
+ nsCString api(aAPI);
+ nsTArray<nsCString> tags(aTags);
+ RefPtr<GMPCrashHelper> helper(aHelper);
+ RefPtr<GeckoMediaPluginServiceChild> self(this);
+ GetServiceChild()->Then(
+ thread,
+ __func__,
+ [self, nodeIdString, api, tags, helper, rawHolder](GMPServiceChild* child) {
+ UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>> holder(rawHolder);
+ 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(nodeIdString,
+ 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=0x%x",
+ static_cast<uint32_t>(rv)));
+ holder->Reject(rv, __func__);
+ return;
+ }
+
+ 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__);
+ });
+
+ return promise;
+}
+
+RefPtr<GetGMPContentParentPromise>
+GeckoMediaPluginServiceChild::GetContentParent(GMPCrashHelper* aHelper,
+ const NodeId& aNodeId,
+ const nsCString& aAPI,
+ const nsTArray<nsCString>& aTags)
+{
+ MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
+
+ MozPromiseHolder<GetGMPContentParentPromise>* rawHolder =
+ new MozPromiseHolder<GetGMPContentParentPromise>();
+ RefPtr<GetGMPContentParentPromise> promise = rawHolder->Ensure(__func__);
+ RefPtr<AbstractThread> thread(GetAbstractGMPThread());
+
+ NodeIdData nodeId(aNodeId.mOrigin, aNodeId.mTopLevelOrigin, aNodeId.mGMPName);
nsCString api(aAPI);
nsTArray<nsCString> tags(aTags);
RefPtr<GMPCrashHelper> helper(aHelper);
RefPtr<GeckoMediaPluginServiceChild> self(this);
GetServiceChild()->Then(thread, __func__,
[self, nodeId, api, tags, helper, rawHolder](GMPServiceChild* child) {
UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>> holder(rawHolder);
nsresult rv;
@@ -77,25 +153,25 @@ GeckoMediaPluginServiceChild::GetContent
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);
+ bool ok = child->SendLaunchGMPForNodeId(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);
--- a/dom/media/gmp/GMPServiceChild.h
+++ b/dom/media/gmp/GMPServiceChild.h
@@ -43,21 +43,27 @@ public:
static void UpdateGMPCapabilities(nsTArray<mozilla::dom::GMPCapabilityData>&& aCapabilities);
protected:
void InitializePlugins(AbstractThread*) override
{
// Nothing to do here.
}
- virtual RefPtr<GetGMPContentParentPromise>
- GetContentParent(GMPCrashHelper* aHelper,
- const nsACString& aNodeId,
- const nsCString& aAPI,
- const nsTArray<nsCString>& aTags) override;
+ virtual RefPtr<GetGMPContentParentPromise> GetContentParent(
+ GMPCrashHelper* aHelper,
+ const nsACString& aNodeIdString,
+ const nsCString& aAPI,
+ const nsTArray<nsCString>& aTags) override;
+
+ RefPtr<GetGMPContentParentPromise> GetContentParent(
+ GMPCrashHelper* aHelper,
+ const NodeId& aNodeId,
+ const nsCString& aAPI,
+ const nsTArray<nsCString>& aTags) override;
private:
friend class OpenPGMPServiceChild;
typedef MozPromise<GMPServiceChild*, nsresult, /* IsExclusive = */ true> GetServiceChildPromise;
RefPtr<GetServiceChildPromise> GetServiceChild();
nsTArray<MozPromiseHolder<GetServiceChildPromise>> mGetServiceChildPromises;
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -348,38 +348,41 @@ GeckoMediaPluginServiceParent::EnsureIni
return GenericPromise::CreateAndResolve(true, __func__);
}
// We should have an init promise in flight.
MOZ_ASSERT(!mInitPromise.IsEmpty());
return mInitPromise.Ensure(__func__);
}
RefPtr<GetGMPContentParentPromise>
-GeckoMediaPluginServiceParent::GetContentParent(GMPCrashHelper* aHelper,
- const nsACString& aNodeId,
- const nsCString& aAPI,
- const nsTArray<nsCString>& aTags)
+GeckoMediaPluginServiceParent::GetContentParent(
+ GMPCrashHelper* aHelper,
+ const nsACString& aNodeIdString,
+ const nsCString& aAPI,
+ const nsTArray<nsCString>& aTags)
{
RefPtr<AbstractThread> thread(GetAbstractGMPThread());
if (!thread) {
return GetGMPContentParentPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
typedef MozPromiseHolder<GetGMPContentParentPromise> PromiseHolder;
PromiseHolder* rawHolder = new PromiseHolder();
RefPtr<GeckoMediaPluginServiceParent> self(this);
RefPtr<GetGMPContentParentPromise> promise = rawHolder->Ensure(__func__);
- nsCString nodeId(aNodeId);
+ nsCString nodeIdString(aNodeIdString);
nsTArray<nsCString> tags(aTags);
nsCString api(aAPI);
RefPtr<GMPCrashHelper> helper(aHelper);
- EnsureInitialized()->Then(thread, __func__,
- [self, tags, api, nodeId, helper, rawHolder]() -> void {
+ EnsureInitialized()->Then(
+ thread,
+ __func__,
+ [self, tags, api, nodeIdString, helper, rawHolder]() -> void {
UniquePtr<PromiseHolder> holder(rawHolder);
- RefPtr<GMPParent> gmp = self->SelectPluginForAPI(nodeId, api, tags);
+ RefPtr<GMPParent> gmp = self->SelectPluginForAPI(nodeIdString, api, tags);
LOGD(("%s: %p returning %p for api %s", __FUNCTION__, (void *)self, (void *)gmp, api.get()));
if (!gmp) {
NS_WARNING("GeckoMediaPluginServiceParent::GetContentParentFrom failed");
holder->Reject(NS_ERROR_FAILURE, __func__);
return;
}
self->ConnectCrashHelper(gmp->GetPluginId(), helper);
gmp->GetGMPContentParent(Move(holder));
@@ -388,16 +391,35 @@ GeckoMediaPluginServiceParent::GetConten
UniquePtr<PromiseHolder> holder(rawHolder);
NS_WARNING("GMPService::EnsureInitialized failed.");
holder->Reject(NS_ERROR_FAILURE, __func__);
});
return promise;
}
+RefPtr<GetGMPContentParentPromise>
+GeckoMediaPluginServiceParent::GetContentParent(
+ GMPCrashHelper* aHelper,
+ const NodeId& aNodeId,
+ const nsCString& aAPI,
+ const nsTArray<nsCString>& aTags)
+{
+ MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
+
+ nsCString nodeIdString;
+ nsresult rv = GetNodeId(
+ aNodeId.mOrigin, aNodeId.mTopLevelOrigin, aNodeId.mGMPName, nodeIdString);
+ if (NS_FAILED(rv)) {
+ return GetGMPContentParentPromise::CreateAndReject(NS_ERROR_FAILURE,
+ __func__);
+ }
+ return GetContentParent(aHelper, nodeIdString, aAPI, aTags);
+}
+
void
GeckoMediaPluginServiceParent::InitializePlugins(
AbstractThread* aAbstractGMPThread)
{
MOZ_ASSERT(aAbstractGMPThread);
MonitorAutoLock lock(mInitPromiseMonitor);
if (mLoadPluginsFromDiskComplete) {
return;
@@ -1732,16 +1754,46 @@ GMPServiceParent::RecvLaunchGMP(const ns
gmp->IncrementGMPContentChildCount();
*aOutRv = NS_OK;
return IPC_OK();
}
mozilla::ipc::IPCResult
+GMPServiceParent::RecvLaunchGMPForNodeId(
+ const NodeIdData& aNodeId,
+ const nsCString& aApi,
+ nsTArray<nsCString>&& aTags,
+ nsTArray<ProcessId>&& aAlreadyBridgedTo,
+ uint32_t* aOutPluginId,
+ ProcessId* aOutId,
+ nsCString* aOutDisplayName,
+ Endpoint<PGMPContentParent>* aOutEndpoint,
+ nsresult* aOutRv)
+{
+ nsCString nodeId;
+ nsresult rv = mService->GetNodeId(
+ aNodeId.mOrigin(), aNodeId.mTopLevelOrigin(), aNodeId.mGMPName(), nodeId);
+ if (!NS_SUCCEEDED(rv)) {
+ *aOutRv = rv;
+ return IPC_OK();
+ }
+ return RecvLaunchGMP(nodeId,
+ aApi,
+ Move(aTags),
+ Move(aAlreadyBridgedTo),
+ aOutPluginId,
+ aOutId,
+ aOutDisplayName,
+ aOutEndpoint,
+ aOutRv);
+}
+
+mozilla::ipc::IPCResult
GMPServiceParent::RecvGetGMPNodeId(const nsString& aOrigin,
const nsString& aTopLevelOrigin,
const nsString& aGMPName,
nsCString* aID)
{
nsresult rv = mService->GetNodeId(aOrigin, aTopLevelOrigin, aGMPName, *aID);
if (!NS_SUCCEEDED(rv)) {
return IPC_FAIL_NO_REASON(this);
--- a/dom/media/gmp/GMPServiceParent.h
+++ b/dom/media/gmp/GMPServiceParent.h
@@ -112,21 +112,27 @@ private:
protected:
friend class GMPParent;
void ReAddOnGMPThread(const RefPtr<GMPParent>& aOld);
void PluginTerminated(const RefPtr<GMPParent>& aOld);
void InitializePlugins(AbstractThread* aAbstractGMPThread) override;
RefPtr<GenericPromise::AllPromiseType> LoadFromEnvironment();
RefPtr<GenericPromise> AddOnGMPThread(nsString aDirectory);
- virtual RefPtr<GetGMPContentParentPromise>
- GetContentParent(GMPCrashHelper* aHelper,
- const nsACString& aNodeId,
- const nsCString& aAPI,
- const nsTArray<nsCString>& aTags) override;
+ virtual RefPtr<GetGMPContentParentPromise> GetContentParent(
+ GMPCrashHelper* aHelper,
+ const nsACString& aNodeIdString,
+ const nsCString& aAPI,
+ const nsTArray<nsCString>& aTags) override;
+
+ RefPtr<GetGMPContentParentPromise> GetContentParent(
+ GMPCrashHelper* aHelper,
+ const NodeId& aNodeId,
+ const nsCString& aAPI,
+ const nsTArray<nsCString>& aTags) override;
private:
// Creates a copy of aOriginal. Note that the caller is responsible for
// adding this to GeckoMediaPluginServiceParent::mPlugins.
already_AddRefed<GMPParent> ClonePlugin(const GMPParent* aOriginal);
nsresult EnsurePluginsOnDiskScanned();
nsresult InitStorage();
@@ -218,33 +224,44 @@ class GMPServiceParent final : public PG
public:
explicit GMPServiceParent(GeckoMediaPluginServiceParent* aService)
: mService(aService)
{
mService->ServiceUserCreated();
}
virtual ~GMPServiceParent();
- mozilla::ipc::IPCResult RecvGetGMPNodeId(const nsString& aOrigin,
- const nsString& aTopLevelOrigin,
- const nsString& aGMPName,
- nsCString* aID) override;
+ ipc::IPCResult RecvGetGMPNodeId(const nsString& aOrigin,
+ const nsString& aTopLevelOrigin,
+ const nsString& aGMPName,
+ nsCString* aID) override;
void ActorDestroy(ActorDestroyReason aWhy) override;
static bool Create(Endpoint<PGMPServiceParent>&& aGMPService);
- 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;
+ 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;
+
+ ipc::IPCResult RecvLaunchGMPForNodeId(
+ const NodeIdData& nodeId,
+ 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;
};
} // namespace gmp
--- a/dom/media/gmp/GMPTypes.ipdlh
+++ b/dom/media/gmp/GMPTypes.ipdlh
@@ -4,16 +4,22 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
using GMPBufferType from "gmp-video-codec.h";
using GMPMediaKeyStatus from "gmp-decryption.h";
namespace mozilla {
namespace gmp {
+struct NodeIdData {
+ nsString mOrigin;
+ nsString mTopLevelOrigin;
+ nsString mGMPName;
+};
+
struct GMPDecryptionData {
uint8_t[] mKeyId;
uint8_t[] mIV;
uint16_t[] mClearBytes;
uint32_t[] mCipherBytes;
nsCString[] mSessionIds;
};
--- a/dom/media/gmp/PGMPService.ipdl
+++ b/dom/media/gmp/PGMPService.ipdl
@@ -1,14 +1,15 @@
/* -*- 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 PGMPContent;
+include GMPTypes;
using base::ProcessId from "base/process.h";
namespace mozilla {
namespace gmp {
sync protocol PGMPService
{
@@ -18,14 +19,24 @@ parent:
nsCString[] tags,
ProcessId[] alreadyBridgedTo)
returns (uint32_t pluginId,
ProcessId id,
nsCString displayName,
Endpoint<PGMPContentParent> endpoint,
nsresult aResult);
+ sync LaunchGMPForNodeId(NodeIdData nodeId,
+ nsCString api,
+ nsCString[] tags,
+ ProcessId[] alreadyBridgedTo)
+ 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