зеркало из https://github.com/mozilla/gecko-dev.git
Bug 855951 - Collect and save TX/RX traffic amounts of TCP connections per-App, r=gene, mcmanus
This commit is contained in:
Родитель
0199f985ae
Коммит
9ea9589875
|
@ -27,7 +27,7 @@ interface nsISocketTransport;
|
|||
// Once bug 723206 will be fixed, this method could be replaced by
|
||||
// arguments when instantiating a TCPSocket object. For example it will
|
||||
// be possible to do (similarly to the WebSocket API):
|
||||
// var s = new MozTCPSocket(host, port);
|
||||
// var s = new MozTCPSocket(host, port);
|
||||
|
||||
// Bug 797561 - Expose a server tcp socket API to web applications
|
||||
|
||||
|
@ -215,7 +215,7 @@ interface nsIDOMTCPSocket : nsISupports
|
|||
* Needed to account for multiple possible types that can be provided to
|
||||
* the socket callbacks as arguments.
|
||||
*/
|
||||
[scriptable, uuid(0baa1be1-6a88-4f85-a6c8-29e95f35c122)]
|
||||
[scriptable, uuid(234c664c-3d6c-4859-b45c-4e9a98cb5bdc)]
|
||||
interface nsITCPSocketInternal : nsISupports {
|
||||
// Trigger the callback for |type| and provide a DOMError() object with the given data
|
||||
void callListenerError(in DOMString type, in DOMString name);
|
||||
|
@ -245,17 +245,20 @@ interface nsITCPSocketInternal : nsISupports {
|
|||
|
||||
// Create a DOM socket on the child side
|
||||
// This is called when the socket is accepted on the parent side.
|
||||
//
|
||||
//
|
||||
// @param socketChild
|
||||
// The socket child object for the IPC implementation.
|
||||
// @param binaryType
|
||||
// "arraybuffer" to use ArrayBuffer instances
|
||||
// "arraybuffer" to use ArrayBuffer instances
|
||||
// in the ondata callback and as the argument to send.
|
||||
// @param window
|
||||
// An object to create ArrayBuffer for this window. See Bug 831107.
|
||||
nsIDOMTCPSocket createAcceptedChild(in nsITCPSocketChild socketChild,
|
||||
in DOMString binaryType,
|
||||
in DOMString binaryType,
|
||||
in nsIDOMWindow window);
|
||||
|
||||
// Set App ID.
|
||||
void setAppId(in unsigned long appId);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,12 +38,13 @@ interface nsITCPSocketParent : nsISupports
|
|||
|
||||
// Intermediate class to handle sending multiple possible data types
|
||||
// and kicking off the chrome process socket object's connection.
|
||||
[scriptable, uuid(38bec1ed-b863-40dd-ba69-7bd92e568ee3)]
|
||||
[scriptable, uuid(be67b1b8-03b0-4171-a791-d004458021b6)]
|
||||
interface nsITCPSocketIntermediary : nsISupports {
|
||||
// Open the connection to the server with the given parameters
|
||||
nsIDOMTCPSocket open(in nsITCPSocketParent parent,
|
||||
in DOMString host, in unsigned short port,
|
||||
in boolean useSSL, in DOMString binaryType);
|
||||
in boolean useSSL, in DOMString binaryType,
|
||||
in unsigned long appId);
|
||||
|
||||
// Listen on a port
|
||||
nsIDOMTCPServerSocket listen(in nsITCPServerSocketParent parent,
|
||||
|
|
|
@ -37,6 +37,7 @@ const kCLOSED = 'closed';
|
|||
const kRESUME_ERROR = 'Calling resume() on a connection that was not suspended.';
|
||||
|
||||
const BUFFER_SIZE = 65536;
|
||||
const NETWORK_STATS_THRESHOLD = 65536;
|
||||
|
||||
// XXX we have no TCPError implementation right now because it's really hard to
|
||||
// do on b2g18. On mozilla-central we want a proper TCPError that ideally
|
||||
|
@ -161,6 +162,14 @@ TCPSocket.prototype = {
|
|||
_waitingForStartTLS: false,
|
||||
_pendingDataAfterStartTLS: [],
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// Network statistics (Gonk-specific feature)
|
||||
_txBytes: 0,
|
||||
_rxBytes: 0,
|
||||
_appId: Ci.nsIScriptSecurityManager.NO_APP_ID,
|
||||
_connectionType: Ci.nsINetworkInterface.NETWORK_TYPE_UNKNOWN,
|
||||
#endif
|
||||
|
||||
// Public accessors.
|
||||
get readyState() {
|
||||
return this._readyState;
|
||||
|
@ -315,6 +324,38 @@ TCPSocket.prototype = {
|
|||
BUFFER_SIZE, /* close source*/ false, /* close sink */ false);
|
||||
},
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// Helper method for collecting network statistics.
|
||||
// Note this method is Gonk-specific.
|
||||
_saveNetworkStats: function ts_saveNetworkStats(enforce) {
|
||||
if (this._txBytes <= 0 && this._rxBytes <= 0) {
|
||||
// There is no traffic at all. No need to save statistics.
|
||||
return;
|
||||
}
|
||||
|
||||
// If "enforce" is false, the traffic amount is saved to NetworkStatsServiceProxy
|
||||
// only when the total amount exceeds the predefined threshold value.
|
||||
// The purpose is to avoid too much overhead for collecting statistics.
|
||||
let totalBytes = this._txBytes + this._rxBytes;
|
||||
if (!enforce && totalBytes < NETWORK_STATS_THRESHOLD) {
|
||||
return;
|
||||
}
|
||||
|
||||
let nssProxy = Cc["@mozilla.org/networkstatsServiceProxy;1"]
|
||||
.getService(Ci.nsINetworkStatsServiceProxy);
|
||||
if (!nssProxy) {
|
||||
LOG("Error: Ci.nsINetworkStatsServiceProxy service is not available.");
|
||||
return;
|
||||
}
|
||||
nssProxy.saveAppStats(this._appId, this._connectionType, Date.now(),
|
||||
this._rxBytes, this._txBytes);
|
||||
|
||||
// Reset the counters once the statistics is saved to NetworkStatsServiceProxy.
|
||||
this._txBytes = this._rxBytes = 0;
|
||||
},
|
||||
// End of helper method for network statistics.
|
||||
#endif
|
||||
|
||||
callListener: function ts_callListener(type, data) {
|
||||
if (!this["on" + type])
|
||||
return;
|
||||
|
@ -371,6 +412,14 @@ TCPSocket.prototype = {
|
|||
return that;
|
||||
},
|
||||
|
||||
setAppId: function ts_setAppId(appId) {
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
this._appId = appId;
|
||||
#else
|
||||
// Do nothing because _appId only exists on Gonk-specific platform.
|
||||
#endif
|
||||
},
|
||||
|
||||
/* end nsITCPSocketInternal methods */
|
||||
|
||||
initWindowless: function ts_initWindowless() {
|
||||
|
@ -479,6 +528,17 @@ TCPSocket.prototype = {
|
|||
let transport = that._transport = this._createTransport(host, port, that._ssl);
|
||||
transport.setEventSink(that, Services.tm.currentThread);
|
||||
that._initStream(that._binaryType);
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// Set _connectionType, which is only required for network statistics.
|
||||
// Note that nsINetworkManager, as well as nsINetworkStatsServiceProxy, is
|
||||
// Gonk-specific.
|
||||
let networkManager = Cc["@mozilla.org/network/manager;1"].getService(Ci.nsINetworkManager);
|
||||
if (networkManager && networkManager.active) {
|
||||
that._connectionType = networkManager.active.type;
|
||||
}
|
||||
#endif
|
||||
|
||||
return that;
|
||||
},
|
||||
|
||||
|
@ -589,6 +649,13 @@ TCPSocket.prototype = {
|
|||
}
|
||||
|
||||
this._ensureCopying();
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// Collect transmitted amount for network statistics.
|
||||
this._txBytes += length;
|
||||
this._saveNetworkStats(false);
|
||||
#endif
|
||||
|
||||
return bufferNotFull;
|
||||
},
|
||||
|
||||
|
@ -621,6 +688,12 @@ TCPSocket.prototype = {
|
|||
},
|
||||
|
||||
_maybeReportErrorAndCloseIfOpen: function(status) {
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// Save network statistics once the connection is closed.
|
||||
// For now this function is Gonk-specific.
|
||||
this._saveNetworkStats(true);
|
||||
#endif
|
||||
|
||||
// If we're closed, we've already reported the error or just don't need to
|
||||
// report the error.
|
||||
if (this._readyState === kCLOSED)
|
||||
|
@ -813,6 +886,12 @@ TCPSocket.prototype = {
|
|||
} else {
|
||||
this.callListener("data", this._inputStreamScriptable.read(count));
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// Collect received amount for network statistics.
|
||||
this._rxBytes += count;
|
||||
this._saveNetworkStats(false);
|
||||
#endif
|
||||
},
|
||||
|
||||
classID: Components.ID("{cda91b22-6472-11e1-aa11-834fec09cd0a}"),
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "mozilla/AppProcessChecker.h"
|
||||
#include "mozilla/net/NeckoCommon.h"
|
||||
#include "mozilla/net/PNeckoParent.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
|
||||
namespace IPC {
|
||||
|
||||
|
@ -91,6 +93,15 @@ TCPSocketParent::RecvOpen(const nsString& aHost, const uint16_t& aPort, const bo
|
|||
return true;
|
||||
}
|
||||
|
||||
// Obtain App ID
|
||||
uint32_t appId = nsIScriptSecurityManager::NO_APP_ID;
|
||||
const PContentParent *content = Manager()->Manager();
|
||||
const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
|
||||
if (browsers.Length() > 0) {
|
||||
TabParent *tab = static_cast<TabParent*>(browsers[0]);
|
||||
appId = tab->OwnAppId();
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
mIntermediary = do_CreateInstance("@mozilla.org/tcp-socket-intermediary;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -98,7 +109,8 @@ TCPSocketParent::RecvOpen(const nsString& aHost, const uint16_t& aPort, const bo
|
|||
return true;
|
||||
}
|
||||
|
||||
rv = mIntermediary->Open(this, aHost, aPort, aUseSSL, aBinaryType, getter_AddRefs(mSocket));
|
||||
rv = mIntermediary->Open(this, aHost, aPort, aUseSSL, aBinaryType, appId,
|
||||
getter_AddRefs(mSocket));
|
||||
if (NS_FAILED(rv) || !mSocket) {
|
||||
FireInteralError(this, __LINE__);
|
||||
return true;
|
||||
|
|
|
@ -30,12 +30,17 @@ TCPSocketParentIntermediary.prototype = {
|
|||
);
|
||||
},
|
||||
|
||||
open: function(aParentSide, aHost, aPort, aUseSSL, aBinaryType) {
|
||||
open: function(aParentSide, aHost, aPort, aUseSSL, aBinaryType, aAppId) {
|
||||
let baseSocket = Cc["@mozilla.org/tcp-socket;1"].createInstance(Ci.nsIDOMTCPSocket);
|
||||
let socket = baseSocket.open(aHost, aPort, {useSecureTransport: aUseSSL, binaryType: aBinaryType});
|
||||
if (!socket)
|
||||
return null;
|
||||
|
||||
let socketInternal = socket.QueryInterface(Ci.nsITCPSocketInternal);
|
||||
if (socketInternal) {
|
||||
socketInternal.setAppId(aAppId);
|
||||
}
|
||||
|
||||
// Handlers are set to the JS-implemented socket object on the parent side.
|
||||
this._setCallbacks(aParentSide, socket);
|
||||
return socket;
|
||||
|
|
|
@ -32,11 +32,14 @@ if CONFIG['MOZ_B2G_RIL']:
|
|||
|
||||
EXTRA_COMPONENTS += [
|
||||
'TCPServerSocket.js',
|
||||
'TCPSocket.js',
|
||||
'TCPSocket.manifest',
|
||||
'TCPSocketParentIntermediary.js',
|
||||
]
|
||||
|
||||
EXTRA_PP_COMPONENTS += [
|
||||
'TCPSocket.js',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_B2G_RIL']:
|
||||
EXTRA_COMPONENTS += [
|
||||
'NetworkStatsManager.js',
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
/**
|
||||
* Information about networks that is exposed to network manager API consumers.
|
||||
*/
|
||||
[scriptable, uuid(04fe5049-1ea8-4b4f-8c27-d23cd24611bb)]
|
||||
[scriptable, uuid(f4cf9d88-f962-4d29-9baa-fb295dad387b)]
|
||||
interface nsINetworkInterface : nsISupports
|
||||
{
|
||||
const long NETWORK_STATE_UNKNOWN = -1;
|
||||
|
@ -24,6 +24,7 @@ interface nsINetworkInterface : nsISupports
|
|||
*/
|
||||
readonly attribute long state;
|
||||
|
||||
const long NETWORK_TYPE_UNKNOWN = -1;
|
||||
const long NETWORK_TYPE_WIFI = 0;
|
||||
const long NETWORK_TYPE_MOBILE = 1;
|
||||
const long NETWORK_TYPE_MOBILE_MMS = 2;
|
||||
|
|
Загрузка…
Ссылка в новой задаче