dom/network/src/NetworkStatsManager.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 "use strict";
michael@0 6
michael@0 7 const DEBUG = false;
michael@0 8 function debug(s) { dump("-*- NetworkStatsManager: " + s + "\n"); }
michael@0 9
michael@0 10 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
michael@0 11
michael@0 12 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
michael@0 13 Cu.import("resource://gre/modules/Services.jsm");
michael@0 14 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
michael@0 15
michael@0 16 // Ensure NetworkStatsService and NetworkStatsDB are loaded in the parent process
michael@0 17 // to receive messages from the child processes.
michael@0 18 let appInfo = Cc["@mozilla.org/xre/app-info;1"];
michael@0 19 let isParentProcess = !appInfo || appInfo.getService(Ci.nsIXULRuntime)
michael@0 20 .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
michael@0 21 if (isParentProcess) {
michael@0 22 Cu.import("resource://gre/modules/NetworkStatsService.jsm");
michael@0 23 }
michael@0 24
michael@0 25 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
michael@0 26 "@mozilla.org/childprocessmessagemanager;1",
michael@0 27 "nsISyncMessageSender");
michael@0 28
michael@0 29 // NetworkStatsData
michael@0 30 const nsIClassInfo = Ci.nsIClassInfo;
michael@0 31 const NETWORKSTATSDATA_CID = Components.ID("{3b16fe17-5583-483a-b486-b64a3243221c}");
michael@0 32 const nsIDOMMozNetworkStatsData = Ci.nsIDOMMozNetworkStatsData;
michael@0 33
michael@0 34 function NetworkStatsData(aWindow, aData) {
michael@0 35 this.rxBytes = aData.rxBytes;
michael@0 36 this.txBytes = aData.txBytes;
michael@0 37 this.date = new aWindow.Date(aData.date.getTime());
michael@0 38 }
michael@0 39
michael@0 40 NetworkStatsData.prototype = {
michael@0 41 __exposedProps__: {
michael@0 42 rxBytes: 'r',
michael@0 43 txBytes: 'r',
michael@0 44 date: 'r',
michael@0 45 },
michael@0 46
michael@0 47 classID : NETWORKSTATSDATA_CID,
michael@0 48 classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSDATA_CID,
michael@0 49 contractID:"@mozilla.org/networkstatsdata;1",
michael@0 50 classDescription: "NetworkStatsData",
michael@0 51 interfaces: [nsIDOMMozNetworkStatsData],
michael@0 52 flags: nsIClassInfo.DOM_OBJECT}),
michael@0 53
michael@0 54 QueryInterface : XPCOMUtils.generateQI([nsIDOMMozNetworkStatsData])
michael@0 55 };
michael@0 56
michael@0 57 // NetworkStatsInterface
michael@0 58 const NETWORKSTATSINTERFACE_CONTRACTID = "@mozilla.org/networkstatsinterface;1";
michael@0 59 const NETWORKSTATSINTERFACE_CID = Components.ID("{f540615b-d803-43ff-8200-2a9d145a5645}");
michael@0 60 const nsIDOMMozNetworkStatsInterface = Ci.nsIDOMMozNetworkStatsInterface;
michael@0 61
michael@0 62 function NetworkStatsInterface(aNetwork) {
michael@0 63 if (DEBUG) {
michael@0 64 debug("NetworkStatsInterface Constructor");
michael@0 65 }
michael@0 66 this.type = aNetwork.type;
michael@0 67 this.id = aNetwork.id;
michael@0 68 }
michael@0 69
michael@0 70 NetworkStatsInterface.prototype = {
michael@0 71 __exposedProps__: {
michael@0 72 id: 'r',
michael@0 73 type: 'r',
michael@0 74 },
michael@0 75
michael@0 76 classID : NETWORKSTATSINTERFACE_CID,
michael@0 77 classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSINTERFACE_CID,
michael@0 78 contractID: NETWORKSTATSINTERFACE_CONTRACTID,
michael@0 79 classDescription: "NetworkStatsInterface",
michael@0 80 interfaces: [nsIDOMMozNetworkStatsInterface],
michael@0 81 flags: nsIClassInfo.DOM_OBJECT}),
michael@0 82
michael@0 83 QueryInterface : XPCOMUtils.generateQI([nsIDOMMozNetworkStatsInterface])
michael@0 84 }
michael@0 85
michael@0 86 // NetworkStats
michael@0 87 const NETWORKSTATS_CONTRACTID = "@mozilla.org/networkstats;1";
michael@0 88 const NETWORKSTATS_CID = Components.ID("{f1996e44-1057-4d4b-8ff8-919e76c4cfa9}");
michael@0 89 const nsIDOMMozNetworkStats = Ci.nsIDOMMozNetworkStats;
michael@0 90
michael@0 91 function NetworkStats(aWindow, aStats) {
michael@0 92 if (DEBUG) {
michael@0 93 debug("NetworkStats Constructor");
michael@0 94 }
michael@0 95 this.appManifestURL = aStats.appManifestURL || null;
michael@0 96 this.serviceType = aStats.serviceType || null;
michael@0 97 this.network = new NetworkStatsInterface(aStats.network);
michael@0 98 this.start = aStats.start ? new aWindow.Date(aStats.start.getTime()) : null;
michael@0 99 this.end = aStats.end ? new aWindow.Date(aStats.end.getTime()) : null;
michael@0 100
michael@0 101 let samples = this.data = new aWindow.Array();
michael@0 102 for (let i = 0; i < aStats.data.length; i++) {
michael@0 103 samples.push(new NetworkStatsData(aWindow, aStats.data[i]));
michael@0 104 }
michael@0 105 }
michael@0 106
michael@0 107 NetworkStats.prototype = {
michael@0 108 __exposedProps__: {
michael@0 109 appManifestURL: 'r',
michael@0 110 serviceType: 'r',
michael@0 111 network: 'r',
michael@0 112 start: 'r',
michael@0 113 end: 'r',
michael@0 114 data: 'r',
michael@0 115 },
michael@0 116
michael@0 117 classID : NETWORKSTATS_CID,
michael@0 118 classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATS_CID,
michael@0 119 contractID: NETWORKSTATS_CONTRACTID,
michael@0 120 classDescription: "NetworkStats",
michael@0 121 interfaces: [nsIDOMMozNetworkStats],
michael@0 122 flags: nsIClassInfo.DOM_OBJECT}),
michael@0 123
michael@0 124 QueryInterface : XPCOMUtils.generateQI([nsIDOMMozNetworkStats,
michael@0 125 nsIDOMMozNetworkStatsData,
michael@0 126 nsIDOMMozNetworkStatsInterface])
michael@0 127 }
michael@0 128
michael@0 129 // NetworkStatsAlarm
michael@0 130 const NETWORKSTATSALARM_CID = Components.ID("{063ebeb2-5c6e-47ae-bdcd-5e6ebdc7a68c}");
michael@0 131 const nsIDOMMozNetworkStatsAlarm = Ci.nsIDOMMozNetworkStatsAlarm;
michael@0 132
michael@0 133 function NetworkStatsAlarm(aAlarm) {
michael@0 134 this.alarmId = aAlarm.id;
michael@0 135 this.network = new NetworkStatsInterface(aAlarm.network);
michael@0 136 this.threshold = aAlarm.threshold;
michael@0 137 this.data = aAlarm.data;
michael@0 138 }
michael@0 139
michael@0 140 NetworkStatsAlarm.prototype = {
michael@0 141 __exposedProps__: {
michael@0 142 alarmId: 'r',
michael@0 143 network: 'r',
michael@0 144 threshold: 'r',
michael@0 145 data: 'r',
michael@0 146 },
michael@0 147
michael@0 148 classID : NETWORKSTATSALARM_CID,
michael@0 149 classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSALARM_CID,
michael@0 150 contractID:"@mozilla.org/networkstatsalarm;1",
michael@0 151 classDescription: "NetworkStatsAlarm",
michael@0 152 interfaces: [nsIDOMMozNetworkStatsAlarm],
michael@0 153 flags: nsIClassInfo.DOM_OBJECT}),
michael@0 154
michael@0 155 QueryInterface : XPCOMUtils.generateQI([nsIDOMMozNetworkStatsAlarm])
michael@0 156 };
michael@0 157
michael@0 158 // NetworkStatsManager
michael@0 159
michael@0 160 const NETWORKSTATSMANAGER_CONTRACTID = "@mozilla.org/networkStatsManager;1";
michael@0 161 const NETWORKSTATSMANAGER_CID = Components.ID("{8a66f4c1-0c25-4a66-9fc5-0106947b91f9}");
michael@0 162 const nsIDOMMozNetworkStatsManager = Ci.nsIDOMMozNetworkStatsManager;
michael@0 163
michael@0 164 function NetworkStatsManager() {
michael@0 165 if (DEBUG) {
michael@0 166 debug("Constructor");
michael@0 167 }
michael@0 168 }
michael@0 169
michael@0 170 NetworkStatsManager.prototype = {
michael@0 171 __proto__: DOMRequestIpcHelper.prototype,
michael@0 172
michael@0 173 checkPrivileges: function checkPrivileges() {
michael@0 174 if (!this.hasPrivileges) {
michael@0 175 throw Components.Exception("Permission denied", Cr.NS_ERROR_FAILURE);
michael@0 176 }
michael@0 177 },
michael@0 178
michael@0 179 getSamples: function getSamples(aNetwork, aStart, aEnd, aOptions) {
michael@0 180 this.checkPrivileges();
michael@0 181
michael@0 182 if (aStart.constructor.name !== "Date" ||
michael@0 183 aEnd.constructor.name !== "Date" ||
michael@0 184 aStart > aEnd) {
michael@0 185 throw Components.results.NS_ERROR_INVALID_ARG;
michael@0 186 }
michael@0 187
michael@0 188 let appManifestURL = null;
michael@0 189 let serviceType = null;
michael@0 190 if (aOptions) {
michael@0 191 if (aOptions.appManifestURL && aOptions.serviceType) {
michael@0 192 throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
michael@0 193 }
michael@0 194 appManifestURL = aOptions.appManifestURL;
michael@0 195 serviceType = aOptions.serviceType;
michael@0 196 }
michael@0 197
michael@0 198 // TODO Bug 929410 Date object cannot correctly pass through cpmm/ppmm IPC
michael@0 199 // This is just a work-around by passing timestamp numbers.
michael@0 200 aStart = aStart.getTime();
michael@0 201 aEnd = aEnd.getTime();
michael@0 202
michael@0 203 let request = this.createRequest();
michael@0 204 cpmm.sendAsyncMessage("NetworkStats:Get",
michael@0 205 { network: aNetwork,
michael@0 206 start: aStart,
michael@0 207 end: aEnd,
michael@0 208 appManifestURL: appManifestURL,
michael@0 209 serviceType: serviceType,
michael@0 210 id: this.getRequestId(request) });
michael@0 211 return request;
michael@0 212 },
michael@0 213
michael@0 214 clearStats: function clearStats(aNetwork) {
michael@0 215 this.checkPrivileges();
michael@0 216
michael@0 217 let request = this.createRequest();
michael@0 218 cpmm.sendAsyncMessage("NetworkStats:Clear",
michael@0 219 { network: aNetwork,
michael@0 220 id: this.getRequestId(request) });
michael@0 221 return request;
michael@0 222 },
michael@0 223
michael@0 224 clearAllStats: function clearAllStats() {
michael@0 225 this.checkPrivileges();
michael@0 226
michael@0 227 let request = this.createRequest();
michael@0 228 cpmm.sendAsyncMessage("NetworkStats:ClearAll",
michael@0 229 {id: this.getRequestId(request)});
michael@0 230 return request;
michael@0 231 },
michael@0 232
michael@0 233 addAlarm: function addAlarm(aNetwork, aThreshold, aOptions) {
michael@0 234 this.checkPrivileges();
michael@0 235
michael@0 236 if (!aOptions) {
michael@0 237 aOptions = Object.create(null);
michael@0 238 }
michael@0 239
michael@0 240 if (aOptions.startTime && aOptions.startTime.constructor.name !== "Date") {
michael@0 241 throw Components.results.NS_ERROR_INVALID_ARG;
michael@0 242 }
michael@0 243
michael@0 244 let request = this.createRequest();
michael@0 245 cpmm.sendAsyncMessage("NetworkStats:SetAlarm",
michael@0 246 {id: this.getRequestId(request),
michael@0 247 data: {network: aNetwork,
michael@0 248 threshold: aThreshold,
michael@0 249 startTime: aOptions.startTime,
michael@0 250 data: aOptions.data,
michael@0 251 manifestURL: this.manifestURL,
michael@0 252 pageURL: this.pageURL}});
michael@0 253 return request;
michael@0 254 },
michael@0 255
michael@0 256 getAllAlarms: function getAllAlarms(aNetwork) {
michael@0 257 this.checkPrivileges();
michael@0 258
michael@0 259 let request = this.createRequest();
michael@0 260 cpmm.sendAsyncMessage("NetworkStats:GetAlarms",
michael@0 261 {id: this.getRequestId(request),
michael@0 262 data: {network: aNetwork,
michael@0 263 manifestURL: this.manifestURL}});
michael@0 264 return request;
michael@0 265 },
michael@0 266
michael@0 267 removeAlarms: function removeAlarms(aAlarmId) {
michael@0 268 this.checkPrivileges();
michael@0 269
michael@0 270 if (aAlarmId == 0) {
michael@0 271 aAlarmId = -1;
michael@0 272 }
michael@0 273
michael@0 274 let request = this.createRequest();
michael@0 275 cpmm.sendAsyncMessage("NetworkStats:RemoveAlarms",
michael@0 276 {id: this.getRequestId(request),
michael@0 277 data: {alarmId: aAlarmId,
michael@0 278 manifestURL: this.manifestURL}});
michael@0 279
michael@0 280 return request;
michael@0 281 },
michael@0 282
michael@0 283 getAvailableNetworks: function getAvailableNetworks() {
michael@0 284 this.checkPrivileges();
michael@0 285
michael@0 286 let request = this.createRequest();
michael@0 287 cpmm.sendAsyncMessage("NetworkStats:GetAvailableNetworks",
michael@0 288 { id: this.getRequestId(request) });
michael@0 289 return request;
michael@0 290 },
michael@0 291
michael@0 292 getAvailableServiceTypes: function getAvailableServiceTypes() {
michael@0 293 this.checkPrivileges();
michael@0 294
michael@0 295 let request = this.createRequest();
michael@0 296 cpmm.sendAsyncMessage("NetworkStats:GetAvailableServiceTypes",
michael@0 297 { id: this.getRequestId(request) });
michael@0 298 return request;
michael@0 299 },
michael@0 300
michael@0 301 get sampleRate() {
michael@0 302 this.checkPrivileges();
michael@0 303 return cpmm.sendSyncMessage("NetworkStats:SampleRate")[0];
michael@0 304 },
michael@0 305
michael@0 306 get maxStorageAge() {
michael@0 307 this.checkPrivileges();
michael@0 308 return cpmm.sendSyncMessage("NetworkStats:MaxStorageAge")[0];
michael@0 309 },
michael@0 310
michael@0 311 receiveMessage: function(aMessage) {
michael@0 312 if (DEBUG) {
michael@0 313 debug("NetworkStatsmanager::receiveMessage: " + aMessage.name);
michael@0 314 }
michael@0 315
michael@0 316 let msg = aMessage.json;
michael@0 317 let req = this.takeRequest(msg.id);
michael@0 318 if (!req) {
michael@0 319 if (DEBUG) {
michael@0 320 debug("No request stored with id " + msg.id);
michael@0 321 }
michael@0 322 return;
michael@0 323 }
michael@0 324
michael@0 325 switch (aMessage.name) {
michael@0 326 case "NetworkStats:Get:Return":
michael@0 327 if (msg.error) {
michael@0 328 Services.DOMRequest.fireError(req, msg.error);
michael@0 329 return;
michael@0 330 }
michael@0 331
michael@0 332 let result = new NetworkStats(this._window, msg.result);
michael@0 333 if (DEBUG) {
michael@0 334 debug("result: " + JSON.stringify(result));
michael@0 335 }
michael@0 336 Services.DOMRequest.fireSuccess(req, result);
michael@0 337 break;
michael@0 338
michael@0 339 case "NetworkStats:GetAvailableNetworks:Return":
michael@0 340 if (msg.error) {
michael@0 341 Services.DOMRequest.fireError(req, msg.error);
michael@0 342 return;
michael@0 343 }
michael@0 344
michael@0 345 let networks = new this._window.Array();
michael@0 346 for (let i = 0; i < msg.result.length; i++) {
michael@0 347 networks.push(new NetworkStatsInterface(msg.result[i]));
michael@0 348 }
michael@0 349
michael@0 350 Services.DOMRequest.fireSuccess(req, networks);
michael@0 351 break;
michael@0 352
michael@0 353 case "NetworkStats:GetAvailableServiceTypes:Return":
michael@0 354 if (msg.error) {
michael@0 355 Services.DOMRequest.fireError(req, msg.error);
michael@0 356 return;
michael@0 357 }
michael@0 358
michael@0 359 let serviceTypes = new this._window.Array();
michael@0 360 for (let i = 0; i < msg.result.length; i++) {
michael@0 361 serviceTypes.push(msg.result[i]);
michael@0 362 }
michael@0 363
michael@0 364 Services.DOMRequest.fireSuccess(req, serviceTypes);
michael@0 365 break;
michael@0 366
michael@0 367 case "NetworkStats:Clear:Return":
michael@0 368 case "NetworkStats:ClearAll:Return":
michael@0 369 if (msg.error) {
michael@0 370 Services.DOMRequest.fireError(req, msg.error);
michael@0 371 return;
michael@0 372 }
michael@0 373
michael@0 374 Services.DOMRequest.fireSuccess(req, true);
michael@0 375 break;
michael@0 376
michael@0 377 case "NetworkStats:SetAlarm:Return":
michael@0 378 case "NetworkStats:RemoveAlarms:Return":
michael@0 379 if (msg.error) {
michael@0 380 Services.DOMRequest.fireError(req, msg.error);
michael@0 381 return;
michael@0 382 }
michael@0 383
michael@0 384 Services.DOMRequest.fireSuccess(req, msg.result);
michael@0 385 break;
michael@0 386
michael@0 387 case "NetworkStats:GetAlarms:Return":
michael@0 388 if (msg.error) {
michael@0 389 Services.DOMRequest.fireError(req, msg.error);
michael@0 390 return;
michael@0 391 }
michael@0 392
michael@0 393 let alarms = new this._window.Array();
michael@0 394 for (let i = 0; i < msg.result.length; i++) {
michael@0 395 alarms.push(new NetworkStatsAlarm(msg.result[i]));
michael@0 396 }
michael@0 397
michael@0 398 Services.DOMRequest.fireSuccess(req, alarms);
michael@0 399 break;
michael@0 400
michael@0 401 default:
michael@0 402 if (DEBUG) {
michael@0 403 debug("Wrong message: " + aMessage.name);
michael@0 404 }
michael@0 405 }
michael@0 406 },
michael@0 407
michael@0 408 init: function(aWindow) {
michael@0 409 // Set navigator.mozNetworkStats to null.
michael@0 410 if (!Services.prefs.getBoolPref("dom.mozNetworkStats.enabled")) {
michael@0 411 return null;
michael@0 412 }
michael@0 413
michael@0 414 let principal = aWindow.document.nodePrincipal;
michael@0 415 let secMan = Services.scriptSecurityManager;
michael@0 416 let perm = principal == secMan.getSystemPrincipal() ?
michael@0 417 Ci.nsIPermissionManager.ALLOW_ACTION :
michael@0 418 Services.perms.testExactPermissionFromPrincipal(principal,
michael@0 419 "networkstats-manage");
michael@0 420
michael@0 421 // Only pages with perm set can use the netstats.
michael@0 422 this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
michael@0 423 if (DEBUG) {
michael@0 424 debug("has privileges: " + this.hasPrivileges);
michael@0 425 }
michael@0 426
michael@0 427 if (!this.hasPrivileges) {
michael@0 428 return null;
michael@0 429 }
michael@0 430
michael@0 431 this.initDOMRequestHelper(aWindow, ["NetworkStats:Get:Return",
michael@0 432 "NetworkStats:GetAvailableNetworks:Return",
michael@0 433 "NetworkStats:GetAvailableServiceTypes:Return",
michael@0 434 "NetworkStats:Clear:Return",
michael@0 435 "NetworkStats:ClearAll:Return",
michael@0 436 "NetworkStats:SetAlarm:Return",
michael@0 437 "NetworkStats:GetAlarms:Return",
michael@0 438 "NetworkStats:RemoveAlarms:Return"]);
michael@0 439
michael@0 440 // Init app properties.
michael@0 441 let appsService = Cc["@mozilla.org/AppsService;1"]
michael@0 442 .getService(Ci.nsIAppsService);
michael@0 443
michael@0 444 this.manifestURL = appsService.getManifestURLByLocalId(principal.appId);
michael@0 445
michael@0 446 let isApp = !!this.manifestURL.length;
michael@0 447 if (isApp) {
michael@0 448 this.pageURL = principal.URI.spec;
michael@0 449 }
michael@0 450 },
michael@0 451
michael@0 452 // Called from DOMRequestIpcHelper
michael@0 453 uninit: function uninit() {
michael@0 454 if (DEBUG) {
michael@0 455 debug("uninit call");
michael@0 456 }
michael@0 457 },
michael@0 458
michael@0 459 classID : NETWORKSTATSMANAGER_CID,
michael@0 460 QueryInterface : XPCOMUtils.generateQI([nsIDOMMozNetworkStatsManager,
michael@0 461 Ci.nsIDOMGlobalPropertyInitializer,
michael@0 462 Ci.nsISupportsWeakReference,
michael@0 463 Ci.nsIObserver]),
michael@0 464
michael@0 465 classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSMANAGER_CID,
michael@0 466 contractID: NETWORKSTATSMANAGER_CONTRACTID,
michael@0 467 classDescription: "NetworkStatsManager",
michael@0 468 interfaces: [nsIDOMMozNetworkStatsManager],
michael@0 469 flags: nsIClassInfo.DOM_OBJECT})
michael@0 470 }
michael@0 471
michael@0 472 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkStatsAlarm,
michael@0 473 NetworkStatsData,
michael@0 474 NetworkStatsInterface,
michael@0 475 NetworkStats,
michael@0 476 NetworkStatsManager]);

mercurial