mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
463 lines
15 KiB
JavaScript
463 lines
15 KiB
JavaScript
/* 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/. */
|
|
|
|
"use strict";
|
|
|
|
const DEBUG = false;
|
|
function debug(s) { dump("-*- NetworkStatsManager: " + s + "\n"); }
|
|
|
|
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
|
|
|
// Ensure NetworkStatsService and NetworkStatsDB are loaded in the parent process
|
|
// to receive messages from the child processes.
|
|
let appInfo = Cc["@mozilla.org/xre/app-info;1"];
|
|
let isParentProcess = !appInfo || appInfo.getService(Ci.nsIXULRuntime)
|
|
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
|
if (isParentProcess) {
|
|
Cu.import("resource://gre/modules/NetworkStatsService.jsm");
|
|
}
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
|
"@mozilla.org/childprocessmessagemanager;1",
|
|
"nsISyncMessageSender");
|
|
|
|
// NetworkStatsData
|
|
const nsIClassInfo = Ci.nsIClassInfo;
|
|
const NETWORKSTATSDATA_CID = Components.ID("{3b16fe17-5583-483a-b486-b64a3243221c}");
|
|
|
|
function NetworkStatsData(aWindow, aData) {
|
|
this.rxBytes = aData.rxBytes;
|
|
this.txBytes = aData.txBytes;
|
|
this.date = new aWindow.Date(aData.date.getTime());
|
|
}
|
|
|
|
NetworkStatsData.prototype = {
|
|
classID : NETWORKSTATSDATA_CID,
|
|
|
|
QueryInterface : XPCOMUtils.generateQI([])
|
|
};
|
|
|
|
// NetworkStatsInterface
|
|
const NETWORKSTATSINTERFACE_CONTRACTID = "@mozilla.org/networkstatsinterface;1";
|
|
const NETWORKSTATSINTERFACE_CID = Components.ID("{f540615b-d803-43ff-8200-2a9d145a5645}");
|
|
|
|
function NetworkStatsInterface() {
|
|
if (DEBUG) {
|
|
debug("NetworkStatsInterface Constructor");
|
|
}
|
|
}
|
|
|
|
NetworkStatsInterface.prototype = {
|
|
__init: function(aNetwork) {
|
|
this.type = aNetwork.type;
|
|
this.id = aNetwork.id;
|
|
},
|
|
|
|
classID : NETWORKSTATSINTERFACE_CID,
|
|
|
|
contractID: NETWORKSTATSINTERFACE_CONTRACTID,
|
|
QueryInterface : XPCOMUtils.generateQI([])
|
|
}
|
|
|
|
// NetworkStats
|
|
const NETWORKSTATS_CID = Components.ID("{28904f59-8497-4ac0-904f-2af14b7fd3de}");
|
|
|
|
function NetworkStats(aWindow, aStats) {
|
|
if (DEBUG) {
|
|
debug("NetworkStats Constructor");
|
|
}
|
|
this.appManifestURL = aStats.appManifestURL || null;
|
|
this.browsingTrafficOnly = aStats.browsingTrafficOnly || false;
|
|
this.serviceType = aStats.serviceType || null;
|
|
this.network = new aWindow.MozNetworkStatsInterface(aStats.network);
|
|
this.start = aStats.start ? new aWindow.Date(aStats.start.getTime()) : null;
|
|
this.end = aStats.end ? new aWindow.Date(aStats.end.getTime()) : null;
|
|
|
|
let samples = this.data = new aWindow.Array();
|
|
for (let i = 0; i < aStats.data.length; i++) {
|
|
samples.push(aWindow.MozNetworkStatsData._create(
|
|
aWindow, new NetworkStatsData(aWindow, aStats.data[i])));
|
|
}
|
|
}
|
|
|
|
NetworkStats.prototype = {
|
|
classID : NETWORKSTATS_CID,
|
|
|
|
QueryInterface : XPCOMUtils.generateQI()
|
|
}
|
|
|
|
// NetworkStatsAlarm
|
|
const NETWORKSTATSALARM_CID = Components.ID("{a93ea13e-409c-4189-9b1e-95fff220be55}");
|
|
|
|
function NetworkStatsAlarm(aWindow, aAlarm) {
|
|
this.alarmId = aAlarm.id;
|
|
this.network = new aWindow.MozNetworkStatsInterface(aAlarm.network);
|
|
this.threshold = aAlarm.threshold;
|
|
this.data = aAlarm.data;
|
|
}
|
|
|
|
NetworkStatsAlarm.prototype = {
|
|
classID : NETWORKSTATSALARM_CID,
|
|
|
|
QueryInterface : XPCOMUtils.generateQI([])
|
|
};
|
|
|
|
// NetworkStatsManager
|
|
|
|
const NETWORKSTATSMANAGER_CONTRACTID = "@mozilla.org/networkStatsManager;1";
|
|
const NETWORKSTATSMANAGER_CID = Components.ID("{ceb874cd-cc1a-4e65-b404-cc2d3e42425f}");
|
|
const nsIDOMMozNetworkStatsManager = Ci.nsIDOMMozNetworkStatsManager;
|
|
|
|
function NetworkStatsManager() {
|
|
if (DEBUG) {
|
|
debug("Constructor");
|
|
}
|
|
}
|
|
|
|
NetworkStatsManager.prototype = {
|
|
__proto__: DOMRequestIpcHelper.prototype,
|
|
|
|
checkPrivileges: function checkPrivileges() {
|
|
if (!this.hasPrivileges) {
|
|
throw Components.Exception("Permission denied", Cr.NS_ERROR_FAILURE);
|
|
}
|
|
},
|
|
|
|
getSamples: function getSamples(aNetwork, aStart, aEnd, aOptions) {
|
|
this.checkPrivileges();
|
|
|
|
if (aStart.constructor.name !== "Date" ||
|
|
aEnd.constructor.name !== "Date" ||
|
|
!(aNetwork instanceof this.window.MozNetworkStatsInterface) ||
|
|
aStart > aEnd) {
|
|
throw Components.results.NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
let appManifestURL = null;
|
|
let browsingTrafficOnly = false;
|
|
let serviceType = null;
|
|
if (aOptions) {
|
|
// appManifestURL is used to query network statistics by app;
|
|
// serviceType is used to query network statistics by system service.
|
|
// It is illegal to specify both of them at the same time.
|
|
if (aOptions.appManifestURL && aOptions.serviceType) {
|
|
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
// browsingTrafficOnly is meaningful only when querying by app.
|
|
if (!aOptions.appManifestURL && aOptions.browsingTrafficOnly) {
|
|
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
appManifestURL = aOptions.appManifestURL;
|
|
serviceType = aOptions.serviceType;
|
|
browsingTrafficOnly = aOptions.browsingTrafficOnly || false;
|
|
}
|
|
|
|
// TODO Bug 929410 Date object cannot correctly pass through cpmm/ppmm IPC
|
|
// This is just a work-around by passing timestamp numbers.
|
|
aStart = aStart.getTime();
|
|
aEnd = aEnd.getTime();
|
|
|
|
let request = this.createRequest();
|
|
cpmm.sendAsyncMessage("NetworkStats:Get",
|
|
{ network: aNetwork.toJSON(),
|
|
start: aStart,
|
|
end: aEnd,
|
|
appManifestURL: appManifestURL,
|
|
browsingTrafficOnly: browsingTrafficOnly,
|
|
serviceType: serviceType,
|
|
id: this.getRequestId(request) });
|
|
return request;
|
|
},
|
|
|
|
clearStats: function clearStats(aNetwork) {
|
|
this.checkPrivileges();
|
|
|
|
if (!aNetwork instanceof this.window.MozNetworkStatsInterface) {
|
|
throw Components.results.NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
let request = this.createRequest();
|
|
cpmm.sendAsyncMessage("NetworkStats:Clear",
|
|
{ network: aNetwork.toJSON(),
|
|
id: this.getRequestId(request) });
|
|
return request;
|
|
},
|
|
|
|
clearAllStats: function clearAllStats() {
|
|
this.checkPrivileges();
|
|
|
|
let request = this.createRequest();
|
|
cpmm.sendAsyncMessage("NetworkStats:ClearAll",
|
|
{id: this.getRequestId(request)});
|
|
return request;
|
|
},
|
|
|
|
addAlarm: function addAlarm(aNetwork, aThreshold, aOptions) {
|
|
this.checkPrivileges();
|
|
|
|
if (!aOptions) {
|
|
aOptions = Object.create(null);
|
|
}
|
|
|
|
if (aOptions.startTime && aOptions.startTime.constructor.name !== "Date" ||
|
|
!(aNetwork instanceof this.window.MozNetworkStatsInterface)) {
|
|
throw Components.results.NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
let request = this.createRequest();
|
|
cpmm.sendAsyncMessage("NetworkStats:SetAlarm",
|
|
{id: this.getRequestId(request),
|
|
data: {network: aNetwork.toJSON(),
|
|
threshold: aThreshold,
|
|
startTime: aOptions.startTime,
|
|
data: aOptions.data,
|
|
manifestURL: this.manifestURL,
|
|
pageURL: this.pageURL}});
|
|
return request;
|
|
},
|
|
|
|
getAllAlarms: function getAllAlarms(aNetwork) {
|
|
this.checkPrivileges();
|
|
|
|
let network = null;
|
|
if (aNetwork) {
|
|
if (!aNetwork instanceof this.window.MozNetworkStatsInterface) {
|
|
throw Components.results.NS_ERROR_INVALID_ARG;
|
|
}
|
|
network = aNetwork.toJSON();
|
|
}
|
|
|
|
let request = this.createRequest();
|
|
cpmm.sendAsyncMessage("NetworkStats:GetAlarms",
|
|
{id: this.getRequestId(request),
|
|
data: {network: network,
|
|
manifestURL: this.manifestURL}});
|
|
return request;
|
|
},
|
|
|
|
removeAlarms: function removeAlarms(aAlarmId) {
|
|
this.checkPrivileges();
|
|
|
|
if (aAlarmId == 0) {
|
|
aAlarmId = -1;
|
|
}
|
|
|
|
let request = this.createRequest();
|
|
cpmm.sendAsyncMessage("NetworkStats:RemoveAlarms",
|
|
{id: this.getRequestId(request),
|
|
data: {alarmId: aAlarmId,
|
|
manifestURL: this.manifestURL}});
|
|
|
|
return request;
|
|
},
|
|
|
|
getAvailableNetworks: function getAvailableNetworks() {
|
|
this.checkPrivileges();
|
|
|
|
let request = this.createRequest();
|
|
cpmm.sendAsyncMessage("NetworkStats:GetAvailableNetworks",
|
|
{ id: this.getRequestId(request) });
|
|
return request;
|
|
},
|
|
|
|
getAvailableServiceTypes: function getAvailableServiceTypes() {
|
|
this.checkPrivileges();
|
|
|
|
let request = this.createRequest();
|
|
cpmm.sendAsyncMessage("NetworkStats:GetAvailableServiceTypes",
|
|
{ id: this.getRequestId(request) });
|
|
return request;
|
|
},
|
|
|
|
get sampleRate() {
|
|
this.checkPrivileges();
|
|
return cpmm.sendSyncMessage("NetworkStats:SampleRate")[0];
|
|
},
|
|
|
|
get maxStorageAge() {
|
|
this.checkPrivileges();
|
|
return cpmm.sendSyncMessage("NetworkStats:MaxStorageAge")[0];
|
|
},
|
|
|
|
receiveMessage: function(aMessage) {
|
|
if (DEBUG) {
|
|
debug("NetworkStatsmanager::receiveMessage: " + aMessage.name);
|
|
}
|
|
|
|
let msg = aMessage.json;
|
|
let req = this.takeRequest(msg.id);
|
|
if (!req) {
|
|
if (DEBUG) {
|
|
debug("No request stored with id " + msg.id);
|
|
}
|
|
return;
|
|
}
|
|
|
|
switch (aMessage.name) {
|
|
case "NetworkStats:Get:Return":
|
|
if (msg.error) {
|
|
Services.DOMRequest.fireError(req, msg.error);
|
|
return;
|
|
}
|
|
|
|
let result = this._window.MozNetworkStats._create(
|
|
this._window, new NetworkStats(this._window, msg.result));
|
|
if (DEBUG) {
|
|
debug("result: " + JSON.stringify(result));
|
|
}
|
|
Services.DOMRequest.fireSuccess(req, result);
|
|
break;
|
|
|
|
case "NetworkStats:GetAvailableNetworks:Return":
|
|
if (msg.error) {
|
|
Services.DOMRequest.fireError(req, msg.error);
|
|
return;
|
|
}
|
|
|
|
let networks = new this._window.Array();
|
|
for (let i = 0; i < msg.result.length; i++) {
|
|
let network = new this._window.MozNetworkStatsInterface(msg.result[i]);
|
|
networks.push(network);
|
|
}
|
|
|
|
Services.DOMRequest.fireSuccess(req, networks);
|
|
break;
|
|
|
|
case "NetworkStats:GetAvailableServiceTypes:Return":
|
|
if (msg.error) {
|
|
Services.DOMRequest.fireError(req, msg.error);
|
|
return;
|
|
}
|
|
|
|
let serviceTypes = new this._window.Array();
|
|
for (let i = 0; i < msg.result.length; i++) {
|
|
serviceTypes.push(msg.result[i]);
|
|
}
|
|
|
|
Services.DOMRequest.fireSuccess(req, serviceTypes);
|
|
break;
|
|
|
|
case "NetworkStats:Clear:Return":
|
|
case "NetworkStats:ClearAll:Return":
|
|
if (msg.error) {
|
|
Services.DOMRequest.fireError(req, msg.error);
|
|
return;
|
|
}
|
|
|
|
Services.DOMRequest.fireSuccess(req, true);
|
|
break;
|
|
|
|
case "NetworkStats:SetAlarm:Return":
|
|
case "NetworkStats:RemoveAlarms:Return":
|
|
if (msg.error) {
|
|
Services.DOMRequest.fireError(req, msg.error);
|
|
return;
|
|
}
|
|
|
|
Services.DOMRequest.fireSuccess(req, msg.result);
|
|
break;
|
|
|
|
case "NetworkStats:GetAlarms:Return":
|
|
if (msg.error) {
|
|
Services.DOMRequest.fireError(req, msg.error);
|
|
return;
|
|
}
|
|
|
|
let alarms = new this._window.Array();
|
|
for (let i = 0; i < msg.result.length; i++) {
|
|
// The WebIDL type of data is any, so we should manually clone it
|
|
// into the content window.
|
|
if ("data" in msg.result[i]) {
|
|
msg.result[i].data = Cu.cloneInto(msg.result[i].data, this._window);
|
|
}
|
|
let alarm = new NetworkStatsAlarm(this._window, msg.result[i]);
|
|
alarms.push(this._window.MozNetworkStatsAlarm._create(this._window, alarm));
|
|
}
|
|
|
|
Services.DOMRequest.fireSuccess(req, alarms);
|
|
break;
|
|
|
|
default:
|
|
if (DEBUG) {
|
|
debug("Wrong message: " + aMessage.name);
|
|
}
|
|
}
|
|
},
|
|
|
|
init: function(aWindow) {
|
|
// Set navigator.mozNetworkStats to null.
|
|
if (!Services.prefs.getBoolPref("dom.mozNetworkStats.enabled")) {
|
|
return null;
|
|
}
|
|
|
|
let principal = aWindow.document.nodePrincipal;
|
|
let secMan = Services.scriptSecurityManager;
|
|
let perm = principal == secMan.getSystemPrincipal() ?
|
|
Ci.nsIPermissionManager.ALLOW_ACTION :
|
|
Services.perms.testExactPermissionFromPrincipal(principal,
|
|
"networkstats-manage");
|
|
|
|
// Only pages with perm set can use the netstats.
|
|
this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
|
|
if (DEBUG) {
|
|
debug("has privileges: " + this.hasPrivileges);
|
|
}
|
|
|
|
if (!this.hasPrivileges) {
|
|
return null;
|
|
}
|
|
|
|
this.initDOMRequestHelper(aWindow, ["NetworkStats:Get:Return",
|
|
"NetworkStats:GetAvailableNetworks:Return",
|
|
"NetworkStats:GetAvailableServiceTypes:Return",
|
|
"NetworkStats:Clear:Return",
|
|
"NetworkStats:ClearAll:Return",
|
|
"NetworkStats:SetAlarm:Return",
|
|
"NetworkStats:GetAlarms:Return",
|
|
"NetworkStats:RemoveAlarms:Return"]);
|
|
|
|
// Init app properties.
|
|
let appsService = Cc["@mozilla.org/AppsService;1"]
|
|
.getService(Ci.nsIAppsService);
|
|
|
|
this.manifestURL = appsService.getManifestURLByLocalId(principal.appId);
|
|
|
|
let isApp = !!this.manifestURL.length;
|
|
if (isApp) {
|
|
this.pageURL = principal.URI.spec;
|
|
}
|
|
|
|
this.window = aWindow;
|
|
},
|
|
|
|
// Called from DOMRequestIpcHelper
|
|
uninit: function uninit() {
|
|
if (DEBUG) {
|
|
debug("uninit call");
|
|
}
|
|
},
|
|
|
|
classID : NETWORKSTATSMANAGER_CID,
|
|
QueryInterface : XPCOMUtils.generateQI([nsIDOMMozNetworkStatsManager,
|
|
Ci.nsIDOMGlobalPropertyInitializer,
|
|
Ci.nsISupportsWeakReference,
|
|
Ci.nsIObserver]),
|
|
|
|
classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSMANAGER_CID,
|
|
contractID: NETWORKSTATSMANAGER_CONTRACTID,
|
|
classDescription: "NetworkStatsManager",
|
|
interfaces: [nsIDOMMozNetworkStatsManager],
|
|
flags: nsIClassInfo.DOM_OBJECT})
|
|
}
|
|
|
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkStatsAlarm,
|
|
NetworkStatsData,
|
|
NetworkStatsInterface,
|
|
NetworkStats,
|
|
NetworkStatsManager]);
|