Bug 1336345. Part 1 - register shutdown blocker on startup. draft
authorJW Wang <jwwang@mozilla.com>
Fri, 03 Feb 2017 15:12:22 +0800
changeset 479147 e7a08656b5578ef62922024fa1821d9fe99b205c
parent 479146 3fa87e2d7d4cdfa33058dae397b92ece01444b94
child 479148 410cc275cf00bfb3f217e4e058437b5dab8fa226
push id44158
push userjwwang@mozilla.com
push dateMon, 06 Feb 2017 02:30:28 +0000
bugs1336345
milestone54.0a1
Bug 1336345. Part 1 - register shutdown blocker on startup. MozReview-Commit-ID: 80DEZEEhm9E
dom/media/MediaShutdownManager.cpp
dom/media/MediaShutdownManager.h
layout/build/nsLayoutStatics.cpp
--- a/dom/media/MediaShutdownManager.cpp
+++ b/dom/media/MediaShutdownManager.cpp
@@ -33,19 +33,16 @@ 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();
-  }
   return *sInstance;
 }
 
 static nsCOMPtr<nsIAsyncShutdownClient>
 GetShutdownBarrier()
 {
   nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdown();
   MOZ_RELEASE_ASSERT(svc);
@@ -58,16 +55,39 @@ GetShutdownBarrier()
     rv = svc->GetXpcomWillShutdown(getter_AddRefs(barrier));
   }
   MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
   MOZ_RELEASE_ASSERT(barrier);
   return barrier.forget();
 }
 
 void
+MediaShutdownManager::InitStatics()
+{
+  sInstance = new MediaShutdownManager();
+
+  // Dispatch a task to avoid "ASSERTION: Recursive GetService!".
+  NS_DispatchToCurrentThread(NS_NewRunnableFunction([] () {
+    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 +108,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 +168,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
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -123,16 +123,17 @@ using namespace mozilla::system;
 #include "mozilla/dom/CustomElementRegistry.h"
 #include "mozilla/dom/time/DateCacheCleaner.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "TouchManager.h"
 #include "MediaDecoder.h"
 #include "MediaPrefs.h"
+#include "MediaShutdownManager.h"
 #include "mozilla/dom/devicestorage/DeviceStorageStatics.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/StaticPresData.h"
 #include "mozilla/dom/WebIDLGlobalNameHash.h"
 
 using namespace mozilla;
 using namespace mozilla::net;
 using namespace mozilla::dom;
@@ -299,16 +300,18 @@ nsLayoutStatics::Initialize()
 
   ServiceWorkerRegistrar::Initialize();
 
 #ifdef DEBUG
   nsStyleContext::Initialize();
   mozilla::LayerAnimationInfo::Initialize();
 #endif
 
+  MediaShutdownManager::InitStatics();
+
   MediaDecoder::InitStatics();
 
   PromiseDebugging::Init();
 
   mozilla::dom::devicestorage::DeviceStorageStatics::Initialize();
 
   mozilla::dom::WebCryptoThreadPool::Initialize();