Bug 777445 - Network activity indicator for B2G, r=jduell

This commit is contained in:
Michal Novotny 2012-09-28 13:53:52 +02:00
parent 971f193cff
commit 874dc9c6a2
8 changed files with 388 additions and 1 deletions

View File

@ -553,3 +553,9 @@ pref("ui.mouse.radius.enabled", true);
// Disable native prompt
pref("browser.prompt.allowNative", false);
// Minimum delay in milliseconds between network activity notifications (0 means
// 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", 250);

View File

@ -3745,3 +3745,9 @@ pref("dom.mozApps.maxLocalId", 1000);
// Let us know wether we should run the permissions update algorithm.
// See Bug 787439
pref("dom.mozApps.runUpdate", true);
// Minimum delay in milliseconds between network activity notifications (0 means
// 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);

View File

@ -37,3 +37,16 @@ interface nsPISocketTransportService : nsISocketTransportService
*/
attribute boolean offline;
};
%{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
* 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"
%}

View File

@ -67,6 +67,7 @@ CPPSRCS = \
nsPreloadedStream.cpp \
nsStreamListenerWrapper.cpp \
ProxyAutoConfig.cpp \
NetworkActivityMonitor.cpp \
$(NULL)
LOCAL_INCLUDES += -I$(topsrcdir)/dom/base

View File

@ -0,0 +1,294 @@
/* -*- 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 "prmem.h"
#include "nsIObserverService.h"
#include "nsPISocketTransportService.h"
#include "nsSocketTransportService2.h"
#include "nsThreadUtils.h"
#include "mozilla/Services.h"
#include "prerror.h"
using namespace mozilla::net;
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::DataInOut(NetworkActivityMonitor::kUpload);
return ret;
}
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);
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);
if (ret > 0)
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
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);
if (ret > 0)
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
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);
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);
if (ret > 0)
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
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);
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);
if (ret > 0)
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
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);
if (ret > 0)
NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
return ret;
}
class NotifyNetworkActivity : public nsRunnable {
public:
NotifyNetworkActivity(nsIObserverService* aObs,
NetworkActivityMonitor::Direction aDirection)
: mObs(aObs)
, mDirection(aDirection)
{}
NS_IMETHOD Run()
{
mObs->NotifyObservers(nullptr,
mDirection == NetworkActivityMonitor::kUpload
? NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC
: NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC,
nullptr);
return NS_OK;
}
private:
nsCOMPtr<nsIObserverService> mObs;
NetworkActivityMonitor::Direction mDirection;
};
NetworkActivityMonitor * NetworkActivityMonitor::gInstance = nullptr;
NetworkActivityMonitor::NetworkActivityMonitor()
: mLayerIdentity(PR_INVALID_IO_LAYER)
, mBlipInterval(PR_INTERVAL_NO_TIMEOUT)
, mLastNotificationTime({PR_INTERVAL_NO_TIMEOUT, PR_INTERVAL_NO_TIMEOUT})
{
NS_ASSERTION(gInstance==nullptr,
"multiple NetworkActivityMonitor instances!");
}
NetworkActivityMonitor::~NetworkActivityMonitor()
{
gInstance = nullptr;
}
nsresult
NetworkActivityMonitor::Init(int32_t blipInterval)
{
nsresult rv;
if (gInstance)
return NS_ERROR_ALREADY_INITIALIZED;
NetworkActivityMonitor * mon = new NetworkActivityMonitor();
rv = mon->Init_Internal(blipInterval);
if (NS_FAILED(rv)) {
delete mon;
return rv;
}
gInstance = mon;
return NS_OK;
}
nsresult
NetworkActivityMonitor::Shutdown()
{
if (!gInstance)
return NS_ERROR_NOT_INITIALIZED;
delete gInstance;
return NS_OK;
}
nsresult
NetworkActivityMonitor::Init_Internal(int32_t blipInterval)
{
mLayerIdentity = PR_GetUniqueIdentity("network activity monitor layer");
mLayerMethods = *PR_GetDefaultIOMethods();
mLayerMethods.connect = nsNetMon_Connect;
mLayerMethods.read = nsNetMon_Read;
mLayerMethods.write = nsNetMon_Write;
mLayerMethods.writev = nsNetMon_Writev;
mLayerMethods.recv = nsNetMon_Recv;
mLayerMethods.send = nsNetMon_Send;
mLayerMethods.recvfrom = nsNetMon_RecvFrom;
mLayerMethods.sendto = nsNetMon_SendTo;
mLayerMethods.acceptread = nsNetMon_AcceptRead;
mObserverService = mozilla::services::GetObserverService();
if (!mObserverService)
return NS_ERROR_FAILURE;
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];
return NS_OK;
}
nsresult
NetworkActivityMonitor::AttachIOLayer(PRFileDesc *fd)
{
if (!gInstance)
return NS_OK;
PRFileDesc * layer;
PRStatus status;
layer = PR_CreateIOLayerStub(gInstance->mLayerIdentity,
&gInstance->mLayerMethods);
if (!layer) {
return NS_ERROR_FAILURE;
}
status = PR_PushIOLayer(fd, PR_NSPR_IO_LAYER, layer);
if (status == PR_FAILURE) {
PR_DELETE(layer);
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
NetworkActivityMonitor::DataInOut(Direction direction)
{
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
if (gInstance) {
PRIntervalTime now = PR_IntervalNow();
if ((now - gInstance->mLastNotificationTime[direction]) >
gInstance->mBlipInterval) {
gInstance->mLastNotificationTime[direction] = now;
gInstance->PostNotification(direction);
}
}
return NS_OK;
}
void
NetworkActivityMonitor::PostNotification(Direction direction)
{
nsRefPtr<nsIRunnable> ev = new NotifyNetworkActivity(mObserverService,
direction);
NS_DispatchToMainThread(ev);
}

View File

@ -0,0 +1,49 @@
/* -*- 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___
#include "nsCOMPtr.h"
#include "prio.h"
#include "prinrval.h"
class nsIObserverService;
namespace mozilla { namespace net {
class NetworkActivityMonitor
{
public:
enum Direction {
kUpload = 0,
kDownload = 1
};
NetworkActivityMonitor();
~NetworkActivityMonitor();
static nsresult Init(int32_t blipInterval);
static nsresult Shutdown();
static nsresult AttachIOLayer(PRFileDesc *fd);
static nsresult DataInOut(Direction direction);
private:
nsresult Init_Internal(int32_t blipInterval);
void PostNotification(Direction direction);
static NetworkActivityMonitor * gInstance;
PRDescIdentity mLayerIdentity;
PRIOMethods mLayerMethods;
PRIntervalTime mBlipInterval;
PRIntervalTime mLastNotificationTime[2];
nsCOMPtr<nsIObserverService> mObserverService;
};
}} // namespace mozilla::net
#endif /* NetworkActivityMonitor_h___ */

View File

@ -24,6 +24,7 @@
#include "prnetdb.h"
#include "prerror.h"
#include "prerr.h"
#include "NetworkActivityMonitor.h"
#include "nsIServiceManager.h"
#include "nsISocketProviderService.h"
@ -1095,6 +1096,9 @@ nsSocketTransport::InitiateSocket()
return rv;
}
// Attach network activity monitor
mozilla::net::NetworkActivityMonitor::AttachIOLayer(fd);
PRStatus status;
// Make the socket non-blocking...

View File

@ -18,6 +18,7 @@
#include "nsIPrefBranch.h"
#include "nsServiceManagerUtils.h"
#include "nsIOService.h"
#include "NetworkActivityMonitor.h"
// XXX: There is no good header file to put these in. :(
@ -40,6 +41,7 @@ PRThread *gSocketThread = nullptr;
#define SEND_BUFFER_PREF "network.tcp.sendbuffer"
#define SOCKET_LIMIT_TARGET 550U
#define SOCKET_LIMIT_MIN 50U
#define BLIB_INTERVAL_PREF "network.activity.blipIntervalMilliseconds"
uint32_t nsSocketTransportService::gMaxCount;
PRCallOnceType nsSocketTransportService::gMaxCountInitOnce;
@ -455,8 +457,18 @@ nsSocketTransportService::Init()
}
nsCOMPtr<nsIPrefBranch> tmpPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (tmpPrefService)
if (tmpPrefService) {
tmpPrefService->AddObserver(SEND_BUFFER_PREF, this, false);
int32_t blipInterval = 0;
rv = tmpPrefService->GetIntPref(BLIB_INTERVAL_PREF, &blipInterval);
if (NS_SUCCEEDED(rv) && blipInterval > 0) {
rv = mozilla::net::NetworkActivityMonitor::Init(blipInterval);
if (NS_FAILED(rv)) {
NS_WARNING("Can't initialize NetworkActivityMonitor");
}
}
}
UpdatePrefs();
mInitialized = true;
@ -501,6 +513,8 @@ nsSocketTransportService::Shutdown()
if (tmpPrefService)
tmpPrefService->RemoveObserver(SEND_BUFFER_PREF, this);
mozilla::net::NetworkActivityMonitor::Shutdown();
mInitialized = false;
mShuttingDown = false;