Bug 1267918 - Add GMPCrashHelper for MediaKeys. r=gerald
So if a GMP crashes while doing EME, we'll get a crash report using the new
mechanism.
MozReview-Commit-ID: G8BlFI9jmiF
--- a/dom/media/eme/CDMProxy.cpp
+++ b/dom/media/eme/CDMProxy.cpp
@@ -14,16 +14,17 @@
#include "MainThreadUtils.h"
#include "mozilla/EMEUtils.h"
#include "nsIConsoleService.h"
#include "prenv.h"
#include "mozilla/PodOperations.h"
#include "mozilla/CDMCallbackProxy.h"
#include "MediaData.h"
#include "nsPrintfCString.h"
+#include "GMPService.h"
namespace mozilla {
CDMProxy::CDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem)
: mKeys(aKeys)
, mKeySystem(aKeySystem)
, mCDM(nullptr)
, mDecryptionJobCount(0)
@@ -38,17 +39,18 @@ CDMProxy::~CDMProxy()
MOZ_COUNT_DTOR(CDMProxy);
}
void
CDMProxy::Init(PromiseId aPromiseId,
const nsAString& aOrigin,
const nsAString& aTopLevelOrigin,
const nsAString& aGMPName,
- bool aInPrivateBrowsing)
+ bool aInPrivateBrowsing,
+ GMPCrashHelper* aCrashHelper)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
EME_LOG("CDMProxy::Init (%s, %s) %s",
NS_ConvertUTF16toUTF8(aOrigin).get(),
NS_ConvertUTF16toUTF8(aTopLevelOrigin).get(),
(aInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"));
@@ -77,16 +79,17 @@ CDMProxy::Init(PromiseId aPromiseId,
}
nsAutoPtr<InitData> data(new InitData());
data->mPromiseId = aPromiseId;
data->mOrigin = aOrigin;
data->mTopLevelOrigin = aTopLevelOrigin;
data->mGMPName = aGMPName;
data->mInPrivateBrowsing = aInPrivateBrowsing;
+ data->mCrashHelper = aCrashHelper;
nsCOMPtr<nsIRunnable> task(
NewRunnableMethod<nsAutoPtr<InitData>>(this,
&CDMProxy::gmp_Init,
Move(data)));
mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
}
#ifdef DEBUG
@@ -221,19 +224,22 @@ CDMProxy::gmp_InitGetGMPDecryptor(nsresu
NS_ConvertUTF16toUTF8(aData->mOrigin).get(),
NS_ConvertUTF16toUTF8(aData->mTopLevelOrigin).get(),
(aData->mInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"),
GetNodeId().get());
nsTArray<nsCString> tags;
tags.AppendElement(NS_ConvertUTF16toUTF8(mKeySystem));
+ // Note: must capture helper refptr here, before the Move()
+ // when we create the GetGMPDecryptorCallback below.
+ RefPtr<GMPCrashHelper> crashHelper = Move(aData->mCrashHelper);
UniquePtr<GetGMPDecryptorCallback> callback(new gmp_InitDoneCallback(this,
Move(aData)));
- nsresult rv = mps->GetGMPDecryptor(nullptr, &tags, GetNodeId(), Move(callback));
+ nsresult rv = mps->GetGMPDecryptor(crashHelper, &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/eme/CDMProxy.h
+++ b/dom/media/eme/CDMProxy.h
@@ -53,17 +53,18 @@ public:
// Main thread only.
// Loads the CDM corresponding to mKeySystem.
// Calls MediaKeys::OnCDMCreated() when the CDM is created.
void Init(PromiseId aPromiseId,
const nsAString& aOrigin,
const nsAString& aTopLevelOrigin,
const nsAString& aGMPName,
- bool aInPrivateBrowsing);
+ bool aInPrivateBrowsing,
+ GMPCrashHelper* aHelper);
// Main thread only.
// Uses the CDM to create a key session.
// Calls MediaKeys::OnSessionActivated() when session is created.
// Assumes ownership of (Move()s) aInitData's contents.
void CreateSession(uint32_t aCreateSessionToken,
dom::SessionType aSessionType,
PromiseId aPromiseId,
@@ -183,16 +184,17 @@ private:
friend class gmp_InitDoneCallback;
friend class gmp_InitGetGMPDecryptorCallback;
struct InitData {
uint32_t mPromiseId;
nsString mOrigin;
nsString mTopLevelOrigin;
nsString mGMPName;
+ RefPtr<GMPCrashHelper> mCrashHelper;
bool mInPrivateBrowsing;
};
// GMP thread only.
void gmp_Init(nsAutoPtr<InitData>&& aData);
void gmp_InitDone(GMPDecryptorProxy* aCDM, nsAutoPtr<InitData>&& aData);
void gmp_InitGetGMPDecryptor(nsresult aResult,
const nsACString& aNodeId,
--- a/dom/media/eme/MediaKeys.cpp
+++ b/dom/media/eme/MediaKeys.cpp
@@ -279,16 +279,36 @@ MediaKeys::ResolvePromise(PromiseId aId)
mKeySessions.Put(session->GetSessionId(), session);
promise->MaybeResolve(session);
} else {
promise->MaybeResolve(JS::UndefinedHandleValue);
}
MOZ_ASSERT(!mPromises.Contains(aId));
}
+class MediaKeysGMPCrashHelper : public GMPCrashHelper
+{
+public:
+ explicit MediaKeysGMPCrashHelper(MediaKeys* aMediaKeys)
+ : mMediaKeys(aMediaKeys)
+ {
+ MOZ_ASSERT(NS_IsMainThread()); // WeakPtr isn't thread safe.
+ }
+ already_AddRefed<nsPIDOMWindowInner>
+ GetPluginCrashedEventTarget() override
+ {
+ MOZ_ASSERT(NS_IsMainThread()); // WeakPtr isn't thread safe.
+ EME_LOG("MediaKeysGMPCrashHelper::GetPluginCrashedEventTarget()");
+ return (mMediaKeys && mMediaKeys->GetParentObject()) ?
+ do_AddRef(mMediaKeys->GetParentObject()) : nullptr;
+ }
+private:
+ WeakPtr<MediaKeys> mMediaKeys;
+};
+
already_AddRefed<DetailedPromise>
MediaKeys::Init(ErrorResult& aRv)
{
RefPtr<DetailedPromise> promise(MakePromise(aRv,
NS_LITERAL_CSTRING("MediaKeys::Init()")));
if (aRv.Failed()) {
return nullptr;
}
@@ -362,17 +382,18 @@ MediaKeys::Init(ErrorResult& aRv)
// rejected.
MOZ_ASSERT(!mCreatePromiseId, "Should only be created once!");
mCreatePromiseId = StorePromise(promise);
AddRef();
mProxy->Init(mCreatePromiseId,
origin,
topLevelOrigin,
KeySystemToGMPName(mKeySystem),
- inPrivateBrowsing);
+ inPrivateBrowsing,
+ new MediaKeysGMPCrashHelper(this));
return promise.forget();
}
void
MediaKeys::OnCDMCreated(PromiseId aId, const nsACString& aNodeId, const uint32_t aPluginId)
{
RefPtr<DetailedPromise> promise(RetrievePromise(aId));
--- a/dom/media/eme/MediaKeys.h
+++ b/dom/media/eme/MediaKeys.h
@@ -14,16 +14,17 @@
#include "mozilla/RefPtr.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsRefPtrHashtable.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/MediaKeysBinding.h"
#include "mozIGeckoMediaPluginService.h"
#include "mozilla/DetailedPromise.h"
+#include "mozilla/WeakPtr.h"
namespace mozilla {
class CDMProxy;
namespace dom {
class ArrayBufferViewOrArrayBuffer;
@@ -31,25 +32,27 @@ class MediaKeySession;
class HTMLMediaElement;
typedef nsRefPtrHashtable<nsStringHashKey, MediaKeySession> KeySessionHashMap;
typedef nsRefPtrHashtable<nsUint32HashKey, dom::DetailedPromise> PromiseHashMap;
typedef nsRefPtrHashtable<nsUint32HashKey, MediaKeySession> PendingKeySessionsHashMap;
typedef uint32_t PromiseId;
// This class is used on the main thread only.
-// Note: it's addref/release is not (and can't be) thread safe!
+// Note: its addref/release is not (and can't be) thread safe!
class MediaKeys final : public nsISupports,
- public nsWrapperCache
+ public nsWrapperCache,
+ public SupportsWeakPtr<MediaKeys>
{
~MediaKeys();
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaKeys)
+ MOZ_DECLARE_WEAKREFERENCE_TYPENAME(MediaKeys)
MediaKeys(nsPIDOMWindowInner* aParentWindow,
const nsAString& aKeySystem, const nsAString& aCDMVersion);
already_AddRefed<DetailedPromise> Init(ErrorResult& aRv);
nsPIDOMWindowInner* GetParentObject() const;