Bug 1433309 - Annotate createMediaKeys promise reject with whether failure occurred due to pending shutdown. r=gerald
Around every Firefox update, Netflix see a spike in
MediaKeySystemAccess.createMediaKeys() promise rejects. I am wondering whether
this is caused by the browser restarting to apply a Firefox update while
Netflix's player is loading. So add more detail to the promise reject as to
the state of the system, to try to validate that theory.
MozReview-Commit-ID: 4IDPsFwKCtq
--- a/dom/media/gmp/ChromiumCDMParent.cpp
+++ b/dom/media/gmp/ChromiumCDMParent.cpp
@@ -7,16 +7,17 @@
#include "ChromiumCDMCallback.h"
#include "ChromiumCDMCallbackProxy.h"
#include "ChromiumCDMProxy.h"
#include "content_decryption_module.h"
#include "GMPContentChild.h"
#include "GMPContentParent.h"
#include "GMPLog.h"
+#include "GMPService.h"
#include "GMPUtils.h"
#include "MediaPrefs.h"
#include "mozilla/dom/MediaKeyMessageEventBinding.h"
#include "mozilla/gmp/GMPTypes.h"
#include "mozilla/Unused.h"
#include "AnnexB.h"
#include "H264.h"
@@ -39,27 +40,52 @@ ChromiumCDMParent::ChromiumCDMParent(GMP
aContentParent,
aPluginId);
}
bool
ChromiumCDMParent::Init(ChromiumCDMCallback* aCDMCallback,
bool aAllowDistinctiveIdentifier,
bool aAllowPersistentState,
- nsIEventTarget* aMainThread)
+ nsIEventTarget* aMainThread,
+ nsCString& aOutFailureReason)
{
- GMP_LOG("ChromiumCDMParent::Init(this=%p)", this);
+ GMP_LOG("ChromiumCDMParent::Init(this=%p) shutdown=%d abormalShutdown=%d "
+ "actorDestroyed=%d",
+ this,
+ mIsShutdown,
+ mAbnormalShutdown,
+ mActorDestroyed);
if (!aCDMCallback || !aMainThread) {
+ aOutFailureReason = nsPrintfCString("ChromiumCDMParent::Init() failed "
+ "nullCallback=%d nullMainThread=%d",
+ !aCDMCallback,
+ !aMainThread);
GMP_LOG("ChromiumCDMParent::Init(this=%p) failure since aCDMCallback(%p) or"
" aMainThread(%p) is nullptr", this, aCDMCallback, aMainThread);
return false;
}
mCDMCallback = aCDMCallback;
mMainThread = aMainThread;
- return SendInit(aAllowDistinctiveIdentifier, aAllowPersistentState);
+
+ if (SendInit(aAllowDistinctiveIdentifier, aAllowPersistentState)) {
+ return true;
+ }
+
+ RefPtr<gmp::GeckoMediaPluginService> service =
+ gmp::GeckoMediaPluginService::GetGeckoMediaPluginService();
+ bool xpcomWillShutdown = service && service->XPCOMWillShutdownReceived();
+ aOutFailureReason = nsPrintfCString(
+ "ChromiumCDMParent::Init() failed "
+ "shutdown=%d cdmCrash=%d actorDestroyed=%d browserShutdown=%d",
+ mIsShutdown,
+ mAbnormalShutdown,
+ mActorDestroyed,
+ xpcomWillShutdown);
+ return false;
}
void
ChromiumCDMParent::CreateSession(uint32_t aCreateSessionToken,
uint32_t aSessionType,
uint32_t aInitDataType,
uint32_t aPromiseId,
const nsTArray<uint8_t>& aInitData)
@@ -860,21 +886,21 @@ ChromiumCDMParent::ActorDestroy(ActorDes
Shutdown();
}
MOZ_ASSERT(mIsShutdown);
RefPtr<ChromiumCDMParent> kungFuDeathGrip(this);
if (mContentParent) {
mContentParent->ChromiumCDMDestroyed(this);
mContentParent = nullptr;
}
- bool abnormalShutdown = (aWhy == AbnormalShutdown);
- if (abnormalShutdown && callback) {
+ mAbnormalShutdown = (aWhy == AbnormalShutdown);
+ if (mAbnormalShutdown && callback) {
callback->Terminated();
}
- MaybeDisconnect(abnormalShutdown);
+ MaybeDisconnect(mAbnormalShutdown);
}
RefPtr<MediaDataDecoder::InitPromise>
ChromiumCDMParent::InitializeVideoDecoder(
const gmp::CDMVideoDecoderConfig& aConfig,
const VideoInfo& aInfo,
RefPtr<layers::ImageContainer> aImageContainer)
{
--- a/dom/media/gmp/ChromiumCDMParent.h
+++ b/dom/media/gmp/ChromiumCDMParent.h
@@ -38,17 +38,18 @@ public:
ChromiumCDMParent(GMPContentParent* aContentParent, uint32_t aPluginId);
uint32_t PluginId() const { return mPluginId; }
bool Init(ChromiumCDMCallback* aCDMCallback,
bool aAllowDistinctiveIdentifier,
bool aAllowPersistentState,
- nsIEventTarget* aMainThread);
+ nsIEventTarget* aMainThread,
+ nsCString& aOutFailureReason);
void CreateSession(uint32_t aCreateSessionToken,
uint32_t aSessionType,
uint32_t aInitDataType,
uint32_t aPromiseId,
const nsTArray<uint8_t>& aInitData);
void LoadSession(uint32_t aPromiseId,
@@ -177,16 +178,17 @@ protected:
// frames from the CDM to Gecko.
uint32_t mVideoShmemsActive = 0;
// Maximum number of shmems to use to return decoded video frames.
uint32_t mVideoShmemLimit;
bool mIsShutdown = false;
bool mVideoDecoderInitialized = false;
bool mActorDestroyed = false;
+ bool mAbnormalShutdown = false;
// The H.264 decoder in Widevine CDM versions 970 and later output in decode
// order rather than presentation order, so we reorder in presentation order
// before presenting. mMaxRefFrames is non-zero if we have an initialized
// decoder and we are decoding H.264. If so, it stores the maximum length of
// the reorder queue that we need. Note we may have multiple decoders for the
// life time of this object, but never more than one active at once.
uint32_t mMaxRefFrames = 0;
--- a/dom/media/gmp/ChromiumCDMProxy.cpp
+++ b/dom/media/gmp/ChromiumCDMProxy.cpp
@@ -96,23 +96,23 @@ ChromiumCDMProxy::Init(PromiseId aPromis
RefPtr<gmp::GetCDMParentPromise> promise =
service->GetCDM(nodeId, { keySystem }, helper);
promise->Then(
thread,
__func__,
[self, aPromiseId](RefPtr<gmp::ChromiumCDMParent> cdm) {
self->mCallback =
MakeUnique<ChromiumCDMCallbackProxy>(self, self->mMainThread);
+ nsCString failureReason;
if (!cdm->Init(self->mCallback.get(),
self->mDistinctiveIdentifierRequired,
self->mPersistentStateRequired,
- self->mMainThread)) {
- self->RejectPromise(aPromiseId,
- NS_ERROR_FAILURE,
- NS_LITERAL_CSTRING("GetCDM failed due to CDM initialization failure."));
+ self->mMainThread,
+ failureReason)) {
+ self->RejectPromise(aPromiseId, NS_ERROR_FAILURE, failureReason);
return;
}
{
MutexAutoLock lock(self->mCDMMutex);
self->mCDM = cdm;
}
self->OnCDMCreated(aPromiseId);
},
--- a/dom/media/gmp/GMPService.cpp
+++ b/dom/media/gmp/GMPService.cpp
@@ -145,16 +145,17 @@ GeckoMediaPluginService::GetGeckoMediaPl
}
NS_IMPL_ISUPPORTS(GeckoMediaPluginService, mozIGeckoMediaPluginService, nsIObserver)
GeckoMediaPluginService::GeckoMediaPluginService()
: mMutex("GeckoMediaPluginService::mMutex")
, mGMPThreadShutdown(false)
, mShuttingDownOnGMPThread(false)
+ , mXPCOMWillShutdown(false)
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIXULAppInfo> appInfo = do_GetService("@mozilla.org/xre/app-info;1");
if (appInfo) {
nsAutoCString version;
nsAutoCString buildID;
if (NS_SUCCEEDED(appInfo->GetVersion(version)) &&
@@ -219,16 +220,18 @@ GeckoMediaPluginService::RunPluginCrashC
nsresult
GeckoMediaPluginService::Init()
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
MOZ_ASSERT(obsService);
MOZ_ALWAYS_SUCCEEDS(obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false));
+ MOZ_ALWAYS_SUCCEEDS(
+ obsService->AddObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, false));
// Kick off scanning for plugins
nsCOMPtr<nsIThread> thread;
return GetThread(getter_AddRefs(thread));
}
RefPtr<GetCDMParentPromise>
GeckoMediaPluginService::GetCDM(const NodeId& aNodeId,
--- a/dom/media/gmp/GMPService.h
+++ b/dom/media/gmp/GMPService.h
@@ -5,16 +5,17 @@
#ifndef GMPService_h_
#define GMPService_h_
#include "nsString.h"
#include "mozIGeckoMediaPluginService.h"
#include "nsIObserver.h"
#include "nsTArray.h"
+#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/Monitor.h"
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsIThread.h"
#include "nsThreadUtils.h"
#include "nsIDocument.h"
#include "nsIWeakReference.h"
@@ -102,16 +103,18 @@ public:
NS_IMETHOD RunPluginCrashCallbacks(uint32_t aPluginId,
const nsACString& aPluginName) override;
RefPtr<AbstractThread> GetAbstractGMPThread();
void ConnectCrashHelper(uint32_t aPluginId, GMPCrashHelper* aHelper);
void DisconnectCrashHelper(GMPCrashHelper* aHelper);
+ bool XPCOMWillShutdownReceived() const { return mXPCOMWillShutdown; }
+
protected:
GeckoMediaPluginService();
virtual ~GeckoMediaPluginService();
virtual void InitializePlugins(AbstractThread* aAbstractGMPThread) = 0;
virtual RefPtr<GetGMPContentParentPromise> GetContentParent(
GMPCrashHelper* aHelper,
@@ -130,16 +133,17 @@ protected:
void ShutdownGMPThread();
Mutex mMutex; // Protects mGMPThread, mAbstractGMPThread, mPluginCrashHelpers,
// mGMPThreadShutdown and some members in derived classes.
nsCOMPtr<nsIThread> mGMPThread;
RefPtr<AbstractThread> mAbstractGMPThread;
bool mGMPThreadShutdown;
bool mShuttingDownOnGMPThread;
+ Atomic<bool> mXPCOMWillShutdown;
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
@@ -382,16 +382,18 @@ GeckoMediaPluginServiceChild::Observe(ns
if (!strcmp(NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, aTopic)) {
if (mServiceChild) {
mozilla::SyncRunnable::DispatchToThread(mGMPThread,
WrapRunnable(mServiceChild.get(),
&PGMPServiceChild::Close));
mServiceChild = nullptr;
}
ShutdownGMPThread();
+ } else if (!strcmp(NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, aTopic)) {
+ mXPCOMWillShutdown = true;
}
return NS_OK;
}
RefPtr<GeckoMediaPluginServiceChild::GetServiceChildPromise>
GeckoMediaPluginServiceChild::GetServiceChild()
{
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -304,16 +304,18 @@ GeckoMediaPluginServiceParent::Observe(n
// GMP thread has already shutdown.
MOZ_ASSERT(mPlugins.IsEmpty());
mWaitingForPluginsSyncShutdown = false;
}
} else if (!strcmp(NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, aTopic)) {
MOZ_ASSERT(mShuttingDown);
ShutdownGMPThread();
+ } else if (!strcmp(NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, aTopic)) {
+ mXPCOMWillShutdown = true;
} else if (!strcmp("last-pb-context-exited", aTopic)) {
// When Private Browsing mode exits, all we need to do is clear
// mTempNodeIds. This drops all the node ids we've cached in memory
// for PB origin-pairs. If we try to open an origin-pair for non-PB
// mode, we'll get the NodeId salt stored on-disk, and if we try to
// open a PB mode origin-pair, we'll re-generate new salt.
mTempNodeIds.Clear();
} else if (!strcmp("browser:purge-session-history", aTopic)) {
--- a/dom/media/gtest/TestCDMStorage.cpp
+++ b/dom/media/gtest/TestCDMStorage.cpp
@@ -460,17 +460,22 @@ class CDMStorageTest
service->GetCDM(aNodeId, Move(tags), nullptr);
auto thread = GetAbstractGMPThread();
promise->Then(thread,
__func__,
[self, aUpdates](RefPtr<gmp::ChromiumCDMParent> cdm) {
self->mCDM = cdm;
EXPECT_TRUE(!!self->mCDM);
self->mCallback.reset(new CallbackProxy(self));
- self->mCDM->Init(self->mCallback.get(), false, true, GetMainThreadEventTarget());
+ nsCString failureReason;
+ self->mCDM->Init(self->mCallback.get(),
+ false,
+ true,
+ GetMainThreadEventTarget(),
+ failureReason);
for (auto& update : aUpdates) {
self->Update(update);
}
},
[](MediaResult rv) { EXPECT_TRUE(false); });
}