Bug 879793 - Update stats when network interface is unregistered. r=clian
authorAlbert Crespell <acperez@tid.es>
Thu, 06 Jun 2013 20:40:50 +0200
changeset 146136 32ea84579cfbe9ee959849f4d8250c3253d88441
parent 146134 0acda90a6f6aac6dc970afaabab158183703d18f
child 146137 e50f7dd54dafa17c90b66c3a6d714ce420029a73
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersclian
bugs879793
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 879793 - Update stats when network interface is unregistered. r=clian
dom/network/src/NetworkStatsService.jsm
dom/system/gonk/NetworkManager.js
dom/system/gonk/nsINetworkManager.idl
--- a/dom/network/src/NetworkStatsService.jsm
+++ b/dom/network/src/NetworkStatsService.jsm
@@ -13,19 +13,20 @@ this.EXPORTED_SYMBOLS = ["NetworkStatsSe
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/NetworkStatsDB.jsm");
 
 const NET_NETWORKSTATSSERVICE_CONTRACTID = "@mozilla.org/network/netstatsservice;1";
 const NET_NETWORKSTATSSERVICE_CID = Components.ID("{18725604-e9ac-488a-8aa0-2471e7f6c0a4}");
 
-const TOPIC_INTERFACE_REGISTERED = "network-interface-registered";
-const NETWORK_TYPE_WIFI = Ci.nsINetworkInterface.NETWORK_TYPE_WIFI;
-const NETWORK_TYPE_MOBILE = Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE;
+const TOPIC_INTERFACE_REGISTERED   = "network-interface-registered";
+const TOPIC_INTERFACE_UNREGISTERED = "network-interface-unregistered";
+const NET_TYPE_WIFI = Ci.nsINetworkInterface.NETWORK_TYPE_WIFI;
+const NET_TYPE_MOBILE = Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE;
 
 XPCOMUtils.defineLazyServiceGetter(this, "gIDBManager",
                                    "@mozilla.org/dom/indexeddb/manager;1",
                                    "nsIIndexedDatabaseManager");
 
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
                                    "@mozilla.org/parentprocessmessagemanager;1",
                                    "nsIMessageListenerManager");
@@ -39,23 +40,27 @@ let myGlobal = this;
 this.NetworkStatsService = {
   init: function() {
     if (DEBUG) {
       debug("Service started");
     }
 
     Services.obs.addObserver(this, "xpcom-shutdown", false);
     Services.obs.addObserver(this, TOPIC_INTERFACE_REGISTERED, false);
+    Services.obs.addObserver(this, TOPIC_INTERFACE_UNREGISTERED, false);
     Services.obs.addObserver(this, "profile-after-change", false);
 
     this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
 
     this._connectionTypes = Object.create(null);
-    this._connectionTypes[NETWORK_TYPE_WIFI] = "wifi";
-    this._connectionTypes[NETWORK_TYPE_MOBILE] = "mobile";
+    this._connectionTypes[NET_TYPE_WIFI] = { name: "wifi",
+                                             network: Object.create(null) };
+    this._connectionTypes[NET_TYPE_MOBILE] = { name: "mobile",
+                                               network: Object.create(null) };
+
 
     this.messages = ["NetworkStats:Get",
                      "NetworkStats:Clear",
                      "NetworkStats:Types",
                      "NetworkStats:SampleRate",
                      "NetworkStats:MaxStorageSamples"];
 
     this.messages.forEach(function(msgName) {
@@ -90,51 +95,58 @@ this.NetworkStatsService = {
         break;
       case "NetworkStats:Clear":
         this.clearDB(mm, msg);
         break;
       case "NetworkStats:Types":
         // This message is sync.
         let types = [];
         for (let i in this._connectionTypes) {
-          types.push(this._connectionTypes[i]);
+          types.push(this._connectionTypes[i].name);
         }
         return types;
       case "NetworkStats:SampleRate":
         // This message is sync.
         return this._db.sampleRate;
       case "NetworkStats:MaxStorageSamples":
         // This message is sync.
         return this._db.maxStorageSamples;
     }
   },
 
   observe: function observe(subject, topic, data) {
     switch (topic) {
       case TOPIC_INTERFACE_REGISTERED:
+      case TOPIC_INTERFACE_UNREGISTERED:
         // If new interface is registered (notified from NetworkManager),
         // the stats are updated for the new interface without waiting to
         // complete the updating period
         let network = subject.QueryInterface(Ci.nsINetworkInterface);
         if (DEBUG) {
-          debug("Network " + network.name + " of type " + network.type + " registered");
+          debug("Network " + network.name + " of type " + network.type + " status change");
         }
-        this.updateStats(network.type);
+        if (this._connectionTypes[network.type]) {
+          this._connectionTypes[network.type].network = network;
+          this.updateStats(network.type);
+        }
         break;
       case "xpcom-shutdown":
         if (DEBUG) {
           debug("Service shutdown");
         }
 
         this.messages.forEach(function(msgName) {
           ppmm.removeMessageListener(msgName, this);
         }, this);
 
         Services.obs.removeObserver(this, "xpcom-shutdown");
         Services.obs.removeObserver(this, "profile-after-change");
+        Services.obs.removeObserver(this, TOPIC_INTERFACE_REGISTERED);
+        Services.obs.removeObserver(this, TOPIC_INTERFACE_UNREGISTERED);
+
         this.timer.cancel();
         this.timer = null;
 
         // Update stats before shutdown
         this.updateAllStats();
         break;
     }
   },
@@ -167,17 +179,17 @@ this.NetworkStatsService = {
         this._db.findAll(function onStatsFound(error, result) {
           mm.sendAsyncMessage("NetworkStats:Get:Return",
                               { id: msg.id, error: error, result: result });
         }, options);
         return;
       }
 
       for (let i in this._connectionTypes) {
-        if (this._connectionTypes[i] == options.connectionType) {
+        if (this._connectionTypes[i].name == options.connectionType) {
           this._db.find(function onStatsFound(error, result) {
             mm.sendAsyncMessage("NetworkStats:Get:Return",
                                 { id: msg.id, error: error, result: result });
           }, options);
           return;
         }
       }
 
@@ -303,55 +315,53 @@ this.NetworkStatsService = {
       return;
     }
 
     // Call the update function for the next element.
     this.update(this.updateQueue[0].type, this.processQueue.bind(this));
   },
 
   update: function update(connectionType, callback) {
-    if (DEBUG) {
-      debug("Update stats for " + this._connectionTypes[connectionType]);
-    }
-
     // Check if connection type is valid.
     if (!this._connectionTypes[connectionType]) {
       if (callback) {
         callback(false, "Invalid network type " + connectionType);
       }
       return;
     }
 
+    if (DEBUG) {
+      debug("Update stats for " + this._connectionTypes[connectionType].name);
+    }
+
     // Request stats to NetworkManager, which will get stats from netd, passing
     // 'networkStatsAvailable' as a callback.
-    if (!networkManager.getNetworkInterfaceStats(connectionType,
-                                                 this.networkStatsAvailable
-                                                     .bind(this, callback))) {
-      if (DEBUG) {
-        debug("There is no interface registered for network type " +
-              this._connectionTypes[connectionType]);
-      }
-
-      // Interface is not registered (up), so nothing to do.
-      callback(true, "OK");
+    let networkName = this._connectionTypes[connectionType].network.name;
+    if (networkName) {
+      networkManager.getNetworkInterfaceStats(networkName,
+                this.networkStatsAvailable.bind(this, callback, connectionType));
+      return;
+    }
+    if (callback) {
+      callback(true, "ok");
     }
   },
 
   /*
    * Callback of request stats. Store stats in database.
    */
-  networkStatsAvailable: function networkStatsAvailable(callback, result, connType, rxBytes, txBytes, date) {
+  networkStatsAvailable: function networkStatsAvailable(callback, connType, result, rxBytes, txBytes, date) {
     if (!result) {
       if (callback) {
         callback(false, "Netd IPC error");
       }
       return;
     }
 
-    let stats = { connectionType: this._connectionTypes[connType],
+    let stats = { connectionType: this._connectionTypes[connType].name,
                   date:           date,
                   rxBytes:        txBytes,
                   txBytes:        rxBytes};
 
     if (DEBUG) {
       debug("Update stats for " + stats.connectionType + ": rx=" + stats.rxBytes +
             " tx=" + stats.txBytes + " timestamp=" + stats.date);
     }
--- a/dom/system/gonk/NetworkManager.js
+++ b/dom/system/gonk/NetworkManager.js
@@ -401,41 +401,33 @@ NetworkManager.prototype = {
   // Clone network info so we can still get information when network is disconnected
   _activeInfo: null,
 
   overrideActive: function overrideActive(network) {
     this._overriddenActive = network;
     this.setAndConfigureActive();
   },
 
-  getNetworkInterfaceStats: function getNetworkInterfaceStats(connectionType, callback) {
-    let iface = this.getNetworkInterface(connectionType);
-
-    if (!iface) {
-      debug("There is no interface registered for network type " + connectionType);
-      return false;
-    }
-
-    debug("getNetworkInterfaceStats for " + iface.name);
+  getNetworkInterfaceStats: function getNetworkInterfaceStats(networkName, callback) {
+    debug("getNetworkInterfaceStats for " + networkName);
 
     let params = {
       cmd: "getNetworkInterfaceStats",
-      ifname: iface.name,
-      connType: connectionType
+      ifname: networkName
     };
 
     params.report = true;
     params.isAsync = true;
 
     this.controlMessage(params, function(result) {
-      let success = result.resultCode >= NETD_COMMAND_OKAY && result.resultCode < NETD_COMMAND_ERROR;
-      callback.networkStatsAvailable(success, result.connType, result.rxBytes, result.txBytes, result.date);
+      let success = result.resultCode >= NETD_COMMAND_OKAY &&
+                    result.resultCode < NETD_COMMAND_ERROR;
+      callback.networkStatsAvailable(success, result.rxBytes,
+                                     result.txBytes, result.date);
     });
-
-    return true;
   },
 
   // Helpers
 
   controlMessage: function controlMessage(params, callback) {
     if (callback) {
       let id = callback.name;
       params.id = id;
--- a/dom/system/gonk/nsINetworkManager.idl
+++ b/dom/system/gonk/nsINetworkManager.idl
@@ -94,30 +94,29 @@ interface nsIWifiTetheringCallback : nsI
    *
    * @param error
    *        An error message if the operation wasn't successful,
    *        or `null` if it was.
    */
   void wifiTetheringEnabledChange(in jsval error);
 };
 
-[scriptable, function, uuid(9a887e18-b879-4bb1-8663-238bc4234ba0)]
+[scriptable, function, uuid(e079aa2a-ec0a-4bbd-b1a4-d81a9faae464)]
 interface nsINetworkStatsCallback : nsISupports
 {
   void networkStatsAvailable(in boolean success,
-                             in short connType,
                              in unsigned long rxBytes,
                              in unsigned long txBytes,
                              in jsval date);
 };
 
 /**
  * Manage network interfaces.
  */
-[scriptable, uuid(24f8ede0-c862-11e2-8b8b-0800200c9a66)]
+[scriptable, uuid(f39a0fb6-2752-47d2-943e-a0cdd3e43494)]
 interface nsINetworkManager : nsISupports
 {
   /**
    * Register the given network interface with the network manager.
    *
    * Consumers will be notified with the 'network-interface-registered'
    * observer notification.
    *
@@ -195,20 +194,18 @@ interface nsINetworkManager : nsISupport
   void setWifiTethering(in boolean enabled,
                         in nsINetworkInterface networkInterface,
                         in jsval config,
                         in nsIWifiTetheringCallback callback);
 
   /**
    * Retrieve network interface stats.
    *
-   * @param networkType
+   * @param networkName
    *        Select the Network interface to request estats.
    *
    * @param callback
    *        Callback to notify result and provide stats, connectionType
    *        and the date when stats are retrieved
-   *
-   * @return false if there is no interface registered for the networkType param.
    */
-  boolean getNetworkInterfaceStats(in short networkType, in nsINetworkStatsCallback callback);
+  void getNetworkInterfaceStats(in DOMString networkName, in nsINetworkStatsCallback callback);
 
 };