Bug 879793 - Update stats when network interface is unregistered. r=clian

This commit is contained in:
Albert Crespell 2013-06-06 20:40:50 +02:00
parent f93a1f4522
commit 60c8fa8f91
3 changed files with 46 additions and 47 deletions

View File

@ -18,9 +18,10 @@ 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",
@ -44,13 +45,17 @@ this.NetworkStatsService = {
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",
@ -95,7 +100,7 @@ this.NetworkStatsService = {
// 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":
@ -110,14 +115,18 @@ this.NetworkStatsService = {
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");
}
if (this._connectionTypes[network.type]) {
this._connectionTypes[network.type].network = network;
this.updateStats(network.type);
}
this.updateStats(network.type);
break;
case "xpcom-shutdown":
if (DEBUG) {
@ -130,6 +139,9 @@ this.NetworkStatsService = {
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;
@ -172,7 +184,7 @@ this.NetworkStatsService = {
}
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 });
@ -308,10 +320,6 @@ this.NetworkStatsService = {
},
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) {
@ -320,25 +328,27 @@ this.NetworkStatsService = {
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");
@ -346,7 +356,7 @@ this.NetworkStatsService = {
return;
}
let stats = { connectionType: this._connectionTypes[connType],
let stats = { connectionType: this._connectionTypes[connType].name,
date: date,
rxBytes: txBytes,
txBytes: rxBytes};

View File

@ -406,31 +406,23 @@ NetworkManager.prototype = {
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

View File

@ -99,11 +99,10 @@ interface nsIWifiTetheringCallback : nsISupports
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);
@ -112,7 +111,7 @@ interface nsINetworkStatsCallback : nsISupports
/**
* Manage network interfaces.
*/
[scriptable, uuid(24f8ede0-c862-11e2-8b8b-0800200c9a66)]
[scriptable, uuid(f39a0fb6-2752-47d2-943e-a0cdd3e43494)]
interface nsINetworkManager : nsISupports
{
/**
@ -200,15 +199,13 @@ interface nsINetworkManager : nsISupports
/**
* 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);
};