--- a/dom/media/eme/CDMProxy.cpp
+++ b/dom/media/eme/CDMProxy.cpp
@@ -223,17 +223,17 @@ CDMProxy::gmp_InitGetGMPDecryptor(nsresu
(aData->mInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"),
GetNodeId().get());
nsTArray<nsCString> tags;
tags.AppendElement(NS_ConvertUTF16toUTF8(mKeySystem));
UniquePtr<GetGMPDecryptorCallback> callback(new gmp_InitDoneCallback(this,
Move(aData)));
- nsresult rv = mps->GetGMPDecryptor(&tags, GetNodeId(), Move(callback));
+ nsresult rv = mps->GetGMPDecryptor(nullptr, &tags, GetNodeId(), Move(callback));
if (NS_FAILED(rv)) {
RejectPromise(promiseID, NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Call to GetGMPDecryptor() failed early"));
}
}
void
CDMProxy::OnCDMCreated(uint32_t aPromiseId)
--- a/dom/media/gmp/GMPService.cpp
+++ b/dom/media/gmp/GMPService.cpp
@@ -271,30 +271,52 @@ GeckoMediaPluginService::AddPluginCrashe
}
NS_IMETHODIMP
GeckoMediaPluginService::RunPluginCrashCallbacks(uint32_t aPluginId,
const nsACString& aPluginName)
{
MOZ_ASSERT(NS_IsMainThread());
LOGD(("%s::%s(%i)", __CLASS__, __FUNCTION__, aPluginId));
- RemoveObsoletePluginCrashCallbacks();
+
+ nsAutoPtr<nsTArray<RefPtr<GMPCrashHelper>>> helpers;
+ {
+ MutexAutoLock lock(mMutex);
+ mPluginCrashHelpers.RemoveAndForget(aPluginId, helpers);
+ }
+ if (!helpers) {
+ LOGD(("%s::%s(%i) No crash helpers, not handling crash.", __CLASS__, __FUNCTION__, aPluginId));
+ return NS_OK;
+ }
- for (size_t i = mPluginCrashCallbacks.Length(); i != 0; --i) {
- RefPtr<GMPCrashCallback>& callback = mPluginCrashCallbacks[i - 1];
- if (callback->GetPluginId() == aPluginId) {
- LOGD(("%s::%s(%i) - Running #%u",
- __CLASS__, __FUNCTION__, aPluginId, i - 1));
- callback->Run(aPluginName);
- mPluginCrashCallbacks.RemoveElementAt(i - 1);
+ for (const auto& helper : *helpers) {
+ nsCOMPtr<nsPIDOMWindowInner> window = helper->GetPluginCrashedEventTarget();
+ if (NS_WARN_IF(!window)) {
+ continue;
+ }
+ nsCOMPtr<nsIDocument> document(window->GetExtantDoc());
+ if (NS_WARN_IF(!document)) {
+ continue;
}
- }
- mPluginCrashes.AppendElement(PluginCrash(aPluginId, aPluginName));
- if (mPluginCrashes.Length() > MAX_PLUGIN_CRASHES) {
- mPluginCrashes.RemoveElementAt(0);
+
+ dom::PluginCrashedEventInit init;
+ init.mPluginID = aPluginId;
+ init.mBubbles = true;
+ init.mCancelable = true;
+ init.mGmpPlugin = true;
+ CopyUTF8toUTF16(aPluginName, init.mPluginName);
+ init.mSubmittedCrashReport = false;
+ RefPtr<dom::PluginCrashedEvent> event =
+ dom::PluginCrashedEvent::Constructor(document,
+ NS_LITERAL_STRING("PluginCrashed"),
+ init);
+ event->SetTrusted(true);
+ event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
+
+ EventDispatcher::DispatchDOMEvent(window, nullptr, event, nullptr, nullptr);
}
return NS_OK;
}
nsresult
GeckoMediaPluginService::Init()
{
@@ -403,32 +425,36 @@ public:
mCallback->Done(gmpADP);
}
private:
UniquePtr<GetGMPAudioDecoderCallback> mCallback;
};
NS_IMETHODIMP
-GeckoMediaPluginService::GetGMPAudioDecoder(nsTArray<nsCString>* aTags,
+GeckoMediaPluginService::GetGMPAudioDecoder(GMPCrashHelper* aHelper,
+ nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPAudioDecoderCallback>&& aCallback)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
NS_ENSURE_ARG(aCallback);
if (mShuttingDownOnGMPThread) {
return NS_ERROR_FAILURE;
}
UniquePtr<GetGMPContentParentCallback> callback(
new GetGMPContentParentForAudioDecoderDone(Move(aCallback)));
- if (!GetContentParentFrom(aNodeId, NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
- *aTags, Move(callback))) {
+ if (!GetContentParentFrom(aHelper,
+ aNodeId,
+ NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
+ *aTags,
+ Move(callback))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
class GetGMPContentParentForVideoDecoderDone : public GetGMPContentParentCallback
{
@@ -448,32 +474,36 @@ public:
mCallback->Done(gmpVDP, videoHost);
}
private:
UniquePtr<GetGMPVideoDecoderCallback> mCallback;
};
NS_IMETHODIMP
-GeckoMediaPluginService::GetGMPVideoDecoder(nsTArray<nsCString>* aTags,
+GeckoMediaPluginService::GetGMPVideoDecoder(GMPCrashHelper* aHelper,
+ nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPVideoDecoderCallback>&& aCallback)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
NS_ENSURE_ARG(aCallback);
if (mShuttingDownOnGMPThread) {
return NS_ERROR_FAILURE;
}
UniquePtr<GetGMPContentParentCallback> callback(
new GetGMPContentParentForVideoDecoderDone(Move(aCallback)));
- if (!GetContentParentFrom(aNodeId, NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
- *aTags, Move(callback))) {
+ if (!GetContentParentFrom(aHelper,
+ aNodeId,
+ NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
+ *aTags,
+ Move(callback))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
class GetGMPContentParentForVideoEncoderDone : public GetGMPContentParentCallback
{
@@ -493,32 +523,36 @@ public:
mCallback->Done(gmpVEP, videoHost);
}
private:
UniquePtr<GetGMPVideoEncoderCallback> mCallback;
};
NS_IMETHODIMP
-GeckoMediaPluginService::GetGMPVideoEncoder(nsTArray<nsCString>* aTags,
+GeckoMediaPluginService::GetGMPVideoEncoder(GMPCrashHelper* aHelper,
+ nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPVideoEncoderCallback>&& aCallback)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
NS_ENSURE_ARG(aCallback);
if (mShuttingDownOnGMPThread) {
return NS_ERROR_FAILURE;
}
UniquePtr<GetGMPContentParentCallback> callback(
new GetGMPContentParentForVideoEncoderDone(Move(aCallback)));
- if (!GetContentParentFrom(aNodeId, NS_LITERAL_CSTRING(GMP_API_VIDEO_ENCODER),
- *aTags, Move(callback))) {
+ if (!GetContentParentFrom(aHelper,
+ aNodeId,
+ NS_LITERAL_CSTRING(GMP_API_VIDEO_ENCODER),
+ *aTags,
+ Move(callback))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
class GetGMPContentParentForDecryptorDone : public GetGMPContentParentCallback
{
@@ -537,17 +571,18 @@ public:
mCallback->Done(ksp);
}
private:
UniquePtr<GetGMPDecryptorCallback> mCallback;
};
NS_IMETHODIMP
-GeckoMediaPluginService::GetGMPDecryptor(nsTArray<nsCString>* aTags,
+GeckoMediaPluginService::GetGMPDecryptor(GMPCrashHelper* aHelper,
+ nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPDecryptorCallback>&& aCallback)
{
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
if (!SandboxInfo::Get().CanSandboxMedia()) {
NS_WARNING("GeckoMediaPluginService::GetGMPDecryptor: "
"EME decryption not available without sandboxing support.");
return NS_ERROR_NOT_AVAILABLE;
@@ -559,27 +594,66 @@ GeckoMediaPluginService::GetGMPDecryptor
NS_ENSURE_ARG(aCallback);
if (mShuttingDownOnGMPThread) {
return NS_ERROR_FAILURE;
}
UniquePtr<GetGMPContentParentCallback> callback(
new GetGMPContentParentForDecryptorDone(Move(aCallback)));
- if (!GetContentParentFrom(aNodeId, NS_LITERAL_CSTRING(GMP_API_DECRYPTOR),
- *aTags, Move(callback))) {
+ if (!GetContentParentFrom(aHelper,
+ aNodeId,
+ NS_LITERAL_CSTRING(GMP_API_DECRYPTOR),
+ *aTags,
+ Move(callback))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
GeckoMediaPluginService::HasPluginForAPI(const nsACString& aAPI,
nsTArray<nsCString>* aTags,
bool* aOutHavePlugin)
{
nsCString unused;
return GetPluginVersionForAPI(aAPI, aTags, aOutHavePlugin, unused);
}
+void
+GeckoMediaPluginService::ConnectCrashHelper(uint32_t aPluginId, GMPCrashHelper* aHelper)
+{
+ if (!aHelper) {
+ return;
+ }
+ MutexAutoLock lock(mMutex);
+ nsTArray<RefPtr<GMPCrashHelper>>* helpers;
+ if (!mPluginCrashHelpers.Get(aPluginId, &helpers)) {
+ helpers = new nsTArray<RefPtr<GMPCrashHelper>>();
+ mPluginCrashHelpers.Put(aPluginId, helpers);
+ } else if (helpers->Contains(aHelper)) {
+ return;
+ }
+ helpers->AppendElement(aHelper);
+}
+
+void GeckoMediaPluginService::DisconnectCrashHelper(GMPCrashHelper* aHelper)
+{
+ if (!aHelper) {
+ return;
+ }
+ MutexAutoLock lock(mMutex);
+ for (auto iter = mPluginCrashHelpers.Iter(); !iter.Done(); iter.Next()) {
+ nsTArray<RefPtr<GMPCrashHelper>>* helpers = iter.Data();
+ if (!helpers->Contains(aHelper)) {
+ continue;
+ }
+ helpers->RemoveElement(aHelper);
+ MOZ_ASSERT(!helpers->Contains(aHelper)); // Ensure there aren't duplicates.
+ if (helpers->IsEmpty()) {
+ iter.Remove();
+ }
+ }
+}
+
} // namespace gmp
} // namespace mozilla
--- a/dom/media/gmp/GMPService.h
+++ b/dom/media/gmp/GMPService.h
@@ -15,19 +15,32 @@
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsIThread.h"
#include "nsThreadUtils.h"
#include "nsPIDOMWindow.h"
#include "nsIDocument.h"
#include "nsIWeakReference.h"
#include "mozilla/AbstractThread.h"
+#include "nsClassHashtable.h"
template <class> struct already_AddRefed;
+// For every GMP actor requested, the caller can specify a crash helper,
+// which is an object which supplies the nsPIDOMWindowInner to which we'll
+// dispatch the PluginCrashed event if the GMP crashes.
+class GMPCrashHelper
+{
+public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPCrashHelper)
+ virtual already_AddRefed<nsPIDOMWindowInner> GetPluginCrashedEventTarget() = 0;
+protected:
+ virtual ~GMPCrashHelper() {}
+};
+
namespace mozilla {
extern LogModule* GetGMPLog();
namespace gmp {
class GetGMPContentParentCallback;
@@ -40,29 +53,33 @@ public:
virtual nsresult Init();
NS_DECL_THREADSAFE_ISUPPORTS
// mozIGeckoMediaPluginService
NS_IMETHOD GetThread(nsIThread** aThread) override;
NS_IMETHOD HasPluginForAPI(const nsACString& aAPI, nsTArray<nsCString>* aTags,
bool *aRetVal) override;
- NS_IMETHOD GetGMPVideoDecoder(nsTArray<nsCString>* aTags,
+ NS_IMETHOD GetGMPVideoDecoder(GMPCrashHelper* aHelper,
+ nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPVideoDecoderCallback>&& aCallback)
override;
- NS_IMETHOD GetGMPVideoEncoder(nsTArray<nsCString>* aTags,
+ NS_IMETHOD GetGMPVideoEncoder(GMPCrashHelper* aHelper,
+ nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPVideoEncoderCallback>&& aCallback)
override;
- NS_IMETHOD GetGMPAudioDecoder(nsTArray<nsCString>* aTags,
+ NS_IMETHOD GetGMPAudioDecoder(GMPCrashHelper* aHelper,
+ nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPAudioDecoderCallback>&& aCallback)
override;
- NS_IMETHOD GetGMPDecryptor(nsTArray<nsCString>* aTags,
+ NS_IMETHOD GetGMPDecryptor(GMPCrashHelper* aHelper,
+ nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPDecryptorCallback>&& aCallback)
override;
int32_t AsyncShutdownTimeoutMs();
NS_IMETHOD RunPluginCrashCallbacks(uint32_t aPluginId,
const nsACString& aPluginName) override;
@@ -70,33 +87,37 @@ public:
// Sets the window to which 'PluginCrashed' chromeonly event is dispatched.
// Note: if the plugin has crashed before the target window has been set,
// the 'PluginCrashed' event is dispatched as soon as a target window is set.
void AddPluginCrashedEventTarget(const uint32_t aPluginId,
nsPIDOMWindowInner* aParentWindow);
RefPtr<AbstractThread> GetAbstractGMPThread();
+ void ConnectCrashHelper(uint32_t aPluginId, GMPCrashHelper* aHelper);
+ void DisconnectCrashHelper(GMPCrashHelper* aHelper);
+
protected:
GeckoMediaPluginService();
virtual ~GeckoMediaPluginService();
void RemoveObsoletePluginCrashCallbacks(); // Called from add/run.
virtual void InitializePlugins(AbstractThread* aAbstractGMPThread) = 0;
- virtual bool GetContentParentFrom(const nsACString& aNodeId,
+ virtual bool GetContentParentFrom(GMPCrashHelper* aHelper,
+ const nsACString& aNodeId,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags,
UniquePtr<GetGMPContentParentCallback>&& aCallback) = 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 and
+ Mutex mMutex; // Protects mGMPThread, mAbstractGMPThread, mPluginCrashHelpers,
// mGMPThreadShutdown and some members in derived classes.
nsCOMPtr<nsIThread> mGMPThread;
RefPtr<AbstractThread> mAbstractGMPThread;
bool mGMPThreadShutdown;
bool mShuttingDownOnGMPThread;
class GMPCrashCallback
{
@@ -135,14 +156,16 @@ protected:
mPluginName == aOther.mPluginName;
}
};
static const size_t MAX_PLUGIN_CRASHES = 100;
nsTArray<PluginCrash> mPluginCrashes;
nsTArray<RefPtr<GMPCrashCallback>> mPluginCrashCallbacks;
+
+ nsClassHashtable<nsUint32HashKey, nsTArray<RefPtr<GMPCrashHelper>>> mPluginCrashHelpers;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPService_h_
--- a/dom/media/gmp/GMPServiceChild.cpp
+++ b/dom/media/gmp/GMPServiceChild.cpp
@@ -45,20 +45,21 @@ GeckoMediaPluginServiceChild::GetSinglet
}
#endif
return service.forget().downcast<GeckoMediaPluginServiceChild>();
}
class GetContentParentFromDone : public GetServiceChildCallback
{
public:
- GetContentParentFromDone(const nsACString& aNodeId, const nsCString& aAPI,
+ GetContentParentFromDone(GMPCrashHelper* aHelper, const nsACString& aNodeId, const nsCString& aAPI,
const nsTArray<nsCString>& aTags,
UniquePtr<GetGMPContentParentCallback>&& aCallback)
- : mNodeId(aNodeId),
+ : mHelper(aHelper),
+ mNodeId(aNodeId),
mAPI(aAPI),
mTags(aTags),
mCallback(Move(aCallback))
{
}
void Done(GMPServiceChild* aGMPServiceChild) override
{
@@ -70,16 +71,21 @@ public:
uint32_t pluginId;
nsresult rv;
bool ok = aGMPServiceChild->SendSelectGMP(mNodeId, mAPI, mTags, &pluginId, &rv);
if (!ok || rv == NS_ERROR_ILLEGAL_DURING_SHUTDOWN) {
mCallback->Done(nullptr);
return;
}
+ if (mHelper) {
+ RefPtr<GeckoMediaPluginService> gmps(GeckoMediaPluginService::GetGeckoMediaPluginService());
+ gmps->ConnectCrashHelper(pluginId, mHelper);
+ }
+
nsTArray<base::ProcessId> alreadyBridgedTo;
aGMPServiceChild->GetAlreadyBridgedTo(alreadyBridgedTo);
base::ProcessId otherProcess;
nsCString displayName;
ok = aGMPServiceChild->SendLaunchGMP(pluginId, alreadyBridgedTo, &otherProcess,
&displayName, &rv);
if (!ok || rv == NS_ERROR_ILLEGAL_DURING_SHUTDOWN) {
@@ -94,32 +100,34 @@ public:
parent->SetDisplayName(displayName);
parent->SetPluginId(pluginId);
}
mCallback->Done(parent);
}
private:
+ RefPtr<GMPCrashHelper> mHelper;
nsCString mNodeId;
nsCString mAPI;
const nsTArray<nsCString> mTags;
UniquePtr<GetGMPContentParentCallback> mCallback;
};
bool
-GeckoMediaPluginServiceChild::GetContentParentFrom(const nsACString& aNodeId,
+GeckoMediaPluginServiceChild::GetContentParentFrom(GMPCrashHelper* aHelper,
+ const nsACString& aNodeId,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags,
UniquePtr<GetGMPContentParentCallback>&& aCallback)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
UniquePtr<GetServiceChildCallback> callback(
- new GetContentParentFromDone(aNodeId, aAPI, aTags, Move(aCallback)));
+ new GetContentParentFromDone(aHelper, aNodeId, aAPI, aTags, Move(aCallback)));
GetServiceChild(Move(callback));
return true;
}
NS_IMETHODIMP
GeckoMediaPluginServiceChild::GetPluginVersionForAPI(const nsACString& aAPI,
nsTArray<nsCString>* aTags,
--- a/dom/media/gmp/GMPServiceChild.h
+++ b/dom/media/gmp/GMPServiceChild.h
@@ -55,17 +55,18 @@ public:
void RemoveGMPContentParent(GMPContentParent* aGMPContentParent);
protected:
void InitializePlugins(AbstractThread*) override
{
// Nothing to do here.
}
- bool GetContentParentFrom(const nsACString& aNodeId,
+ bool GetContentParentFrom(GMPCrashHelper* aHelper,
+ const nsACString& aNodeId,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags,
UniquePtr<GetGMPContentParentCallback>&& aCallback)
override;
private:
friend class OpenPGMPServiceChild;
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -520,41 +520,44 @@ GeckoMediaPluginServiceParent::EnsureIni
return GenericPromise::CreateAndResolve(true, __func__);
}
// We should have an init promise in flight.
MOZ_ASSERT(!mInitPromise.IsEmpty());
return mInitPromise.Ensure(__func__);
}
bool
-GeckoMediaPluginServiceParent::GetContentParentFrom(const nsACString& aNodeId,
+GeckoMediaPluginServiceParent::GetContentParentFrom(GMPCrashHelper* aHelper,
+ const nsACString& aNodeId,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags,
UniquePtr<GetGMPContentParentCallback>&& aCallback)
{
RefPtr<AbstractThread> thread(GetAbstractGMPThread());
if (!thread) {
return false;
}
RefPtr<GeckoMediaPluginServiceParent> self(this);
nsCString nodeId(aNodeId);
nsTArray<nsCString> tags(aTags);
nsCString api(aAPI);
GetGMPContentParentCallback* rawCallback = aCallback.release();
+ RefPtr<GMPCrashHelper> helper(aHelper);
EnsureInitialized()->Then(thread, __func__,
- [self, tags, api, nodeId, rawCallback]() -> void {
+ [self, tags, api, nodeId, rawCallback, helper]() -> void {
UniquePtr<GetGMPContentParentCallback> callback(rawCallback);
RefPtr<GMPParent> gmp = self->SelectPluginForAPI(nodeId, api, tags);
LOGD(("%s: %p returning %p for api %s", __FUNCTION__, (void *)self, (void *)gmp, api.get()));
if (!gmp) {
NS_WARNING("GeckoMediaPluginServiceParent::GetContentParentFrom failed");
callback->Done(nullptr);
return;
}
+ self->ConnectCrashHelper(gmp->GetPluginId(), helper);
gmp->GetGMPContentParent(Move(callback));
},
[rawCallback]() -> void {
UniquePtr<GetGMPContentParentCallback> callback(rawCallback);
NS_WARNING("GMPService::EnsureInitialized failed.");
callback->Done(nullptr);
});
return true;
--- a/dom/media/gmp/GMPServiceParent.h
+++ b/dom/media/gmp/GMPServiceParent.h
@@ -110,17 +110,18 @@ 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);
- bool GetContentParentFrom(const nsACString& aNodeId,
+ bool GetContentParentFrom(GMPCrashHelper* aHelper,
+ const nsACString& aNodeId,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags,
UniquePtr<GetGMPContentParentCallback>&& aCallback)
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);
--- a/dom/media/gmp/mozIGeckoMediaPluginService.idl
+++ b/dom/media/gmp/mozIGeckoMediaPluginService.idl
@@ -10,16 +10,17 @@
#include "mozilla/UniquePtr.h"
#include "nsTArray.h"
#include "nsStringGlue.h"
class GMPAudioDecoderProxy;
class GMPDecryptorProxy;
class GMPVideoDecoderProxy;
class GMPVideoEncoderProxy;
class GMPVideoHost;
+class GMPCrashHelper;
template<class T>
class GMPGetterCallback
{
public:
GMPGetterCallback() { MOZ_COUNT_CTOR(GMPGetterCallback<T>); }
virtual ~GMPGetterCallback() { MOZ_COUNT_DTOR(GMPGetterCallback<T>); }
virtual void Done(T*) = 0;
@@ -46,16 +47,17 @@ public:
%}
[ptr] native TagArray(nsTArray<nsCString>);
native GetGMPDecryptorCallback(mozilla::UniquePtr<GetGMPDecryptorCallback>&&);
native GetGMPAudioDecoderCallback(mozilla::UniquePtr<GetGMPAudioDecoderCallback>&&);
native GetGMPVideoDecoderCallback(mozilla::UniquePtr<GetGMPVideoDecoderCallback>&&);
native GetGMPVideoEncoderCallback(mozilla::UniquePtr<GetGMPVideoEncoderCallback>&&);
native GetNodeIdCallback(mozilla::UniquePtr<GetNodeIdCallback>&&);
+native GMPCrashHelperPtr(GMPCrashHelper*);
[scriptable, uuid(44d362ae-937a-4803-bee6-f2512a0149d1)]
interface mozIGeckoMediaPluginService : nsISupports
{
/**
* The GMP thread. Callable from any thread.
*/
@@ -89,65 +91,70 @@ interface mozIGeckoMediaPluginService :
* Callable only on GMP thread.
* This is an asynchronous operation, the Done method of the callback object
* will be called on the GMP thread with the result (which might be null in
* the case of failure). This method always takes ownership of the callback
* object, but if this method returns an error then the Done method of the
* callback object will not be called at all.
*/
[noscript]
- void getGMPVideoDecoder(in TagArray tags,
+ void getGMPVideoDecoder(in GMPCrashHelperPtr helper,
+ in TagArray tags,
[optional] in ACString nodeId,
in GetGMPVideoDecoderCallback callback);
/**
* Get a video encoder that supports the specified tags.
* The array of tags should at least contain a codec tag, and optionally
* other tags.
* Callable only on GMP thread.
* This is an asynchronous operation, the Done method of the callback object
* will be called on the GMP thread with the result (which might be null in
* the case of failure). This method always takes ownership of the callback
* object, but if this method returns an error then the Done method of the
* callback object will not be called at all.
*/
[noscript]
- void getGMPVideoEncoder(in TagArray tags,
+ void getGMPVideoEncoder(in GMPCrashHelperPtr helper,
+ in TagArray tags,
[optional] in ACString nodeId,
in GetGMPVideoEncoderCallback callback);
/**
* Returns an audio decoder that supports the specified tags.
* The array of tags should at least contain a codec tag, and optionally
* other tags such as for EME keysystem.
* Callable only on GMP thread.
* This is an asynchronous operation, the Done method of the callback object
* will be called on the GMP thread with the result (which might be null in
* the case of failure). This method always takes ownership of the callback
* object, but if this method returns an error then the Done method of the
* callback object will not be called at all.
*/
[noscript]
- void getGMPAudioDecoder(in TagArray tags,
+ void getGMPAudioDecoder(in GMPCrashHelperPtr helper,
+ in TagArray tags,
[optional] in ACString nodeId,
in GetGMPAudioDecoderCallback callback);
/**
* Returns a decryption session manager that supports the specified tags.
* The array of tags should at least contain a key system tag, and optionally
* other tags.
* Callable only on GMP thread.
* This is an asynchronous operation, the Done method of the callback object
* will be called on the GMP thread with the result (which might be null in
* the case of failure). This method always takes ownership of the callback
* object, but if this method returns an error then the Done method of the
* callback object will not be called at all.
*/
[noscript]
- void getGMPDecryptor(in TagArray tags, in ACString nodeId,
+ void getGMPDecryptor(in GMPCrashHelperPtr helper,
+ in TagArray tags,
+ in ACString nodeId,
in GetGMPDecryptorCallback callback);
/**
* Gets the NodeId for a (origin, urlbarOrigin, isInprivateBrowsing) tuple.
*/
[noscript]
void getNodeId(in AString origin,
in AString topLevelOrigin,
--- a/dom/media/gtest/TestGMPCrossOrigin.cpp
+++ b/dom/media/gtest/TestGMPCrossOrigin.cpp
@@ -46,17 +46,18 @@ struct GMPTestRunner
void RunTestGMPCrossOrigin3(GMPTestMonitor& aMonitor);
void RunTestGMPCrossOrigin4(GMPTestMonitor& aMonitor);
private:
~GMPTestRunner() { }
};
template<class T, class Base,
- nsresult (NS_STDCALL GeckoMediaPluginService::*Getter)(nsTArray<nsCString>*,
+ nsresult (NS_STDCALL GeckoMediaPluginService::*Getter)(GMPCrashHelper*,
+ nsTArray<nsCString>*,
const nsACString&,
UniquePtr<Base>&&)>
class RunTestGMPVideoCodec : public Base
{
public:
void Done(T* aGMP, GMPVideoHost* aHost) override
{
EXPECT_TRUE(aGMP);
@@ -85,17 +86,17 @@ protected:
static nsresult Get(const nsACString& aNodeId, UniquePtr<Base>&& aCallback)
{
nsTArray<nsCString> tags;
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
tags.AppendElement(NS_LITERAL_CSTRING("fake"));
RefPtr<GeckoMediaPluginService> service =
GeckoMediaPluginService::GetGeckoMediaPluginService();
- return ((*service).*Getter)(&tags, aNodeId, Move(aCallback));
+ return ((*service).*Getter)(nullptr, &tags, aNodeId, Move(aCallback));
}
protected:
GMPTestMonitor& mMonitor;
};
typedef RunTestGMPVideoCodec<GMPVideoDecoderProxy,
GetGMPVideoDecoderCallback,
@@ -673,17 +674,17 @@ class GMPStorageTest : public GMPDecrypt
EXPECT_TRUE(!mNodeId.IsEmpty());
nsTArray<nsCString> tags;
tags.AppendElement(NS_LITERAL_CSTRING("fake"));
UniquePtr<GetGMPDecryptorCallback> callback(
new CreateDecryptorDone(this, aContinuation));
nsresult rv =
- service->GetGMPDecryptor(&tags, mNodeId, Move(callback));
+ service->GetGMPDecryptor(nullptr, &tags, mNodeId, Move(callback));
EXPECT_TRUE(NS_SUCCEEDED(rv));
}
void TestBasicStorage() {
AssertIsOnGMPThread();
EXPECT_TRUE(IsGMPStorageIsEmpty());
RefPtr<GeckoMediaPluginService> service =
--- a/dom/media/gtest/TestGMPRemoveAndDelete.cpp
+++ b/dom/media/gtest/TestGMPRemoveAndDelete.cpp
@@ -318,17 +318,17 @@ GMPRemoveTest::gmp_GetVideoDecoder(nsCSt
GMPTestMonitor* mMonitor;
GMPVideoDecoderProxy** mDecoder;
GMPVideoHost** mHost;
};
UniquePtr<GetGMPVideoDecoderCallback>
cb(new Callback(&mTestMonitor, aOutDecoder, aOutHost));
- if (NS_FAILED(GetService()->GetGMPVideoDecoder(&tags, aNodeId, Move(cb)))) {
+ if (NS_FAILED(GetService()->GetGMPVideoDecoder(nullptr, &tags, aNodeId, Move(cb)))) {
mTestMonitor.SetFinished();
}
}
void
GMPRemoveTest::CloseVideoDecoder()
{
mGMPThread->Dispatch(
--- a/dom/media/platforms/agnostic/gmp/GMPAudioDecoder.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPAudioDecoder.cpp
@@ -225,17 +225,17 @@ GMPAudioDecoder::Init()
mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
MOZ_ASSERT(mMPS);
RefPtr<InitPromise> promise(mInitPromise.Ensure(__func__));
nsTArray<nsCString> tags;
InitTags(tags);
UniquePtr<GetGMPAudioDecoderCallback> callback(new GMPInitDoneCallback(this));
- if (NS_FAILED(mMPS->GetGMPAudioDecoder(&tags, GetNodeId(), Move(callback)))) {
+ if (NS_FAILED(mMPS->GetGMPAudioDecoder(nullptr, &tags, GetNodeId(), Move(callback)))) {
mInitPromise.Reject(MediaDataDecoder::DecoderFailureReason::INIT_ERROR, __func__);
}
return promise;
}
nsresult
GMPAudioDecoder::Input(MediaRawData* aSample)
--- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
@@ -276,17 +276,17 @@ GMPVideoDecoder::Init()
mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
MOZ_ASSERT(mMPS);
RefPtr<InitPromise> promise(mInitPromise.Ensure(__func__));
nsTArray<nsCString> tags;
InitTags(tags);
UniquePtr<GetGMPVideoDecoderCallback> callback(new GMPInitDoneCallback(this));
- if (NS_FAILED(mMPS->GetGMPVideoDecoder(&tags, GetNodeId(), Move(callback)))) {
+ if (NS_FAILED(mMPS->GetGMPVideoDecoder(nullptr, &tags, GetNodeId(), Move(callback)))) {
mInitPromise.Reject(MediaDataDecoder::DecoderFailureReason::INIT_ERROR, __func__);
}
return promise;
}
nsresult
GMPVideoDecoder::Input(MediaRawData* aSample)
--- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
@@ -228,17 +228,18 @@ WebrtcGmpVideoEncoder::InitEncode_g(
uint32_t aMaxPayloadSize,
const RefPtr<GmpInitDoneRunnable>& aInitDone)
{
nsTArray<nsCString> tags;
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
UniquePtr<GetGMPVideoEncoderCallback> callback(
new InitDoneCallback(aThis, aInitDone, aCodecParams, aMaxPayloadSize));
aThis->mInitting = true;
- nsresult rv = aThis->mMPS->GetGMPVideoEncoder(&tags,
+ nsresult rv = aThis->mMPS->GetGMPVideoEncoder(nullptr,
+ &tags,
NS_LITERAL_CSTRING(""),
Move(callback));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOGD(("GMP Encode: GetGMPVideoEncoder failed"));
aThis->Close_g();
aInitDone->Dispatch(WEBRTC_VIDEO_CODEC_ERROR,
"GMP Encode: GetGMPVideoEncoder failed");
}
@@ -359,17 +360,18 @@ WebrtcGmpVideoEncoder::RegetEncoderForRe
aHeight));
// OpenH264 codec (at least) can't handle dynamic input resolution changes
// re-init the plugin when the resolution changes
// XXX allow codec to indicate it doesn't need re-init!
nsTArray<nsCString> tags;
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
mInitting = true;
- if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoEncoder(&tags,
+ if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoEncoder(nullptr,
+ &tags,
NS_LITERAL_CSTRING(""),
Move(callback))))) {
aInitDone->Dispatch(WEBRTC_VIDEO_CODEC_ERROR,
"GMP Encode: GetGMPVideoEncoder failed");
}
}
int32_t
@@ -713,17 +715,18 @@ WebrtcGmpVideoDecoder::InitDecode_g(
int32_t aNumberOfCores,
const RefPtr<GmpInitDoneRunnable>& aInitDone)
{
nsTArray<nsCString> tags;
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
UniquePtr<GetGMPVideoDecoderCallback> callback(
new InitDoneCallback(aThis, aInitDone));
aThis->mInitting = true;
- nsresult rv = aThis->mMPS->GetGMPVideoDecoder(&tags,
+ nsresult rv = aThis->mMPS->GetGMPVideoDecoder(nullptr,
+ &tags,
NS_LITERAL_CSTRING(""),
Move(callback));
if (NS_WARN_IF(NS_FAILED(rv))) {
LOGD(("GMP Decode: GetGMPVideoDecoder failed"));
aThis->Close_g();
aInitDone->Dispatch(WEBRTC_VIDEO_CODEC_ERROR,
"GMP Decode: GetGMPVideoDecoder failed.");
}