Bug 1492036 - Reporting API - part 8 - memory-pressure, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 14 Nov 2018 20:02:34 +0100
changeset 446487 2751ee1bdac688b2a7b83114975ea3dc4e772327
parent 446486 6119216d9038e35089b6d5a23a3d9a0deb1b8416
child 446488 91659baa6ddbb00282b9a3f9b9748cb25597c13e
push id35042
push useraiakab@mozilla.com
push dateThu, 15 Nov 2018 09:54:38 +0000
treeherdermozilla-central@dca9c72df68b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1492036
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1492036 - Reporting API - part 8 - memory-pressure, r=smaug
dom/base/nsGlobalWindowInner.cpp
dom/reporting/ReportingObserver.cpp
dom/reporting/ReportingObserver.h
dom/reporting/tests/.eslintrc.js
dom/reporting/tests/mochitest.ini
dom/reporting/tests/test_memoryPressure.html
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -5667,16 +5667,17 @@ nsGlobalWindowInner::Observe(nsISupports
         FireOfflineStatusEventIfChanged();
     }
     return NS_OK;
   }
 
   if (!nsCRT::strcmp(aTopic, MEMORY_PRESSURE_OBSERVER_TOPIC)) {
     if (mPerformance) {
       mPerformance->MemoryPressure();
+      mReportRecords.Clear();
     }
     return NS_OK;
   }
 
   if (!nsCRT::strcmp(aTopic, "clear-site-data-reload-needed")) {
     // The reload is propagated from the top-level window only.
     NS_ConvertUTF16toUTF8 otherOrigin(aData);
     PropagateClearSiteDataReload(otherOrigin);
--- a/dom/reporting/ReportingObserver.cpp
+++ b/dom/reporting/ReportingObserver.cpp
@@ -9,17 +9,17 @@
 #include "nsContentUtils.h"
 #include "nsGlobalWindowInner.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(ReportingObserver)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ReportingObserver)
-  tmp->Disconnect();
+  tmp->Shutdown();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mReports)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ReportingObserver)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReports)
@@ -27,18 +27,20 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(ReportingObserver)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(ReportingObserver)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(ReportingObserver)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReportingObserver)
+  NS_INTERFACE_MAP_ENTRY(nsIObserver)
+  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 /* static */ already_AddRefed<ReportingObserver>
 ReportingObserver::Constructor(const GlobalObject& aGlobal,
                                ReportingObserverCallback& aCallback,
                                const ReportingObserverOptions& aOptions,
                                ErrorResult& aRv)
 {
@@ -47,16 +49,28 @@ ReportingObserver::Constructor(const Glo
 
   nsTArray<nsString> types;
   if (aOptions.mTypes.WasPassed()) {
     types = aOptions.mTypes.Value();
   }
 
   RefPtr<ReportingObserver> ro =
     new ReportingObserver(window, aCallback, types, aOptions.mBuffered);
+
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (NS_WARN_IF(!obs)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  aRv = obs->AddObserver(ro, "memory-pressure", true);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
   return ro.forget();
 }
 
 ReportingObserver::ReportingObserver(nsPIDOMWindowInner* aWindow,
                                      ReportingObserverCallback& aCallback,
                                      const nsTArray<nsString>& aTypes,
                                      bool aBuffered)
   : mWindow(aWindow)
@@ -64,17 +78,28 @@ ReportingObserver::ReportingObserver(nsP
   , mTypes(aTypes)
   , mBuffered(aBuffered)
 {
   MOZ_ASSERT(aWindow);
 }
 
 ReportingObserver::~ReportingObserver()
 {
+  Shutdown();
+}
+
+void
+ReportingObserver::Shutdown()
+{
   Disconnect();
+
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->RemoveObserver(this, "memory-pressure");
+  }
 }
 
 JSObject*
 ReportingObserver::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return ReportingObserver_Binding::Wrap(aCx, this, aGivenProto);
 }
 
@@ -154,10 +179,19 @@ ReportingObserver::MaybeNotify()
       return;
     }
   }
 
   // We should report if this throws exception. But where?
   mCallback->Call(reports, *this);
 }
 
+NS_IMETHODIMP
+ReportingObserver::Observe(nsISupports* aSubject, const char* aTopic,
+                           const char16_t* aData)
+{
+  MOZ_ASSERT(!strcmp(aTopic, "memory-pressure"));
+  mReports.Clear();
+  return NS_OK;
+}
+
 } // dom namespace
 } // mozilla namespace
--- a/dom/reporting/ReportingObserver.h
+++ b/dom/reporting/ReportingObserver.h
@@ -5,34 +5,39 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_ReportingObserver_h
 #define mozilla_dom_ReportingObserver_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsIObserver.h"
+#include "nsWeakReference.h"
 #include "nsWrapperCache.h"
 #include "nsTArray.h"
 
 class nsPIDOMWindowInner;
 
 namespace mozilla {
 namespace dom {
 
 class Report;
 class ReportingObserverCallback;
 struct ReportingObserverOptions;
 
-class ReportingObserver final : public nsISupports
+class ReportingObserver final : public nsIObserver
                               , public nsWrapperCache
+                              , public nsSupportsWeakReference
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ReportingObserver)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(ReportingObserver,
+                                                         nsIObserver)
+  NS_DECL_NSIOBSERVER
 
   static already_AddRefed<ReportingObserver>
   Constructor(const GlobalObject& aGlobal,
               ReportingObserverCallback& aCallback,
               const ReportingObserverOptions& aOptions,
               ErrorResult& aRv);
 
   ReportingObserver(nsPIDOMWindowInner* aWindow,
@@ -62,16 +67,19 @@ public:
   MaybeReport(Report* aReport);
 
   void
   MaybeNotify();
 
 private:
   ~ReportingObserver();
 
+  void
+  Shutdown();
+
   nsTArray<RefPtr<Report>> mReports;
 
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
   RefPtr<ReportingObserverCallback> mCallback;
   nsTArray<nsString> mTypes;
   bool mBuffered;
 };
 
new file mode 100644
--- /dev/null
+++ b/dom/reporting/tests/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/mochitest-test",
+  ],
+};
--- a/dom/reporting/tests/mochitest.ini
+++ b/dom/reporting/tests/mochitest.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 prefs =
   dom.reporting.enabled=true
   dom.reporting.testing.enabled=true
 
 [test_deprecated.html]
+[test_memoryPressure.html]
new file mode 100644
--- /dev/null
+++ b/dom/reporting/tests/test_memoryPressure.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for ReportingObserver + memory-pressure</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="application/javascript">
+
+info("Testing TakeRecords() without memory-pressure");
+let o = new ReportingObserver(() => {});
+o.observe();
+
+new TestingDeprecatedInterface();
+let r = o.takeRecords();
+is(r.length, 1, "We have 1 report");
+
+r = o.takeRecords();
+is(r.length, 0, "We have 0 reports after a takeRecords()");
+
+info("Testing DeprecatedTestingMethod report");
+
+new TestingDeprecatedInterface();
+SpecialPowers.Services.obs.notifyObservers(null, "memory-pressure", "heap-minimize");
+
+r = o.takeRecords();
+is(r.length, 0, "We have 0 reports after a memory-pressure");
+
+</script>
+</body>
+</html>