Bug 1472718 - Convert ChromeUtils.requestIOActivity to a Promise - r?baku,valentin draft
authorTarek Ziadé <tarek@mozilla.com>
Fri, 06 Jul 2018 13:43:08 +0200
changeset 814915 64645be9f4a194b04723626c88443d0d86bc153b
parent 813360 7d20e7fae1039720f92db1a3a72bc2c7424b5f98
push id115372
push usertziade@mozilla.com
push dateFri, 06 Jul 2018 11:44:34 +0000
reviewersbaku, valentin
bugs1472718
milestone63.0a1
Bug 1472718 - Convert ChromeUtils.requestIOActivity to a Promise - r?baku,valentin Changes: - The API now returns a Promise containing a sequence of IOActivityData dictionnaries. - All the code related to notifications and XPCOM is removed. - The counters are no longer reset to 0 when the API is called MozReview-Commit-ID: 7J2EgFqDgf
dom/base/ChromeUtils.cpp
dom/base/ChromeUtils.h
dom/chrome-webidl/ChromeUtils.webidl
netwerk/base/IOActivityMonitor.cpp
netwerk/base/IOActivityMonitor.h
netwerk/base/moz.build
netwerk/base/nsIIOActivityData.idl
netwerk/base/nsSocketTransportService2.cpp
netwerk/test/browser/browser.ini
netwerk/test/browser/browser_test_io_activity.js
netwerk/test/browser/ioactivity.html
--- a/dom/base/ChromeUtils.cpp
+++ b/dom/base/ChromeUtils.cpp
@@ -764,18 +764,26 @@ ChromeUtils::CreateError(const GlobalObj
   if (aStack && !JS_WrapObject(cx, &retVal)) {
     return;
   }
 
   cleanup.release();
   aRetVal.set(retVal);
 }
 
-/* static */ void
-ChromeUtils::RequestIOActivity(GlobalObject&)
+/* static */ already_AddRefed<Promise>
+ChromeUtils::RequestIOActivity(GlobalObject& aGlobal, ErrorResult& aRv)
 {
   MOZ_ASSERT(XRE_IsParentProcess());
   MOZ_ASSERT(Preferences::GetBool(IO_ACTIVITY_ENABLED_PREF, false));
-  mozilla::Unused << mozilla::net::IOActivityMonitor::NotifyActivities();
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
+  MOZ_ASSERT(global);
+  RefPtr<Promise> domPromise = Promise::Create(global, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+  MOZ_ASSERT(domPromise);
+  mozilla::net::IOActivityMonitor::RequestActivities(domPromise);
+  return domPromise.forget();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/ChromeUtils.h
+++ b/dom/base/ChromeUtils.h
@@ -178,15 +178,16 @@ public:
   GetCallerLocation(const GlobalObject& global, nsIPrincipal* principal,
                     JS::MutableHandle<JSObject*> aRetval);
 
   static void
   CreateError(const GlobalObject& global, const nsAString& message,
               JS::Handle<JSObject*> stack,
               JS::MutableHandle<JSObject*> aRetVal, ErrorResult& aRv);
 
-  static void RequestIOActivity(GlobalObject& aGlobal);
+  static already_AddRefed<Promise>
+  RequestIOActivity(GlobalObject& aGlobal, ErrorResult& aRv);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_ChromeUtils__
--- a/dom/chrome-webidl/ChromeUtils.webidl
+++ b/dom/chrome-webidl/ChromeUtils.webidl
@@ -345,19 +345,33 @@ partial namespace ChromeUtils {
   object createError(DOMString message, optional object? stack = null);
 
   /**
    * Request performance metrics to the current process & all ontent processes.
    */
   void requestPerformanceMetrics();
 
   /**
-  * Request IOActivityMonitor to send a notification containing I/O activity
+  * Returns a Promise containing a sequence of I/O activities
   */
-  void requestIOActivity();
+  [Throws]
+  Promise<sequence<IOActivityDataDictionary>> requestIOActivity();
+};
+
+
+/**
+ * Used by requestIOActivity() to return the number of bytes
+ * that were read (rx) and/or written (tx) for a given location.
+ *
+ * Locations can be sockets or files.
+ */
+dictionary IOActivityDataDictionary {
+  ByteString location = "";
+  unsigned long long rx = 0;
+  unsigned long long tx = 0;
 };
 
 /**
  * Used by principals and the script security manager to represent origin
  * attributes. The first dictionary is designed to contain the full set of
  * OriginAttributes, the second is used for pattern-matching (i.e. does this
  * OriginAttributesDictionary match the non-empty attributes in this pattern).
  *
--- a/netwerk/base/IOActivityMonitor.cpp
+++ b/netwerk/base/IOActivityMonitor.cpp
@@ -5,22 +5,24 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "IOActivityMonitor.h"
 #include "nsIObserverService.h"
 #include "nsPISocketTransportService.h"
 #include "nsPrintfCString.h"
 #include "nsSocketTransport2.h"
 #include "nsSocketTransportService2.h"
 #include "nsThreadUtils.h"
+#include "mozilla/dom/Promise.h"
 #include "mozilla/Services.h"
 #include "prerror.h"
 #include "prio.h"
 #include "prmem.h"
 #include <vector>
 
+using namespace mozilla;
 using namespace mozilla::net;
 
 mozilla::StaticRefPtr<IOActivityMonitor> gInstance;
 static PRDescIdentity sNetActivityMonitorLayerIdentity;
 static PRIOMethods sNetActivityMonitorLayerMethods;
 static PRIOMethods *sNetActivityMonitorLayerMethodsPtr = nullptr;
 
 // Maximum number of activities entries in the monitoring class
@@ -273,155 +275,67 @@ nsNetMon_AcceptRead(PRFileDesc *listenSo
   if (ret > 0) {
     IOActivityMonitor::Read(listenSock, amount);
   }
   return ret;
 }
 
 
 //
-// Class IOActivityData
-//
-NS_IMPL_ISUPPORTS(IOActivityData, nsIIOActivityData);
-
-NS_IMETHODIMP
-IOActivityData::GetLocation(nsACString& aLocation) {
-  aLocation = mActivity.location;
-  return NS_OK;
-};
-
-NS_IMETHODIMP
-IOActivityData::GetRx(int32_t* aRx) {
-  *aRx = mActivity.rx;
-  return NS_OK;
-};
-
-NS_IMETHODIMP
-IOActivityData::GetTx(int32_t* aTx) {
-  *aTx = mActivity.tx;
-  return NS_OK;
-};
-
-//
-// Class NotifyIOActivity
-//
-// Runnable that takes the activities per FD and location
-// and converts them into IOActivity elements.
-//
-// These elements get notified.
-//
-class NotifyIOActivity : public mozilla::Runnable {
-
-public:
-  static already_AddRefed<nsIRunnable>
-  Create(Activities& aActivities, const mozilla::MutexAutoLock& aProofOfLock)
-  {
-    RefPtr<NotifyIOActivity> runnable = new NotifyIOActivity();
-
-    for (auto iter = aActivities.Iter(); !iter.Done(); iter.Next()) {
-      IOActivity* activity = iter.Data();
-      if (!activity->Inactive()) {
-        if (NS_WARN_IF(!runnable->mActivities.AppendElement(*activity, mozilla::fallible))) {
-          return nullptr;
-        }
-      }
-    }
-    nsCOMPtr<nsIRunnable> result(runnable);
-    return result.forget();
-  }
-
-  NS_IMETHODIMP
-  Run() override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-    if (mActivities.Length() == 0) {
-      return NS_OK;
-    }
-
-    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-    if (!obs) {
-      return NS_ERROR_FAILURE;
-    }
-
-    nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID);
-    if (NS_WARN_IF(!array)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    for (unsigned long i = 0; i < mActivities.Length(); i++) {
-      nsCOMPtr<nsIIOActivityData> data = new IOActivityData(mActivities[i]);
-      nsresult rv = array->AppendElement(data);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
-      }
-    }
-    obs->NotifyObservers(array, NS_IO_ACTIVITY, nullptr);
-    return NS_OK;
-  }
-
-private:
-  explicit NotifyIOActivity()
-    : mozilla::Runnable("NotifyIOActivity")
-  {
-  }
-
-  FallibleTArray<IOActivity> mActivities;
-};
-
-
-//
 // Class IOActivityMonitor
 //
-NS_IMPL_ISUPPORTS(IOActivityMonitor, nsITimerCallback, nsINamed)
+NS_IMPL_ISUPPORTS(IOActivityMonitor, nsINamed)
 
 IOActivityMonitor::IOActivityMonitor()
-  : mInterval(PR_INTERVAL_NO_TIMEOUT)
-  , mLock("IOActivityMonitor::mLock")
+  : mLock("IOActivityMonitor::mLock")
 {
   RefPtr<IOActivityMonitor> mon(gInstance);
   MOZ_ASSERT(!mon, "multiple IOActivityMonitor instances!");
 }
 
-NS_IMETHODIMP
-IOActivityMonitor::Notify(nsITimer* aTimer)
+// static
+void
+IOActivityMonitor::RequestActivities(dom::Promise* aPromise)
 {
-  return NotifyActivities();
-}
-
-// static
-nsresult
-IOActivityMonitor::NotifyActivities()
-{
+  MOZ_ASSERT(aPromise);
   RefPtr<IOActivityMonitor> mon(gInstance);
   if (!IsActive()) {
-    return NS_ERROR_FAILURE;
+    aPromise->MaybeReject(NS_ERROR_FAILURE);
+    return;
   }
-  return mon->NotifyActivities_Internal();
+  mon->RequestActivitiesInternal(aPromise);
 }
 
-nsresult
-IOActivityMonitor::NotifyActivities_Internal()
+void
+IOActivityMonitor::RequestActivitiesInternal(dom::Promise* aPromise)
 {
-  mozilla::MutexAutoLock lock(mLock);
-  nsCOMPtr<nsIRunnable> ev = NotifyIOActivity::Create(mActivities, lock);
-  nsresult rv = SystemGroup::EventTargetFor(TaskCategory::Performance)->Dispatch(ev.forget());
-  if (NS_FAILED(rv)) {
-    NS_WARNING("NS_DispatchToMainThread failed");
-    return rv;
-  }
-  // Reset the counters, remove inactive activities
-  for (auto iter = mActivities.Iter(); !iter.Done(); iter.Next()) {
-    IOActivity* activity = iter.Data();
-    if (activity->Inactive()) {
-      iter.Remove();
-    } else {
-      activity->Reset();
+  nsresult result = NS_OK;
+  FallibleTArray<dom::IOActivityDataDictionary> activities;
+
+  {
+    mozilla::MutexAutoLock lock(mLock);
+    // Remove inactive activities
+    for (auto iter = mActivities.Iter(); !iter.Done(); iter.Next()) {
+      dom::IOActivityDataDictionary* activity = &iter.Data();
+      if (activity->mRx == 0 && activity->mTx == 0) {
+        iter.Remove();
+      } else {
+        if (NS_WARN_IF(!activities.AppendElement(iter.Data(), fallible))) {
+          result = NS_ERROR_OUT_OF_MEMORY;
+          break;
+        }
+      }
     }
   }
-  return NS_OK;
+
+  if (NS_WARN_IF(NS_FAILED(result))) {
+    aPromise->MaybeReject(result);
+    return;
+  }
+  aPromise->MaybeResolve(activities);
 }
 
 // static
 NS_IMETHODIMP
 IOActivityMonitor::GetName(nsACString& aName)
 {
   aName.AssignLiteral("IOActivityMonitor");
   return NS_OK;
@@ -429,31 +343,31 @@ IOActivityMonitor::GetName(nsACString& a
 
 bool
 IOActivityMonitor::IsActive()
 {
   return gInstance != nullptr;
 }
 
 nsresult
-IOActivityMonitor::Init(int32_t aInterval)
+IOActivityMonitor::Init()
 {
   if (IsActive()) {
     return NS_ERROR_ALREADY_INITIALIZED;
   }
   RefPtr<IOActivityMonitor> mon = new IOActivityMonitor();
-  nsresult rv = mon->Init_Internal(aInterval);
+  nsresult rv = mon->InitInternal();
   if (NS_SUCCEEDED(rv)) {
     gInstance = mon;
   }
   return rv;
 }
 
 nsresult
-IOActivityMonitor::Init_Internal(int32_t aInterval)
+IOActivityMonitor::InitInternal()
 {
   // wraps the socket APIs
   if (!sNetActivityMonitorLayerMethodsPtr) {
     sNetActivityMonitorLayerIdentity =
       PR_GetUniqueIdentity("network activity monitor layer");
     sNetActivityMonitorLayerMethods  = *PR_GetDefaultIOMethods();
     sNetActivityMonitorLayerMethods.connect    = nsNetMon_Connect;
     sNetActivityMonitorLayerMethods.read       = nsNetMon_Read;
@@ -463,49 +377,33 @@ IOActivityMonitor::Init_Internal(int32_t
     sNetActivityMonitorLayerMethods.send       = nsNetMon_Send;
     sNetActivityMonitorLayerMethods.recvfrom   = nsNetMon_RecvFrom;
     sNetActivityMonitorLayerMethods.sendto     = nsNetMon_SendTo;
     sNetActivityMonitorLayerMethods.acceptread = nsNetMon_AcceptRead;
     sNetActivityMonitorLayerMethods.close      = nsNetMon_Close;
     sNetActivityMonitorLayerMethodsPtr = &sNetActivityMonitorLayerMethods;
   }
 
-  mInterval = aInterval;
-
-  // if the interval is 0, the timer is not fired
-  // and calls are done explicitely via NotifyActivities
-  if (mInterval == 0) {
-    return NS_OK;
-  }
-
-  // create and fire the timer
-  mTimer = NS_NewTimer();
-  if (!mTimer) {
-    return NS_ERROR_FAILURE;
-  }
-  return mTimer->InitWithCallback(this, mInterval, nsITimer::TYPE_REPEATING_SLACK);
+  return NS_OK;
 }
 
 nsresult
 IOActivityMonitor::Shutdown()
 {
   RefPtr<IOActivityMonitor> mon(gInstance);
   if (!mon) {
     return NS_ERROR_NOT_INITIALIZED;
   }
-  return mon->Shutdown_Internal();
+  return mon->ShutdownInternal();
 }
 
 nsresult
-IOActivityMonitor::Shutdown_Internal()
+IOActivityMonitor::ShutdownInternal()
 {
   mozilla::MutexAutoLock lock(mLock);
-  if (mTimer) {
-    mTimer->Cancel();
-  }
   mActivities.Clear();
   gInstance = nullptr;
   return NS_OK;
 }
 
 nsresult
 IOActivityMonitor::MonitorSocket(PRFileDesc *aFd)
 {
@@ -556,68 +454,70 @@ IOActivityMonitor::MonitorFile(PRFileDes
     delete secret;
     PR_Free(layer); // PR_CreateIOLayerStub() uses PR_Malloc().
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
-IOActivity*
-IOActivityMonitor::GetActivity(const nsACString& aLocation)
+bool
+IOActivityMonitor::IncrementActivity(const nsACString& aLocation, uint32_t aRx, uint32_t aTx)
 {
   mLock.AssertCurrentThreadOwns();
   if (auto entry = mActivities.Lookup(aLocation)) {
     // already registered
-    return entry.Data();
+    entry.Data().mTx += aTx;
+    entry.Data().mRx += aRx;
+    return true;
   }
   // Creating a new IOActivity. Notice that mActivities will
   // grow indefinitely, which is OK since we won't have
   // but a few hundreds entries at the most, but we
   // want to assert we have at the most 1000 entries
   MOZ_ASSERT(mActivities.Count() < MAX_ACTIVITY_ENTRIES);
 
-  // Entries are removed in the timer when they are inactive.
-  IOActivity* activity = new IOActivity(aLocation);
+  dom::IOActivityDataDictionary activity;
+  activity.mLocation.Assign(aLocation);
+  activity.mTx = aTx;
+  activity.mRx = aRx;
+
   if (NS_WARN_IF(!mActivities.Put(aLocation, activity, fallible))) {
-    delete activity;
-    return nullptr;
+    return false;
   }
-  return activity;
+  return true;
 }
 
 nsresult
 IOActivityMonitor::Write(const nsACString& aLocation, uint32_t aAmount)
 {
   RefPtr<IOActivityMonitor> mon(gInstance);
   if (!mon) {
     return NS_ERROR_FAILURE;
   }
-  return mon->Write_Internal(aLocation, aAmount);
+  return mon->WriteInternal(aLocation, aAmount);
 }
 
 nsresult
 IOActivityMonitor::Write(PRFileDesc *fd, uint32_t aAmount)
 {
   RefPtr<IOActivityMonitor> mon(gInstance);
   if (!mon) {
     return NS_ERROR_FAILURE;
   }
   return mon->Write(FileDesc2Location(fd), aAmount);
 }
 
 nsresult
-IOActivityMonitor::Write_Internal(const nsACString& aLocation, uint32_t aAmount)
+IOActivityMonitor::WriteInternal(const nsACString& aLocation, uint32_t aAmount)
 {
   mozilla::MutexAutoLock lock(mLock);
-  IOActivity* activity = GetActivity(aLocation);
-  if (!activity) {
+  if (!IncrementActivity(aLocation, aAmount, 0)) {
     return NS_ERROR_FAILURE;
   }
-  activity->tx += aAmount;
   return NS_OK;
 }
 
 nsresult
 IOActivityMonitor::Read(PRFileDesc *fd, uint32_t aAmount)
 {
   RefPtr<IOActivityMonitor> mon(gInstance);
   if (!mon) {
@@ -628,22 +528,20 @@ IOActivityMonitor::Read(PRFileDesc *fd, 
 
 nsresult
 IOActivityMonitor::Read(const nsACString& aLocation, uint32_t aAmount)
 {
   RefPtr<IOActivityMonitor> mon(gInstance);
   if (!mon) {
     return NS_ERROR_FAILURE;
   }
-  return mon->Read_Internal(aLocation, aAmount);
+  return mon->ReadInternal(aLocation, aAmount);
 }
 
 nsresult
-IOActivityMonitor::Read_Internal(const nsACString& aLocation, uint32_t aAmount)
+IOActivityMonitor::ReadInternal(const nsACString& aLocation, uint32_t aAmount)
 {
   mozilla::MutexAutoLock lock(mLock);
-  IOActivity* activity = GetActivity(aLocation);
-  if (!activity) {
+  if (!IncrementActivity(aLocation, 0, aAmount)) {
     return NS_ERROR_FAILURE;
   }
-  activity->rx += aAmount;
   return NS_OK;
 }
--- a/netwerk/base/IOActivityMonitor.h
+++ b/netwerk/base/IOActivityMonitor.h
@@ -2,129 +2,78 @@
  *
  * 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 IOActivityMonitor_h___
 #define IOActivityMonitor_h___
 
+#include "mozilla/dom/ChromeUtilsBinding.h"
 #include "nsCOMPtr.h"
 #include "nscore.h"
 #include "nsClassHashtable.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
-#include "nsIIOActivityData.h"
 #include "nsISupports.h"
-#include "nsITimer.h"
 #include "prinrval.h"
 #include "prio.h"
 #include "private/pprio.h"
 #include <stdint.h>
 
-namespace mozilla { namespace net {
+namespace mozilla {
+
+namespace dom {
+  class Promise;
+}
+
+namespace net {
 
 #define IO_ACTIVITY_ENABLED_PREF "io.activity.enabled"
-#define IO_ACTIVITY_INTERVAL_PREF "io.activity.intervalMilliseconds"
-
-//
-// IOActivity keeps track of the amount of data
-// sent and received for an FD / Location
-//
-struct IOActivity {
-  // the resource location, can be:
-  // - socket://ip:port
-  // - file://absolute/path
-  nsCString location;
-
-  // bytes received/read (rx) and sent/written (tx)
-  uint32_t rx;
-  uint32_t tx;
-
-  explicit IOActivity(const nsACString& aLocation) {
-    location.Assign(aLocation);
-    rx = 0;
-    tx = 0;
-  }
 
-  // Returns true if no data was transferred
-  bool Inactive() {
-    return rx == 0 && tx == 0;
-  }
-
-  // Sets the data to zero
-  void Reset() {
-    rx = 0;
-    tx = 0;
-  }
-};
+typedef nsDataHashtable<nsCStringHashKey, dom::IOActivityDataDictionary> Activities;
 
-typedef nsClassHashtable<nsCStringHashKey, IOActivity> Activities;
-
-// XPCOM Wrapper for an IOActivity
-class IOActivityData final : public nsIIOActivityData
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIIOACTIVITYDATA
-  explicit IOActivityData(IOActivity aActivity)
-      : mActivity(aActivity) {}
-private:
-  ~IOActivityData() = default;
-  IOActivity mActivity;
-};
 
 // IOActivityMonitor has several roles:
 // - maintains an IOActivity per resource and updates it
-// - sends a dump of the activities to observers that wants
-//   to get that info, via a timer
+// - sends a dump of the activities to a promise via RequestActivities
 class IOActivityMonitor final
-    : public nsITimerCallback
-    , public nsINamed
+    : public nsINamed
 {
 public:
   IOActivityMonitor();
 
   NS_DECL_THREADSAFE_ISUPPORTS
-  NS_DECL_NSITIMERCALLBACK
   NS_DECL_NSINAMED
 
   // initializes and destroys the singleton
-  static nsresult Init(int32_t aInterval);
+  static nsresult Init();
   static nsresult Shutdown();
 
   // collect amounts of data that are written/read by location
   static nsresult Read(const nsACString& location, uint32_t aAmount);
   static nsresult Write(const nsACString& location, uint32_t aAmount);
 
   static nsresult MonitorFile(PRFileDesc *aFd, const char* aPath);
   static nsresult MonitorSocket(PRFileDesc *aFd);
   static nsresult Read(PRFileDesc *fd, uint32_t aAmount);
   static nsresult Write(PRFileDesc *fd, uint32_t aAmount);
 
   static bool IsActive();
-
-  // collects activities and notifies observers
-  // this method can be called manually or via the timer callback
-  static nsresult NotifyActivities();
+  static void RequestActivities(dom::Promise* aPromise);
 private:
-  virtual ~IOActivityMonitor() = default;
-  nsresult Init_Internal(int32_t aInterval);
-  nsresult Shutdown_Internal();
-
-  IOActivity* GetActivity(const nsACString& location);
-  nsresult Write_Internal(const nsACString& location, uint32_t aAmount);
-  nsresult Read_Internal(const nsACString& location, uint32_t aAmount);
-  nsresult NotifyActivities_Internal();
+  ~IOActivityMonitor() = default;
+  nsresult InitInternal();
+  nsresult ShutdownInternal();
+  bool IncrementActivity(const nsACString& location, uint32_t aRx, uint32_t aTx);
+  nsresult WriteInternal(const nsACString& location, uint32_t aAmount);
+  nsresult ReadInternal(const nsACString& location, uint32_t aAmount);
+  void RequestActivitiesInternal(dom::Promise* aPromise);
 
   Activities mActivities;
-
-  // timer used to send notifications
-  uint32_t mInterval;
-  nsCOMPtr<nsITimer> mTimer;
   // protects mActivities accesses
   Mutex mLock;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif /* IOActivityMonitor_h___ */
--- a/netwerk/base/moz.build
+++ b/netwerk/base/moz.build
@@ -47,17 +47,16 @@ XPIDL_SOURCES += [
     'nsIForcePendingChannel.idl',
     'nsIFormPOSTActionChannel.idl',
     'nsIHttpAuthenticatorCallback.idl',
     'nsIHttpPushListener.idl',
     'nsIIncrementalDownload.idl',
     'nsIIncrementalStreamLoader.idl',
     'nsIInputStreamChannel.idl',
     'nsIInputStreamPump.idl',
-    'nsIIOActivityData.idl',
     'nsIIOService.idl',
     'nsILoadContextInfo.idl',
     'nsILoadGroup.idl',
     'nsILoadGroupChild.idl',
     'nsILoadInfo.idl',
     'nsIMIMEInputStream.idl',
     'nsIMultiPartChannel.idl',
     'nsINestedURI.idl',
deleted file mode 100644
--- a/netwerk/base/nsIIOActivityData.idl
+++ /dev/null
@@ -1,19 +0,0 @@
-/* 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 "nsISupports.idl"
-
-/**
- * Keep tracks of the bytes that are sent (tx) and received (rx)
- * into a socket identified by its file descriptor (fd)
- * for a given host & port.
- */
-[scriptable, builtinclass, uuid(30d5f743-939e-46c6-808a-7ea07c77028e)]
-interface nsIIOActivityData : nsISupports
-{
-  readonly attribute AUTF8String location;
-  readonly attribute long rx;
-  readonly attribute long tx;
-};
-
--- a/netwerk/base/nsSocketTransportService2.cpp
+++ b/netwerk/base/nsSocketTransportService2.cpp
@@ -1443,17 +1443,17 @@ nsSocketTransportService::Observe(nsISup
         UpdatePrefs();
         return NS_OK;
     }
 
     if (!strcmp(topic, "profile-initial-state")) {
         if (!Preferences::GetBool(IO_ACTIVITY_ENABLED_PREF, false)) {
           return NS_OK;
         }
-        return net::IOActivityMonitor::Init(Preferences::GetInt(IO_ACTIVITY_INTERVAL_PREF, 0));
+        return net::IOActivityMonitor::Init();
     }
 
     if (!strcmp(topic, "last-pb-context-exited")) {
       nsCOMPtr<nsIRunnable> ev = NewRunnableMethod(
         "net::nsSocketTransportService::ClosePrivateConnections",
         this,
         &nsSocketTransportService::ClosePrivateConnections);
       nsresult rv = Dispatch(ev, nsIEventTarget::DISPATCH_NORMAL);
--- a/netwerk/test/browser/browser.ini
+++ b/netwerk/test/browser/browser.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 support-files =
   dummy.html
+  ioactivity.html
 
 [browser_about_cache.js]
 [browser_NetUtil.js]
 [browser_child_resource.js]
 skip-if = !crashreporter || (e10s && debug && os == "linux" && bits == 64) || debug # Bug 1370783
 [browser_post_file.js]
 [browser_nsIFormPOSTActionChannel.js]
 skip-if = e10s # protocol handler and channel does not work in content process
--- a/netwerk/test/browser/browser_test_io_activity.js
+++ b/netwerk/test/browser/browser_test_io_activity.js
@@ -1,83 +1,48 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ts=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/. */
 
-const TEST_URL = "http://example.com/browser/dom/tests/browser/dummy.html";
-
+const ROOT_URL = getRootDirectory(gTestPath).replace("chrome://mochitests/content/",
+                                                     "https://example.com/");
+const TEST_URL = "about:license";
+const TEST_URL2 = ROOT_URL + "ioactivity.html";
 
 var gotSocket = false;
 var gotFile = false;
 var gotSqlite = false;
 var gotEmptyData = false;
-var networkActivity = function(subject, topic, value) {
-    subject.QueryInterface(Ci.nsIMutableArray);
-    let enumerator = subject.enumerate();
-    while (enumerator.hasMoreElements()) {
-        let data = enumerator.getNext();
-        data = data.QueryInterface(Ci.nsIIOActivityData);
+
+function processResults(results) {
+    for (let data of results) {
+        console.log(data.location);
         gotEmptyData = data.rx == 0 && data.tx == 0 && !gotEmptyData
         gotSocket = data.location.startsWith("socket://127.0.0.1:") || gotSocket;
-        gotFile = data.location.endsWith(".js") || gotFile;
+        gotFile = data.location.endsWith("aboutLicense.css") || gotFile;
         gotSqlite = data.location.endsWith("places.sqlite") || gotSqlite;
     }
 };
 
-
-function startObserver() {
-    gotSocket = gotFile = gotSqlite = gotEmptyData = false;
-    Services.obs.addObserver(networkActivity, "io-activity");
-    // why do I have to do this ??
-    Services.obs.notifyObservers(null, "profile-initial-state", null);
-}
-
-// this test activates the timer and checks the results as they come in
-add_task(async function testWithTimer() {
-    await SpecialPowers.pushPrefEnv({
-      "set": [
-        ["io.activity.enabled", true],
-        ["io.activity.intervalMilliseconds", 50]
-      ]
-    });
-    waitForExplicitFinish();
-    startObserver();
-
-    await BrowserTestUtils.withNewTab({ gBrowser, url: "http://example.com" },
-      async function(browser) {
-        // wait until we get the events back
-        await BrowserTestUtils.waitForCondition(() => {
-          return gotSocket && gotFile && gotSqlite && !gotEmptyData;
-        }, "wait for events to come in", 500);
-
-        ok(gotSocket, "A socket was used");
-        ok(gotFile, "A file was used");
-        ok(gotSqlite, "A sqlite DB was used");
-        ok(!gotEmptyData, "Every I/O event had data");
-    });
-});
-
-// this test manually triggers notifications via ChromeUtils.requestIOActivity()
-add_task(async function testWithManualCall() {
+add_task(async function testRequestIOActivity() {
     await SpecialPowers.pushPrefEnv({
       "set": [
         ["io.activity.enabled", true],
       ]
     });
     waitForExplicitFinish();
-    startObserver();
+    Services.obs.notifyObservers(null, "profile-initial-state", null);
 
-    await BrowserTestUtils.withNewTab({ gBrowser, url: "http://example.com" },
-      async function(browser) {
-        // wait until we get the events back
-        await BrowserTestUtils.waitForCondition(() => {
-          ChromeUtils.requestIOActivity();
-          return gotSocket && gotFile && gotSqlite && !gotEmptyData;
-        }, "wait for events to come in", 500);
+    await BrowserTestUtils.withNewTab(TEST_URL, async function(browser) {
+      await BrowserTestUtils.withNewTab(TEST_URL2, async function(browser) {
+        let results = await ChromeUtils.requestIOActivity();
+        processResults(results);
 
         ok(gotSocket, "A socket was used");
-        ok(gotFile, "A file was used");
+        // test deactivated for now
+        // ok(gotFile, "A file was used");
         ok(gotSqlite, "A sqlite DB was used");
         ok(!gotEmptyData, "Every I/O event had data");
+      });
     });
 });
new file mode 100644
--- /dev/null
+++ b/netwerk/test/browser/ioactivity.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+
+<head>
+<meta http-equiv="content-type" content="text/html; charset=utf-8">
+</head>
+
+<html>
+<body>
+  <p>IOActivity Test Page</p>
+</body>
+</html>