Bug 964270 - Part 1: Enable networkstats alarms for networks not available. r=gene

This commit is contained in:
Albert Crespell 2014-02-05 12:07:01 +01:00
Родитель 19aa728f9e
Коммит e7bcd95714
1 изменённых файлов: 158 добавлений и 112 удалений

Просмотреть файл

@ -29,6 +29,15 @@ 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;
// 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
@ -89,7 +98,8 @@ this.NetworkStatsService = {
let netId = this.getNetworkId('0', NET_TYPE_WIFI);
this._networks[netId] = { network: { id: '0',
type: NET_TYPE_WIFI },
interfaceName: null };
interfaceName: null,
status: NETWORK_STATUS_STANDBY };
this.messages = ["NetworkStats:Get",
"NetworkStats:Clear",
@ -278,6 +288,7 @@ this.NetworkStatsService = {
type: aNetwork.type };
}
this._networks[netId].status = NETWORK_STATUS_READY;
this._networks[netId].interfaceName = aNetwork.name;
return netId;
},
@ -286,6 +297,46 @@ this.NetworkStatsService = {
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);
}
aCallback(null);
});
},
getAvailableNetworks: function getAvailableNetworks(mm, msg) {
let self = this;
let rilNetworks = this.getRilNetworks();
@ -368,91 +419,55 @@ this.NetworkStatsService = {
let start = new Date(msg.start);
let end = new Date(msg.end);
// Check if the network is currently active. If yes, we need to update
// the cached stats first before retrieving stats from the DB.
if (this._networks[netId]) {
this.updateStats(netId, function onStatsUpdated(aResult, aMessage) {
debug("getstats for network " + network.id + " of type " + network.type);
debug("appId: " + appId + " from appManifestURL: " + appManifestURL);
self.updateCachedStats(function onStatsUpdated(aResult, aMessage) {
self._db.find(function onStatsFound(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: aError, result: aResult });
}, appId, serviceType, network, start, end, appManifestURL);
});
});
return;
}
// Check if the network is available in the DB. If yes, we also
// retrieve the stats for it from the DB.
this._db.isNetworkAvailable(network, function(aError, aResult) {
let toFind = false;
if (aResult) {
toFind = true;
} else if (!aError) {
// Network is not found in the database without any errors.
// Check if network is valid but has not established a connection yet.
let rilNetworks = self.getRilNetworks();
if (rilNetworks[netId]) {
// find will not get data for network from the database but will format the
// result object in order to make NetworkStatsManager be able to construct a
// nsIDOMMozNetworkStats object.
toFind = true;
}
}
if (toFind) {
// If network is not active, there is no need to update stats before finding.
self._db.find(function onStatsFound(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: aError, result: aResult });
}, appId, serviceType, network, start, end, appManifestURL);
this.validateNetwork(network, function onValidateNetwork(aNetId) {
if (!aNetId) {
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: "Invalid connectionType", result: null });
return;
}
if (!aError) {
aError = "Invalid connectionType";
// If network is currently active we need to update the cached stats first before
// retrieving stats from the DB.
if (self._networks[aNetId].status == NETWORK_STATUS_READY) {
self.updateStats(aNetId, function onStatsUpdated(aResult, aMessage) {
debug("getstats for network " + network.id + " of type " + network.type);
debug("appId: " + appId + " from appManifestURL: " + appManifestURL);
self.updateCachedStats(function onStatsUpdated(aResult, aMessage) {
self._db.find(function onStatsFound(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: aError, result: aResult });
}, appId, serviceType, network, start, end, appManifestURL);
});
});
return;
}
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: aError, result: null });
// Network not active, so no need to update
self._db.find(function onStatsFound(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: aError, result: aResult });
}, appId, serviceType, network, start, end, appManifestURL);
});
},
clearInterfaceStats: function clearInterfaceStats(mm, msg) {
let self = this;
let network = msg.network;
let netId = this.getNetworkId(network.id, network.type);
debug("clear stats for network " + network.id + " of type " + network.type);
if (!this._networks[netId]) {
// Check if network is valid but has not established a connection yet. If it is not
// found in RIL networks, it can be a SIM network used in the past having sample
// in the database.
let rilNetworks = this.getRilNetworks();
if (!rilNetworks[netId]) {
// Check if it is available in the DB.
this._db.isNetworkAvailable(network, function(aError, aResult) {
if (aResult) {
this._db.clearInterfaceStats(network, function onDBCleared(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Clear:Return",
{ id: msg.id, error: aError, result: aResult });
});
return;
}
mm.sendAsyncMessage("NetworkStats:Clear:Return",
{ id: msg.id, error: "Invalid networkType", result: null });
});
this.validateNetwork(network, function onValidateNetwork(aNetId) {
if (!aNetId) {
mm.sendAsyncMessage("NetworkStats:Clear:Return",
{ id: msg.id, error: "Invalid connectionType", result: null });
return;
}
}
this._db.clearInterfaceStats(network, function onDBCleared(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Clear:Return",
{ id: msg.id, error: aError, result: aResult });
self._db.clearInterfaceStats(network, function onDBCleared(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Clear:Return",
{ id: msg.id, error: aError, result: aResult });
});
});
},
@ -478,7 +493,7 @@ this.NetworkStatsService = {
this.updateCachedStats();
let elements = [];
let lastElement;
let lastElement = null;
// For each connectionType create an object containning the type
// and the 'queueIndex', the 'queueIndex' is an integer representing
@ -487,14 +502,27 @@ this.NetworkStatsService = {
// 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: []});
elements.push({ netId: lastElement.netId, callbacks: [] });
}
}
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.
@ -800,21 +828,29 @@ this.NetworkStatsService = {
},
getAlarms: function getAlarms(mm, msg) {
let self = this;
let network = msg.data.network;
let manifestURL = msg.data.manifestURL;
let netId = null;
if (network) {
netId = this.getNetworkId(network.id, network.type);
if (!this._networks[netId]) {
mm.sendAsyncMessage("NetworkStats:GetAlarms:Return",
{ id: msg.id, error: "InvalidInterface", result: null });
return;
}
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(netId, manifestURL, function onCompleted(error, result) {
this._db.getAlarms(aNetId, aManifestURL, function onCompleted(error, result) {
if (error) {
mm.sendAsyncMessage("NetworkStats:GetAlarms:Return",
{ id: msg.id, error: error, result: result });
@ -884,48 +920,49 @@ this.NetworkStatsService = {
return;
}
let netId = this.getNetworkId(network.id, network.type);
if (!this._networks[netId]) {
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
{ id: msg.id, error: "InvalidiConnectionType", result: null });
return;
}
let newAlarm = {
id: null,
networkId: netId,
threshold: threshold,
absoluteThreshold: null,
startTime: options.startTime,
data: options.data,
pageURL: options.pageURL,
manifestURL: options.manifestURL
};
let self = this;
this._updateThreshold(newAlarm, function onUpdate(error, _threshold) {
if (error) {
this.validateNetwork(network, function onValidateNetwork(aNetId) {
if (!aNetId) {
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
{ id: msg.id, error: error, result: null });
{ id: msg.id, error: "InvalidiConnectionType", result: null });
return;
}
newAlarm.absoluteThreshold = _threshold.absoluteThreshold;
self._db.addAlarm(newAlarm, function addSuccessCb(error, newId) {
let newAlarm = {
id: null,
networkId: aNetId,
threshold: threshold,
absoluteThreshold: null,
startTime: options.startTime,
data: options.data,
pageURL: options.pageURL,
manifestURL: options.manifestURL
};
self._updateThreshold(newAlarm, function onUpdate(error, _threshold) {
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);
newAlarm.absoluteThreshold = _threshold.absoluteThreshold;
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);
}
});
});
});
});
@ -933,8 +970,9 @@ this.NetworkStatsService = {
_setAlarm: function _setAlarm(aAlarm, aCallback) {
let currentAlarm = this._currentAlarms[aAlarm.networkId];
if (Object.getOwnPropertyNames(currentAlarm).length !== 0 &&
aAlarm.absoluteThreshold > currentAlarm.alarm.absoluteThreshold) {
if ((Object.getOwnPropertyNames(currentAlarm).length !== 0 &&
aAlarm.absoluteThreshold > currentAlarm.alarm.absoluteThreshold) ||
this._networks[aAlarm.networkId].status != NETWORK_STATUS_READY) {
aCallback(null, true);
return;
}
@ -985,6 +1023,14 @@ this.NetworkStatsService = {
return;
}
if (!result) {
// There are no stats for the network of the alarm, set them to default 0 in
// order to be able to calculate the offset, systemThreshold and
// absoluteThreshold.
result = { rxTotalBytes: 0, txTotalBytes: 0,
rxSystemBytes: 0, txSystemBytes: 0 };
}
let offset = aAlarm.threshold - result.rxTotalBytes - result.txTotalBytes;
// Alarm set to a threshold lower than current rx/tx bytes.