Bumping manifests a=b2g-bump
[gecko.git] / dom / network / NetworkStatsManager.js
blob83644fc32df81fdc8f1158cd670009c0dccfc98d
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");
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}");
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() {
50   if (DEBUG) {
51     debug("NetworkStatsInterface Constructor");
52   }
55 NetworkStatsInterface.prototype = {
56   __init: function(aNetwork) {
57     this.type = aNetwork.type;
58     this.id = aNetwork.id;
59   },
61   classID : NETWORKSTATSINTERFACE_CID,
63   contractID: NETWORKSTATSINTERFACE_CONTRACTID,
64   QueryInterface : XPCOMUtils.generateQI([])
67 // NetworkStats
68 const NETWORKSTATS_CID = Components.ID("{28904f59-8497-4ac0-904f-2af14b7fd3de}");
70 function NetworkStats(aWindow, aStats) {
71   if (DEBUG) {
72     debug("NetworkStats Constructor");
73   }
74   this.appManifestURL = aStats.appManifestURL || null;
75   this.browsingTrafficOnly = aStats.browsingTrafficOnly || false;
76   this.serviceType = aStats.serviceType || null;
77   this.network = new aWindow.MozNetworkStatsInterface(aStats.network);
78   this.start = aStats.start ? new aWindow.Date(aStats.start.getTime()) : null;
79   this.end = aStats.end ? new aWindow.Date(aStats.end.getTime()) : null;
81   let samples = this.data = new aWindow.Array();
82   for (let i = 0; i < aStats.data.length; i++) {
83     samples.push(aWindow.MozNetworkStatsData._create(
84       aWindow, new NetworkStatsData(aWindow, aStats.data[i])));
85   }
88 NetworkStats.prototype = {
89   classID : NETWORKSTATS_CID,
91   QueryInterface : XPCOMUtils.generateQI()
94 // NetworkStatsAlarm
95 const NETWORKSTATSALARM_CID = Components.ID("{a93ea13e-409c-4189-9b1e-95fff220be55}");
97 function NetworkStatsAlarm(aWindow, aAlarm) {
98   this.alarmId = aAlarm.id;
99   this.network = new aWindow.MozNetworkStatsInterface(aAlarm.network);
100   this.threshold = aAlarm.threshold;
101   this.data = aAlarm.data;
104 NetworkStatsAlarm.prototype = {
105   classID : NETWORKSTATSALARM_CID,
107   QueryInterface : XPCOMUtils.generateQI([])
110 // NetworkStatsManager
112 const NETWORKSTATSMANAGER_CONTRACTID = "@mozilla.org/networkStatsManager;1";
113 const NETWORKSTATSMANAGER_CID        = Components.ID("{ceb874cd-cc1a-4e65-b404-cc2d3e42425f}");
114 const nsIDOMMozNetworkStatsManager   = Ci.nsIDOMMozNetworkStatsManager;
116 function NetworkStatsManager() {
117   if (DEBUG) {
118     debug("Constructor");
119   }
122 NetworkStatsManager.prototype = {
123   __proto__: DOMRequestIpcHelper.prototype,
125   checkPrivileges: function checkPrivileges() {
126     if (!this.hasPrivileges) {
127       throw Components.Exception("Permission denied", Cr.NS_ERROR_FAILURE);
128     }
129   },
131   getSamples: function getSamples(aNetwork, aStart, aEnd, aOptions) {
132     this.checkPrivileges();
134     if (aStart.constructor.name !== "Date" ||
135         aEnd.constructor.name !== "Date" ||
136         !(aNetwork instanceof this.window.MozNetworkStatsInterface) ||
137         aStart > aEnd) {
138       throw Components.results.NS_ERROR_INVALID_ARG;
139     }
141     let appManifestURL = null;
142     let browsingTrafficOnly = false;
143     let serviceType = null;
144     if (aOptions) {
145       // appManifestURL is used to query network statistics by app;
146       // serviceType is used to query network statistics by system service.
147       // It is illegal to specify both of them at the same time.
148       if (aOptions.appManifestURL && aOptions.serviceType) {
149         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
150       }
151       // browsingTrafficOnly is meaningful only when querying by app.
152       if (!aOptions.appManifestURL && aOptions.browsingTrafficOnly) {
153         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
154       }
155       appManifestURL = aOptions.appManifestURL;
156       serviceType = aOptions.serviceType;
157       browsingTrafficOnly = aOptions.browsingTrafficOnly || false;
158     }
160     // TODO Bug 929410 Date object cannot correctly pass through cpmm/ppmm IPC
161     // This is just a work-around by passing timestamp numbers.
162     aStart = aStart.getTime();
163     aEnd = aEnd.getTime();
165     let request = this.createRequest();
166     cpmm.sendAsyncMessage("NetworkStats:Get",
167                           { network: aNetwork.toJSON(),
168                             start: aStart,
169                             end: aEnd,
170                             appManifestURL: appManifestURL,
171                             browsingTrafficOnly: browsingTrafficOnly,
172                             serviceType: serviceType,
173                             id: this.getRequestId(request) });
174     return request;
175   },
177   clearStats: function clearStats(aNetwork) {
178     this.checkPrivileges();
180     if (!aNetwork instanceof this.window.MozNetworkStatsInterface) {
181       throw Components.results.NS_ERROR_INVALID_ARG;
182     }
184     let request = this.createRequest();
185     cpmm.sendAsyncMessage("NetworkStats:Clear",
186                           { network: aNetwork.toJSON(),
187                             id: this.getRequestId(request) });
188     return request;
189   },
191   clearAllStats: function clearAllStats() {
192     this.checkPrivileges();
194     let request = this.createRequest();
195     cpmm.sendAsyncMessage("NetworkStats:ClearAll",
196                           {id: this.getRequestId(request)});
197     return request;
198   },
200   addAlarm: function addAlarm(aNetwork, aThreshold, aOptions) {
201     this.checkPrivileges();
203     if (!aOptions) {
204       aOptions = Object.create(null);
205     }
207     if (aOptions.startTime && aOptions.startTime.constructor.name !== "Date" ||
208         !(aNetwork instanceof this.window.MozNetworkStatsInterface)) {
209       throw Components.results.NS_ERROR_INVALID_ARG;
210     }
212     let request = this.createRequest();
213     cpmm.sendAsyncMessage("NetworkStats:SetAlarm",
214                           {id: this.getRequestId(request),
215                            data: {network: aNetwork.toJSON(),
216                                   threshold: aThreshold,
217                                   startTime: aOptions.startTime,
218                                   data: aOptions.data,
219                                   manifestURL: this.manifestURL,
220                                   pageURL: this.pageURL}});
221     return request;
222   },
224   getAllAlarms: function getAllAlarms(aNetwork) {
225     this.checkPrivileges();
227     let network = null;
228     if (aNetwork) {
229       if (!aNetwork instanceof this.window.MozNetworkStatsInterface) {
230         throw Components.results.NS_ERROR_INVALID_ARG;
231       }
232       network = aNetwork.toJSON();
233     }
235     let request = this.createRequest();
236     cpmm.sendAsyncMessage("NetworkStats:GetAlarms",
237                           {id: this.getRequestId(request),
238                            data: {network: network,
239                                   manifestURL: this.manifestURL}});
240     return request;
241   },
243   removeAlarms: function removeAlarms(aAlarmId) {
244     this.checkPrivileges();
246     if (aAlarmId == 0) {
247       aAlarmId = -1;
248     }
250     let request = this.createRequest();
251     cpmm.sendAsyncMessage("NetworkStats:RemoveAlarms",
252                           {id: this.getRequestId(request),
253                            data: {alarmId: aAlarmId,
254                                   manifestURL: this.manifestURL}});
256     return request;
257   },
259   getAvailableNetworks: function getAvailableNetworks() {
260     this.checkPrivileges();
262     let request = this.createRequest();
263     cpmm.sendAsyncMessage("NetworkStats:GetAvailableNetworks",
264                           { id: this.getRequestId(request) });
265     return request;
266   },
268   getAvailableServiceTypes: function getAvailableServiceTypes() {
269     this.checkPrivileges();
271     let request = this.createRequest();
272     cpmm.sendAsyncMessage("NetworkStats:GetAvailableServiceTypes",
273                           { id: this.getRequestId(request) });
274     return request;
275   },
277   get sampleRate() {
278     this.checkPrivileges();
279     return cpmm.sendSyncMessage("NetworkStats:SampleRate")[0];
280   },
282   get maxStorageAge() {
283     this.checkPrivileges();
284     return cpmm.sendSyncMessage("NetworkStats:MaxStorageAge")[0];
285   },
287   receiveMessage: function(aMessage) {
288     if (DEBUG) {
289       debug("NetworkStatsmanager::receiveMessage: " + aMessage.name);
290     }
292     let msg = aMessage.json;
293     let req = this.takeRequest(msg.id);
294     if (!req) {
295       if (DEBUG) {
296         debug("No request stored with id " + msg.id);
297       }
298       return;
299     }
301     switch (aMessage.name) {
302       case "NetworkStats:Get:Return":
303         if (msg.error) {
304           Services.DOMRequest.fireError(req, msg.error);
305           return;
306         }
308         let result = this._window.MozNetworkStats._create(
309           this._window, new NetworkStats(this._window, msg.result));
310         if (DEBUG) {
311           debug("result: " + JSON.stringify(result));
312         }
313         Services.DOMRequest.fireSuccess(req, result);
314         break;
316       case "NetworkStats:GetAvailableNetworks:Return":
317         if (msg.error) {
318           Services.DOMRequest.fireError(req, msg.error);
319           return;
320         }
322         let networks = new this._window.Array();
323         for (let i = 0; i < msg.result.length; i++) {
324           let network = new this._window.MozNetworkStatsInterface(msg.result[i]);
325           networks.push(network);
326         }
328         Services.DOMRequest.fireSuccess(req, networks);
329         break;
331       case "NetworkStats:GetAvailableServiceTypes:Return":
332         if (msg.error) {
333           Services.DOMRequest.fireError(req, msg.error);
334           return;
335         }
337         let serviceTypes = new this._window.Array();
338         for (let i = 0; i < msg.result.length; i++) {
339           serviceTypes.push(msg.result[i]);
340         }
342         Services.DOMRequest.fireSuccess(req, serviceTypes);
343         break;
345       case "NetworkStats:Clear:Return":
346       case "NetworkStats:ClearAll:Return":
347         if (msg.error) {
348           Services.DOMRequest.fireError(req, msg.error);
349           return;
350         }
352         Services.DOMRequest.fireSuccess(req, true);
353         break;
355       case "NetworkStats:SetAlarm:Return":
356       case "NetworkStats:RemoveAlarms:Return":
357         if (msg.error) {
358           Services.DOMRequest.fireError(req, msg.error);
359           return;
360         }
362         Services.DOMRequest.fireSuccess(req, msg.result);
363         break;
365       case "NetworkStats:GetAlarms:Return":
366         if (msg.error) {
367           Services.DOMRequest.fireError(req, msg.error);
368           return;
369         }
371         let alarms = new this._window.Array();
372         for (let i = 0; i < msg.result.length; i++) {
373           // The WebIDL type of data is any, so we should manually clone it
374           // into the content window.
375           if ("data" in msg.result[i]) {
376             msg.result[i].data = Cu.cloneInto(msg.result[i].data, this._window);
377           }
378           let alarm = new NetworkStatsAlarm(this._window, msg.result[i]);
379           alarms.push(this._window.MozNetworkStatsAlarm._create(this._window, alarm));
380         }
382         Services.DOMRequest.fireSuccess(req, alarms);
383         break;
385       default:
386         if (DEBUG) {
387           debug("Wrong message: " + aMessage.name);
388         }
389     }
390   },
392   init: function(aWindow) {
393     // Set navigator.mozNetworkStats to null.
394     if (!Services.prefs.getBoolPref("dom.mozNetworkStats.enabled")) {
395       return null;
396     }
398     let principal = aWindow.document.nodePrincipal;
399     let secMan = Services.scriptSecurityManager;
400     let perm = principal == secMan.getSystemPrincipal() ?
401                  Ci.nsIPermissionManager.ALLOW_ACTION :
402                  Services.perms.testExactPermissionFromPrincipal(principal,
403                                                                  "networkstats-manage");
405     // Only pages with perm set can use the netstats.
406     this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
407     if (DEBUG) {
408       debug("has privileges: " + this.hasPrivileges);
409     }
411     if (!this.hasPrivileges) {
412       return null;
413     }
415     this.initDOMRequestHelper(aWindow, ["NetworkStats:Get:Return",
416                                         "NetworkStats:GetAvailableNetworks:Return",
417                                         "NetworkStats:GetAvailableServiceTypes:Return",
418                                         "NetworkStats:Clear:Return",
419                                         "NetworkStats:ClearAll:Return",
420                                         "NetworkStats:SetAlarm:Return",
421                                         "NetworkStats:GetAlarms:Return",
422                                         "NetworkStats:RemoveAlarms:Return"]);
424     // Init app properties.
425     let appsService = Cc["@mozilla.org/AppsService;1"]
426                         .getService(Ci.nsIAppsService);
428     this.manifestURL = appsService.getManifestURLByLocalId(principal.appId);
430     let isApp = !!this.manifestURL.length;
431     if (isApp) {
432       this.pageURL = principal.URI.spec;
433     }
435     this.window = aWindow;
436   },
438   // Called from DOMRequestIpcHelper
439   uninit: function uninit() {
440     if (DEBUG) {
441       debug("uninit call");
442     }
443   },
445   classID : NETWORKSTATSMANAGER_CID,
446   QueryInterface : XPCOMUtils.generateQI([nsIDOMMozNetworkStatsManager,
447                                          Ci.nsIDOMGlobalPropertyInitializer,
448                                          Ci.nsISupportsWeakReference,
449                                          Ci.nsIObserver]),
451   classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSMANAGER_CID,
452                                      contractID: NETWORKSTATSMANAGER_CONTRACTID,
453                                      classDescription: "NetworkStatsManager",
454                                      interfaces: [nsIDOMMozNetworkStatsManager],
455                                      flags: nsIClassInfo.DOM_OBJECT})
458 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkStatsAlarm,
459                                                      NetworkStatsData,
460                                                      NetworkStatsInterface,
461                                                      NetworkStats,
462                                                      NetworkStatsManager]);