Bug 1267918 - Add GMPCrashHelper for HTMLMediaElement. r=gerald
This ensures that unencrypted GMP decoding crash reporting works.
MozReview-Commit-ID: 84TAV5F9Ie0
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -13,16 +13,17 @@
#include "nsCycleCollectionParticipant.h"
#include "nsIObserver.h"
#include "mozilla/CORSMode.h"
#include "DecoderTraits.h"
#include "nsIAudioChannelAgent.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/TextTrackManager.h"
+#include "mozilla/WeakPtr.h"
#include "MediaDecoder.h"
#ifdef MOZ_EME
#include "mozilla/dom/MediaKeys.h"
#endif
#include "mozilla/StateWatching.h"
#include "nsGkAtoms.h"
#include "PrincipalChangeObserver.h"
@@ -76,29 +77,32 @@ class MediaSource;
class TextTrackList;
class AudioTrackList;
class VideoTrackList;
class HTMLMediaElement : public nsGenericHTMLElement,
public nsIDOMHTMLMediaElement,
public MediaDecoderOwner,
public nsIAudioChannelAgentCallback,
- public PrincipalChangeObserver<DOMMediaStream>
+ public PrincipalChangeObserver<DOMMediaStream>,
+ public SupportsWeakPtr<HTMLMediaElement>
{
friend AutoNotifyAudioChannelAgent;
public:
typedef mozilla::TimeStamp TimeStamp;
typedef mozilla::layers::ImageContainer ImageContainer;
typedef mozilla::VideoFrameContainer VideoFrameContainer;
typedef mozilla::MediaStream MediaStream;
typedef mozilla::MediaResource MediaResource;
typedef mozilla::MediaDecoderOwner MediaDecoderOwner;
typedef mozilla::MetadataTags MetadataTags;
+ MOZ_DECLARE_WEAKREFERENCE_TYPENAME(HTMLMediaElement)
+
CORSMode GetCORSMode() {
return mCORSMode;
}
explicit HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
/**
* This is used when the browser is constructing a video element to play
--- a/dom/media/AbstractMediaDecoder.h
+++ b/dom/media/AbstractMediaDecoder.h
@@ -11,16 +11,18 @@
#include "mozilla/StateMirroring.h"
#include "MediaEventSource.h"
#include "MediaInfo.h"
#include "nsISupports.h"
#include "nsDataHashtable.h"
#include "nsThreadUtils.h"
+class GMPCrashHelper;
+
namespace mozilla
{
namespace layers
{
class ImageContainer;
} // namespace layers
class MediaResource;
@@ -84,16 +86,18 @@ public:
// Returns the owner of this media decoder. The owner should only be used
// on the main thread.
virtual MediaDecoderOwner* GetOwner() = 0;
// Set by Reader if the current audio track can be offloaded
virtual void SetPlatformCanOffloadAudio(bool aCanOffloadAudio) {}
+ virtual already_AddRefed<GMPCrashHelper> GetCrashHelper() { return nullptr; }
+
// Stack based class to assist in notifying the frame statistics of
// parsed and decoded frames. Use inside video demux & decode functions
// to ensure all parsed and decoded frames are reported on all return paths.
class AutoNotifyDecoded {
public:
explicit AutoNotifyDecoded(AbstractMediaDecoder* aDecoder)
: mParsed(0), mDecoded(0), mDropped(0), mDecoder(aDecoder) {}
~AutoNotifyDecoded() {
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -25,16 +25,17 @@
#include "mozilla/dom/AudioTrack.h"
#include "mozilla/dom/AudioTrackList.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/VideoTrack.h"
#include "mozilla/dom/VideoTrackList.h"
#include "nsPrintfCString.h"
#include "mozilla/Telemetry.h"
+#include "GMPService.h"
#ifdef MOZ_ANDROID_OMX
#include "AndroidBridge.h"
#endif
using namespace mozilla::dom;
using namespace mozilla::layers;
using namespace mozilla::media;
@@ -1103,16 +1104,44 @@ MediaDecoder::IsEndedOrShutdown() const
bool
MediaDecoder::OwnerHasError() const
{
MOZ_ASSERT(NS_IsMainThread());
return mShuttingDown || mOwner->HasError();
}
+class MediaElementGMPCrashHelper : public GMPCrashHelper
+{
+public:
+ explicit MediaElementGMPCrashHelper(HTMLMediaElement* aElement)
+ : mElement(aElement)
+ {
+ MOZ_ASSERT(NS_IsMainThread()); // WeakPtr isn't thread safe.
+ }
+ already_AddRefed<nsPIDOMWindowInner> GetPluginCrashedEventTarget() override
+ {
+ MOZ_ASSERT(NS_IsMainThread()); // WeakPtr isn't thread safe.
+ if (!mElement) {
+ return nullptr;
+ }
+ return do_AddRef(mElement->OwnerDoc()->GetInnerWindow());
+ }
+private:
+ WeakPtr<HTMLMediaElement> mElement;
+};
+
+already_AddRefed<GMPCrashHelper>
+MediaDecoder::GetCrashHelper()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ return mOwner->GetMediaElement() ?
+ MakeAndAddRef<MediaElementGMPCrashHelper>(mOwner->GetMediaElement()) : nullptr;
+}
+
bool
MediaDecoder::IsEnded() const
{
MOZ_ASSERT(NS_IsMainThread());
return mPlayState == PLAY_STATE_ENDED ||
(mWasEndedWhenEnteredDormant && (mPlayState != PLAY_STATE_SHUTDOWN));
}
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -238,16 +238,18 @@ public:
// has shutdown.
// Call on the main thread only.
virtual bool IsEndedOrShutdown() const;
// Return true if the MediaDecoderOwner's error attribute is not null.
// If the MediaDecoder is shutting down, OwnerHasError will return true.
bool OwnerHasError() const;
+ already_AddRefed<GMPCrashHelper> GetCrashHelper() override;
+
protected:
// Updates the media duration. This is called while the media is being
// played, calls before the media has reached loaded metadata are ignored.
// The duration is assumed to be an estimate, and so a degree of
// instability is expected; if the incoming duration is not significantly
// different from the existing duration, the change request is ignored.
// If the incoming duration is significantly different, the duration is
// changed, this causes a durationchanged event to fire to the media
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -173,16 +173,20 @@ MediaFormatReader::Init()
InitLayersBackendType();
mAudio.mTaskQueue =
new TaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER));
mVideo.mTaskQueue =
new TaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER));
+ // Note: GMPCrashHelper must be created on main thread, as it may use
+ // weak references, which aren't threadsafe.
+ mCrashHelper = mDecoder->GetCrashHelper();
+
return NS_OK;
}
#ifdef MOZ_EME
class DispatchKeyNeededEvent : public Runnable {
public:
DispatchKeyNeededEvent(AbstractMediaDecoder* aDecoder,
nsTArray<uint8_t>& aInitData,
@@ -406,30 +410,32 @@ MediaFormatReader::EnsureDecoderCreated(
MonitorAutoLock mon(decoder.mMonitor);
switch (aTrack) {
case TrackType::kAudioTrack: {
decoder.mDecoder = mPlatform->CreateDecoder({
decoder.mInfo ? *decoder.mInfo->GetAsAudioInfo() : mInfo.mAudio,
decoder.mTaskQueue,
- decoder.mCallback.get()
+ decoder.mCallback.get(),
+ mCrashHelper
});
break;
}
case TrackType::kVideoTrack: {
// Decoders use the layers backend to decide if they can use hardware decoding,
// so specify LAYERS_NONE if we want to forcibly disable it.
decoder.mDecoder = mPlatform->CreateDecoder({
mVideo.mInfo ? *mVideo.mInfo->GetAsVideoInfo() : mInfo.mVideo,
decoder.mTaskQueue,
decoder.mCallback.get(),
mLayersBackendType,
GetImageContainer(),
+ mCrashHelper
});
break;
}
default:
break;
}
if (decoder.mDecoder ) {
decoder.mDescription = decoder.mDecoder->GetDescriptionName();
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -566,13 +566,14 @@ private:
MozPromiseHolder<SeekPromise> mSeekPromise;
RefPtr<VideoFrameContainer> mVideoFrameContainer;
layers::ImageContainer* GetImageContainer();
#ifdef MOZ_EME
RefPtr<CDMProxy> mCDMProxy;
#endif
+ RefPtr<GMPCrashHelper> mCrashHelper;
};
} // namespace mozilla
#endif
--- a/dom/media/platforms/PlatformDecoderModule.h
+++ b/dom/media/platforms/PlatformDecoderModule.h
@@ -7,16 +7,17 @@
#if !defined(PlatformDecoderModule_h_)
#define PlatformDecoderModule_h_
#include "MediaDecoderReader.h"
#include "mozilla/MozPromise.h"
#include "mozilla/layers/LayersTypes.h"
#include "nsTArray.h"
#include "mozilla/RefPtr.h"
+#include "GMPService.h"
#include <queue>
namespace mozilla {
class TrackInfo;
class AudioInfo;
class VideoInfo;
class MediaRawData;
class DecoderDoctorDiagnostics;
@@ -57,23 +58,25 @@ struct CreateDecoderParams {
}
const TrackInfo& mConfig;
TaskQueue* mTaskQueue = nullptr;
MediaDataDecoderCallback* mCallback = nullptr;
DecoderDoctorDiagnostics* mDiagnostics = nullptr;
layers::ImageContainer* mImageContainer = nullptr;
layers::LayersBackend mLayersBackend = layers::LayersBackend::LAYERS_NONE;
+ RefPtr<GMPCrashHelper> mCrashHelper;
private:
void Set(TaskQueue* aTaskQueue) { mTaskQueue = aTaskQueue; }
void Set(MediaDataDecoderCallback* aCallback) { mCallback = aCallback; }
void Set(DecoderDoctorDiagnostics* aDiagnostics) { mDiagnostics = aDiagnostics; }
void Set(layers::ImageContainer* aImageContainer) { mImageContainer = aImageContainer; }
void Set(layers::LayersBackend aLayersBackend) { mLayersBackend = aLayersBackend; }
+ void Set(GMPCrashHelper* aCrashHelper) { mCrashHelper = aCrashHelper; }
template <typename T1, typename T2, typename... Ts>
void Set(T1 a1, T2 a2, Ts... as)
{
// Parameter pack expansion trick, to call Set() on each argument.
using expander = int[];
(void)expander {
(Set(a1), 0), (Set(a2), 0), (Set(as), 0)...
};
--- a/dom/media/platforms/agnostic/gmp/GMPAudioDecoder.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPAudioDecoder.cpp
@@ -126,16 +126,17 @@ AudioCallbackAdapter::Terminated()
mCallback->Error(MediaDataDecoderError::FATAL_ERROR);
}
GMPAudioDecoderParams::GMPAudioDecoderParams(const CreateDecoderParams& aParams)
: mConfig(aParams.AudioConfig())
, mTaskQueue(aParams.mTaskQueue)
, mCallback(nullptr)
, mAdapter(nullptr)
+ , mCrashHelper(aParams.mCrashHelper)
{}
GMPAudioDecoderParams&
GMPAudioDecoderParams::WithCallback(MediaDataDecoderProxy* aWrapper)
{
MOZ_ASSERT(aWrapper);
MOZ_ASSERT(!mCallback); // Should only be called once per instance.
mCallback = aWrapper->Callback();
@@ -153,16 +154,17 @@ GMPAudioDecoderParams::WithAdapter(Audio
return *this;
}
GMPAudioDecoder::GMPAudioDecoder(const GMPAudioDecoderParams& aParams)
: mConfig(aParams.mConfig)
, mCallback(aParams.mCallback)
, mGMP(nullptr)
, mAdapter(aParams.mAdapter)
+ , mCrashHelper(aParams.mCrashHelper)
{
MOZ_ASSERT(!mAdapter || mCallback == mAdapter->Callback());
if (!mAdapter) {
mAdapter = new AudioCallbackAdapter(mCallback);
}
}
void
@@ -225,17 +227,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(nullptr, &tags, GetNodeId(), Move(callback)))) {
+ if (NS_FAILED(mMPS->GetGMPAudioDecoder(mCrashHelper, &tags, GetNodeId(), Move(callback)))) {
mInitPromise.Reject(MediaDataDecoder::DecoderFailureReason::INIT_ERROR, __func__);
}
return promise;
}
nsresult
GMPAudioDecoder::Input(MediaRawData* aSample)
--- a/dom/media/platforms/agnostic/gmp/GMPAudioDecoder.h
+++ b/dom/media/platforms/agnostic/gmp/GMPAudioDecoder.h
@@ -52,16 +52,17 @@ struct GMPAudioDecoderParams {
explicit GMPAudioDecoderParams(const CreateDecoderParams& aParams);
GMPAudioDecoderParams& WithCallback(MediaDataDecoderProxy* aWrapper);
GMPAudioDecoderParams& WithAdapter(AudioCallbackAdapter* aAdapter);
const AudioInfo& mConfig;
TaskQueue* mTaskQueue;
MediaDataDecoderCallbackProxy* mCallback;
AudioCallbackAdapter* mAdapter;
+ RefPtr<GMPCrashHelper> mCrashHelper;
};
class GMPAudioDecoder : public MediaDataDecoder {
public:
explicit GMPAudioDecoder(const GMPAudioDecoderParams& aParams);
RefPtr<InitPromise> Init() override;
nsresult Input(MediaRawData* aSample) override;
@@ -98,13 +99,14 @@ private:
void GMPInitDone(GMPAudioDecoderProxy* aGMP);
const AudioInfo mConfig;
MediaDataDecoderCallbackProxy* mCallback;
nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
GMPAudioDecoderProxy* mGMP;
nsAutoPtr<AudioCallbackAdapter> mAdapter;
MozPromiseHolder<InitPromise> mInitPromise;
+ RefPtr<GMPCrashHelper> mCrashHelper;
};
} // namespace mozilla
#endif // GMPAudioDecoder_h_
--- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
@@ -106,16 +106,17 @@ VideoCallbackAdapter::Terminated()
GMPVideoDecoderParams::GMPVideoDecoderParams(const CreateDecoderParams& aParams)
: mConfig(aParams.VideoConfig())
, mTaskQueue(aParams.mTaskQueue)
, mCallback(nullptr)
, mAdapter(nullptr)
, mImageContainer(aParams.mImageContainer)
, mLayersBackend(aParams.mLayersBackend)
+ , mCrashHelper(aParams.mCrashHelper)
{}
GMPVideoDecoderParams&
GMPVideoDecoderParams::WithCallback(MediaDataDecoderProxy* aWrapper)
{
MOZ_ASSERT(aWrapper);
MOZ_ASSERT(!mCallback); // Should only be called once per instance.
mCallback = aWrapper->Callback();
@@ -135,16 +136,17 @@ GMPVideoDecoderParams::WithAdapter(Video
GMPVideoDecoder::GMPVideoDecoder(const GMPVideoDecoderParams& aParams)
: mConfig(aParams.mConfig)
, mCallback(aParams.mCallback)
, mGMP(nullptr)
, mHost(nullptr)
, mAdapter(aParams.mAdapter)
, mConvertNALUnitLengths(false)
+ , mCrashHelper(aParams.mCrashHelper)
{
MOZ_ASSERT(!mAdapter || mCallback == mAdapter->Callback());
if (!mAdapter) {
mAdapter = new VideoCallbackAdapter(mCallback,
VideoInfo(mConfig.mDisplay.width,
mConfig.mDisplay.height),
aParams.mImageContainer);
}
@@ -276,17 +278,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(nullptr, &tags, GetNodeId(), Move(callback)))) {
+ if (NS_FAILED(mMPS->GetGMPVideoDecoder(mCrashHelper, &tags, GetNodeId(), Move(callback)))) {
mInitPromise.Reject(MediaDataDecoder::DecoderFailureReason::INIT_ERROR, __func__);
}
return promise;
}
nsresult
GMPVideoDecoder::Input(MediaRawData* aSample)
--- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h
+++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h
@@ -57,16 +57,17 @@ struct GMPVideoDecoderParams {
GMPVideoDecoderParams& WithAdapter(VideoCallbackAdapter* aAdapter);
const VideoInfo& mConfig;
TaskQueue* mTaskQueue;
MediaDataDecoderCallbackProxy* mCallback;
VideoCallbackAdapter* mAdapter;
layers::ImageContainer* mImageContainer;
layers::LayersBackend mLayersBackend;
+ RefPtr<GMPCrashHelper> mCrashHelper;
};
class GMPVideoDecoder : public MediaDataDecoder {
public:
explicit GMPVideoDecoder(const GMPVideoDecoderParams& aParams);
RefPtr<InitPromise> Init() override;
nsresult Input(MediaRawData* aSample) override;
@@ -106,13 +107,14 @@ private:
const VideoInfo mConfig;
MediaDataDecoderCallbackProxy* mCallback;
nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
GMPVideoDecoderProxy* mGMP;
GMPVideoHost* mHost;
nsAutoPtr<VideoCallbackAdapter> mAdapter;
bool mConvertNALUnitLengths;
MozPromiseHolder<InitPromise> mInitPromise;
+ RefPtr<GMPCrashHelper> mCrashHelper;
};
} // namespace mozilla
#endif // GMPVideoDecoder_h_
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -20,16 +20,17 @@ H264Converter::H264Converter(PlatformDec
: mPDM(aPDM)
, mOriginalConfig(aParams.VideoConfig())
, mCurrentConfig(aParams.VideoConfig())
, mLayersBackend(aParams.mLayersBackend)
, mImageContainer(aParams.mImageContainer)
, mTaskQueue(aParams.mTaskQueue)
, mCallback(aParams.mCallback)
, mDecoder(nullptr)
+ , mGMPCrashHelper(aParams.mCrashHelper)
, mNeedAVCC(aPDM->DecoderNeedsConversion(aParams.mConfig) == PlatformDecoderModule::kNeedAVCC)
, mLastError(NS_OK)
{
CreateDecoder(aParams.mDiagnostics);
}
H264Converter::~H264Converter()
{
@@ -142,17 +143,18 @@ H264Converter::CreateDecoder(DecoderDoct
}
mDecoder = mPDM->CreateVideoDecoder({
mNeedAVCC ? mCurrentConfig : mOriginalConfig,
mTaskQueue,
mCallback,
aDiagnostics,
mImageContainer,
- mLayersBackend
+ mLayersBackend,
+ mGMPCrashHelper
});
if (!mDecoder) {
mLastError = NS_ERROR_FAILURE;
return NS_ERROR_FAILURE;
}
return NS_OK;
}
--- a/dom/media/platforms/wrappers/H264Converter.h
+++ b/dom/media/platforms/wrappers/H264Converter.h
@@ -60,15 +60,16 @@ private:
VideoInfo mCurrentConfig;
layers::LayersBackend mLayersBackend;
RefPtr<layers::ImageContainer> mImageContainer;
const RefPtr<TaskQueue> mTaskQueue;
nsTArray<RefPtr<MediaRawData>> mMediaRawSamples;
MediaDataDecoderCallback* mCallback;
RefPtr<MediaDataDecoder> mDecoder;
MozPromiseRequestHolder<InitPromise> mInitPromiseRequest;
+ RefPtr<GMPCrashHelper> mGMPCrashHelper;
bool mNeedAVCC;
nsresult mLastError;
};
} // namespace mozilla
#endif // mozilla_H264Converter_h