Bug 1336345. Part 1 - register shutdown blocker only once when the 1st MediaDecoder is created.
MozReview-Commit-ID: 80DEZEEhm9E
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -455,16 +455,17 @@ MediaDecoder::MediaDecoder(MediaDecoderO
mWatchManager.Watch(mPlayState, &MediaDecoder::UpdateLogicalPosition);
mWatchManager.Watch(mLogicallySeeking, &MediaDecoder::UpdateLogicalPosition);
// mIgnoreProgressData
mWatchManager.Watch(mLogicallySeeking, &MediaDecoder::SeekingChanged);
mWatchManager.Watch(mIsAudioDataAudible, &MediaDecoder::NotifyAudibleStateChanged);
+ MediaShutdownManager::InitStatics();
MediaShutdownManager::Instance().Register(this);
}
#undef INIT_MIRROR
#undef INIT_CANONICAL
void
MediaDecoder::Shutdown()
--- a/dom/media/MediaShutdownManager.cpp
+++ b/dom/media/MediaShutdownManager.cpp
@@ -33,19 +33,17 @@ MediaShutdownManager::~MediaShutdownMana
// Note that we don't use ClearOnShutdown() on this StaticRefPtr, as that
// may interfere with our shutdown listener.
StaticRefPtr<MediaShutdownManager> MediaShutdownManager::sInstance;
MediaShutdownManager&
MediaShutdownManager::Instance()
{
MOZ_ASSERT(NS_IsMainThread());
- if (!sInstance) {
- sInstance = new MediaShutdownManager();
- }
+ MOZ_DIAGNOSTIC_ASSERT(sInstance);
return *sInstance;
}
static nsCOMPtr<nsIAsyncShutdownClient>
GetShutdownBarrier()
{
nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdown();
MOZ_RELEASE_ASSERT(svc);
@@ -58,16 +56,43 @@ GetShutdownBarrier()
rv = svc->GetXpcomWillShutdown(getter_AddRefs(barrier));
}
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
MOZ_RELEASE_ASSERT(barrier);
return barrier.forget();
}
void
+MediaShutdownManager::InitStatics()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ static bool sInitDone = false;
+ if (sInitDone) {
+ return;
+ }
+
+ sInitDone = true;
+ sInstance = new MediaShutdownManager();
+
+ nsresult rv = GetShutdownBarrier()->AddBlocker(
+ sInstance, NS_LITERAL_STRING(__FILE__), __LINE__,
+ NS_LITERAL_STRING("MediaShutdownManager shutdown"));
+ if (NS_FAILED(rv)) {
+ // Leak the buffer on the heap to make sure that it lives long enough,
+ // as MOZ_CRASH_ANNOTATE expects the pointer passed to it to live to
+ // the end of the program.
+ const size_t CAPACITY = 256;
+ auto buf = new char[CAPACITY];
+ snprintf(buf, CAPACITY, "Failed to add shutdown blocker! rv=%x", uint32_t(rv));
+ MOZ_CRASH_ANNOTATE(buf);
+ MOZ_REALLY_CRASH();
+ }
+}
+
+void
MediaShutdownManager::EnsureCorrectShutdownObserverState()
{
bool needShutdownObserver = mDecoders.Count() > 0;
if (needShutdownObserver != mIsObservingShutdown) {
mIsObservingShutdown = needShutdownObserver;
if (mIsObservingShutdown) {
nsresult rv = GetShutdownBarrier()->AddBlocker(
this, NS_LITERAL_STRING(__FILE__), __LINE__,
@@ -88,36 +113,50 @@ MediaShutdownManager::EnsureCorrectShutd
// this instance, so don't deref |this| clearing sInstance.
sInstance = nullptr;
DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::BlockShutdown() end."));
}
}
}
void
+MediaShutdownManager::RemoveBlocker()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(mIsDoingXPCOMShutDown);
+ MOZ_ASSERT(mDecoders.Count() == 0);
+ GetShutdownBarrier()->RemoveBlocker(this);
+ // Clear our singleton reference. This will probably delete
+ // this instance, so don't deref |this| clearing sInstance.
+ sInstance = nullptr;
+ DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::BlockShutdown() end."));
+}
+
+void
MediaShutdownManager::Register(MediaDecoder* aDecoder)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(!mIsDoingXPCOMShutDown);
// Don't call Register() after you've Unregistered() all the decoders,
// that's not going to work.
MOZ_ASSERT(!mDecoders.Contains(aDecoder));
mDecoders.PutEntry(aDecoder);
MOZ_ASSERT(mDecoders.Contains(aDecoder));
MOZ_ASSERT(mDecoders.Count() > 0);
- EnsureCorrectShutdownObserverState();
}
void
MediaShutdownManager::Unregister(MediaDecoder* aDecoder)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mDecoders.Contains(aDecoder));
mDecoders.RemoveEntry(aDecoder);
- EnsureCorrectShutdownObserverState();
+ if (mIsDoingXPCOMShutDown && mDecoders.Count() == 0) {
+ RemoveBlocker();
+ }
}
NS_IMETHODIMP
MediaShutdownManager::GetName(nsAString& aName)
{
aName = NS_LITERAL_STRING("MediaShutdownManager: shutdown");
return NS_OK;
}
@@ -134,18 +173,21 @@ MediaShutdownManager::BlockShutdown(nsIA
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(sInstance);
DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::BlockShutdown() start..."));
// Set this flag to ensure no Register() is allowed when Shutdown() begins.
mIsDoingXPCOMShutDown = true;
- DebugOnly<uint32_t> oldCount = mDecoders.Count();
- MOZ_ASSERT(oldCount > 0);
+ auto oldCount = mDecoders.Count();
+ if (oldCount == 0) {
+ RemoveBlocker();
+ return NS_OK;
+ }
// Iterate over the decoders and shut them down.
for (auto iter = mDecoders.Iter(); !iter.Done(); iter.Next()) {
MediaDecoderOwner* owner = iter.Get()->GetKey()->GetOwner();
if (owner) {
// The owner will call MediaDecoder::Shutdown() and
// drop its reference to the decoder.
owner->NotifyXPCOMShutdown();
--- a/dom/media/MediaShutdownManager.h
+++ b/dom/media/MediaShutdownManager.h
@@ -49,16 +49,18 @@ class MediaDecoder;
// MediaShutdownManager& instance = MediaShutdownManager::Instance();
// instance.Unregister(someDecoder); // Warning! May delete instance!
// instance.Register(someOtherDecoder); // BAD! instance may be dangling!
class MediaShutdownManager : public nsIAsyncShutdownBlocker {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIASYNCSHUTDOWNBLOCKER
+ static void InitStatics();
+
// The MediaShutdownManager is a singleton, access its instance with
// this accessor.
static MediaShutdownManager& Instance();
// Notifies the MediaShutdownManager that it needs to track the shutdown
// of this MediaDecoder.
void Register(MediaDecoder* aDecoder);
@@ -66,16 +68,17 @@ public:
// tracking has shutdown, and it no longer needs to be shutdown in the
// xpcom-shutdown listener.
void Unregister(MediaDecoder* aDecoder);
private:
MediaShutdownManager();
virtual ~MediaShutdownManager();
+ void RemoveBlocker();
// Ensures we have a shutdown listener if we need one, and removes the
// listener and destroys the singleton if we don't.
void EnsureCorrectShutdownObserverState();
static StaticRefPtr<MediaShutdownManager> sInstance;
// References to the MediaDecoder. The decoders unregister themselves