Bug 1393399 P2 - keep the GPU process crash time and send back to MFR;
We keep the GPU crash time and send back to MFR through MediaResult.
We cannot save the information in VideoDecoderChild as a static member because we are going to read it in MFR's task queue and the data was written in VideoDecoderManager's thread. This is going to be racing.
MozReview-Commit-ID: FXqOgelWY6e
--- a/dom/media/MediaResult.h
+++ b/dom/media/MediaResult.h
@@ -4,16 +4,17 @@
* 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/. */
#ifndef MediaResult_h_
#define MediaResult_h_
#include "nsString.h" // Required before 'mozilla/ErrorNames.h'!?
#include "mozilla/ErrorNames.h"
+#include "mozilla/TimeStamp.h"
#include "nsError.h"
#include "nsPrintfCString.h"
// MediaResult can be used interchangeably with nsresult.
// It allows to store extra information such as where the error occurred.
// While nsresult is typically passed by value; due to its potential size, using
// MediaResult const references is recommended.
namespace mozilla {
@@ -57,19 +58,23 @@ public:
GetErrorName(mCode, static_cast<nsACString&>(name));
return nsPrintfCString("%s (0x%08" PRIx32 ")%s%s",
name.get(),
static_cast<uint32_t>(mCode),
mMessage.IsEmpty() ? "" : " - ",
mMessage.get());
}
+ void SetGPUCrashTimeStamp(const TimeStamp& aTime) { mGPUCrashTimeStamp = aTime; }
+ const TimeStamp& GPUCrashTimeStamp() const { return mGPUCrashTimeStamp; }
+
private:
nsresult mCode;
nsCString mMessage;
+ TimeStamp mGPUCrashTimeStamp; // Used in bug 1393399 for temporary telemetry usage.
};
#ifdef _MSC_VER
#define RESULT_DETAIL(arg, ...) nsPrintfCString("%s: " arg, __FUNCSIG__, ##__VA_ARGS__)
#else
#define RESULT_DETAIL(arg, ...) nsPrintfCString("%s: " arg, __PRETTY_FUNCTION__, ##__VA_ARGS__)
#endif
--- a/dom/media/ipc/VideoDecoderChild.cpp
+++ b/dom/media/ipc/VideoDecoderChild.cpp
@@ -135,35 +135,36 @@ VideoDecoderChild::RecvFlushComplete()
mFlushPromise.ResolveIfExists(true, __func__);
return IPC_OK();
}
void
VideoDecoderChild::ActorDestroy(ActorDestroyReason aWhy)
{
if (aWhy == AbnormalShutdown) {
+ // GPU process crashed, record the time and send back to MFR for telemetry.
+ mGPUCrashTime = TimeStamp::Now();
+
// Defer reporting an error until we've recreated the manager so that
// it'll be safe for MediaFormatReader to recreate decoders
RefPtr<VideoDecoderChild> ref = this;
GetManager()->RunWhenRecreated(
NS_NewRunnableFunction("dom::VideoDecoderChild::ActorDestroy", [=]() {
+ MediaResult error(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER);
+ error.SetGPUCrashTimeStamp(ref->mGPUCrashTime);
if (ref->mInitialized) {
mDecodedData.Clear();
- mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER,
- __func__);
- mDrainPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER,
- __func__);
- mFlushPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER,
- __func__);
+ mDecodePromise.RejectIfExists(error, __func__);
+ mDrainPromise.RejectIfExists(error, __func__);
+ mFlushPromise.RejectIfExists(error, __func__);
// Make sure the next request will be rejected accordingly if ever
// called.
mNeedNewDecoder = true;
} else {
- ref->mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER,
- __func__);
+ ref->mInitPromise.RejectIfExists(error, __func__);
}
}));
}
mCanSend = false;
#ifdef XP_WIN
ReportUnblacklistingTelemetry(aWhy == AbnormalShutdown,
mBlacklistedD3D11Driver,
@@ -240,18 +241,19 @@ VideoDecoderChild::Init()
}
RefPtr<MediaDataDecoder::DecodePromise>
VideoDecoderChild::Decode(MediaRawData* aSample)
{
AssertOnManagerThread();
if (mNeedNewDecoder) {
- return MediaDataDecoder::DecodePromise::CreateAndReject(
- NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER, __func__);
+ MediaResult error(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER);
+ error.SetGPUCrashTimeStamp(mGPUCrashTime);
+ return MediaDataDecoder::DecodePromise::CreateAndReject(error, __func__);
}
if (!mCanSend) {
// We're here if the IPC channel has died but we're still waiting for the
// RunWhenRecreated task to complete. The decode promise will be rejected
// when that task is run.
return mDecodePromise.Ensure(__func__);
}
@@ -279,32 +281,34 @@ VideoDecoderChild::Decode(MediaRawData*
RefPtr<MediaDataDecoder::FlushPromise>
VideoDecoderChild::Flush()
{
AssertOnManagerThread();
mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
mDrainPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
if (mNeedNewDecoder) {
- return MediaDataDecoder::FlushPromise::CreateAndReject(
- NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER, __func__);
+ MediaResult error(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER);
+ error.SetGPUCrashTimeStamp(mGPUCrashTime);
+ return MediaDataDecoder::FlushPromise::CreateAndReject(error, __func__);
}
if (mCanSend) {
SendFlush();
}
return mFlushPromise.Ensure(__func__);
}
RefPtr<MediaDataDecoder::DecodePromise>
VideoDecoderChild::Drain()
{
AssertOnManagerThread();
if (mNeedNewDecoder) {
- return MediaDataDecoder::DecodePromise::CreateAndReject(
- NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER, __func__);
+ MediaResult error(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER);
+ error.SetGPUCrashTimeStamp(mGPUCrashTime);
+ return MediaDataDecoder::DecodePromise::CreateAndReject(error, __func__);
}
if (mCanSend) {
SendDrain();
}
return mDrainPromise.Ensure(__func__);
}
void
--- a/dom/media/ipc/VideoDecoderChild.h
+++ b/dom/media/ipc/VideoDecoderChild.h
@@ -77,14 +77,15 @@ private:
// Set to true if the actor got destroyed and we haven't yet notified the
// caller.
bool mNeedNewDecoder;
MediaDataDecoder::DecodedData mDecodedData;
nsCString mBlacklistedD3D11Driver;
nsCString mBlacklistedD3D9Driver;
+ TimeStamp mGPUCrashTime;
};
} // namespace dom
} // namespace mozilla
#endif // include_dom_ipc_VideoDecoderChild_h