Bug 1415536 - Extend NotifyNetworkActivity to get sent/received bytes r=baku,valentin

MozReview-Commit-ID: Afdvz0lktY8

--HG--
extra : rebase_source : 900d807ec9a9f5305c07947ced00a6f68192ed9d
This commit is contained in:
Tarek Ziadé 2017-11-23 09:37:54 +01:00
Родитель a5aef799e1
Коммит 8ecfc87eb1
10 изменённых файлов: 456 добавлений и 105 удалений

Просмотреть файл

@ -5155,7 +5155,7 @@ pref("dom.idle-observers-api.fuzz_time.disabled", true);
// no notifications). The delay is the same for both download and upload, though // no notifications). The delay is the same for both download and upload, though
// they are handled separately. This pref is only read once at startup: // they are handled separately. This pref is only read once at startup:
// a restart is required to enable a new value. // a restart is required to enable a new value.
pref("network.activity.blipIntervalMilliseconds", 0); pref("network.activity.intervalMilliseconds", 0);
// If true, reuse the same global for (almost) everything loaded by the component // 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 // loader (JS components, JSMs, etc). This saves memory, but makes it possible

Просмотреть файл

@ -3,18 +3,32 @@
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "NetworkActivityMonitor.h" #include "NetworkActivityMonitor.h"
#include "prmem.h"
#include "nsIObserverService.h" #include "nsIObserverService.h"
#include "nsPISocketTransportService.h" #include "nsPISocketTransportService.h"
#include "nsPrintfCString.h"
#include "nsSocketTransport2.h"
#include "nsSocketTransportService2.h" #include "nsSocketTransportService2.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "mozilla/Services.h" #include "mozilla/Services.h"
#include "prerror.h" #include "prerror.h"
#include "prio.h"
#include "prmem.h"
#include <vector>
using namespace mozilla::net; using namespace mozilla::net;
struct SocketActivity {
PROsfd fd;
uint32_t port;
nsString host;
uint32_t rx;
uint32_t tx;
};
static PRStatus static PRStatus
nsNetMon_Connect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) nsNetMon_Connect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
{ {
@ -22,18 +36,29 @@ nsNetMon_Connect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
PRErrorCode code; PRErrorCode code;
ret = fd->lower->methods->connect(fd->lower, addr, timeout); ret = fd->lower->methods->connect(fd->lower, addr, timeout);
if (ret == PR_SUCCESS || (code = PR_GetError()) == PR_WOULD_BLOCK_ERROR || if (ret == PR_SUCCESS || (code = PR_GetError()) == PR_WOULD_BLOCK_ERROR ||
code == PR_IN_PROGRESS_ERROR) code == PR_IN_PROGRESS_ERROR) {
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload); NetworkActivityMonitor::RegisterFd(fd, addr);
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, 0);
}
return ret; return ret;
} }
static PRStatus
nsNetMon_Close(PRFileDesc *fd)
{
NetworkActivityMonitor::UnregisterFd(fd);
return fd->lower->methods->close(fd->lower);
}
static int32_t static int32_t
nsNetMon_Read(PRFileDesc *fd, void *buf, int32_t len) nsNetMon_Read(PRFileDesc *fd, void *buf, int32_t len)
{ {
int32_t ret; int32_t ret;
ret = fd->lower->methods->read(fd->lower, buf, len); ret = fd->lower->methods->read(fd->lower, buf, len);
if (ret >= 0) if (ret >= 0) {
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload); NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, fd, len);
}
return ret; return ret;
} }
@ -42,8 +67,9 @@ nsNetMon_Write(PRFileDesc *fd, const void *buf, int32_t len)
{ {
int32_t ret; int32_t ret;
ret = fd->lower->methods->write(fd->lower, buf, len); ret = fd->lower->methods->write(fd->lower, buf, len);
if (ret > 0) if (ret > 0) {
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload); NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, len);
}
return ret; return ret;
} }
@ -55,8 +81,9 @@ nsNetMon_Writev(PRFileDesc *fd,
{ {
int32_t ret; int32_t ret;
ret = fd->lower->methods->writev(fd->lower, iov, size, timeout); ret = fd->lower->methods->writev(fd->lower, iov, size, timeout);
if (ret > 0) if (ret > 0) {
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload); NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, size);
}
return ret; return ret;
} }
@ -69,8 +96,9 @@ nsNetMon_Recv(PRFileDesc *fd,
{ {
int32_t ret; int32_t ret;
ret = fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout); ret = fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout);
if (ret >= 0) if (ret >= 0) {
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload); NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, fd, amount);
}
return ret; return ret;
} }
@ -83,8 +111,9 @@ nsNetMon_Send(PRFileDesc *fd,
{ {
int32_t ret; int32_t ret;
ret = fd->lower->methods->send(fd->lower, buf, amount, flags, timeout); ret = fd->lower->methods->send(fd->lower, buf, amount, flags, timeout);
if (ret > 0) if (ret > 0) {
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload); NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, amount);
}
return ret; return ret;
} }
@ -103,8 +132,9 @@ nsNetMon_RecvFrom(PRFileDesc *fd,
flags, flags,
addr, addr,
timeout); timeout);
if (ret >= 0) if (ret >= 0) {
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload); NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, fd, amount);
}
return ret; return ret;
} }
@ -123,8 +153,9 @@ nsNetMon_SendTo(PRFileDesc *fd,
flags, flags,
addr, addr,
timeout); timeout);
if (ret > 0) if (ret > 0) {
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload); NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, amount);
}
return ret; return ret;
} }
@ -143,88 +174,182 @@ nsNetMon_AcceptRead(PRFileDesc *listenSock,
buf, buf,
amount, amount,
timeout); timeout);
if (ret > 0) if (ret > 0) {
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload); NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, listenSock, amount);
}
return ret; return ret;
} }
NS_IMPL_ISUPPORTS(NetworkData, nsINetworkActivityData);
NS_IMETHODIMP
NetworkData::GetHost(nsAString& aHost) {
aHost = mHost;
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;
return NS_OK;
};
NS_IMETHODIMP
NetworkData::GetFd(int32_t* aFd) {
*aFd = mFd;
return NS_OK;
};
class NotifyNetworkActivity : public mozilla::Runnable { class NotifyNetworkActivity : public mozilla::Runnable {
public: public:
explicit NotifyNetworkActivity(NetworkActivityMonitor::Direction aDirection) explicit NotifyNetworkActivity(NetworkActivity* aActivity)
: mozilla::Runnable("NotifyNetworkActivity") : mozilla::Runnable("NotifyNetworkActivity")
, mDirection(aDirection)
{} {
NS_IMETHOD Run() override 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);
}
}
}
NS_IMETHODIMP
Run() override
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); if (mActivities.Length() == 0) {
if (!obs) return NS_OK;
return NS_ERROR_FAILURE; }
obs->NotifyObservers(nullptr, nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
mDirection == NetworkActivityMonitor::kUpload if (!obs) {
? NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC return NS_ERROR_FAILURE;
: NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC, }
nullptr);
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);
nsresult rv = array->AppendElement(data);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
obs->NotifyObservers(array, NS_NETWORK_ACTIVITY, nullptr);
return NS_OK; return NS_OK;
} }
private: private:
NetworkActivityMonitor::Direction mDirection; nsTArray<SocketActivity> mActivities;
}; };
NetworkActivityMonitor * NetworkActivityMonitor::gInstance = nullptr;
mozilla::StaticRefPtr<NetworkActivityMonitor> gInstance;
static PRDescIdentity sNetActivityMonitorLayerIdentity; static PRDescIdentity sNetActivityMonitorLayerIdentity;
static PRIOMethods sNetActivityMonitorLayerMethods; static PRIOMethods sNetActivityMonitorLayerMethods;
static PRIOMethods *sNetActivityMonitorLayerMethodsPtr = nullptr; static PRIOMethods *sNetActivityMonitorLayerMethodsPtr = nullptr;
NS_IMPL_ISUPPORTS(NetworkActivityMonitor, nsITimerCallback, nsINamed)
NetworkActivityMonitor::NetworkActivityMonitor() NetworkActivityMonitor::NetworkActivityMonitor()
: mBlipInterval(PR_INTERVAL_NO_TIMEOUT) : mInterval(PR_INTERVAL_NO_TIMEOUT)
, mLock("NetworkActivityMonitor::mLock")
{ {
MOZ_COUNT_CTOR(NetworkActivityMonitor); RefPtr<NetworkActivityMonitor> mon(gInstance);
MOZ_ASSERT(!mon, "multiple NetworkActivityMonitor instances!");
NS_ASSERTION(gInstance==nullptr,
"multiple NetworkActivityMonitor instances!");
} }
NetworkActivityMonitor::~NetworkActivityMonitor() NS_IMETHODIMP
NetworkActivityMonitor::Notify(nsITimer* aTimer)
{ {
MOZ_COUNT_DTOR(NetworkActivityMonitor); mozilla::MutexAutoLock lock(mLock);
gInstance = nullptr; 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);
}
return NS_OK;
} }
NS_IMETHODIMP
NetworkActivityMonitor::GetName(nsACString& aName)
{
aName.AssignLiteral("NetworkActivityMonitor");
return NS_OK;
}
nsresult nsresult
NetworkActivityMonitor::Init(int32_t blipInterval) NetworkActivityMonitor::Init(int32_t aInterval)
{ {
nsresult rv; nsresult rv = NS_OK;
RefPtr<NetworkActivityMonitor> mon(gInstance);
if (gInstance) if (mon) {
return NS_ERROR_ALREADY_INITIALIZED; return NS_ERROR_ALREADY_INITIALIZED;
} else {
NetworkActivityMonitor * mon = new NetworkActivityMonitor(); mon = new NetworkActivityMonitor();
rv = mon->Init_Internal(blipInterval); rv = mon->Init_Internal(aInterval);
if (NS_FAILED(rv)) { if (NS_SUCCEEDED(rv)) {
delete mon;
return rv;
}
gInstance = mon; gInstance = mon;
return NS_OK; } else {
rv = NS_ERROR_FAILURE;
}
}
return rv;
} }
nsresult nsresult
NetworkActivityMonitor::Shutdown() NetworkActivityMonitor::Shutdown()
{ {
if (!gInstance) RefPtr<NetworkActivityMonitor> mon(gInstance);
if (!mon) {
return NS_ERROR_NOT_INITIALIZED; return NS_ERROR_NOT_INITIALIZED;
}
delete gInstance; mon->Shutdown_Internal();
gInstance = nullptr;
return NS_OK; return NS_OK;
} }
nsresult nsresult
NetworkActivityMonitor::Init_Internal(int32_t blipInterval) NetworkActivityMonitor::Init_Internal(int32_t aInterval)
{ {
if (!sNetActivityMonitorLayerMethodsPtr) { if (!sNetActivityMonitorLayerMethodsPtr) {
sNetActivityMonitorLayerIdentity = sNetActivityMonitorLayerIdentity =
@ -239,27 +364,35 @@ NetworkActivityMonitor::Init_Internal(int32_t blipInterval)
sNetActivityMonitorLayerMethods.recvfrom = nsNetMon_RecvFrom; sNetActivityMonitorLayerMethods.recvfrom = nsNetMon_RecvFrom;
sNetActivityMonitorLayerMethods.sendto = nsNetMon_SendTo; sNetActivityMonitorLayerMethods.sendto = nsNetMon_SendTo;
sNetActivityMonitorLayerMethods.acceptread = nsNetMon_AcceptRead; sNetActivityMonitorLayerMethods.acceptread = nsNetMon_AcceptRead;
sNetActivityMonitorLayerMethods.close = nsNetMon_Close;
sNetActivityMonitorLayerMethodsPtr = &sNetActivityMonitorLayerMethods; sNetActivityMonitorLayerMethodsPtr = &sNetActivityMonitorLayerMethods;
} }
mBlipInterval = PR_MillisecondsToInterval(blipInterval); // create and fire the timer
// Set the last notification times to time that has just expired, so any mInterval = aInterval;
// activity even right now will trigger notification. mTimer = NS_NewTimer();
mLastNotificationTime[kUpload] = PR_IntervalNow() - mBlipInterval; if (!mTimer) {
mLastNotificationTime[kDownload] = mLastNotificationTime[kUpload]; return NS_ERROR_FAILURE;
}
return mTimer->InitWithCallback(this, mInterval, nsITimer::TYPE_REPEATING_SLACK);
}
nsresult
NetworkActivityMonitor::Shutdown_Internal()
{
mTimer->Cancel();
return NS_OK; return NS_OK;
} }
nsresult nsresult
NetworkActivityMonitor::AttachIOLayer(PRFileDesc *fd) NetworkActivityMonitor::AttachIOLayer(PRFileDesc *fd)
{ {
if (!gInstance) RefPtr<NetworkActivityMonitor> mon(gInstance);
if (!mon) {
return NS_OK; return NS_OK;
}
PRFileDesc * layer; PRFileDesc * layer;
PRStatus status; PRStatus status;
layer = PR_CreateIOLayerStub(sNetActivityMonitorLayerIdentity, layer = PR_CreateIOLayerStub(sNetActivityMonitorLayerIdentity,
sNetActivityMonitorLayerMethodsPtr); sNetActivityMonitorLayerMethodsPtr);
if (!layer) { if (!layer) {
@ -277,25 +410,102 @@ NetworkActivityMonitor::AttachIOLayer(PRFileDesc *fd)
} }
nsresult nsresult
NetworkActivityMonitor::DataInOut(Direction direction) NetworkActivityMonitor::RegisterFd(PRFileDesc *aFd, const PRNetAddr *aAddr) {
{
MOZ_ASSERT(OnSocketThread(), "not on socket thread"); MOZ_ASSERT(OnSocketThread(), "not on socket thread");
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");
}
RefPtr<NetworkActivityMonitor> mon(gInstance);
if (mon) {
return mon->RegisterFd_Internal(osfd, NS_ConvertUTF8toUTF16(host), port);
}
return NS_ERROR_FAILURE;
}
if (gInstance) { nsresult
PRIntervalTime now = PR_IntervalNow(); NetworkActivityMonitor::UnregisterFd(PRFileDesc *aFd)
if ((now - gInstance->mLastNotificationTime[direction]) > {
gInstance->mBlipInterval) { nsresult rv;
gInstance->mLastNotificationTime[direction] = now; PROsfd osfd = PR_FileDesc2NativeHandle(aFd);
gInstance->PostNotification(direction); if (NS_WARN_IF(osfd == -1)) {
rv = ErrorAccordingToNSPR(PR_GetError());
} else {
RefPtr<NetworkActivityMonitor> mon(gInstance);
if (mon) {
rv = mon->UnregisterFd_Internal(osfd);
} else {
rv = NS_ERROR_FAILURE;
} }
} }
return rv;
}
nsresult
NetworkActivityMonitor::UnregisterFd_Internal(PROsfd aOsfd)
{
mozilla::MutexAutoLock lock(mLock);
// XXX we should remove scokets that have been unregistered
// after some time.
mActivity.active.Put(aOsfd, false);
return NS_OK; return NS_OK;
} }
void
NetworkActivityMonitor::PostNotification(Direction direction) nsresult
NetworkActivityMonitor::RegisterFd_Internal(PROsfd aOsfd, const nsString& host, uint16_t port)
{ {
nsCOMPtr<nsIRunnable> ev = new NotifyNetworkActivity(direction); mozilla::MutexAutoLock lock(mLock);
NS_DispatchToMainThread(ev); 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;
}
nsresult
NetworkActivityMonitor::DataInOut(Direction aDirection, PRFileDesc *aFd, uint32_t aAmount)
{
nsresult rv = NS_OK;
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
RefPtr<NetworkActivityMonitor> mon(gInstance);
if (mon) {
PROsfd osfd = PR_FileDesc2NativeHandle(aFd);
if (NS_WARN_IF(osfd == -1)) {
rv = ErrorAccordingToNSPR(PR_GetError());
} else {
rv = mon->DataInOut_Internal(osfd, aDirection, aAmount);
}
}
return rv;
}
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);
}
return NS_OK;
} }

Просмотреть файл

@ -7,14 +7,56 @@
#ifndef NetworkActivityMonitor_h___ #ifndef NetworkActivityMonitor_h___
#define NetworkActivityMonitor_h___ #define NetworkActivityMonitor_h___
#include <stdint.h> #include "nsCOMPtr.h"
#include "nscore.h" #include "nscore.h"
#include "prio.h" #include "nsDataHashtable.h"
#include "nsHashKeys.h"
#include "nsINetworkActivityData.h"
#include "nsISupports.h"
#include "nsITimer.h"
#include "prinrval.h" #include "prinrval.h"
#include "prio.h"
#include "private/pprio.h"
#include <stdint.h>
namespace mozilla { namespace net { namespace mozilla { namespace net {
class NetworkActivityMonitor typedef nsDataHashtable<nsUint32HashKey, uint32_t> SocketBytes;
typedef nsDataHashtable<nsUint32HashKey, uint32_t> SocketPort;
typedef nsDataHashtable<nsUint32HashKey, nsString> SocketHost;
typedef nsDataHashtable<nsUint32HashKey, bool> SocketActive;
struct NetworkActivity {
SocketPort port;
SocketHost host;
SocketBytes rx;
SocketBytes tx;
SocketActive active;
};
class NetworkData final : public nsINetworkActivityData
{
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) {}
private:
~NetworkData() = default;
nsString mHost;
int32_t mPort;
int32_t mFd;
int32_t mRx;
int32_t mTx;
};
class NetworkActivityMonitor: public nsITimerCallback
, public nsINamed
{ {
public: public:
enum Direction { enum Direction {
@ -23,21 +65,28 @@ public:
}; };
NetworkActivityMonitor(); NetworkActivityMonitor();
~NetworkActivityMonitor();
static nsresult Init(int32_t blipInterval); NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSITIMERCALLBACK
NS_DECL_NSINAMED
static nsresult Init(int32_t aInterval);
static nsresult Shutdown(); static nsresult Shutdown();
static nsresult AttachIOLayer(PRFileDesc *fd); static nsresult AttachIOLayer(PRFileDesc *fd);
static nsresult DataInOut(Direction direction); static nsresult DataInOut(Direction aDirection, PRFileDesc *aFd, uint32_t aAmount);
static nsresult RegisterFd(PRFileDesc *aFd, const PRNetAddr *aAddr);
static nsresult UnregisterFd(PRFileDesc *aFd);
private: private:
nsresult Init_Internal(int32_t blipInterval); virtual ~NetworkActivityMonitor() = default;
void PostNotification(Direction direction); nsresult Init_Internal(int32_t aInterval);
nsresult Shutdown_Internal();
static NetworkActivityMonitor * gInstance; nsresult RegisterFd_Internal(PROsfd aOsfd, const nsString& host, uint16_t port);
PRIntervalTime mBlipInterval; nsresult UnregisterFd_Internal(PROsfd aOsfd);
PRIntervalTime mLastNotificationTime[2]; nsresult DataInOut_Internal(PROsfd aOsfd, Direction aDirection, uint32_t aAmount);
uint32_t mInterval;
NetworkActivity mActivity;
nsCOMPtr<nsITimer> mTimer;
Mutex mLock;
}; };
} // namespace net } // namespace net

Просмотреть файл

@ -62,6 +62,7 @@ XPIDL_SOURCES += [
'nsINestedURI.idl', 'nsINestedURI.idl',
'nsINetAddr.idl', 'nsINetAddr.idl',
'nsINetUtil.idl', 'nsINetUtil.idl',
'nsINetworkActivityData.idl',
'nsINetworkInfoService.idl', 'nsINetworkInfoService.idl',
'nsINetworkInterceptController.idl', 'nsINetworkInterceptController.idl',
'nsINetworkLinkService.idl', 'nsINetworkLinkService.idl',

Просмотреть файл

@ -0,0 +1,21 @@
/* 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 nsINetworkActivityData : nsISupports
{
readonly attribute DOMString host;
readonly attribute long port;
readonly attribute long rx;
readonly attribute long tx;
readonly attribute long fd;
};

Просмотреть файл

@ -49,13 +49,13 @@ interface nsPISocketTransportService : nsIRoutedSocketTransportService
%{C++ %{C++
/* /*
* Network activity indicator: we send out these topics no more than every * Network activity: we send out this topic no more than every
* blipIntervalMilliseconds (as set by the * intervalMilliseconds (as set by the
* "network.activity.blipIntervalMilliseconds" preference: if 0 no notifications * "network.activity.intervalMilliseconds" preference: if 0 no notifications
* are sent) if the network is currently active (i.e. we're sending/receiving * are sent) if the network is currently active (i.e. we're sending/receiving
* data to/from the socket). * data to/from the socket).
*/ */
#define NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC "network-activity-blip-upload" #define NS_NETWORK_ACTIVITY "network-activity"
#define NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC "network-activity-blip-download"
%} %}

Просмотреть файл

@ -49,7 +49,7 @@ static Atomic<PRThread*, Relaxed> gSocketThread;
#define KEEPALIVE_PROBE_COUNT_PREF "network.tcp.keepalive.probe_count" #define KEEPALIVE_PROBE_COUNT_PREF "network.tcp.keepalive.probe_count"
#define SOCKET_LIMIT_TARGET 1000U #define SOCKET_LIMIT_TARGET 1000U
#define SOCKET_LIMIT_MIN 50U #define SOCKET_LIMIT_MIN 50U
#define BLIP_INTERVAL_PREF "network.activity.blipIntervalMilliseconds" #define INTERVAL_PREF "network.activity.intervalMilliseconds"
#define MAX_TIME_BETWEEN_TWO_POLLS "network.sts.max_time_for_events_between_two_polls" #define MAX_TIME_BETWEEN_TWO_POLLS "network.sts.max_time_for_events_between_two_polls"
#define TELEMETRY_PREF "toolkit.telemetry.enabled" #define TELEMETRY_PREF "toolkit.telemetry.enabled"
#define MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN "network.sts.max_time_for_pr_close_during_shutdown" #define MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN "network.sts.max_time_for_pr_close_during_shutdown"
@ -1353,12 +1353,12 @@ nsSocketTransportService::Observe(nsISupports *subject,
} }
if (!strcmp(topic, "profile-initial-state")) { if (!strcmp(topic, "profile-initial-state")) {
int32_t blipInterval = Preferences::GetInt(BLIP_INTERVAL_PREF, 0); int32_t interval = Preferences::GetInt(INTERVAL_PREF, 0);
if (blipInterval <= 0) { if (interval <= 0) {
return NS_OK; return NS_OK;
} }
return net::NetworkActivityMonitor::Init(blipInterval); return net::NetworkActivityMonitor::Init(interval);
} }
if (!strcmp(topic, "last-pb-context-exited")) { if (!strcmp(topic, "last-pb-context-exited")) {

Просмотреть файл

@ -0,0 +1,69 @@
// test for networkactivity
//
Cu.import("resource://testing-common/httpd.js");
Cu.import("resource://gre/modules/NetUtil.jsm");
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
var httpserver = new HttpServer();
var results = [];
var prefs = Cc["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
function createChannel() {
var chan = NetUtil.newChannel({
uri: "http://localhost:" + httpserver.identity.primaryPort + "/ok",
loadUsingSystemPrincipal: true
});
var httpChan = chan.QueryInterface(Components.interfaces.nsIHttpChannel);
return httpChan;
}
function handler(metadata, response) {
var body = "meh";
response.setHeader("Content-Type", "text/plain", false);
response.setStatusLine(metadata.httpVersion, 200, "OK");
response.bodyOutputStream.write(body, body.length);
}
async function checkValueAndTrigger(request, data) {
// give Firefox 150 ms to send notifications out
do_timeout(150, doTest);
}
function doTest() {
prefs.clearUserPref("network.activity.intervalMilliseconds");
ok(results.length>0);
ok(results[0].host == "127.0.0.1");
ok(results[0].rx > 100);
httpserver.stop(do_test_finished);
}
function run_test() {
// setting up an observer
let networkActivity = function(subject, topic, value) {
subject.QueryInterface(Ci.nsIMutableArray);
let enumerator = subject.enumerate();
while (enumerator.hasMoreElements()) {
let data = enumerator.getNext();
data.QueryInterface(Ci.nsINetworkActivityData);
results.push(data);
}
};
Services.obs.addObserver(networkActivity, 'network-activity');
// send events every 100ms
prefs.setIntPref("network.activity.intervalMilliseconds", 100);
// why do I have to do this ??
Services.obs.notifyObservers(null, "profile-initial-state", null);
do_test_pending();
httpserver.registerPathHandler("/ok", handler);
httpserver.start(-1);
var channel = createChannel();
channel.asyncOpen2(new ChannelListener(checkValueAndTrigger, null));
}

Просмотреть файл

@ -21,6 +21,7 @@ support-files =
test_link.url test_link.url
../../dns/effective_tld_names.dat ../../dns/effective_tld_names.dat
[test_network_activity.js]
[test_nsIBufferedOutputStream_writeFrom_block.js] [test_nsIBufferedOutputStream_writeFrom_block.js]
[test_cache2-00-service-get.js] [test_cache2-00-service-get.js]
[test_cache2-01-basic.js] [test_cache2-01-basic.js]

Просмотреть файл

@ -160,7 +160,7 @@ user_pref("dom.use_xbl_scopes_for_remote_xul", true);
user_pref("captivedetect.canonicalURL", "http://%(server)s/captive-detect/success.txt"); user_pref("captivedetect.canonicalURL", "http://%(server)s/captive-detect/success.txt");
// Get network events. // Get network events.
user_pref("network.activity.blipIntervalMilliseconds", 250); user_pref("network.activity.intervalMilliseconds", 5000);
// We do not wish to display datareporting policy notifications as it might // We do not wish to display datareporting policy notifications as it might
// cause other tests to fail. Tests that wish to test the notification functionality // cause other tests to fail. Tests that wish to test the notification functionality