bug 904170 - telemetry for daily http data consumption r=jduell

This commit is contained in:
Patrick McManus 2013-09-22 23:01:10 -04:00
parent 1da3704a92
commit 176a4657e1
12 changed files with 589 additions and 18 deletions

View File

@ -378,6 +378,8 @@
@BINPATH@/components/PeerConnection.js @BINPATH@/components/PeerConnection.js
@BINPATH@/components/PeerConnection.manifest @BINPATH@/components/PeerConnection.manifest
#endif #endif
@BINPATH@/components/HttpDataUsage.manifest
@BINPATH@/components/HttpDataUsage.js
@BINPATH@/components/SiteSpecificUserAgent.js @BINPATH@/components/SiteSpecificUserAgent.js
@BINPATH@/components/SiteSpecificUserAgent.manifest @BINPATH@/components/SiteSpecificUserAgent.manifest
@BINPATH@/components/storage-Legacy.js @BINPATH@/components/storage-Legacy.js

View File

@ -544,6 +544,9 @@
@BINPATH@/components/PeerConnection.manifest @BINPATH@/components/PeerConnection.manifest
#endif #endif
@BINPATH@/components/HttpDataUsage.manifest
@BINPATH@/components/HttpDataUsage.js
@BINPATH@/chrome/marionette@JAREXT@ @BINPATH@/chrome/marionette@JAREXT@
@BINPATH@/chrome/marionette.manifest @BINPATH@/chrome/marionette.manifest
@BINPATH@/components/MarionetteComponents.manifest @BINPATH@/components/MarionetteComponents.manifest

View File

@ -406,6 +406,9 @@
@BINPATH@/components/PeerConnection.manifest @BINPATH@/components/PeerConnection.manifest
#endif #endif
@BINPATH@/components/HttpDataUsage.manifest
@BINPATH@/components/HttpDataUsage.js
#ifdef MOZ_SERVICES_HEALTHREPORT #ifdef MOZ_SERVICES_HEALTHREPORT
@BINPATH@/components/HealthReportComponents.manifest @BINPATH@/components/HealthReportComponents.manifest
@BINPATH@/components/HealthReportService.js @BINPATH@/components/HealthReportService.js

View File

@ -0,0 +1,222 @@
/* -*- indent-tabs-mode: nil -*- */
/* 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/. */
/* HTTPDATA_* telemetry producer
every 3 minutes of idle time we update a data file and report it
once a day. this avoids adding io to the shutdown path
*/
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
const CC = Components.Constructor;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "idleService",
"@mozilla.org/widget/idleservice;1",
"nsIIdleService");
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
const MB = 1000000;
var gDataUsage;
function HttpDataUsage() {}
HttpDataUsage.prototype = {
classID: Components.ID("{6d72bfca-2747-4859-887f-6f06d4ce6787}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
contractID: "@mozilla.org/network/HttpDataUsage;1",
_isIdleObserver: false,
_locked : false,
_do_telemetry : false,
_idle_timeout : 60 * 3,
_quanta : 86400000, // per day
_logtime : new Date(),
_ethernetRead : 0,
_ethernetWritten : 0,
_cellRead : 0,
_cellWritten : 0,
_dataFile : FileUtils.getFile("ProfD", ["httpDataUsage.dat"], true),
_dataUsage : Cc["@mozilla.org/network/protocol;1?name=http"]
.getService(Ci.nsIHttpProtocolHandler)
.QueryInterface(Ci.nsIHttpDataUsage),
_pipe : CC("@mozilla.org/pipe;1", "nsIPipe", "init"),
_outputStream : CC("@mozilla.org/network/file-output-stream;1",
"nsIFileOutputStream", "init"),
setup: function setup() {
gDataUsage = this;
var enabled = false;
try {
if (Services.prefs.getBoolPref("toolkit.telemetry.enabled"))
enabled = true;
} catch (e) { }
try {
if (Services.prefs.getBoolPref("toolkit.telemetry.enabledPreRelease"))
enabled = true;
} catch (e) { }
// this isn't important enough to worry about getting a
// runtime telemetry config change for
if (!enabled)
return;
if (this._dataUsage == null)
return;
idleService.addIdleObserver(this, this._idle_timeout);
this._isIdleObserver = true;
},
shutdown: function shutdown() {
if (this._isIdleObserver)
idleService.removeIdleObserver(this, this._idle_timeout);
this._isIdleObserver = false;
},
sUpdateStats2: function sUpdateStats2(stream, result) {
gDataUsage.updateStats2(stream, result);
},
sGatherTelemetry2: function sGatherTelemetry2(stream, result) {
gDataUsage.gatherTelemetry2(stream, result);
},
readCounters: function readCounters(stream, result) {
if (Components.isSuccessCode(result)) {
let count = stream.available();
let data = NetUtil.readInputStreamToString(stream, count);
var list = data.split(",");
if (list.length == 5) {
this._logtime = new Date(Number(list[0]));
this._ethernetRead = Number(list[1]);
this._ethernetWritten = Number(list[2]);
this._cellRead = Number(list[3]);
this._cellWritten = Number(list[4]);
}
}
this._ethernetRead += this._dataUsage.ethernetBytesRead;
this._ethernetWritten += this._dataUsage.ethernetBytesWritten;
this._cellRead += this._dataUsage.cellBytesRead;
this._cellWritten += this._dataUsage.cellBytesWritten;
this._dataUsage.resetHttpDataUsage();
},
// writeCounters also releases the lock
writeCounters: function writeCounters() {
var dataout = this._logtime.getTime().toString() + "," +
this._ethernetRead.toString() + "," +
this._ethernetWritten.toString() + "," +
this._cellRead.toString() + "," +
this._cellWritten.toString() + "\n";
var buffer = new this._pipe(true, false, 4096, 1, null);
buffer.outputStream.write(dataout, dataout.length);
buffer.outputStream.close();
var fileOut = new this._outputStream(this._dataFile, -1, -1, 0);
NetUtil.asyncCopy(buffer.inputStream, fileOut,
function (result) { gDataUsage.finishedWriting(); });
},
updateStats2: function updateStats2(stream, result) {
this.readCounters(stream, result);
this.writeCounters();
},
gatherTelemetry2: function gatherTelemetry2(stream, result) {
this.readCounters(stream, result);
var now = new Date();
var elapsed = now.getTime() - this._logtime.getTime();
// make sure we have at least 1 day of data
if (elapsed < this._quanta) {
this.finishedWriting();
return;
}
var days = elapsed / this._quanta;
var eInPerQuanta = Math.floor(this._ethernetRead / days);
var eOutPerQuanta = Math.floor(this._ethernetWritten / days);
var cInPerQuanta = Math.floor(this._cellRead / days);
var cOutPerQuanta = Math.floor(this._cellWritten / days);
var histogram;
while (elapsed >= this._quanta) {
histogram = Services.telemetry.getHistogramById("HTTPDATA_DAILY_ETHERNET_IN");
histogram.add(Math.round(eInPerQuanta / MB));
histogram = Services.telemetry.getHistogramById("HTTPDATA_DAILY_ETHERNET_OUT");
histogram.add(Math.round(eOutPerQuanta / MB));
histogram = Services.telemetry.getHistogramById("HTTPDATA_DAILY_CELL_IN");
histogram.add(Math.round(cInPerQuanta / MB));
histogram = Services.telemetry.getHistogramById("HTTPDATA_DAILY_CELL_OUT");
histogram.add(Math.round(cOutPerQuanta / MB));
elapsed -= this._quanta;
this._ethernetRead -= eInPerQuanta;
this._ethernetWritten -= eOutPerQuanta;
this._cellRead -= cInPerQuanta;
this._cellWritten -= cOutPerQuanta;
}
this._logtime = new Date(now.getTime() - elapsed);
this.writeCounters();
},
finishedWriting : function finishedWriting() {
this._locked = false;
if (this._do_telemetry) {
this._do_telemetry = false;
this.gatherTelemetry();
}
},
updateStats: function updateStats() {
if (this._locked)
return;
this._locked = true;
NetUtil.asyncFetch(this._dataFile, this.sUpdateStats2);
},
gatherTelemetry: function gatherTelemetry() {
if (this._locked)
return; // oh well, maybe next time
this._locked = true;
NetUtil.asyncFetch(this._dataFile, this.sGatherTelemetry2);
},
observe: function (aSubject, aTopic, aData) {
switch (aTopic) {
case "profile-after-change":
this.setup();
break;
case "gather-telemetry":
this._do_telemetry = true;
this.updateStats();
break;
case "idle":
this.updateStats();
break;
case "profile-change-net-teardown":
this.shutdown();
break;
}
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([HttpDataUsage]);

View File

@ -0,0 +1,3 @@
component {6d72bfca-2747-4859-887f-6f06d4ce6787} HttpDataUsage.js
contract @mozilla.org/network/HttpDataUsage;1 {6d72bfca-2747-4859-887f-6f06d4ce6787}
category profile-after-change HttpDataUsage @mozilla.org/network/HttpDataUsage;1

View File

@ -13,6 +13,7 @@ XPIDL_SOURCES += [
'nsIHttpChannelAuthProvider.idl', 'nsIHttpChannelAuthProvider.idl',
'nsIHttpChannelChild.idl', 'nsIHttpChannelChild.idl',
'nsIHttpChannelInternal.idl', 'nsIHttpChannelInternal.idl',
'nsIHttpDataUsage.idl',
'nsIHttpEventSink.idl', 'nsIHttpEventSink.idl',
'nsIHttpHeaderVisitor.idl', 'nsIHttpHeaderVisitor.idl',
'nsIHttpProtocolHandler.idl', 'nsIHttpProtocolHandler.idl',
@ -81,6 +82,11 @@ EXTRA_JS_MODULES += [
'UserAgentUpdates.jsm', 'UserAgentUpdates.jsm',
] ]
EXTRA_COMPONENTS += [
'HttpDataUsage.js',
'HttpDataUsage.manifest',
]
FAIL_ON_WARNINGS = True FAIL_ON_WARNINGS = True
LIBXUL_LIBRARY = True LIBXUL_LIBRARY = True

View File

@ -46,6 +46,8 @@ nsHttpConnection::nsHttpConnection()
, mMaxBytesRead(0) , mMaxBytesRead(0)
, mTotalBytesRead(0) , mTotalBytesRead(0)
, mTotalBytesWritten(0) , mTotalBytesWritten(0)
, mUnreportedBytesRead(0)
, mUnreportedBytesWritten(0)
, mKeepAlive(true) // assume to keep-alive by default , mKeepAlive(true) // assume to keep-alive by default
, mKeepAliveMask(true) , mKeepAliveMask(true)
, mDontReuse(false) , mDontReuse(false)
@ -75,6 +77,7 @@ nsHttpConnection::~nsHttpConnection()
{ {
LOG(("Destroying nsHttpConnection @%x\n", this)); LOG(("Destroying nsHttpConnection @%x\n", this));
ReportDataUsage(false);
if (!mEverUsedSpdy) { if (!mEverUsedSpdy) {
LOG(("nsHttpConnection %p performed %d HTTP/1.x transactions\n", LOG(("nsHttpConnection %p performed %d HTTP/1.x transactions\n",
this, mHttp1xTransactionCount)); this, mHttp1xTransactionCount));
@ -1182,6 +1185,8 @@ nsHttpConnection::CloseTransaction(nsAHttpTransaction *trans, nsresult reason)
mCallbacks = nullptr; mCallbacks = nullptr;
} }
ReportDataUsage(false);
if (NS_FAILED(reason)) if (NS_FAILED(reason))
Close(reason); Close(reason);
@ -1224,8 +1229,11 @@ nsHttpConnection::OnReadSegment(const char *buf,
else { else {
mLastWriteTime = PR_IntervalNow(); mLastWriteTime = PR_IntervalNow();
mSocketOutCondition = NS_OK; // reset condition mSocketOutCondition = NS_OK; // reset condition
if (!mProxyConnectInProgress) if (!mProxyConnectInProgress) {
mTotalBytesWritten += *countRead; mTotalBytesWritten += *countRead;
mUnreportedBytesWritten += *countRead;
ReportDataUsage(true);
}
} }
return mSocketOutCondition; return mSocketOutCondition;
@ -1443,6 +1451,8 @@ nsHttpConnection::OnSocketReadable()
else { else {
mCurrentBytesRead += n; mCurrentBytesRead += n;
mTotalBytesRead += n; mTotalBytesRead += n;
mUnreportedBytesRead += n;
ReportDataUsage(true);
if (NS_FAILED(mSocketInCondition)) { if (NS_FAILED(mSocketInCondition)) {
// continue waiting for the socket if necessary... // continue waiting for the socket if necessary...
if (mSocketInCondition == NS_BASE_STREAM_WOULD_BLOCK) if (mSocketInCondition == NS_BASE_STREAM_WOULD_BLOCK)
@ -1507,6 +1517,27 @@ nsHttpConnection::SetupProxyConnect()
return NS_NewCStringInputStream(getter_AddRefs(mProxyConnectStream), buf); return NS_NewCStringInputStream(getter_AddRefs(mProxyConnectStream), buf);
} }
void
nsHttpConnection::ReportDataUsage(bool allowDefer)
{
static const uint64_t kDeferThreshold = 128000;
if (!mUnreportedBytesRead && !mUnreportedBytesWritten)
return;
if (!gHttpHandler->IsTelemetryEnabled())
return;
if (allowDefer &&
(mUnreportedBytesRead + mUnreportedBytesWritten) < kDeferThreshold) {
return;
}
gHttpHandler->UpdateDataUsage(mCallbacks,
mUnreportedBytesRead, mUnreportedBytesWritten);
mUnreportedBytesRead = mUnreportedBytesWritten = 0;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// nsHttpConnection::nsISupports // nsHttpConnection::nsISupports
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -193,6 +193,9 @@ private:
// Directly Add a transaction to an active connection for SPDY // Directly Add a transaction to an active connection for SPDY
nsresult AddTransaction(nsAHttpTransaction *, int32_t); nsresult AddTransaction(nsAHttpTransaction *, int32_t);
// used to inform nsIHttpDataUsage of transfer
void ReportDataUsage(bool);
private: private:
nsCOMPtr<nsISocketTransport> mSocketTransport; nsCOMPtr<nsISocketTransport> mSocketTransport;
nsCOMPtr<nsIAsyncInputStream> mSocketIn; nsCOMPtr<nsIAsyncInputStream> mSocketIn;
@ -226,6 +229,10 @@ private:
int64_t mTotalBytesRead; // total data read int64_t mTotalBytesRead; // total data read
int64_t mTotalBytesWritten; // does not include CONNECT tunnel int64_t mTotalBytesWritten; // does not include CONNECT tunnel
// for nsIHttpDataUsage
uint64_t mUnreportedBytesRead; // subset of totalBytesRead
uint64_t mUnreportedBytesWritten; // subset of totalBytesWritten
nsRefPtr<nsIAsyncInputStream> mInputOverflow; nsRefPtr<nsIAsyncInputStream> mInputOverflow;
PRIntervalTime mRtt; PRIntervalTime mRtt;

View File

@ -69,6 +69,10 @@
#include <os2.h> #include <os2.h>
#endif #endif
#if defined(MOZ_WIDGET_GONK)
#include "nsINetworkManager.h"
#endif
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
using namespace mozilla; using namespace mozilla;
using namespace mozilla::net; using namespace mozilla::net;
@ -198,6 +202,12 @@ nsHttpHandler::nsHttpHandler()
, mRequestTokenBucketHz(100) , mRequestTokenBucketHz(100)
, mRequestTokenBucketBurst(32) , mRequestTokenBucketBurst(32)
, mCritialRequestPrioritization(true) , mCritialRequestPrioritization(true)
, mEthernetBytesRead(0)
, mEthernetBytesWritten(0)
, mCellBytesRead(0)
, mCellBytesWritten(0)
, mNetworkTypeKnown(false)
, mNetworkTypeWasEthernet(true)
{ {
#if defined(PR_LOGGING) #if defined(PR_LOGGING)
gHttpLog = PR_NewLogModule("nsHttp"); gHttpLog = PR_NewLogModule("nsHttp");
@ -1505,13 +1515,14 @@ nsHttpHandler::SetAcceptEncodings(const char *aAcceptEncodings)
// nsHttpHandler::nsISupports // nsHttpHandler::nsISupports
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
NS_IMPL_ISUPPORTS6(nsHttpHandler, NS_IMPL_ISUPPORTS7(nsHttpHandler,
nsIHttpProtocolHandler, nsIHttpProtocolHandler,
nsIProxiedProtocolHandler, nsIProxiedProtocolHandler,
nsIProtocolHandler, nsIProtocolHandler,
nsIObserver, nsIObserver,
nsISupportsWeakReference, nsISupportsWeakReference,
nsISpeculativeConnect) nsISpeculativeConnect,
nsIHttpDataUsage)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// nsHttpHandler::nsIProtocolHandler // nsHttpHandler::nsIProtocolHandler
@ -1931,45 +1942,248 @@ nsHttpHandler::SpeculativeConnect(nsIURI *aURI,
return SpeculativeConnect(ci, aCallbacks); return SpeculativeConnect(ci, aCallbacks);
} }
void // nsIHttpDataUsage
nsHttpHandler::TickleWifi(nsIInterfaceRequestor *cb)
NS_IMETHODIMP
nsHttpHandler::GetEthernetBytesRead(uint64_t *aEthernetBytesRead)
{ {
if (!cb || !mWifiTickler) MOZ_ASSERT(NS_IsMainThread());
*aEthernetBytesRead = mEthernetBytesRead;
return NS_OK;
}
NS_IMETHODIMP
nsHttpHandler::GetEthernetBytesWritten(uint64_t *aEthernetBytesWritten)
{
MOZ_ASSERT(NS_IsMainThread());
*aEthernetBytesWritten = mEthernetBytesWritten;
return NS_OK;
}
NS_IMETHODIMP
nsHttpHandler::GetCellBytesRead(uint64_t *aCellBytesRead)
{
MOZ_ASSERT(NS_IsMainThread());
*aCellBytesRead = mCellBytesRead;
return NS_OK;
}
NS_IMETHODIMP
nsHttpHandler::GetCellBytesWritten(uint64_t *aCellBytesWritten)
{
MOZ_ASSERT(NS_IsMainThread());
*aCellBytesWritten = mCellBytesWritten;
return NS_OK;
}
NS_IMETHODIMP
nsHttpHandler::ResetHttpDataUsage()
{
MOZ_ASSERT(NS_IsMainThread());
mEthernetBytesRead = mEthernetBytesWritten = 0;
mCellBytesRead = mCellBytesWritten = 0;
return NS_OK;
}
class DataUsageEvent : public nsRunnable
{
public:
explicit DataUsageEvent(nsIInterfaceRequestor *cb,
uint64_t bytesRead,
uint64_t bytesWritten)
: mCB(cb), mRead(bytesRead), mWritten(bytesWritten) { }
NS_IMETHOD Run() MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
if (gHttpHandler)
gHttpHandler->UpdateDataUsage(mCB, mRead, mWritten);
return NS_OK;
}
private:
~DataUsageEvent() { }
nsCOMPtr<nsIInterfaceRequestor> mCB;
uint64_t mRead;
uint64_t mWritten;
};
void
nsHttpHandler::UpdateDataUsage(nsIInterfaceRequestor *cb,
uint64_t bytesRead, uint64_t bytesWritten)
{
if (!IsTelemetryEnabled())
return; return;
// If B2G requires a similar mechanism nsINetworkManager, currently only avail if (!NS_IsMainThread()) {
// on B2G, contains the necessary information on wifi and gateway nsRefPtr<nsIRunnable> event = new DataUsageEvent(cb, bytesRead, bytesWritten);
NS_DispatchToMainThread(event);
return;
}
bool isEthernet = true;
if (NS_FAILED(GetNetworkEthernetInfo(cb, &isEthernet))) {
// without a window it is hard for android to determine the network type
// so on failures we will just use the last value
if (!mNetworkTypeKnown)
return;
isEthernet = mNetworkTypeWasEthernet;
}
if (isEthernet) {
mEthernetBytesRead += bytesRead;
mEthernetBytesWritten += bytesWritten;
} else {
mCellBytesRead += bytesRead;
mCellBytesWritten += bytesWritten;
}
}
nsresult
nsHttpHandler::GetNetworkEthernetInfo(nsIInterfaceRequestor *cb,
bool *aEthernet)
{
NS_ENSURE_ARG_POINTER(aEthernet);
nsresult rv = GetNetworkEthernetInfoInner(cb, aEthernet);
if (NS_SUCCEEDED(rv)) {
mNetworkTypeKnown = true;
mNetworkTypeWasEthernet = *aEthernet;
}
return rv;
}
// aEthernet and aGateway are required out parameters
// on b2g and desktop gateway cannot be determined yet and
// this function returns ERROR_NOT_IMPLEMENTED.
nsresult
nsHttpHandler::GetNetworkInfo(nsIInterfaceRequestor *cb,
bool *aEthernet,
uint32_t *aGateway)
{
NS_ENSURE_ARG_POINTER(aEthernet);
NS_ENSURE_ARG_POINTER(aGateway);
nsresult rv = GetNetworkInfoInner(cb, aEthernet, aGateway);
if (NS_SUCCEEDED(rv)) {
mNetworkTypeKnown = true;
mNetworkTypeWasEthernet = *aEthernet;
}
return rv;
}
nsresult
nsHttpHandler::GetNetworkInfoInner(nsIInterfaceRequestor *cb,
bool *aEthernet,
uint32_t *aGateway)
{
NS_ENSURE_ARG_POINTER(aEthernet);
NS_ENSURE_ARG_POINTER(aGateway);
*aGateway = 0;
*aEthernet = true;
#if defined(MOZ_WIDGET_GONK)
// b2g only allows you to ask for ethernet or not right now.
return NS_ERROR_NOT_IMPLEMENTED;
#endif
#if defined(ANDROID)
if (!cb)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMWindow> domWindow; nsCOMPtr<nsIDOMWindow> domWindow;
cb->GetInterface(NS_GET_IID(nsIDOMWindow), getter_AddRefs(domWindow)); cb->GetInterface(NS_GET_IID(nsIDOMWindow), getter_AddRefs(domWindow));
if (!domWindow) if (!domWindow)
return; return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNavigator> domNavigator; nsCOMPtr<nsIDOMNavigator> domNavigator;
domWindow->GetNavigator(getter_AddRefs(domNavigator)); domWindow->GetNavigator(getter_AddRefs(domNavigator));
nsCOMPtr<nsIMozNavigatorNetwork> networkNavigator = nsCOMPtr<nsIMozNavigatorNetwork> networkNavigator =
do_QueryInterface(domNavigator); do_QueryInterface(domNavigator);
if (!networkNavigator) if (!networkNavigator)
return; return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMMozConnection> mozConnection; nsCOMPtr<nsIDOMMozConnection> mozConnection;
networkNavigator->GetMozConnection(getter_AddRefs(mozConnection)); networkNavigator->GetMozConnection(getter_AddRefs(mozConnection));
nsCOMPtr<nsINetworkProperties> networkProperties = nsCOMPtr<nsINetworkProperties> networkProperties =
do_QueryInterface(mozConnection); do_QueryInterface(mozConnection);
if (!networkProperties) if (!networkProperties)
return NS_ERROR_FAILURE;
nsresult rv;
rv = networkProperties->GetDhcpGateway(aGateway);
if (NS_FAILED(rv))
return rv;
return networkProperties->GetIsWifi(aEthernet);
#endif
// desktop does not currently know about the gateway
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsHttpHandler::GetNetworkEthernetInfoInner(nsIInterfaceRequestor *cb,
bool *aEthernet)
{
*aEthernet = true;
#if defined(MOZ_WIDGET_GONK)
int32_t networkType;
nsCOMPtr<nsINetworkManager> networkManager =
do_GetService("@mozilla.org/network/manager;1");
if (!networkManager)
return NS_ERROR_FAILURE;
if (NS_FAILED(networkManager->GetPreferredNetworkType(&networkType)))
return NS_ERROR_FAILURE;
*aEthernet = networkType == nsINetworkInterface::NETWORK_TYPE_WIFI;
return NS_OK;
#endif
#if defined(ANDROID)
if (!cb)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMWindow> domWindow;
cb->GetInterface(NS_GET_IID(nsIDOMWindow), getter_AddRefs(domWindow));
if (!domWindow)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNavigator> domNavigator;
domWindow->GetNavigator(getter_AddRefs(domNavigator));
nsCOMPtr<nsIMozNavigatorNetwork> networkNavigator =
do_QueryInterface(domNavigator);
if (!networkNavigator)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMMozConnection> mozConnection;
networkNavigator->GetMozConnection(getter_AddRefs(mozConnection));
nsCOMPtr<nsINetworkProperties> networkProperties =
do_QueryInterface(mozConnection);
if (!networkProperties)
return NS_ERROR_FAILURE;
return networkProperties->GetIsWifi(aEthernet);
#endif
// desktop assumes never on cell data
*aEthernet = true;
return NS_OK;
}
void
nsHttpHandler::TickleWifi(nsIInterfaceRequestor *cb)
{
if (!cb || !mWifiTickler)
return; return;
uint32_t gwAddress; uint32_t gwAddress;
bool isWifi; bool isWifi;
nsresult rv;
rv = networkProperties->GetDhcpGateway(&gwAddress); nsresult rv = GetNetworkInfo(cb, &isWifi, &gwAddress);
if (NS_SUCCEEDED(rv)) if (NS_FAILED(rv) || !gwAddress || !isWifi)
rv = networkProperties->GetIsWifi(&isWifi);
if (NS_FAILED(rv))
return;
if (!gwAddress || !isWifi)
return; return;
mWifiTickler->SetIPV4Address(gwAddress); mWifiTickler->SetIPV4Address(gwAddress);

View File

@ -15,6 +15,7 @@
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsWeakReference.h" #include "nsWeakReference.h"
#include "nsIHttpDataUsage.h"
#include "nsIHttpProtocolHandler.h" #include "nsIHttpProtocolHandler.h"
#include "nsIObserver.h" #include "nsIObserver.h"
#include "nsISpeculativeConnect.h" #include "nsISpeculativeConnect.h"
@ -50,6 +51,7 @@ class nsHttpHandler : public nsIHttpProtocolHandler
, public nsIObserver , public nsIObserver
, public nsSupportsWeakReference , public nsSupportsWeakReference
, public nsISpeculativeConnect , public nsISpeculativeConnect
, public nsIHttpDataUsage
{ {
public: public:
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
@ -58,6 +60,7 @@ public:
NS_DECL_NSIHTTPPROTOCOLHANDLER NS_DECL_NSIHTTPPROTOCOLHANDLER
NS_DECL_NSIOBSERVER NS_DECL_NSIOBSERVER
NS_DECL_NSISPECULATIVECONNECT NS_DECL_NSISPECULATIVECONNECT
NS_DECL_NSIHTTPDATAUSAGE
nsHttpHandler(); nsHttpHandler();
virtual ~nsHttpHandler(); virtual ~nsHttpHandler();
@ -473,8 +476,30 @@ public:
} }
private: private:
// for nsIHttpDataUsage
uint64_t mEthernetBytesRead;
uint64_t mEthernetBytesWritten;
uint64_t mCellBytesRead;
uint64_t mCellBytesWritten;
bool mNetworkTypeKnown;
bool mNetworkTypeWasEthernet;
nsRefPtr<mozilla::net::Tickler> mWifiTickler; nsRefPtr<mozilla::net::Tickler> mWifiTickler;
nsresult GetNetworkEthernetInfo(nsIInterfaceRequestor *cb,
bool *ethernet);
nsresult GetNetworkEthernetInfoInner(nsIInterfaceRequestor *cb,
bool *ethernet);
nsresult GetNetworkInfo(nsIInterfaceRequestor *cb,
bool *ethernet, uint32_t *gw);
nsresult GetNetworkInfoInner(nsIInterfaceRequestor *cb,
bool *ethernet, uint32_t *gw);
void TickleWifi(nsIInterfaceRequestor *cb); void TickleWifi(nsIInterfaceRequestor *cb);
public:
// this is called to update the member variables used for nsIHttpDataUsage
// it can be called from any thread
void UpdateDataUsage(nsIInterfaceRequestor *cb,
uint64_t bytesRead, uint64_t bytesWritten);
}; };
extern nsHttpHandler *gHttpHandler; extern nsHttpHandler *gHttpHandler;

View File

@ -0,0 +1,27 @@
/* -*- 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/. */
#include "nsISupports.idl"
/**
* nsIHttpDataUsage contains counters for the amount of HTTP data transferred
* in and out of this session since the last time it was reset with the
* resetHttpDataUsage() method. These counters are normally reset on each
* telemetry ping.
*
* Data is split into ethernet and cell. ethernet includes wifi.
*
*/
[scriptable, uuid(79dee3eb-9323-4d5c-b0a8-1baa18934d9e)]
interface nsIHttpDataUsage : nsISupports
{
readonly attribute unsigned long long ethernetBytesRead;
readonly attribute unsigned long long ethernetBytesWritten;
readonly attribute unsigned long long cellBytesRead;
readonly attribute unsigned long long cellBytesWritten;
void resetHttpDataUsage();
};

View File

@ -869,6 +869,34 @@
"kind": "boolean", "kind": "boolean",
"description": "Whether a HTTP base page load was over SSL or not." "description": "Whether a HTTP base page load was over SSL or not."
}, },
"HTTPDATA_DAILY_ETHERNET_IN": {
"kind": "exponential",
"high": "10000",
"n_buckets": 200,
"extended_statistics_ok": true,
"description": "MB of http ethernet data recvd in one day"
},
"HTTPDATA_DAILY_ETHERNET_OUT": {
"kind": "exponential",
"high": "10000",
"n_buckets": 200,
"extended_statistics_ok": true,
"description": "MB of http ethernet data sent in one day"
},
"HTTPDATA_DAILY_CELL_IN": {
"kind": "exponential",
"high": "10000",
"n_buckets": 200,
"extended_statistics_ok": true,
"description": "MB of http cell data recvd in one day"
},
"HTTPDATA_DAILY_CELL_OUT": {
"kind": "exponential",
"high": "10000",
"n_buckets": 200,
"extended_statistics_ok": true,
"description": "MB of http cell data sent in one day"
},
"SSL_HANDSHAKE_VERSION": { "SSL_HANDSHAKE_VERSION": {
"kind": "enumerated", "kind": "enumerated",
"n_values": 16, "n_values": 16,