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

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

mercurial