Bug 1448040 - Remove HangMonitor/ChromeHangs r?Nika draft
authorDoug Thayer <dothayer@mozilla.com>
Sun, 29 Apr 2018 18:21:20 -0700
changeset 809382 e2bdd6e18841589d097c00791ba769ad374c89ad
parent 809260 1c33a38da75d550750923358e73d7af2102b9c1d
push id113654
push userbmo:dothayer@mozilla.com
push dateThu, 21 Jun 2018 22:59:15 +0000
reviewersNika
bugs1448040
milestone62.0a1
Bug 1448040 - Remove HangMonitor/ChromeHangs r?Nika Fairly straightforward, just a blanket removal. Haven't heard anything on dev-platform or fx-data-dev regarding this removal, so I think it's likely safe to remove on Nightly, and we can revert if anyone makes a fuss. As part of removing the HangMonitor, I renamed a few things and reorganized the namespaces to not depend on a HangMonitor namespace. Hopefully this doesn't produce too much noise in the diff, it just seemed appropriate to move everything around rather than keep dangling vestiges of the old system. MozReview-Commit-ID: 8C8NFnOP5GU
dom/base/nsContentUtils.cpp
dom/ipc/ContentChild.cpp
dom/plugins/ipc/PluginModuleParent.cpp
dom/plugins/ipc/PluginModuleParent.h
ipc/mscom/MainThreadInvoker.cpp
js/src/tests/user.js
modules/libpref/init/all.js
testing/marionette/client/marionette_driver/geckoinstance.py
testing/marionette/components/marionette.js
toolkit/components/backgroundhangmonitor/BackgroundHangMonitor.cpp
toolkit/components/backgroundhangmonitor/BackgroundHangMonitor.h
toolkit/components/backgroundhangmonitor/HangAnnotations.cpp
toolkit/components/backgroundhangmonitor/HangAnnotations.h
toolkit/components/backgroundhangmonitor/moz.build
toolkit/components/telemetry/CombinedStacks.cpp
toolkit/components/telemetry/HangReports.cpp
toolkit/components/telemetry/HangReports.h
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/telemetry/Telemetry.h
toolkit/components/telemetry/TelemetrySession.jsm
toolkit/components/telemetry/docs/data/main-ping.rst
toolkit/components/telemetry/moz.build
toolkit/components/telemetry/nsITelemetry.idl
toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
toolkit/content/aboutTelemetry.js
toolkit/content/aboutTelemetry.xhtml
toolkit/crashreporter/docs/index.rst
toolkit/locales/en-US/chrome/global/aboutTelemetry.dtd
toolkit/locales/en-US/chrome/global/aboutTelemetry.properties
widget/android/GeckoEditableSupport.h
widget/android/jni/moz.build
widget/android/nsAppShell.cpp
widget/android/nsAppShell.h
widget/android/nsWindow.cpp
widget/cocoa/nsAppShell.mm
widget/gtk/nsAppShell.cpp
widget/windows/WinUtils.cpp
widget/windows/nsAppShell.cpp
widget/windows/nsWindow.cpp
xpcom/build/XPCOMInit.cpp
xpcom/threads/CPUUsageWatcher.cpp
xpcom/threads/CPUUsageWatcher.h
xpcom/threads/HangAnnotations.cpp
xpcom/threads/HangAnnotations.h
xpcom/threads/HangMonitor.cpp
xpcom/threads/HangMonitor.h
xpcom/threads/moz.build
xpcom/threads/nsThread.cpp
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -28,16 +28,17 @@
 #include "gfxDrawable.h"
 #include "gfxPrefs.h"
 #include "ImageOps.h"
 #include "mozAutoDocUpdate.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/AutoTimelineMarker.h"
+#include "mozilla/BackgroundHangMonitor.h"
 #include "mozilla/Base64.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/dom/BlobURLProtocolHandler.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/CustomElementRegistry.h"
 #include "mozilla/dom/MessageBroadcaster.h"
@@ -595,25 +596,25 @@ NS_IMPL_ISUPPORTS(nsContentUtils::nsCont
  * interacting with the browser. It listens to observer events to toggle the
  * value of the sUserActive static.
  *
  * This class is an internal implementation detail.
  * nsContentUtils::GetUserIsInteracting() should be used to access current
  * user interaction status.
  */
 class nsContentUtils::UserInteractionObserver final : public nsIObserver
-                                                    , public HangMonitor::Annotator
+                                                    , public BackgroundHangAnnotator
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   void Init();
   void Shutdown();
-  void AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) override;
+  void AnnotateHang(BackgroundHangAnnotations& aAnnotations) override;
 
   static Atomic<bool> sUserActive;
 
 private:
   ~UserInteractionObserver() {}
 };
 
 /* static */
@@ -10775,43 +10776,43 @@ void
 nsContentUtils::UserInteractionObserver::Init()
 {
   // Listen for the observer messages from EventStateManager which are telling
   // us whether or not the user is interacting.
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   obs->AddObserver(this, kUserInteractionInactive, false);
   obs->AddObserver(this, kUserInteractionActive, false);
 
-  // We can't register ourselves as an annotator yet, as the HangMonitor hasn't
-  // started yet. It will have started by the time we have the chance to spin
-  // the event loop.
+  // We can't register ourselves as an annotator yet, as the
+  // BackgroundHangMonitor hasn't started yet. It will have started by the
+  // time we have the chance to spin the event loop.
   RefPtr<UserInteractionObserver> self = this;
   NS_DispatchToMainThread(
     NS_NewRunnableFunction("nsContentUtils::UserInteractionObserver::Init",
-                           [=]() { HangMonitor::RegisterAnnotator(*self); }));
+                           [=]() { BackgroundHangMonitor::RegisterAnnotator(*self); }));
 }
 
 void
 nsContentUtils::UserInteractionObserver::Shutdown()
 {
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     obs->RemoveObserver(this, kUserInteractionInactive);
     obs->RemoveObserver(this, kUserInteractionActive);
   }
 
-  HangMonitor::UnregisterAnnotator(*this);
+  BackgroundHangMonitor::UnregisterAnnotator(*this);
 }
 
 /**
- * NB: This function is always called by the HangMonitor thread.
+ * NB: This function is always called by the BackgroundHangMonitor thread.
  *     Plan accordingly
  */
 void
-nsContentUtils::UserInteractionObserver::AnnotateHang(HangMonitor::HangAnnotations& aAnnotations)
+nsContentUtils::UserInteractionObserver::AnnotateHang(BackgroundHangAnnotations& aAnnotations)
 {
   // NOTE: Only annotate the hang report if the user is known to be interacting.
   if (sUserActive) {
     aAnnotations.AddAnnotation(NS_LITERAL_STRING("UserInteracting"), true);
   }
 }
 
 NS_IMETHODIMP
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -10,16 +10,17 @@
 
 #include "ContentChild.h"
 
 #include "GeckoProfiler.h"
 #include "TabChild.h"
 #include "HandlerServiceChild.h"
 
 #include "mozilla/Attributes.h"
+#include "mozilla/BackgroundHangMonitor.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ProcessHangMonitorIPC.h"
 #include "mozilla/Unused.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/TelemetryIPC.h"
 #include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h"
 #include "mozilla/docshell/OfflineCacheUpdateChild.h"
@@ -505,25 +506,25 @@ ConsoleListener::Observe(nsIConsoleMessa
   nsresult rv = aMessage->GetMessageMoz(getter_Copies(msg));
   NS_ENSURE_SUCCESS(rv, rv);
   mChild->SendConsoleMessage(msg);
   return NS_OK;
 }
 
 #ifdef NIGHTLY_BUILD
 /**
- * The singleton of this class is registered with the HangMonitor as an
+ * The singleton of this class is registered with the BackgroundHangMonitor as an
  * annotator, so that the hang monitor can record whether or not there were
  * pending input events when the thread hung.
  */
 class PendingInputEventHangAnnotator final
-  : public HangMonitor::Annotator
+  : public BackgroundHangAnnotator
 {
 public:
-  virtual void AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) override
+  virtual void AnnotateHang(BackgroundHangAnnotations& aAnnotations) override
   {
     int32_t pending = ContentChild::GetSingleton()->GetPendingInputEvents();
     if (pending > 0) {
       aAnnotations.AddAnnotation(NS_LITERAL_STRING("PendingInput"), pending);
     }
   }
 
   static PendingInputEventHangAnnotator sSingleton;
@@ -707,17 +708,17 @@ ContentChild::Init(MessageLoop* aIOLoop,
 
   SetProcessName(NS_LITERAL_STRING("Web Content"));
 
 #ifdef NIGHTLY_BUILD
   // NOTE: We have to register the annotator on the main thread, as annotators
   // only affect a single thread.
   SystemGroup::Dispatch(TaskCategory::Other,
                         NS_NewRunnableFunction("RegisterPendingInputEventHangAnnotator", [] {
-                          HangMonitor::RegisterAnnotator(
+                          BackgroundHangMonitor::RegisterAnnotator(
                             PendingInputEventHangAnnotator::sSingleton);
                         }));
 #endif
 
   return true;
 }
 
 void
@@ -3049,17 +3050,17 @@ ContentChild::ShutdownInternal()
         &ContentChild::ShutdownInternal),
       100);
     return;
   }
 
   mShuttingDown = true;
 
 #ifdef NIGHTLY_BUILD
-  HangMonitor::UnregisterAnnotator(PendingInputEventHangAnnotator::sSingleton);
+  BackgroundHangMonitor::UnregisterAnnotator(PendingInputEventHangAnnotator::sSingleton);
 #endif
 
   if (mPolicy) {
     mPolicy->Deactivate();
     mPolicy = nullptr;
   }
 
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -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/. */
 
 #include "mozilla/plugins/PluginModuleParent.h"
 
 #include "base/process_util.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/AutoRestore.h"
+#include "mozilla/BackgroundHangMonitor.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/ipc/CrashReporterClient.h"
 #include "mozilla/ipc/CrashReporterHost.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 #include "mozilla/ipc/MessageChannel.h"
 #include "mozilla/ipc/ProtocolUtils.h"
@@ -655,17 +656,17 @@ PluginModuleChromeParent::PluginModuleCh
 #endif
   , mIsBlocklisted(false)
   , mIsCleaningFromTimeout(false)
 {
     NS_ASSERTION(mSubprocess, "Out of memory!");
     mSandboxLevel = aSandboxLevel;
     mRunID = GeckoChildProcessHost::GetUniqueID();
 
-    mozilla::HangMonitor::RegisterAnnotator(*this);
+    mozilla::BackgroundHangMonitor::RegisterAnnotator(*this);
 }
 
 PluginModuleChromeParent::~PluginModuleChromeParent()
 {
     if (!OkToCleanup()) {
         MOZ_CRASH("unsafe destruction");
     }
 
@@ -708,17 +709,17 @@ PluginModuleChromeParent::~PluginModuleC
     Preferences::UnregisterCallback(TimeoutChanged, kHangUIMinDisplayPref, this);
 
     if (mHangUIParent) {
         delete mHangUIParent;
         mHangUIParent = nullptr;
     }
 #endif
 
-    mozilla::HangMonitor::UnregisterAnnotator(*this);
+    mozilla::BackgroundHangMonitor::UnregisterAnnotator(*this);
 }
 
 void
 PluginModuleChromeParent::WriteExtraDataForMinidump()
 {
     // mCrashReporterMutex is already held by the caller
     mCrashReporterMutex.AssertCurrentThreadOwns();
 
@@ -987,26 +988,26 @@ PluginModuleChromeParent::ExitedCxxStack
 {
     mHangAnnotationFlags = 0;
 #ifdef XP_WIN
     FinishHangUI();
 #endif
 }
 
 /**
- * This function is always called by the HangMonitor thread.
+ * This function is always called by the BackgroundHangMonitor thread.
  */
 void
-PluginModuleChromeParent::AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations)
+PluginModuleChromeParent::AnnotateHang(mozilla::BackgroundHangAnnotations& aAnnotations)
 {
     uint32_t flags = mHangAnnotationFlags;
     if (flags) {
         /* We don't actually annotate anything specifically for kInPluginCall;
            we use it to determine whether to annotate other things. It will
-           be pretty obvious from the ChromeHang stack that we're in a plugin
+           be pretty obvious from the hang stack that we're in a plugin
            call when the hang occurred. */
         if (flags & kHangUIShown) {
             aAnnotations.AddAnnotation(NS_LITERAL_STRING("HangUIShown"),
                                        true);
         }
         if (flags & kHangUIContinued) {
             aAnnotations.AddAnnotation(NS_LITERAL_STRING("HangUIContinued"),
                                        true);
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -348,17 +348,17 @@ class PluginModuleContentParent : public
 
     static PluginModuleContentParent* sSavedModuleParent;
 
     uint32_t mPluginId;
 };
 
 class PluginModuleChromeParent
     : public PluginModuleParent
-    , public mozilla::HangMonitor::Annotator
+    , public mozilla::BackgroundHangAnnotator
 {
     friend class mozilla::ipc::CrashReporterHost;
     using TerminateChildProcessCallback =
         mozilla::ipc::CrashReporterHost::CallbackWrapper<bool>;
     using TakeFullMinidumpCallback =
         mozilla::ipc::CrashReporterHost::CallbackWrapper<nsString>;
   public:
     /**
@@ -472,17 +472,17 @@ private:
 
     void
     ExitedCxxStack() override;
 
     mozilla::ipc::IProtocol* GetInvokingProtocol();
     PluginInstanceParent* GetManagingInstance(mozilla::ipc::IProtocol* aProtocol);
 
     virtual void
-    AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations) override;
+    AnnotateHang(mozilla::BackgroundHangAnnotations& aAnnotations) override;
 
     virtual bool ShouldContinueFromReplyTimeout() override;
 
     void ProcessFirstMinidump();
     void WriteExtraDataForMinidump();
     void RetainPluginRef();
     void ReleasePluginRef();
 
--- a/ipc/mscom/MainThreadInvoker.cpp
+++ b/ipc/mscom/MainThreadInvoker.cpp
@@ -4,19 +4,19 @@
  * 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/. */
 
 #include "mozilla/mscom/MainThreadInvoker.h"
 
 #include "GeckoProfiler.h"
 #include "MainThreadUtils.h"
 #include "mozilla/Assertions.h"
+#include "mozilla/BackgroundHangMonitor.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/DebugOnly.h"
-#include "mozilla/HangMonitor.h"
 #include "mozilla/mscom/SpinEvent.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/SystemGroup.h"
 #include "private/prpriv.h" // For PR_GetThreadID
 #include <winternl.h> // For NTSTATUS and NTAPI
 
 namespace {
 
@@ -176,17 +176,17 @@ MainThreadInvoker::Invoke(already_AddRef
   mDuration = syncRunnable->GetDuration();
   return result;
 }
 
 /* static */ VOID CALLBACK
 MainThreadInvoker::MainThreadAPC(ULONG_PTR aParam)
 {
   AUTO_PROFILER_THREAD_WAKE;
-  mozilla::HangMonitor::NotifyActivity(mozilla::HangMonitor::kGeneralActivity);
+  mozilla::BackgroundHangMonitor().NotifyActivity();
   MOZ_ASSERT(NS_IsMainThread());
   auto runnable = reinterpret_cast<SyncRunnable*>(aParam);
   runnable->APCRun();
   NS_RELEASE(runnable);
 }
 
 } // namespace mscom
 } // namespace mozilla
--- a/js/src/tests/user.js
+++ b/js/src/tests/user.js
@@ -2,17 +2,16 @@ user_pref("app.update.enabled", false);
 user_pref("browser.dom.window.dump.enabled", true);
 user_pref("browser.sessionstore.resume_from_crash", false);
 user_pref("browser.shell.checkDefaultBrowser", false);
 user_pref("browser.xul.error_pages.enabled", true);
 user_pref("security.fileuri.strict_origin_policy", false);
 user_pref("dom.allow_scripts_to_close_windows", true);
 user_pref("dom.disable_open_during_load", false);
 user_pref("dom.max_script_run_time", 0);
-user_pref("hangmonitor.timeout", 0);
 user_pref("dom.max_chrome_script_run_time", 0);
 user_pref("javascript.allow.mailnews", true);
 user_pref("javascript.options.showInConsole", true);
 user_pref("layout.css.report_errors", true);
 user_pref("browser.warnOnQuit", false);
 user_pref("browser.cache.check_doc_frequency", 1);
 user_pref("extensions.checkCompatibility", false);
 user_pref("extensions.checkUpdateSecurity", false);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3110,22 +3110,16 @@ pref("input_event_queue.duration.min", 1
 // The default amount of time (milliseconds) required for handling a input
 // event.
 pref("input_event_queue.default_duration_per_event", 1);
 
 // The number of processed input events we use to predict the amount of time
 // required to process the following input events.
 pref("input_event_queue.count_for_prediction", 9);
 
-// Hang monitor timeout after which we kill the browser, in seconds
-// (0 is disabled)
-// Disabled on all platforms per bug 705748 until the found issues are
-// resolved.
-pref("hangmonitor.timeout", 0);
-
 pref("plugins.load_appdir_plugins", false);
 // If true, plugins will be click to play
 pref("plugins.click_to_play", false);
 
 // This only supports one hidden ctp plugin, edit nsPluginArray.cpp if adding a second
 pref("plugins.navigator.hidden_ctp_plugin", "");
 
 // The default value for nsIPluginTag.enabledState (STATE_ENABLED = 2)
--- a/testing/marionette/client/marionette_driver/geckoinstance.py
+++ b/testing/marionette/client/marionette_driver/geckoinstance.py
@@ -87,19 +87,16 @@ class GeckoInstance(object):
         "general.useragent.updates.enabled": False,
 
         # Always use network provider for geolocation tests
         # so we bypass the OSX dialog raised by the corelocation provider
         "geo.provider.testing": True,
         # Do not scan Wifi
         "geo.wifi.scan": False,
 
-        # No hang monitor
-        "hangmonitor.timeout": 0,
-
         "javascript.options.showInConsole": True,
 
         # Enable Marionette component
         "marionette.enabled": True,
         # (deprecated and can be removed when Firefox 60 ships)
         "marionette.defaultPrefs.enabled": True,
 
         # Disable recommended automation prefs in CI
--- a/testing/marionette/components/marionette.js
+++ b/testing/marionette/components/marionette.js
@@ -211,19 +211,16 @@ const RECOMMENDED_PREFS = new Map([
 
   // Always use network provider for geolocation tests so we bypass the
   // macOS dialog raised by the corelocation provider
   ["geo.provider.testing", true],
 
   // Do not scan Wifi
   ["geo.wifi.scan", false],
 
-  // No hang monitor
-  ["hangmonitor.timeout", 0],
-
   // Show chrome errors and warnings in the error console
   ["javascript.options.showInConsole", true],
 
   // Do not prompt with long usernames or passwords in URLs
   ["network.http.phishy-userpass-length", 255],
 
   // Do not prompt for temporary redirects
   ["network.http.prompt-temp-redirect", false],
--- a/toolkit/components/backgroundhangmonitor/BackgroundHangMonitor.cpp
+++ b/toolkit/components/backgroundhangmonitor/BackgroundHangMonitor.cpp
@@ -197,19 +197,19 @@ public:
   BackgroundHangMonitor::ThreadType mThreadType;
 #ifdef MOZ_GECKO_PROFILER
   // Platform-specific helper to get hang stacks
   ThreadStackHelper mStackHelper;
 #endif
   // Stack of current hang
   HangStack mHangStack;
   // Annotations for the current hang
-  HangMonitor::HangAnnotations mAnnotations;
+  BackgroundHangAnnotations mAnnotations;
   // Annotators registered for this thread
-  HangMonitor::Observer::Annotators mAnnotators;
+  BackgroundHangAnnotators mAnnotators;
   // The name of the runnable which is hanging the current process
   nsCString mRunnableName;
   // The name of the thread which is being monitored
   nsCString mThreadName;
 
   BackgroundHangThread(const char* aName,
                        uint32_t aTimeoutMs,
                        uint32_t aMaxTimeoutMs,
@@ -483,30 +483,24 @@ BackgroundHangThread::~BackgroundHangThr
 }
 
 void
 BackgroundHangThread::ReportHang(TimeDuration aHangTime)
 {
   // Recovered from a hang; called on the monitor thread
   // mManager->mLock IS locked
 
-  nsTArray<HangAnnotation> annotations;
-  for (auto& annotation : mAnnotations) {
-    HangAnnotation annot(annotation.mName, annotation.mValue);
-    annotations.AppendElement(std::move(annot));
-  }
-
   HangDetails hangDetails(
     aHangTime,
     nsDependentCString(XRE_ChildProcessTypeToString(XRE_GetProcessType())),
     VoidString(),
     mThreadName,
     mRunnableName,
     std::move(mHangStack),
-    std::move(annotations)
+    std::move(mAnnotations)
   );
 
   // If the hang processing thread exists, we can process the native stack
   // on it. Otherwise, we are unable to report a native stack, so we just
   // report without one.
   if (mManager->mHangProcessingThread) {
     nsCOMPtr<nsIRunnable> processHangStackRunnable =
       new ProcessHangStackRunnable(std::move(hangDetails));
@@ -762,31 +756,31 @@ BackgroundHangMonitor::NotifyWait()
 
   if (Telemetry::CanRecordExtended()) {
     mThread->NotifyWait();
   }
 #endif
 }
 
 bool
-BackgroundHangMonitor::RegisterAnnotator(HangMonitor::Annotator& aAnnotator)
+BackgroundHangMonitor::RegisterAnnotator(BackgroundHangAnnotator& aAnnotator)
 {
 #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
   BackgroundHangThread* thisThread = BackgroundHangThread::FindThread();
   if (!thisThread) {
     return false;
   }
   return thisThread->mAnnotators.Register(aAnnotator);
 #else
   return false;
 #endif
 }
 
 bool
-BackgroundHangMonitor::UnregisterAnnotator(HangMonitor::Annotator& aAnnotator)
+BackgroundHangMonitor::UnregisterAnnotator(BackgroundHangAnnotator& aAnnotator)
 {
 #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
   BackgroundHangThread* thisThread = BackgroundHangThread::FindThread();
   if (!thisThread) {
     return false;
   }
   return thisThread->mAnnotators.Unregister(aAnnotator);
 #else
--- a/toolkit/components/backgroundhangmonitor/BackgroundHangMonitor.h
+++ b/toolkit/components/backgroundhangmonitor/BackgroundHangMonitor.h
@@ -184,22 +184,22 @@ public:
    */
   void NotifyWait();
 
   /**
    * Register an annotator with BHR for the current thread.
    * @param aAnnotator annotator to register
    * @return true if the annotator was registered, otherwise false.
    */
-  static bool RegisterAnnotator(HangMonitor::Annotator& aAnnotator);
+  static bool RegisterAnnotator(BackgroundHangAnnotator& aAnnotator);
 
   /**
    * Unregister an annotator that was previously registered via
    * RegisterAnnotator.
    * @param aAnnotator annotator to unregister
    * @return true if there are still remaining annotators registered
    */
-  static bool UnregisterAnnotator(HangMonitor::Annotator& aAnnotator);
+  static bool UnregisterAnnotator(BackgroundHangAnnotator& aAnnotator);
 };
 
 } // namespace mozilla
 
 #endif // mozilla_BackgroundHangMonitor_h
new file mode 100644
--- /dev/null
+++ b/toolkit/components/backgroundhangmonitor/HangAnnotations.cpp
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+#include "mozilla/HangAnnotations.h"
+
+#include <vector>
+
+#include "MainThreadUtils.h"
+#include "mozilla/DebugOnly.h"
+#include "nsXULAppAPI.h"
+#include "mozilla/BackgroundHangMonitor.h"
+
+namespace mozilla {
+
+void
+BackgroundHangAnnotations::AddAnnotation(const nsString& aName, const int32_t aData)
+{
+  nsAutoString dataString;
+  dataString.AppendInt(aData);
+  AppendElement(HangAnnotation(aName, dataString));
+}
+
+void
+BackgroundHangAnnotations::AddAnnotation(const nsString& aName, const double aData)
+{
+  nsAutoString dataString;
+  dataString.AppendFloat(aData);
+  AppendElement(HangAnnotation(aName, dataString));
+}
+
+void
+BackgroundHangAnnotations::AddAnnotation(const nsString& aName, const nsString& aData)
+{
+  AppendElement(HangAnnotation(aName, aData));
+}
+
+void
+BackgroundHangAnnotations::AddAnnotation(const nsString& aName, const nsCString& aData)
+{
+  NS_ConvertUTF8toUTF16 dataString(aData);
+  AppendElement(HangAnnotation(aName, dataString));
+}
+
+void
+BackgroundHangAnnotations::AddAnnotation(const nsString& aName, const bool aData)
+{
+  if (aData) {
+    AppendElement(HangAnnotation(aName, NS_LITERAL_STRING("true")));
+  } else {
+    AppendElement(HangAnnotation(aName, NS_LITERAL_STRING("false")));
+  }
+}
+
+BackgroundHangAnnotators::BackgroundHangAnnotators()
+  : mMutex("BackgroundHangAnnotators::mMutex")
+{
+  MOZ_COUNT_CTOR(BackgroundHangAnnotators);
+}
+
+BackgroundHangAnnotators::~BackgroundHangAnnotators()
+{
+  MOZ_ASSERT(mAnnotators.empty());
+  MOZ_COUNT_DTOR(BackgroundHangAnnotators);
+}
+
+bool
+BackgroundHangAnnotators::Register(BackgroundHangAnnotator& aAnnotator)
+{
+  MutexAutoLock lock(mMutex);
+  auto result = mAnnotators.insert(&aAnnotator);
+  return result.second;
+}
+
+bool
+BackgroundHangAnnotators::Unregister(BackgroundHangAnnotator& aAnnotator)
+{
+  MutexAutoLock lock(mMutex);
+  DebugOnly<std::set<BackgroundHangAnnotator*>::size_type> numErased;
+  numErased = mAnnotators.erase(&aAnnotator);
+  MOZ_ASSERT(numErased == 1);
+  return mAnnotators.empty();
+}
+
+BackgroundHangAnnotations
+BackgroundHangAnnotators::GatherAnnotations()
+{
+  BackgroundHangAnnotations annotations;
+  { // Scope for lock
+    MutexAutoLock lock(mMutex);
+    for (std::set<BackgroundHangAnnotator*>::iterator i = mAnnotators.begin(),
+         e = mAnnotators.end();
+         i != e; ++i) {
+      (*i)->AnnotateHang(annotations);
+    }
+  }
+  return annotations;
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/toolkit/components/backgroundhangmonitor/HangAnnotations.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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 mozilla_HangAnnotations_h
+#define mozilla_HangAnnotations_h
+
+#include <set>
+
+#include "mozilla/HangTypes.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/Vector.h"
+#include "nsString.h"
+#include "nsTArray.h"
+#include "mozilla/ipc/IPDLParamTraits.h"
+
+namespace mozilla {
+
+/**
+ * This class extends nsTArray<HangAnnotation> with some methods for adding
+ * annotations being reported by a registered hang Annotator.
+ */
+class BackgroundHangAnnotations : public nsTArray<HangAnnotation>
+{
+public:
+  void AddAnnotation(const nsString& aName, const int32_t aData);
+  void AddAnnotation(const nsString& aName, const double aData);
+  void AddAnnotation(const nsString& aName, const nsString& aData);
+  void AddAnnotation(const nsString& aName, const nsCString& aData);
+  void AddAnnotation(const nsString& aName, const bool aData);
+};
+
+class BackgroundHangAnnotator
+{
+public:
+  /**
+   * NB: This function is always called by the BackgroundHangMonitor thread.
+   *     Plan accordingly.
+   */
+  virtual void AnnotateHang(BackgroundHangAnnotations& aAnnotations) = 0;
+};
+
+class BackgroundHangAnnotators
+{
+public:
+  BackgroundHangAnnotators();
+  ~BackgroundHangAnnotators();
+
+  bool Register(BackgroundHangAnnotator& aAnnotator);
+  bool Unregister(BackgroundHangAnnotator& aAnnotator);
+
+  BackgroundHangAnnotations GatherAnnotations();
+
+private:
+  Mutex mMutex;
+  std::set<BackgroundHangAnnotator*> mAnnotators;
+};
+
+namespace ipc {
+
+template<>
+struct IPDLParamTraits<mozilla::BackgroundHangAnnotations>
+  : public IPDLParamTraits<nsTArray<mozilla::HangAnnotation>>
+{
+  typedef mozilla::BackgroundHangAnnotations paramType;
+};
+
+} // namespace ipc
+
+} // namespace mozilla
+
+#endif // mozilla_HangAnnotations_h
--- a/toolkit/components/backgroundhangmonitor/moz.build
+++ b/toolkit/components/backgroundhangmonitor/moz.build
@@ -28,21 +28,23 @@ if CONFIG['NIGHTLY_BUILD'] and \
 XPIDL_SOURCES += [
     'nsIHangDetails.idl',
 ]
 
 XPIDL_MODULE = 'backgroundhangmonitor'
 
 EXPORTS.mozilla += [
     'BackgroundHangMonitor.h',
+    'HangAnnotations.h',
     'HangDetails.h',
 ]
 
 UNIFIED_SOURCES += [
     'BackgroundHangMonitor.cpp',
+    'HangAnnotations.cpp',
     'HangDetails.cpp',
 ]
 
 IPDL_SOURCES += [
     'HangTypes.ipdlh',
 ]
 
 if CONFIG['MOZ_GECKO_PROFILER']:
--- a/toolkit/components/telemetry/CombinedStacks.cpp
+++ b/toolkit/components/telemetry/CombinedStacks.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "CombinedStacks.h"
-#include "HangAnnotations.h"
 #include "mozilla/HangAnnotations.h"
 #include "jsapi.h"
 
 namespace mozilla {
 namespace Telemetry {
 
 // The maximum number of chrome hangs stacks that we're keeping.
 const size_t kMaxChromeStacksKept = 50;
deleted file mode 100644
--- a/toolkit/components/telemetry/HangReports.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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/. */
-
-#include "HangReports.h"
-
-namespace mozilla {
-namespace Telemetry {
-
-using namespace HangMonitor;
-
-// This utility function generates a string key that is used to index the annotations
-// in a hash map from |HangReports::AddHang|.
-nsresult
-ComputeAnnotationsKey(const HangAnnotations& aAnnotations, nsAString& aKeyOut)
-{
-  if (aAnnotations.IsEmpty()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  for (auto& annotation : aAnnotations) {
-    aKeyOut.Append(annotation.mName);
-    aKeyOut.Append(annotation.mValue);
-  }
-  return NS_OK;
-}
-
-#if defined(MOZ_GECKO_PROFILER)
-/** The maximum number of stacks that we're keeping for hang reports. */
-const size_t kMaxHangStacksKept = 50;
-
-void
-HangReports::AddHang(const Telemetry::ProcessedStack& aStack,
-                     uint32_t aDuration,
-                     int32_t aSystemUptime,
-                     int32_t aFirefoxUptime,
-                     HangAnnotations&& aAnnotations) {
-  // Append the new stack to the stack's circular queue.
-  size_t hangIndex = mStacks.AddStack(aStack);
-  // Append the hang info at the same index, in mHangInfo.
-  HangInfo info = { aDuration, aSystemUptime, aFirefoxUptime };
-  if (mHangInfo.size() < kMaxHangStacksKept) {
-    mHangInfo.push_back(info);
-  } else {
-    mHangInfo[hangIndex] = info;
-    // Remove any reference to the stack overwritten in the circular queue
-    // from the annotations.
-    PruneStackReferences(hangIndex);
-  }
-
-  nsAutoString annotationsKey;
-  // Generate a key to index aAnnotations in the hash map.
-  nsresult rv = ComputeAnnotationsKey(aAnnotations, annotationsKey);
-  if (NS_FAILED(rv)) {
-    return;
-  }
-
-  AnnotationInfo* annotationsEntry = mAnnotationInfo.Get(annotationsKey);
-  if (annotationsEntry) {
-    // If the key is already in the hash map, append the index of the chrome hang
-    // to its indices.
-    annotationsEntry->mHangIndices.AppendElement(hangIndex);
-    return;
-  }
-
-  // If the key was not found, add the annotations to the hash map.
-  mAnnotationInfo.Put(annotationsKey, new AnnotationInfo(hangIndex, std::move(aAnnotations)));
-}
-
-/**
- * This function removes links to discarded chrome hangs stacks and prunes unused
- * annotations.
- */
-void
-HangReports::PruneStackReferences(const size_t aRemovedStackIndex) {
-  // We need to adjust the indices that link annotations to chrome hangs. Since we
-  // removed a stack, we must remove all references to it and prune annotations
-  // linked to no stacks.
-  for (auto iter = mAnnotationInfo.Iter(); !iter.Done(); iter.Next()) {
-    nsTArray<uint32_t>& stackIndices = iter.Data()->mHangIndices;
-    size_t toRemove = stackIndices.NoIndex;
-    for (size_t k = 0; k < stackIndices.Length(); k++) {
-      // Is this index referencing the removed stack?
-      if (stackIndices[k] == aRemovedStackIndex) {
-        toRemove = k;
-        break;
-      }
-    }
-
-    // Remove the index referencing the old stack from the annotation.
-    if (toRemove != stackIndices.NoIndex) {
-      stackIndices.RemoveElementAt(toRemove);
-    }
-
-    // If this annotation no longer references any stack, drop it.
-    if (!stackIndices.Length()) {
-      iter.Remove();
-    }
-  }
-}
-#endif
-
-size_t
-HangReports::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
-  size_t n = 0;
-  n += mStacks.SizeOfExcludingThis();
-  // This is a crude approximation. See comment on
-  // CombinedStacks::SizeOfExcludingThis.
-  n += mHangInfo.capacity() * sizeof(HangInfo);
-  n += mAnnotationInfo.ShallowSizeOfExcludingThis(aMallocSizeOf);
-  n += mAnnotationInfo.Count() * sizeof(AnnotationInfo);
-  for (auto iter = mAnnotationInfo.ConstIter(); !iter.Done(); iter.Next()) {
-    n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
-    auto& annotations = iter.Data()->mAnnotations;
-    n += annotations.ShallowSizeOfExcludingThis(aMallocSizeOf);
-  }
-  return n;
-}
-
-const CombinedStacks&
-HangReports::GetStacks() const {
-  return mStacks;
-}
-
-uint32_t
-HangReports::GetDuration(unsigned aIndex) const {
-  return mHangInfo[aIndex].mDuration;
-}
-
-int32_t
-HangReports::GetSystemUptime(unsigned aIndex) const {
-  return mHangInfo[aIndex].mSystemUptime;
-}
-
-int32_t
-HangReports::GetFirefoxUptime(unsigned aIndex) const {
-  return mHangInfo[aIndex].mFirefoxUptime;
-}
-
-const nsClassHashtable<nsStringHashKey, HangReports::AnnotationInfo>&
-HangReports::GetAnnotationInfo() const {
-  return mAnnotationInfo;
-}
-
-} // namespace Telemetry
-} // namespace mozilla
deleted file mode 100644
--- a/toolkit/components/telemetry/HangReports.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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 HangReports_h__
-#define HangReports_h__
-
-#include <vector>
-#include "mozilla/HangAnnotations.h"
-#include "ProcessedStack.h"
-#include "nsTArray.h"
-#include "nsString.h"
-#include "nsClassHashtable.h"
-#include "CombinedStacks.h"
-
-namespace mozilla {
-namespace Telemetry {
-
-nsresult
-ComputeAnnotationsKey(const HangMonitor::HangAnnotations& aAnnotations, nsAString& aKeyOut);
-
-class HangReports {
-public:
-  /**
-   * This struct encapsulates information for an individual ChromeHang annotation.
-   * mHangIndex is the index of the corresponding ChromeHang.
-   */
-  struct AnnotationInfo {
-    AnnotationInfo(uint32_t aHangIndex,
-                   HangMonitor::HangAnnotations&& aAnnotations)
-      : mAnnotations(std::move(aAnnotations))
-    {
-      mHangIndices.AppendElement(aHangIndex);
-    }
-    AnnotationInfo(AnnotationInfo&& aOther)
-      : mHangIndices(aOther.mHangIndices)
-      , mAnnotations(std::move(aOther.mAnnotations))
-    {}
-    ~AnnotationInfo() = default;
-    AnnotationInfo& operator=(AnnotationInfo&& aOther)
-    {
-      mHangIndices = aOther.mHangIndices;
-      mAnnotations = std::move(aOther.mAnnotations);
-      return *this;
-    }
-    // To save memory, a single AnnotationInfo can be associated to multiple chrome
-    // hangs. The following array holds the index of each related chrome hang.
-    nsTArray<uint32_t> mHangIndices;
-    HangMonitor::HangAnnotations mAnnotations;
-
-  private:
-    // Force move constructor
-    AnnotationInfo(const AnnotationInfo& aOther) = delete;
-    void operator=(const AnnotationInfo& aOther) = delete;
-  };
-  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
-#if defined(MOZ_GECKO_PROFILER)
-  void AddHang(const Telemetry::ProcessedStack& aStack, uint32_t aDuration,
-               int32_t aSystemUptime, int32_t aFirefoxUptime,
-               HangMonitor::HangAnnotations&& aAnnotations);
-  void PruneStackReferences(const size_t aRemovedStackIndex);
-#endif
-  uint32_t GetDuration(unsigned aIndex) const;
-  int32_t GetSystemUptime(unsigned aIndex) const;
-  int32_t GetFirefoxUptime(unsigned aIndex) const;
-  const nsClassHashtable<nsStringHashKey, AnnotationInfo>& GetAnnotationInfo() const;
-  const CombinedStacks& GetStacks() const;
-private:
-  /**
-   * This struct encapsulates the data for an individual ChromeHang, excluding
-   * annotations.
-   */
-  struct HangInfo {
-    // Hang duration (in seconds)
-    uint32_t mDuration;
-    // System uptime (in minutes) at the time of the hang
-    int32_t mSystemUptime;
-    // Firefox uptime (in minutes) at the time of the hang
-    int32_t mFirefoxUptime;
-  };
-  std::vector<HangInfo> mHangInfo;
-  nsClassHashtable<nsStringHashKey, AnnotationInfo> mAnnotationInfo;
-  CombinedStacks mStacks;
-};
-
-} // namespace Telemetry
-} // namespace mozilla
-
-#endif // CombinedStacks_h__
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -77,47 +77,42 @@
 #include "mozilla/FStream.h"
 #include "mozilla/ProcessedStack.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/IOInterposer.h"
 #include "mozilla/PoisonIOInterposer.h"
 #include "mozilla/StartupTimeline.h"
-#include "mozilla/HangMonitor.h"
 #if defined(XP_WIN)
 #include "mozilla/WinDllServices.h"
 #endif
 #include "nsNativeCharsetUtils.h"
 #include "nsProxyRelease.h"
-#include "HangReports.h"
 
 #if defined(MOZ_GECKO_PROFILER)
 #include "shared-libraries.h"
 #include "KeyedStackCapturer.h"
 #endif // MOZ_GECKO_PROFILER
 
 #if defined(MOZ_TELEMETRY_GECKOVIEW)
 #include "geckoview/TelemetryGeckoViewPersistence.h"
 #endif
 
 namespace {
 
 using namespace mozilla;
-using namespace mozilla::HangMonitor;
 using Telemetry::Common::AutoHashtable;
 using Telemetry::Common::ToJSString;
 using Telemetry::Common::GetCurrentProduct;
 using Telemetry::Common::SetCurrentProduct;
 using Telemetry::Common::SupportedProduct;
 using mozilla::dom::Promise;
 using mozilla::dom::AutoJSAPI;
-using mozilla::Telemetry::HangReports;
 using mozilla::Telemetry::CombinedStacks;
-using mozilla::Telemetry::ComputeAnnotationsKey;
 using mozilla::Telemetry::TelemetryIOInterposeObserver;
 
 #if defined(MOZ_GECKO_PROFILER)
 using mozilla::Telemetry::KeyedStackCapturer;
 #endif
 
 // This is not a member of TelemetryImpl because we want to record I/O during
 // startup.
@@ -145,23 +140,16 @@ class TelemetryImpl final
 public:
   void InitMemoryReporter();
 
   static already_AddRefed<nsITelemetry> CreateTelemetryInstance();
   static void ShutdownTelemetry();
   static void RecordSlowStatement(const nsACString &sql, const nsACString &dbName,
                                   uint32_t delay);
 #if defined(MOZ_GECKO_PROFILER)
-  static void RecordChromeHang(uint32_t aDuration,
-                               Telemetry::ProcessedStack &aStack,
-                               int32_t aSystemUptime,
-                               int32_t aFirefoxUptime,
-                               HangAnnotations&& aAnnotations);
-#endif
-#if defined(MOZ_GECKO_PROFILER)
   static void DoStackCapture(const nsACString& aKey);
 #endif
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
   struct Stat {
     uint32_t hitCount;
     uint32_t totalTime;
   };
   struct StmtStats {
@@ -200,18 +188,16 @@ private:
                    bool includePrivateSql);
 
   void ReadLateWritesStacks(nsIFile* aProfileDir);
 
   static TelemetryImpl *sTelemetry;
   AutoHashtable<SlowSQLEntryType> mPrivateSQL;
   AutoHashtable<SlowSQLEntryType> mSanitizedSQL;
   Mutex mHashMutex;
-  HangReports mHangReports;
-  Mutex mHangReportsMutex;
   Atomic<bool> mCanRecordBase;
   Atomic<bool> mCanRecordExtended;
 
 #if defined(MOZ_GECKO_PROFILER)
   // Stores data about stacks captured on demand.
   KeyedStackCapturer mStackCapturer;
 #endif
 
@@ -490,17 +476,16 @@ TelemetryImpl::AsyncFetchTelemetryData(n
                                                          profileDir);
 
   targetThread->Dispatch(event, NS_DISPATCH_NORMAL);
   return NS_OK;
 }
 
 TelemetryImpl::TelemetryImpl()
   : mHashMutex("Telemetry::mHashMutex")
-  , mHangReportsMutex("Telemetry::mHangReportsMutex")
   , mCanRecordBase(false)
   , mCanRecordExtended(false)
   , mCachedTelemetryData(false)
   , mLastShutdownTime(0)
   , mFailedLockCount(0)
 {
   // We expect TelemetryHistogram::InitializeGlobalState() to have been
   // called before we get to this point.
@@ -508,17 +493,16 @@ TelemetryImpl::TelemetryImpl()
 }
 
 TelemetryImpl::~TelemetryImpl() {
   UnregisterWeakMemoryReporter(this);
 
   // This is still racey as access to these collections is guarded using sTelemetry.
   // We will fix this in bug 1367344.
   MutexAutoLock hashLock(mHashMutex);
-  MutexAutoLock hangReportsLock(mHangReportsMutex);
 }
 
 void
 TelemetryImpl::InitMemoryReporter() {
   RegisterWeakMemoryReporter(this);
 }
 
 bool
@@ -648,132 +632,16 @@ TelemetryImpl::GetWebrtcStats(JSContext 
 NS_IMETHODIMP
 TelemetryImpl::GetMaximalNumberOfConcurrentThreads(uint32_t *ret)
 {
   *ret = nsThreadManager::get().GetHighestNumberOfThreads();
   return NS_OK;
 }
 
 NS_IMETHODIMP
-TelemetryImpl::GetChromeHangs(JSContext *cx, JS::MutableHandle<JS::Value> ret)
-{
-  MutexAutoLock hangReportMutex(mHangReportsMutex);
-
-  const CombinedStacks& stacks = mHangReports.GetStacks();
-  JS::Rooted<JSObject*> fullReportObj(cx, CreateJSStackObject(cx, stacks));
-  if (!fullReportObj) {
-    return NS_ERROR_FAILURE;
-  }
-
-  ret.setObject(*fullReportObj);
-
-  JS::Rooted<JSObject*> durationArray(cx, JS_NewArrayObject(cx, 0));
-  JS::Rooted<JSObject*> systemUptimeArray(cx, JS_NewArrayObject(cx, 0));
-  JS::Rooted<JSObject*> firefoxUptimeArray(cx, JS_NewArrayObject(cx, 0));
-  JS::Rooted<JSObject*> annotationsArray(cx, JS_NewArrayObject(cx, 0));
-  if (!durationArray || !systemUptimeArray || !firefoxUptimeArray ||
-      !annotationsArray) {
-    return NS_ERROR_FAILURE;
-  }
-
-  bool ok = JS_DefineProperty(cx, fullReportObj, "durations",
-                              durationArray, JSPROP_ENUMERATE);
-  if (!ok) {
-    return NS_ERROR_FAILURE;
-  }
-
-  ok = JS_DefineProperty(cx, fullReportObj, "systemUptime",
-                         systemUptimeArray, JSPROP_ENUMERATE);
-  if (!ok) {
-    return NS_ERROR_FAILURE;
-  }
-
-  ok = JS_DefineProperty(cx, fullReportObj, "firefoxUptime",
-                         firefoxUptimeArray, JSPROP_ENUMERATE);
-  if (!ok) {
-    return NS_ERROR_FAILURE;
-  }
-
-  ok = JS_DefineProperty(cx, fullReportObj, "annotations", annotationsArray,
-                         JSPROP_ENUMERATE);
-  if (!ok) {
-    return NS_ERROR_FAILURE;
-  }
-
-
-  const size_t length = stacks.GetStackCount();
-  for (size_t i = 0; i < length; ++i) {
-    if (!JS_DefineElement(cx, durationArray, i, mHangReports.GetDuration(i),
-                          JSPROP_ENUMERATE)) {
-      return NS_ERROR_FAILURE;
-    }
-    if (!JS_DefineElement(cx, systemUptimeArray, i, mHangReports.GetSystemUptime(i),
-                          JSPROP_ENUMERATE)) {
-      return NS_ERROR_FAILURE;
-    }
-    if (!JS_DefineElement(cx, firefoxUptimeArray, i, mHangReports.GetFirefoxUptime(i),
-                          JSPROP_ENUMERATE)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    size_t annotationIndex = 0;
-    const nsClassHashtable<nsStringHashKey, HangReports::AnnotationInfo>& annotationInfo =
-      mHangReports.GetAnnotationInfo();
-
-    for (auto iter = annotationInfo.ConstIter(); !iter.Done(); iter.Next()) {
-      const HangReports::AnnotationInfo* info = iter.Data();
-
-      JS::Rooted<JSObject*> keyValueArray(cx, JS_NewArrayObject(cx, 0));
-      if (!keyValueArray) {
-        return NS_ERROR_FAILURE;
-      }
-
-      // Create an array containing all the indices of the chrome hangs relative to this
-      // annotation.
-      JS::Rooted<JS::Value> indicesArray(cx);
-      if (!mozilla::dom::ToJSValue(cx, info->mHangIndices, &indicesArray)) {
-        return NS_ERROR_OUT_OF_MEMORY;
-      }
-
-      // We're saving the annotation as [[indices], {annotation-data}], so add the indices
-      // array as the first element of that structure.
-      if (!JS_DefineElement(cx, keyValueArray, 0, indicesArray, JSPROP_ENUMERATE)) {
-        return NS_ERROR_FAILURE;
-      }
-
-      // Create the annotations object...
-      JS::Rooted<JSObject*> jsAnnotation(cx, JS_NewPlainObject(cx));
-      if (!jsAnnotation) {
-        return NS_ERROR_FAILURE;
-      }
-
-      for (auto& annot : info->mAnnotations) {
-        JS::RootedValue jsValue(cx);
-        jsValue.setString(JS_NewUCStringCopyN(cx, annot.mValue.get(), annot.mValue.Length()));
-        if (!JS_DefineUCProperty(cx, jsAnnotation, annot.mName.get(), annot.mName.Length(),
-                                 jsValue, JSPROP_ENUMERATE)) {
-          return NS_ERROR_FAILURE;
-        }
-      }
-
-      // ... and append it after the indices array.
-      if (!JS_DefineElement(cx, keyValueArray, 1, jsAnnotation, JSPROP_ENUMERATE)) {
-        return NS_ERROR_FAILURE;
-      }
-      if (!JS_DefineElement(cx, annotationsArray, annotationIndex++,
-                         keyValueArray, JSPROP_ENUMERATE)) {
-        return NS_ERROR_FAILURE;
-      }
-    }
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 TelemetryImpl::SnapshotCapturedStacks(bool clear, JSContext *cx, JS::MutableHandle<JS::Value> ret)
 {
 #if defined(MOZ_GECKO_PROFILER)
   nsresult rv = mStackCapturer.ReflectCapturedStacks(cx, ret);
   if (clear) {
     mStackCapturer.Clear();
   }
   return rv;
@@ -1582,32 +1450,16 @@ TelemetryImpl::RecordIceCandidates(const
 {
   if (!sTelemetry || !TelemetryHistogram::CanRecordExtended())
     return;
 
   sTelemetry->mWebrtcTelemetry.RecordIceCandidateMask(iceCandidateBitmask, success);
 }
 
 #if defined(MOZ_GECKO_PROFILER)
-void
-TelemetryImpl::RecordChromeHang(uint32_t aDuration,
-                                Telemetry::ProcessedStack &aStack,
-                                int32_t aSystemUptime,
-                                int32_t aFirefoxUptime,
-                                HangAnnotations&& aAnnotations)
-{
-  if (!sTelemetry || !TelemetryHistogram::CanRecordExtended())
-    return;
-
-  MutexAutoLock hangReportMutex(sTelemetry->mHangReportsMutex);
-
-  sTelemetry->mHangReports.AddHang(aStack, aDuration,
-                                   aSystemUptime, aFirefoxUptime,
-                                   std::move(aAnnotations));
-}
 
 void
 TelemetryImpl::DoStackCapture(const nsACString& aKey) {
   if (Telemetry::CanRecordExtended() && XRE_IsParentProcess()) {
     sTelemetry->mStackCapturer.Capture(aKey);
   }
 }
 #endif
@@ -1894,20 +1746,16 @@ TelemetryImpl::SizeOfIncludingThis(mozil
   n += TelemetryHistogram::GetMapShallowSizesOfExcludingThis(aMallocSizeOf);
   n += TelemetryScalar::GetMapShallowSizesOfExcludingThis(aMallocSizeOf);
   n += mWebrtcTelemetry.SizeOfExcludingThis(aMallocSizeOf);
   { // Scope for mHashMutex lock
     MutexAutoLock lock(mHashMutex);
     n += mPrivateSQL.SizeOfExcludingThis(aMallocSizeOf);
     n += mSanitizedSQL.SizeOfExcludingThis(aMallocSizeOf);
   }
-  { // Scope for mHangReportsMutex lock
-    MutexAutoLock lock(mHangReportsMutex);
-    n += mHangReports.SizeOfExcludingThis(aMallocSizeOf);
-  }
 
   // It's a bit gross that we measure this other stuff that lives outside of
   // TelemetryImpl... oh well.
   if (sTelemetryIOObserver) {
     n += sTelemetryIOObserver->SizeOfIncludingThis(aMallocSizeOf);
   }
 
   n += TelemetryHistogram::GetHistogramSizesofIncludingThis(aMallocSizeOf);
@@ -2155,32 +2003,19 @@ void Init()
 {
   // Make the service manager hold a long-lived reference to the service
   nsCOMPtr<nsITelemetry> telemetryService =
     do_GetService("@mozilla.org/base/telemetry;1");
   MOZ_ASSERT(telemetryService);
 }
 
 #if defined(MOZ_GECKO_PROFILER)
-void RecordChromeHang(uint32_t duration,
-                      ProcessedStack &aStack,
-                      int32_t aSystemUptime,
-                      int32_t aFirefoxUptime,
-                      HangAnnotations&& aAnnotations)
-{
-  TelemetryImpl::RecordChromeHang(duration, aStack,
-                                  aSystemUptime, aFirefoxUptime,
-                                  std::move(aAnnotations));
-}
-
 void CaptureStack(const nsACString& aKey)
 {
-#ifdef MOZ_GECKO_PROFILER
   TelemetryImpl::DoStackCapture(aKey);
-#endif
 }
 #endif
 
 void
 WriteFailedProfileLock(nsIFile* aProfileDir)
 {
   nsCOMPtr<nsIFile> file;
   nsresult rv = GetFailedProfileLockFile(getter_AddRefs(file), aProfileDir);
--- a/toolkit/components/telemetry/Telemetry.h
+++ b/toolkit/components/telemetry/Telemetry.h
@@ -24,19 +24,16 @@
  * For documentation on how to add and use new Telemetry probes, see:
  * https://developer.mozilla.org/en-US/docs/Mozilla/Performance/Adding_a_new_Telemetry_probe
  *
  * For more general information on Telemetry see:
  * https://wiki.mozilla.org/Telemetry
  *****************************************************************************/
 
 namespace mozilla {
-namespace HangMonitor {
-  class HangAnnotations;
-} // namespace HangMonitor
 namespace Telemetry {
 
 struct HistogramAccumulation;
 struct KeyedHistogramAccumulation;
 struct ScalarAction;
 struct KeyedScalarAction;
 struct ChildEventData;
 
@@ -483,22 +480,16 @@ class ProcessedStack;
  *
  * @param aDuration - Approximate duration of main thread hang, in seconds
  * @param aStack - Array of PCs from the hung call stack
  * @param aSystemUptime - System uptime at the time of the hang, in minutes
  * @param aFirefoxUptime - Firefox uptime at the time of the hang, in minutes
  * @param aAnnotations - Any annotations to be added to the report
  */
 #if defined(MOZ_GECKO_PROFILER)
-void RecordChromeHang(uint32_t aDuration,
-                      ProcessedStack &aStack,
-                      int32_t aSystemUptime,
-                      int32_t aFirefoxUptime,
-                      mozilla::HangMonitor::HangAnnotations&& aAnnotations);
-
 /**
  * Record the current thread's call stack on demand. Note that, the stack is
  * only captured once. Subsequent calls result in incrementing the capture
  * counter.
  *
  * @param aKey - A user defined key associated with the captured stack.
  *
  * NOTE: Unwinding call stacks is an expensive operation performance-wise.
--- a/toolkit/components/telemetry/TelemetrySession.jsm
+++ b/toolkit/components/telemetry/TelemetrySession.jsm
@@ -1125,17 +1125,16 @@ var Impl = {
     // Payload common to chrome and content processes.
     let payloadObj = {
       ver: PAYLOAD_VERSION,
       simpleMeasurements,
     };
 
     // Add extended set measurements common to chrome & content processes
     if (Telemetry.canRecordExtended) {
-      payloadObj.chromeHangs = protect(() => Telemetry.chromeHangs);
       payloadObj.log = [];
       payloadObj.webrtc = protect(() => Telemetry.webrtcStats);
     }
 
     if (Utils.isContentProcess) {
       return payloadObj;
     }
 
--- a/toolkit/components/telemetry/docs/data/main-ping.rst
+++ b/toolkit/components/telemetry/docs/data/main-ping.rst
@@ -56,17 +56,17 @@ Structure:
       },
 
       processes: {...},
       simpleMeasurements: {...},
 
       // The following properties may all be null if we fail to collect them.
       histograms: {...},
       keyedHistograms: {...},
-      chromeHangs: {...},
+      chromeHangs: {...}, // removed in firefox 62
       threadHangStats: [...], // obsolete in firefox 57, use the 'bhr' ping
       capturedStacks: {...},
       log: [...], // obsolete in firefox 61, use Event Telemetry or Scalars
       webrtc: {...},
       gc: {...},
       fileIOReports: {...},
       lateWrites: {...},
       addonDetails: {...},
@@ -344,16 +344,19 @@ Structure:
       ],
       "captures": [["string-key", stack-index, count], ... ]
     }
 
 .. _chromeHangs:
 
 chromeHangs
 -----------
+As of Firefox 62, chromeHangs has been removed. Please look to the bhr ping for
+similar functionality.
+
 Contains the statistics about the hangs happening exclusively on the main thread of the parent process. Precise C++ stacks are reported. This is only available on Nightly Release on Windows, when building using "--enable-profiling" switch.
 
 Some limits are applied:
 
 * Reported chrome hang stacks are limited in depth to 50 entries.
 * The maximum number of reported stacks is 50.
 
 The module names can contain unicode characters.
--- a/toolkit/components/telemetry/moz.build
+++ b/toolkit/components/telemetry/moz.build
@@ -59,17 +59,16 @@ EXPORTS.mozilla += [
     'ipc/TelemetryIPC.h',
     'ProcessedStack.h',
     'Telemetry.h',
 ]
 
 SOURCES += [
     'CombinedStacks.cpp',
     'geckoview/TelemetryGeckoViewPersistence.cpp',
-    'HangReports.cpp',
     'ipc/TelemetryIPC.cpp',
     'ipc/TelemetryIPCAccumulator.cpp',
     'ProcessedStack.cpp',
     'Telemetry.cpp',
     'TelemetryCommon.cpp',
     'TelemetryEvent.cpp',
     'TelemetryHistogram.cpp',
     'TelemetryIOInterposeObserver.cpp',
--- a/toolkit/components/telemetry/nsITelemetry.idl
+++ b/toolkit/components/telemetry/nsITelemetry.idl
@@ -124,24 +124,16 @@ interface nsITelemetry : nsISupports
 
   /**
    * A number representing the highest number of concurrent threads
    * reached during this session.
    */
   readonly attribute uint32_t maximalNumberOfConcurrentThreads;
 
   /*
-   * An array of chrome hang reports. Each element is a hang report represented
-   * as an object containing the hang duration, call stack PCs and information
-   * about modules in memory.
-   */
-  [implicit_jscontext]
-  readonly attribute jsval chromeHangs;
-
-  /*
    * Record the current thread's call stack on demand. Note that, the stack is
    * only captured at the first call. All subsequent calls result in incrementing
    * the capture counter without doing actual stack unwinding.
    *
    * @param aKey - A user defined key associated with the captured stack.
    *
    * NOTE: Unwinding call stacks is an expensive operation performance-wise.
    */
--- a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
@@ -1824,17 +1824,17 @@ add_task(async function test_schedulerNo
   Assert.ok(!(await OS.File.exists(ABORTED_FILE)));
 
   await TelemetryController.testShutdown();
   PingServer.resetPingHandler();
 });
 
 add_task(async function test_pingExtendedStats() {
   const EXTENDED_PAYLOAD_FIELDS = [
-    "chromeHangs", "log", "slowSQL", "fileIOReports", "lateWrites",
+    "log", "slowSQL", "fileIOReports", "lateWrites",
     "addonDetails", "webrtc"
   ];
 
   if (AppConstants.platform == "android") {
     EXTENDED_PAYLOAD_FIELDS.push("UIMeasurements");
   }
 
   // Reset telemetry and disable sending extended statistics.
--- a/toolkit/content/aboutTelemetry.js
+++ b/toolkit/content/aboutTelemetry.js
@@ -994,42 +994,16 @@ function SymbolicationRequest_fetchSymbo
   this.symbolRequest.setRequestHeader("Content-type", "application/json");
   this.symbolRequest.setRequestHeader("Content-length",
                                       requestJSON.length);
   this.symbolRequest.setRequestHeader("Connection", "close");
   this.symbolRequest.onreadystatechange = this.handleSymbolResponse.bind(this);
   this.symbolRequest.send(requestJSON);
 };
 
-var ChromeHangs = {
-
-  symbolRequest: null,
-
-  /**
-   * Renders raw chrome hang data
-   */
-  render: function ChromeHangs_render(chromeHangs) {
-    setHasData("chrome-hangs-section", !!chromeHangs);
-    if (!chromeHangs) {
-      return;
-    }
-
-    let stacks = chromeHangs.stacks;
-    let memoryMap = chromeHangs.memoryMap;
-    let durations = chromeHangs.durations;
-
-    StackRenderer.renderStacks("chrome-hangs", stacks, memoryMap,
-                               (index) => this.renderHangHeader(index, durations));
-  },
-
-  renderHangHeader: function ChromeHangs_renderHangHeader(aIndex, aDurations) {
-    StackRenderer.renderHeader("chrome-hangs", [aIndex + 1, aDurations[aIndex]]);
-  }
-};
-
 var CapturedStacks = {
   symbolRequest: null,
 
   render: function CapturedStacks_render(payload) {
     // Retrieve captured stacks from telemetry payload.
     let capturedStacks = "processes" in payload && "parent" in payload.processes
       ? payload.processes.parent.capturedStacks
       : false;
@@ -1222,17 +1196,16 @@ var Histogram = {
 
 var Search = {
 
   HASH_SEARCH: "search=",
 
   // A list of ids of sections that do not support search.
   blacklist: [
     "late-writes-section",
-    "chrome-hangs-section",
     "raw-payload-section"
   ],
 
   // Pass if: all non-empty array items match (case-sensitive)
   isPassText(subject, filter) {
     for (let item of filter) {
       if (item.length && !subject.includes(item)) {
         return false; // mismatch and not a spurious space
@@ -1989,40 +1962,16 @@ function setupListeners() {
   search.addEventListener("input", Search.searchHandler);
 
   // Clean up observers when page is closed
   window.addEventListener("unload",
     function(aEvent) {
       Settings.detachObservers();
   }, {once: true});
 
-  document.getElementById("chrome-hangs-fetch-symbols").addEventListener("click",
-    function() {
-      if (!gPingData) {
-        return;
-      }
-
-      let hangs = gPingData.payload.chromeHangs;
-      let req = new SymbolicationRequest("chrome-hangs",
-                                         ChromeHangs.renderHangHeader,
-                                         hangs.memoryMap,
-                                         hangs.stacks,
-                                         hangs.durations);
-      req.fetchSymbols();
-  });
-
-  document.getElementById("chrome-hangs-hide-symbols").addEventListener("click",
-    function() {
-      if (!gPingData) {
-        return;
-      }
-
-      ChromeHangs.render(gPingData.payload.chromeHangs);
-  });
-
   document.getElementById("captured-stacks-fetch-symbols").addEventListener("click",
     function() {
       if (!gPingData) {
         return;
       }
       let capturedStacks = gPingData.payload.processes.parent.capturedStacks;
       let req = new SymbolicationRequest("captured-stacks",
                                          CapturedStacks.renderCaptureHeader,
@@ -2401,17 +2350,14 @@ function displayRichPingData(ping, updat
   // Show event data.
   Events.render(payload);
 
   // Show captured stacks.
   CapturedStacks.render(payload);
 
   LateWritesSingleton.renderLateWrites(payload.lateWrites);
 
-  // Show chrome hang stacks
-  ChromeHangs.render(payload.chromeHangs);
-
   // Show simple measurements
   SimpleMeasurements.render(payload);
 
 }
 
 window.addEventListener("load", onLoad);
--- a/toolkit/content/aboutTelemetry.xhtml
+++ b/toolkit/content/aboutTelemetry.xhtml
@@ -61,19 +61,16 @@
         <span class="category-name">&aboutTelemetry.eventsSection;</span>
       </div>
       <div class="category" value="simple-measurements-section">
         <span class="category-name">&aboutTelemetry.simpleMeasurementsSection;</span>
       </div>
       <div class="category" value="slow-sql-section">
         <span class="category-name">&aboutTelemetry.slowSqlSection;</span>
       </div>
-      <div class="category" value="chrome-hangs-section">
-        <span class="category-name">&aboutTelemetry.chromeHangsSection;</span>
-      </div>
       <div class="category" value="addon-details-section">
         <span class="category-name">&aboutTelemetry.addonDetailsSection;</span>
       </div>
       <div class="category" value="captured-stacks-section">
         <span class="category-name">&aboutTelemetry.capturedStacksSection;</span>
       </div>
       <div class="category" value="late-writes-section">
         <span class="category-name">&aboutTelemetry.lateWritesSection;</span>
@@ -189,22 +186,16 @@
         <div id="simple-measurements" class="data"></div>
       </section>
 
       <section id="slow-sql-section">
         <p id="sql-warning">&aboutTelemetry.fullSqlWarning;</p>
         <div id="slow-sql-tables" class="data"></div>
       </section>
 
-      <section id="chrome-hangs-section">
-        <a id="chrome-hangs-fetch-symbols" href="">&aboutTelemetry.fetchStackSymbols;</a>
-        <a id="chrome-hangs-hide-symbols" href="">&aboutTelemetry.hideStackSymbols;</a>
-        <div id="chrome-hangs" class="data"></div>
-      </section>
-
       <section id="late-writes-section">
         <a id="late-writes-fetch-symbols" href="">&aboutTelemetry.fetchStackSymbols;</a>
         <a id="late-writes-hide-symbols" href="">&aboutTelemetry.hideStackSymbols;</a>
         <div id="late-writes" class="data"></div>
       </section>
 
       <section id="addon-details-section">
         <div id="addon-details" class="data"></div>
--- a/toolkit/crashreporter/docs/index.rst
+++ b/toolkit/crashreporter/docs/index.rst
@@ -194,24 +194,16 @@ but there will be multiple dump files: a
 one for the plugin process, and perhaps also additional dumps for the Flash
 sandbox and broker processes. All of these files are submitted together as a
 unit. Before submission, the filenames of the files are linked:
 
 - **uuid.ini** - *annotations, includes an additional_minidumps field*
 - **uuid.dmp** - *plugin process dump file*
 - **uuid-<other>.dmp** - *other process dump file as listed in additional_minidumps*
 
-Browser Hangs
-=============
-
-There is a feature of Firefox that will crash Firefox if it stops processing
-messages after a certain period of time. This feature doesn't work well and is
-disabled by default. See ``xpcom/threads/HangMonitor.cpp``. Hang crashes
-are annotated with ``Hang=1``.
-
 about:crashes
 =============
 
 If the crash reporter subsystem is enabled, the *about:crashes*
 page will be registered with the application. This page provides
 information about previous and submitted crashes.
 
 It is also possible to submit crashes from *about:crashes*.
--- a/toolkit/locales/en-US/chrome/global/aboutTelemetry.dtd
+++ b/toolkit/locales/en-US/chrome/global/aboutTelemetry.dtd
@@ -32,17 +32,16 @@
 <!ENTITY aboutTelemetry.sessionInfoSection "Session Information">
 <!ENTITY aboutTelemetry.scalarsSection "Scalars">
 <!ENTITY aboutTelemetry.keyedScalarsSection "Keyed Scalars">
 <!ENTITY aboutTelemetry.histogramsSection "Histograms">
 <!ENTITY aboutTelemetry.keyedHistogramsSection "Keyed Histograms">
 <!ENTITY aboutTelemetry.eventsSection "Events">
 <!ENTITY aboutTelemetry.simpleMeasurementsSection "Simple Measurements">
 <!ENTITY aboutTelemetry.slowSqlSection "Slow SQL Statements">
-<!ENTITY aboutTelemetry.chromeHangsSection "Browser Hangs">
 <!ENTITY aboutTelemetry.addonDetailsSection "Add-on Details">
 <!ENTITY aboutTelemetry.capturedStacksSection "Captured Stacks">
 <!ENTITY aboutTelemetry.lateWritesSection "Late Writes">
 <!ENTITY aboutTelemetry.rawPayloadSection "Raw Payload">
 <!ENTITY aboutTelemetry.raw "Raw JSON">
 
 <!ENTITY aboutTelemetry.fullSqlWarning "NOTE: Slow SQL debugging is enabled. Full SQL strings may be displayed below but they will not be submitted to Telemetry.">
 <!ENTITY aboutTelemetry.fetchStackSymbols "Fetch function names for stacks">
--- a/toolkit/locales/en-US/chrome/global/aboutTelemetry.properties
+++ b/toolkit/locales/en-US/chrome/global/aboutTelemetry.properties
@@ -76,20 +76,16 @@ addonTableDetails = Details
 # LOCALIZATION NOTE(addonProvider):
 # - %1$S is replaced by the name of an Add-on Provider (e.g. “XPI”, “Plugin”)
 addonProvider = %1$S Provider
 
 keysHeader = Property
 namesHeader = Name
 valuesHeader = Value
 
-# LOCALIZATION NOTE(chrome-hangs-title):
-# - %1$S is replaced by the number of the hang
-# - %2$S is replaced by the duration of the hang
-chrome-hangs-title = Hang Report #%1$S (%2$S seconds)
 # LOCALIZATION NOTE(captured-stacks-title):
 # - %1$S is replaced by the string key for this stack
 # - %2$S is replaced by the number of times this stack was captured
 captured-stacks-title = %1$S (capture count: %2$S)
 # LOCALIZATION NOTE(late-writes-title):
 # - %1$S is replaced by the number of the late write
 late-writes-title = Late Write #%1$S
 
--- a/widget/android/GeckoEditableSupport.h
+++ b/widget/android/GeckoEditableSupport.h
@@ -140,25 +140,25 @@ class GeckoEditableSupport final
 public:
     template<typename Functor>
     static void OnNativeCall(Functor&& aCall)
     {
         struct IMEEvent : nsAppShell::LambdaEvent<Functor>
         {
             explicit IMEEvent(Functor&& l) : nsAppShell::LambdaEvent<Functor>(std::move(l)) {}
 
-            nsAppShell::Event::Type ActivityType() const override
+            bool IsUIEvent() const override
             {
                 using GES = GeckoEditableSupport;
                 if (this->lambda.IsTarget(&GES::OnKeyEvent) ||
                         this->lambda.IsTarget(&GES::OnImeReplaceText) ||
                         this->lambda.IsTarget(&GES::OnImeUpdateComposition)) {
-                    return nsAppShell::Event::Type::kUIActivity;
+                    return true;
                 }
-                return nsAppShell::Event::Type::kGeneralActivity;
+                return false;
             }
 
             void Run() override
             {
                 if (!this->lambda.GetNativeObject()) {
                     // Ignore stale calls after disposal.
                     jni::GetGeckoThreadEnv()->ExceptionClear();
                     return;
--- a/widget/android/jni/moz.build
+++ b/widget/android/jni/moz.build
@@ -14,14 +14,16 @@ EXPORTS.mozilla.jni += [
     'Types.h',
     'Utils.h',
 ]
 
 UNIFIED_SOURCES += [
     'Utils.cpp',
 ]
 
+include('/ipc/chromium/chromium-config.mozbuild')
+
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '/widget',
     '/widget/android',
 ]
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -736,26 +736,26 @@ nsAppShell::ProcessNextNativeEvent(bool 
             // wait for new events.
             if (jni::IsAvailable() && XRE_IsParentProcess() &&
                     AndroidBridge::Bridge()->PumpMessageLoop()) {
                 return true;
             }
 
             AUTO_PROFILER_LABEL("nsAppShell::ProcessNextNativeEvent:Wait",
                                 IDLE);
-            mozilla::HangMonitor::Suspend();
+            mozilla::BackgroundHangMonitor().NotifyWait();
 
             curEvent = mEventQueue.Pop(/* mayWait */ true);
         }
     }
 
     if (!curEvent)
         return false;
 
-    mozilla::HangMonitor::NotifyActivity(curEvent->ActivityType());
+    mozilla::BackgroundHangMonitor().NotifyActivity();
 
     curEvent->Run();
     return true;
 }
 
 void
 nsAppShell::SyncRunEvent(Event&& event,
                          UniquePtr<Event>(*eventFactory)(UniquePtr<Event>&&))
--- a/widget/android/nsAppShell.h
+++ b/widget/android/nsAppShell.h
@@ -3,17 +3,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 nsAppShell_h__
 #define nsAppShell_h__
 
 #include <time.h>
 
-#include "mozilla/HangMonitor.h"
+#include "mozilla/BackgroundHangMonitor.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/Move.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Unused.h"
 #include "mozilla/jni/Natives.h"
@@ -31,18 +31,16 @@ void NotifyEvent();
 class nsWindow;
 
 class nsAppShell :
     public nsBaseAppShell
 {
 public:
     struct Event : mozilla::LinkedListElement<Event>
     {
-        typedef mozilla::HangMonitor::ActivityType Type;
-
         static uint64_t GetTime()
         {
             timespec time;
             if (clock_gettime(CLOCK_MONOTONIC, &time)) {
                 return 0ull;
             }
             return uint64_t(time.tv_sec) * 1000000000ull + time.tv_nsec;
         }
@@ -59,19 +57,19 @@ public:
         virtual ~Event() {}
         virtual void Run() = 0;
 
         virtual void PostTo(mozilla::LinkedList<Event>& queue)
         {
             queue.insertBack(this);
         }
 
-        virtual Type ActivityType() const
+        virtual bool IsUIEvent() const
         {
-            return Type::kGeneralActivity;
+            return false;
         }
     };
 
     template<typename T>
     class LambdaEvent : public Event
     {
     protected:
         T lambda;
@@ -243,18 +241,17 @@ protected:
 
             // Ownership of event object transfers to the return value.
             mozilla::UniquePtr<Event> event(mQueue.popFirst());
             if (!event || !event->mPostTime) {
                 return event;
             }
 
 #ifdef EARLY_BETA_OR_EARLIER
-            const size_t latencyType = (event->ActivityType() ==
-                    Event::Type::kUIActivity) ? LATENCY_UI : LATENCY_OTHER;
+            const size_t latencyType = event->IsUIEvent() ? LATENCY_UI : LATENCY_OTHER;
             const uint64_t latency = Event::GetTime() - event->mPostTime;
 
             sLatencyCount[latencyType]++;
             sLatencyTime[latencyType] += latency;
 #endif
             return event;
         }
 
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -348,19 +348,19 @@ class nsWindow::NPZCSupport final
                 return;
             }
 
             nsWindow* const window = npzcSupport->mWindow;
             window->UserActivity();
             return mLambda(window);
         }
 
-        nsAppShell::Event::Type ActivityType() const override
+        bool IsUIEvent() const override
         {
-            return nsAppShell::Event::Type::kUIActivity;
+            return true;
         }
     };
 
     template<typename Lambda>
     void PostInputEvent(Lambda&& aLambda)
     {
         // Use priority queue for input events.
         nsAppShell::PostEvent(MakeUnique<InputEvent<Lambda>>(
--- a/widget/cocoa/nsAppShell.mm
+++ b/widget/cocoa/nsAppShell.mm
@@ -25,17 +25,17 @@
 #include "nsIInterfaceRequestor.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsObjCExceptions.h"
 #include "nsCocoaFeatures.h"
 #include "nsCocoaUtils.h"
 #include "nsChildView.h"
 #include "nsToolkit.h"
 #include "TextInputHandler.h"
-#include "mozilla/HangMonitor.h"
+#include "mozilla/BackgroundHangMonitor.h"
 #include "GeckoProfiler.h"
 #include "ScreenHelperCocoa.h"
 #include "mozilla/widget/ScreenManager.h"
 #include "HeadlessScreenHelper.h"
 #include "pratom.h"
 #if !defined(RELEASE_OR_BETA) || defined(DEBUG)
 #include "nsSandboxViolationSink.h"
 #endif
@@ -131,17 +131,18 @@ static bool gAppShellMethodsSwizzled = f
 
 - (void)sendEvent:(NSEvent *)anEvent
 {
   // Mark this function as non-idle because it's one of the exit points from
   // the event loop (running inside of -[GeckoNSApplication nextEventMatchingMask:...])
   // into non-idle code. So we basically unset the IDLE category from the inside.
   AUTO_PROFILER_LABEL("-[GeckoNSApplication sendEvent:]", OTHER);
 
-  mozilla::HangMonitor::NotifyActivity();
+  mozilla::BackgroundHangMonitor().NotifyActivity();
+
   if ([anEvent type] == NSApplicationDefined &&
       [anEvent subtype] == kEventSubtypeTrace) {
     mozilla::SignalTracerThread();
     return;
   }
   [super sendEvent:anEvent];
 }
 
@@ -167,22 +168,22 @@ static bool gAppShellMethodsSwizzled = f
   // idleness but isn't perfect. For example, sometimes there's some Cocoa-
   // internal activity that's triggered from the event loop, and we'll
   // misidentify the stacks for that activity as idle because there's no Gecko
   // code on the stack that can change the stack's category to something
   // non-idle.
   AUTO_PROFILER_LABEL("-[GeckoNSApplication nextEventMatchingMask:untilDate:inMode:dequeue:]", IDLE);
 
   if (expiration) {
-    mozilla::HangMonitor::Suspend();
+    mozilla::BackgroundHangMonitor().NotifyWait();
   }
   NSEvent* nextEvent = [super nextEventMatchingMask:mask
                         untilDate:expiration inMode:mode dequeue:flag];
   if (expiration) {
-    mozilla::HangMonitor::NotifyActivity();
+    mozilla::BackgroundHangMonitor().NotifyActivity();
   }
   return nextEvent;
 }
 
 @end
 
 // AppShellDelegate
 //
@@ -608,17 +609,17 @@ nsAppShell::ProcessNextNativeEvent(bool 
     waitUntil = [NSDate distantFuture];
 
   NSRunLoop* currentRunLoop = [NSRunLoop currentRunLoop];
 
   EventQueueRef currentEventQueue = GetCurrentEventQueue();
   EventTargetRef eventDispatcherTarget = GetEventDispatcherTarget();
 
   if (aMayWait) {
-    mozilla::HangMonitor::Suspend();
+    mozilla::BackgroundHangMonitor().NotifyWait();
   }
 
   // Only call -[NSApp sendEvent:] (and indirectly send user-input events to
   // Gecko) if aMayWait is true.  Tbis ensures most calls to -[NSApp
   // sendEvent:] happen under nsAppShell::Run(), at the lowest level of
   // recursion -- thereby making it less likely Gecko will process user-input
   // events in the wrong order or skip some of them.  It also avoids eating
   // too much CPU in nsBaseAppShell::OnProcessNextEvent() (which calls
@@ -634,17 +635,17 @@ nsAppShell::ProcessNextNativeEvent(bool 
       currentMode = [currentRunLoop currentMode];
       if (!currentMode)
         currentMode = NSDefaultRunLoopMode;
       NSEvent *nextEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
                                               untilDate:waitUntil
                                                  inMode:currentMode
                                                 dequeue:YES];
       if (nextEvent) {
-        mozilla::HangMonitor::NotifyActivity();
+        mozilla::BackgroundHangMonitor().NotifyActivity();
         [NSApp sendEvent:nextEvent];
         eventProcessed = true;
       }
     } else {
       // AcquireFirstMatchingEventInQueue() doesn't spin the (native) event
       // loop, though it does queue up any newly available events from the
       // window server.
       EventRef currentEvent = AcquireFirstMatchingEventInQueue(currentEventQueue, 0, NULL,
--- a/widget/gtk/nsAppShell.cpp
+++ b/widget/gtk/nsAppShell.cpp
@@ -9,17 +9,17 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <gdk/gdk.h>
 #include "nsAppShell.h"
 #include "nsWindow.h"
 #include "mozilla/Logging.h"
 #include "prenv.h"
-#include "mozilla/HangMonitor.h"
+#include "mozilla/BackgroundHangMonitor.h"
 #include "mozilla/Unused.h"
 #include "mozilla/WidgetUtils.h"
 #include "GeckoProfiler.h"
 #include "nsIPowerManagerService.h"
 #ifdef MOZ_ENABLE_DBUS
 #include "WakeLockListener.h"
 #endif
 #include "gfxPlatform.h"
@@ -41,24 +41,24 @@ LazyLogModule gWidgetDragLog("WidgetDrag
 LazyLogModule gWidgetDrawLog("WidgetDraw");
 
 static GPollFunc sPollFunc;
 
 // Wrapper function to disable hang monitoring while waiting in poll().
 static gint
 PollWrapper(GPollFD *ufds, guint nfsd, gint timeout_)
 {
-    mozilla::HangMonitor::Suspend();
+    mozilla::BackgroundHangMonitor().NotifyWait();
     gint result;
     {
         AUTO_PROFILER_LABEL("PollWrapper", IDLE);
         AUTO_PROFILER_THREAD_SLEEP;
         result = (*sPollFunc)(ufds, nfsd, timeout_);
     }
-    mozilla::HangMonitor::NotifyActivity();
+    mozilla::BackgroundHangMonitor().NotifyActivity();
     return result;
 }
 
 #ifdef MOZ_WIDGET_GTK
 // For bug 726483.
 static decltype(GtkContainerClass::check_resize) sReal_gtk_window_check_resize;
 
 static void
--- a/widget/windows/WinUtils.cpp
+++ b/widget/windows/WinUtils.cpp
@@ -10,20 +10,20 @@
 #include <winioctl.h>
 
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "nsWindow.h"
 #include "nsWindowDefs.h"
 #include "KeyboardLayout.h"
 #include "mozilla/ArrayUtils.h"
+#include "mozilla/BackgroundHangMonitor.h"
 #include "mozilla/dom/MouseEventBinding.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/DataSurfaceHelpers.h"
-#include "mozilla/HangMonitor.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/WindowsVersion.h"
 #include "mozilla/Unused.h"
 #include "nsIContentPolicy.h"
 #include "nsContentUtils.h"
 
 #include "mozilla/Logging.h"
@@ -759,17 +759,17 @@ WinUtils::WaitForMessage(DWORD aTimeoutM
       break;
     }
 #if defined(ACCESSIBILITY)
     if (result == WAIT_IO_COMPLETION) {
       if (NS_IsMainThread()) {
         // We executed an APC that would have woken up the hang monitor. Since
         // there are no more APCs pending and we are now going to sleep again,
         // we should notify the hang monitor.
-        mozilla::HangMonitor::Suspend();
+        mozilla::BackgroundHangMonitor().NotifyWait();
       }
       continue;
     }
 #endif // defined(ACCESSIBILITY)
 
     // Sent messages (via SendMessage and friends) are processed differently
     // than queued messages (via PostMessage); the destination window procedure
     // of the sent message is called during (Get|Peek)Message. Since PeekMessage
--- a/widget/windows/nsAppShell.cpp
+++ b/widget/windows/nsAppShell.cpp
@@ -10,17 +10,17 @@
 #include "nsThreadUtils.h"
 #include "WinUtils.h"
 #include "WinTaskbar.h"
 #include "WinMouseScrollHandler.h"
 #include "nsWindowDefs.h"
 #include "nsString.h"
 #include "WinIMEHandler.h"
 #include "mozilla/widget/AudioSession.h"
-#include "mozilla/HangMonitor.h"
+#include "mozilla/BackgroundHangMonitor.h"
 #include "nsIDOMWakeLockListener.h"
 #include "nsIPowerManagerService.h"
 #include "mozilla/StaticPtr.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "GeckoProfiler.h"
 #include "nsComponentManagerUtils.h"
 #include "ScreenHelperWin.h"
@@ -524,19 +524,17 @@ nsAppShell::ProcessNextNativeEvent(bool 
 
     if (gotMessage) {
       if (msg.message == WM_QUIT) {
         ::PostQuitMessage(msg.wParam);
         Exit();
       } else {
         // If we had UI activity we would be processing it now so we know we
         // have either kUIActivity or kActivityNoUIAVail.
-        mozilla::HangMonitor::NotifyActivity(
-          uiMessage ? mozilla::HangMonitor::kUIActivity :
-                      mozilla::HangMonitor::kActivityNoUIAVail);
+        mozilla::BackgroundHangMonitor().NotifyActivity();
 
         if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST &&
             IMEHandler::ProcessRawKeyMessage(msg)) {
           continue;  // the message is consumed.
         }
 
         // Store Printer Properties messages for reposting, because they are not
         // processed by a window procedure, but are explicitly waited for in the
@@ -547,17 +545,17 @@ nsAppShell::ProcessNextNativeEvent(bool 
           continue;
         }
 
         ::TranslateMessage(&msg);
         ::DispatchMessageW(&msg);
       }
     } else if (mayWait) {
       // Block and wait for any posted application message
-      mozilla::HangMonitor::Suspend();
+      mozilla::BackgroundHangMonitor().NotifyWait();
       {
         AUTO_PROFILER_LABEL("nsAppShell::ProcessNextNativeEvent::Wait", IDLE);
         AUTO_PROFILER_THREAD_SLEEP;
         WinUtils::WaitForMessage();
       }
     }
   } while (!gotMessage && mayWait);
 
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -177,17 +177,17 @@
 
 #include "nsWindowDefs.h"
 
 #include "nsCrashOnException.h"
 #include "nsIXULRuntime.h"
 
 #include "nsIContent.h"
 
-#include "mozilla/HangMonitor.h"
+#include "mozilla/BackgroundHangMonitor.h"
 #include "WinIMEHandler.h"
 
 #include "npapi.h"
 
 #include <d3d11.h>
 
 #include "InkCollector.h"
 
@@ -4952,38 +4952,24 @@ DisplaySystemMenu(HWND hWnd, nsSizeMode 
     if (cmd) {
       PostMessage(hWnd, WM_SYSCOMMAND, cmd, 0);
       return true;
     }
   }
   return false;
 }
 
-inline static mozilla::HangMonitor::ActivityType ActivityTypeForMessage(UINT msg)
-{
-  if ((msg >= WM_KEYFIRST && msg <= WM_IME_KEYLAST) ||
-      (msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) ||
-      (msg >= MOZ_WM_MOUSEWHEEL_FIRST && msg <= MOZ_WM_MOUSEWHEEL_LAST) ||
-      (msg >= NS_WM_IMEFIRST && msg <= NS_WM_IMELAST)) {
-    return mozilla::HangMonitor::kUIActivity;
-  }
-
-  // This may not actually be right, but we don't want to reset the timer if
-  // we're not actually processing a UI message.
-  return mozilla::HangMonitor::kActivityUIAVail;
-}
-
 // The WndProc procedure for all nsWindows in this toolkit. This merely catches
 // exceptions and passes the real work to WindowProcInternal. See bug 587406
 // and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx
 LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
   mozilla::ipc::CancelCPOWs();
 
-  HangMonitor::NotifyActivity(ActivityTypeForMessage(msg));
+  BackgroundHangMonitor().NotifyActivity();
 
   return mozilla::CallWindowProcCrashProtected(WindowProcInternal, hWnd, msg, wParam, lParam);
 }
 
 LRESULT CALLBACK nsWindow::WindowProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
   if (::GetWindowLongPtrW(hWnd, GWLP_ID) == eFakeTrackPointScrollableID) {
     // This message was sent to the FAKETRACKPOINTSCROLLABLE.
--- a/xpcom/build/XPCOMInit.cpp
+++ b/xpcom/build/XPCOMInit.cpp
@@ -102,17 +102,16 @@ extern nsresult nsStringInputStreamConst
 #include "nsMemoryInfoDumper.h"
 #include "nsSecurityConsoleMessage.h"
 #include "nsMessageLoop.h"
 #include "nss.h"
 
 #include <locale.h>
 #include "mozilla/Services.h"
 #include "mozilla/Omnijar.h"
-#include "mozilla/HangMonitor.h"
 #include "mozilla/ScriptPreloader.h"
 #include "mozilla/SystemGroup.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/BackgroundHangMonitor.h"
 
 #include "nsChromeRegistry.h"
 #include "nsChromeProtocolHandler.h"
 #include "mozilla/PoisonIOInterposer.h"
@@ -734,17 +733,16 @@ NS_InitXPCOM2(nsIServiceManager** aResul
   RegisterStrongMemoryReporter(new ICUReporter());
   RegisterStrongMemoryReporter(new OggReporter());
 #ifdef MOZ_VPX
   RegisterStrongMemoryReporter(new VPXReporter());
 #endif
 
   mozilla::Telemetry::Init();
 
-  mozilla::HangMonitor::Startup();
   mozilla::BackgroundHangMonitor::Startup();
 
   const MessageLoop* const loop = MessageLoop::current();
   sMainHangMonitor = new mozilla::BackgroundHangMonitor(
     loop->thread_name().c_str(),
     loop->transient_hang_timeout(),
     loop->permanent_hang_timeout());
 
@@ -793,17 +791,16 @@ NS_InitMinimalXPCOM()
 
   // Global cycle collector initialization.
   if (!nsCycleCollector_init()) {
     return NS_ERROR_UNEXPECTED;
   }
 
   SharedThreadPool::InitStatics();
   mozilla::Telemetry::Init();
-  mozilla::HangMonitor::Startup();
   mozilla::BackgroundHangMonitor::Startup();
 
   return NS_OK;
 }
 
 //
 // NS_ShutdownXPCOM()
 //
@@ -859,17 +856,17 @@ SetGMPMemoryFunctions()
   }
 }
 #endif
 
 nsresult
 ShutdownXPCOM(nsIServiceManager* aServMgr)
 {
   // Make sure the hang monitor is enabled for shutdown.
-  HangMonitor::NotifyActivity();
+  BackgroundHangMonitor().NotifyActivity();
 
   if (!NS_IsMainThread()) {
     MOZ_CRASH("Shutdown on wrong thread");
   }
 
   nsresult rv;
   nsCOMPtr<nsISimpleEnumerator> moduleLoaders;
 
@@ -932,17 +929,17 @@ ShutdownXPCOM(nsIServiceManager* aServMg
 
     // Shutdown all remaining threads.  This method does not return until
     // all threads created using the thread manager (with the exception of
     // the main thread) have exited.
     nsThreadManager::get().Shutdown();
 
     NS_ProcessPendingEvents(thread);
 
-    HangMonitor::NotifyActivity();
+    BackgroundHangMonitor().NotifyActivity();
 
     // Late-write checks needs to find the profile directory, so it has to
     // be initialized before mozilla::services::Shutdown or (because of
     // xpcshell tests replacing the service) modules being unloaded.
     mozilla::InitLateWriteChecks();
 
     // We save the "xpcom-shutdown-loaders" observers to notify after
     // the observerservice is gone.
@@ -1085,17 +1082,16 @@ ShutdownXPCOM(nsIServiceManager* aServMg
     sCommandLineWasInitialized = false;
   }
 
   delete sExitManager;
   sExitManager = nullptr;
 
   Omnijar::CleanUp();
 
-  HangMonitor::Shutdown();
   BackgroundHangMonitor::Shutdown();
 
   delete sMainHangMonitor;
   sMainHangMonitor = nullptr;
 
   NS_LogTerm();
 
   return NS_OK;
--- a/xpcom/threads/CPUUsageWatcher.cpp
+++ b/xpcom/threads/CPUUsageWatcher.cpp
@@ -182,26 +182,26 @@ CPUUsageWatcher::Init()
   mGlobalUpdateTime = globalTimes.updateTime;
   mGlobalUsageTime = globalTimes.usageTime;
 
   mInitialized = true;
 
   CPUUsageWatcher* self = this;
   NS_DispatchToMainThread(
     NS_NewRunnableFunction("CPUUsageWatcher::Init",
-                           [=]() { HangMonitor::RegisterAnnotator(*self); }));
+                           [=]() { BackgroundHangMonitor::RegisterAnnotator(*self); }));
 
   return Ok();
 }
 
 void
 CPUUsageWatcher::Uninit()
 {
   if (mInitialized) {
-    HangMonitor::UnregisterAnnotator(*this);
+    BackgroundHangMonitor::UnregisterAnnotator(*this);
   }
   mInitialized = false;
 }
 
 Result<Ok, CPUUsageWatcherError>
 CPUUsageWatcher::CollectCPUUsage()
 {
   if (!mInitialized) {
@@ -234,17 +234,17 @@ CPUUsageWatcher::CollectCPUUsage()
 
   mExternalUsageRatio = std::max(0.0f,
                                  globalUsageNormalized - processUsageNormalized);
 
   return Ok();
 }
 
 void
-CPUUsageWatcher::AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) {
+CPUUsageWatcher::AnnotateHang(BackgroundHangAnnotations& aAnnotations) {
   if (!mInitialized) {
     return;
   }
 
   if (mExternalUsageRatio > mExternalUsageThreshold) {
     aAnnotations.AddAnnotation(NS_LITERAL_STRING("ExternalCPUHigh"), true);
   }
 }
@@ -260,13 +260,13 @@ CPUUsageWatcher::Init()
 void CPUUsageWatcher::Uninit() {}
 
 Result<Ok, CPUUsageWatcherError>
 CPUUsageWatcher::CollectCPUUsage()
 {
   return Ok();
 }
 
-void CPUUsageWatcher::AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) {}
+void CPUUsageWatcher::AnnotateHang(BackgroundHangAnnotations& aAnnotations) {}
 
 #endif // CPU_USAGE_WATCHER_ACTIVE
 
 } // namespace mozilla
--- a/xpcom/threads/CPUUsageWatcher.h
+++ b/xpcom/threads/CPUUsageWatcher.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_CPUUsageWatcher_h
 #define mozilla_CPUUsageWatcher_h
 
 #include <stdint.h>
 
 #include "mozilla/HangAnnotations.h"
+#include "mozilla/BackgroundHangMonitor.h"
 
 // We only support OSX and Windows, because on Linux we're forced to read
 // from /proc/stat in order to get global CPU values. We would prefer to not
 // eat that cost for this.
 #if defined(NIGHTLY_BUILD) && (defined(XP_WIN) || defined(XP_MACOSX))
 #define CPU_USAGE_WATCHER_ACTIVE
 #endif
 
@@ -26,23 +27,23 @@ enum CPUUsageWatcherError : uint8_t
   GetNumberOfProcessorsError,
   GetProcessTimesError,
   GetSystemTimesError,
   HostStatisticsError,
   ProcStatError,
 };
 
 class CPUUsageHangAnnotator
-  : public HangMonitor::Annotator
+  : public BackgroundHangAnnotator
 {
 public:
 };
 
 class CPUUsageWatcher
-  : public HangMonitor::Annotator
+  : public BackgroundHangAnnotator
 {
 public:
 #ifdef CPU_USAGE_WATCHER_ACTIVE
   CPUUsageWatcher()
     : mInitialized(false)
     , mExternalUsageThreshold(0)
     , mExternalUsageRatio(0)
     , mProcessUsageTime(0)
@@ -57,17 +58,17 @@ public:
 
   void Uninit();
 
   // Updates necessary values to allow AnnotateHang to function. This must be
   // called on some semi-regular basis, as it will calculate the mean CPU
   // usage values between now and the last time it was called.
   Result<Ok, CPUUsageWatcherError> CollectCPUUsage();
 
-  void AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) final;
+  void AnnotateHang(BackgroundHangAnnotations& aAnnotations) final;
 private:
 #ifdef CPU_USAGE_WATCHER_ACTIVE
   bool mInitialized;
   // The threshold above which we will mark a hang as occurring under high
   // external CPU usage conditions
   float mExternalUsageThreshold;
   // The CPU usage (0-1) external to our process, averaged between the two
   // most recent monitor thread runs
deleted file mode 100644
--- a/xpcom/threads/HangAnnotations.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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/. */
-
-#include "mozilla/HangAnnotations.h"
-
-#include <vector>
-
-#include "MainThreadUtils.h"
-#include "mozilla/DebugOnly.h"
-#include "nsXULAppAPI.h"
-#include "mozilla/BackgroundHangMonitor.h"
-
-namespace mozilla {
-namespace HangMonitor {
-
-// Chrome hang annotators. This can go away once BHR has completely replaced
-// ChromeHangs.
-static StaticAutoPtr<Observer::Annotators> gChromehangAnnotators;
-
-void
-HangAnnotations::AddAnnotation(const nsAString& aName, const int32_t aData)
-{
-  nsAutoString dataString;
-  dataString.AppendInt(aData);
-  AppendElement(Annotation(aName, dataString));
-}
-
-void
-HangAnnotations::AddAnnotation(const nsAString& aName, const double aData)
-{
-  nsAutoString dataString;
-  dataString.AppendFloat(aData);
-  AppendElement(Annotation(aName, dataString));
-}
-
-void
-HangAnnotations::AddAnnotation(const nsAString& aName, const nsAString& aData)
-{
-  AppendElement(Annotation(aName, aData));
-}
-
-void
-HangAnnotations::AddAnnotation(const nsAString& aName, const nsACString& aData)
-{
-  NS_ConvertUTF8toUTF16 dataString(aData);
-  AppendElement(Annotation(aName, dataString));
-}
-
-void
-HangAnnotations::AddAnnotation(const nsAString& aName, const bool aData)
-{
-  if (aData) {
-    AppendElement(Annotation(aName, NS_LITERAL_STRING("true")));
-  } else {
-    AppendElement(Annotation(aName, NS_LITERAL_STRING("false")));
-  }
-}
-
-namespace Observer {
-
-Annotators::Annotators()
-  : mMutex("HangMonitor::Annotators::mMutex")
-{
-  MOZ_COUNT_CTOR(Annotators);
-}
-
-Annotators::~Annotators()
-{
-  MOZ_ASSERT(mAnnotators.empty());
-  MOZ_COUNT_DTOR(Annotators);
-}
-
-bool
-Annotators::Register(Annotator& aAnnotator)
-{
-  MutexAutoLock lock(mMutex);
-  auto result = mAnnotators.insert(&aAnnotator);
-  return result.second;
-}
-
-bool
-Annotators::Unregister(Annotator& aAnnotator)
-{
-  MutexAutoLock lock(mMutex);
-  DebugOnly<std::set<Annotator*>::size_type> numErased;
-  numErased = mAnnotators.erase(&aAnnotator);
-  MOZ_ASSERT(numErased == 1);
-  return mAnnotators.empty();
-}
-
-HangAnnotations
-Annotators::GatherAnnotations()
-{
-  HangAnnotations annotations;
-  { // Scope for lock
-    MutexAutoLock lock(mMutex);
-    for (std::set<Annotator*>::iterator i = mAnnotators.begin(),
-                                        e = mAnnotators.end();
-         i != e; ++i) {
-      (*i)->AnnotateHang(annotations);
-    }
-  }
-  return annotations;
-}
-
-} // namespace Observer
-
-void
-RegisterAnnotator(Annotator& aAnnotator)
-{
-  BackgroundHangMonitor::RegisterAnnotator(aAnnotator);
-  // We still register annotators for ChromeHangs
-  if (NS_IsMainThread() &&
-      GeckoProcessType_Default == XRE_GetProcessType()) {
-    if (!gChromehangAnnotators) {
-      gChromehangAnnotators = new Observer::Annotators();
-    }
-    gChromehangAnnotators->Register(aAnnotator);
-  }
-}
-
-void
-UnregisterAnnotator(Annotator& aAnnotator)
-{
-  BackgroundHangMonitor::UnregisterAnnotator(aAnnotator);
-  // We still register annotators for ChromeHangs
-  if (NS_IsMainThread() &&
-      GeckoProcessType_Default == XRE_GetProcessType()) {
-    if (gChromehangAnnotators->Unregister(aAnnotator)) {
-      gChromehangAnnotators = nullptr;
-    }
-  }
-}
-
-HangAnnotations
-ChromeHangAnnotatorCallout()
-{
-  if (!gChromehangAnnotators) {
-    return HangAnnotations();
-  }
-  return gChromehangAnnotators->GatherAnnotations();
-}
-
-} // namespace HangMonitor
-} // namespace mozilla
-
-namespace IPC {
-
-using mozilla::HangMonitor::Annotation;
-
-void
-ParamTraits<Annotation>::Write(Message* aMsg, const Annotation& aParam)
-{
-  WriteParam(aMsg, aParam.mName);
-  WriteParam(aMsg, aParam.mValue);
-}
-
-bool
-ParamTraits<Annotation>::Read(const Message* aMsg,
-                              PickleIterator* aIter,
-                              Annotation* aResult)
-{
-  if (!ReadParam(aMsg, aIter, &aResult->mName)) {
-    return false;
-  }
-  if (!ReadParam(aMsg, aIter, &aResult->mValue)) {
-    return false;
-  }
-  return true;
-}
-
-} // namespace IPC
deleted file mode 100644
--- a/xpcom/threads/HangAnnotations.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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 mozilla_HangAnnotations_h
-#define mozilla_HangAnnotations_h
-
-#include <set>
-
-#include "ipc/IPCMessageUtils.h"
-#include "mozilla/MemoryReporting.h"
-#include "mozilla/Mutex.h"
-#include "mozilla/Vector.h"
-#include "nsString.h"
-#include "nsTArray.h"
-
-namespace mozilla {
-namespace HangMonitor {
-
-/**
- * This type represents an individual hang annotation.
- */
-class Annotation
-{
-public:
-  Annotation() {}
-  Annotation(const nsAString& aName, const nsAString& aValue)
-    : mName(aName), mValue(aValue)
-  {}
-
-  nsString mName;
-  nsString mValue;
-};
-
-/**
- * This class extends nsTArray<Annotation> with some methods for adding
- * annotations being reported by a registered hang Annotator.
- */
-class HangAnnotations : public nsTArray<Annotation>
-{
-public:
-  void AddAnnotation(const nsAString& aName, const int32_t aData);
-  void AddAnnotation(const nsAString& aName, const double aData);
-  void AddAnnotation(const nsAString& aName, const nsAString& aData);
-  void AddAnnotation(const nsAString& aName, const nsACString& aData);
-  void AddAnnotation(const nsAString& aName, const bool aData);
-};
-
-class Annotator
-{
-public:
-  /**
-   * NB: This function is always called by the HangMonitor thread.
-   *     Plan accordingly.
-   */
-  virtual void AnnotateHang(HangAnnotations& aAnnotations) = 0;
-};
-
-/**
- * Registers an Annotator to be called when a hang is detected.
- * @param aAnnotator Reference to an object that implements the
- * HangMonitor::Annotator interface.
- */
-void RegisterAnnotator(Annotator& aAnnotator);
-
-/**
- * Registers an Annotator that was previously registered via RegisterAnnotator.
- * @param aAnnotator Reference to an object that implements the
- * HangMonitor::Annotator interface.
- */
-void UnregisterAnnotator(Annotator& aAnnotator);
-
-/**
- * Gathers annotations. This function should be called by ChromeHangs.
- * @return HangAnnotations object.
- */
-HangAnnotations ChromeHangAnnotatorCallout();
-
-namespace Observer {
-
-class Annotators
-{
-public:
-  Annotators();
-  ~Annotators();
-
-  bool Register(Annotator& aAnnotator);
-  bool Unregister(Annotator& aAnnotator);
-
-  HangAnnotations GatherAnnotations();
-
-private:
-  Mutex                mMutex;
-  std::set<Annotator*> mAnnotators;
-};
-
-} // namespace Observer
-
-} // namespace HangMonitor
-} // namespace mozilla
-
-namespace IPC {
-
-template<>
-class ParamTraits<mozilla::HangMonitor::HangAnnotations>
-  : public ParamTraits<nsTArray<mozilla::HangMonitor::Annotation>>
-{
-public:
-  typedef mozilla::HangMonitor::HangAnnotations paramType;
-};
-
-template<>
-class ParamTraits<mozilla::HangMonitor::Annotation>
-{
-public:
-  typedef mozilla::HangMonitor::Annotation paramType;
-  static void Write(Message* aMsg, const paramType& aParam);
-  static bool Read(const Message* aMsg,
-                   PickleIterator* aIter,
-                   paramType* aResult);
-};
-
-} // namespace IPC
-
-#endif // mozilla_HangAnnotations_h
deleted file mode 100644
--- a/xpcom/threads/HangMonitor.cpp
+++ /dev/null
@@ -1,424 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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/. */
-
-#include "mozilla/HangMonitor.h"
-
-#include "mozilla/Atomics.h"
-#include "mozilla/BackgroundHangMonitor.h"
-#include "mozilla/Monitor.h"
-#include "mozilla/Preferences.h"
-#include "mozilla/ProcessedStack.h"
-#include "mozilla/Telemetry.h"
-#include "mozilla/StaticPtr.h"
-#include "mozilla/UniquePtr.h"
-#include "nsExceptionHandler.h"
-#include "nsReadableUtils.h"
-#include "nsThreadUtils.h"
-#include "mozilla/StackWalk.h"
-#include "nsThreadUtils.h"
-#include "nsXULAppAPI.h"
-#include "GeckoProfiler.h"
-
-#ifdef XP_WIN
-#include <windows.h>
-#endif
-
-#if defined(MOZ_GECKO_PROFILER) && defined(MOZ_PROFILING) && defined(XP_WIN)
-  #define REPORT_CHROME_HANGS
-#endif
-
-namespace mozilla {
-namespace HangMonitor {
-
-/**
- * A flag which may be set from within a debugger to disable the hang
- * monitor.
- */
-volatile bool gDebugDisableHangMonitor = false;
-
-const char kHangMonitorPrefName[] = "hangmonitor.timeout";
-
-#ifdef REPORT_CHROME_HANGS
-const char kTelemetryPrefName[] = "toolkit.telemetry.enabled";
-#endif
-
-// Monitor protects gShutdown and gTimeout, but not gTimestamp which rely on
-// being atomically set by the processor; synchronization doesn't really matter
-// in this use case.
-Monitor* gMonitor;
-
-// The timeout preference, in seconds.
-int32_t gTimeout;
-
-PRThread* gThread;
-
-// Set when shutdown begins to signal the thread to exit immediately.
-bool gShutdown;
-
-// The timestamp of the last event notification, or PR_INTERVAL_NO_WAIT if
-// we're currently not processing events.
-Atomic<PRIntervalTime> gTimestamp(PR_INTERVAL_NO_WAIT);
-
-#ifdef REPORT_CHROME_HANGS
-// Main thread ID used in reporting chrome hangs under Windows
-static HANDLE winMainThreadHandle = nullptr;
-
-// Default timeout for reporting chrome hangs to Telemetry (5 seconds)
-static const int32_t DEFAULT_CHROME_HANG_INTERVAL = 5;
-
-// Maximum number of PCs to gather from the stack
-static const int32_t MAX_CALL_STACK_PCS = 400;
-#endif
-
-// PrefChangedFunc
-void
-PrefChanged(const char*, void*)
-{
-  int32_t newval = Preferences::GetInt(kHangMonitorPrefName);
-#ifdef REPORT_CHROME_HANGS
-  // Monitor chrome hangs on the profiling branch if Telemetry enabled
-  if (newval == 0) {
-    bool telemetryEnabled = Preferences::GetBool(kTelemetryPrefName);
-    if (telemetryEnabled) {
-      newval = DEFAULT_CHROME_HANG_INTERVAL;
-    }
-  }
-#endif
-  MonitorAutoLock lock(*gMonitor);
-  if (newval != gTimeout) {
-    gTimeout = newval;
-    lock.Notify();
-  }
-}
-
-void
-Crash()
-{
-  if (gDebugDisableHangMonitor) {
-    return;
-  }
-
-#ifdef XP_WIN
-  if (::IsDebuggerPresent()) {
-    return;
-  }
-#endif
-
-  // If you change this, you must also deal with the threadsafety of AnnotateCrashReport in
-  // non-chrome processes!
-  if (GeckoProcessType_Default == XRE_GetProcessType()) {
-    CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Hang"),
-                                       NS_LITERAL_CSTRING("1"));
-    CrashReporter::SetMinidumpAnalysisAllThreads();
-  }
-
-  MOZ_CRASH("HangMonitor triggered");
-}
-
-#ifdef REPORT_CHROME_HANGS
-
-static void
-ChromeStackWalker(uint32_t aFrameNumber, void* aPC, void* aSP, void* aClosure)
-{
-  MOZ_ASSERT(aClosure);
-  std::vector<uintptr_t>* stack =
-    static_cast<std::vector<uintptr_t>*>(aClosure);
-  if (stack->size() == MAX_CALL_STACK_PCS) {
-    return;
-  }
-  MOZ_ASSERT(stack->size() < MAX_CALL_STACK_PCS);
-  stack->push_back(reinterpret_cast<uintptr_t>(aPC));
-}
-
-static void
-GetChromeHangReport(Telemetry::ProcessedStack& aStack,
-                    int32_t& aSystemUptime,
-                    int32_t& aFirefoxUptime)
-{
-  MOZ_ASSERT(winMainThreadHandle);
-
-  // The thread we're about to suspend might have the alloc lock
-  // so allocate ahead of time
-  std::vector<uintptr_t> rawStack;
-  rawStack.reserve(MAX_CALL_STACK_PCS);
-
-  DWORD ret = ::SuspendThread(winMainThreadHandle);
-  bool suspended = false;
-  if (ret != (DWORD)-1) {
-    // SuspendThread is asynchronous, so the thread may still be running. Use
-    // GetThreadContext to ensure it's really suspended.
-    // See https://blogs.msdn.microsoft.com/oldnewthing/20150205-00/?p=44743.
-    CONTEXT context;
-    context.ContextFlags = CONTEXT_CONTROL;
-    if (::GetThreadContext(winMainThreadHandle, &context)) {
-      suspended = true;
-    }
-  }
-
-  if (!suspended) {
-    if (ret != (DWORD)-1) {
-      MOZ_ALWAYS_TRUE(::ResumeThread(winMainThreadHandle) != DWORD(-1));
-    }
-    return;
-  }
-
-  MozStackWalkThread(ChromeStackWalker, /* skipFrames */ 0, /* maxFrames */ 0,
-                     &rawStack, winMainThreadHandle, nullptr);
-  ret = ::ResumeThread(winMainThreadHandle);
-  if (ret == (DWORD)-1) {
-    return;
-  }
-  aStack = Telemetry::GetStackAndModules(rawStack);
-
-  // Record system uptime (in minutes) at the time of the hang
-  aSystemUptime = ((GetTickCount() / 1000) - (gTimeout * 2)) / 60;
-
-  // Record Firefox uptime (in minutes) at the time of the hang
-  bool error;
-  TimeStamp processCreation = TimeStamp::ProcessCreation(&error);
-  if (!error) {
-    TimeDuration td = TimeStamp::Now() - processCreation;
-    aFirefoxUptime = (static_cast<int32_t>(td.ToSeconds()) - (gTimeout * 2)) / 60;
-  } else {
-    aFirefoxUptime = -1;
-  }
-}
-
-#endif
-
-void
-ThreadMain(void*)
-{
-  AUTO_PROFILER_REGISTER_THREAD("Hang Monitor");
-  NS_SetCurrentThreadName("Hang Monitor");
-
-  MonitorAutoLock lock(*gMonitor);
-
-  // In order to avoid issues with the hang monitor incorrectly triggering
-  // during a general system stop such as sleeping, the monitor thread must
-  // run twice to trigger hang protection.
-  PRIntervalTime lastTimestamp = 0;
-  int waitCount = 0;
-
-#ifdef REPORT_CHROME_HANGS
-  Telemetry::ProcessedStack stack;
-  int32_t systemUptime = -1;
-  int32_t firefoxUptime = -1;
-  HangAnnotations annotations;
-#endif
-
-  while (true) {
-    if (gShutdown) {
-      return; // Exit the thread
-    }
-
-    // avoid rereading the volatile value in this loop
-    PRIntervalTime timestamp = gTimestamp;
-
-    PRIntervalTime now = PR_IntervalNow();
-
-    if (timestamp != PR_INTERVAL_NO_WAIT &&
-        now < timestamp) {
-      // 32-bit overflow, reset for another waiting period
-      timestamp = 1; // lowest legal PRInterval value
-    }
-
-    if (timestamp != PR_INTERVAL_NO_WAIT &&
-        timestamp == lastTimestamp &&
-        gTimeout > 0) {
-      ++waitCount;
-#ifdef REPORT_CHROME_HANGS
-      // Capture the chrome-hang stack + Firefox & system uptimes after
-      // the minimum hang duration has been reached (not when the hang ends)
-      if (waitCount == 2) {
-        GetChromeHangReport(stack, systemUptime, firefoxUptime);
-        annotations = ChromeHangAnnotatorCallout();
-      }
-#else
-      // This is the crash-on-hang feature.
-      // See bug 867313 for the quirk in the waitCount comparison
-      if (waitCount >= 2) {
-        int32_t delay =
-          int32_t(PR_IntervalToSeconds(now - timestamp));
-        if (delay >= gTimeout) {
-          MonitorAutoUnlock unlock(*gMonitor);
-          Crash();
-        }
-      }
-#endif
-    } else {
-#ifdef REPORT_CHROME_HANGS
-      if (waitCount >= 2) {
-        uint32_t hangDuration = PR_IntervalToSeconds(now - lastTimestamp);
-        Telemetry::RecordChromeHang(hangDuration, stack, systemUptime,
-                                    firefoxUptime, std::move(annotations));
-        stack.Clear();
-      }
-#endif
-      lastTimestamp = timestamp;
-      waitCount = 0;
-    }
-
-    TimeDuration timeout;
-    if (gTimeout <= 0) {
-      timeout = TimeDuration::Forever();
-    } else {
-      timeout = TimeDuration::FromMilliseconds(gTimeout * 500);
-    }
-    lock.Wait(timeout);
-  }
-}
-
-void
-Startup()
-{
-  if (GeckoProcessType_Default != XRE_GetProcessType() &&
-      GeckoProcessType_Content != XRE_GetProcessType()) {
-    return;
-  }
-
-  MOZ_ASSERT(!gMonitor, "Hang monitor already initialized");
-  gMonitor = new Monitor("HangMonitor");
-
-  Preferences::RegisterCallback(PrefChanged, kHangMonitorPrefName);
-  PrefChanged(nullptr, nullptr);
-
-#ifdef REPORT_CHROME_HANGS
-  Preferences::RegisterCallback(PrefChanged, kTelemetryPrefName);
-  winMainThreadHandle =
-    OpenThread(THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId());
-  if (!winMainThreadHandle) {
-    return;
-  }
-#endif
-
-  // Don't actually start measuring hangs until we hit the main event loop.
-  // This potentially misses a small class of really early startup hangs,
-  // but avoids dealing with some xpcshell tests and other situations which
-  // start XPCOM but don't ever start the event loop.
-  Suspend();
-
-  gThread = PR_CreateThread(PR_USER_THREAD,
-                            ThreadMain,
-                            nullptr, PR_PRIORITY_LOW, PR_GLOBAL_THREAD,
-                            PR_JOINABLE_THREAD, 0);
-}
-
-void
-Shutdown()
-{
-  if (GeckoProcessType_Default != XRE_GetProcessType() &&
-      GeckoProcessType_Content != XRE_GetProcessType()) {
-    return;
-  }
-
-  MOZ_ASSERT(gMonitor, "Hang monitor not started");
-
-  {
-    // Scope the lock we're going to delete later
-    MonitorAutoLock lock(*gMonitor);
-    gShutdown = true;
-    lock.Notify();
-  }
-
-  // thread creation could theoretically fail
-  if (gThread) {
-    PR_JoinThread(gThread);
-    gThread = nullptr;
-  }
-
-  delete gMonitor;
-  gMonitor = nullptr;
-}
-
-static bool
-IsUIMessageWaiting()
-{
-#ifndef XP_WIN
-  return false;
-#else
-  // There should never be mouse, keyboard, or IME messages in a message queue
-  // in the content process, so don't waste time making multiple PeekMessage
-  // calls.
-  if (GeckoProcessType_Content == XRE_GetProcessType()) {
-    return false;
-  }
-#define NS_WM_IMEFIRST WM_IME_SETCONTEXT
-#define NS_WM_IMELAST  WM_IME_KEYUP
-  BOOL haveUIMessageWaiting = FALSE;
-  MSG msg;
-  haveUIMessageWaiting |= ::PeekMessageW(&msg, nullptr, WM_KEYFIRST,
-                                         WM_IME_KEYLAST, PM_NOREMOVE);
-  haveUIMessageWaiting |= ::PeekMessageW(&msg, nullptr, NS_WM_IMEFIRST,
-                                         NS_WM_IMELAST, PM_NOREMOVE);
-  haveUIMessageWaiting |= ::PeekMessageW(&msg, nullptr, WM_MOUSEFIRST,
-                                         WM_MOUSELAST, PM_NOREMOVE);
-  return haveUIMessageWaiting;
-#endif
-}
-
-void
-NotifyActivity(ActivityType aActivityType)
-{
-  MOZ_ASSERT(NS_IsMainThread(),
-             "HangMonitor::Notify called from off the main thread.");
-
-  // Determine the activity type more specifically
-  if (aActivityType == kGeneralActivity) {
-    aActivityType = IsUIMessageWaiting() ? kActivityUIAVail :
-                                           kActivityNoUIAVail;
-  }
-
-  // Calculate the cumulative amount of lag time since the last UI message
-  static uint32_t cumulativeUILagMS = 0;
-  switch (aActivityType) {
-    case kActivityNoUIAVail:
-      cumulativeUILagMS = 0;
-      break;
-    case kActivityUIAVail:
-    case kUIActivity:
-      if (gTimestamp != PR_INTERVAL_NO_WAIT) {
-        cumulativeUILagMS += PR_IntervalToMilliseconds(PR_IntervalNow() -
-                                                       gTimestamp);
-      }
-      break;
-    default:
-      break;
-  }
-
-  // This is not a locked activity because PRTimeStamp is a 32-bit quantity
-  // which can be read/written atomically, and we don't want to pay locking
-  // penalties here.
-  gTimestamp = PR_IntervalNow();
-
-  // If we have UI activity we should reset the timer and report it
-  if (aActivityType == kUIActivity) {
-    mozilla::Telemetry::Accumulate(mozilla::Telemetry::EVENTLOOP_UI_ACTIVITY_EXP_MS,
-                                     cumulativeUILagMS);
-    cumulativeUILagMS = 0;
-  }
-
-  if (gThread && !gShutdown) {
-    mozilla::BackgroundHangMonitor().NotifyActivity();
-  }
-}
-
-void
-Suspend()
-{
-  MOZ_ASSERT(NS_IsMainThread(),
-             "HangMonitor::Suspend called from off the main thread.");
-
-  // Because gTimestamp changes this resets the wait count.
-  gTimestamp = PR_INTERVAL_NO_WAIT;
-
-  if (gThread && !gShutdown) {
-    mozilla::BackgroundHangMonitor().NotifyWait();
-  }
-}
-
-} // namespace HangMonitor
-} // namespace mozilla
deleted file mode 100644
--- a/xpcom/threads/HangMonitor.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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 mozilla_HangMonitor_h
-#define mozilla_HangMonitor_h
-
-namespace mozilla {
-namespace HangMonitor {
-
-/**
- * Signifies the type of activity in question
-*/
-enum ActivityType
-{
-  /* There is activity and it is known to be UI related activity. */
-  kUIActivity,
-
-  /* There is non UI activity and no UI activity is pending */
-  kActivityNoUIAVail,
-
-  /* There is non UI activity and UI activity is known to be pending */
-  kActivityUIAVail,
-
-  /* There is non UI activity and UI activity pending is unknown */
-  kGeneralActivity
-};
-
-/**
- * Start monitoring hangs. Should be called by the XPCOM startup process only.
- */
-void Startup();
-
-/**
- * Stop monitoring hangs and join the thread.
- */
-void Shutdown();
-
-/**
- * Notify the hang monitor of activity which will reset its internal timer.
- *
- * @param activityType The type of activity being reported.
- * @see ActivityType
- */
-void NotifyActivity(ActivityType activityType = kGeneralActivity);
-
-/*
- * Notify the hang monitor that the browser is now idle and no detection should
- * be done.
- */
-void Suspend();
-
-} // namespace HangMonitor
-} // namespace mozilla
-
-#endif // mozilla_HangMonitor_h
--- a/xpcom/threads/moz.build
+++ b/xpcom/threads/moz.build
@@ -39,18 +39,16 @@ EXPORTS.mozilla += [
     'AbstractEventQueue.h',
     'AbstractThread.h',
     'BlockingResourceBase.h',
     'CondVar.h',
     'CooperativeThreadPool.h',
     'CPUUsageWatcher.h',
     'DeadlockDetector.h',
     'EventQueue.h',
-    'HangAnnotations.h',
-    'HangMonitor.h',
     'IdleTaskRunner.h',
     'LazyIdleThread.h',
     'MainThreadIdlePeriod.h',
     'Monitor.h',
     'MozPromise.h',
     'Mutex.h',
     'PerformanceCounter.h',
     'Queue.h',
@@ -77,18 +75,16 @@ SOURCES += [
 ]
 
 UNIFIED_SOURCES += [
     'AbstractThread.cpp',
     'BlockingResourceBase.cpp',
     'CooperativeThreadPool.cpp',
     'CPUUsageWatcher.cpp',
     'EventQueue.cpp',
-    'HangAnnotations.cpp',
-    'HangMonitor.cpp',
     'InputEventStatistics.cpp',
     'LabeledEventQueue.cpp',
     'LazyIdleThread.cpp',
     'MainThreadIdlePeriod.cpp',
     'nsEnvironment.cpp',
     'nsILabelableRunnable.cpp',
     'nsMemoryPressure.cpp',
     'nsProcessCommon.cpp',
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -16,20 +16,20 @@
 #include "mozilla/ReentrantMonitor.h"
 #include "nsMemoryPressure.h"
 #include "nsThreadManager.h"
 #include "nsIClassInfoImpl.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsQueryObject.h"
 #include "pratom.h"
+#include "mozilla/BackgroundHangMonitor.h"
 #include "mozilla/CycleCollectedJSContext.h"
 #include "mozilla/Logging.h"
 #include "nsIObserverService.h"
-#include "mozilla/HangMonitor.h"
 #include "mozilla/IOInterposer.h"
 #include "mozilla/ipc/MessageChannel.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Scheduler.h"
 #include "mozilla/SchedulerGroup.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPrefs.h"
@@ -987,17 +987,17 @@ nsThread::ProcessNextEvent(bool aMayWait
     }
 
     *aResult = (event.get() != nullptr);
 
     if (event) {
       LOG(("THRD(%p) running [%p]\n", this, event.get()));
 
       if (MAIN_THREAD == mIsMainThread) {
-        HangMonitor::NotifyActivity();
+        BackgroundHangMonitor().NotifyActivity();
       }
 
       bool schedulerLoggingEnabled = mozilla::StaticPrefs::dom_performance_enable_scheduler_timing();
       if (schedulerLoggingEnabled
           && mNestedEventLoopDepth > mCurrentEventLoopDepth
           && mCurrentPerformanceCounter) {
           // This is a recursive call, we're saving the time
           // spent in the parent event if the runnable is linked to a DocGroup.
@@ -1214,17 +1214,17 @@ nsThread::SetScriptObserver(mozilla::Cyc
 void
 nsThread::DoMainThreadSpecificProcessing(bool aReallyWait)
 {
   MOZ_ASSERT(mIsMainThread == MAIN_THREAD);
 
   ipc::CancelCPOWs();
 
   if (aReallyWait) {
-    HangMonitor::Suspend();
+    BackgroundHangMonitor().NotifyWait();
   }
 
   // Fire a memory pressure notification, if one is pending.
   if (!ShuttingDown()) {
     MemoryPressureState mpPending = NS_GetPendingMemoryPressure();
     if (mpPending != MemPressure_None) {
       nsCOMPtr<nsIObserverService> os = services::GetObserverService();