Browse Source

minor backports

Frank-Rainer Grahl 3 months ago
parent
commit
9fe9257390

+ 467 - 0
mozilla-release/patches/1444490-61a1.patch

@@ -0,0 +1,467 @@
+# HG changeset patch
+# User Tom Ritter <tom@mozilla.com>
+# Date 1520606238 21600
+# Node ID ab89c04fa91c6f6cea88b34d4a6ced81c6a3a2cd
+# Parent  22d80c6d2f93a74670e11b39f580409961bc804a
+Bug 1444490 Declare classses (and one method) in network/ final to reduce virtual function calls r=nwgh
+
+MozReview-Commit-ID: 4oaazbPhpbc
+
+diff --git a/netwerk/base/Dashboard.cpp b/netwerk/base/Dashboard.cpp
+--- a/netwerk/base/Dashboard.cpp
++++ b/netwerk/base/Dashboard.cpp
+@@ -280,17 +280,17 @@ public:
+ 
+     nsCOMPtr<nsIDNSRecord> mRecord;
+     RefPtr<LookupHelper> mHelper;
+ };
+ 
+ NS_IMPL_ISUPPORTS0(LookupArgument)
+ 
+ 
+-class LookupHelper
++class LookupHelper final
+     : public nsIDNSListener
+ {
+     virtual ~LookupHelper()
+     {
+         if (mCancel) {
+             mCancel->Cancel(NS_ERROR_ABORT);
+         }
+     }
+diff --git a/netwerk/base/LoadContextInfo.h b/netwerk/base/LoadContextInfo.h
+--- a/netwerk/base/LoadContextInfo.h
++++ b/netwerk/base/LoadContextInfo.h
+@@ -8,17 +8,17 @@
+ #include "nsILoadContextInfo.h"
+ 
+ class nsIChannel;
+ class nsILoadContext;
+ 
+ namespace mozilla {
+ namespace net {
+ 
+-class LoadContextInfo : public nsILoadContextInfo
++class LoadContextInfo final : public nsILoadContextInfo
+ {
+ public:
+   NS_DECL_THREADSAFE_ISUPPORTS
+   NS_DECL_NSILOADCONTEXTINFO
+ 
+   LoadContextInfo(bool aIsAnonymous, OriginAttributes aOriginAttributes);
+ 
+ private:
+diff --git a/netwerk/base/NetworkActivityMonitor.h b/netwerk/base/NetworkActivityMonitor.h
+--- a/netwerk/base/NetworkActivityMonitor.h
++++ b/netwerk/base/NetworkActivityMonitor.h
+@@ -50,18 +50,19 @@ private:
+   nsString mHost;
+   int32_t mPort;
+   int32_t mFd;
+   int32_t mRx;
+   int32_t mTx;
+ };
+ 
+ 
+-class NetworkActivityMonitor: public nsITimerCallback
+-                            , public nsINamed
++class NetworkActivityMonitor final
++    : public nsITimerCallback
++    , public nsINamed
+ {
+ public:
+   enum Direction {
+     kUpload   = 0,
+     kDownload = 1
+   };
+ 
+   NetworkActivityMonitor();
+diff --git a/netwerk/base/Predictor.h b/netwerk/base/Predictor.h
+--- a/netwerk/base/Predictor.h
++++ b/netwerk/base/Predictor.h
+@@ -32,22 +32,23 @@ class nsILoadContextInfo;
+ class nsITimer;
+ 
+ namespace mozilla {
+ namespace net {
+ 
+ class nsHttpRequestHead;
+ class nsHttpResponseHead;
+ 
+-class Predictor : public nsINetworkPredictor
+-                , public nsIObserver
+-                , public nsISpeculativeConnectionOverrider
+-                , public nsIInterfaceRequestor
+-                , public nsICacheEntryMetaDataVisitor
+-                , public nsINetworkPredictorVerifier
++class Predictor final
++  : public nsINetworkPredictor
++  , public nsIObserver
++  , public nsISpeculativeConnectionOverrider
++  , public nsIInterfaceRequestor
++  , public nsICacheEntryMetaDataVisitor
++  , public nsINetworkPredictorVerifier
+ {
+ public:
+   NS_DECL_ISUPPORTS
+   NS_DECL_NSINETWORKPREDICTOR
+   NS_DECL_NSIOBSERVER
+   NS_DECL_NSISPECULATIVECONNECTIONOVERRIDER
+   NS_DECL_NSIINTERFACEREQUESTOR
+   NS_DECL_NSICACHEENTRYMETADATAVISITOR
+diff --git a/netwerk/base/nsBufferedStreams.h b/netwerk/base/nsBufferedStreams.h
+--- a/netwerk/base/nsBufferedStreams.h
++++ b/netwerk/base/nsBufferedStreams.h
+@@ -56,23 +56,24 @@ protected:
+ 
+     bool                        mBufferDisabled;
+     bool                        mEOF;  // True if mStream is at EOF
+     uint8_t                     mGetBufferCount;
+ };
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-class nsBufferedInputStream : public nsBufferedStream,
+-                              public nsIBufferedInputStream,
+-                              public nsIStreamBufferAccess,
+-                              public nsIIPCSerializableInputStream,
+-                              public nsIAsyncInputStream,
+-                              public nsIInputStreamCallback,
+-                              public nsICloneableInputStream
++class nsBufferedInputStream final
++    : public nsBufferedStream,
++      public nsIBufferedInputStream,
++      public nsIStreamBufferAccess,
++      public nsIIPCSerializableInputStream,
++      public nsIAsyncInputStream,
++      public nsIInputStreamCallback,
++      public nsICloneableInputStream
+ {
+ public:
+     NS_DECL_ISUPPORTS_INHERITED
+     NS_DECL_NSIINPUTSTREAM
+     NS_DECL_NSIBUFFEREDINPUTSTREAM
+     NS_DECL_NSISTREAMBUFFERACCESS
+     NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
+     NS_DECL_NSIASYNCINPUTSTREAM
+diff --git a/netwerk/base/nsSimpleURI.h.1444490.latetr b/netwerk/base/nsSimpleURI.h.1444490.latetr
+new file mode 100644
+--- /dev/null
++++ b/netwerk/base/nsSimpleURI.h.1444490.latetr
+@@ -0,0 +1,21 @@
++--- nsSimpleURI.h
+++++ nsSimpleURI.h
++@@ -73,17 +73,17 @@ protected:
++         eIgnoreRef,
++         eHonorRef,
++         eReplaceRef
++     };
++ 
++     virtual nsresult SetSpecInternal(const nsACString &input);
++     virtual nsresult SetScheme(const nsACString &input);
++     virtual nsresult SetUserPass(const nsACString &input);
++-    virtual nsresult SetUsername(const nsACString &input);
+++    nsresult SetUsername(const nsACString &input);
++     virtual nsresult SetPassword(const nsACString &input);
++     virtual nsresult SetHostPort(const nsACString &aValue);
++     virtual nsresult SetHost(const nsACString &input);
++     virtual nsresult SetPort(int32_t port);
++     virtual nsresult SetPathQueryRef(const nsACString &input);
++     virtual nsresult SetRef(const nsACString &input);
++     virtual nsresult SetFilePath(const nsACString &input);
++     virtual nsresult SetQuery(const nsACString &input);
+diff --git a/netwerk/cache2/CacheFileChunk.h b/netwerk/cache2/CacheFileChunk.h
+--- a/netwerk/cache2/CacheFileChunk.h
++++ b/netwerk/cache2/CacheFileChunk.h
+@@ -129,18 +129,19 @@ public:
+ class ChunkListeners {
+ public:
+   ChunkListeners()  { MOZ_COUNT_CTOR(ChunkListeners); }
+   ~ChunkListeners() { MOZ_COUNT_DTOR(ChunkListeners); }
+ 
+   nsTArray<ChunkListenerItem *> mItems;
+ };
+ 
+-class CacheFileChunk : public CacheFileIOListener
+-                     , public CacheMemoryConsumer
++class CacheFileChunk final
++  : public CacheFileIOListener
++  , public CacheMemoryConsumer
+ {
+ public:
+   NS_DECL_THREADSAFE_ISUPPORTS
+   bool DispatchRelease();
+ 
+   CacheFileChunk(CacheFile *aFile, uint32_t aIndex, bool aInitByWriter);
+ 
+   void     InitNew();
+diff --git a/netwerk/cache2/CacheFileIOManager.h b/netwerk/cache2/CacheFileIOManager.h
+--- a/netwerk/cache2/CacheFileIOManager.h
++++ b/netwerk/cache2/CacheFileIOManager.h
+@@ -38,17 +38,17 @@ class CacheFileIOListener;
+ class CacheFileHandlesEntry;
+ #endif
+ 
+ #define ENTRIES_DIR "entries"
+ #define DOOMED_DIR  "doomed"
+ #define TRASH_DIR   "trash"
+ 
+ 
+-class CacheFileHandle : public nsISupports
++class CacheFileHandle final : public nsISupports
+ {
+ public:
+   enum class PinningStatus : uint32_t {
+     UNKNOWN,
+     NON_PINNED,
+     PINNED
+   };
+ 
+@@ -254,18 +254,19 @@ public:
+   NS_IMETHOD OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult) = 0;
+ 
+   virtual bool IsKilled() { return false; }
+ };
+ 
+ NS_DEFINE_STATIC_IID_ACCESSOR(CacheFileIOListener, CACHEFILEIOLISTENER_IID)
+ 
+ 
+-class CacheFileIOManager : public nsITimerCallback
+-                         , public nsINamed
++class CacheFileIOManager final
++  : public nsITimerCallback
++  , public nsINamed
+ {
+ public:
+   NS_DECL_THREADSAFE_ISUPPORTS
+   NS_DECL_NSITIMERCALLBACK
+   NS_DECL_NSINAMED
+ 
+   enum {
+     OPEN         =  0U,
+diff --git a/netwerk/cache2/CacheFileMetadata.h b/netwerk/cache2/CacheFileMetadata.h
+--- a/netwerk/cache2/CacheFileMetadata.h
++++ b/netwerk/cache2/CacheFileMetadata.h
+@@ -118,18 +118,19 @@ public:
+   NS_IMETHOD OnMetadataWritten(nsresult aResult) = 0;
+   virtual bool IsKilled() = 0;
+ };
+ 
+ NS_DEFINE_STATIC_IID_ACCESSOR(CacheFileMetadataListener,
+                               CACHEFILEMETADATALISTENER_IID)
+ 
+ 
+-class CacheFileMetadata : public CacheFileIOListener
+-                        , public CacheMemoryConsumer
++class CacheFileMetadata final
++  : public CacheFileIOListener
++  , public CacheMemoryConsumer
+ {
+ public:
+   NS_DECL_THREADSAFE_ISUPPORTS
+ 
+   CacheFileMetadata(CacheFileHandle *aHandle,
+                     const nsACString &aKey);
+   CacheFileMetadata(bool aMemoryOnly,
+                     bool aPinned,
+diff --git a/netwerk/cache2/CacheIOThread.h b/netwerk/cache2/CacheIOThread.h
+--- a/netwerk/cache2/CacheIOThread.h
++++ b/netwerk/cache2/CacheIOThread.h
+@@ -23,17 +23,17 @@ namespace net {
+ namespace detail {
+ // A class keeping platform specific information needed to watch and
+ // cancel any long blocking synchronous IO.  Must be predeclared here
+ // since including windows.h breaks stuff with number of macro definition
+ // conflicts.
+ class BlockingIOWatcher;
+ }
+ 
+-class CacheIOThread : public nsIThreadObserver
++class CacheIOThread final : public nsIThreadObserver
+ {
+   virtual ~CacheIOThread();
+ 
+ public:
+   NS_DECL_THREADSAFE_ISUPPORTS
+   NS_DECL_NSITHREADOBSERVER
+ 
+   CacheIOThread();
+diff --git a/netwerk/cache2/CacheIndex.cpp b/netwerk/cache2/CacheIndex.cpp
+--- a/netwerk/cache2/CacheIndex.cpp
++++ b/netwerk/cache2/CacheIndex.cpp
+@@ -165,17 +165,17 @@ private:
+   RefPtr<CacheIndex> mIndex;
+   RefPtr<CacheIndexRecordWrapper> mOldRecord;
+   uint32_t mOldFrecency{0};
+   bool mDoNotSearchInIndex{false};
+   bool mDoNotSearchInUpdates{false};
+   const StaticMutexAutoLock& mProofOfLock;
+ };
+ 
+-class FileOpenHelper : public CacheFileIOListener
++class FileOpenHelper final : public CacheFileIOListener
+ {
+ public:
+   NS_DECL_THREADSAFE_ISUPPORTS
+ 
+   explicit FileOpenHelper(CacheIndex* aIndex)
+     : mIndex(aIndex)
+     , mCanceled(false)
+   {}
+diff --git a/netwerk/cache2/CacheIndex.h b/netwerk/cache2/CacheIndex.h
+--- a/netwerk/cache2/CacheIndex.h
++++ b/netwerk/cache2/CacheIndex.h
+@@ -676,18 +676,19 @@ private:
+   // information is not correct.
+   bool     mStateLogged;
+ 
+   // Disables logging in this instance of CacheIndexStats
+   bool     mDisableLogging;
+ #endif
+ };
+ 
+-class CacheIndex : public CacheFileIOListener
+-                 , public nsIRunnable
++class CacheIndex final
++  : public CacheFileIOListener
++  , public nsIRunnable
+ {
+ public:
+   NS_DECL_THREADSAFE_ISUPPORTS
+   NS_DECL_NSIRUNNABLE
+ 
+   CacheIndex();
+ 
+   static nsresult Init(nsIFile *aCacheDirectory);
+diff --git a/netwerk/cookie/nsCookie.h b/netwerk/cookie/nsCookie.h
+--- a/netwerk/cookie/nsCookie.h
++++ b/netwerk/cookie/nsCookie.h
+@@ -22,17 +22,17 @@ using mozilla::OriginAttributes;
+  * for xpcom access of cookie objects.
+  */
+ 
+ /******************************************************************************
+  * nsCookie:
+  * implementation
+  ******************************************************************************/
+ 
+-class nsCookie : public nsICookie2
++class nsCookie final : public nsICookie2
+ {
+   public:
+     // nsISupports
+     NS_DECL_ISUPPORTS
+     NS_DECL_NSICOOKIE
+     NS_DECL_NSICOOKIE2
+ 
+   private:
+diff --git a/netwerk/protocol/http/AlternateServices.h b/netwerk/protocol/http/AlternateServices.h
+--- a/netwerk/protocol/http/AlternateServices.h
++++ b/netwerk/protocol/http/AlternateServices.h
+@@ -137,17 +137,17 @@ public:
+   explicit AltSvcOverride(nsIInterfaceRequestor *aRequestor)
+     : mCallbacks(aRequestor) {}
+ 
+ private:
+   virtual ~AltSvcOverride() {}
+   nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
+ };
+ 
+-class TransactionObserver : public nsIStreamListener
++class TransactionObserver final : public nsIStreamListener
+ {
+ public:
+   NS_DECL_THREADSAFE_ISUPPORTS
+   NS_DECL_NSISTREAMLISTENER
+   NS_DECL_NSIREQUESTOBSERVER
+ 
+   TransactionObserver(nsHttpChannel *channel, WellKnownChecker *checker);
+   void Complete(nsHttpTransaction *, nsresult);
+diff --git a/netwerk/protocol/http/nsHttpConnectionInfo.h b/netwerk/protocol/http/nsHttpConnectionInfo.h
+--- a/netwerk/protocol/http/nsHttpConnectionInfo.h
++++ b/netwerk/protocol/http/nsHttpConnectionInfo.h
+@@ -27,17 +27,17 @@
+ // however, proxy conenctions made with http/2 (or spdy) can tunnel to the origin
+ // and multiplex non tunneled transactions at the same time, so they have a
+ // special wildcard CI that accepts all origins through that proxy.
+ 
+ namespace mozilla { namespace net {
+ 
+ extern LazyLogModule gHttpLog;
+ 
+-class nsHttpConnectionInfo: public ARefBase
++class nsHttpConnectionInfo final : public ARefBase
+ {
+ public:
+     nsHttpConnectionInfo(const nsACString &originHost,
+                          int32_t originPort,
+                          const nsACString &npnToken,
+                          const nsACString &username,
+                          nsProxyInfo *proxyInfo,
+                          const OriginAttributes &originAttributes,
+diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.h b/netwerk/protocol/http/nsHttpConnectionMgr.h
+--- a/netwerk/protocol/http/nsHttpConnectionMgr.h
++++ b/netwerk/protocol/http/nsHttpConnectionMgr.h
+@@ -500,17 +500,17 @@ private:
+         RefPtr<nsConnectionEntry>      mEnt;
+         nsCOMPtr<nsITimer>             mSynTimer;
+         nsCOMPtr<nsISocketTransport>   mBackupTransport;
+         nsCOMPtr<nsIAsyncOutputStream> mBackupStreamOut;
+         nsCOMPtr<nsIAsyncInputStream>  mBackupStreamIn;
+     };
+     friend class nsHalfOpenSocket;
+ 
+-    class PendingTransactionInfo : public ARefBase
++    class PendingTransactionInfo final : public ARefBase
+     {
+     public:
+         explicit PendingTransactionInfo(nsHttpTransaction * trans)
+             : mTransaction(trans)
+         {}
+ 
+         NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PendingTransactionInfo, override)
+ 
+diff --git a/netwerk/protocol/res/ExtensionProtocolHandler.cpp b/netwerk/protocol/res/ExtensionProtocolHandler.cpp
+--- a/netwerk/protocol/res/ExtensionProtocolHandler.cpp
++++ b/netwerk/protocol/res/ExtensionProtocolHandler.cpp
+@@ -132,17 +132,17 @@ class ExtensionStreamGetter : public Ref
+     nsCOMPtr<nsIJARChannel> mJarChannel;
+     nsCOMPtr<nsIFile> mJarFile;
+     nsCOMPtr<nsIStreamListener> mListener;
+     nsCOMPtr<nsIChannel> mChannel;
+     nsCOMPtr<nsISerialEventTarget> mMainThreadEventTarget;
+     bool mIsJarChannel;
+ };
+ 
+-class ExtensionJARFileOpener : public nsISupports
++class ExtensionJARFileOpener final : public nsISupports
+ {
+ public:
+   ExtensionJARFileOpener(nsIFile* aFile,
+                          NeckoParent::GetExtensionFDResolver& aResolve) :
+     mFile(aFile),
+     mResolve(aResolve)
+   {
+     MOZ_ASSERT(aFile);
+diff --git a/netwerk/test/TestCommon.h b/netwerk/test/TestCommon.h
+--- a/netwerk/test/TestCommon.h
++++ b/netwerk/test/TestCommon.h
+@@ -6,17 +6,17 @@
+ #define TestCommon_h__
+ 
+ #include <stdlib.h>
+ #include "nsThreadUtils.h"
+ #include "mozilla/Attributes.h"
+ 
+ //-----------------------------------------------------------------------------
+ 
+-class WaitForCondition : public nsIRunnable
++class WaitForCondition final : public nsIRunnable
+ {
+ public:
+   NS_DECL_THREADSAFE_ISUPPORTS
+ 
+   void Wait(int pending)
+   {
+     MOZ_ASSERT(NS_IsMainThread());
+     MOZ_ASSERT(mPending == 0);

+ 1699 - 0
mozilla-release/patches/1447931-62a1.patch

@@ -0,0 +1,1699 @@
+# HG changeset patch
+# User Tarek Ziadé <tarek@mozilla.com>
+# Date 1528834970 25200
+# Node ID 1d8ffa02b2af02b23a34f426466a8f26395ac0d2
+# Parent  23ab9d4fe794988e9b1d85472daca3c1b796b633
+Bug 1447931 - NetworkActivity becomes IOActivity - r=baku,mak,valentin
+
+Generalizes NetworkActivity so it can be used for sockets but also disk files.
+The host/port data becomes a single location string prefixed with socket://
+or file:// and we're not using the FD as the identifier anymore.
+
+IOActivityMonitor is now used in three places:
+
+- nsFileStreams for plain files
+- TelemetryVFS for sqlite files
+- nsSocketTransport & nsUDPSocket for UDP & TCP sockets
+
+MozReview-Commit-ID: GNu5o400PaV
+
+diff --git a/dom/tests/browser/dummy.html b/dom/tests/browser/dummy.html
+--- a/dom/tests/browser/dummy.html
++++ b/dom/tests/browser/dummy.html
+@@ -1,9 +1,13 @@
++<!doctype html>
+ <html>
+ <head>
+ <title>Dummy test page</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
+ </head>
+ <body>
+ <p>Dummy test page</p>
++<script>
++  localStorage.setItem("foo", "bar");
++</script>
+ </body>
+ </html>
+diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
+--- a/modules/libpref/init/all.js
++++ b/modules/libpref/init/all.js
+@@ -5412,21 +5412,23 @@ pref("memory.dump_reports_on_oom", false
+ 
+ // Number of stack frames to capture in createObjectURL for about:memory.
+ pref("memory.blob_report.stack_frames", 0);
+ 
+ // Disable idle observer fuzz, because only privileged content can access idle
+ // observers (bug 780507).
+ pref("dom.idle-observers-api.fuzz_time.disabled", true);
+ 
+-// Minimum delay in milliseconds between network activity notifications (0 means
+-// no notifications). The delay is the same for both download and upload, though
++// Minimum delay in milliseconds between I/O activity notifications (0 means
++// no notifications). I/O activity includes socket and disk files.
++//
++// The delay is the same for both read and write, though
+ // they are handled separately. This pref is only read once at startup:
+ // a restart is required to enable a new value.
+-pref("network.activity.intervalMilliseconds", 0);
++pref("io.activity.intervalMilliseconds", 0);
+ 
+ // If true, reuse the same global for (almost) everything loaded by the component
+ // loader (JS components, JSMs, etc). This saves memory, but makes it possible
+ // for the scripts to interfere with each other.  A restart is required for this
+ // to take effect.
+ pref("jsloader.shareGlobal", false);
+ 
+ // When we're asked to take a screenshot, don't wait more than 2000ms for the
+diff --git a/netwerk/base/NetworkActivityMonitor.cpp b/netwerk/base/IOActivityMonitor.cpp
+rename from netwerk/base/NetworkActivityMonitor.cpp
+rename to netwerk/base/IOActivityMonitor.cpp
+--- a/netwerk/base/NetworkActivityMonitor.cpp
++++ b/netwerk/base/IOActivityMonitor.cpp
+@@ -1,369 +1,444 @@
+ /* -*- 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/. */
+-#include "NetworkActivityMonitor.h"
++#include "IOActivityMonitor.h"
+ #include "nsIObserverService.h"
+ #include "nsPISocketTransportService.h"
+ #include "nsPrintfCString.h"
+ #include "nsSocketTransport2.h"
+ #include "nsSocketTransportService2.h"
+ #include "nsThreadUtils.h"
+ #include "mozilla/Services.h"
+ #include "prerror.h"
+ #include "prio.h"
+ #include "prmem.h"
+ #include <vector>
+ 
+-
+ using namespace mozilla::net;
+ 
+-
+-struct SocketActivity {
+-    PROsfd fd;
+-    uint32_t port;
+-    nsString host;
+-    uint32_t rx;
+-    uint32_t tx;
+-};
+-
+-mozilla::StaticRefPtr<NetworkActivityMonitor> gInstance;
++mozilla::StaticRefPtr<IOActivityMonitor> gInstance;
+ static PRDescIdentity sNetActivityMonitorLayerIdentity;
+ static PRIOMethods sNetActivityMonitorLayerMethods;
+ static PRIOMethods *sNetActivityMonitorLayerMethodsPtr = nullptr;
+ 
++// Maximum number of activities entries in the monitoring class
++#define MAX_ACTIVITY_ENTRIES 1000
++
++
++// ActivityMonitorSecret is stored in the activity monitor layer
++// and provides a method to get the location.
++//
++// A location can be :
++// - a TCP or UDP socket. The form will be socket://ip:port
++// - a File. The form will be file://path
++//
++// For other cases, the location will be fd://number
++class ActivityMonitorSecret final
++{
++public:
++  // constructor used for sockets
++  explicit ActivityMonitorSecret(PRFileDesc* aFd) {
++    mFd = aFd;
++    mLocationSet = false;
++  }
++
++  // constructor used for files
++  explicit ActivityMonitorSecret(PRFileDesc* aFd, const char* aLocation) {
++    mFd = aFd;
++    mLocation.AppendPrintf("file://%s", aLocation);
++    mLocationSet = true;
++  }
++
++  nsCString getLocation() {
++    if (!mLocationSet) {
++      LazySetLocation();
++    }
++    return mLocation;
++  }
++private:
++  // Called to set the location using the FD on the first getLocation() usage
++  // which is typically when a socket is opened. If done earlier, at
++  // construction time, the host won't be bound yet.
++  //
++  // If the location is a file, it needs to be initialized in the
++  // constructor.
++  void LazySetLocation() {
++    mLocationSet = true;
++    PRFileDesc* extract = mFd;
++    while (PR_GetDescType(extract) == PR_DESC_LAYERED) {
++      if (!extract->lower) {
++        break;
++      }
++      extract = extract->lower;
++    }
++
++    PRDescType fdType = PR_GetDescType(extract);
++    // we should not use LazySetLocation for files
++    MOZ_ASSERT(fdType != PR_DESC_FILE);
++
++    switch (fdType) {
++      case PR_DESC_SOCKET_TCP:
++      case PR_DESC_SOCKET_UDP: {
++        mLocation.AppendPrintf("socket://");
++        PRNetAddr addr;
++        PRStatus status = PR_GetSockName(mFd, &addr);
++        if (NS_WARN_IF(status == PR_FAILURE)) {
++          mLocation.AppendPrintf("unknown");
++          break;
++        }
++
++        // grabbing the host
++        char netAddr[mozilla::net::kNetAddrMaxCStrBufSize] = {0};
++        status = PR_NetAddrToString(&addr, netAddr, sizeof(netAddr) - 1);
++        if (NS_WARN_IF(status == PR_FAILURE) || netAddr[0] == 0) {
++          mLocation.AppendPrintf("unknown");
++          break;
++        }
++        mLocation.Append(netAddr);
++
++        // adding the port
++        uint16_t port;
++        if (addr.raw.family == PR_AF_INET) {
++          port = addr.inet.port;
++        } else {
++          port = addr.ipv6.port;
++        }
++        mLocation.AppendPrintf(":%d", port);
++      } break;
++
++      // for all other cases, we just send back fd://<value>
++      default: {
++        mLocation.AppendPrintf("fd://%d", PR_FileDesc2NativeHandle(mFd));
++      }
++    } // end switch
++  }
++private:
++  nsCString mLocation;
++  bool mLocationSet;
++  PRFileDesc* mFd;
++};
++
++// FileDesc2Location converts a PRFileDesc into a "location" by
++// grabbing the ActivityMonitorSecret in layer->secret
++static nsAutoCString
++FileDesc2Location(PRFileDesc *fd)
++{
++  nsAutoCString location;
++  PRFileDesc *monitorLayer = PR_GetIdentitiesLayer(fd, sNetActivityMonitorLayerIdentity);
++  if (!monitorLayer) {
++    location.AppendPrintf("unknown");
++    return location;
++  }
++
++  ActivityMonitorSecret* secret = (ActivityMonitorSecret*)monitorLayer->secret;
++  location.AppendPrintf("%s", secret->getLocation().get());
++  return location;
++}
++
++//
++// Wrappers around the socket APIS
++//
+ static PRStatus
+ nsNetMon_Connect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
+ {
+-  PRStatus ret;
+-  PRErrorCode code;
+-  ret = fd->lower->methods->connect(fd->lower, addr, timeout);
+-  if (ret == PR_SUCCESS || (code = PR_GetError()) == PR_WOULD_BLOCK_ERROR ||
+-      code == PR_IN_PROGRESS_ERROR) {
+-      NetworkActivityMonitor::RegisterFd(fd, addr);
+-      NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, 0);
+-  }
+-  return ret;
++  return fd->lower->methods->connect(fd->lower, addr, timeout);
+ }
+ 
+ 
+ static PRStatus
+ nsNetMon_Close(PRFileDesc *fd)
+ {
+   if (!fd) {
+     return PR_FAILURE;
+   }
+-  NetworkActivityMonitor::UnregisterFd(fd);
+   PRFileDesc* layer = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
+   MOZ_RELEASE_ASSERT(layer &&
+                      layer->identity == sNetActivityMonitorLayerIdentity,
+                      "NetActivityMonitor Layer not on top of stack");
++
++  if (layer->secret) {
++    delete (ActivityMonitorSecret *)layer->secret;
++    layer->secret = nullptr;
++  }
+   layer->dtor(layer);
+   return fd->methods->close(fd);
+ }
+ 
+ 
+ static int32_t
+ nsNetMon_Read(PRFileDesc *fd, void *buf, int32_t len)
+ {
+-  int32_t ret;
+-  ret = fd->lower->methods->read(fd->lower, buf, len);
++  int32_t ret = fd->lower->methods->read(fd->lower, buf, len);
+   if (ret >= 0) {
+-    NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, fd, len);
++    IOActivityMonitor::Read(fd, len);
+   }
+   return ret;
+ }
+ 
+ static int32_t
+ nsNetMon_Write(PRFileDesc *fd, const void *buf, int32_t len)
+ {
+-  int32_t ret;
+-  ret = fd->lower->methods->write(fd->lower, buf, len);
++  int32_t ret = fd->lower->methods->write(fd->lower, buf, len);
+   if (ret > 0) {
+-    NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, len);
++    IOActivityMonitor::Write(fd, len);
+   }
+   return ret;
+ }
+ 
+ static int32_t
+ nsNetMon_Writev(PRFileDesc *fd,
+                 const PRIOVec *iov,
+                 int32_t size,
+                 PRIntervalTime timeout)
+ {
+-  int32_t ret;
+-  ret = fd->lower->methods->writev(fd->lower, iov, size, timeout);
++  int32_t ret = fd->lower->methods->writev(fd->lower, iov, size, timeout);
+   if (ret > 0) {
+-    NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, size);
++    IOActivityMonitor::Write(fd, size);
+   }
+   return ret;
+ }
+ 
+ static int32_t
+ nsNetMon_Recv(PRFileDesc *fd,
+               void *buf,
+               int32_t amount,
+               int flags,
+               PRIntervalTime timeout)
+ {
+-  int32_t ret;
+-  ret = fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout);
+-  if (ret >= 0) {
+-    NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, fd, amount);
++  int32_t ret = fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout);
++  if (ret > 0) {
++    IOActivityMonitor::Read(fd, amount);
+   }
+   return ret;
+ }
+ 
+ static int32_t
+ nsNetMon_Send(PRFileDesc *fd,
+               const void *buf,
+               int32_t amount,
+               int flags,
+               PRIntervalTime timeout)
+ {
+-  int32_t ret;
+-  ret = fd->lower->methods->send(fd->lower, buf, amount, flags, timeout);
++  int32_t ret = fd->lower->methods->send(fd->lower, buf, amount, flags, timeout);
+   if (ret > 0) {
+-    NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, amount);
++    IOActivityMonitor::Write(fd, amount);
+   }
+   return ret;
+ }
+ 
+ static int32_t
+ nsNetMon_RecvFrom(PRFileDesc *fd,
+                   void *buf,
+                   int32_t amount,
+                   int flags,
+                   PRNetAddr *addr,
+                   PRIntervalTime timeout)
+ {
+-  int32_t ret;
+-  ret = fd->lower->methods->recvfrom(fd->lower,
+-                                     buf,
+-                                     amount,
+-                                     flags,
+-                                     addr,
+-                                     timeout);
+-  if (ret >= 0) {
+-    NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, fd, amount);
++  int32_t ret = fd->lower->methods->recvfrom(fd->lower, buf, amount, flags,
++                                             addr, timeout);
++  if (ret > 0) {
++    IOActivityMonitor::Read(fd, amount);
+   }
+   return ret;
+ }
+ 
+ static int32_t
+ nsNetMon_SendTo(PRFileDesc *fd,
+                 const void *buf,
+                 int32_t amount,
+                 int flags,
+                 const PRNetAddr *addr,
+                 PRIntervalTime timeout)
+ {
+-  int32_t ret;
+-  ret = fd->lower->methods->sendto(fd->lower,
+-                                   buf,
+-                                   amount,
+-                                   flags,
+-                                   addr,
+-                                   timeout);
++  int32_t ret = fd->lower->methods->sendto(fd->lower, buf, amount, flags,
++                                           addr, timeout);
+   if (ret > 0) {
+-    NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, amount);
++    IOActivityMonitor::Write(fd, amount);
+   }
+   return ret;
+ }
+ 
+ static int32_t
+ nsNetMon_AcceptRead(PRFileDesc *listenSock,
+                     PRFileDesc **acceptedSock,
+                     PRNetAddr **peerAddr,
+                     void *buf,
+                     int32_t amount,
+                     PRIntervalTime timeout)
+ {
+-  int32_t ret;
+-  ret = listenSock->lower->methods->acceptread(listenSock->lower,
+-                                               acceptedSock,
+-                                               peerAddr,
+-                                               buf,
+-                                               amount,
+-                                               timeout);
++  int32_t ret = listenSock->lower->methods->acceptread(listenSock->lower, acceptedSock,
++                                                       peerAddr, buf, amount, timeout);
+   if (ret > 0) {
+-    NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, listenSock, amount);
++    IOActivityMonitor::Read(listenSock, amount);
+   }
+   return ret;
+ }
+ 
+ 
+-NS_IMPL_ISUPPORTS(NetworkData, nsINetworkActivityData);
++//
++// Class IOActivityData
++//
++NS_IMPL_ISUPPORTS(IOActivityData, nsIIOActivityData);
+ 
+ NS_IMETHODIMP
+-NetworkData::GetHost(nsAString& aHost) {
+-  aHost = mHost;
++IOActivityData::GetLocation(nsACString& aLocation) {
++  aLocation = mActivity.location;
+   return NS_OK;
+ };
+ 
+ NS_IMETHODIMP
+-NetworkData::GetPort(int32_t* aPort) {
+-  *aPort = mPort;
+-  return NS_OK;
+-};
+-
+-NS_IMETHODIMP
+-NetworkData::GetRx(int32_t* aRx) {
+-  *aRx = mRx;
+-  return NS_OK;
+-};
+-
+-NS_IMETHODIMP
+-NetworkData::GetTx(int32_t* aTx) {
+-  *aTx = mTx;
++IOActivityData::GetRx(int32_t* aRx) {
++  *aRx = mActivity.rx;
+   return NS_OK;
+ };
+ 
+ NS_IMETHODIMP
+-NetworkData::GetFd(int32_t* aFd) {
+-  *aFd = mFd;
++IOActivityData::GetTx(int32_t* aTx) {
++  *aTx = mActivity.tx;
+   return NS_OK;
+ };
+ 
+-class NotifyNetworkActivity : public mozilla::Runnable {
++//
++// 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:
+-  explicit NotifyNetworkActivity(NetworkActivity* aActivity)
+-    : mozilla::Runnable("NotifyNetworkActivity")
+-
++  static already_AddRefed<nsIRunnable>
++  Create(Activities& aActivities, const mozilla::MutexAutoLock& aProofOfLock)
+   {
+-    uint32_t rx;
+-    uint32_t tx;
+-    PROsfd fd;
+-    for (auto iter = aActivity->rx.Iter(); !iter.Done(); iter.Next()) {
+-      rx = iter.Data();
+-      fd = iter.Key();
+-      tx = aActivity->tx.Get(fd);
+-      if (rx == 0 && tx == 0) {
+-        // nothing to do
+-      } else {
+-        SocketActivity activity;
+-        activity.fd = fd;
+-        activity.rx = rx;
+-        activity.tx = tx;
+-        activity.host = aActivity->host.Get(fd);
+-        activity.port = aActivity->port.Get(fd);
+-        mActivities.AppendElement(activity);
++    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<nsINetworkActivityData> data =
+-        new NetworkData(mActivities[i].host,
+-                        mActivities[i].port,
+-                        mActivities[i].fd,
+-                        mActivities[i].rx,
+-                        mActivities[i].tx);
+-
++      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_NETWORK_ACTIVITY, nullptr);
++    obs->NotifyObservers(array, NS_IO_ACTIVITY, nullptr);
+     return NS_OK;
+   }
++
+ private:
+-  nsTArray<SocketActivity> mActivities;
++  explicit NotifyIOActivity()
++    : mozilla::Runnable("NotifyIOActivity")
++  {
++  }
++
++  FallibleTArray<IOActivity> mActivities;
+ };
+ 
+ 
+-NS_IMPL_ISUPPORTS(NetworkActivityMonitor, nsITimerCallback, nsINamed)
++//
++// Class IOActivityMonitor
++//
++NS_IMPL_ISUPPORTS(IOActivityMonitor, nsITimerCallback, nsINamed)
+ 
+-NetworkActivityMonitor::NetworkActivityMonitor()
++IOActivityMonitor::IOActivityMonitor()
+   : mInterval(PR_INTERVAL_NO_TIMEOUT)
+-  , mLock("NetworkActivityMonitor::mLock")
++  , mLock("IOActivityMonitor::mLock")
+ {
+-  RefPtr<NetworkActivityMonitor> mon(gInstance);
+-  MOZ_ASSERT(!mon, "multiple NetworkActivityMonitor instances!");
++  RefPtr<IOActivityMonitor> mon(gInstance);
++  MOZ_ASSERT(!mon, "multiple IOActivityMonitor instances!");
+ }
+ 
+ NS_IMETHODIMP
+-NetworkActivityMonitor::Notify(nsITimer* aTimer)
++IOActivityMonitor::Notify(nsITimer* aTimer)
+ {
+   mozilla::MutexAutoLock lock(mLock);
+-  nsCOMPtr<nsIRunnable> ev = new NotifyNetworkActivity(&mActivity);
+-  NS_DispatchToMainThread(ev);
+-  // reset the counters
+-  for (auto iter = mActivity.host.Iter(); !iter.Done(); iter.Next()) {
+-      uint32_t fd = iter.Key();
+-      mActivity.tx.Put(fd, 0);
+-      mActivity.rx.Put(fd, 0);
++  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();
++    }
+   }
+   return NS_OK;
+ }
+ 
++// static
+ NS_IMETHODIMP
+-NetworkActivityMonitor::GetName(nsACString& aName)
++IOActivityMonitor::GetName(nsACString& aName)
+ {
+-  aName.AssignLiteral("NetworkActivityMonitor");
++  aName.AssignLiteral("IOActivityMonitor");
+   return NS_OK;
+ }
+ 
++bool
++IOActivityMonitor::IsActive()
++{
++  return gInstance != nullptr;
++}
+ 
+ nsresult
+-NetworkActivityMonitor::Init(int32_t aInterval)
++IOActivityMonitor::Init(int32_t aInterval)
+ {
+-  nsresult rv = NS_OK;
+-  RefPtr<NetworkActivityMonitor> mon(gInstance);
+-  if (mon) {
++  if (IsActive()) {
+     return NS_ERROR_ALREADY_INITIALIZED;
+   }
+-  mon = new NetworkActivityMonitor();
+-  rv = mon->Init_Internal(aInterval);
++  RefPtr<IOActivityMonitor> mon = new IOActivityMonitor();
++  nsresult rv = mon->Init_Internal(aInterval);
+   if (NS_SUCCEEDED(rv)) {
+     gInstance = mon;
+-  } else {
+-    rv = NS_ERROR_FAILURE;
+   }
+   return rv;
+ }
+ 
+ nsresult
+-NetworkActivityMonitor::Shutdown()
++IOActivityMonitor::Init_Internal(int32_t aInterval)
+ {
+-  RefPtr<NetworkActivityMonitor> mon(gInstance);
+-  if (!mon) {
+-    return NS_ERROR_NOT_INITIALIZED;
+-  }
+-  mon->Shutdown_Internal();
+-  gInstance = nullptr;
+-  return NS_OK;
+-}
+-
+-nsresult
+-NetworkActivityMonitor::Init_Internal(int32_t aInterval)
+-{
++  // wraps the socket APIs
+   if (!sNetActivityMonitorLayerMethodsPtr) {
+     sNetActivityMonitorLayerIdentity =
+       PR_GetUniqueIdentity("network activity monitor layer");
+     sNetActivityMonitorLayerMethods  = *PR_GetDefaultIOMethods();
+     sNetActivityMonitorLayerMethods.connect    = nsNetMon_Connect;
+     sNetActivityMonitorLayerMethods.read       = nsNetMon_Read;
+     sNetActivityMonitorLayerMethods.write      = nsNetMon_Write;
+     sNetActivityMonitorLayerMethods.writev     = nsNetMon_Writev;
+@@ -381,133 +456,168 @@ NetworkActivityMonitor::Init_Internal(in
+   mTimer = NS_NewTimer();
+   if (!mTimer) {
+     return NS_ERROR_FAILURE;
+   }
+   return mTimer->InitWithCallback(this, mInterval, nsITimer::TYPE_REPEATING_SLACK);
+ }
+ 
+ nsresult
+-NetworkActivityMonitor::Shutdown_Internal()
++IOActivityMonitor::Shutdown()
+ {
++  RefPtr<IOActivityMonitor> mon(gInstance);
++  if (!mon) {
++    return NS_ERROR_NOT_INITIALIZED;
++  }
++  return mon->Shutdown_Internal();
++}
++
++nsresult
++IOActivityMonitor::Shutdown_Internal()
++{
++  mozilla::MutexAutoLock lock(mLock);
+   mTimer->Cancel();
++  mActivities.Clear();
++  gInstance = nullptr;
+   return NS_OK;
+ }
+ 
+ nsresult
+-NetworkActivityMonitor::AttachIOLayer(PRFileDesc *fd)
++IOActivityMonitor::MonitorSocket(PRFileDesc *aFd)
+ {
+-  RefPtr<NetworkActivityMonitor> mon(gInstance);
+-  if (!mon) {
++  RefPtr<IOActivityMonitor> mon(gInstance);
++  if (!IsActive()) {
++    return NS_OK;
++  }
++  PRFileDesc* layer;
++  PRStatus status;
++  layer = PR_CreateIOLayerStub(sNetActivityMonitorLayerIdentity,
++                               sNetActivityMonitorLayerMethodsPtr);
++  if (!layer) {
++    return NS_ERROR_FAILURE;
++  }
++
++  ActivityMonitorSecret* secret = new ActivityMonitorSecret(aFd);
++  layer->secret = reinterpret_cast<PRFilePrivate *>(secret);
++  status = PR_PushIOLayer(aFd, PR_NSPR_IO_LAYER, layer);
++
++  if (status == PR_FAILURE) {
++    delete secret;
++    PR_Free(layer); // PR_CreateIOLayerStub() uses PR_Malloc().
++    return NS_ERROR_FAILURE;
++  }
++  return NS_OK;
++}
++
++nsresult
++IOActivityMonitor::MonitorFile(PRFileDesc *aFd, const char* aPath)
++{
++  RefPtr<IOActivityMonitor> mon(gInstance);
++  if (!IsActive()) {
+     return NS_OK;
+   }
+   PRFileDesc* layer;
+   PRStatus status;
+   layer = PR_CreateIOLayerStub(sNetActivityMonitorLayerIdentity,
+                                sNetActivityMonitorLayerMethodsPtr);
+   if (!layer) {
+     return NS_ERROR_FAILURE;
+   }
+ 
+-  status = PR_PushIOLayer(fd, PR_NSPR_IO_LAYER, layer);
++  ActivityMonitorSecret* secret = new ActivityMonitorSecret(aFd, aPath);
++  layer->secret = reinterpret_cast<PRFilePrivate *>(secret);
+ 
++  status = PR_PushIOLayer(aFd, PR_NSPR_IO_LAYER, layer);
+   if (status == PR_FAILURE) {
++    delete secret;
+     PR_Free(layer); // PR_CreateIOLayerStub() uses PR_Malloc().
+     return NS_ERROR_FAILURE;
+   }
++
++  return NS_OK;
++}
++
++IOActivity*
++IOActivityMonitor::GetActivity(const nsACString& aLocation)
++{
++  mLock.AssertCurrentThreadOwns();
++  if (auto entry = mActivities.Lookup(aLocation)) {
++    // already registered
++    return entry.Data();
++  }
++  // 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);
++  if (NS_WARN_IF(!mActivities.Put(aLocation, activity, fallible))) {
++    delete activity;
++    return nullptr;
++  }
++  return activity;
++}
++
++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);
++}
++
++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)
++{
++  mozilla::MutexAutoLock lock(mLock);
++  IOActivity* activity = GetActivity(aLocation);
++  if (!activity) {
++    return NS_ERROR_FAILURE;
++  }
++  activity->tx += aAmount;
+   return NS_OK;
+ }
+ 
+ nsresult
+-NetworkActivityMonitor::RegisterFd(PRFileDesc *aFd, const PRNetAddr *aAddr) {
+-  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
+-  RefPtr<NetworkActivityMonitor> mon(gInstance);
++IOActivityMonitor::Read(PRFileDesc *fd, uint32_t aAmount)
++{
++  RefPtr<IOActivityMonitor> mon(gInstance);
+   if (!mon) {
+     return NS_ERROR_FAILURE;
+   }
+-
+-  PROsfd osfd = PR_FileDesc2NativeHandle(aFd);
+-  if (NS_WARN_IF(osfd == -1)) {
+-    return ErrorAccordingToNSPR(PR_GetError());
+-  }
+-  uint16_t port;
+-  if (aAddr->raw.family == PR_AF_INET) {
+-    port = aAddr->inet.port;
+-  } else {
+-    port = aAddr->ipv6.port;
+-  }
+-  char _host[net::kNetAddrMaxCStrBufSize] = {0};
+-  nsAutoCString host;
+-  if (PR_NetAddrToString(aAddr, _host, sizeof(_host) - 1) == PR_SUCCESS) {
+-    host.Assign(_host);
+-  } else {
+-    host.AppendPrintf("N/A");
+-  }
+-  return mon->RegisterFd_Internal(osfd, NS_ConvertUTF8toUTF16(host), port);
+-}
+-
+-nsresult
+-NetworkActivityMonitor::UnregisterFd(PRFileDesc *aFd)
+-{
+-  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
+-  RefPtr<NetworkActivityMonitor> mon(gInstance);
+-  if (!mon) {
+-    return NS_ERROR_FAILURE;
+-  }
+-  PROsfd osfd = PR_FileDesc2NativeHandle(aFd);
+-  if (NS_WARN_IF(osfd == -1)) {
+-    return ErrorAccordingToNSPR(PR_GetError());
+-  }
+-  return mon->UnregisterFd_Internal(osfd);
++  return mon->Read(FileDesc2Location(fd), aAmount);
+ }
+ 
+ nsresult
+-NetworkActivityMonitor::UnregisterFd_Internal(PROsfd aOsfd)
++IOActivityMonitor::Read(const nsACString& aLocation, uint32_t aAmount)
+ {
+-  mozilla::MutexAutoLock lock(mLock);
+-  // XXX indefinitely growing list
+-  mActivity.active.Put(aOsfd, false);
+-  return NS_OK;
+-}
+-
+-
+-nsresult
+-NetworkActivityMonitor::RegisterFd_Internal(PROsfd aOsfd, const nsString& host, uint16_t port)
+-{
+-  mozilla::MutexAutoLock lock(mLock);
+-  mActivity.port.Put(aOsfd, port);
+-  mActivity.host.Put(aOsfd, host);
+-  mActivity.rx.Put(aOsfd, 0);
+-  mActivity.tx.Put(aOsfd, 0);
+-  mActivity.active.Put(aOsfd, true);
+-  return NS_OK;
++  RefPtr<IOActivityMonitor> mon(gInstance);
++  if (!mon) {
++    return NS_ERROR_FAILURE;
++  }
++  return mon->Read_Internal(aLocation, aAmount);
+ }
+ 
+ nsresult
+-NetworkActivityMonitor::DataInOut(Direction aDirection, PRFileDesc *aFd, uint32_t aAmount)
++IOActivityMonitor::Read_Internal(const nsACString& aLocation, uint32_t aAmount)
+ {
+-  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
+-  RefPtr<NetworkActivityMonitor> mon(gInstance);
+-  if (!mon) {
++  mozilla::MutexAutoLock lock(mLock);
++  IOActivity* activity = GetActivity(aLocation);
++  if (!activity) {
+     return NS_ERROR_FAILURE;
+   }
+-  PROsfd osfd = PR_FileDesc2NativeHandle(aFd);
+-  if (NS_WARN_IF(osfd == -1)) {
+-    return ErrorAccordingToNSPR(PR_GetError());
+-  }
+-  return mon->DataInOut_Internal(osfd, aDirection, aAmount);
+-}
+-
+-nsresult
+-NetworkActivityMonitor::DataInOut_Internal(PROsfd aOsfd, Direction aDirection, uint32_t aAmount)
+-{
+-  mozilla::MutexAutoLock lock(mLock);
+-  uint32_t current;
+-  if (aDirection == NetworkActivityMonitor::kUpload) {
+-    current = mActivity.tx.Get(aOsfd);
+-    mActivity.tx.Put(aOsfd, aAmount + current);
+-  }
+-  else {
+-    current = mActivity.rx.Get(aOsfd);
+-    mActivity.rx.Put(aOsfd, aAmount + current);
+-  }
++  activity->rx += aAmount;
+   return NS_OK;
+ }
+diff --git a/netwerk/base/NetworkActivityMonitor.h b/netwerk/base/IOActivityMonitor.h
+rename from netwerk/base/NetworkActivityMonitor.h
+rename to netwerk/base/IOActivityMonitor.h
+--- a/netwerk/base/NetworkActivityMonitor.h
++++ b/netwerk/base/IOActivityMonitor.h
+@@ -1,96 +1,122 @@
+ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+  *
+  * 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 NetworkActivityMonitor_h___
+-#define NetworkActivityMonitor_h___
++#ifndef IOActivityMonitor_h___
++#define IOActivityMonitor_h___
+ 
+ #include "nsCOMPtr.h"
+ #include "nscore.h"
++#include "nsClassHashtable.h"
+ #include "nsDataHashtable.h"
+ #include "nsHashKeys.h"
+-#include "nsINetworkActivityData.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 {
+ 
+-typedef nsDataHashtable<nsUint32HashKey, uint32_t> SocketBytes;
+-typedef nsDataHashtable<nsUint32HashKey, uint32_t> SocketPort;
+-typedef nsDataHashtable<nsUint32HashKey, nsString> SocketHost;
+-typedef nsDataHashtable<nsUint32HashKey, bool> SocketActive;
++//
++// 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;
+ 
+-struct NetworkActivity {
+-    SocketPort port;
+-    SocketHost host;
+-    SocketBytes rx;
+-    SocketBytes tx;
+-    SocketActive active;
++  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 nsClassHashtable<nsCStringHashKey, IOActivity> Activities;
+ 
+-class NetworkData final : public nsINetworkActivityData
++// XPCOM Wrapper for an IOActivity
++class IOActivityData final : public nsIIOActivityData
+ {
+ public:
+   NS_DECL_ISUPPORTS
+-  NS_DECL_NSINETWORKACTIVITYDATA
+-  NetworkData(const nsString& aHost, int32_t aPort, int32_t aFd,
+-              int32_t aRx, int32_t aTx)
+-      : mHost(aHost), mPort(aPort), mFd(aFd), mRx(aRx), mTx(aTx) {}
++  NS_DECL_NSIIOACTIVITYDATA
++  explicit IOActivityData(IOActivity aActivity)
++      : mActivity(aActivity) {}
+ private:
+-  ~NetworkData() = default;
+-
+-  nsString mHost;
+-  int32_t mPort;
+-  int32_t mFd;
+-  int32_t mRx;
+-  int32_t mTx;
++  ~IOActivityData() = default;
++  IOActivity mActivity;
+ };
+ 
+-
+-class NetworkActivityMonitor final
++// 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
++class IOActivityMonitor final
+     : public nsITimerCallback
+     , public nsINamed
+ {
+ public:
+-  enum Direction {
+-    kUpload   = 0,
+-    kDownload = 1
+-  };
+-
+-  NetworkActivityMonitor();
++  IOActivityMonitor();
+ 
+   NS_DECL_THREADSAFE_ISUPPORTS
+   NS_DECL_NSITIMERCALLBACK
+   NS_DECL_NSINAMED
+ 
++  // initializes and destroys the singleton
+   static nsresult Init(int32_t aInterval);
+   static nsresult Shutdown();
+-  static nsresult AttachIOLayer(PRFileDesc *fd);
+-  static nsresult DataInOut(Direction aDirection, PRFileDesc *aFd, uint32_t aAmount);
+-  static nsresult RegisterFd(PRFileDesc *aFd, const PRNetAddr *aAddr);
+-  static nsresult UnregisterFd(PRFileDesc *aFd);
++
++  // 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();
+ private:
+-  virtual ~NetworkActivityMonitor() = default;
++  virtual ~IOActivityMonitor() = default;
+   nsresult Init_Internal(int32_t aInterval);
+   nsresult Shutdown_Internal();
+-  nsresult RegisterFd_Internal(PROsfd aOsfd, const nsString& host, uint16_t port);
+-  nsresult UnregisterFd_Internal(PROsfd aOsfd);
+-  nsresult DataInOut_Internal(PROsfd aOsfd, Direction aDirection, uint32_t aAmount);
+-  uint32_t                        mInterval;
+-  NetworkActivity                 mActivity;
+-  nsCOMPtr<nsITimer>              mTimer;
+-  Mutex                           mLock;
++
++  IOActivity* GetActivity(const nsACString& location);
++  nsresult Write_Internal(const nsACString& location, uint32_t aAmount);
++  nsresult Read_Internal(const nsACString& location, uint32_t aAmount);
++
++  Activities mActivities;
++
++  // timer used to send notifications
++  uint32_t mInterval;
++  nsCOMPtr<nsITimer> mTimer;
++  // protects mActivities accesses
++  Mutex mLock;
+ };
+ 
+ } // namespace net
+ } // namespace mozilla
+ 
+-#endif /* NetworkActivityMonitor_h___ */
++#endif /* IOActivityMonitor_h___ */
+diff --git a/netwerk/base/moz.build b/netwerk/base/moz.build
+--- a/netwerk/base/moz.build
++++ b/netwerk/base/moz.build
+@@ -47,28 +47,28 @@ XPIDL_SOURCES += [
+     'nsIForcePendingChannel.idl',
+     'nsIFormPOSTActionChannel.idl',
+     'nsIHttpAuthenticatorCallback.idl',
+     'nsIHttpPushListener.idl',
+     'nsIIncrementalDownload.idl',
+     'nsIIncrementalStreamLoader.idl',
+     'nsIInputStreamChannel.idl',
+     'nsIInputStreamPump.idl',
++    'nsIIOActivityData.idl',
+     'nsIIOService.idl',
+     'nsIIOService2.idl',
+     'nsILoadContextInfo.idl',
+     'nsILoadGroup.idl',
+     'nsILoadGroupChild.idl',
+     'nsILoadInfo.idl',
+     'nsIMIMEInputStream.idl',
+     'nsIMultiPartChannel.idl',
+     'nsINestedURI.idl',
+     'nsINetAddr.idl',
+     'nsINetUtil.idl',
+-    'nsINetworkActivityData.idl',
+     'nsINetworkInfoService.idl',
+     'nsINetworkInterceptController.idl',
+     'nsINetworkLinkService.idl',
+     'nsINetworkPredictor.idl',
+     'nsINetworkPredictorVerifier.idl',
+     'nsINetworkProperties.idl',
+     'nsINullChannel.idl',
+     'nsIParentChannel.idl',
+@@ -170,16 +170,17 @@ EXPORTS.mozilla += [
+ ]
+ 
+ EXPORTS.mozilla.net += [
+     'CaptivePortalService.h',
+     'ChannelDiverterChild.h',
+     'ChannelDiverterParent.h',
+     'Dashboard.h',
+     'DashboardTypes.h',
++    'IOActivityMonitor.h',
+     'MemoryDownloader.h',
+     'MozURL.h',
+     'PartiallySeekableInputStream.h',
+     'Predictor.h',
+     'ReferrerPolicy.h',
+     'SimpleChannelParent.h',
+     'TCPFastOpen.h',
+ ]
+@@ -187,21 +188,21 @@ EXPORTS.mozilla.net += [
+ UNIFIED_SOURCES += [
+     'ArrayBufferInputStream.cpp',
+     'BackgroundFileSaver.cpp',
+     'CaptivePortalService.cpp',
+     'ChannelDiverterChild.cpp',
+     'ChannelDiverterParent.cpp',
+     'Dashboard.cpp',
+     'EventTokenBucket.cpp',
++    'IOActivityMonitor.cpp',
+     'LoadContextInfo.cpp',
+     'LoadInfo.cpp',
+     'MemoryDownloader.cpp',
+     'MozURL.cpp',
+-    'NetworkActivityMonitor.cpp',
+     'nsAsyncRedirectVerifyHelper.cpp',
+     'nsAsyncStreamCopier.cpp',
+     'nsAuthInformationHolder.cpp',
+     'nsBase64Encoder.cpp',
+     'nsBaseChannel.cpp',
+     'nsBaseContentStream.cpp',
+     'nsBufferedStreams.cpp',
+     'nsChannelClassifier.cpp',
+diff --git a/netwerk/base/nsFileStreams.cpp b/netwerk/base/nsFileStreams.cpp
+--- a/netwerk/base/nsFileStreams.cpp
++++ b/netwerk/base/nsFileStreams.cpp
+@@ -10,30 +10,36 @@
+ #elif defined(XP_WIN)
+ #include <windows.h>
+ #include "nsILocalFileWin.h"
+ #else
+ // XXX add necessary include file for ftruncate (or equivalent)
+ #endif
+ 
+ #include "private/pprio.h"
++#include "prerror.h"
+ 
++#include "IOActivityMonitor.h"
+ #include "nsFileStreams.h"
+ #include "nsIFile.h"
+ #include "nsReadLine.h"
+ #include "nsIClassInfoImpl.h"
++#include "nsLiteralString.h"
++#include "nsSocketTransport2.h"    // for ErrorAccordingToNSPR()
+ #include "mozilla/ipc/InputStreamUtils.h"
+ #include "mozilla/Unused.h"
+ #include "mozilla/FileUtils.h"
+ #include "nsNetCID.h"
+ #include "nsXULAppAPI.h"
+ 
+ typedef mozilla::ipc::FileDescriptor::PlatformHandleType FileHandleType;
+ 
+ using namespace mozilla::ipc;
++using namespace mozilla::net;
++
+ using mozilla::DebugOnly;
+ using mozilla::Maybe;
+ using mozilla::Nothing;
+ using mozilla::Some;
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ // nsFileStreamBase
+ 
+@@ -347,17 +353,32 @@ nsFileStreamBase::DoOpen()
+     } else
+ #endif // XP_WIN
+     {
+       rv = mOpenParams.localFile->OpenNSPRFileDesc(mOpenParams.ioFlags,
+                                                    mOpenParams.perm,
+                                                    &fd);
+     }
+ 
++    if (rv == NS_OK && IOActivityMonitor::IsActive()) {
++      auto nativePath = mOpenParams.localFile->NativePath();
++      if (!nativePath.IsEmpty()) {
++        // registering the file to the activity monitor
++        #ifdef XP_WIN
++        // 16 bits unicode
++        IOActivityMonitor::MonitorFile(fd, NS_ConvertUTF16toUTF8(nativePath.get()).get());
++        #else
++        // 8 bit unicode
++        IOActivityMonitor::MonitorFile(fd, nativePath.get());
++        #endif
++      }
++    }
++
+     CleanUpOpen();
++
+     if (NS_FAILED(rv)) {
+         mState = eError;
+         mErrorValue = rv;
+         return rv;
+     }
+ 
+     mFD = fd;
+     mState = eOpened;
+diff --git a/netwerk/base/nsINetworkActivityData.idl b/netwerk/base/nsIIOActivityData.idl
+rename from netwerk/base/nsINetworkActivityData.idl
+rename to netwerk/base/nsIIOActivityData.idl
+--- a/netwerk/base/nsINetworkActivityData.idl
++++ b/netwerk/base/nsIIOActivityData.idl
+@@ -5,17 +5,15 @@
+ #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 nsINetworkActivityData : nsISupports
++interface nsIIOActivityData : nsISupports
+ {
+-  readonly attribute DOMString host;
+-  readonly attribute long port;
++  readonly attribute AUTF8String location;
+   readonly attribute long rx;
+   readonly attribute long tx;
+-  readonly attribute long fd;
+ };
+ 
+diff --git a/netwerk/base/nsPISocketTransportService.idl b/netwerk/base/nsPISocketTransportService.idl
+--- a/netwerk/base/nsPISocketTransportService.idl
++++ b/netwerk/base/nsPISocketTransportService.idl
+@@ -44,18 +44,18 @@ interface nsPISocketTransportService : n
+   /**
+    * Controls the default retransmission count for keepalive probes.
+    */
+   readonly attribute long keepaliveProbeCount;
+ };
+ 
+ %{C++
+ /*
+- * Network activity: we send out this topic no more than every
++ * I/O activity: we send out this topic no more than every
+  * intervalMilliseconds (as set by the
+- * "network.activity.intervalMilliseconds" preference: if 0 no notifications
+- * are sent) if the network is currently active (i.e. we're sending/receiving
+- * data to/from the socket).
++ * "io.activity.intervalMilliseconds" preference: if 0 no notifications
++ * are sent) if the I/O is currently active (i.e. we're sending/receiving
++ * data to/from the socket or writing/reading to/from a file).
+  */
+-#define NS_NETWORK_ACTIVITY "network-activity"
++#define NS_IO_ACTIVITY "io-activity"
+ 
+ 
+ %}
+diff --git a/netwerk/base/nsSocketTransport2.cpp b/netwerk/base/nsSocketTransport2.cpp
+--- a/netwerk/base/nsSocketTransport2.cpp
++++ b/netwerk/base/nsSocketTransport2.cpp
+@@ -14,17 +14,17 @@
+ #include "nsTransportUtils.h"
+ #include "nsProxyInfo.h"
+ #include "nsNetCID.h"
+ #include "nsNetUtil.h"
+ #include "nsAutoPtr.h"
+ #include "nsCOMPtr.h"
+ #include "plstr.h"
+ #include "prerr.h"
+-#include "NetworkActivityMonitor.h"
++#include "IOActivityMonitor.h"
+ #include "NSSErrorsService.h"
+ #include "mozilla/dom/ToJSValue.h"
+ #include "mozilla/net/NeckoChild.h"
+ #include "nsThreadUtils.h"
+ #include "nsISocketProviderService.h"
+ #include "nsISocketProvider.h"
+ #include "nsISSLSocketControl.h"
+ #include "nsIPipe.h"
+@@ -1361,18 +1361,18 @@ nsSocketTransport::InitiateSocket()
+     bool usingSSL;
+ 
+     rv = BuildSocket(fd, proxyTransparent, usingSSL);
+     if (NS_FAILED(rv)) {
+         SOCKET_LOG(("  BuildSocket failed [rv=%" PRIx32 "]\n", static_cast<uint32_t>(rv)));
+         return rv;
+     }
+ 
+-    // Attach network activity monitor
+-    NetworkActivityMonitor::AttachIOLayer(fd);
++    // create proxy via IOActivityMonitor
++    IOActivityMonitor::MonitorSocket(fd);
+ 
+     PRStatus status;
+ 
+     // Make the socket non-blocking...
+     PRSocketOptionData opt;
+     opt.option = PR_SockOpt_Nonblocking;
+     opt.value.non_blocking = true;
+     status = PR_SetSocketOption(fd, &opt);
+diff --git a/netwerk/base/nsSocketTransportService2.cpp b/netwerk/base/nsSocketTransportService2.cpp
+--- a/netwerk/base/nsSocketTransportService2.cpp
++++ b/netwerk/base/nsSocketTransportService2.cpp
+@@ -1,16 +1,16 @@
+ // vim:set sw=4 sts=4 et cin:
+ /* 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 "nsSocketTransportService2.h"
+ #include "nsSocketTransport2.h"
+-#include "NetworkActivityMonitor.h"
++#include "IOActivityMonitor.h"
+ #include "mozilla/IntegerPrintfMacros.h"
+ #include "mozilla/Preferences.h"
+ #include "nsIOService.h"
+ #include "nsASocketHandler.h"
+ #include "nsError.h"
+ #include "prnetdb.h"
+ #include "prerror.h"
+ #include "nsIPrefService.h"
+@@ -43,17 +43,17 @@ static Atomic<PRThread*, Relaxed> gSocke
+ 
+ #define SEND_BUFFER_PREF "network.tcp.sendbuffer"
+ #define KEEPALIVE_ENABLED_PREF "network.tcp.keepalive.enabled"
+ #define KEEPALIVE_IDLE_TIME_PREF "network.tcp.keepalive.idle_time"
+ #define KEEPALIVE_RETRY_INTERVAL_PREF "network.tcp.keepalive.retry_interval"
+ #define KEEPALIVE_PROBE_COUNT_PREF "network.tcp.keepalive.probe_count"
+ #define SOCKET_LIMIT_TARGET 1000U
+ #define SOCKET_LIMIT_MIN      50U
+-#define INTERVAL_PREF "network.activity.intervalMilliseconds"
++#define IO_ACTIVITY_INTERVAL_PREF "io.activity.intervalMilliseconds"
+ #define MAX_TIME_BETWEEN_TWO_POLLS "network.sts.max_time_for_events_between_two_polls"
+ #define POLL_BUSY_WAIT_PERIOD "network.sts.poll_busy_wait_period"
+ #define POLL_BUSY_WAIT_PERIOD_TIMEOUT "network.sts.poll_busy_wait_period_timeout"
+ #define MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN "network.sts.max_time_for_pr_close_during_shutdown"
+ #define POLLABLE_EVENT_TIMEOUT "network.sts.pollable_event_timeout"
+ 
+ #define REPAIR_POLLABLE_EVENT_TIME 10
+ 
+@@ -709,17 +709,17 @@ nsSocketTransportService::ShutdownThread
+         obsSvc->RemoveObserver(this, NS_NETWORK_LINK_TOPIC);
+     }
+ 
+     if (mAfterWakeUpTimer) {
+         mAfterWakeUpTimer->Cancel();
+         mAfterWakeUpTimer = nullptr;
+     }
+ 
+-    NetworkActivityMonitor::Shutdown();
++    IOActivityMonitor::Shutdown();
+ 
+     mInitialized = false;
+     mShuttingDown = false;
+ 
+     return NS_OK;
+ }
+ 
+ NS_IMETHODIMP
+@@ -1373,22 +1373,22 @@ nsSocketTransportService::Observe(nsISup
+     SOCKET_LOG(("nsSocketTransportService::Observe topic=%s", topic));
+ 
+     if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
+         UpdatePrefs();
+         return NS_OK;
+     }
+ 
+     if (!strcmp(topic, "profile-initial-state")) {
+-        int32_t interval = Preferences::GetInt(INTERVAL_PREF, 0);
++        int32_t interval = Preferences::GetInt(IO_ACTIVITY_INTERVAL_PREF, 0);
+         if (interval <= 0) {
+             return NS_OK;
+         }
+ 
+-        return net::NetworkActivityMonitor::Init(interval);
++        return net::IOActivityMonitor::Init(interval);
+     }
+ 
+     if (!strcmp(topic, "last-pb-context-exited")) {
+       nsCOMPtr<nsIRunnable> ev = NewRunnableMethod(
+         "net::nsSocketTransportService::ClosePrivateConnections",
+         this,
+         &nsSocketTransportService::ClosePrivateConnections);
+       nsresult rv = Dispatch(ev, nsIEventTarget::DISPATCH_NORMAL);
+diff --git a/netwerk/base/nsUDPSocket.cpp b/netwerk/base/nsUDPSocket.cpp
+--- a/netwerk/base/nsUDPSocket.cpp
++++ b/netwerk/base/nsUDPSocket.cpp
+@@ -15,17 +15,17 @@
+ #include "nsError.h"
+ #include "nsNetCID.h"
+ #include "nsNetUtil.h"
+ #include "nsIOService.h"
+ #include "prnetdb.h"
+ #include "prio.h"
+ #include "nsNetAddr.h"
+ #include "nsNetSegmentUtils.h"
+-#include "NetworkActivityMonitor.h"
++#include "IOActivityMonitor.h"
+ #include "nsServiceManagerUtils.h"
+ #include "nsStreamUtils.h"
+ #include "nsIPipe.h"
+ #include "prerror.h"
+ #include "nsThreadUtils.h"
+ #include "nsIDNSRecord.h"
+ #include "nsIDNSService.h"
+ #include "nsICancelable.h"
+@@ -676,18 +676,18 @@ nsUDPSocket::InitWithAddress(const NetAd
+   if (PR_GetSockName(mFD, &addr) != PR_SUCCESS)
+   {
+     NS_WARNING("cannot get socket name");
+     goto fail;
+   }
+ 
+   PRNetAddrToNetAddr(&addr, &mAddr);
+ 
+-  // create proxy via NetworkActivityMonitor
+-  NetworkActivityMonitor::AttachIOLayer(mFD);
++  // create proxy via IOActivityMonitor
++  IOActivityMonitor::MonitorSocket(mFD);
+ 
+   // wait until AsyncListen is called before polling the socket for
+   // client connections.
+   return NS_OK;
+ 
+ fail:
+   Close();
+   return NS_ERROR_FAILURE;
+diff --git a/netwerk/test/browser/browser.ini b/netwerk/test/browser/browser.ini
+--- a/netwerk/test/browser/browser.ini
++++ b/netwerk/test/browser/browser.ini
+@@ -5,9 +5,10 @@ support-files =
+ [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
+ [browser_resource_navigation.js]
++[browser_test_io_activity.js]
+ [browser_cookie_sync_across_tabs.js]
+diff --git a/netwerk/test/browser/browser_test_io_activity.js b/netwerk/test/browser/browser_test_io_activity.js
+new file mode 100644
+--- /dev/null
++++ b/netwerk/test/browser/browser_test_io_activity.js
+@@ -0,0 +1,53 @@
++/* -*- 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";
++
++
++add_task(async function test() {
++
++    SpecialPowers.setIntPref('io.activity.intervalMilliseconds', 50);
++    waitForExplicitFinish();
++
++    // grab events..
++    let gotSocket = false;
++    let gotFile = false;
++    let gotSqlite = false;
++    let gotEmptyData = false;
++
++    let 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);
++            gotEmptyData = data.rx == 0 && data.tx == 0 && !gotEmptyData
++            gotSocket = data.location.startsWith("socket://127.0.0.1:") || gotSocket;
++            gotFile = data.location.endsWith(".js") || gotFile;
++            gotSqlite = data.location.endsWith("places.sqlite") || gotSqlite;
++        }
++    };
++
++    Services.obs.addObserver(networkActivity, "io-activity");
++
++    // why do I have to do this ??
++    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(() => {
++          return gotSocket && gotFile && gotSqlite && !gotEmptyData;
++        }, "wait for events to come in", 250, 5);
++
++        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");
++    });
++
++    SpecialPowers.clearUserPref('io.activity.intervalMilliseconds');
++});
+diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini
+--- a/netwerk/test/unit/xpcshell.ini
++++ b/netwerk/test/unit/xpcshell.ini
+@@ -16,17 +16,16 @@ support-files =
+   data/test_readline7.txt
+   data/test_readline8.txt
+   data/signed_win.exe
+   socks_client_subprocess.js
+   test_link.desktop
+   test_link.url
+   ../../dns/effective_tld_names.dat
+ 
+-[test_network_activity.js]
+ [test_nsIBufferedOutputStream_writeFrom_block.js]
+ [test_cache2-00-service-get.js]
+ [test_cache2-01-basic.js]
+ [test_cache2-01a-basic-readonly.js]
+ [test_cache2-01b-basic-datasize.js]
+ [test_cache2-01c-basic-hasmeta-only.js]
+ [test_cache2-01d-basic-not-wanted.js]
+ [test_cache2-01e-basic-bypass-if-busy.js]
+diff --git a/storage/TelemetryVFS.cpp b/storage/TelemetryVFS.cpp
+--- a/storage/TelemetryVFS.cpp
++++ b/storage/TelemetryVFS.cpp
+@@ -7,16 +7,17 @@
+ #include <string.h>
+ #include "mozilla/Telemetry.h"
+ #include "mozilla/Preferences.h"
+ #include "sqlite3.h"
+ #include "nsThreadUtils.h"
+ #include "mozilla/dom/quota/PersistenceType.h"
+ #include "mozilla/dom/quota/QuotaManager.h"
+ #include "mozilla/dom/quota/QuotaObject.h"
++#include "mozilla/net/IOActivityMonitor.h"
+ #include "mozilla/IOInterposer.h"
+ 
+ // The last VFS version for which this file has been updated.
+ #define LAST_KNOWN_VFS_VERSION 3
+ 
+ // The last io_methods version for which this file has been updated.
+ #define LAST_KNOWN_IOMETHODS_VERSION 3
+ 
+@@ -29,16 +30,17 @@
+  * locking is slower than POSIX locking, so we do not want to do it by default.
+ */
+ #define PREF_NFS_FILESYSTEM   "storage.nfs_filesystem"
+ 
+ namespace {
+ 
+ using namespace mozilla;
+ using namespace mozilla::dom::quota;
++using namespace mozilla::net;
+ 
+ struct Histograms {
+   const char *name;
+   const Telemetry::HistogramID readB;
+   const Telemetry::HistogramID writeB;
+   const Telemetry::HistogramID readMS;
+   const Telemetry::HistogramID writeMS;
+   const Telemetry::HistogramID syncMS;
+@@ -145,16 +147,19 @@ struct telemetry_file {
+ 
+   // quota object for this file
+   RefPtr<QuotaObject> quotaObject;
+ 
+   // The chunk size for this file. See the documentation for
+   // sqlite3_file_control() and FCNTL_CHUNK_SIZE.
+   int fileChunkSize;
+ 
++  // The filename
++  char* location;
++
+   // This contains the vfs that actually does work
+   sqlite3_file pReal[1];
+ };
+ 
+ const char*
+ DatabasePathFromWALPath(const char *zWALName)
+ {
+   /**
+@@ -353,16 +358,17 @@ xClose(sqlite3_file *pFile)
+   { // Scope for IOThreadAutoTimer
+     IOThreadAutoTimer ioTimer(IOInterposeObserver::OpClose);
+     rc = p->pReal->pMethods->xClose(p->pReal);
+   }
+   if( rc==SQLITE_OK ){
+     delete p->base.pMethods;
+     p->base.pMethods = nullptr;
+     p->quotaObject = nullptr;
++    delete[] p->location;
+ #ifdef DEBUG
+     p->fileChunkSize = 0;
+ #endif
+   }
+   return rc;
+ }
+ 
+ /*
+@@ -370,16 +376,19 @@ xClose(sqlite3_file *pFile)
+ */
+ int
+ xRead(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst)
+ {
+   telemetry_file *p = (telemetry_file *)pFile;
+   IOThreadAutoTimer ioTimer(p->histograms->readMS, IOInterposeObserver::OpRead);
+   int rc;
+   rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
++  if (rc == SQLITE_OK && IOActivityMonitor::IsActive()) {
++    IOActivityMonitor::Read(nsDependentCString(p->location), iAmt);
++  }
+   // sqlite likes to read from empty files, this is normal, ignore it.
+   if (rc != SQLITE_IOERR_SHORT_READ)
+     Telemetry::Accumulate(p->histograms->readB, rc == SQLITE_OK ? iAmt : 0);
+   return rc;
+ }
+ 
+ /*
+ ** Return the current file-size of a telemetry_file.
+@@ -405,16 +414,20 @@ xWrite(sqlite3_file *pFile, const void *
+   int rc;
+   if (p->quotaObject) {
+     MOZ_ASSERT(INT64_MAX - iOfst >= iAmt);
+     if (!p->quotaObject->MaybeUpdateSize(iOfst + iAmt, /* aTruncate */ false)) {
+       return SQLITE_FULL;
+     }
+   }
+   rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
++  if (rc == SQLITE_OK && IOActivityMonitor::IsActive()) {
++    IOActivityMonitor::Write(nsDependentCString(p->location), iAmt);
++  }
++
+   Telemetry::Accumulate(p->histograms->writeB, rc == SQLITE_OK ? iAmt : 0);
+   if (p->quotaObject && rc != SQLITE_OK) {
+     NS_WARNING("xWrite failed on a quota-controlled file, attempting to "
+                "update its current size...");
+     sqlite_int64 currentSize;
+     if (xFileSize(pFile, &currentSize) == SQLITE_OK) {
+       p->quotaObject->MaybeUpdateSize(currentSize, /* aTruncate */ true);
+     }
+@@ -656,16 +669,26 @@ xOpen(sqlite3_vfs* vfs, const char *zNam
+   }
+   p->histograms = h;
+ 
+   MaybeEstablishQuotaControl(zName, p, flags);
+ 
+   rc = orig_vfs->xOpen(orig_vfs, zName, p->pReal, flags, pOutFlags);
+   if( rc != SQLITE_OK )
+     return rc;
++
++  if (zName) {
++    p->location = new char[7 + strlen(zName) + 1];
++    strcpy(p->location, "file://");
++    strcpy(p->location + 7, zName);
++  } else {
++    p->location = new char[8];
++    strcpy(p->location, "file://");
++  }
++
+   if( p->pReal->pMethods ){
+     sqlite3_io_methods *pNew = new sqlite3_io_methods;
+     const sqlite3_io_methods *pSub = p->pReal->pMethods;
+     memset(pNew, 0, sizeof(*pNew));
+     // If the io_methods version is higher than the last known one, you should
+     // update this VFS adding appropriate IO methods for any methods added in
+     // the version change.
+     pNew->iVersion = pSub->iVersion;

+ 103 - 0
mozilla-release/patches/1472722-63a1.patch

@@ -0,0 +1,103 @@
+# HG changeset patch
+# User Marco Bonardo <mbonardo@mozilla.com>
+# Date 1531500897 0
+# Node ID b3494bf0c3d31048eb0af0324f107208d7e5ecc6
+# Parent  c0774c99c10fa770a2cd30ebe452a53d2e75d277
+Bug 1472722 - Use the unix-excl Sqlite VFS by default. r=nalexander,asuth
+
+Use the exclusive VFS on unix systems, so that:
+1. we can avoid the memory mapped -shm files in wal mode
+2. we gain more compatibility with nfs shares
+3. we gain some protection from third parties touching open dbs
+
+On the other side it won't be possible anymore to use an open database from a
+different process (like the Sqlite command line), for which we provide an hidden
+pref: storage.multiProcessAccess.enabled
+
+Differential Revision: https://phabricator.services.mozilla.com/D1964
+
+diff --git a/storage/TelemetryVFS.cpp b/storage/TelemetryVFS.cpp
+--- a/storage/TelemetryVFS.cpp
++++ b/storage/TelemetryVFS.cpp
+@@ -17,24 +17,31 @@
+ 
+ // The last VFS version for which this file has been updated.
+ #define LAST_KNOWN_VFS_VERSION 3
+ 
+ // The last io_methods version for which this file has been updated.
+ #define LAST_KNOWN_IOMETHODS_VERSION 3
+ 
+ /**
+- * This preference is a workaround to allow users/sysadmins to identify
+- * that the profile exists on an NFS share whose implementation
+- * is incompatible with SQLite's default locking implementation.
+- * Bug 433129 attempted to automatically identify such file-systems,
+- * but a reliable way was not found and it was determined that the fallback
+- * locking is slower than POSIX locking, so we do not want to do it by default.
+-*/
+-#define PREF_NFS_FILESYSTEM   "storage.nfs_filesystem"
++ * By default use the unix-excl VFS, for the following reasons:
++ * 1. It improves compatibility with NFS shares, whose implementation
++ *    is incompatible with SQLite's locking requirements.
++ *    Bug 433129 attempted to automatically identify such file-systems,
++ *    but a reliable way was not found and the fallback locking is slower than
++ *    POSIX locking, so we do not want to do it by default.
++ * 2. It allows wal mode to avoid the memory mapped -shm file, reducing the
++ *    likelihood of SIGBUS failures when disk space is exhausted.
++ * 3. It provides some protection from third party database tampering while a
++ *    connection is open.
++ * This preference allows to revert to the "unix" VFS, that is not exclusive,
++ * thus it can be used by developers to query a database through the Sqlite
++ * command line while it's already in use.
++ */
++#define PREF_MULTI_PROCESS_ACCESS "storage.multiProcessAccess.enabled"
+ 
+ namespace {
+ 
+ using namespace mozilla;
+ using namespace mozilla::dom::quota;
+ using namespace mozilla::net;
+ 
+ struct Histograms {
+@@ -854,32 +861,32 @@ namespace storage {
+ const char *GetVFSName()
+ {
+   return "telemetry-vfs";
+ }
+ 
+ sqlite3_vfs* ConstructTelemetryVFS()
+ {
+ #if defined(XP_WIN)
+-#define EXPECTED_VFS     "win32"
+-#define EXPECTED_VFS_NFS "win32"
++#define EXPECTED_VFS      "win32"
++#define EXPECTED_VFS_EXCL "win32"
+ #else
+-#define EXPECTED_VFS     "unix"
+-#define EXPECTED_VFS_NFS "unix-excl"
++#define EXPECTED_VFS      "unix"
++#define EXPECTED_VFS_EXCL "unix-excl"
+ #endif
+ 
+   bool expected_vfs;
+   sqlite3_vfs *vfs;
+-  if (Preferences::GetBool(PREF_NFS_FILESYSTEM)) {
+-    vfs = sqlite3_vfs_find(EXPECTED_VFS_NFS);
+-    expected_vfs = (vfs != nullptr);
+-  }
+-  else {
++  if (Preferences::GetBool(PREF_MULTI_PROCESS_ACCESS, false)) {
++    // Use the non-exclusive VFS.
+     vfs = sqlite3_vfs_find(nullptr);
+     expected_vfs = vfs->zName && !strcmp(vfs->zName, EXPECTED_VFS);
++  } else {
++    vfs = sqlite3_vfs_find(EXPECTED_VFS_EXCL);
++    expected_vfs = (vfs != nullptr);
+   }
+   if (!expected_vfs) {
+     return nullptr;
+   }
+ 
+   sqlite3_vfs *tvfs = new ::sqlite3_vfs;
+   memset(tvfs, 0, sizeof(::sqlite3_vfs));
+   // If the VFS version is higher than the last known one, you should update

+ 28 - 0
mozilla-release/patches/TOP-NOBUG-fixups-25320.patch

@@ -0,0 +1,28 @@
+# HG changeset patch
+# User Frank-Rainer Grahl <frgrahl@gmx.net>
+# Date 1720810040 -7200
+# Parent  ee64a2ec4cfc6790b804c562ca1bdf01091d6f7d
+No Bug - Fix up code for missing patches. r=me a=me
+
+diff --git a/netwerk/base/IOActivityMonitor.cpp b/netwerk/base/IOActivityMonitor.cpp
+--- a/netwerk/base/IOActivityMonitor.cpp
++++ b/netwerk/base/IOActivityMonitor.cpp
+@@ -380,17 +380,17 @@ IOActivityMonitor::IOActivityMonitor()
+   MOZ_ASSERT(!mon, "multiple IOActivityMonitor instances!");
+ }
+ 
+ NS_IMETHODIMP
+ IOActivityMonitor::Notify(nsITimer* aTimer)
+ {
+   mozilla::MutexAutoLock lock(mLock);
+   nsCOMPtr<nsIRunnable> ev = NotifyIOActivity::Create(mActivities, lock);
+-  nsresult rv = SystemGroup::EventTargetFor(TaskCategory::Performance)->Dispatch(ev.forget());
++  nsresult rv = SystemGroup::EventTargetFor(TaskCategory::Network)->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()) {

+ 4 - 0
mozilla-release/patches/series

@@ -7112,12 +7112,15 @@ TOP-1906540-mozdevice-removal-mozilla-25320.patch
 1423495-2-61a1.patch
 1423495-3-61a1.patch
 1423495-4no5-61a1.patch
+1444490-61a1.patch
 1423495-6-61a1.patch
 1457401-61a1.patch
 1462605-62a1.patch
 1462880-62a1.patch
 1463065-62a1.patch
 1465585-3a-std-62a1.patch
+1447931-62a1.patch
+1472722-63a1.patch
 1462883-1no2-63a1.patch
 1462883-3-63a1.patch
 1500733-1-65a1.patch
@@ -7129,3 +7132,4 @@ TOP-1906540-mozdevice-removal-mozilla-25320.patch
 1559403-1-69a1.patch
 1559403-2-69a1.patch
 1566482-70a1.patch
+TOP-NOBUG-fixups-25320.patch