diff options
Diffstat (limited to 'dom/network')
-rw-r--r-- | dom/network/EthernetManager.js | 655 | ||||
-rw-r--r-- | dom/network/EthernetManager.manifest | 2 | ||||
-rw-r--r-- | dom/network/NetUtils.cpp | 200 | ||||
-rw-r--r-- | dom/network/NetUtils.h | 75 | ||||
-rw-r--r-- | dom/network/NetworkStatsDB.jsm | 1285 | ||||
-rw-r--r-- | dom/network/NetworkStatsManager.js | 388 | ||||
-rw-r--r-- | dom/network/NetworkStatsManager.manifest | 14 | ||||
-rw-r--r-- | dom/network/NetworkStatsService.jsm | 1171 | ||||
-rw-r--r-- | dom/network/NetworkStatsServiceProxy.js | 90 | ||||
-rw-r--r-- | dom/network/NetworkStatsServiceProxy.manifest | 2 | ||||
-rw-r--r-- | dom/network/TCPSocket.cpp | 72 | ||||
-rw-r--r-- | dom/network/TCPSocket.h | 17 | ||||
-rw-r--r-- | dom/network/interfaces/moz.build | 6 | ||||
-rw-r--r-- | dom/network/interfaces/nsIEthernetManager.idl | 137 | ||||
-rw-r--r-- | dom/network/interfaces/nsINetworkStatsServiceProxy.idl | 64 | ||||
-rw-r--r-- | dom/network/moz.build | 22 |
16 files changed, 1 insertions, 4199 deletions
diff --git a/dom/network/EthernetManager.js b/dom/network/EthernetManager.js deleted file mode 100644 index 4b11e5666..000000000 --- a/dom/network/EthernetManager.js +++ /dev/null @@ -1,655 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* 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 {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -const TOPIC_INTERFACE_STATE_CHANGED = "network-interface-state-changed"; - -const ETHERNET_NETWORK_IFACE_PREFIX = "eth"; -const DEFAULT_ETHERNET_NETWORK_IFACE = "eth0"; - -const INTERFACE_IPADDR_NULL = "0.0.0.0"; -const INTERFACE_GATEWAY_NULL = "0.0.0.0"; -const INTERFACE_PREFIX_NULL = 0; -const INTERFACE_MACADDR_NULL = "00:00:00:00:00:00"; - -const NETWORK_INTERFACE_UP = "up"; -const NETWORK_INTERFACE_DOWN = "down"; - -const IP_MODE_DHCP = "dhcp"; -const IP_MODE_STATIC = "static"; - -const PREF_NETWORK_DEBUG_ENABLED = "network.debugging.enabled"; - -XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager", - "@mozilla.org/network/manager;1", - "nsINetworkManager"); - -XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService", - "@mozilla.org/network/service;1", - "nsINetworkService"); - -let debug; -function updateDebug() { - let debugPref = false; // set default value here. - try { - debugPref = debugPref || Services.prefs.getBoolPref(PREF_NETWORK_DEBUG_ENABLED); - } catch (e) {} - - if (debugPref) { - debug = function(s) { - dump("-*- EthernetManager: " + s + "\n"); - }; - } else { - debug = function(s) {}; - } -} -updateDebug(); - -// nsINetworkInterface - -function EthernetInterface(attr) { - this.info.state = attr.state; - this.info.type = attr.type; - this.info.name = attr.name; - this.info.ipMode = attr.ipMode; - this.info.ips = [attr.ip]; - this.info.prefixLengths = [attr.prefixLength]; - this.info.gateways = [attr.gateway]; - this.info.dnses = attr.dnses; - this.httpProxyHost = ""; - this.httpProxyPort = 0; -} -EthernetInterface.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterface]), - - updateConfig: function(config) { - debug("Interface " + this.info.name + " updateConfig " + JSON.stringify(config)); - this.info.state = (config.state != undefined) ? - config.state : this.info.state; - this.info.ips = (config.ip != undefined) ? [config.ip] : this.info.ips; - this.info.prefixLengths = (config.prefixLength != undefined) ? - [config.prefixLength] : this.info.prefixLengths; - this.info.gateways = (config.gateway != undefined) ? - [config.gateway] : this.info.gateways; - this.info.dnses = (config.dnses != undefined) ? config.dnses : this.info.dnses; - this.httpProxyHost = (config.httpProxyHost != undefined) ? - config.httpProxyHost : this.httpProxyHost; - this.httpProxyPort = (config.httpProxyPort != undefined) ? - config.httpProxyPort : this.httpProxyPort; - this.info.ipMode = (config.ipMode != undefined) ? - config.ipMode : this.info.ipMode; - }, - - info: { - getAddresses: function(ips, prefixLengths) { - ips.value = this.ips.slice(); - prefixLengths.value = this.prefixLengths.slice(); - - return this.ips.length; - }, - - getGateways: function(count) { - if (count) { - count.value = this.gateways.length; - } - return this.gateways.slice(); - }, - - getDnses: function(count) { - if (count) { - count.value = this.dnses.length; - } - return this.dnses.slice(); - } - } -}; - -// nsIEthernetManager - -/* - * Network state transition diagram - * - * ---------- enable --------- connect ----------- disconnect -------------- - * | Disabled | -----> | Enabled | -------> | Connected | <----------> | Disconnected | - * ---------- --------- ----------- connect -------------- - * ^ | | | - * | disable | | | - * ----------------------------------------------------------------------- - */ - -function EthernetManager() { - debug("EthernetManager start"); - - // Interface list. - this.ethernetInterfaces = {}; - - // Used to memorize last connection information. - this.lastStaticConfig = {}; - - Services.obs.addObserver(this, "xpcom-shutdown", false); -} - -EthernetManager.prototype = { - classID: Components.ID("a96441dd-36b3-4f7f-963b-2c032e28a039"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsIEthernetManager]), - - ethernetInterfaces: null, - lastStaticConfig: null, - - observer: function(subject, topic, data) { - switch (topic) { - case "xpcom-shutdown": - debug("xpcom-shutdown"); - - this._shutdown(); - - Services.obs.removeObserver(this, "xpcom-shutdown"); - break; - } - }, - - _shutdown: function() { - debug("Shuting down"); - (function onRemove(ifnameList) { - if (!ifnameList.length) { - return; - } - - let ifname = ifnameList.shift(); - this.removeInterface(ifname, { notify: onRemove.bind(this, ifnameList) }); - }).call(this, Object.keys(this.ethernetInterfaces)); - }, - - get interfaceList() { - return Object.keys(this.ethernetInterfaces); - }, - - scan: function(callback) { - debug("Scan"); - - gNetworkService.getInterfaces(function(success, list) { - let ethList = []; - - if (!success) { - if (callback) { - callback.notify(ethList); - } - return; - } - - for (let i = 0; i < list.length; i++) { - debug("Found interface " + list[i]); - if (!list[i].startsWith(ETHERNET_NETWORK_IFACE_PREFIX)) { - continue; - } - ethList.push(list[i]); - } - - if (callback) { - callback.notify(ethList); - } - }); - }, - - addInterface: function(ifname, callback) { - debug("Add interface " + ifname); - - if (!ifname || !ifname.startsWith(ETHERNET_NETWORK_IFACE_PREFIX)) { - if (callback) { - callback.notify(false, "Invalid interface."); - } - return; - } - - if (this.ethernetInterfaces[ifname]) { - if (callback) { - callback.notify(true, "Interface already exists."); - } - return; - } - - gNetworkService.getInterfaceConfig(ifname, function(success, result) { - if (!success) { - if (callback) { - callback.notify(false, "Netd error."); - } - return; - } - - // Since the operation may still succeed with an invalid interface name, - // check the mac address as well. - if (result.macAddr == INTERFACE_MACADDR_NULL) { - if (callback) { - callback.notify(false, "Interface not found."); - } - return; - } - - this.ethernetInterfaces[ifname] = new EthernetInterface({ - state: result.link == NETWORK_INTERFACE_UP ? - Ci.nsINetworkInfo.NETWORK_STATE_DISABLED : - Ci.nsINetworkInfo.NETWORK_STATE_ENABLED, - name: ifname, - type: Ci.nsINetworkInfo.NETWORK_TYPE_ETHERNET, - ip: result.ip, - prefixLength: result.prefix, - ipMode: IP_MODE_DHCP - }); - - // Register the interface to NetworkManager. - gNetworkManager.registerNetworkInterface(this.ethernetInterfaces[ifname]); - - debug("Add interface " + ifname + " succeeded with " + - JSON.stringify(this.ethernetInterfaces[ifname])); - - if (callback) { - callback.notify(true, "ok"); - } - }.bind(this)); - }, - - removeInterface: function(ifname, callback) { - debug("Remove interface " + ifname); - - if (!ifname || !ifname.startsWith(ETHERNET_NETWORK_IFACE_PREFIX)) { - if (callback) { - callback.notify(false, "Invalid interface."); - } - return; - } - - if (!this.ethernetInterfaces[ifname]) { - if (callback) { - callback.notify(true, "Interface does not exist."); - } - return; - } - - // Make sure interface is disable before removing. - this.disable(ifname, { notify: function(success, message) { - // Unregister the interface from NetworkManager and also remove it from - // the interface list. - gNetworkManager.unregisterNetworkInterface(this.ethernetInterfaces[ifname]); - delete this.ethernetInterfaces[ifname]; - - debug("Remove interface " + ifname + " succeeded."); - - if (callback) { - callback.notify(true, "ok"); - } - }.bind(this)}); - }, - - updateInterfaceConfig: function(ifname, config, callback) { - debug("Update interface config with " + ifname); - - this._ensureIfname(ifname, callback, function(iface) { - if (!config) { - if (callback) { - callback.notify(false, "No config to update."); - } - return; - } - - // Network state can not be modified externally. - if (config.state) { - delete config.state; - } - - let currentIpMode = iface.info.ipMode; - - // Update config. - this.ethernetInterfaces[iface.info.name].updateConfig(config); - - // Do not automatically re-connect if the interface is not in connected - // state. - if (iface.info.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) { - if (callback) { - callback.notify(true, "ok"); - } - return; - } - - let newIpMode = this.ethernetInterfaces[iface.info.name].info.ipMode; - - if (newIpMode == IP_MODE_STATIC) { - this._setStaticIP(iface.info.name, callback); - return; - } - if ((currentIpMode == IP_MODE_STATIC) && (newIpMode == IP_MODE_DHCP)) { - gNetworkService.stopDhcp(iface.info.name, function(success) { - if (success) { - debug("DHCP for " + iface.info.name + " stopped."); - } - }); - - // Clear the current network settings before do dhcp request, otherwise - // dhcp settings could fail. - this.disconnect(iface.info.name, { notify: function(success, message) { - if (!success) { - if (callback) { - callback.notify("Disconnect failed."); - } - return; - } - this._runDhcp(iface.info.name, callback); - }.bind(this) }); - return; - } - - if (callback) { - callback.notify(true, "ok"); - } - }.bind(this)); - }, - - enable: function(ifname, callback) { - debug("Enable interface " + ifname); - - this._ensureIfname(ifname, callback, function(iface) { - // Interface can be only enabled in the state of disabled. - if (iface.info.state != Ci.nsINetworkInfo.NETWORK_STATE_DISABLED) { - if (callback) { - callback.notify(true, "Interface already enabled."); - } - return; - } - - let ips = {}; - let prefixLengths = {}; - iface.info.getAddresses(ips, prefixLengths); - let config = { ifname: iface.info.name, - ip: ips.value[0], - prefix: prefixLengths.value[0], - link: NETWORK_INTERFACE_UP }; - gNetworkService.setInterfaceConfig(config, function(success) { - if (!success) { - if (callback) { - callback.notify(false, "Netd Error."); - } - return; - } - - this.ethernetInterfaces[iface.info.name].updateConfig({ - state: Ci.nsINetworkInfo.NETWORK_STATE_ENABLED - }); - - debug("Enable interface " + iface.info.name + " succeeded."); - - if (callback) { - callback.notify(true, "ok"); - } - }.bind(this)); - }.bind(this)); - }, - - disable: function(ifname, callback) { - debug("Disable interface " + ifname); - - this._ensureIfname(ifname, callback, function(iface) { - if (iface.info.state == Ci.nsINetworkInfo.NETWORK_STATE_DISABLED) { - if (callback) { - callback.notify(true, "Interface already disabled."); - } - return; - } - - if (iface.info.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) { - gNetworkService.stopDhcp(iface.info.name, function(success) { - if (success) { - debug("DHCP for " + iface.info.name + " stopped."); - } - }); - } - - let ips = {}; - let prefixLengths = {}; - iface.info.getAddresses(ips, prefixLengths); - let config = { ifname: iface.info.name, - ip: ips.value[0], - prefix: prefixLengths.value[0], - link: NETWORK_INTERFACE_DOWN }; - gNetworkService.setInterfaceConfig(config, function(success) { - if (!success) { - if (callback) { - callback.notify(false, "Netd Error."); - } - return; - } - - this.ethernetInterfaces[iface.info.name].updateConfig({ - state: Ci.nsINetworkInfo.NETWORK_STATE_DISABLED - }); - - debug("Disable interface " + iface.info.name + " succeeded."); - - if (callback) { - callback.notify(true, "ok"); - } - }.bind(this)); - }.bind(this)); - }, - - connect: function(ifname, callback) { - debug("Connect interface " + ifname); - - this._ensureIfname(ifname, callback, function(iface) { - // Interface can only be connected in the state of enabled or - // disconnected. - if (iface.info.state == Ci.nsINetworkInfo.NETWORK_STATE_DISABLED || - iface.info.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) { - if (callback) { - callback.notify(true, "Interface " + ifname + " is not available or " - + " already connected."); - } - return; - } - - if (iface.info.ipMode == IP_MODE_DHCP) { - this._runDhcp(iface.info.name, callback); - return; - } - - if (iface.info.ipMode == IP_MODE_STATIC) { - if (this._checkConfigNull(iface) && this.lastStaticConfig[iface.info.name]) { - debug("Connect with lastStaticConfig " + - JSON.stringify(this.lastStaticConfig[iface.info.name])); - this.ethernetInterfaces[iface.info.name].updateConfig( - this.lastStaticConfig[iface.info.name]); - } - this._setStaticIP(iface.info.name, callback); - return; - } - - if (callback) { - callback.notify(false, "IP mode is wrong or not set."); - } - }.bind(this)); - }, - - disconnect: function(ifname, callback) { - debug("Disconnect interface " + ifname); - - this._ensureIfname(ifname, callback, function(iface) { - // Interface can be only disconnected in the state of connected. - if (iface.info.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) { - if (callback) { - callback.notify(true, "Interface is already disconnected"); - } - return; - } - - let config = { ifname: iface.info.name, - ip: INTERFACE_IPADDR_NULL, - prefix: INTERFACE_PREFIX_NULL, - link: NETWORK_INTERFACE_UP }; - gNetworkService.setInterfaceConfig(config, function(success) { - if (!success) { - if (callback) { - callback.notify(false, "Netd error."); - } - return; - } - - // Stop dhcp daemon. - gNetworkService.stopDhcp(iface.info.name, function(success) { - if (success) { - debug("DHCP for " + iface.info.name + " stopped."); - } - }); - - this.ethernetInterfaces[iface.info.name].updateConfig({ - state: Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED, - ip: INTERFACE_IPADDR_NULL, - prefixLength: INTERFACE_PREFIX_NULL, - gateway: INTERFACE_GATEWAY_NULL - }); - - gNetworkManager.updateNetworkInterface(this.ethernetInterfaces[ifname]); - - debug("Disconnect interface " + iface.info.name + " succeeded."); - - if (callback) { - callback.notify(true, "ok"); - } - }.bind(this)); - }.bind(this)); - }, - - _checkConfigNull: function(iface) { - let ips = {}; - let prefixLengths = {}; - let gateways = iface.info.getGateways(); - iface.info.getAddresses(ips, prefixLengths); - - if (ips.value[0] == INTERFACE_IPADDR_NULL && - prefixLengths.value[0] == INTERFACE_PREFIX_NULL && - gateways[0] == INTERFACE_GATEWAY_NULL) { - return true; - } - - return false; - }, - - _ensureIfname: function(ifname, callback, func) { - // If no given ifname, use the default one. - if (!ifname) { - ifname = DEFAULT_ETHERNET_NETWORK_IFACE; - } - - let iface = this.ethernetInterfaces[ifname]; - if (!iface) { - if (callback) { - callback.notify(true, "Interface " + ifname + " is not available."); - } - return; - } - - func.call(this, iface); - }, - - _runDhcp: function(ifname, callback) { - debug("runDhcp with " + ifname); - - if (!this.ethernetInterfaces[ifname]) { - if (callback) { - callback.notify(false, "Invalid interface."); - } - return; - } - - gNetworkService.dhcpRequest(ifname, function(success, result) { - if (!success) { - if (callback) { - callback.notify(false, "DHCP failed."); - } - return; - } - - debug("DHCP succeeded with " + JSON.stringify(result)); - - // Clear last static network information when connecting with dhcp mode. - if (this.lastStaticConfig[ifname]) { - this.lastStaticConfig[ifname] = null; - } - - this.ethernetInterfaces[ifname].updateConfig({ - state: Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED, - ip: result.ipaddr_str, - gateway: result.gateway_str, - prefixLength: result.prefixLength, - dnses: [result.dns1_str, result.dns2_str] - }); - - gNetworkManager.updateNetworkInterface(this.ethernetInterfaces[ifname]); - - debug("Connect interface " + ifname + " with DHCP succeeded."); - - if (callback) { - callback.notify(true, "ok"); - } - }.bind(this)); - }, - - _setStaticIP: function(ifname, callback) { - let iface = this.ethernetInterfaces[ifname]; - if (!iface) { - if (callback) { - callback.notify(false, "Invalid interface."); - } - return; - } - - let ips = {}; - let prefixLengths = {}; - iface.info.getAddresses(ips, prefixLengths); - - let config = { ifname: iface.info.name, - ip: ips.value[0], - prefix: prefixLengths.value[0], - link: NETWORK_INTERFACE_UP }; - gNetworkService.setInterfaceConfig(config, function(success) { - if (!success) { - if (callback) { - callback.notify(false, "Netd Error."); - } - return; - } - - // Keep the lastest static network information. - let ips = {}; - let prefixLengths = {}; - let gateways = iface.info.getGateways(); - iface.info.getAddresses(ips, prefixLengths); - - this.lastStaticConfig[iface.info.name] = { - ip: ips.value[0], - prefixLength: prefixLengths.value[0], - gateway: gateways[0] - }; - - this.ethernetInterfaces[ifname].updateConfig({ - state: Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED, - }); - - gNetworkManager.updateNetworkInterface(this.ethernetInterfaces[ifname]); - - debug("Connect interface " + ifname + " with static ip succeeded."); - - if (callback) { - callback.notify(true, "ok"); - } - }.bind(this)); - }, -} - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([EthernetManager]); diff --git a/dom/network/EthernetManager.manifest b/dom/network/EthernetManager.manifest deleted file mode 100644 index d25a069e1..000000000 --- a/dom/network/EthernetManager.manifest +++ /dev/null @@ -1,2 +0,0 @@ -component {a96441dd-36b3-4f7f-963b-2c032e28a039} EthernetManager.js -contract @mozilla.org/ethernetManager;1 {a96441dd-36b3-4f7f-963b-2c032e28a039} diff --git a/dom/network/NetUtils.cpp b/dom/network/NetUtils.cpp deleted file mode 100644 index 78c5be802..000000000 --- a/dom/network/NetUtils.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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/. */ - -#include "NetUtils.h" -#include <dlfcn.h> -#include <errno.h> -#include "prinit.h" -#include "mozilla/Assertions.h" -#include "nsDebug.h" -#include "SystemProperty.h" - -using mozilla::system::Property; - -static void* sNetUtilsLib; -static PRCallOnceType sInitNetUtilsLib; - -static PRStatus -InitNetUtilsLib() -{ - sNetUtilsLib = dlopen("/system/lib/libnetutils.so", RTLD_LAZY); - // We might fail to open the hardware lib. That's OK. - return PR_SUCCESS; -} - -static void* -GetNetUtilsLibHandle() -{ - PR_CallOnce(&sInitNetUtilsLib, InitNetUtilsLib); - return sNetUtilsLib; -} - -// static -void* -NetUtils::GetSharedLibrary() -{ - void* netLib = GetNetUtilsLibHandle(); - if (!netLib) { - NS_WARNING("No /system/lib/libnetutils.so"); - } - return netLib; -} - -// static -int32_t -NetUtils::SdkVersion() -{ - char propVersion[Property::VALUE_MAX_LENGTH]; - Property::Get("ro.build.version.sdk", propVersion, "0"); - int32_t version = strtol(propVersion, nullptr, 10); - return version; -} - -DEFINE_DLFUNC(ifc_enable, int32_t, const char*) -DEFINE_DLFUNC(ifc_disable, int32_t, const char*) -DEFINE_DLFUNC(ifc_configure, int32_t, const char*, in_addr_t, uint32_t, - in_addr_t, in_addr_t, in_addr_t) -DEFINE_DLFUNC(ifc_reset_connections, int32_t, const char*, const int32_t) -DEFINE_DLFUNC(ifc_set_default_route, int32_t, const char*, in_addr_t) -DEFINE_DLFUNC(ifc_add_route, int32_t, const char*, const char*, uint32_t, const char*) -DEFINE_DLFUNC(ifc_remove_route, int32_t, const char*, const char*, uint32_t, const char*) -DEFINE_DLFUNC(ifc_remove_host_routes, int32_t, const char*) -DEFINE_DLFUNC(ifc_remove_default_route, int32_t, const char*) -DEFINE_DLFUNC(dhcp_stop, int32_t, const char*) - -NetUtils::NetUtils() -{ -} - -int32_t NetUtils::do_ifc_enable(const char *ifname) -{ - USE_DLFUNC(ifc_enable) - return ifc_enable(ifname); -} - -int32_t NetUtils::do_ifc_disable(const char *ifname) -{ - USE_DLFUNC(ifc_disable) - return ifc_disable(ifname); -} - -int32_t NetUtils::do_ifc_configure(const char *ifname, - in_addr_t address, - uint32_t prefixLength, - in_addr_t gateway, - in_addr_t dns1, - in_addr_t dns2) -{ - USE_DLFUNC(ifc_configure) - int32_t ret = ifc_configure(ifname, address, prefixLength, gateway, dns1, dns2); - return ret; -} - -int32_t NetUtils::do_ifc_reset_connections(const char *ifname, - const int32_t resetMask) -{ - USE_DLFUNC(ifc_reset_connections) - return ifc_reset_connections(ifname, resetMask); -} - -int32_t NetUtils::do_ifc_set_default_route(const char *ifname, - in_addr_t gateway) -{ - USE_DLFUNC(ifc_set_default_route) - return ifc_set_default_route(ifname, gateway); -} - -int32_t NetUtils::do_ifc_add_route(const char *ifname, - const char *dst, - uint32_t prefixLength, - const char *gateway) -{ - USE_DLFUNC(ifc_add_route) - return ifc_add_route(ifname, dst, prefixLength, gateway); -} - -int32_t NetUtils::do_ifc_remove_route(const char *ifname, - const char *dst, - uint32_t prefixLength, - const char *gateway) -{ - USE_DLFUNC(ifc_remove_route) - return ifc_remove_route(ifname, dst, prefixLength, gateway); -} - -int32_t NetUtils::do_ifc_remove_host_routes(const char *ifname) -{ - USE_DLFUNC(ifc_remove_host_routes) - return ifc_remove_host_routes(ifname); -} - -int32_t NetUtils::do_ifc_remove_default_route(const char *ifname) -{ - USE_DLFUNC(ifc_remove_default_route) - return ifc_remove_default_route(ifname); -} - -int32_t NetUtils::do_dhcp_stop(const char *ifname) -{ - USE_DLFUNC(dhcp_stop) - return dhcp_stop(ifname); -} - -int32_t NetUtils::do_dhcp_do_request(const char *ifname, - char *ipaddr, - char *gateway, - uint32_t *prefixLength, - char *dns1, - char *dns2, - char *server, - uint32_t *lease, - char* vendorinfo) -{ - int32_t ret = -1; - uint32_t sdkVersion = SdkVersion(); - - if (sdkVersion == 15) { - // ICS - // http://androidxref.com/4.0.4/xref/system/core/libnetutils/dhcp_utils.c#149 - DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*, uint32_t*, char*, char*, char*, uint32_t*) - USE_DLFUNC(dhcp_do_request) - vendorinfo[0] = '\0'; - - ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns1, dns2, - server, lease); - } else if (sdkVersion == 16 || sdkVersion == 17) { - // JB 4.1 and 4.2 - // http://androidxref.com/4.1.2/xref/system/core/libnetutils/dhcp_utils.c#175 - // http://androidxref.com/4.2.2_r1/xref/system/core/include/netutils/dhcp.h#26 - DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*, uint32_t*, char*, char*, char*, uint32_t*, char*) - USE_DLFUNC(dhcp_do_request) - ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns1, dns2, - server, lease, vendorinfo); - } else if (sdkVersion == 18) { - // JB 4.3 - // http://androidxref.com/4.3_r2.1/xref/system/core/libnetutils/dhcp_utils.c#181 - DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*, uint32_t*, char**, char*, uint32_t*, char*, char*) - USE_DLFUNC(dhcp_do_request) - char *dns[3] = {dns1, dns2, nullptr}; - char domains[Property::VALUE_MAX_LENGTH]; - ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns, - server, lease, vendorinfo, domains); - } else if (sdkVersion >= 19) { - // KitKat 4.4.X - // http://androidxref.com/4.4_r1/xref/system/core/libnetutils/dhcp_utils.c#18 - // Lollipop 5.0 - //http://androidxref.com/5.0.0_r2/xref/system/core/libnetutils/dhcp_utils.c#186 - DEFINE_DLFUNC(dhcp_do_request, int32_t, const char*, char*, char*, uint32_t*, char**, char*, uint32_t*, char*, char*, char*) - USE_DLFUNC(dhcp_do_request) - char *dns[3] = {dns1, dns2, nullptr}; - char domains[Property::VALUE_MAX_LENGTH]; - char mtu[Property::VALUE_MAX_LENGTH]; - ret = dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns, server, lease, vendorinfo, domains, mtu); - } else { - NS_WARNING("Unable to perform do_dhcp_request: unsupported sdk version!"); - } - return ret; -} diff --git a/dom/network/NetUtils.h b/dom/network/NetUtils.h deleted file mode 100644 index 4af365406..000000000 --- a/dom/network/NetUtils.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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/. */ - -/** - * Abstraction on top of the network support from libnetutils that we - * use to set up network connections. - */ - -#ifndef NetUtils_h -#define NetUtils_h - -#include "arpa/inet.h" - -// Copied from ifc.h -#define RESET_IPV4_ADDRESSES 0x01 -#define RESET_IPV6_ADDRESSES 0x02 -#define RESET_ALL_ADDRESSES (RESET_IPV4_ADDRESSES | RESET_IPV6_ADDRESSES) - -// Implements netutils functions. No need for an abstract class here since we -// only have a one sdk specific method (dhcp_do_request) -class NetUtils -{ -public: - static void* GetSharedLibrary(); - - NetUtils(); - - int32_t do_ifc_enable(const char *ifname); - int32_t do_ifc_disable(const char *ifname); - int32_t do_ifc_configure(const char *ifname, - in_addr_t address, - uint32_t prefixLength, - in_addr_t gateway, - in_addr_t dns1, - in_addr_t dns2); - int32_t do_ifc_reset_connections(const char *ifname, const int32_t resetMask); - int32_t do_ifc_set_default_route(const char *ifname, in_addr_t gateway); - int32_t do_ifc_add_route(const char *ifname, - const char *dst, - uint32_t prefixLength, - const char *gateway); - int32_t do_ifc_remove_route(const char *ifname, - const char *dst, - uint32_t prefixLength, - const char *gateway); - int32_t do_ifc_remove_host_routes(const char *ifname); - int32_t do_ifc_remove_default_route(const char *ifname); - int32_t do_dhcp_stop(const char *ifname); - int32_t do_dhcp_do_request(const char *ifname, - char *ipaddr, - char *gateway, - uint32_t *prefixLength, - char *dns1, - char *dns2, - char *server, - uint32_t *lease, - char* vendorinfo); - - static int32_t SdkVersion(); -}; - -// Defines a function type with the right arguments and return type. -#define DEFINE_DLFUNC(name, ret, args...) typedef ret (*FUNC##name)(args); - -// Set up a dlsymed function ready to use. -#define USE_DLFUNC(name) \ - FUNC##name name = (FUNC##name) dlsym(GetSharedLibrary(), #name); \ - if (!name) { \ - MOZ_CRASH("Symbol not found in shared library : " #name); \ - } - -#endif // NetUtils_h diff --git a/dom/network/NetworkStatsDB.jsm b/dom/network/NetworkStatsDB.jsm deleted file mode 100644 index aa74d40ad..000000000 --- a/dom/network/NetworkStatsDB.jsm +++ /dev/null @@ -1,1285 +0,0 @@ -/* 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"; - -this.EXPORTED_SYMBOLS = ['NetworkStatsDB']; - -const DEBUG = false; -function debug(s) { dump("-*- NetworkStatsDB: " + 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/IndexedDBHelper.jsm"); -Cu.importGlobalProperties(["indexedDB"]); - -XPCOMUtils.defineLazyServiceGetter(this, "appsService", - "@mozilla.org/AppsService;1", - "nsIAppsService"); - -const DB_NAME = "net_stats"; -const DB_VERSION = 9; -const DEPRECATED_STATS_STORE_NAME = - [ - "net_stats_v2", // existed only in DB version 2 - "net_stats", // existed in DB version 1 and 3 to 5 - "net_stats_store", // existed in DB version 6 to 8 - ]; -const STATS_STORE_NAME = "net_stats_store_v3"; // since DB version 9 -const ALARMS_STORE_NAME = "net_alarm"; - -// Constant defining the maximum values allowed per interface. If more, older -// will be erased. -const VALUES_MAX_LENGTH = 6 * 30; - -// Constant defining the rate of the samples. Daily. -const SAMPLE_RATE = 1000 * 60 * 60 * 24; - -this.NetworkStatsDB = function NetworkStatsDB() { - if (DEBUG) { - debug("Constructor"); - } - this.initDBHelper(DB_NAME, DB_VERSION, [STATS_STORE_NAME, ALARMS_STORE_NAME]); -} - -NetworkStatsDB.prototype = { - __proto__: IndexedDBHelper.prototype, - - dbNewTxn: function dbNewTxn(store_name, txn_type, callback, txnCb) { - function successCb(result) { - txnCb(null, result); - } - function errorCb(error) { - txnCb(error, null); - } - return this.newTxn(txn_type, store_name, callback, successCb, errorCb); - }, - - /** - * The onupgradeneeded handler of the IDBOpenDBRequest. - * This function is called in IndexedDBHelper open() method. - * - * @param {IDBTransaction} aTransaction - * {IDBDatabase} aDb - * {64-bit integer} aOldVersion The version number on local storage. - * {64-bit integer} aNewVersion The version number to be upgraded to. - * - * @note Be careful with the database upgrade pattern. - * Because IndexedDB operations are performed asynchronously, we must - * apply a recursive approach instead of an iterative approach while - * upgrading versions. - */ - upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) { - if (DEBUG) { - debug("upgrade schema from: " + aOldVersion + " to " + aNewVersion + " called!"); - } - let db = aDb; - let objectStore; - - // An array of upgrade functions for each version. - let upgradeSteps = [ - function upgrade0to1() { - if (DEBUG) debug("Upgrade 0 to 1: Create object stores and indexes."); - - // Create the initial database schema. - objectStore = db.createObjectStore(DEPRECATED_STATS_STORE_NAME[1], - { keyPath: ["connectionType", "timestamp"] }); - objectStore.createIndex("connectionType", "connectionType", { unique: false }); - objectStore.createIndex("timestamp", "timestamp", { unique: false }); - objectStore.createIndex("rxBytes", "rxBytes", { unique: false }); - objectStore.createIndex("txBytes", "txBytes", { unique: false }); - objectStore.createIndex("rxTotalBytes", "rxTotalBytes", { unique: false }); - objectStore.createIndex("txTotalBytes", "txTotalBytes", { unique: false }); - - upgradeNextVersion(); - }, - - function upgrade1to2() { - if (DEBUG) debug("Upgrade 1 to 2: Do nothing."); - upgradeNextVersion(); - }, - - function upgrade2to3() { - if (DEBUG) debug("Upgrade 2 to 3: Add keyPath appId to object store."); - - // In order to support per-app traffic data storage, the original - // objectStore needs to be replaced by a new objectStore with new - // key path ("appId") and new index ("appId"). - // Also, since now networks are identified by their - // [networkId, networkType] not just by their connectionType, - // to modify the keyPath is mandatory to delete the object store - // and create it again. Old data is going to be deleted because the - // networkId for each sample can not be set. - - // In version 1.2 objectStore name was 'net_stats_v2', to avoid errors when - // upgrading from 1.2 to 1.3 objectStore name should be checked. - let stores = db.objectStoreNames; - let deprecatedName = DEPRECATED_STATS_STORE_NAME[0]; - let storeName = DEPRECATED_STATS_STORE_NAME[1]; - if(stores.contains(deprecatedName)) { - // Delete the obsolete stats store. - db.deleteObjectStore(deprecatedName); - } else { - // Re-create stats object store without copying records. - db.deleteObjectStore(storeName); - } - - objectStore = db.createObjectStore(storeName, { keyPath: ["appId", "network", "timestamp"] }); - objectStore.createIndex("appId", "appId", { unique: false }); - objectStore.createIndex("network", "network", { unique: false }); - objectStore.createIndex("networkType", "networkType", { unique: false }); - objectStore.createIndex("timestamp", "timestamp", { unique: false }); - objectStore.createIndex("rxBytes", "rxBytes", { unique: false }); - objectStore.createIndex("txBytes", "txBytes", { unique: false }); - objectStore.createIndex("rxTotalBytes", "rxTotalBytes", { unique: false }); - objectStore.createIndex("txTotalBytes", "txTotalBytes", { unique: false }); - - upgradeNextVersion(); - }, - - function upgrade3to4() { - if (DEBUG) debug("Upgrade 3 to 4: Delete redundant indexes."); - - // Delete redundant indexes (leave "network" only). - objectStore = aTransaction.objectStore(DEPRECATED_STATS_STORE_NAME[1]); - if (objectStore.indexNames.contains("appId")) { - objectStore.deleteIndex("appId"); - } - if (objectStore.indexNames.contains("networkType")) { - objectStore.deleteIndex("networkType"); - } - if (objectStore.indexNames.contains("timestamp")) { - objectStore.deleteIndex("timestamp"); - } - if (objectStore.indexNames.contains("rxBytes")) { - objectStore.deleteIndex("rxBytes"); - } - if (objectStore.indexNames.contains("txBytes")) { - objectStore.deleteIndex("txBytes"); - } - if (objectStore.indexNames.contains("rxTotalBytes")) { - objectStore.deleteIndex("rxTotalBytes"); - } - if (objectStore.indexNames.contains("txTotalBytes")) { - objectStore.deleteIndex("txTotalBytes"); - } - - upgradeNextVersion(); - }, - - function upgrade4to5() { - if (DEBUG) debug("Upgrade 4 to 5: Create object store for alarms."); - - // In order to manage alarms, it is necessary to use a global counter - // (totalBytes) that will increase regardless of the system reboot. - objectStore = aTransaction.objectStore(DEPRECATED_STATS_STORE_NAME[1]); - - // Now, systemBytes will hold the old totalBytes and totalBytes will - // keep the increasing counter. |counters| will keep the track of - // accumulated values. - let counters = {}; - - objectStore.openCursor().onsuccess = function(event) { - let cursor = event.target.result; - if (!cursor){ - // upgrade4to5 completed now. - upgradeNextVersion(); - return; - } - - cursor.value.rxSystemBytes = cursor.value.rxTotalBytes; - cursor.value.txSystemBytes = cursor.value.txTotalBytes; - - if (cursor.value.appId == 0) { - let netId = cursor.value.network[0] + '' + cursor.value.network[1]; - if (!counters[netId]) { - counters[netId] = { - rxCounter: 0, - txCounter: 0, - lastRx: 0, - lastTx: 0 - }; - } - - let rxDiff = cursor.value.rxSystemBytes - counters[netId].lastRx; - let txDiff = cursor.value.txSystemBytes - counters[netId].lastTx; - if (rxDiff < 0 || txDiff < 0) { - // System reboot between samples, so take the current one. - rxDiff = cursor.value.rxSystemBytes; - txDiff = cursor.value.txSystemBytes; - } - - counters[netId].rxCounter += rxDiff; - counters[netId].txCounter += txDiff; - cursor.value.rxTotalBytes = counters[netId].rxCounter; - cursor.value.txTotalBytes = counters[netId].txCounter; - - counters[netId].lastRx = cursor.value.rxSystemBytes; - counters[netId].lastTx = cursor.value.txSystemBytes; - } else { - cursor.value.rxTotalBytes = cursor.value.rxSystemBytes; - cursor.value.txTotalBytes = cursor.value.txSystemBytes; - } - - cursor.update(cursor.value); - cursor.continue(); - }; - - // Create object store for alarms. - objectStore = db.createObjectStore(ALARMS_STORE_NAME, { keyPath: "id", autoIncrement: true }); - objectStore.createIndex("alarm", ['networkId','threshold'], { unique: false }); - objectStore.createIndex("manifestURL", "manifestURL", { unique: false }); - }, - - function upgrade5to6() { - if (DEBUG) debug("Upgrade 5 to 6: Add keyPath serviceType to object store."); - - // In contrast to "per-app" traffic data, "system-only" traffic data - // refers to data which can not be identified by any applications. - // To further support "system-only" data storage, the data can be - // saved by service type (e.g., Tethering, OTA). Thus it's needed to - // have a new key ("serviceType") for the ojectStore. - let newObjectStore; - let deprecatedName = DEPRECATED_STATS_STORE_NAME[1]; - newObjectStore = db.createObjectStore(DEPRECATED_STATS_STORE_NAME[2], - { keyPath: ["appId", "serviceType", "network", "timestamp"] }); - newObjectStore.createIndex("network", "network", { unique: false }); - - // Copy the data from the original objectStore to the new objectStore. - objectStore = aTransaction.objectStore(deprecatedName); - objectStore.openCursor().onsuccess = function(event) { - let cursor = event.target.result; - if (!cursor) { - db.deleteObjectStore(deprecatedName); - // upgrade5to6 completed now. - upgradeNextVersion(); - return; - } - - let newStats = cursor.value; - newStats.serviceType = ""; - newObjectStore.put(newStats); - cursor.continue(); - }; - }, - - function upgrade6to7() { - if (DEBUG) debug("Upgrade 6 to 7: Replace alarm threshold by relativeThreshold."); - - // Replace threshold attribute of alarm index by relativeThreshold in alarms DB. - // Now alarms are indexed by relativeThreshold, which is the threshold relative - // to current system stats. - let alarmsStore = aTransaction.objectStore(ALARMS_STORE_NAME); - - // Delete "alarm" index. - if (alarmsStore.indexNames.contains("alarm")) { - alarmsStore.deleteIndex("alarm"); - } - - // Create new "alarm" index. - alarmsStore.createIndex("alarm", ['networkId','relativeThreshold'], { unique: false }); - - // Populate new "alarm" index attributes. - alarmsStore.openCursor().onsuccess = function(event) { - let cursor = event.target.result; - if (!cursor) { - upgrade6to7_updateTotalBytes(); - return; - } - - cursor.value.relativeThreshold = cursor.value.threshold; - cursor.value.absoluteThreshold = cursor.value.threshold; - delete cursor.value.threshold; - - cursor.update(cursor.value); - cursor.continue(); - } - - function upgrade6to7_updateTotalBytes() { - if (DEBUG) debug("Upgrade 6 to 7: Update TotalBytes."); - // Previous versions save accumulative totalBytes, increasing although the system - // reboots or resets stats. But is necessary to reset the total counters when reset - // through 'clearInterfaceStats'. - let statsStore = aTransaction.objectStore(DEPRECATED_STATS_STORE_NAME[2]); - let networks = []; - - // Find networks stored in the database. - statsStore.index("network").openKeyCursor(null, "nextunique").onsuccess = function(event) { - let cursor = event.target.result; - - // Store each network into an array. - if (cursor) { - networks.push(cursor.key); - cursor.continue(); - return; - } - - // Start to deal with each network. - let pending = networks.length; - - if (pending === 0) { - // Found no records of network. upgrade6to7 completed now. - upgradeNextVersion(); - return; - } - - networks.forEach(function(network) { - let lowerFilter = [0, "", network, 0]; - let upperFilter = [0, "", network, ""]; - let range = IDBKeyRange.bound(lowerFilter, upperFilter, false, false); - - // Find number of samples for a given network. - statsStore.count(range).onsuccess = function(event) { - let recordCount = event.target.result; - - // If there are more samples than the max allowed, there is no way to know - // when does reset take place. - if (recordCount === 0 || recordCount >= VALUES_MAX_LENGTH) { - pending--; - if (pending === 0) { - upgradeNextVersion(); - } - return; - } - - let last = null; - // Reset detected if the first sample totalCounters are different than bytes - // counters. If so, the total counters should be recalculated. - statsStore.openCursor(range).onsuccess = function(event) { - let cursor = event.target.result; - if (!cursor) { - pending--; - if (pending === 0) { - upgradeNextVersion(); - } - return; - } - if (!last) { - if (cursor.value.rxTotalBytes == cursor.value.rxBytes && - cursor.value.txTotalBytes == cursor.value.txBytes) { - pending--; - if (pending === 0) { - upgradeNextVersion(); - } - return; - } - - cursor.value.rxTotalBytes = cursor.value.rxBytes; - cursor.value.txTotalBytes = cursor.value.txBytes; - cursor.update(cursor.value); - last = cursor.value; - cursor.continue(); - return; - } - - // Recalculate the total counter for last / current sample - cursor.value.rxTotalBytes = last.rxTotalBytes + cursor.value.rxBytes; - cursor.value.txTotalBytes = last.txTotalBytes + cursor.value.txBytes; - cursor.update(cursor.value); - last = cursor.value; - cursor.continue(); - } - } - }, this); // end of networks.forEach() - }; // end of statsStore.index("network").openKeyCursor().onsuccess callback - } // end of function upgrade6to7_updateTotalBytes - }, - - function upgrade7to8() { - if (DEBUG) debug("Upgrade 7 to 8: Create index serviceType."); - - // Create index for 'ServiceType' in order to make it retrievable. - let statsStore = aTransaction.objectStore(DEPRECATED_STATS_STORE_NAME[2]); - statsStore.createIndex("serviceType", "serviceType", { unique: false }); - - upgradeNextVersion(); - }, - - function upgrade8to9() { - if (DEBUG) debug("Upgrade 8 to 9: Add keyPath isInBrowser to " + - "network stats object store"); - - // Since B2G v2.0, there is no stand-alone browser app anymore. - // The browser app is a mozbrowser iframe element owned by system app. - // In order to separate traffic generated from system and browser, we - // have to add a new attribute |isInBrowser| as keyPath. - // Refer to bug 1070944 for more detail. - let newObjectStore; - let deprecatedName = DEPRECATED_STATS_STORE_NAME[2]; - newObjectStore = db.createObjectStore(STATS_STORE_NAME, - { keyPath: ["appId", "isInBrowser", "serviceType", - "network", "timestamp"] }); - newObjectStore.createIndex("network", "network", { unique: false }); - newObjectStore.createIndex("serviceType", "serviceType", { unique: false }); - - // Copy records from the current object store to the new one. - objectStore = aTransaction.objectStore(deprecatedName); - objectStore.openCursor().onsuccess = function (event) { - let cursor = event.target.result; - if (!cursor) { - db.deleteObjectStore(deprecatedName); - // upgrade8to9 completed now. - return; - } - let newStats = cursor.value; - // Augment records by adding the new isInBrowser attribute. - // Notes: - // 1. Key value cannot be boolean type. Use 1/0 instead of true/false. - // 2. Most traffic of system app should come from its browser iframe, - // thus assign isInBrowser as 1 for system app. - let manifestURL = appsService.getManifestURLByLocalId(newStats.appId); - if (manifestURL && manifestURL.search(/app:\/\/system\./) === 0) { - newStats.isInBrowser = 1; - } else { - newStats.isInBrowser = 0; - } - newObjectStore.put(newStats); - cursor.continue(); - }; - } - ]; - - let index = aOldVersion; - let outer = this; - - function upgradeNextVersion() { - if (index == aNewVersion) { - debug("Upgrade finished."); - return; - } - - try { - var i = index++; - if (DEBUG) debug("Upgrade step: " + i + "\n"); - upgradeSteps[i].call(outer); - } catch (ex) { - dump("Caught exception " + ex); - throw ex; - return; - } - } - - if (aNewVersion > upgradeSteps.length) { - debug("No migration steps for the new version!"); - aTransaction.abort(); - return; - } - - upgradeNextVersion(); - }, - - importData: function importData(aStats) { - let stats = { appId: aStats.appId, - isInBrowser: aStats.isInBrowser ? 1 : 0, - serviceType: aStats.serviceType, - network: [aStats.networkId, aStats.networkType], - timestamp: aStats.timestamp, - rxBytes: aStats.rxBytes, - txBytes: aStats.txBytes, - rxSystemBytes: aStats.rxSystemBytes, - txSystemBytes: aStats.txSystemBytes, - rxTotalBytes: aStats.rxTotalBytes, - txTotalBytes: aStats.txTotalBytes }; - - return stats; - }, - - exportData: function exportData(aStats) { - let stats = { appId: aStats.appId, - isInBrowser: aStats.isInBrowser ? true : false, - serviceType: aStats.serviceType, - networkId: aStats.network[0], - networkType: aStats.network[1], - timestamp: aStats.timestamp, - rxBytes: aStats.rxBytes, - txBytes: aStats.txBytes, - rxTotalBytes: aStats.rxTotalBytes, - txTotalBytes: aStats.txTotalBytes }; - - return stats; - }, - - normalizeDate: function normalizeDate(aDate) { - // Convert to UTC according to timezone and - // filter timestamp to get SAMPLE_RATE precission - let timestamp = aDate.getTime() - aDate.getTimezoneOffset() * 60 * 1000; - timestamp = Math.floor(timestamp / SAMPLE_RATE) * SAMPLE_RATE; - return timestamp; - }, - - saveStats: function saveStats(aStats, aResultCb) { - let isAccumulative = aStats.isAccumulative; - let timestamp = this.normalizeDate(aStats.date); - - let stats = { appId: aStats.appId, - isInBrowser: aStats.isInBrowser, - serviceType: aStats.serviceType, - networkId: aStats.networkId, - networkType: aStats.networkType, - timestamp: timestamp, - rxBytes: isAccumulative ? 0 : aStats.rxBytes, - txBytes: isAccumulative ? 0 : aStats.txBytes, - rxSystemBytes: isAccumulative ? aStats.rxBytes : 0, - txSystemBytes: isAccumulative ? aStats.txBytes : 0, - rxTotalBytes: isAccumulative ? aStats.rxBytes : 0, - txTotalBytes: isAccumulative ? aStats.txBytes : 0 }; - - stats = this.importData(stats); - - this.dbNewTxn(STATS_STORE_NAME, "readwrite", function(aTxn, aStore) { - if (DEBUG) { - debug("Filtered time: " + new Date(timestamp)); - debug("New stats: " + JSON.stringify(stats)); - } - - let lowerFilter = [stats.appId, stats.isInBrowser, stats.serviceType, - stats.network, 0]; - let upperFilter = [stats.appId, stats.isInBrowser, stats.serviceType, - stats.network, ""]; - let range = IDBKeyRange.bound(lowerFilter, upperFilter, false, false); - - let request = aStore.openCursor(range, 'prev'); - request.onsuccess = function onsuccess(event) { - let cursor = event.target.result; - if (!cursor) { - // Empty, so save first element. - - if (!isAccumulative) { - this._saveStats(aTxn, aStore, stats); - return; - } - - // There could be a time delay between the point when the network - // interface comes up and the point when the database is initialized. - // In this short interval some traffic data are generated but are not - // registered by the first sample. - stats.rxBytes = stats.rxTotalBytes; - stats.txBytes = stats.txTotalBytes; - - // However, if the interface is not switched on after the database is - // initialized (dual sim use case) stats should be set to 0. - let req = aStore.index("network").openKeyCursor(null, "nextunique"); - req.onsuccess = function onsuccess(event) { - let cursor = event.target.result; - if (cursor) { - if (cursor.key[1] == stats.network[1]) { - stats.rxBytes = 0; - stats.txBytes = 0; - this._saveStats(aTxn, aStore, stats); - return; - } - - cursor.continue(); - return; - } - - this._saveStats(aTxn, aStore, stats); - }.bind(this); - - return; - } - - // There are old samples - if (DEBUG) { - debug("Last value " + JSON.stringify(cursor.value)); - } - - // Remove stats previous to now - VALUE_MAX_LENGTH - this._removeOldStats(aTxn, aStore, stats.appId, stats.isInBrowser, - stats.serviceType, stats.network, stats.timestamp); - - // Process stats before save - this._processSamplesDiff(aTxn, aStore, cursor, stats, isAccumulative); - }.bind(this); - }.bind(this), aResultCb); - }, - - /* - * This function check that stats are saved in the database following the sample rate. - * In this way is easier to find elements when stats are requested. - */ - _processSamplesDiff: function _processSamplesDiff(aTxn, - aStore, - aLastSampleCursor, - aNewSample, - aIsAccumulative) { - let lastSample = aLastSampleCursor.value; - - // Get difference between last and new sample. - let diff = (aNewSample.timestamp - lastSample.timestamp) / SAMPLE_RATE; - if (diff % 1) { - // diff is decimal, so some error happened because samples are stored as a multiple - // of SAMPLE_RATE - aTxn.abort(); - throw new Error("Error processing samples"); - } - - if (DEBUG) { - debug("New: " + aNewSample.timestamp + " - Last: " + - lastSample.timestamp + " - diff: " + diff); - } - - // If the incoming data has a accumulation feature, the new - // |txBytes|/|rxBytes| is assigend by differnces between the new - // |txTotalBytes|/|rxTotalBytes| and the last |txTotalBytes|/|rxTotalBytes|. - // Else, if incoming data is non-accumulative, the |txBytes|/|rxBytes| - // is the new |txBytes|/|rxBytes|. - let rxDiff = 0; - let txDiff = 0; - if (aIsAccumulative) { - rxDiff = aNewSample.rxSystemBytes - lastSample.rxSystemBytes; - txDiff = aNewSample.txSystemBytes - lastSample.txSystemBytes; - if (rxDiff < 0 || txDiff < 0) { - rxDiff = aNewSample.rxSystemBytes; - txDiff = aNewSample.txSystemBytes; - } - aNewSample.rxBytes = rxDiff; - aNewSample.txBytes = txDiff; - - aNewSample.rxTotalBytes = lastSample.rxTotalBytes + rxDiff; - aNewSample.txTotalBytes = lastSample.txTotalBytes + txDiff; - } else { - rxDiff = aNewSample.rxBytes; - txDiff = aNewSample.txBytes; - } - - if (diff == 1) { - // New element. - - // If the incoming data is non-accumulative, the new - // |rxTotalBytes|/|txTotalBytes| needs to be updated by adding new - // |rxBytes|/|txBytes| to the last |rxTotalBytes|/|txTotalBytes|. - if (!aIsAccumulative) { - aNewSample.rxTotalBytes = aNewSample.rxBytes + lastSample.rxTotalBytes; - aNewSample.txTotalBytes = aNewSample.txBytes + lastSample.txTotalBytes; - } - - this._saveStats(aTxn, aStore, aNewSample); - return; - } - if (diff > 1) { - // Some samples lost. Device off during one or more samplerate periods. - // Time or timezone changed - // Add lost samples with 0 bytes and the actual one. - if (diff > VALUES_MAX_LENGTH) { - diff = VALUES_MAX_LENGTH; - } - - let data = []; - for (let i = diff - 2; i >= 0; i--) { - let time = aNewSample.timestamp - SAMPLE_RATE * (i + 1); - let sample = { appId: aNewSample.appId, - isInBrowser: aNewSample.isInBrowser, - serviceType: aNewSample.serviceType, - network: aNewSample.network, - timestamp: time, - rxBytes: 0, - txBytes: 0, - rxSystemBytes: lastSample.rxSystemBytes, - txSystemBytes: lastSample.txSystemBytes, - rxTotalBytes: lastSample.rxTotalBytes, - txTotalBytes: lastSample.txTotalBytes }; - - data.push(sample); - } - - data.push(aNewSample); - this._saveStats(aTxn, aStore, data); - return; - } - if (diff == 0 || diff < 0) { - // New element received before samplerate period. It means that device has - // been restarted (or clock / timezone change). - // Update element. If diff < 0, clock or timezone changed back. Place data - // in the last sample. - - // Old |rxTotalBytes|/|txTotalBytes| needs to get updated by adding the - // last |rxTotalBytes|/|txTotalBytes|. - lastSample.rxBytes += rxDiff; - lastSample.txBytes += txDiff; - lastSample.rxSystemBytes = aNewSample.rxSystemBytes; - lastSample.txSystemBytes = aNewSample.txSystemBytes; - lastSample.rxTotalBytes += rxDiff; - lastSample.txTotalBytes += txDiff; - - if (DEBUG) { - debug("Update: " + JSON.stringify(lastSample)); - } - let req = aLastSampleCursor.update(lastSample); - } - }, - - _saveStats: function _saveStats(aTxn, aStore, aNetworkStats) { - if (DEBUG) { - debug("_saveStats: " + JSON.stringify(aNetworkStats)); - } - - if (Array.isArray(aNetworkStats)) { - let len = aNetworkStats.length - 1; - for (let i = 0; i <= len; i++) { - aStore.put(aNetworkStats[i]); - } - } else { - aStore.put(aNetworkStats); - } - }, - - _removeOldStats: function _removeOldStats(aTxn, aStore, aAppId, aIsInBrowser, - aServiceType, aNetwork, aDate) { - // Callback function to remove old items when new ones are added. - let filterDate = aDate - (SAMPLE_RATE * VALUES_MAX_LENGTH - 1); - let lowerFilter = [aAppId, aIsInBrowser, aServiceType, aNetwork, 0]; - let upperFilter = [aAppId, aIsInBrowser, aServiceType, aNetwork, filterDate]; - let range = IDBKeyRange.bound(lowerFilter, upperFilter, false, false); - let lastSample = null; - let self = this; - - aStore.openCursor(range).onsuccess = function(event) { - var cursor = event.target.result; - if (cursor) { - lastSample = cursor.value; - cursor.delete(); - cursor.continue(); - return; - } - - // If all samples for a network are removed, an empty sample - // has to be saved to keep the totalBytes in order to compute - // future samples because system counters are not set to 0. - // Thus, if there are no samples left, the last sample removed - // will be saved again after setting its bytes to 0. - let request = aStore.index("network").openCursor(aNetwork); - request.onsuccess = function onsuccess(event) { - let cursor = event.target.result; - if (!cursor && lastSample != null) { - let timestamp = new Date(); - timestamp = self.normalizeDate(timestamp); - lastSample.timestamp = timestamp; - lastSample.rxBytes = 0; - lastSample.txBytes = 0; - self._saveStats(aTxn, aStore, lastSample); - } - }; - }; - }, - - clearInterfaceStats: function clearInterfaceStats(aNetwork, aResultCb) { - let network = [aNetwork.network.id, aNetwork.network.type]; - let self = this; - - // Clear and save an empty sample to keep sync with system counters - this.dbNewTxn(STATS_STORE_NAME, "readwrite", function(aTxn, aStore) { - let sample = null; - let request = aStore.index("network").openCursor(network, "prev"); - request.onsuccess = function onsuccess(event) { - let cursor = event.target.result; - if (cursor) { - if (!sample && cursor.value.appId == 0) { - sample = cursor.value; - } - - cursor.delete(); - cursor.continue(); - return; - } - - if (sample) { - let timestamp = new Date(); - timestamp = self.normalizeDate(timestamp); - sample.timestamp = timestamp; - sample.appId = 0; - sample.isInBrowser = 0; - sample.serviceType = ""; - sample.rxBytes = 0; - sample.txBytes = 0; - sample.rxTotalBytes = 0; - sample.txTotalBytes = 0; - - self._saveStats(aTxn, aStore, sample); - } - }; - }, this._resetAlarms.bind(this, aNetwork.networkId, aResultCb)); - }, - - clearStats: function clearStats(aNetworks, aResultCb) { - let index = 0; - let stats = []; - let self = this; - - let callback = function(aError, aResult) { - index++; - - if (!aError && index < aNetworks.length) { - self.clearInterfaceStats(aNetworks[index], callback); - return; - } - - aResultCb(aError, aResult); - }; - - if (!aNetworks[index]) { - aResultCb(null, true); - return; - } - this.clearInterfaceStats(aNetworks[index], callback); - }, - - getCurrentStats: function getCurrentStats(aNetwork, aDate, aResultCb) { - if (DEBUG) { - debug("Get current stats for " + JSON.stringify(aNetwork) + " since " + aDate); - } - - let network = [aNetwork.id, aNetwork.type]; - if (aDate) { - this._getCurrentStatsFromDate(network, aDate, aResultCb); - return; - } - - this._getCurrentStats(network, aResultCb); - }, - - _getCurrentStats: function _getCurrentStats(aNetwork, aResultCb) { - this.dbNewTxn(STATS_STORE_NAME, "readonly", function(txn, store) { - let request = null; - let upperFilter = [0, 1, "", aNetwork, Date.now()]; - let range = IDBKeyRange.upperBound(upperFilter, false); - let result = { rxBytes: 0, txBytes: 0, - rxTotalBytes: 0, txTotalBytes: 0 }; - - request = store.openCursor(range, "prev"); - - request.onsuccess = function onsuccess(event) { - let cursor = event.target.result; - if (cursor) { - result.rxBytes = result.rxTotalBytes = cursor.value.rxTotalBytes; - result.txBytes = result.txTotalBytes = cursor.value.txTotalBytes; - } - - txn.result = result; - }; - }.bind(this), aResultCb); - }, - - _getCurrentStatsFromDate: function _getCurrentStatsFromDate(aNetwork, aDate, aResultCb) { - aDate = new Date(aDate); - this.dbNewTxn(STATS_STORE_NAME, "readonly", function(txn, store) { - let request = null; - let start = this.normalizeDate(aDate); - let upperFilter = [0, 1, "", aNetwork, Date.now()]; - let range = IDBKeyRange.upperBound(upperFilter, false); - let result = { rxBytes: 0, txBytes: 0, - rxTotalBytes: 0, txTotalBytes: 0 }; - - request = store.openCursor(range, "prev"); - - request.onsuccess = function onsuccess(event) { - let cursor = event.target.result; - if (cursor) { - result.rxBytes = result.rxTotalBytes = cursor.value.rxTotalBytes; - result.txBytes = result.txTotalBytes = cursor.value.txTotalBytes; - } - - let timestamp = cursor.value.timestamp; - let range = IDBKeyRange.lowerBound(lowerFilter, false); - request = store.openCursor(range); - - request.onsuccess = function onsuccess(event) { - let cursor = event.target.result; - if (cursor) { - if (cursor.value.timestamp == timestamp) { - // There is one sample only. - result.rxBytes = cursor.value.rxBytes; - result.txBytes = cursor.value.txBytes; - } else { - result.rxBytes -= cursor.value.rxTotalBytes; - result.txBytes -= cursor.value.txTotalBytes; - } - } - - txn.result = result; - }; - }; - }.bind(this), aResultCb); - }, - - find: function find(aResultCb, aAppId, aBrowsingTrafficOnly, aServiceType, - aNetwork, aStart, aEnd, aAppManifestURL) { - let offset = (new Date()).getTimezoneOffset() * 60 * 1000; - let start = this.normalizeDate(aStart); - let end = this.normalizeDate(aEnd); - - if (DEBUG) { - debug("Find samples for appId: " + aAppId + - " browsingTrafficOnly: " + aBrowsingTrafficOnly + - " serviceType: " + aServiceType + - " network: " + JSON.stringify(aNetwork) + " from " + start + - " until " + end); - debug("Start time: " + new Date(start)); - debug("End time: " + new Date(end)); - } - - // Find samples of browsing traffic (isInBrowser = 1) first since they are - // needed no matter browsingTrafficOnly is true or false. - // We have to make two queries to database because we cannot filter correct - // records by a single query that sets ranges for two keys (isInBrowser and - // timestamp). We think it is because the keyPath contains an array - // (network) so such query does not work. - this.dbNewTxn(STATS_STORE_NAME, "readonly", function(aTxn, aStore) { - let network = [aNetwork.id, aNetwork.type]; - let lowerFilter = [aAppId, 1, aServiceType, network, start]; - let upperFilter = [aAppId, 1, aServiceType, network, end]; - let range = IDBKeyRange.bound(lowerFilter, upperFilter, false, false); - - let data = []; - - if (!aTxn.result) { - aTxn.result = {}; - } - aTxn.result.appManifestURL = aAppManifestURL; - aTxn.result.browsingTrafficOnly = aBrowsingTrafficOnly; - aTxn.result.serviceType = aServiceType; - aTxn.result.network = aNetwork; - aTxn.result.start = aStart; - aTxn.result.end = aEnd; - - let request = aStore.openCursor(range).onsuccess = function(event) { - var cursor = event.target.result; - if (cursor){ - // We use rxTotalBytes/txTotalBytes instead of rxBytes/txBytes for - // the first (oldest) sample. The rx/txTotalBytes fields record - // accumulative usage amount, which means even if old samples were - // expired and removed from the Database, we can still obtain the - // correct network usage. - if (data.length == 0) { - data.push({ rxBytes: cursor.value.rxTotalBytes, - txBytes: cursor.value.txTotalBytes, - date: new Date(cursor.value.timestamp + offset) }); - } else { - data.push({ rxBytes: cursor.value.rxBytes, - txBytes: cursor.value.txBytes, - date: new Date(cursor.value.timestamp + offset) }); - } - cursor.continue(); - return; - } - - if (aBrowsingTrafficOnly) { - this.fillResultSamples(start + offset, end + offset, data); - aTxn.result.data = data; - return; - } - - // Find samples of app traffic (isInBrowser = 0) as well if - // browsingTrafficOnly is false. - lowerFilter = [aAppId, 0, aServiceType, network, start]; - upperFilter = [aAppId, 0, aServiceType, network, end]; - range = IDBKeyRange.bound(lowerFilter, upperFilter, false, false); - request = aStore.openCursor(range).onsuccess = function(event) { - cursor = event.target.result; - if (cursor) { - var date = new Date(cursor.value.timestamp + offset); - var foundData = data.find(function (element, index, array) { - if (element.date.getTime() !== date.getTime()) { - return false; - } - return element; - }, date); - - if (foundData) { - foundData.rxBytes += cursor.value.rxBytes; - foundData.txBytes += cursor.value.txBytes; - } else { - // We use rxTotalBytes/txTotalBytes instead of rxBytes/txBytes - // for the first (oldest) sample. The rx/txTotalBytes fields - // record accumulative usage amount, which means even if old - // samples were expired and removed from the Database, we can - // still obtain the correct network usage. - if (data.length == 0) { - data.push({ rxBytes: cursor.value.rxTotalBytes, - txBytes: cursor.value.txTotalBytes, - date: new Date(cursor.value.timestamp + offset) }); - } else { - data.push({ rxBytes: cursor.value.rxBytes, - txBytes: cursor.value.txBytes, - date: new Date(cursor.value.timestamp + offset) }); - } - } - cursor.continue(); - return; - } - this.fillResultSamples(start + offset, end + offset, data); - aTxn.result.data = data; - }.bind(this); // openCursor(range).onsuccess() callback - }.bind(this); // openCursor(range).onsuccess() callback - }.bind(this), aResultCb); - }, - - /* - * Fill data array (samples from database) with empty samples to match - * requested start / end dates. - */ - fillResultSamples: function fillResultSamples(aStart, aEnd, aData) { - if (aData.length == 0) { - aData.push({ rxBytes: undefined, - txBytes: undefined, - date: new Date(aStart) }); - } - - while (aStart < aData[0].date.getTime()) { - aData.unshift({ rxBytes: undefined, - txBytes: undefined, - date: new Date(aData[0].date.getTime() - SAMPLE_RATE) }); - } - - while (aEnd > aData[aData.length - 1].date.getTime()) { - aData.push({ rxBytes: undefined, - txBytes: undefined, - date: new Date(aData[aData.length - 1].date.getTime() + SAMPLE_RATE) }); - } - }, - - getAvailableNetworks: function getAvailableNetworks(aResultCb) { - this.dbNewTxn(STATS_STORE_NAME, "readonly", function(aTxn, aStore) { - if (!aTxn.result) { - aTxn.result = []; - } - - let request = aStore.index("network").openKeyCursor(null, "nextunique"); - request.onsuccess = function onsuccess(event) { - let cursor = event.target.result; - if (cursor) { - aTxn.result.push({ id: cursor.key[0], - type: cursor.key[1] }); - cursor.continue(); - return; - } - }; - }, aResultCb); - }, - - isNetworkAvailable: function isNetworkAvailable(aNetwork, aResultCb) { - this.dbNewTxn(STATS_STORE_NAME, "readonly", function(aTxn, aStore) { - if (!aTxn.result) { - aTxn.result = false; - } - - let network = [aNetwork.id, aNetwork.type]; - let request = aStore.index("network").openKeyCursor(IDBKeyRange.only(network)); - request.onsuccess = function onsuccess(event) { - if (event.target.result) { - aTxn.result = true; - } - }; - }, aResultCb); - }, - - getAvailableServiceTypes: function getAvailableServiceTypes(aResultCb) { - this.dbNewTxn(STATS_STORE_NAME, "readonly", function(aTxn, aStore) { - if (!aTxn.result) { - aTxn.result = []; - } - - let request = aStore.index("serviceType").openKeyCursor(null, "nextunique"); - request.onsuccess = function onsuccess(event) { - let cursor = event.target.result; - if (cursor && cursor.key != "") { - aTxn.result.push({ serviceType: cursor.key }); - cursor.continue(); - return; - } - }; - }, aResultCb); - }, - - get sampleRate () { - return SAMPLE_RATE; - }, - - get maxStorageSamples () { - return VALUES_MAX_LENGTH; - }, - - logAllRecords: function logAllRecords(aResultCb) { - this.dbNewTxn(STATS_STORE_NAME, "readonly", function(aTxn, aStore) { - aStore.mozGetAll().onsuccess = function onsuccess(event) { - aTxn.result = event.target.result; - }; - }, aResultCb); - }, - - alarmToRecord: function alarmToRecord(aAlarm) { - let record = { networkId: aAlarm.networkId, - absoluteThreshold: aAlarm.absoluteThreshold, - relativeThreshold: aAlarm.relativeThreshold, - startTime: aAlarm.startTime, - data: aAlarm.data, - manifestURL: aAlarm.manifestURL, - pageURL: aAlarm.pageURL }; - - if (aAlarm.id) { - record.id = aAlarm.id; - } - - return record; - }, - - recordToAlarm: function recordToalarm(aRecord) { - let alarm = { networkId: aRecord.networkId, - absoluteThreshold: aRecord.absoluteThreshold, - relativeThreshold: aRecord.relativeThreshold, - startTime: aRecord.startTime, - data: aRecord.data, - manifestURL: aRecord.manifestURL, - pageURL: aRecord.pageURL }; - - if (aRecord.id) { - alarm.id = aRecord.id; - } - - return alarm; - }, - - addAlarm: function addAlarm(aAlarm, aResultCb) { - this.dbNewTxn(ALARMS_STORE_NAME, "readwrite", function(txn, store) { - if (DEBUG) { - debug("Going to add " + JSON.stringify(aAlarm)); - } - - let record = this.alarmToRecord(aAlarm); - store.put(record).onsuccess = function setResult(aEvent) { - txn.result = aEvent.target.result; - if (DEBUG) { - debug("Request successful. New record ID: " + txn.result); - } - }; - }.bind(this), aResultCb); - }, - - getFirstAlarm: function getFirstAlarm(aNetworkId, aResultCb) { - let self = this; - - this.dbNewTxn(ALARMS_STORE_NAME, "readonly", function(txn, store) { - if (DEBUG) { - debug("Get first alarm for network " + aNetworkId); - } - - let lowerFilter = [aNetworkId, 0]; - let upperFilter = [aNetworkId, ""]; - let range = IDBKeyRange.bound(lowerFilter, upperFilter); - - store.index("alarm").openCursor(range).onsuccess = function onsuccess(event) { - let cursor = event.target.result; - txn.result = null; - if (cursor) { - txn.result = self.recordToAlarm(cursor.value); - } - }; - }, aResultCb); - }, - - removeAlarm: function removeAlarm(aAlarmId, aManifestURL, aResultCb) { - this.dbNewTxn(ALARMS_STORE_NAME, "readwrite", function(txn, store) { - if (DEBUG) { - debug("Remove alarm " + aAlarmId); - } - - store.get(aAlarmId).onsuccess = function onsuccess(event) { - let record = event.target.result; - txn.result = false; - if (!record || (aManifestURL && record.manifestURL != aManifestURL)) { - return; - } - - store.delete(aAlarmId); - txn.result = true; - } - }, aResultCb); - }, - - removeAlarms: function removeAlarms(aManifestURL, aResultCb) { - this.dbNewTxn(ALARMS_STORE_NAME, "readwrite", function(txn, store) { - if (DEBUG) { - debug("Remove alarms of " + aManifestURL); - } - - store.index("manifestURL").openCursor(aManifestURL) - .onsuccess = function onsuccess(event) { - let cursor = event.target.result; - if (cursor) { - cursor.delete(); - cursor.continue(); - } - } - }, aResultCb); - }, - - updateAlarm: function updateAlarm(aAlarm, aResultCb) { - let self = this; - this.dbNewTxn(ALARMS_STORE_NAME, "readwrite", function(txn, store) { - if (DEBUG) { - debug("Update alarm " + aAlarm.id); - } - - let record = self.alarmToRecord(aAlarm); - store.openCursor(record.id).onsuccess = function onsuccess(event) { - let cursor = event.target.result; - txn.result = false; - if (cursor) { - cursor.update(record); - txn.result = true; - } - } - }, aResultCb); - }, - - getAlarms: function getAlarms(aNetworkId, aManifestURL, aResultCb) { - let self = this; - this.dbNewTxn(ALARMS_STORE_NAME, "readonly", function(txn, store) { - if (DEBUG) { - debug("Get alarms for " + aManifestURL); - } - - txn.result = []; - store.index("manifestURL").openCursor(aManifestURL) - .onsuccess = function onsuccess(event) { - let cursor = event.target.result; - if (!cursor) { - return; - } - - if (!aNetworkId || cursor.value.networkId == aNetworkId) { - txn.result.push(self.recordToAlarm(cursor.value)); - } - - cursor.continue(); - } - }, aResultCb); - }, - - _resetAlarms: function _resetAlarms(aNetworkId, aResultCb) { - this.dbNewTxn(ALARMS_STORE_NAME, "readwrite", function(txn, store) { - if (DEBUG) { - debug("Reset alarms for network " + aNetworkId); - } - - let lowerFilter = [aNetworkId, 0]; - let upperFilter = [aNetworkId, ""]; - let range = IDBKeyRange.bound(lowerFilter, upperFilter); - - store.index("alarm").openCursor(range).onsuccess = function onsuccess(event) { - let cursor = event.target.result; - if (cursor) { - if (cursor.value.startTime) { - cursor.value.relativeThreshold = cursor.value.threshold; - cursor.update(cursor.value); - } - cursor.continue(); - return; - } - }; - }, aResultCb); - } -}; diff --git a/dom/network/NetworkStatsManager.js b/dom/network/NetworkStatsManager.js deleted file mode 100644 index b963aba2b..000000000 --- a/dom/network/NetworkStatsManager.js +++ /dev/null @@ -1,388 +0,0 @@ -/* 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. -var appInfo = Cc["@mozilla.org/xre/app-info;1"]; -var 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}"); - -function NetworkStatsManager() { - if (DEBUG) { - debug("Constructor"); - } -} - -NetworkStatsManager.prototype = { - __proto__: DOMRequestIpcHelper.prototype, - - getSamples: function getSamples(aNetwork, aStart, aEnd, aOptions) { - if (aStart > aEnd) { - throw Components.results.NS_ERROR_INVALID_ARG; - } - - // 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; - } - - let appManifestURL = aOptions.appManifestURL; - let serviceType = aOptions.serviceType; - let browsingTrafficOnly = aOptions.browsingTrafficOnly; - - // 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) { - let request = this.createRequest(); - cpmm.sendAsyncMessage("NetworkStats:Clear", - { network: aNetwork.toJSON(), - id: this.getRequestId(request) }); - return request; - }, - - clearAllStats: function clearAllStats() { - let request = this.createRequest(); - cpmm.sendAsyncMessage("NetworkStats:ClearAll", - {id: this.getRequestId(request)}); - return request; - }, - - addAlarm: function addAlarm(aNetwork, aThreshold, aOptions) { - 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) { - let network = null; - if (aNetwork) { - 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) { - 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() { - let request = this.createRequest(); - cpmm.sendAsyncMessage("NetworkStats:GetAvailableNetworks", - { id: this.getRequestId(request) }); - return request; - }, - - getAvailableServiceTypes: function getAvailableServiceTypes() { - let request = this.createRequest(); - cpmm.sendAsyncMessage("NetworkStats:GetAvailableServiceTypes", - { id: this.getRequestId(request) }); - return request; - }, - - get sampleRate() { - return cpmm.sendSyncMessage("NetworkStats:SampleRate")[0]; - }, - - get maxStorageAge() { - 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) { - let principal = aWindow.document.nodePrincipal; - - 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, - contractID : NETWORKSTATSMANAGER_CONTRACTID, - QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer, - Ci.nsISupportsWeakReference, - Ci.nsIObserver]), -} - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkStatsAlarm, - NetworkStatsData, - NetworkStatsInterface, - NetworkStats, - NetworkStatsManager]); diff --git a/dom/network/NetworkStatsManager.manifest b/dom/network/NetworkStatsManager.manifest deleted file mode 100644 index 8e8700910..000000000 --- a/dom/network/NetworkStatsManager.manifest +++ /dev/null @@ -1,14 +0,0 @@ -component {3b16fe17-5583-483a-b486-b64a3243221c} NetworkStatsManager.js -contract @mozilla.org/networkStatsdata;1 {3b16fe17-5583-483a-b486-b64a3243221c} - -component {28904f59-8497-4ac0-904f-2af14b7fd3de} NetworkStatsManager.js -contract @mozilla.org/networkStats;1 {28904f59-8497-4ac0-904f-2af14b7fd3de} - -component {f540615b-d803-43ff-8200-2a9d145a5645} NetworkStatsManager.js -contract @mozilla.org/networkstatsinterface;1 {f540615b-d803-43ff-8200-2a9d145a5645} - -component {a93ea13e-409c-4189-9b1e-95fff220be55} NetworkStatsManager.js -contract @mozilla.org/networkstatsalarm;1 {a93ea13e-409c-4189-9b1e-95fff220be55} - -component {ceb874cd-cc1a-4e65-b404-cc2d3e42425f} NetworkStatsManager.js -contract @mozilla.org/networkStatsManager;1 {ceb874cd-cc1a-4e65-b404-cc2d3e42425f} diff --git a/dom/network/NetworkStatsService.jsm b/dom/network/NetworkStatsService.jsm deleted file mode 100644 index 4b6d69498..000000000 --- a/dom/network/NetworkStatsService.jsm +++ /dev/null @@ -1,1171 +0,0 @@ -/* 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) { - if (DEBUG) { - dump("-*- NetworkStatsService: " + s + "\n"); - } -} - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -this.EXPORTED_SYMBOLS = ["NetworkStatsService"]; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/NetworkStatsDB.jsm"); -Cu.import("resource://gre/modules/Timer.jsm"); - -const NET_NETWORKSTATSSERVICE_CONTRACTID = "@mozilla.org/network/netstatsservice;1"; -const NET_NETWORKSTATSSERVICE_CID = Components.ID("{18725604-e9ac-488a-8aa0-2471e7f6c0a4}"); - -const TOPIC_BANDWIDTH_CONTROL = "netd-bandwidth-control" - -const TOPIC_CONNECTION_STATE_CHANGED = "network-connection-state-changed"; -const NET_TYPE_WIFI = Ci.nsINetworkInfo.NETWORK_TYPE_WIFI; -const NET_TYPE_MOBILE = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE; - -// Networks have different status that NetworkStats API needs to be aware of. -// Network is present and ready, so NetworkManager provides the whole info. -const NETWORK_STATUS_READY = 0; -// Network is present but hasn't established a connection yet (e.g. SIM that has not -// enabled 3G since boot). -const NETWORK_STATUS_STANDBY = 1; -// Network is not present, but stored in database by the previous connections. -const NETWORK_STATUS_AWAY = 2; - -// The maximum traffic amount can be saved in the |cachedStats|. -const MAX_CACHED_TRAFFIC = 500 * 1000 * 1000; // 500 MB - -const QUEUE_TYPE_UPDATE_STATS = 0; -const QUEUE_TYPE_UPDATE_CACHE = 1; -const QUEUE_TYPE_WRITE_CACHE = 2; - -XPCOMUtils.defineLazyServiceGetter(this, "ppmm", - "@mozilla.org/parentprocessmessagemanager;1", - "nsIMessageListenerManager"); - -XPCOMUtils.defineLazyServiceGetter(this, "gRil", - "@mozilla.org/ril;1", - "nsIRadioInterfaceLayer"); - -XPCOMUtils.defineLazyServiceGetter(this, "networkService", - "@mozilla.org/network/service;1", - "nsINetworkService"); - -XPCOMUtils.defineLazyServiceGetter(this, "appsService", - "@mozilla.org/AppsService;1", - "nsIAppsService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService", - "@mozilla.org/settingsService;1", - "nsISettingsService"); - -XPCOMUtils.defineLazyServiceGetter(this, "messenger", - "@mozilla.org/system-message-internal;1", - "nsISystemMessagesInternal"); - -XPCOMUtils.defineLazyServiceGetter(this, "gIccService", - "@mozilla.org/icc/iccservice;1", - "nsIIccService"); - -this.NetworkStatsService = { - init: function() { - debug("Service started"); - - Services.obs.addObserver(this, "xpcom-shutdown", false); - Services.obs.addObserver(this, TOPIC_CONNECTION_STATE_CHANGED, false); - Services.obs.addObserver(this, TOPIC_BANDWIDTH_CONTROL, false); - Services.obs.addObserver(this, "profile-after-change", false); - - this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - - // Object to store network interfaces, each network interface is composed - // by a network object (network type and network Id) and a interfaceName - // that contains the name of the physical interface (wlan0, rmnet0, etc.). - // The network type can be 0 for wifi or 1 for mobile. On the other hand, - // the network id is '0' for wifi or the iccid for mobile (SIM). - // Each networkInterface is placed in the _networks object by the index of - // 'networkId + networkType'. - // - // _networks object allows to map available network interfaces at low level - // (wlan0, rmnet0, etc.) to a network. It's not mandatory to have a - // networkInterface per network but can't exist a networkInterface not - // being mapped to a network. - - this._networks = Object.create(null); - - // There is no way to know a priori if wifi connection is available, - // just when the wifi driver is loaded, but it is unloaded when - // wifi is switched off. So wifi connection is hardcoded - let netId = this.getNetworkId('0', NET_TYPE_WIFI); - this._networks[netId] = { network: { id: '0', - type: NET_TYPE_WIFI }, - interfaceName: null, - status: NETWORK_STATUS_STANDBY }; - - this.messages = ["NetworkStats:Get", - "NetworkStats:Clear", - "NetworkStats:ClearAll", - "NetworkStats:SetAlarm", - "NetworkStats:GetAlarms", - "NetworkStats:RemoveAlarms", - "NetworkStats:GetAvailableNetworks", - "NetworkStats:GetAvailableServiceTypes", - "NetworkStats:SampleRate", - "NetworkStats:MaxStorageAge"]; - - this.messages.forEach(function(aMsgName) { - ppmm.addMessageListener(aMsgName, this); - }, this); - - this._db = new NetworkStatsDB(); - - // Stats for all interfaces are updated periodically - this.timer.initWithCallback(this, this._db.sampleRate, - Ci.nsITimer.TYPE_REPEATING_PRECISE_CAN_SKIP); - - // Stats not from netd are firstly stored in the cached. - this.cachedStats = Object.create(null); - this.cachedStatsDate = new Date(); - - this.updateQueue = []; - this.isQueueRunning = false; - - this._currentAlarms = {}; - this.initAlarms(); - }, - - receiveMessage: function(aMessage) { - if (!aMessage.target.assertPermission("networkstats-manage")) { - return; - } - - debug("receiveMessage " + aMessage.name); - - let mm = aMessage.target; - let msg = aMessage.json; - - switch (aMessage.name) { - case "NetworkStats:Get": - this.getSamples(mm, msg); - break; - case "NetworkStats:Clear": - this.clearInterfaceStats(mm, msg); - break; - case "NetworkStats:ClearAll": - this.clearDB(mm, msg); - break; - case "NetworkStats:SetAlarm": - this.setAlarm(mm, msg); - break; - case "NetworkStats:GetAlarms": - this.getAlarms(mm, msg); - break; - case "NetworkStats:RemoveAlarms": - this.removeAlarms(mm, msg); - break; - case "NetworkStats:GetAvailableNetworks": - this.getAvailableNetworks(mm, msg); - break; - case "NetworkStats:GetAvailableServiceTypes": - this.getAvailableServiceTypes(mm, msg); - break; - case "NetworkStats:SampleRate": - // This message is sync. - return this._db.sampleRate; - case "NetworkStats:MaxStorageAge": - // This message is sync. - return this._db.maxStorageSamples * this._db.sampleRate; - } - }, - - observe: function observe(aSubject, aTopic, aData) { - switch (aTopic) { - case TOPIC_CONNECTION_STATE_CHANGED: - - // If new interface is registered (notified from NetworkService), - // the stats are updated for the new interface without waiting to - // complete the updating period. - - let networkInfo = aSubject.QueryInterface(Ci.nsINetworkInfo); - debug("Network " + networkInfo.name + " of type " + networkInfo.type + " status change"); - - let netId = this.convertNetworkInfo(networkInfo); - if (!netId) { - break; - } - - this._updateCurrentAlarm(netId); - - debug("NetId: " + netId); - this.updateStats(netId); - break; - - case TOPIC_BANDWIDTH_CONTROL: - debug("Bandwidth message from netd: " + JSON.stringify(aData)); - - let interfaceName = aData.substring(aData.lastIndexOf(" ") + 1); - for (let networkId in this._networks) { - if (interfaceName == this._networks[networkId].interfaceName) { - let currentAlarm = this._currentAlarms[networkId]; - if (Object.getOwnPropertyNames(currentAlarm).length !== 0) { - this._fireAlarm(currentAlarm.alarm); - } - break; - } - } - break; - - case "xpcom-shutdown": - debug("Service shutdown"); - - this.messages.forEach(function(aMsgName) { - ppmm.removeMessageListener(aMsgName, this); - }, this); - - Services.obs.removeObserver(this, "xpcom-shutdown"); - Services.obs.removeObserver(this, "profile-after-change"); - Services.obs.removeObserver(this, TOPIC_CONNECTION_STATE_CHANGED); - Services.obs.removeObserver(this, TOPIC_BANDWIDTH_CONTROL); - - this.timer.cancel(); - this.timer = null; - - // Update stats before shutdown - this.updateAllStats(); - break; - } - }, - - /* - * nsITimerCallback - * Timer triggers the update of all stats - */ - notify: function(aTimer) { - this.updateAllStats(); - }, - - /* - * nsINetworkStatsService - */ - getRilNetworks: function() { - let networks = {}; - let numRadioInterfaces = gRil.numRadioInterfaces; - for (let i = 0; i < numRadioInterfaces; i++) { - let icc = gIccService.getIccByServiceId(i); - let radioInterface = gRil.getRadioInterface(i); - if (icc && icc.iccInfo) { - let netId = this.getNetworkId(icc.iccInfo.iccid, - NET_TYPE_MOBILE); - networks[netId] = { id : icc.iccInfo.iccid, - type: NET_TYPE_MOBILE }; - } - } - return networks; - }, - - convertNetworkInfo: function(aNetworkInfo) { - if (aNetworkInfo.type != NET_TYPE_MOBILE && - aNetworkInfo.type != NET_TYPE_WIFI) { - return null; - } - - let id = '0'; - if (aNetworkInfo.type == NET_TYPE_MOBILE) { - if (!(aNetworkInfo instanceof Ci.nsIRilNetworkInfo)) { - debug("Error! Mobile network should be an nsIRilNetworkInfo!"); - return null; - } - - let rilNetwork = aNetworkInfo.QueryInterface(Ci.nsIRilNetworkInfo); - id = rilNetwork.iccId; - } - - let netId = this.getNetworkId(id, aNetworkInfo.type); - - if (!this._networks[netId]) { - this._networks[netId] = Object.create(null); - this._networks[netId].network = { id: id, - type: aNetworkInfo.type }; - } - - this._networks[netId].status = NETWORK_STATUS_READY; - this._networks[netId].interfaceName = aNetworkInfo.name; - return netId; - }, - - getNetworkId: function getNetworkId(aIccId, aNetworkType) { - return aIccId + '' + aNetworkType; - }, - - /* Function to ensure that one network is valid. The network is valid if its status is - * NETWORK_STATUS_READY, NETWORK_STATUS_STANDBY or NETWORK_STATUS_AWAY. - * - * The result is |netId| or null in case of a non-valid network - * aCallback is signatured as |function(netId)|. - */ - validateNetwork: function validateNetwork(aNetwork, aCallback) { - let netId = this.getNetworkId(aNetwork.id, aNetwork.type); - - if (this._networks[netId]) { - aCallback(netId); - return; - } - - // Check if network is valid (RIL entry) but has not established a connection yet. - // If so add to networks list with empty interfaceName. - let rilNetworks = this.getRilNetworks(); - if (rilNetworks[netId]) { - this._networks[netId] = Object.create(null); - this._networks[netId].network = rilNetworks[netId]; - this._networks[netId].status = NETWORK_STATUS_STANDBY; - this._currentAlarms[netId] = Object.create(null); - aCallback(netId); - return; - } - - // Check if network is available in the DB. - this._db.isNetworkAvailable(aNetwork, function(aError, aResult) { - if (aResult) { - this._networks[netId] = Object.create(null); - this._networks[netId].network = aNetwork; - this._networks[netId].status = NETWORK_STATUS_AWAY; - this._currentAlarms[netId] = Object.create(null); - aCallback(netId); - return; - } - - aCallback(null); - }.bind(this)); - }, - - getAvailableNetworks: function getAvailableNetworks(mm, msg) { - let self = this; - let rilNetworks = this.getRilNetworks(); - this._db.getAvailableNetworks(function onGetNetworks(aError, aResult) { - - // Also return the networks that are valid but have not - // established connections yet. - for (let netId in rilNetworks) { - let found = false; - for (let i = 0; i < aResult.length; i++) { - if (netId == self.getNetworkId(aResult[i].id, aResult[i].type)) { - found = true; - break; - } - } - if (!found) { - aResult.push(rilNetworks[netId]); - } - } - - mm.sendAsyncMessage("NetworkStats:GetAvailableNetworks:Return", - { id: msg.id, error: aError, result: aResult }); - }); - }, - - getAvailableServiceTypes: function getAvailableServiceTypes(mm, msg) { - this._db.getAvailableServiceTypes(function onGetServiceTypes(aError, aResult) { - mm.sendAsyncMessage("NetworkStats:GetAvailableServiceTypes:Return", - { id: msg.id, error: aError, result: aResult }); - }); - }, - - initAlarms: function initAlarms() { - debug("Init usage alarms"); - let self = this; - - for (let netId in this._networks) { - this._currentAlarms[netId] = Object.create(null); - - this._db.getFirstAlarm(netId, function getResult(error, result) { - if (!error && result) { - self._setAlarm(result, function onSet(error, success) { - if (error == "InvalidStateError") { - self._fireAlarm(result); - } - }); - } - }); - } - }, - - /* - * Function called from manager to get stats from database. - * In order to return updated stats, first is performed a call to - * updateAllStats function, which will get last stats from netd - * and update the database. - * Then, depending on the request (stats per appId or total stats) - * it retrieve them from database and return to the manager. - */ - getSamples: function getSamples(mm, msg) { - let network = msg.network; - let netId = this.getNetworkId(network.id, network.type); - - let appId = 0; - let appManifestURL = msg.appManifestURL; - if (appManifestURL) { - appId = appsService.getAppLocalIdByManifestURL(appManifestURL); - - if (!appId) { - mm.sendAsyncMessage("NetworkStats:Get:Return", - { id: msg.id, - error: "Invalid appManifestURL", result: null }); - return; - } - } - - let browsingTrafficOnly = msg.browsingTrafficOnly || false; - let serviceType = msg.serviceType || ""; - - let start = new Date(msg.start); - let end = new Date(msg.end); - - let callback = (function (aError, aResult) { - this._db.find(function onStatsFound(aError, aResult) { - mm.sendAsyncMessage("NetworkStats:Get:Return", - { id: msg.id, error: aError, result: aResult }); - }, appId, browsingTrafficOnly, serviceType, network, start, end, appManifestURL); - }).bind(this); - - this.validateNetwork(network, function onValidateNetwork(aNetId) { - if (!aNetId) { - mm.sendAsyncMessage("NetworkStats:Get:Return", - { id: msg.id, error: "Invalid connectionType", result: null }); - return; - } - - // If network is currently active we need to update the cached stats first before - // retrieving stats from the DB. - if (this._networks[aNetId].status == NETWORK_STATUS_READY) { - debug("getstats for network " + network.id + " of type " + network.type); - debug("appId: " + appId + " from appManifestURL: " + appManifestURL); - debug("browsingTrafficOnly: " + browsingTrafficOnly); - debug("serviceType: " + serviceType); - - if (appId || serviceType) { - this.updateCachedStats(callback); - return; - } - - this.updateStats(aNetId, function onStatsUpdated(aResult, aMessage) { - this.updateCachedStats(callback); - }.bind(this)); - return; - } - - // Network not active, so no need to update - this._db.find(function onStatsFound(aError, aResult) { - mm.sendAsyncMessage("NetworkStats:Get:Return", - { id: msg.id, error: aError, result: aResult }); - }, appId, browsingTrafficOnly, serviceType, network, start, end, appManifestURL); - }.bind(this)); - }, - - clearInterfaceStats: function clearInterfaceStats(mm, msg) { - let self = this; - let network = msg.network; - - debug("clear stats for network " + network.id + " of type " + network.type); - - this.validateNetwork(network, function onValidateNetwork(aNetId) { - if (!aNetId) { - mm.sendAsyncMessage("NetworkStats:Clear:Return", - { id: msg.id, error: "Invalid connectionType", result: null }); - return; - } - - network = {network: network, networkId: aNetId}; - self.updateStats(aNetId, function onUpdate(aResult, aMessage) { - if (!aResult) { - mm.sendAsyncMessage("NetworkStats:Clear:Return", - { id: msg.id, error: aMessage, result: null }); - return; - } - - self._db.clearInterfaceStats(network, function onDBCleared(aError, aResult) { - self._updateCurrentAlarm(aNetId); - mm.sendAsyncMessage("NetworkStats:Clear:Return", - { id: msg.id, error: aError, result: aResult }); - }); - }); - }); - }, - - clearDB: function clearDB(mm, msg) { - let self = this; - this._db.getAvailableNetworks(function onGetNetworks(aError, aResult) { - if (aError) { - mm.sendAsyncMessage("NetworkStats:ClearAll:Return", - { id: msg.id, error: aError, result: aResult }); - return; - } - - let networks = aResult; - networks.forEach(function(network, index) { - networks[index] = {network: network, networkId: self.getNetworkId(network.id, network.type)}; - }, self); - - self.updateAllStats(function onUpdate(aResult, aMessage){ - if (!aResult) { - mm.sendAsyncMessage("NetworkStats:ClearAll:Return", - { id: msg.id, error: aMessage, result: null }); - return; - } - - self._db.clearStats(networks, function onDBCleared(aError, aResult) { - networks.forEach(function(network, index) { - self._updateCurrentAlarm(network.networkId); - }, self); - mm.sendAsyncMessage("NetworkStats:ClearAll:Return", - { id: msg.id, error: aError, result: aResult }); - }); - }); - }); - }, - - updateAllStats: function updateAllStats(aCallback) { - let elements = []; - let lastElement = null; - let callback = (function (success, message) { - this.updateCachedStats(aCallback); - }).bind(this); - - // For each connectionType create an object containning the type - // and the 'queueIndex', the 'queueIndex' is an integer representing - // the index of a connection type in the global queue array. So, if - // the connection type is already in the queue it is not appended again, - // else it is pushed in 'elements' array, which later will be pushed to - // the queue array. - for (let netId in this._networks) { - if (this._networks[netId].status != NETWORK_STATUS_READY) { - continue; - } - - lastElement = { netId: netId, - queueIndex: this.updateQueueIndex(netId) }; - - if (lastElement.queueIndex == -1) { - elements.push({ netId: lastElement.netId, - callbacks: [], - queueType: QUEUE_TYPE_UPDATE_STATS }); - } - } - - if (!lastElement) { - // No elements need to be updated, probably because status is different than - // NETWORK_STATUS_READY. - if (aCallback) { - aCallback(true, "OK"); - } - return; - } - - if (elements.length > 0) { - // If length of elements is greater than 0, callback is set to - // the last element. - elements[elements.length - 1].callbacks.push(callback); - this.updateQueue = this.updateQueue.concat(elements); - } else { - // Else, it means that all connection types are already in the queue to - // be updated, so callback for this request is added to - // the element in the main queue with the index of the last 'lastElement'. - // But before is checked that element is still in the queue because it can - // be processed while generating 'elements' array. - let element = this.updateQueue[lastElement.queueIndex]; - if (aCallback && - (!element || element.netId != lastElement.netId)) { - aCallback(); - return; - } - - this.updateQueue[lastElement.queueIndex].callbacks.push(callback); - } - - // Call the function that process the elements of the queue. - this.processQueue(); - - if (DEBUG) { - this.logAllRecords(); - } - }, - - updateStats: function updateStats(aNetId, aCallback) { - // Check if the connection is in the main queue, push a new element - // if it is not being processed or add a callback if it is. - let index = this.updateQueueIndex(aNetId); - if (index == -1) { - this.updateQueue.push({ netId: aNetId, - callbacks: [aCallback], - queueType: QUEUE_TYPE_UPDATE_STATS }); - } else { - this.updateQueue[index].callbacks.push(aCallback); - return; - } - - // Call the function that process the elements of the queue. - this.processQueue(); - }, - - /* - * Find if a connection is in the main queue array and return its - * index, if it is not in the array return -1. - */ - updateQueueIndex: function updateQueueIndex(aNetId) { - return this.updateQueue.map(function(e) { return e.netId; }).indexOf(aNetId); - }, - - /* - * Function responsible of process all requests in the queue. - */ - processQueue: function processQueue(aResult, aMessage) { - // If aResult is not undefined, the caller of the function is the result - // of processing an element, so remove that element and call the callbacks - // it has. - let self = this; - - if (aResult != undefined) { - let item = this.updateQueue.shift(); - for (let callback of item.callbacks) { - if (callback) { - callback(aResult, aMessage); - } - } - } else { - // The caller is a function that has pushed new elements to the queue, - // if isQueueRunning is false it means there is no processing currently - // being done, so start. - if (this.isQueueRunning) { - return; - } else { - this.isQueueRunning = true; - } - } - - // Check length to determine if queue is empty and stop processing. - if (this.updateQueue.length < 1) { - this.isQueueRunning = false; - return; - } - - // Process the next item as soon as possible. - setTimeout(function () { - self.run(self.updateQueue[0]); - }, 0); - }, - - run: function run(item) { - switch (item.queueType) { - case QUEUE_TYPE_UPDATE_STATS: - this.update(item.netId, this.processQueue.bind(this)); - break; - case QUEUE_TYPE_UPDATE_CACHE: - this.updateCache(this.processQueue.bind(this)); - break; - case QUEUE_TYPE_WRITE_CACHE: - this.writeCache(item.stats, this.processQueue.bind(this)); - break; - } - }, - - update: function update(aNetId, aCallback) { - // Check if connection type is valid. - if (!this._networks[aNetId]) { - if (aCallback) { - aCallback(false, "Invalid network " + aNetId); - } - return; - } - - let interfaceName = this._networks[aNetId].interfaceName; - debug("Update stats for " + interfaceName); - - // Request stats to NetworkService, which will get stats from netd, passing - // 'networkStatsAvailable' as a callback. - if (interfaceName) { - networkService.getNetworkInterfaceStats(interfaceName, - this.networkStatsAvailable.bind(this, aCallback, aNetId)); - return; - } - - if (aCallback) { - aCallback(true, "ok"); - } - }, - - /* - * Callback of request stats. Store stats in database. - */ - networkStatsAvailable: function networkStatsAvailable(aCallback, aNetId, - aResult, aRxBytes, - aTxBytes, aTimestamp) { - if (!aResult) { - if (aCallback) { - aCallback(false, "Netd IPC error"); - } - return; - } - - let stats = { appId: 0, - isInBrowser: false, - serviceType: "", - networkId: this._networks[aNetId].network.id, - networkType: this._networks[aNetId].network.type, - date: new Date(aTimestamp), - rxBytes: aTxBytes, - txBytes: aRxBytes, - isAccumulative: true }; - - debug("Update stats for: " + JSON.stringify(stats)); - - this._db.saveStats(stats, function onSavedStats(aError, aResult) { - if (aCallback) { - if (aError) { - aCallback(false, aError); - return; - } - - aCallback(true, "OK"); - } - }); - }, - - /* - * Function responsible for receiving stats which are not from netd. - */ - saveStats: function saveStats(aAppId, aIsInIsolatedMozBrowser, aServiceType, - aNetworkInfo, aTimeStamp, aRxBytes, aTxBytes, - aIsAccumulative, aCallback) { - let netId = this.convertNetworkInfo(aNetworkInfo); - if (!netId) { - if (aCallback) { - aCallback(false, "Invalid network type"); - } - return; - } - - // Check if |aConnectionType|, |aAppId| and |aServiceType| are valid. - // There are two invalid cases for the combination of |aAppId| and - // |aServiceType|: - // a. Both |aAppId| is non-zero and |aServiceType| is non-empty. - // b. Both |aAppId| is zero and |aServiceType| is empty. - if (!this._networks[netId] || (aAppId && aServiceType) || - (!aAppId && !aServiceType)) { - debug("Invalid network interface, appId or serviceType"); - return; - } - - let stats = { appId: aAppId, - isInBrowser: aIsInIsolatedMozBrowser, - serviceType: aServiceType, - networkId: this._networks[netId].network.id, - networkType: this._networks[netId].network.type, - date: new Date(aTimeStamp), - rxBytes: aRxBytes, - txBytes: aTxBytes, - isAccumulative: aIsAccumulative }; - - this.updateQueue.push({ stats: stats, - callbacks: [aCallback], - queueType: QUEUE_TYPE_WRITE_CACHE }); - - this.processQueue(); - }, - - /* - * - */ - writeCache: function writeCache(aStats, aCallback) { - debug("saveStats: " + aStats.appId + " " + aStats.isInBrowser + " " + - aStats.serviceType + " " + aStats.networkId + " " + - aStats.networkType + " " + aStats.date + " " + - aStats.rxBytes + " " + aStats.txBytes); - - // Generate an unique key from |appId|, |isInBrowser|, |serviceType| and - // |netId|, which is used to retrieve data in |cachedStats|. - let netId = this.getNetworkId(aStats.networkId, aStats.networkType); - let key = aStats.appId + "" + aStats.isInBrowser + "" + - aStats.serviceType + "" + netId; - - // |cachedStats| only keeps the data with the same date. - // If the incoming date is different from |cachedStatsDate|, - // both |cachedStats| and |cachedStatsDate| will get updated. - let diff = (this._db.normalizeDate(aStats.date) - - this._db.normalizeDate(this.cachedStatsDate)) / - this._db.sampleRate; - if (diff != 0) { - this.updateCache(function onUpdated(success, message) { - this.cachedStatsDate = aStats.date; - this.cachedStats[key] = aStats; - - if (aCallback) { - aCallback(true, "ok"); - } - }.bind(this)); - return; - } - - // Try to find the matched row in the cached by |appId| and |connectionType|. - // If not found, save the incoming data into the cached. - let cachedStats = this.cachedStats[key]; - if (!cachedStats) { - this.cachedStats[key] = aStats; - if (aCallback) { - aCallback(true, "ok"); - } - return; - } - - // Find matched row, accumulate the traffic amount. - cachedStats.rxBytes += aStats.rxBytes; - cachedStats.txBytes += aStats.txBytes; - - // If new rxBytes or txBytes exceeds MAX_CACHED_TRAFFIC - // the corresponding row will be saved to indexedDB. - // Then, the row will be removed from the cached. - if (cachedStats.rxBytes > MAX_CACHED_TRAFFIC || - cachedStats.txBytes > MAX_CACHED_TRAFFIC) { - this._db.saveStats(cachedStats, function (error, result) { - debug("Application stats inserted in indexedDB"); - if (aCallback) { - aCallback(true, "ok"); - } - }); - delete this.cachedStats[key]; - return; - } - - if (aCallback) { - aCallback(true, "ok"); - } - }, - - updateCachedStats: function updateCachedStats(aCallback) { - this.updateQueue.push({ callbacks: [aCallback], - queueType: QUEUE_TYPE_UPDATE_CACHE }); - - this.processQueue(); - }, - - updateCache: function updateCache(aCallback) { - debug("updateCache: " + this.cachedStatsDate); - - let stats = Object.keys(this.cachedStats); - if (stats.length == 0) { - // |cachedStats| is empty, no need to update. - if (aCallback) { - aCallback(true, "no need to update"); - } - return; - } - - let index = 0; - this._db.saveStats(this.cachedStats[stats[index]], - function onSavedStats(error, result) { - debug("Application stats inserted in indexedDB"); - - // Clean up the |cachedStats| after updating. - if (index == stats.length - 1) { - this.cachedStats = Object.create(null); - - if (aCallback) { - aCallback(true, "ok"); - } - return; - } - - // Update is not finished, keep updating. - index += 1; - this._db.saveStats(this.cachedStats[stats[index]], - onSavedStats.bind(this, error, result)); - }.bind(this)); - }, - - get maxCachedTraffic () { - return MAX_CACHED_TRAFFIC; - }, - - logAllRecords: function logAllRecords() { - this._db.logAllRecords(function onResult(aError, aResult) { - if (aError) { - debug("Error: " + aError); - return; - } - - debug("===== LOG ====="); - debug("There are " + aResult.length + " items"); - debug(JSON.stringify(aResult)); - }); - }, - - getAlarms: function getAlarms(mm, msg) { - let self = this; - let network = msg.data.network; - let manifestURL = msg.data.manifestURL; - - if (network) { - this.validateNetwork(network, function onValidateNetwork(aNetId) { - if (!aNetId) { - mm.sendAsyncMessage("NetworkStats:GetAlarms:Return", - { id: msg.id, error: "InvalidInterface", result: null }); - return; - } - - self._getAlarms(mm, msg, aNetId, manifestURL); - }); - return; - } - - this._getAlarms(mm, msg, null, manifestURL); - }, - - _getAlarms: function _getAlarms(mm, msg, aNetId, aManifestURL) { - let self = this; - this._db.getAlarms(aNetId, aManifestURL, function onCompleted(error, result) { - if (error) { - mm.sendAsyncMessage("NetworkStats:GetAlarms:Return", - { id: msg.id, error: error, result: result }); - return; - } - - let alarms = [] - // NetworkStatsManager must return the network instead of the networkId. - for (let i = 0; i < result.length; i++) { - let alarm = result[i]; - alarms.push({ id: alarm.id, - network: self._networks[alarm.networkId].network, - threshold: alarm.absoluteThreshold, - data: alarm.data }); - } - - mm.sendAsyncMessage("NetworkStats:GetAlarms:Return", - { id: msg.id, error: null, result: alarms }); - }); - }, - - removeAlarms: function removeAlarms(mm, msg) { - let alarmId = msg.data.alarmId; - let manifestURL = msg.data.manifestURL; - - let self = this; - let callback = function onRemove(error, result) { - if (error) { - mm.sendAsyncMessage("NetworkStats:RemoveAlarms:Return", - { id: msg.id, error: error, result: result }); - return; - } - - for (let i in self._currentAlarms) { - let currentAlarm = self._currentAlarms[i].alarm; - if (currentAlarm && ((alarmId == currentAlarm.id) || - (alarmId == -1 && currentAlarm.manifestURL == manifestURL))) { - - self._updateCurrentAlarm(currentAlarm.networkId); - } - } - - mm.sendAsyncMessage("NetworkStats:RemoveAlarms:Return", - { id: msg.id, error: error, result: true }); - }; - - if (alarmId == -1) { - this._db.removeAlarms(manifestURL, callback); - } else { - this._db.removeAlarm(alarmId, manifestURL, callback); - } - }, - - /* - * Function called from manager to set an alarm. - */ - setAlarm: function setAlarm(mm, msg) { - let options = msg.data; - let network = options.network; - let threshold = options.threshold; - - debug("Set alarm at " + threshold + " for " + JSON.stringify(network)); - - if (threshold < 0) { - mm.sendAsyncMessage("NetworkStats:SetAlarm:Return", - { id: msg.id, error: "InvalidThresholdValue", result: null }); - return; - } - - let self = this; - this.validateNetwork(network, function onValidateNetwork(aNetId) { - if (!aNetId) { - mm.sendAsyncMessage("NetworkStats:SetAlarm:Return", - { id: msg.id, error: "InvalidiConnectionType", result: null }); - return; - } - - let newAlarm = { - id: null, - networkId: aNetId, - absoluteThreshold: threshold, - relativeThreshold: null, - startTime: options.startTime, - data: options.data, - pageURL: options.pageURL, - manifestURL: options.manifestURL - }; - - self._getAlarmQuota(newAlarm, function onUpdate(error, quota) { - if (error) { - mm.sendAsyncMessage("NetworkStats:SetAlarm:Return", - { id: msg.id, error: error, result: null }); - return; - } - - self._db.addAlarm(newAlarm, function addSuccessCb(error, newId) { - if (error) { - mm.sendAsyncMessage("NetworkStats:SetAlarm:Return", - { id: msg.id, error: error, result: null }); - return; - } - - newAlarm.id = newId; - self._setAlarm(newAlarm, function onSet(error, success) { - mm.sendAsyncMessage("NetworkStats:SetAlarm:Return", - { id: msg.id, error: error, result: newId }); - - if (error == "InvalidStateError") { - self._fireAlarm(newAlarm); - } - }); - }); - }); - }); - }, - - _setAlarm: function _setAlarm(aAlarm, aCallback) { - let currentAlarm = this._currentAlarms[aAlarm.networkId]; - if ((Object.getOwnPropertyNames(currentAlarm).length !== 0 && - aAlarm.relativeThreshold > currentAlarm.alarm.relativeThreshold) || - this._networks[aAlarm.networkId].status != NETWORK_STATUS_READY) { - aCallback(null, true); - return; - } - - let self = this; - - this._getAlarmQuota(aAlarm, function onUpdate(aError, aQuota) { - if (aError) { - aCallback(aError, null); - return; - } - - let callback = function onAlarmSet(aError) { - if (aError) { - debug("Set alarm error: " + aError); - aCallback("netdError", null); - return; - } - - self._currentAlarms[aAlarm.networkId].alarm = aAlarm; - - aCallback(null, true); - }; - - debug("Set alarm " + JSON.stringify(aAlarm)); - let interfaceName = self._networks[aAlarm.networkId].interfaceName; - if (interfaceName) { - networkService.setNetworkInterfaceAlarm(interfaceName, - aQuota, - callback); - return; - } - - aCallback(null, true); - }); - }, - - _getAlarmQuota: function _getAlarmQuota(aAlarm, aCallback) { - let self = this; - this.updateStats(aAlarm.networkId, function onStatsUpdated(aResult, aMessage) { - self._db.getCurrentStats(self._networks[aAlarm.networkId].network, - aAlarm.startTime, - function onStatsFound(error, result) { - if (error) { - debug("Error getting stats for " + - JSON.stringify(self._networks[aAlarm.networkId]) + ": " + error); - aCallback(error, result); - return; - } - - let quota = aAlarm.absoluteThreshold - result.rxBytes - result.txBytes; - - // Alarm set to a threshold lower than current rx/tx bytes. - if (quota <= 0) { - aCallback("InvalidStateError", null); - return; - } - - aAlarm.relativeThreshold = aAlarm.startTime - ? result.rxTotalBytes + result.txTotalBytes + quota - : aAlarm.absoluteThreshold; - - aCallback(null, quota); - }); - }); - }, - - _fireAlarm: function _fireAlarm(aAlarm) { - debug("Fire alarm"); - - let self = this; - this._db.removeAlarm(aAlarm.id, null, function onRemove(aError, aResult){ - if (!aError && !aResult) { - return; - } - - self._fireSystemMessage(aAlarm); - self._updateCurrentAlarm(aAlarm.networkId); - }); - }, - - _updateCurrentAlarm: function _updateCurrentAlarm(aNetworkId) { - this._currentAlarms[aNetworkId] = Object.create(null); - - let self = this; - this._db.getFirstAlarm(aNetworkId, function onGet(error, result){ - if (error) { - debug("Error getting the first alarm"); - return; - } - - if (!result) { - let interfaceName = self._networks[aNetworkId].interfaceName; - networkService.setNetworkInterfaceAlarm(interfaceName, -1, - function onComplete(){}); - return; - } - - self._setAlarm(result, function onSet(error, success){ - if (error == "InvalidStateError") { - self._fireAlarm(result); - return; - } - }); - }); - }, - - _fireSystemMessage: function _fireSystemMessage(aAlarm) { - debug("Fire system message: " + JSON.stringify(aAlarm)); - - let manifestURI = Services.io.newURI(aAlarm.manifestURL, null, null); - let pageURI = Services.io.newURI(aAlarm.pageURL, null, null); - - let alarm = { "id": aAlarm.id, - "threshold": aAlarm.absoluteThreshold, - "data": aAlarm.data }; - messenger.sendMessage("networkstats-alarm", alarm, pageURI, manifestURI); - } -}; - -NetworkStatsService.init(); diff --git a/dom/network/NetworkStatsServiceProxy.js b/dom/network/NetworkStatsServiceProxy.js deleted file mode 100644 index f3df4344d..000000000 --- a/dom/network/NetworkStatsServiceProxy.js +++ /dev/null @@ -1,90 +0,0 @@ -/* 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("-*- NetworkStatsServiceProxy: " + s + "\n"); } - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -this.EXPORTED_SYMBOLS = ["NetworkStatsServiceProxy"]; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/NetworkStatsService.jsm"); - -const NETWORKSTATSSERVICEPROXY_CONTRACTID = "@mozilla.org/networkstatsServiceProxy;1"; -const NETWORKSTATSSERVICEPROXY_CID = Components.ID("98fd8f69-784e-4626-aa59-56d6436a3c24"); -const nsINetworkStatsServiceProxy = Ci.nsINetworkStatsServiceProxy; - -function NetworkStatsServiceProxy() { - if (DEBUG) { - debug("Proxy started"); - } -} - -NetworkStatsServiceProxy.prototype = { - /* - * Function called in the protocol layer (HTTP, FTP, WebSocket ...etc) - * to pass the per-app stats to NetworkStatsService. - */ - saveAppStats: function saveAppStats(aAppId, aIsInIsolatedMozBrowser, aNetworkInfo, aTimeStamp, - aRxBytes, aTxBytes, aIsAccumulative, - aCallback) { - if (!aNetworkInfo) { - if (DEBUG) { - debug("|aNetworkInfo| is not specified. Failed to save stats. Returning."); - } - return; - } - - if (DEBUG) { - debug("saveAppStats: " + aAppId + " " + aIsInIsolatedMozBrowser + " " + - aNetworkInfo.type + " " + aTimeStamp + " " + - aRxBytes + " " + aTxBytes + " " + aIsAccumulative); - } - - if (aCallback) { - aCallback = aCallback.notify; - } - - NetworkStatsService.saveStats(aAppId, aIsInIsolatedMozBrowser, "", aNetworkInfo, - aTimeStamp, aRxBytes, aTxBytes, - aIsAccumulative, aCallback); - }, - - /* - * Function called in the points of different system services - * to pass the per-service stats to NetworkStatsService. - */ - saveServiceStats: function saveServiceStats(aServiceType, aNetworkInfo, - aTimeStamp, aRxBytes, aTxBytes, - aIsAccumulative, aCallback) { - if (!aNetworkInfo) { - if (DEBUG) { - debug("|aNetworkInfo| is not specified. Failed to save stats. Returning."); - } - return; - } - - if (DEBUG) { - debug("saveServiceStats: " + aServiceType + " " + aNetworkInfo.type + " " + - aTimeStamp + " " + aRxBytes + " " + aTxBytes + " " + - aIsAccumulative); - } - - if (aCallback) { - aCallback = aCallback.notify; - } - - NetworkStatsService.saveStats(0, false, aServiceType , aNetworkInfo, aTimeStamp, - aRxBytes, aTxBytes, aIsAccumulative, - aCallback); - }, - - classID : NETWORKSTATSSERVICEPROXY_CID, - QueryInterface : XPCOMUtils.generateQI([nsINetworkStatsServiceProxy]), -} - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkStatsServiceProxy]); diff --git a/dom/network/NetworkStatsServiceProxy.manifest b/dom/network/NetworkStatsServiceProxy.manifest deleted file mode 100644 index 24f09f088..000000000 --- a/dom/network/NetworkStatsServiceProxy.manifest +++ /dev/null @@ -1,2 +0,0 @@ -component {98fd8f69-784e-4626-aa59-56d6436a3c24} NetworkStatsServiceProxy.js -contract @mozilla.org/networkstatsServiceProxy;1 {98fd8f69-784e-4626-aa59-56d6436a3c24} diff --git a/dom/network/TCPSocket.cpp b/dom/network/TCPSocket.cpp index 4eb2f72f6..38827a9ac 100644 --- a/dom/network/TCPSocket.cpp +++ b/dom/network/TCPSocket.cpp @@ -33,11 +33,6 @@ #include "nsStringStream.h" #include "secerr.h" #include "sslerr.h" -#ifdef MOZ_WIDGET_GONK -#include "nsINetworkStatsServiceProxy.h" -#include "nsINetworkManager.h" -#include "nsINetworkInterface.h" -#endif #define BUFFER_SIZE 65536 #define NETWORK_STATS_THRESHOLD 65536 @@ -163,12 +158,6 @@ TCPSocket::TCPSocket(nsIGlobalObject* aGlobal, const nsAString& aHost, uint16_t , mTrackingNumber(0) , mWaitingForStartTLS(false) , mObserversActive(false) -#ifdef MOZ_WIDGET_GONK - , mTxBytes(0) - , mRxBytes(0) - , mAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID) - , mInIsolatedMozBrowser(false) -#endif { if (aGlobal) { nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal); @@ -323,13 +312,6 @@ TCPSocket::InitWithTransport(nsISocketTransport* aTransport) mTransport->GetPort(&port); mPort = port; -#ifdef MOZ_WIDGET_GONK - nsCOMPtr<nsINetworkManager> networkManager = do_GetService("@mozilla.org/network/manager;1"); - if (networkManager) { - networkManager->GetActiveNetworkInfo(getter_AddRefs(mActiveNetworkInfo)); - } -#endif - return NS_OK; } @@ -651,12 +633,6 @@ TCPSocket::Resume(mozilla::ErrorResult& aRv) nsresult TCPSocket::MaybeReportErrorAndCloseIfOpen(nsresult status) { -#ifdef MOZ_WIDGET_GONK - // Save network statistics once the connection is closed. - // For now this function is Gonk-specific. - SaveNetworkStats(true); -#endif - // If we're closed, we've already reported the error or just don't need to // report the error. if (mReadyState == TCPReadyState::Closed) { @@ -941,12 +917,6 @@ TCPSocket::Send(nsIInputStream* aStream, uint32_t aByteLength) EnsureCopying(); -#ifdef MOZ_WIDGET_GONK - // Collect transmitted amount for network statistics. - mTxBytes += aByteLength; - SaveNetworkStats(false); -#endif - return !bufferFull; } @@ -1069,12 +1039,6 @@ NS_IMETHODIMP TCPSocket::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, nsIInputStream* aStream, uint64_t aOffset, uint32_t aCount) { -#ifdef MOZ_WIDGET_GONK - // Collect received amount for network statistics. - mRxBytes += aCount; - SaveNetworkStats(false); -#endif - if (mUseArrayBuffers) { nsTArray<uint8_t> buffer; buffer.SetCapacity(aCount); @@ -1160,10 +1124,7 @@ TCPSocket::SetSocketBridgeParent(TCPSocketParent* aBridgeParent) void TCPSocket::SetAppIdAndBrowser(uint32_t aAppId, bool aInIsolatedMozBrowser) { -#ifdef MOZ_WIDGET_GONK - mAppId = aAppId; - mInIsolatedMozBrowser = aInIsolatedMozBrowser; -#endif + /*** STUB ***/ } NS_IMETHODIMP @@ -1190,37 +1151,6 @@ TCPSocket::UpdateBufferedAmount(uint32_t aBufferedAmount, uint32_t aTrackingNumb return NS_OK; } -#ifdef MOZ_WIDGET_GONK -void -TCPSocket::SaveNetworkStats(bool aEnforce) -{ - if (!mTxBytes && !mRxBytes) { - // There is no traffic at all. No need to save statistics. - return; - } - - // If "enforce" is false, the traffic amount is saved to NetworkStatsServiceProxy - // only when the total amount exceeds the predefined threshold value. - // The purpose is to avoid too much overhead for collecting statistics. - uint32_t totalBytes = mTxBytes + mRxBytes; - if (!aEnforce && totalBytes < NETWORK_STATS_THRESHOLD) { - return; - } - - nsCOMPtr<nsINetworkStatsServiceProxy> nssProxy = - do_GetService("@mozilla.org/networkstatsServiceProxy;1"); - if (!nssProxy) { - return; - } - - nssProxy->SaveAppStats(mAppId, mInIsolatedMozBrowser, mActiveNetworkInfo, - PR_Now(), mRxBytes, mTxBytes, false, nullptr); - - // Reset the counters once the statistics is saved to NetworkStatsServiceProxy. - mTxBytes = mRxBytes = 0; -} -#endif - NS_IMETHODIMP TCPSocket::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) { diff --git a/dom/network/TCPSocket.h b/dom/network/TCPSocket.h index e98c03ca5..4ad425b9e 100644 --- a/dom/network/TCPSocket.h +++ b/dom/network/TCPSocket.h @@ -179,10 +179,6 @@ private: void ActivateTLS(); // Dispatch an error event if necessary, then dispatch a "close" event. nsresult MaybeReportErrorAndCloseIfOpen(nsresult status); -#ifdef MOZ_WIDGET_GONK - // Store and reset any saved network stats for this socket. - void SaveNetworkStats(bool aEnforce); -#endif // Helper for FireDataStringEvent/FireDataArrayEvent. nsresult FireDataEvent(JSContext* aCx, const nsAString& aType, @@ -246,19 +242,6 @@ private: nsTArray<nsCOMPtr<nsIInputStream>> mPendingDataWhileCopierActive; bool mObserversActive; - -#ifdef MOZ_WIDGET_GONK - // Number of bytes sent. - uint32_t mTxBytes; - // Number of bytes received. - uint32_t mRxBytes; - // The app that owns this socket. - uint32_t mAppId; - // Was this socket created inside of an isolated browser frame? - bool mInIsolatedMozBrowser; - // The name of the active network used by this socket. - nsCOMPtr<nsINetworkInfo> mActiveNetworkInfo; -#endif }; } // namespace dom diff --git a/dom/network/interfaces/moz.build b/dom/network/interfaces/moz.build index add687542..ad2e56bd6 100644 --- a/dom/network/interfaces/moz.build +++ b/dom/network/interfaces/moz.build @@ -10,10 +10,4 @@ XPIDL_SOURCES += [ 'nsIUDPSocketChild.idl', ] -if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - XPIDL_SOURCES += [ - 'nsIEthernetManager.idl', - 'nsINetworkStatsServiceProxy.idl', - ] - XPIDL_MODULE = 'dom_network' diff --git a/dom/network/interfaces/nsIEthernetManager.idl b/dom/network/interfaces/nsIEthernetManager.idl deleted file mode 100644 index 2b92dc88f..000000000 --- a/dom/network/interfaces/nsIEthernetManager.idl +++ /dev/null @@ -1,137 +0,0 @@ -/* 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/. */ - -#include "nsISupports.idl" - -[scriptable, function, uuid(2a3ad56c-edc0-439f-8aae-900b331ddf49)] -interface nsIEthernetManagerCallback : nsISupports -{ - /** - * Callback function used to report the success of different operations. - * - * @param success - * Boolean value indicates the success of an operation. - * @prarm message - * Message reported in the end of operation. - */ - void notify(in boolean success, in DOMString message); -}; - -[scriptable, function, uuid(1746e7dd-92d4-43fa-8ef4-bc13d0b60353)] -interface nsIEthernetManagerScanCallback : nsISupports -{ - /** - * Callback function used to report the result of scan function. - * - * @param list - * List of available ethernet interfaces. - */ - void notify(in jsval list); -}; - -/** - * An internal idl provides control to ethernet interfaces. - */ -[scriptable, uuid(81750c87-bb3b-4724-b955-834eafa53fd1)] -interface nsIEthernetManager : nsISupports -{ - /** - * List of exisiting interface name. - */ - readonly attribute jsval interfaceList; - - /** - * Scan available ethernet interfaces on device. - * - * @param callback - * Callback function. - */ - void scan(in nsIEthernetManagerScanCallback callback); - - /** - * Add a new interface to the interface list. - * - * @param ifname - * Interface name. Should be the form of "eth*". - * @param callback - * Callback function. - */ - void addInterface(in DOMString ifname, - in nsIEthernetManagerCallback callback); - - /** - * Remove an existing interface from the interface list. - * - * @param ifname - * Interface name. - * @param Callback - * Callback function. - */ - void removeInterface(in DOMString ifname, - in nsIEthernetManagerCallback callback); - - /** - * Update a conifg of an existing interface in the interface list. - * - * @param ifname - * Interface name. - * @param config - * .ip: IP address. - * .prefixLength: Mask length. - * .gateway: Gateway. - * .dnses: DNS addresses. - * .httpProxyHost: HTTP proxy host. - * .httpProxyPort: HTTP proxy port. - * .ipMode: IP mode, can be 'dhcp' or 'static'. - * @param callback - * Callback function. - */ - void updateInterfaceConfig(in DOMString ifname, - in jsval config, - in nsIEthernetManagerCallback callback); - - /** - * Enable networking of an existing interface in the interface list. - * - * @param ifname - * Interface name. - * @param callback - * Callback function. - */ - void enable(in DOMString ifname, - in nsIEthernetManagerCallback callback); - - /** - * Disable networking of an existing interface in the interface list. - * - * @param ifname - * Interface name. - * @param callback - * Callback function. - */ - void disable(in DOMString ifname, - in nsIEthernetManagerCallback callback); - - /** - * Make an existing interface connect to network. - * - * @param ifname - * Interface name. - * @param callback - * Callback function. - */ - void connect(in DOMString ifname, - in nsIEthernetManagerCallback callback); - - /** - * Disconnect a connected interface in the interface list. - * - * @param ifname - * Interface name. - * @param callback - * Callback function. - */ - void disconnect(in DOMString ifname, - in nsIEthernetManagerCallback callback); -}; diff --git a/dom/network/interfaces/nsINetworkStatsServiceProxy.idl b/dom/network/interfaces/nsINetworkStatsServiceProxy.idl deleted file mode 100644 index cd6765c68..000000000 --- a/dom/network/interfaces/nsINetworkStatsServiceProxy.idl +++ /dev/null @@ -1,64 +0,0 @@ -/* 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/. */ - -#include "nsISupports.idl" - -interface nsINetworkInfo; - -[scriptable, function, uuid(5f821529-1d80-4ab5-a933-4e1b3585b6bc)] -interface nsINetworkStatsServiceProxyCallback : nsISupports -{ - /* - * @param aResult callback result with boolean value - * @param aMessage message - */ - void notify(in boolean aResult, in jsval aMessage); -}; - -[scriptable, uuid(f4f3e901-e102-499d-9d37-dc9951f52df7)] -interface nsINetworkStatsServiceProxy : nsISupports -{ - /* - * An interface used to record per-app traffic data. - * @param aAppId app id - * @param aIsInIsolatedMozBrowser - * true if the frame is an isolated mozbrowser element. <iframe - * mozbrowser mozapp> and <xul:browser> are not considered to be - * mozbrowser elements. <iframe mozbrowser noisolation> does not count - * as isolated since isolation is disabled. Isolation can only be - * disabled if the containing document is chrome. - * @param aNetworkInterface network - * @param aTimeStamp time stamp - * @param aRxBytes received data amount - * @param aTxBytes transmitted data amount - * @param aIsAccumulative is stats accumulative - * @param aCallback an optional callback - */ - void saveAppStats(in unsigned long aAppId, - in boolean aIsInIsolatedMozBrowser, - in nsINetworkInfo aNetworkInfo, - in unsigned long long aTimeStamp, - in unsigned long long aRxBytes, - in unsigned long long aTxBytes, - in boolean aIsAccumulative, - [optional] in nsINetworkStatsServiceProxyCallback aCallback); - - /* - * An interface used to record per-system service traffic data. - * @param aServiceType system service type - * @param aNetworkInterface network - * @param aTimeStamp time stamp - * @param aRxBytes received data amount - * @param aTxBytes transmitted data amount - * @param aIsAccumulative is stats accumulative - * @param aCallback an optional callback - */ - void saveServiceStats(in string aServiceType, - in nsINetworkInfo aNetworkInfo, - in unsigned long long aTimeStamp, - in unsigned long long aRxBytes, - in unsigned long long aTxBytes, - in boolean aIsAccumulative, - [optional] in nsINetworkStatsServiceProxyCallback aCallback); -}; diff --git a/dom/network/moz.build b/dom/network/moz.build index 63e5c75c0..ffb90d116 100644 --- a/dom/network/moz.build +++ b/dom/network/moz.build @@ -40,28 +40,6 @@ UNIFIED_SOURCES += [ 'UDPSocketParent.cpp', ] -if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - EXTRA_JS_MODULES += [ - 'NetworkStatsDB.jsm', - 'NetworkStatsService.jsm', - ] - -if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - EXTRA_COMPONENTS += [ - 'EthernetManager.js', - 'EthernetManager.manifest', - 'NetworkStatsManager.js', - 'NetworkStatsManager.manifest', - 'NetworkStatsServiceProxy.js', - 'NetworkStatsServiceProxy.manifest', - ] - EXPORTS.mozilla.dom.network += [ - 'NetUtils.h', - ] - UNIFIED_SOURCES += [ - 'NetUtils.cpp', - ] - IPDL_SOURCES += [ 'PTCPServerSocket.ipdl', 'PTCPSocket.ipdl', |