1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
8 function debug(s) { dump("-*- NetworkStatsManager: " + s + "\n"); }
10 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
12 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
13 Cu.import("resource://gre/modules/Services.jsm");
14 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
16 // Ensure NetworkStatsService and NetworkStatsDB are loaded in the parent process
17 // to receive messages from the child processes.
18 let appInfo = Cc["@mozilla.org/xre/app-info;1"];
19 let isParentProcess = !appInfo || appInfo.getService(Ci.nsIXULRuntime)
20 .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
21 if (isParentProcess) {
22 Cu.import("resource://gre/modules/NetworkStatsService.jsm");
25 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
26 "@mozilla.org/childprocessmessagemanager;1",
27 "nsISyncMessageSender");
30 const nsIClassInfo = Ci.nsIClassInfo;
31 const NETWORKSTATSDATA_CID = Components.ID("{3b16fe17-5583-483a-b486-b64a3243221c}");
33 function NetworkStatsData(aWindow, aData) {
34 this.rxBytes = aData.rxBytes;
35 this.txBytes = aData.txBytes;
36 this.date = new aWindow.Date(aData.date.getTime());
39 NetworkStatsData.prototype = {
40 classID : NETWORKSTATSDATA_CID,
42 QueryInterface : XPCOMUtils.generateQI([])
45 // NetworkStatsInterface
46 const NETWORKSTATSINTERFACE_CONTRACTID = "@mozilla.org/networkstatsinterface;1";
47 const NETWORKSTATSINTERFACE_CID = Components.ID("{f540615b-d803-43ff-8200-2a9d145a5645}");
49 function NetworkStatsInterface() {
51 debug("NetworkStatsInterface Constructor");
55 NetworkStatsInterface.prototype = {
56 __init: function(aNetwork) {
57 this.type = aNetwork.type;
58 this.id = aNetwork.id;
61 classID : NETWORKSTATSINTERFACE_CID,
63 contractID: NETWORKSTATSINTERFACE_CONTRACTID,
64 QueryInterface : XPCOMUtils.generateQI([])
68 const NETWORKSTATS_CID = Components.ID("{28904f59-8497-4ac0-904f-2af14b7fd3de}");
70 function NetworkStats(aWindow, aStats) {
72 debug("NetworkStats Constructor");
74 this.appManifestURL = aStats.appManifestURL || null;
75 this.serviceType = aStats.serviceType || null;
76 this.network = new aWindow.MozNetworkStatsInterface(aStats.network);
77 this.start = aStats.start ? new aWindow.Date(aStats.start.getTime()) : null;
78 this.end = aStats.end ? new aWindow.Date(aStats.end.getTime()) : null;
80 let samples = this.data = new aWindow.Array();
81 for (let i = 0; i < aStats.data.length; i++) {
82 samples.push(aWindow.MozNetworkStatsData._create(
83 aWindow, new NetworkStatsData(aWindow, aStats.data[i])));
87 NetworkStats.prototype = {
88 classID : NETWORKSTATS_CID,
90 QueryInterface : XPCOMUtils.generateQI()
94 const NETWORKSTATSALARM_CID = Components.ID("{a93ea13e-409c-4189-9b1e-95fff220be55}");
96 function NetworkStatsAlarm(aWindow, aAlarm) {
97 this.alarmId = aAlarm.id;
98 this.network = new aWindow.MozNetworkStatsInterface(aAlarm.network);
99 this.threshold = aAlarm.threshold;
100 this.data = aAlarm.data;
103 NetworkStatsAlarm.prototype = {
104 classID : NETWORKSTATSALARM_CID,
106 QueryInterface : XPCOMUtils.generateQI([])
109 // NetworkStatsManager
111 const NETWORKSTATSMANAGER_CONTRACTID = "@mozilla.org/networkStatsManager;1";
112 const NETWORKSTATSMANAGER_CID = Components.ID("{ceb874cd-cc1a-4e65-b404-cc2d3e42425f}");
113 const nsIDOMMozNetworkStatsManager = Ci.nsIDOMMozNetworkStatsManager;
115 function NetworkStatsManager() {
117 debug("Constructor");
121 NetworkStatsManager.prototype = {
122 __proto__: DOMRequestIpcHelper.prototype,
124 checkPrivileges: function checkPrivileges() {
125 if (!this.hasPrivileges) {
126 throw Components.Exception("Permission denied", Cr.NS_ERROR_FAILURE);
130 getSamples: function getSamples(aNetwork, aStart, aEnd, aOptions) {
131 this.checkPrivileges();
133 if (aStart.constructor.name !== "Date" ||
134 aEnd.constructor.name !== "Date" ||
135 !(aNetwork instanceof this.window.MozNetworkStatsInterface) ||
137 throw Components.results.NS_ERROR_INVALID_ARG;
140 let appManifestURL = null;
141 let serviceType = null;
143 if (aOptions.appManifestURL && aOptions.serviceType) {
144 throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
146 appManifestURL = aOptions.appManifestURL;
147 serviceType = aOptions.serviceType;
150 // TODO Bug 929410 Date object cannot correctly pass through cpmm/ppmm IPC
151 // This is just a work-around by passing timestamp numbers.
152 aStart = aStart.getTime();
153 aEnd = aEnd.getTime();
155 let request = this.createRequest();
156 cpmm.sendAsyncMessage("NetworkStats:Get",
157 { network: aNetwork.toJSON(),
160 appManifestURL: appManifestURL,
161 serviceType: serviceType,
162 id: this.getRequestId(request) });
166 clearStats: function clearStats(aNetwork) {
167 this.checkPrivileges();
169 if (!aNetwork instanceof this.window.MozNetworkStatsInterface) {
170 throw Components.results.NS_ERROR_INVALID_ARG;
173 let request = this.createRequest();
174 cpmm.sendAsyncMessage("NetworkStats:Clear",
175 { network: aNetwork.toJSON(),
176 id: this.getRequestId(request) });
180 clearAllStats: function clearAllStats() {
181 this.checkPrivileges();
183 let request = this.createRequest();
184 cpmm.sendAsyncMessage("NetworkStats:ClearAll",
185 {id: this.getRequestId(request)});
189 addAlarm: function addAlarm(aNetwork, aThreshold, aOptions) {
190 this.checkPrivileges();
193 aOptions = Object.create(null);
196 if (aOptions.startTime && aOptions.startTime.constructor.name !== "Date" ||
197 !(aNetwork instanceof this.window.MozNetworkStatsInterface)) {
198 throw Components.results.NS_ERROR_INVALID_ARG;
201 let request = this.createRequest();
202 cpmm.sendAsyncMessage("NetworkStats:SetAlarm",
203 {id: this.getRequestId(request),
204 data: {network: aNetwork.toJSON(),
205 threshold: aThreshold,
206 startTime: aOptions.startTime,
208 manifestURL: this.manifestURL,
209 pageURL: this.pageURL}});
213 getAllAlarms: function getAllAlarms(aNetwork) {
214 this.checkPrivileges();
218 if (!aNetwork instanceof this.window.MozNetworkStatsInterface) {
219 throw Components.results.NS_ERROR_INVALID_ARG;
221 network = aNetwork.toJSON();
224 let request = this.createRequest();
225 cpmm.sendAsyncMessage("NetworkStats:GetAlarms",
226 {id: this.getRequestId(request),
227 data: {network: network,
228 manifestURL: this.manifestURL}});
232 removeAlarms: function removeAlarms(aAlarmId) {
233 this.checkPrivileges();
239 let request = this.createRequest();
240 cpmm.sendAsyncMessage("NetworkStats:RemoveAlarms",
241 {id: this.getRequestId(request),
242 data: {alarmId: aAlarmId,
243 manifestURL: this.manifestURL}});
248 getAvailableNetworks: function getAvailableNetworks() {
249 this.checkPrivileges();
251 let request = this.createRequest();
252 cpmm.sendAsyncMessage("NetworkStats:GetAvailableNetworks",
253 { id: this.getRequestId(request) });
257 getAvailableServiceTypes: function getAvailableServiceTypes() {
258 this.checkPrivileges();
260 let request = this.createRequest();
261 cpmm.sendAsyncMessage("NetworkStats:GetAvailableServiceTypes",
262 { id: this.getRequestId(request) });
267 this.checkPrivileges();
268 return cpmm.sendSyncMessage("NetworkStats:SampleRate")[0];
271 get maxStorageAge() {
272 this.checkPrivileges();
273 return cpmm.sendSyncMessage("NetworkStats:MaxStorageAge")[0];
276 receiveMessage: function(aMessage) {
278 debug("NetworkStatsmanager::receiveMessage: " + aMessage.name);
281 let msg = aMessage.json;
282 let req = this.takeRequest(msg.id);
285 debug("No request stored with id " + msg.id);
290 switch (aMessage.name) {
291 case "NetworkStats:Get:Return":
293 Services.DOMRequest.fireError(req, msg.error);
297 let result = this._window.MozNetworkStats._create(
298 this._window, new NetworkStats(this._window, msg.result));
300 debug("result: " + JSON.stringify(result));
302 Services.DOMRequest.fireSuccess(req, result);
305 case "NetworkStats:GetAvailableNetworks:Return":
307 Services.DOMRequest.fireError(req, msg.error);
311 let networks = new this._window.Array();
312 for (let i = 0; i < msg.result.length; i++) {
313 let network = new this._window.MozNetworkStatsInterface(msg.result[i]);
314 networks.push(network);
317 Services.DOMRequest.fireSuccess(req, networks);
320 case "NetworkStats:GetAvailableServiceTypes:Return":
322 Services.DOMRequest.fireError(req, msg.error);
326 let serviceTypes = new this._window.Array();
327 for (let i = 0; i < msg.result.length; i++) {
328 serviceTypes.push(msg.result[i]);
331 Services.DOMRequest.fireSuccess(req, serviceTypes);
334 case "NetworkStats:Clear:Return":
335 case "NetworkStats:ClearAll:Return":
337 Services.DOMRequest.fireError(req, msg.error);
341 Services.DOMRequest.fireSuccess(req, true);
344 case "NetworkStats:SetAlarm:Return":
345 case "NetworkStats:RemoveAlarms:Return":
347 Services.DOMRequest.fireError(req, msg.error);
351 Services.DOMRequest.fireSuccess(req, msg.result);
354 case "NetworkStats:GetAlarms:Return":
356 Services.DOMRequest.fireError(req, msg.error);
360 let alarms = new this._window.Array();
361 for (let i = 0; i < msg.result.length; i++) {
362 // The WebIDL type of data is any, so we should manually clone it
363 // into the content window.
364 if ("data" in msg.result[i]) {
365 msg.result[i].data = Cu.cloneInto(msg.result[i].data, this._window);
367 let alarm = new NetworkStatsAlarm(this._window, msg.result[i]);
368 alarms.push(this._window.MozNetworkStatsAlarm._create(this._window, alarm));
371 Services.DOMRequest.fireSuccess(req, alarms);
376 debug("Wrong message: " + aMessage.name);
381 init: function(aWindow) {
382 // Set navigator.mozNetworkStats to null.
383 if (!Services.prefs.getBoolPref("dom.mozNetworkStats.enabled")) {
387 let principal = aWindow.document.nodePrincipal;
388 let secMan = Services.scriptSecurityManager;
389 let perm = principal == secMan.getSystemPrincipal() ?
390 Ci.nsIPermissionManager.ALLOW_ACTION :
391 Services.perms.testExactPermissionFromPrincipal(principal,
392 "networkstats-manage");
394 // Only pages with perm set can use the netstats.
395 this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
397 debug("has privileges: " + this.hasPrivileges);
400 if (!this.hasPrivileges) {
404 this.initDOMRequestHelper(aWindow, ["NetworkStats:Get:Return",
405 "NetworkStats:GetAvailableNetworks:Return",
406 "NetworkStats:GetAvailableServiceTypes:Return",
407 "NetworkStats:Clear:Return",
408 "NetworkStats:ClearAll:Return",
409 "NetworkStats:SetAlarm:Return",
410 "NetworkStats:GetAlarms:Return",
411 "NetworkStats:RemoveAlarms:Return"]);
413 // Init app properties.
414 let appsService = Cc["@mozilla.org/AppsService;1"]
415 .getService(Ci.nsIAppsService);
417 this.manifestURL = appsService.getManifestURLByLocalId(principal.appId);
419 let isApp = !!this.manifestURL.length;
421 this.pageURL = principal.URI.spec;
424 this.window = aWindow;
427 // Called from DOMRequestIpcHelper
428 uninit: function uninit() {
430 debug("uninit call");
434 classID : NETWORKSTATSMANAGER_CID,
435 QueryInterface : XPCOMUtils.generateQI([nsIDOMMozNetworkStatsManager,
436 Ci.nsIDOMGlobalPropertyInitializer,
437 Ci.nsISupportsWeakReference,
440 classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSMANAGER_CID,
441 contractID: NETWORKSTATSMANAGER_CONTRACTID,
442 classDescription: "NetworkStatsManager",
443 interfaces: [nsIDOMMozNetworkStatsManager],
444 flags: nsIClassInfo.DOM_OBJECT})
447 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkStatsAlarm,
449 NetworkStatsInterface,
451 NetworkStatsManager]);