зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
a5aef799e1
Коммит
8ecfc87eb1
|
@ -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
|
||||
// they are handled separately. This pref is only read once at startup:
|
||||
// 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
|
||||
// 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
|
||||
* 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 "prmem.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;
|
||||
};
|
||||
|
||||
|
||||
static PRStatus
|
||||
nsNetMon_Connect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
|
||||
{
|
||||
|
@ -22,18 +36,29 @@ nsNetMon_Connect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
|
|||
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::DataInOut(NetworkActivityMonitor::kUpload);
|
||||
code == PR_IN_PROGRESS_ERROR) {
|
||||
NetworkActivityMonitor::RegisterFd(fd, addr);
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PRStatus
|
||||
nsNetMon_Close(PRFileDesc *fd)
|
||||
{
|
||||
NetworkActivityMonitor::UnregisterFd(fd);
|
||||
return fd->lower->methods->close(fd->lower);
|
||||
}
|
||||
|
||||
|
||||
static int32_t
|
||||
nsNetMon_Read(PRFileDesc *fd, void *buf, int32_t len)
|
||||
{
|
||||
int32_t ret;
|
||||
ret = fd->lower->methods->read(fd->lower, buf, len);
|
||||
if (ret >= 0)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
|
||||
if (ret >= 0) {
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, fd, len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -42,8 +67,9 @@ nsNetMon_Write(PRFileDesc *fd, const void *buf, int32_t len)
|
|||
{
|
||||
int32_t ret;
|
||||
ret = fd->lower->methods->write(fd->lower, buf, len);
|
||||
if (ret > 0)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
|
||||
if (ret > 0) {
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -55,8 +81,9 @@ nsNetMon_Writev(PRFileDesc *fd,
|
|||
{
|
||||
int32_t ret;
|
||||
ret = fd->lower->methods->writev(fd->lower, iov, size, timeout);
|
||||
if (ret > 0)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
|
||||
if (ret > 0) {
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, size);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -69,8 +96,9 @@ nsNetMon_Recv(PRFileDesc *fd,
|
|||
{
|
||||
int32_t ret;
|
||||
ret = fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout);
|
||||
if (ret >= 0)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
|
||||
if (ret >= 0) {
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, fd, amount);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -83,8 +111,9 @@ nsNetMon_Send(PRFileDesc *fd,
|
|||
{
|
||||
int32_t ret;
|
||||
ret = fd->lower->methods->send(fd->lower, buf, amount, flags, timeout);
|
||||
if (ret > 0)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
|
||||
if (ret > 0) {
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, amount);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -103,8 +132,9 @@ nsNetMon_RecvFrom(PRFileDesc *fd,
|
|||
flags,
|
||||
addr,
|
||||
timeout);
|
||||
if (ret >= 0)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
|
||||
if (ret >= 0) {
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, fd, amount);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -123,8 +153,9 @@ nsNetMon_SendTo(PRFileDesc *fd,
|
|||
flags,
|
||||
addr,
|
||||
timeout);
|
||||
if (ret > 0)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
|
||||
if (ret > 0) {
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload, fd, amount);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -143,88 +174,182 @@ nsNetMon_AcceptRead(PRFileDesc *listenSock,
|
|||
buf,
|
||||
amount,
|
||||
timeout);
|
||||
if (ret > 0)
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
|
||||
if (ret > 0) {
|
||||
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload, listenSock, amount);
|
||||
}
|
||||
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 {
|
||||
public:
|
||||
explicit NotifyNetworkActivity(NetworkActivityMonitor::Direction aDirection)
|
||||
explicit NotifyNetworkActivity(NetworkActivity* aActivity)
|
||||
: 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());
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (!obs)
|
||||
return NS_ERROR_FAILURE;
|
||||
if (mActivities.Length() == 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
obs->NotifyObservers(nullptr,
|
||||
mDirection == NetworkActivityMonitor::kUpload
|
||||
? NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC
|
||||
: NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC,
|
||||
nullptr);
|
||||
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);
|
||||
|
||||
nsresult rv = array->AppendElement(data);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
obs->NotifyObservers(array, NS_NETWORK_ACTIVITY, nullptr);
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
NetworkActivityMonitor::Direction mDirection;
|
||||
nsTArray<SocketActivity> mActivities;
|
||||
};
|
||||
|
||||
NetworkActivityMonitor * NetworkActivityMonitor::gInstance = nullptr;
|
||||
|
||||
mozilla::StaticRefPtr<NetworkActivityMonitor> gInstance;
|
||||
static PRDescIdentity sNetActivityMonitorLayerIdentity;
|
||||
static PRIOMethods sNetActivityMonitorLayerMethods;
|
||||
static PRIOMethods *sNetActivityMonitorLayerMethodsPtr = nullptr;
|
||||
NS_IMPL_ISUPPORTS(NetworkActivityMonitor, nsITimerCallback, nsINamed)
|
||||
|
||||
NetworkActivityMonitor::NetworkActivityMonitor()
|
||||
: mBlipInterval(PR_INTERVAL_NO_TIMEOUT)
|
||||
: mInterval(PR_INTERVAL_NO_TIMEOUT)
|
||||
, mLock("NetworkActivityMonitor::mLock")
|
||||
{
|
||||
MOZ_COUNT_CTOR(NetworkActivityMonitor);
|
||||
|
||||
NS_ASSERTION(gInstance==nullptr,
|
||||
"multiple NetworkActivityMonitor instances!");
|
||||
RefPtr<NetworkActivityMonitor> mon(gInstance);
|
||||
MOZ_ASSERT(!mon, "multiple NetworkActivityMonitor instances!");
|
||||
}
|
||||
|
||||
NetworkActivityMonitor::~NetworkActivityMonitor()
|
||||
NS_IMETHODIMP
|
||||
NetworkActivityMonitor::Notify(nsITimer* aTimer)
|
||||
{
|
||||
MOZ_COUNT_DTOR(NetworkActivityMonitor);
|
||||
gInstance = nullptr;
|
||||
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);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NetworkActivityMonitor::GetName(nsACString& aName)
|
||||
{
|
||||
aName.AssignLiteral("NetworkActivityMonitor");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
NetworkActivityMonitor::Init(int32_t blipInterval)
|
||||
NetworkActivityMonitor::Init(int32_t aInterval)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (gInstance)
|
||||
nsresult rv = NS_OK;
|
||||
RefPtr<NetworkActivityMonitor> mon(gInstance);
|
||||
if (mon) {
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
|
||||
NetworkActivityMonitor * mon = new NetworkActivityMonitor();
|
||||
rv = mon->Init_Internal(blipInterval);
|
||||
if (NS_FAILED(rv)) {
|
||||
delete mon;
|
||||
return rv;
|
||||
}
|
||||
|
||||
} else {
|
||||
mon = new NetworkActivityMonitor();
|
||||
rv = mon->Init_Internal(aInterval);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
gInstance = mon;
|
||||
return NS_OK;
|
||||
} else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NetworkActivityMonitor::Shutdown()
|
||||
{
|
||||
if (!gInstance)
|
||||
RefPtr<NetworkActivityMonitor> mon(gInstance);
|
||||
if (!mon) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
delete gInstance;
|
||||
}
|
||||
mon->Shutdown_Internal();
|
||||
gInstance = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NetworkActivityMonitor::Init_Internal(int32_t blipInterval)
|
||||
NetworkActivityMonitor::Init_Internal(int32_t aInterval)
|
||||
{
|
||||
if (!sNetActivityMonitorLayerMethodsPtr) {
|
||||
sNetActivityMonitorLayerIdentity =
|
||||
|
@ -239,27 +364,35 @@ NetworkActivityMonitor::Init_Internal(int32_t blipInterval)
|
|||
sNetActivityMonitorLayerMethods.recvfrom = nsNetMon_RecvFrom;
|
||||
sNetActivityMonitorLayerMethods.sendto = nsNetMon_SendTo;
|
||||
sNetActivityMonitorLayerMethods.acceptread = nsNetMon_AcceptRead;
|
||||
sNetActivityMonitorLayerMethods.close = nsNetMon_Close;
|
||||
sNetActivityMonitorLayerMethodsPtr = &sNetActivityMonitorLayerMethods;
|
||||
}
|
||||
|
||||
mBlipInterval = PR_MillisecondsToInterval(blipInterval);
|
||||
// Set the last notification times to time that has just expired, so any
|
||||
// activity even right now will trigger notification.
|
||||
mLastNotificationTime[kUpload] = PR_IntervalNow() - mBlipInterval;
|
||||
mLastNotificationTime[kDownload] = mLastNotificationTime[kUpload];
|
||||
// create and fire the timer
|
||||
mInterval = aInterval;
|
||||
mTimer = NS_NewTimer();
|
||||
if (!mTimer) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return mTimer->InitWithCallback(this, mInterval, nsITimer::TYPE_REPEATING_SLACK);
|
||||
}
|
||||
|
||||
nsresult
|
||||
NetworkActivityMonitor::Shutdown_Internal()
|
||||
{
|
||||
mTimer->Cancel();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NetworkActivityMonitor::AttachIOLayer(PRFileDesc *fd)
|
||||
{
|
||||
if (!gInstance)
|
||||
RefPtr<NetworkActivityMonitor> mon(gInstance);
|
||||
if (!mon) {
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
PRFileDesc * layer;
|
||||
PRStatus status;
|
||||
|
||||
layer = PR_CreateIOLayerStub(sNetActivityMonitorLayerIdentity,
|
||||
sNetActivityMonitorLayerMethodsPtr);
|
||||
if (!layer) {
|
||||
|
@ -277,25 +410,102 @@ NetworkActivityMonitor::AttachIOLayer(PRFileDesc *fd)
|
|||
}
|
||||
|
||||
nsresult
|
||||
NetworkActivityMonitor::DataInOut(Direction direction)
|
||||
{
|
||||
NetworkActivityMonitor::RegisterFd(PRFileDesc *aFd, const PRNetAddr *aAddr) {
|
||||
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) {
|
||||
PRIntervalTime now = PR_IntervalNow();
|
||||
if ((now - gInstance->mLastNotificationTime[direction]) >
|
||||
gInstance->mBlipInterval) {
|
||||
gInstance->mLastNotificationTime[direction] = now;
|
||||
gInstance->PostNotification(direction);
|
||||
nsresult
|
||||
NetworkActivityMonitor::UnregisterFd(PRFileDesc *aFd)
|
||||
{
|
||||
nsresult rv;
|
||||
PROsfd osfd = PR_FileDesc2NativeHandle(aFd);
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
NetworkActivityMonitor::PostNotification(Direction direction)
|
||||
|
||||
nsresult
|
||||
NetworkActivityMonitor::RegisterFd_Internal(PROsfd aOsfd, const nsString& host, uint16_t port)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> ev = new NotifyNetworkActivity(direction);
|
||||
NS_DispatchToMainThread(ev);
|
||||
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;
|
||||
}
|
||||
|
||||
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___
|
||||
#define NetworkActivityMonitor_h___
|
||||
|
||||
#include <stdint.h>
|
||||
#include "nsCOMPtr.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 "prio.h"
|
||||
#include "private/pprio.h"
|
||||
#include <stdint.h>
|
||||
|
||||
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:
|
||||
enum Direction {
|
||||
|
@ -23,21 +65,28 @@ public:
|
|||
};
|
||||
|
||||
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 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:
|
||||
nsresult Init_Internal(int32_t blipInterval);
|
||||
void PostNotification(Direction direction);
|
||||
|
||||
static NetworkActivityMonitor * gInstance;
|
||||
PRIntervalTime mBlipInterval;
|
||||
PRIntervalTime mLastNotificationTime[2];
|
||||
virtual ~NetworkActivityMonitor() = 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;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
|
|
@ -62,6 +62,7 @@ XPIDL_SOURCES += [
|
|||
'nsINestedURI.idl',
|
||||
'nsINetAddr.idl',
|
||||
'nsINetUtil.idl',
|
||||
'nsINetworkActivityData.idl',
|
||||
'nsINetworkInfoService.idl',
|
||||
'nsINetworkInterceptController.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++
|
||||
/*
|
||||
* Network activity indicator: we send out these topics no more than every
|
||||
* blipIntervalMilliseconds (as set by the
|
||||
* "network.activity.blipIntervalMilliseconds" preference: if 0 no notifications
|
||||
* Network 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).
|
||||
*/
|
||||
#define NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC "network-activity-blip-upload"
|
||||
#define NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC "network-activity-blip-download"
|
||||
#define NS_NETWORK_ACTIVITY "network-activity"
|
||||
|
||||
|
||||
%}
|
||||
|
|
|
@ -49,7 +49,7 @@ static Atomic<PRThread*, Relaxed> gSocketThread;
|
|||
#define KEEPALIVE_PROBE_COUNT_PREF "network.tcp.keepalive.probe_count"
|
||||
#define SOCKET_LIMIT_TARGET 1000U
|
||||
#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 TELEMETRY_PREF "toolkit.telemetry.enabled"
|
||||
#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")) {
|
||||
int32_t blipInterval = Preferences::GetInt(BLIP_INTERVAL_PREF, 0);
|
||||
if (blipInterval <= 0) {
|
||||
int32_t interval = Preferences::GetInt(INTERVAL_PREF, 0);
|
||||
if (interval <= 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return net::NetworkActivityMonitor::Init(blipInterval);
|
||||
return net::NetworkActivityMonitor::Init(interval);
|
||||
}
|
||||
|
||||
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
|
||||
../../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]
|
||||
|
|
|
@ -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");
|
||||
// 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
|
||||
// cause other tests to fail. Tests that wish to test the notification functionality
|
||||
|
|
Загрузка…
Ссылка в новой задаче