This commit is contained in:
Ryan VanderMeulen 2013-12-06 15:56:46 -05:00
Родитель ceaf334c45 1fad3297b3
Коммит e837de97ec
41 изменённых файлов: 1846 добавлений и 293 удалений

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

@ -18,4 +18,4 @@
# Modifying this file will now automatically clobber the buildbot machines \o/ # Modifying this file will now automatically clobber the buildbot machines \o/
# #
Bug 915735 requires clobber Bug 933585 - clobber required on windows

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

@ -1,4 +1,4 @@
{ {
"revision": "d10e0357c63bb565db8bdd3c23f062bfb9e21315", "revision": "63d432c3395f95c0ba19578487b796c1707042bd",
"repo_path": "/integration/gaia-central" "repo_path": "/integration/gaia-central"
} }

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

@ -44,7 +44,6 @@ pref("layers.componentalpha.enabled", false);
pref("apz.touch_start_tolerance", "0.1"); // dpi * tolerance = pixel threshold pref("apz.touch_start_tolerance", "0.1"); // dpi * tolerance = pixel threshold
pref("apz.pan_repaint_interval", 50); // prefer 20 fps pref("apz.pan_repaint_interval", 50); // prefer 20 fps
pref("apz.fling_repaint_interval", 50); // prefer 20 fps pref("apz.fling_repaint_interval", 50); // prefer 20 fps
pref("apz.fling_friction", "0.002");
pref("apz.fling_stopped_threshold", "0.2"); pref("apz.fling_stopped_threshold", "0.2");
// 0 = free, 1 = standard, 2 = sticky // 0 = free, 1 = standard, 2 = sticky

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

@ -78,7 +78,7 @@ SetObexPacketInfo(uint8_t* aRetBuf, uint8_t aOpcode, int aPacketLength)
aRetBuf[2] = aPacketLength & 0x00FF; aRetBuf[2] = aPacketLength & 0x00FF;
} }
void bool
ParseHeaders(const uint8_t* aHeaderStart, ParseHeaders(const uint8_t* aHeaderStart,
int aTotalLength, int aTotalLength,
ObexHeaderSet* aRetHandlerSet) ObexHeaderSet* aRetHandlerSet)
@ -88,7 +88,7 @@ ParseHeaders(const uint8_t* aHeaderStart,
while (ptr - aHeaderStart < aTotalLength) { while (ptr - aHeaderStart < aTotalLength) {
ObexHeaderId headerId = (ObexHeaderId)*ptr++; ObexHeaderId headerId = (ObexHeaderId)*ptr++;
int contentLength = 0; uint16_t contentLength = 0;
uint8_t highByte, lowByte; uint8_t highByte, lowByte;
// Defined in 2.1 OBEX Headers, IrOBEX 1.2 // Defined in 2.1 OBEX Headers, IrOBEX 1.2
@ -101,7 +101,7 @@ ParseHeaders(const uint8_t* aHeaderStart,
// byte sequence, length prefixed with 2 byte unsigned integer. // byte sequence, length prefixed with 2 byte unsigned integer.
highByte = *ptr++; highByte = *ptr++;
lowByte = *ptr++; lowByte = *ptr++;
contentLength = (((int)highByte << 8) | lowByte) - 3; contentLength = (((uint16_t)highByte << 8) | lowByte) - 3;
break; break;
case 0x02: case 0x02:
@ -115,10 +115,20 @@ ParseHeaders(const uint8_t* aHeaderStart,
break; break;
} }
aRetHandlerSet->AddHeader(new ObexHeader(headerId, contentLength, ptr)); // Length check to prevent from memory pollusion.
if (ptr + contentLength > aHeaderStart + aTotalLength) {
// Severe error occurred. We can't even believe the received data, so
// clear all headers.
MOZ_ASSERT(false);
aRetHandlerSet->ClearHeaders();
return false;
}
aRetHandlerSet->AddHeader(new ObexHeader(headerId, contentLength, ptr));
ptr += contentLength; ptr += contentLength;
} }
return true;
} }
END_BLUETOOTH_NAMESPACE END_BLUETOOTH_NAMESPACE

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

@ -102,7 +102,8 @@ enum ObexResponseCode {
DatabaseLocked = 0xE1, DatabaseLocked = 0xE1,
}; };
class ObexHeader { class ObexHeader
{
public: public:
ObexHeader(ObexHeaderId aId, int aDataLength, const uint8_t* aData) ObexHeader(ObexHeaderId aId, int aDataLength, const uint8_t* aData)
: mId(aId) : mId(aId)
@ -122,11 +123,9 @@ public:
nsAutoArrayPtr<uint8_t> mData; nsAutoArrayPtr<uint8_t> mData;
}; };
class ObexHeaderSet { class ObexHeaderSet
{
public: public:
uint8_t mOpcode;
nsTArray<nsAutoPtr<ObexHeader> > mHeaders;
ObexHeaderSet(uint8_t aOpcode) : mOpcode(aOpcode) ObexHeaderSet(uint8_t aOpcode) : mOpcode(aOpcode)
{ {
} }
@ -241,6 +240,15 @@ public:
return false; return false;
} }
void ClearHeaders()
{
mHeaders.Clear();
}
private:
uint8_t mOpcode;
nsTArray<nsAutoPtr<ObexHeader> > mHeaders;
}; };
int AppendHeaderName(uint8_t* aRetBuf, const char* aName, int aLength); int AppendHeaderName(uint8_t* aRetBuf, const char* aName, int aLength);
@ -249,7 +257,11 @@ int AppendHeaderEndOfBody(uint8_t* aRetBuf);
int AppendHeaderLength(uint8_t* aRetBuf, int aObjectLength); int AppendHeaderLength(uint8_t* aRetBuf, int aObjectLength);
int AppendHeaderConnectionId(uint8_t* aRetBuf, int aConnectionId); int AppendHeaderConnectionId(uint8_t* aRetBuf, int aConnectionId);
void SetObexPacketInfo(uint8_t* aRetBuf, uint8_t aOpcode, int aPacketLength); void SetObexPacketInfo(uint8_t* aRetBuf, uint8_t aOpcode, int aPacketLength);
void ParseHeaders(const uint8_t* aHeaderStart,
/**
* @return true when the message was parsed without any error, false otherwise.
*/
bool ParseHeaders(const uint8_t* aHeaderStart,
int aTotalLength, int aTotalLength,
ObexHeaderSet* aRetHanderSet); ObexHeaderSet* aRetHanderSet);

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

@ -803,25 +803,31 @@ BluetoothOppManager::ServerDataHandler(UnixSocketRawData* aMessage)
// Section 3.3.1 "Connect", IrOBEX 1.2 // Section 3.3.1 "Connect", IrOBEX 1.2
// [opcode:1][length:2][version:1][flags:1][MaxPktSizeWeCanReceive:2] // [opcode:1][length:2][version:1][flags:1][MaxPktSizeWeCanReceive:2]
// [Headers:var] // [Headers:var]
ParseHeaders(&aMessage->mData[7], if (!ParseHeaders(&aMessage->mData[7], receivedLength - 7, &pktHeaders)) {
receivedLength - 7, ReplyError(ObexResponseCode::BadRequest);
&pktHeaders); return;
}
ReplyToConnect(); ReplyToConnect();
AfterOppConnected(); AfterOppConnected();
} else if (opCode == ObexRequestCode::Abort) { } else if (opCode == ObexRequestCode::Abort) {
// Section 3.3.5 "Abort", IrOBEX 1.2 // Section 3.3.5 "Abort", IrOBEX 1.2
// [opcode:1][length:2][Headers:var] // [opcode:1][length:2][Headers:var]
ParseHeaders(&aMessage->mData[3], if (!ParseHeaders(&aMessage->mData[3], receivedLength - 3, &pktHeaders)) {
receivedLength - 3, ReplyError(ObexResponseCode::BadRequest);
&pktHeaders); return;
}
ReplyToDisconnectOrAbort(); ReplyToDisconnectOrAbort();
DeleteReceivedFile(); DeleteReceivedFile();
} else if (opCode == ObexRequestCode::Disconnect) { } else if (opCode == ObexRequestCode::Disconnect) {
// Section 3.3.2 "Disconnect", IrOBEX 1.2 // Section 3.3.2 "Disconnect", IrOBEX 1.2
// [opcode:1][length:2][Headers:var] // [opcode:1][length:2][Headers:var]
ParseHeaders(&aMessage->mData[3], if (!ParseHeaders(&aMessage->mData[3], receivedLength - 3, &pktHeaders)) {
receivedLength - 3, ReplyError(ObexResponseCode::BadRequest);
&pktHeaders); return;
}
ReplyToDisconnectOrAbort(); ReplyToDisconnectOrAbort();
AfterOppDisconnected(); AfterOppDisconnected();
FileTransferComplete(); FileTransferComplete();
@ -1197,7 +1203,7 @@ BluetoothOppManager::ReplyToPut(bool aFinal, bool aContinue)
void void
BluetoothOppManager::ReplyError(uint8_t aError) BluetoothOppManager::ReplyError(uint8_t aError)
{ {
if (!mConnected) return; BT_LOGR("error: %d", aError);
// Section 3.2 "Response Format", IrOBEX 1.2 // Section 3.2 "Response Format", IrOBEX 1.2
// [opcode:1][length:2][Headers:var] // [opcode:1][length:2][Headers:var]

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

@ -341,9 +341,12 @@ Call::IsActive()
/** /**
* BluetoothHfpManager * BluetoothHfpManager
*/ */
BluetoothHfpManager::BluetoothHfpManager() : mPhoneType(PhoneType::NONE) BluetoothHfpManager::BluetoothHfpManager() : mController(nullptr)
, mController(nullptr)
{ {
#ifdef MOZ_B2G_RIL
mPhoneType = PhoneType::NONE;
#endif // MOZ_B2G_RIL
Reset(); Reset();
} }

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

@ -819,25 +819,31 @@ BluetoothOppManager::ServerDataHandler(UnixSocketRawData* aMessage)
// Section 3.3.1 "Connect", IrOBEX 1.2 // Section 3.3.1 "Connect", IrOBEX 1.2
// [opcode:1][length:2][version:1][flags:1][MaxPktSizeWeCanReceive:2] // [opcode:1][length:2][version:1][flags:1][MaxPktSizeWeCanReceive:2]
// [Headers:var] // [Headers:var]
ParseHeaders(&aMessage->mData[7], if (!ParseHeaders(&aMessage->mData[7], receivedLength - 7, &pktHeaders)) {
receivedLength - 7, ReplyError(ObexResponseCode::BadRequest);
&pktHeaders); return;
}
ReplyToConnect(); ReplyToConnect();
AfterOppConnected(); AfterOppConnected();
} else if (opCode == ObexRequestCode::Abort) { } else if (opCode == ObexRequestCode::Abort) {
// Section 3.3.5 "Abort", IrOBEX 1.2 // Section 3.3.5 "Abort", IrOBEX 1.2
// [opcode:1][length:2][Headers:var] // [opcode:1][length:2][Headers:var]
ParseHeaders(&aMessage->mData[3], if (!ParseHeaders(&aMessage->mData[3], receivedLength - 3, &pktHeaders)) {
receivedLength - 3, ReplyError(ObexResponseCode::BadRequest);
&pktHeaders); return;
}
ReplyToDisconnectOrAbort(); ReplyToDisconnectOrAbort();
DeleteReceivedFile(); DeleteReceivedFile();
} else if (opCode == ObexRequestCode::Disconnect) { } else if (opCode == ObexRequestCode::Disconnect) {
// Section 3.3.2 "Disconnect", IrOBEX 1.2 // Section 3.3.2 "Disconnect", IrOBEX 1.2
// [opcode:1][length:2][Headers:var] // [opcode:1][length:2][Headers:var]
ParseHeaders(&aMessage->mData[3], if (!ParseHeaders(&aMessage->mData[3], receivedLength - 3, &pktHeaders)) {
receivedLength - 3, ReplyError(ObexResponseCode::BadRequest);
&pktHeaders); return;
}
ReplyToDisconnectOrAbort(); ReplyToDisconnectOrAbort();
AfterOppDisconnected(); AfterOppDisconnected();
FileTransferComplete(); FileTransferComplete();
@ -1213,7 +1219,7 @@ BluetoothOppManager::ReplyToPut(bool aFinal, bool aContinue)
void void
BluetoothOppManager::ReplyError(uint8_t aError) BluetoothOppManager::ReplyError(uint8_t aError)
{ {
if (!mConnected) return; BT_LOGR("error: %d", aError);
// Section 3.2 "Response Format", IrOBEX 1.2 // Section 3.2 "Response Format", IrOBEX 1.2
// [opcode:1][length:2][Headers:var] // [opcode:1][length:2][Headers:var]

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

@ -79,6 +79,7 @@ enum {
CAMERA_PARAM_PICTURESIZE, CAMERA_PARAM_PICTURESIZE,
CAMERA_PARAM_THUMBNAILSIZE, CAMERA_PARAM_THUMBNAILSIZE,
CAMERA_PARAM_THUMBNAILQUALITY, CAMERA_PARAM_THUMBNAILQUALITY,
CAMERA_PARAM_SENSORANGLE,
CAMERA_PARAM_SUPPORTED_PREVIEWSIZES, CAMERA_PARAM_SUPPORTED_PREVIEWSIZES,
CAMERA_PARAM_SUPPORTED_VIDEOSIZES, CAMERA_PARAM_SUPPORTED_VIDEOSIZES,

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

@ -268,6 +268,14 @@ CameraControlImpl::Get(uint32_t aKey, idl::CameraSize& aSize)
return NS_OK; return NS_OK;
} }
nsresult
CameraControlImpl::Get(uint32_t aKey, int32_t* aValue)
{
MOZ_ASSERT(aValue);
*aValue = GetParameterInt32(aKey);
return NS_OK;
}
already_AddRefed<RecorderProfileManager> already_AddRefed<RecorderProfileManager>
CameraControlImpl::GetRecorderProfileManager() CameraControlImpl::GetRecorderProfileManager()
{ {

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

@ -75,6 +75,7 @@ public:
nsresult Get(nsICameraPreviewStateChange** aOnPreviewStateChange); nsresult Get(nsICameraPreviewStateChange** aOnPreviewStateChange);
nsresult Set(uint32_t aKey, const idl::CameraSize& aSize); nsresult Set(uint32_t aKey, const idl::CameraSize& aSize);
nsresult Get(uint32_t aKey, idl::CameraSize& aSize); nsresult Get(uint32_t aKey, idl::CameraSize& aSize);
nsresult Get(uint32_t aKey, int32_t* aValue);
nsresult SetFocusAreas(JSContext* aCx, const JS::Value& aValue) nsresult SetFocusAreas(JSContext* aCx, const JS::Value& aValue)
{ {
@ -92,6 +93,7 @@ public:
virtual const char* GetParameter(const char* aKey) = 0; virtual const char* GetParameter(const char* aKey) = 0;
virtual const char* GetParameterConstChar(uint32_t aKey) = 0; virtual const char* GetParameterConstChar(uint32_t aKey) = 0;
virtual double GetParameterDouble(uint32_t aKey) = 0; virtual double GetParameterDouble(uint32_t aKey) = 0;
virtual int32_t GetParameterInt32(uint32_t aKey) = 0;
virtual void GetParameter(uint32_t aKey, nsTArray<idl::CameraRegion>& aRegions) = 0; virtual void GetParameter(uint32_t aKey, nsTArray<idl::CameraRegion>& aRegions) = 0;
virtual void GetParameter(uint32_t aKey, idl::CameraSize& aSize) = 0; virtual void GetParameter(uint32_t aKey, idl::CameraSize& aSize) = 0;
virtual void SetParameter(const char* aKey, const char* aValue) = 0; virtual void SetParameter(const char* aKey, const char* aValue) = 0;

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

@ -285,6 +285,14 @@ nsDOMCameraControl::GetExposureCompensation(ErrorResult& aRv)
return compensation; return compensation;
} }
int32_t
nsDOMCameraControl::SensorAngle()
{
int32_t angle;
mCameraControl->Get(CAMERA_PARAM_SENSORANGLE, &angle);
return angle;
}
already_AddRefed<nsICameraShutterCallback> already_AddRefed<nsICameraShutterCallback>
nsDOMCameraControl::GetOnShutter(ErrorResult& aRv) nsDOMCameraControl::GetOnShutter(ErrorResult& aRv)
{ {

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

@ -76,6 +76,7 @@ public:
double GetFocusDistanceFar(ErrorResult& aRv); double GetFocusDistanceFar(ErrorResult& aRv);
void SetExposureCompensation(const dom::Optional<double>& aCompensation, ErrorResult& aRv); void SetExposureCompensation(const dom::Optional<double>& aCompensation, ErrorResult& aRv);
double GetExposureCompensation(ErrorResult& aRv); double GetExposureCompensation(ErrorResult& aRv);
int32_t SensorAngle();
already_AddRefed<nsICameraShutterCallback> GetOnShutter(ErrorResult& aRv); already_AddRefed<nsICameraShutterCallback> GetOnShutter(ErrorResult& aRv);
void SetOnShutter(nsICameraShutterCallback* aCb, ErrorResult& aRv); void SetOnShutter(nsICameraShutterCallback* aCb, ErrorResult& aRv);
already_AddRefed<nsICameraClosedCallback> GetOnClosed(ErrorResult& aRv); already_AddRefed<nsICameraClosedCallback> GetOnClosed(ErrorResult& aRv);

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

@ -24,6 +24,7 @@ public:
const char* GetParameter(const char* aKey); const char* GetParameter(const char* aKey);
const char* GetParameterConstChar(uint32_t aKey); const char* GetParameterConstChar(uint32_t aKey);
double GetParameterDouble(uint32_t aKey); double GetParameterDouble(uint32_t aKey);
int32_t GetParameterInt32(uint32_t aKey);
void GetParameter(uint32_t aKey, nsTArray<idl::CameraRegion>& aRegions); void GetParameter(uint32_t aKey, nsTArray<idl::CameraRegion>& aRegions);
void GetParameter(uint32_t aKey, idl::CameraSize& aSize); void GetParameter(uint32_t aKey, idl::CameraSize& aSize);
void SetParameter(const char* aKey, const char* aValue); void SetParameter(const char* aKey, const char* aValue);
@ -101,6 +102,12 @@ nsFallbackCameraControl::GetParameterDouble(uint32_t aKey)
return NAN; return NAN;
} }
int32_t
nsFallbackCameraControl::GetParameterInt32(uint32_t aKey)
{
return 0;
}
void void
nsFallbackCameraControl::GetParameter(uint32_t aKey, nsTArray<idl::CameraRegion>& aRegions) nsFallbackCameraControl::GetParameter(uint32_t aKey, nsTArray<idl::CameraRegion>& aRegions)
{ {

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

@ -434,6 +434,25 @@ nsGonkCameraControl::GetParameterDouble(uint32_t aKey)
} }
} }
int32_t
nsGonkCameraControl::GetParameterInt32(uint32_t aKey)
{
if (aKey == CAMERA_PARAM_SENSORANGLE) {
if (!mCameraHw.get()) {
return 0;
}
return mCameraHw->GetSensorOrientation();
}
const char* key = getKeyText(aKey);
if (!key) {
return 0;
}
RwAutoLockRead lock(mRwLock);
return mParams.getInt(key);
}
void void
nsGonkCameraControl::GetParameter(uint32_t aKey, nsGonkCameraControl::GetParameter(uint32_t aKey,
nsTArray<idl::CameraRegion>& aRegions) nsTArray<idl::CameraRegion>& aRegions)

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

@ -53,6 +53,7 @@ public:
const char* GetParameter(const char* aKey); const char* GetParameter(const char* aKey);
const char* GetParameterConstChar(uint32_t aKey); const char* GetParameterConstChar(uint32_t aKey);
double GetParameterDouble(uint32_t aKey); double GetParameterDouble(uint32_t aKey);
int32_t GetParameterInt32(uint32_t aKey);
void GetParameter(uint32_t aKey, nsTArray<idl::CameraRegion>& aRegions); void GetParameter(uint32_t aKey, nsTArray<idl::CameraRegion>& aRegions);
void GetParameter(uint32_t aKey, nsTArray<idl::CameraSize>& aSizes); void GetParameter(uint32_t aKey, nsTArray<idl::CameraSize>& aSizes);
void GetParameter(uint32_t aKey, idl::CameraSize& aSize); void GetParameter(uint32_t aKey, idl::CameraSize& aSize);

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

@ -46,6 +46,7 @@ public:
virtual nsresult Get(nsICameraPreviewStateChange** aOnPreviewStateChange) = 0; virtual nsresult Get(nsICameraPreviewStateChange** aOnPreviewStateChange) = 0;
virtual nsresult Set(uint32_t aKey, const idl::CameraSize& aSize) = 0; virtual nsresult Set(uint32_t aKey, const idl::CameraSize& aSize) = 0;
virtual nsresult Get(uint32_t aKey, idl::CameraSize& aSize) = 0; virtual nsresult Get(uint32_t aKey, idl::CameraSize& aSize) = 0;
virtual nsresult Get(uint32_t aKey, int32_t* aValue) = 0;
virtual nsresult SetFocusAreas(JSContext* aCx, const JS::Value& aValue) = 0; virtual nsresult SetFocusAreas(JSContext* aCx, const JS::Value& aValue) = 0;
virtual nsresult SetMeteringAreas(JSContext* aCx, const JS::Value& aValue) = 0; virtual nsresult SetMeteringAreas(JSContext* aCx, const JS::Value& aValue) = 0;
virtual nsresult GetVideoSizes(nsTArray<idl::CameraSize>& aVideoSizes) = 0; virtual nsresult GetVideoSizes(nsTArray<idl::CameraSize>& aVideoSizes) = 0;

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

@ -62,6 +62,9 @@ this.SystemMessagePermissionsTable = {
"settings": ["read", "write"] "settings": ["read", "write"]
}, },
"media-button": { }, "media-button": { },
"networkstats-alarm": {
"networkstats-manage": []
},
"notification": { "notification": {
"desktop-notification": [] "desktop-notification": []
}, },

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

@ -20,7 +20,22 @@ interface nsIDOMMozNetworkStatsInterface : nsISupports
readonly attribute DOMString id; readonly attribute DOMString id;
}; };
[scriptable, uuid(5f033d31-c9a2-4e2d-83aa-6a807f1e0c11)] dictionary NetworkStatsAlarmOptions
{
jsval startTime; // Date object
jsval data;
};
[scriptable, builtinclass, uuid(063ebeb2-5c6e-47ae-bdcd-5e6ebdc7a68c)]
interface nsIDOMMozNetworkStatsAlarm : nsISupports
{
readonly attribute unsigned long alarmId;
readonly attribute nsIDOMMozNetworkStatsInterface network;
readonly attribute long threshold;
readonly attribute jsval data;
};
[scriptable, uuid(50d109b8-0d7f-4208-81fe-5f07a759f159)]
interface nsIDOMMozNetworkStatsManager : nsISupports interface nsIDOMMozNetworkStatsManager : nsISupports
{ {
/** /**
@ -42,6 +57,41 @@ interface nsIDOMMozNetworkStatsManager : nsISupports
in jsval end, in jsval end,
[optional] in DOMString manifestURL); [optional] in DOMString manifestURL);
/**
* Install an alarm on a network. The network must be in the return of
* getAvailableNetworks() otherwise an "InvalidNetwork" exception will
* be raised.
*
* When total data usage reaches threshold bytes, a "networkstats-alarm"
* system message is sent to the application, where the optional parameter
* |data| must be a cloneable object.
*
* If success, the |result| field of the DOMRequest keeps the alarm Id.
*/
nsIDOMDOMRequest addAlarm(in nsIDOMMozNetworkStatsInterface network,
in long threshold,
[optional] in jsval options /* NetworkStatsAlarmOptions */);
/**
* Obtain all alarms for those networks returned by getAvailableNetworks().
* If a network is provided, only retrieves the alarms for that network.
* The network must be one of those returned by getAvailebleNetworks() or an
* "InvalidNetwork" exception will be raised.
*
* Each alarm object has the same fields as that in the system message:
* - alarmId
* - network
* - threshold
* - data
*/
nsIDOMDOMRequest getAllAlarms([optional] in nsIDOMMozNetworkStatsInterface network);
/**
* Remove all network alarms. If an |alarmId| is provided, then only that
* alarm is removed.
*/
nsIDOMDOMRequest removeAlarms([optional] in long alarmId);
/** /**
* Remove all stats related with the provided network from DB. * Remove all stats related with the provided network from DB.
*/ */

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

@ -16,8 +16,9 @@ Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
Cu.importGlobalProperties(["indexedDB"]); Cu.importGlobalProperties(["indexedDB"]);
const DB_NAME = "net_stats"; const DB_NAME = "net_stats";
const DB_VERSION = 4; const DB_VERSION = 5;
const STORE_NAME = "net_stats"; const STATS_STORE_NAME = "net_stats";
const ALARMS_STORE_NAME = "net_alarm";
// Constant defining the maximum values allowed per interface. If more, older // Constant defining the maximum values allowed per interface. If more, older
// will be erased. // will be erased.
@ -30,20 +31,20 @@ this.NetworkStatsDB = function NetworkStatsDB() {
if (DEBUG) { if (DEBUG) {
debug("Constructor"); debug("Constructor");
} }
this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME]); this.initDBHelper(DB_NAME, DB_VERSION, [STATS_STORE_NAME, ALARMS_STORE_NAME]);
} }
NetworkStatsDB.prototype = { NetworkStatsDB.prototype = {
__proto__: IndexedDBHelper.prototype, __proto__: IndexedDBHelper.prototype,
dbNewTxn: function dbNewTxn(txn_type, callback, txnCb) { dbNewTxn: function dbNewTxn(store_name, txn_type, callback, txnCb) {
function successCb(result) { function successCb(result) {
txnCb(null, result); txnCb(null, result);
} }
function errorCb(error) { function errorCb(error) {
txnCb(error, null); txnCb(error, null);
} }
return this.newTxn(txn_type, STORE_NAME, callback, successCb, errorCb); return this.newTxn(txn_type, store_name, callback, successCb, errorCb);
}, },
upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) { upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
@ -58,7 +59,7 @@ NetworkStatsDB.prototype = {
* Create the initial database schema. * Create the initial database schema.
*/ */
objectStore = db.createObjectStore(STORE_NAME, { keyPath: ["connectionType", "timestamp"] }); objectStore = db.createObjectStore(STATS_STORE_NAME, { keyPath: ["connectionType", "timestamp"] });
objectStore.createIndex("connectionType", "connectionType", { unique: false }); objectStore.createIndex("connectionType", "connectionType", { unique: false });
objectStore.createIndex("timestamp", "timestamp", { unique: false }); objectStore.createIndex("timestamp", "timestamp", { unique: false });
objectStore.createIndex("rxBytes", "rxBytes", { unique: false }); objectStore.createIndex("rxBytes", "rxBytes", { unique: false });
@ -77,9 +78,9 @@ NetworkStatsDB.prototype = {
// to modify the keyPath is mandatory to delete the object store // to modify the keyPath is mandatory to delete the object store
// and create it again. Old data is going to be deleted because the // and create it again. Old data is going to be deleted because the
// networkId for each sample can not be set. // networkId for each sample can not be set.
db.deleteObjectStore(STORE_NAME); db.deleteObjectStore(STATS_STORE_NAME);
objectStore = db.createObjectStore(STORE_NAME, { keyPath: ["appId", "network", "timestamp"] }); objectStore = db.createObjectStore(STATS_STORE_NAME, { keyPath: ["appId", "network", "timestamp"] });
objectStore.createIndex("appId", "appId", { unique: false }); objectStore.createIndex("appId", "appId", { unique: false });
objectStore.createIndex("network", "network", { unique: false }); objectStore.createIndex("network", "network", { unique: false });
objectStore.createIndex("networkType", "networkType", { unique: false }); objectStore.createIndex("networkType", "networkType", { unique: false });
@ -94,7 +95,7 @@ NetworkStatsDB.prototype = {
} }
} else if (currVersion == 3) { } else if (currVersion == 3) {
// Delete redundent indexes (leave "network" only). // Delete redundent indexes (leave "network" only).
objectStore = aTransaction.objectStore(STORE_NAME); objectStore = aTransaction.objectStore(STATS_STORE_NAME);
if (objectStore.indexNames.contains("appId")) { if (objectStore.indexNames.contains("appId")) {
objectStore.deleteIndex("appId"); objectStore.deleteIndex("appId");
} }
@ -120,18 +121,82 @@ NetworkStatsDB.prototype = {
if (DEBUG) { if (DEBUG) {
debug("Deleted redundent indexes for version 4"); debug("Deleted redundent indexes for version 4");
} }
} else if (currVersion == 4) {
// 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(STATS_STORE_NAME);
// 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){
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 });
if (DEBUG) {
debug("Created alarms store for version 5");
}
} }
} }
}, },
importData: function importData(aStats) { importData: function importData(aStats) {
let stats = { appId: aStats.appId, let stats = { appId: aStats.appId,
network: [aStats.networkId, aStats.networkType], network: [aStats.networkId, aStats.networkType],
timestamp: aStats.timestamp, timestamp: aStats.timestamp,
rxBytes: aStats.rxBytes, rxBytes: aStats.rxBytes,
txBytes: aStats.txBytes, txBytes: aStats.txBytes,
rxTotalBytes: aStats.rxTotalBytes, rxSystemBytes: aStats.rxSystemBytes,
txTotalBytes: aStats.txTotalBytes }; txSystemBytes: aStats.txSystemBytes,
rxTotalBytes: aStats.rxTotalBytes,
txTotalBytes: aStats.txTotalBytes };
return stats; return stats;
}, },
@ -160,18 +225,20 @@ NetworkStatsDB.prototype = {
saveStats: function saveStats(aStats, aResultCb) { saveStats: function saveStats(aStats, aResultCb) {
let timestamp = this.normalizeDate(aStats.date); let timestamp = this.normalizeDate(aStats.date);
let stats = { appId: aStats.appId, let stats = { appId: aStats.appId,
networkId: aStats.networkId, networkId: aStats.networkId,
networkType: aStats.networkType, networkType: aStats.networkType,
timestamp: timestamp, timestamp: timestamp,
rxBytes: (aStats.appId == 0) ? 0 : aStats.rxBytes, rxBytes: (aStats.appId == 0) ? 0 : aStats.rxBytes,
txBytes: (aStats.appId == 0) ? 0 : aStats.txBytes, txBytes: (aStats.appId == 0) ? 0 : aStats.txBytes,
rxTotalBytes: (aStats.appId == 0) ? aStats.rxBytes : 0, rxSystemBytes: (aStats.appId == 0) ? aStats.rxBytes : 0,
txTotalBytes: (aStats.appId == 0) ? aStats.txBytes : 0 }; txSystemBytes: (aStats.appId == 0) ? aStats.txBytes : 0,
rxTotalBytes: (aStats.appId == 0) ? aStats.rxBytes : 0,
txTotalBytes: (aStats.appId == 0) ? aStats.txBytes : 0 };
stats = this.importData(stats); stats = this.importData(stats);
this.dbNewTxn("readwrite", function(aTxn, aStore) { this.dbNewTxn(STATS_STORE_NAME, "readwrite", function(aTxn, aStore) {
if (DEBUG) { if (DEBUG) {
debug("Filtered time: " + new Date(timestamp)); debug("Filtered time: " + new Date(timestamp));
debug("New stats: " + JSON.stringify(stats)); debug("New stats: " + JSON.stringify(stats));
@ -241,21 +308,29 @@ NetworkStatsDB.prototype = {
// |txTotalBytes|/|rxTotalBytes| and the last |txTotalBytes|/|rxTotalBytes|. // |txTotalBytes|/|rxTotalBytes| and the last |txTotalBytes|/|rxTotalBytes|.
// Else, the incoming data is per-app data (|newSample.appId| is not 0), // Else, the incoming data is per-app data (|newSample.appId| is not 0),
// the |txBytes|/|rxBytes| is directly the new |txBytes|/|rxBytes|. // the |txBytes|/|rxBytes| is directly the new |txBytes|/|rxBytes|.
let rxDiff = 0;
let txDiff = 0;
if (aNewSample.appId == 0) { if (aNewSample.appId == 0) {
let rxDiff = aNewSample.rxTotalBytes - lastSample.rxTotalBytes; rxDiff = aNewSample.rxSystemBytes - lastSample.rxSystemBytes;
let txDiff = aNewSample.txTotalBytes - lastSample.txTotalBytes; txDiff = aNewSample.txSystemBytes - lastSample.txSystemBytes;
if (rxDiff < 0 || txDiff < 0) { if (rxDiff < 0 || txDiff < 0) {
rxDiff = aNewSample.rxTotalBytes; rxDiff = aNewSample.rxSystemBytes;
txDiff = aNewSample.txTotalBytes; txDiff = aNewSample.txSystemBytes;
} }
aNewSample.rxBytes = rxDiff; aNewSample.rxBytes = rxDiff;
aNewSample.txBytes = txDiff; aNewSample.txBytes = txDiff;
aNewSample.rxTotalBytes = lastSample.rxTotalBytes + rxDiff;
aNewSample.txTotalBytes = lastSample.txTotalBytes + txDiff;
} else {
rxDiff = aNewSample.rxBytes;
txDiff = aNewSample.txBytes;
} }
if (diff == 1) { if (diff == 1) {
// New element. // New element.
// If the incoming data is per-data data, new |rxTotalBytes|/|txTotalBytes| // If the incoming data is per-app data, new |rxTotalBytes|/|txTotalBytes|
// needs to be obtained by adding new |rxBytes|/|txBytes| to last // needs to be obtained by adding new |rxBytes|/|txBytes| to last
// |rxTotalBytes|/|txTotalBytes|. // |rxTotalBytes|/|txTotalBytes|.
if (aNewSample.appId != 0) { if (aNewSample.appId != 0) {
@ -277,13 +352,15 @@ NetworkStatsDB.prototype = {
let data = []; let data = [];
for (let i = diff - 2; i >= 0; i--) { for (let i = diff - 2; i >= 0; i--) {
let time = aNewSample.timestamp - SAMPLE_RATE * (i + 1); let time = aNewSample.timestamp - SAMPLE_RATE * (i + 1);
let sample = { appId: aNewSample.appId, let sample = { appId: aNewSample.appId,
network: aNewSample.network, network: aNewSample.network,
timestamp: time, timestamp: time,
rxBytes: 0, rxBytes: 0,
txBytes: 0, txBytes: 0,
rxTotalBytes: lastSample.rxTotalBytes, rxSystemBytes: lastSample.rxSystemBytes,
txTotalBytes: lastSample.txTotalBytes }; txSystemBytes: lastSample.txSystemBytes,
rxTotalBytes: lastSample.rxTotalBytes,
txTotalBytes: lastSample.txTotalBytes };
data.push(sample); data.push(sample);
} }
@ -293,27 +370,20 @@ NetworkStatsDB.prototype = {
return; return;
} }
if (diff == 0 || diff < 0) { if (diff == 0 || diff < 0) {
// New element received before samplerate period. // New element received before samplerate period. It means that device has
// It means that device has been restarted (or clock / timezone change). // been restarted (or clock / timezone change).
// Update element. // Update element. If diff < 0, clock or timezone changed back. Place data
// in the last sample.
// 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;
lastSample.rxBytes += aNewSample.rxBytes;
lastSample.txBytes += aNewSample.txBytes;
// If incoming data is obtained from netd, last |rxTotalBytes|/|txTotalBytes|
// needs to get updated by replacing the new |rxTotalBytes|/|txTotalBytes|.
if (aNewSample.appId == 0) {
lastSample.rxTotalBytes = aNewSample.rxTotalBytes;
lastSample.txTotalBytes = aNewSample.txTotalBytes;
} else {
// Else, the incoming data is per-app data, old |rxTotalBytes|/
// |txTotalBytes| needs to get updated by adding the new
// |rxBytes|/|txBytes| to last |rxTotalBytes|/|txTotalBytes|.
lastSample.rxTotalBytes += aNewSample.rxBytes;
lastSample.txTotalBytes += aNewSample.txBytes;
}
if (DEBUG) { if (DEBUG) {
debug("Update: " + JSON.stringify(lastSample)); debug("Update: " + JSON.stringify(lastSample));
} }
@ -379,7 +449,7 @@ NetworkStatsDB.prototype = {
let self = this; let self = this;
// Clear and save an empty sample to keep sync with system counters // Clear and save an empty sample to keep sync with system counters
this.dbNewTxn("readwrite", function(aTxn, aStore) { this.dbNewTxn(STATS_STORE_NAME, "readwrite", function(aTxn, aStore) {
let sample = null; let sample = null;
let request = aStore.index("network").openCursor(network, "prev"); let request = aStore.index("network").openCursor(network, "prev");
request.onsuccess = function onsuccess(event) { request.onsuccess = function onsuccess(event) {
@ -431,6 +501,33 @@ NetworkStatsDB.prototype = {
this.clearInterfaceStats(aNetworks[index], callback); this.clearInterfaceStats(aNetworks[index], callback);
}, },
getCurrentStats: function getCurrentStats(aNetwork, aDate, aResultCb) {
if (DEBUG) {
debug("Get current stats for " + JSON.stringify(aNetwork) + " since " + aDate);
}
this.dbNewTxn(STATS_STORE_NAME, "readonly", function(txn, store) {
let request = null;
let network = [aNetwork.id, aNetwork.type];
if (aDate) {
let start = this.normalizeDate(aDate);
let lowerFilter = [0, network, start];
let range = this.dbGlobal.IDBKeyRange.lowerBound(lowerFilter, false);
request = store.openCursor(range);
} else {
request = store.index("network").openCursor(network, "prev");
}
request.onsuccess = function onsuccess(event) {
txn.result = null;
let cursor = event.target.result;
if (cursor) {
txn.result = cursor.value;
}
};
}.bind(this), aResultCb);
},
find: function find(aResultCb, aNetwork, aStart, aEnd, aAppId, aManifestURL) { find: function find(aResultCb, aNetwork, aStart, aEnd, aAppId, aManifestURL) {
let offset = (new Date()).getTimezoneOffset() * 60 * 1000; let offset = (new Date()).getTimezoneOffset() * 60 * 1000;
let start = this.normalizeDate(aStart); let start = this.normalizeDate(aStart);
@ -443,7 +540,7 @@ NetworkStatsDB.prototype = {
debug("End time: " + new Date(end)); debug("End time: " + new Date(end));
} }
this.dbNewTxn("readonly", function(aTxn, aStore) { this.dbNewTxn(STATS_STORE_NAME, "readonly", function(aTxn, aStore) {
let network = [aNetwork.id, aNetwork.type]; let network = [aNetwork.id, aNetwork.type];
let lowerFilter = [aAppId, network, start]; let lowerFilter = [aAppId, network, start];
let upperFilter = [aAppId, network, end]; let upperFilter = [aAppId, network, end];
@ -503,7 +600,7 @@ NetworkStatsDB.prototype = {
}, },
getAvailableNetworks: function getAvailableNetworks(aResultCb) { getAvailableNetworks: function getAvailableNetworks(aResultCb) {
this.dbNewTxn("readonly", function(aTxn, aStore) { this.dbNewTxn(STATS_STORE_NAME, "readonly", function(aTxn, aStore) {
if (!aTxn.result) { if (!aTxn.result) {
aTxn.result = []; aTxn.result = [];
} }
@ -522,7 +619,7 @@ NetworkStatsDB.prototype = {
}, },
isNetworkAvailable: function isNetworkAvailable(aNetwork, aResultCb) { isNetworkAvailable: function isNetworkAvailable(aNetwork, aResultCb) {
this.dbNewTxn("readonly", function(aTxn, aStore) { this.dbNewTxn(STATS_STORE_NAME, "readonly", function(aTxn, aStore) {
if (!aTxn.result) { if (!aTxn.result) {
aTxn.result = false; aTxn.result = false;
} }
@ -546,10 +643,159 @@ NetworkStatsDB.prototype = {
}, },
logAllRecords: function logAllRecords(aResultCb) { logAllRecords: function logAllRecords(aResultCb) {
this.dbNewTxn("readonly", function(aTxn, aStore) { this.dbNewTxn(STATS_STORE_NAME, "readonly", function(aTxn, aStore) {
aStore.mozGetAll().onsuccess = function onsuccess(event) { aStore.mozGetAll().onsuccess = function onsuccess(event) {
aTxn.result = event.target.result; aTxn.result = event.target.result;
}; };
}, aResultCb); }, aResultCb);
}, },
alarmToRecord: function alarmToRecord(aAlarm) {
let record = { networkId: aAlarm.networkId,
threshold: aAlarm.threshold,
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,
threshold: aRecord.threshold,
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) {
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) {
let alarm = { id: cursor.value.id,
networkId: cursor.value.networkId,
threshold: cursor.value.threshold,
data: cursor.value.data };
txn.result.push(alarm);
}
cursor.continue();
}
}, aResultCb);
}
}; };

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

@ -30,7 +30,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
// NetworkStatsData // NetworkStatsData
const nsIClassInfo = Ci.nsIClassInfo; const nsIClassInfo = Ci.nsIClassInfo;
const NETWORKSTATSDATA_CID = Components.ID("{3b16fe17-5583-483a-b486-b64a3243221c}"); const NETWORKSTATSDATA_CID = Components.ID("{3b16fe17-5583-483a-b486-b64a3243221c}");
const nsIDOMMozNetworkStatsData = Components.interfaces.nsIDOMMozNetworkStatsData; const nsIDOMMozNetworkStatsData = Ci.nsIDOMMozNetworkStatsData;
function NetworkStatsData(aData) { function NetworkStatsData(aData) {
this.rxBytes = aData.rxBytes; this.rxBytes = aData.rxBytes;
@ -40,10 +40,10 @@ function NetworkStatsData(aData) {
NetworkStatsData.prototype = { NetworkStatsData.prototype = {
__exposedProps__: { __exposedProps__: {
rxBytes: 'r', rxBytes: 'r',
txBytes: 'r', txBytes: 'r',
date: 'r', date: 'r',
}, },
classID : NETWORKSTATSDATA_CID, classID : NETWORKSTATSDATA_CID,
classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSDATA_CID, classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSDATA_CID,
@ -58,7 +58,7 @@ NetworkStatsData.prototype = {
// NetworkStatsInterface // NetworkStatsInterface
const NETWORKSTATSINTERFACE_CONTRACTID = "@mozilla.org/networkstatsinterface;1"; const NETWORKSTATSINTERFACE_CONTRACTID = "@mozilla.org/networkstatsinterface;1";
const NETWORKSTATSINTERFACE_CID = Components.ID("{f540615b-d803-43ff-8200-2a9d145a5645}"); const NETWORKSTATSINTERFACE_CID = Components.ID("{f540615b-d803-43ff-8200-2a9d145a5645}");
const nsIDOMMozNetworkStatsInterface = Components.interfaces.nsIDOMMozNetworkStatsInterface; const nsIDOMMozNetworkStatsInterface = Ci.nsIDOMMozNetworkStatsInterface;
function NetworkStatsInterface(aNetwork) { function NetworkStatsInterface(aNetwork) {
if (DEBUG) { if (DEBUG) {
@ -70,9 +70,9 @@ function NetworkStatsInterface(aNetwork) {
NetworkStatsInterface.prototype = { NetworkStatsInterface.prototype = {
__exposedProps__: { __exposedProps__: {
id: 'r', id: 'r',
type: 'r', type: 'r',
}, },
classID : NETWORKSTATSINTERFACE_CID, classID : NETWORKSTATSINTERFACE_CID,
classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSINTERFACE_CID, classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSINTERFACE_CID,
@ -87,7 +87,7 @@ NetworkStatsInterface.prototype = {
// NetworkStats // NetworkStats
const NETWORKSTATS_CONTRACTID = "@mozilla.org/networkstats;1"; const NETWORKSTATS_CONTRACTID = "@mozilla.org/networkstats;1";
const NETWORKSTATS_CID = Components.ID("{b6fc4b14-628d-4c99-bf4e-e4ed56916cbe}"); const NETWORKSTATS_CID = Components.ID("{b6fc4b14-628d-4c99-bf4e-e4ed56916cbe}");
const nsIDOMMozNetworkStats = Components.interfaces.nsIDOMMozNetworkStats; const nsIDOMMozNetworkStats = Ci.nsIDOMMozNetworkStats;
function NetworkStats(aWindow, aStats) { function NetworkStats(aWindow, aStats) {
if (DEBUG) { if (DEBUG) {
@ -106,12 +106,12 @@ function NetworkStats(aWindow, aStats) {
NetworkStats.prototype = { NetworkStats.prototype = {
__exposedProps__: { __exposedProps__: {
manifestURL: 'r', manifestURL: 'r',
network: 'r', network: 'r',
start: 'r', start: 'r',
end: 'r', end: 'r',
data: 'r', data: 'r',
}, },
classID : NETWORKSTATS_CID, classID : NETWORKSTATS_CID,
classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATS_CID, classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATS_CID,
@ -125,11 +125,40 @@ NetworkStats.prototype = {
nsIDOMMozNetworkStatsInterface]) nsIDOMMozNetworkStatsInterface])
} }
// NetworkStatsAlarm
const NETWORKSTATSALARM_CID = Components.ID("{063ebeb2-5c6e-47ae-bdcd-5e6ebdc7a68c}");
const nsIDOMMozNetworkStatsAlarm = Ci.nsIDOMMozNetworkStatsAlarm;
function NetworkStatsAlarm(aAlarm) {
this.alarmId = aAlarm.id;
this.network = new NetworkStatsInterface(aAlarm.network);
this.threshold = aAlarm.threshold;
this.data = aAlarm.data;
}
NetworkStatsAlarm.prototype = {
__exposedProps__: {
alarmId: 'r',
network: 'r',
threshold: 'r',
data: 'r',
},
classID : NETWORKSTATSALARM_CID,
classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSALARM_CID,
contractID:"@mozilla.org/networkstatsalarm;1",
classDescription: "NetworkStatsAlarm",
interfaces: [nsIDOMMozNetworkStatsAlarm],
flags: nsIClassInfo.DOM_OBJECT}),
QueryInterface : XPCOMUtils.generateQI([nsIDOMMozNetworkStatsAlarm])
};
// NetworkStatsManager // NetworkStatsManager
const NETWORKSTATSMANAGER_CONTRACTID = "@mozilla.org/networkStatsManager;1"; const NETWORKSTATSMANAGER_CONTRACTID = "@mozilla.org/networkStatsManager;1";
const NETWORKSTATSMANAGER_CID = Components.ID("{5f033d31-c9a2-4e2d-83aa-6a807f1e0c11}"); const NETWORKSTATSMANAGER_CID = Components.ID("{50d109b8-0d7f-4208-81fe-5f07a759f159}");
const nsIDOMMozNetworkStatsManager = Components.interfaces.nsIDOMMozNetworkStatsManager; const nsIDOMMozNetworkStatsManager = Ci.nsIDOMMozNetworkStatsManager;
function NetworkStatsManager() { function NetworkStatsManager() {
if (DEBUG) { if (DEBUG) {
@ -189,6 +218,52 @@ NetworkStatsManager.prototype = {
return request; return request;
}, },
addAlarm: function addAlarm(aNetwork, aThreshold, aOptions) {
this.checkPrivileges();
if (!aOptions) {
aOptions = Object.create(null);
}
let request = this.createRequest();
cpmm.sendAsyncMessage("NetworkStats:SetAlarm",
{id: this.getRequestId(request),
data: {network: aNetwork,
threshold: aThreshold,
startTime: aOptions.startTime,
data: aOptions.data,
manifestURL: this.manifestURL,
pageURL: this.pageURL}});
return request;
},
getAllAlarms: function getAllAlarms(aNetwork) {
this.checkPrivileges();
let request = this.createRequest();
cpmm.sendAsyncMessage("NetworkStats:GetAlarms",
{id: this.getRequestId(request),
data: {network: aNetwork,
manifestURL: this.manifestURL}});
return request;
},
removeAlarms: function removeAlarms(aAlarmId) {
this.checkPrivileges();
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() { getAvailableNetworks: function getAvailableNetworks() {
this.checkPrivileges(); this.checkPrivileges();
@ -212,8 +287,8 @@ NetworkStatsManager.prototype = {
if (DEBUG) { if (DEBUG) {
debug("NetworkStatsmanager::receiveMessage: " + aMessage.name); debug("NetworkStatsmanager::receiveMessage: " + aMessage.name);
} }
let msg = aMessage.json;
let msg = aMessage.json;
let req = this.takeRequest(msg.id); let req = this.takeRequest(msg.id);
if (!req) { if (!req) {
if (DEBUG) { if (DEBUG) {
@ -260,6 +335,30 @@ NetworkStatsManager.prototype = {
Services.DOMRequest.fireSuccess(req, true); Services.DOMRequest.fireSuccess(req, true);
break; 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 = Cu.createArrayIn(this._window);
for (let i = 0; i < msg.result.length; i++) {
alarms.push(new NetworkStatsAlarm(msg.result[i]));
}
Services.DOMRequest.fireSuccess(req, alarms);
break;
default: default:
if (DEBUG) { if (DEBUG) {
debug("Wrong message: " + aMessage.name); debug("Wrong message: " + aMessage.name);
@ -293,7 +392,21 @@ NetworkStatsManager.prototype = {
this.initDOMRequestHelper(aWindow, ["NetworkStats:Get:Return", this.initDOMRequestHelper(aWindow, ["NetworkStats:Get:Return",
"NetworkStats:GetAvailableNetworks:Return", "NetworkStats:GetAvailableNetworks:Return",
"NetworkStats:Clear:Return", "NetworkStats:Clear:Return",
"NetworkStats:ClearAll: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;
}
}, },
// Called from DOMRequestIpcHelper // Called from DOMRequestIpcHelper
@ -316,7 +429,8 @@ NetworkStatsManager.prototype = {
flags: nsIClassInfo.DOM_OBJECT}) flags: nsIClassInfo.DOM_OBJECT})
} }
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkStatsData, this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkStatsAlarm,
NetworkStatsData,
NetworkStatsInterface, NetworkStatsInterface,
NetworkStats, NetworkStats,
NetworkStatsManager]); NetworkStatsManager]);

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

@ -7,6 +7,9 @@ contract @mozilla.org/networkStats;1 {b6fc4b14-628d-4c99-bf4e-e4ed56916cbe}
component {f540615b-d803-43ff-8200-2a9d145a5645} NetworkStatsManager.js component {f540615b-d803-43ff-8200-2a9d145a5645} NetworkStatsManager.js
contract @mozilla.org/networkstatsinterface;1 {f540615b-d803-43ff-8200-2a9d145a5645} contract @mozilla.org/networkstatsinterface;1 {f540615b-d803-43ff-8200-2a9d145a5645}
component {5f033d31-c9a2-4e2d-83aa-6a807f1e0c11} NetworkStatsManager.js component {063ebeb2-5c6e-47ae-bdcd-5e6ebdc7a68c} NetworkStatsManager.js
contract @mozilla.org/networkStatsManager;1 {5f033d31-c9a2-4e2d-83aa-6a807f1e0c11} contract @mozilla.org/networkstatsalarm;1 {063ebeb2-5c6e-47ae-bdcd-5e6ebdc7a68c}
component {50d109b8-0d7f-4208-81fe-5f07a759f159} NetworkStatsManager.js
contract @mozilla.org/networkStatsManager;1 {50d109b8-0d7f-4208-81fe-5f07a759f159}
category JavaScript-navigator-property mozNetworkStats @mozilla.org/networkStatsManager;1 category JavaScript-navigator-property mozNetworkStats @mozilla.org/networkStatsManager;1

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

@ -22,6 +22,8 @@ Cu.import("resource://gre/modules/NetworkStatsDB.jsm");
const NET_NETWORKSTATSSERVICE_CONTRACTID = "@mozilla.org/network/netstatsservice;1"; const NET_NETWORKSTATSSERVICE_CONTRACTID = "@mozilla.org/network/netstatsservice;1";
const NET_NETWORKSTATSSERVICE_CID = Components.ID("{18725604-e9ac-488a-8aa0-2471e7f6c0a4}"); const NET_NETWORKSTATSSERVICE_CID = Components.ID("{18725604-e9ac-488a-8aa0-2471e7f6c0a4}");
const TOPIC_BANDWIDTH_CONTROL = "netd-bandwidth-control"
const TOPIC_INTERFACE_REGISTERED = "network-interface-registered"; const TOPIC_INTERFACE_REGISTERED = "network-interface-registered";
const TOPIC_INTERFACE_UNREGISTERED = "network-interface-unregistered"; const TOPIC_INTERFACE_UNREGISTERED = "network-interface-unregistered";
const NET_TYPE_WIFI = Ci.nsINetworkInterface.NETWORK_TYPE_WIFI; const NET_TYPE_WIFI = Ci.nsINetworkInterface.NETWORK_TYPE_WIFI;
@ -50,6 +52,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
"@mozilla.org/settingsService;1", "@mozilla.org/settingsService;1",
"nsISettingsService"); "nsISettingsService");
XPCOMUtils.defineLazyServiceGetter(this, "messenger",
"@mozilla.org/system-message-internal;1",
"nsISystemMessagesInternal");
this.NetworkStatsService = { this.NetworkStatsService = {
init: function() { init: function() {
debug("Service started"); debug("Service started");
@ -57,6 +63,7 @@ this.NetworkStatsService = {
Services.obs.addObserver(this, "xpcom-shutdown", false); Services.obs.addObserver(this, "xpcom-shutdown", false);
Services.obs.addObserver(this, TOPIC_INTERFACE_REGISTERED, false); Services.obs.addObserver(this, TOPIC_INTERFACE_REGISTERED, false);
Services.obs.addObserver(this, TOPIC_INTERFACE_UNREGISTERED, false); Services.obs.addObserver(this, TOPIC_INTERFACE_UNREGISTERED, false);
Services.obs.addObserver(this, TOPIC_BANDWIDTH_CONTROL, false);
Services.obs.addObserver(this, "profile-after-change", false); Services.obs.addObserver(this, "profile-after-change", false);
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
@ -87,6 +94,9 @@ this.NetworkStatsService = {
this.messages = ["NetworkStats:Get", this.messages = ["NetworkStats:Get",
"NetworkStats:Clear", "NetworkStats:Clear",
"NetworkStats:ClearAll", "NetworkStats:ClearAll",
"NetworkStats:SetAlarm",
"NetworkStats:GetAlarms",
"NetworkStats:RemoveAlarms",
"NetworkStats:GetAvailableNetworks", "NetworkStats:GetAvailableNetworks",
"NetworkStats:SampleRate", "NetworkStats:SampleRate",
"NetworkStats:MaxStorageAge"]; "NetworkStats:MaxStorageAge"];
@ -107,6 +117,9 @@ this.NetworkStatsService = {
this.updateQueue = []; this.updateQueue = [];
this.isQueueRunning = false; this.isQueueRunning = false;
this._currentAlarms = {};
this.initAlarms();
}, },
receiveMessage: function(aMessage) { receiveMessage: function(aMessage) {
@ -129,6 +142,15 @@ this.NetworkStatsService = {
case "NetworkStats:ClearAll": case "NetworkStats:ClearAll":
this.clearDB(mm, msg); this.clearDB(mm, msg);
break; 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": case "NetworkStats:GetAvailableNetworks":
this.getAvailableNetworks(mm, msg); this.getAvailableNetworks(mm, msg);
break; break;
@ -146,7 +168,7 @@ this.NetworkStatsService = {
case TOPIC_INTERFACE_REGISTERED: case TOPIC_INTERFACE_REGISTERED:
case TOPIC_INTERFACE_UNREGISTERED: case TOPIC_INTERFACE_UNREGISTERED:
// If new interface is registered (notified from NetworkManager), // If new interface is registered (notified from NetworkService),
// the stats are updated for the new interface without waiting to // the stats are updated for the new interface without waiting to
// complete the updating period. // complete the updating period.
@ -158,9 +180,27 @@ this.NetworkStatsService = {
break; break;
} }
this._updateCurrentAlarm(netId);
debug("NetId: " + netId); debug("NetId: " + netId);
this.updateStats(netId); this.updateStats(netId);
break; 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": case "xpcom-shutdown":
debug("Service shutdown"); debug("Service shutdown");
@ -172,6 +212,7 @@ this.NetworkStatsService = {
Services.obs.removeObserver(this, "profile-after-change"); Services.obs.removeObserver(this, "profile-after-change");
Services.obs.removeObserver(this, TOPIC_INTERFACE_REGISTERED); Services.obs.removeObserver(this, TOPIC_INTERFACE_REGISTERED);
Services.obs.removeObserver(this, TOPIC_INTERFACE_UNREGISTERED); Services.obs.removeObserver(this, TOPIC_INTERFACE_UNREGISTERED);
Services.obs.removeObserver(this, TOPIC_BANDWIDTH_CONTROL);
this.timer.cancel(); this.timer.cancel();
this.timer = null; this.timer = null;
@ -266,6 +307,25 @@ this.NetworkStatsService = {
}); });
}, },
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. * Function called from manager to get stats from database.
* In order to return updated stats, first is performed a call to * In order to return updated stats, first is performed a call to
@ -482,8 +542,8 @@ this.NetworkStatsService = {
} }
} else { } else {
// The caller is a function that has pushed new elements to the queue, // 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 // if isQueueRunning is false it means there is no processing currently
// done, so start. // being done, so start.
if (this.isQueueRunning) { if (this.isQueueRunning) {
if(this.updateQueue.length > 1) { if(this.updateQueue.length > 1) {
return; return;
@ -515,7 +575,7 @@ this.NetworkStatsService = {
let interfaceName = this._networks[aNetId].interfaceName; let interfaceName = this._networks[aNetId].interfaceName;
debug("Update stats for " + interfaceName); debug("Update stats for " + interfaceName);
// Request stats to NetworkManager, which will get stats from netd, passing // Request stats to NetworkService, which will get stats from netd, passing
// 'networkStatsAvailable' as a callback. // 'networkStatsAvailable' as a callback.
if (interfaceName) { if (interfaceName) {
networkService.getNetworkInterfaceStats(interfaceName, networkService.getNetworkInterfaceStats(interfaceName,
@ -706,6 +766,262 @@ this.NetworkStatsService = {
debug(JSON.stringify(aResult)); debug(JSON.stringify(aResult));
}); });
}, },
getAlarms: function getAlarms(mm, msg) {
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;
}
}
let self = this;
this._db.getAlarms(netId, manifestURL, 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.threshold,
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 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) {
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
{ id: msg.id, error: error, result: null });
return;
}
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);
}
});
});
});
},
_setAlarm: function _setAlarm(aAlarm, aCallback) {
let currentAlarm = this._currentAlarms[aAlarm.networkId];
if (Object.getOwnPropertyNames(currentAlarm).length !== 0 &&
aAlarm.absoluteThreshold > currentAlarm.alarm.absoluteThreshold) {
aCallback(null, true);
return;
}
let self = this;
this._updateThreshold(aAlarm, function onUpdate(aError, aThreshold) {
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,
aThreshold.systemThreshold,
callback);
return;
}
aCallback(null, true);
});
},
_updateThreshold: function _updateThreshold(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 offset = aAlarm.threshold - result.rxTotalBytes - result.txTotalBytes;
// Alarm set to a threshold lower than current rx/tx bytes.
if (offset <= 0) {
aCallback("InvalidStateError", null);
return;
}
let threshold = {
systemThreshold: result.rxSystemBytes + result.txSystemBytes + offset,
absoluteThreshold: result.rxTotalBytes + result.txTotalBytes + offset
};
aCallback(null, threshold);
});
});
},
_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.threshold,
"data": aAlarm.data };
messenger.sendMessage("networkstats-alarm", alarm, pageURI, manifestURI);
}
}; };
NetworkStatsService.init(); NetworkStatsService.init();

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

@ -15,5 +15,6 @@ MOCHITEST_FILES = \
test_networkstats_disabled.html \ test_networkstats_disabled.html \
test_networkstats_enabled_no_perm.html \ test_networkstats_enabled_no_perm.html \
test_networkstats_enabled_perm.html \ test_networkstats_enabled_perm.html \
test_networkstats_alarms.html \
$(NULL) $(NULL)
endif endif

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

@ -0,0 +1,175 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for NetworkStats alarms</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content">
</div>
<pre id="test">
<script type="application/javascript">
function test() {
ok(true, "Checking if no alarms are set.");
req = navigator.mozNetworkStats.getAllAlarms();
req.onsuccess = function () {
ok(true, "Succeeded to get alarms.");
ok(Array.isArray(req.result) && req.result.length == 0,
"There are no alarms set.");
next();
};
req.onerror = function () {
ok(false, "getAllAlarms() shouldn't fail!");
}
}
var req;
var index = -1;
var wifi = {'type': 0, 'id': '0'};
var mobile = {'type': 1, 'id': '1'};
var steps = [
function () {
ok(true, "Calling getAllAlarms() with invalid network.");
req = navigator.mozNetworkStats.getAllAlarms(mobile);
req.onsuccess = function () {
ok(false, "getAllAlarms() shouldn't succeed!");
};
req.onerror = function () {
ok(req.error.name == "InvalidInterface", "Get InvalidInterface error");
next();
}
},
function () {
ok(true, "Calling addAlarm() with invalid network or parameters.");
try {
navigator.mozNetworkStats.addAlarm();
} catch(ex) {
ok(ex.result == SpecialPowers.Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS,
"addAlarm() throws NS_ERROR_XPC_NOT_ENOUGH_ARGS exception when no parameters");
}
try {
navigator.mozNetworkStats.addAlarm(100000);
} catch(ex) {
ok(ex.result == SpecialPowers.Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS,
"addAlarm() throws NS_ERROR_XPC_NOT_ENOUGH_ARGS exception when no network");
}
try {
navigator.mozNetworkStats.addAlarm(wifi);
} catch(ex) {
ok(ex.result == SpecialPowers.Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS,
"addAlarm() throws NS_ERROR_XPC_NOT_ENOUGH_ARGS exception when no threshold");
}
req = navigator.mozNetworkStats.addAlarm(mobile, -100000);
req.onsuccess = function () {
ok(false, "addAlarm() shouldn't succeed with negative threshold.");
};
req.onerror = function () {
ok(req.error.name == "InvalidThresholdValue", "Get InvalidThresholdValue error");
next();
}
},
function () {
ok(true, "Calling addAlarm()");
req = navigator.mozNetworkStats.addAlarm(wifi, 1000000);
req.onsuccess = function () {
ok(true, "Succeeded to add alarm. AlarmId: " + req.result);
next();
};
req.onerror = function () {
ok(false, "addAlarm() shouldn't fail.");
};
},
function () {
ok(true, "Calling getAllAlarms()");
req = navigator.mozNetworkStats.getAllAlarms(wifi);
req.onsuccess = function () {
ok(req.result.length == 1, "Only one alarm");
ok(req.result[0].alarmId == 1, "Get correct alarmId");
next();
};
req.onerror = function () {
ok(false, "getAllAlarms() shouldn't fail.");
}
},
function () {
ok(true, "Calling removeAlarms() to remove alarms.");
req = navigator.mozNetworkStats.removeAlarms();
req.onsuccess = function () {
ok(req.result, "Succeeded to remove alarms.");
next();
};
req.onerror = function () {
ok(false, "removeAlarms() shouldn't fail.");
}
},
function () {
ok(true, "Checking if all alarms are removed.");
req = navigator.mozNetworkStats.getAllAlarms();
req.onsuccess = function () {
ok(Array.isArray(req.result) && req.result.length == 0,
"Succeeded to remove all alarms.");
next();
};
req.onerror = function () {
ok(false, "getAllAlarms() shouldn't fail.");
}
},
function () {
ok(true, "all done!\n");
SpecialPowers.removePermission("networkstats-manage", document);
SimpleTest.finish();
return;
}
];
function next() {
index += 1;
if (index >= steps.length) {
ok(false, "Shouldn't get here!");
return;
}
try {
steps[index]();
} catch(ex) {
ok(false, "Caught exception", ex);
}
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.addPermission("networkstats-manage", true, document);
SpecialPowers.pushPrefEnv({'set': [["dom.mozNetworkStats.enabled", true]]}, test);
</script>
</pre>
</body>
</html>

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

@ -13,10 +13,8 @@
<script type="application/javascript"> <script type="application/javascript">
function test() { function test() {
ok('mozNetworkStats' in navigator, "navigator.mozMozNetworkStats should exist"); netStats = window.navigator.mozNetworkStats;
ok(navigator.mozNetworkStats, "navigator.mozNetworkStats returns an object"); ok(netStats, "mozNetworkStats exists");
netStats = navigator.mozNetworkStats;
// Test IDL attributes // Test IDL attributes
ok('sampleRate' in netStats, ok('sampleRate' in netStats,

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

@ -7,12 +7,28 @@ Cu.import("resource://gre/modules/NetworkStatsDB.jsm");
const netStatsDb = new NetworkStatsDB(); const netStatsDb = new NetworkStatsDB();
function clearWholeDB(callback) { function clearStore(store, callback) {
netStatsDb.dbNewTxn("readwrite", function(aTxn, aStore) { netStatsDb.dbNewTxn(store, "readwrite", function(aTxn, aStore) {
aStore.delete(); aStore.openCursor().onsuccess = function (event) {
let cursor = event.target.result;
if (cursor){
cursor.delete();
cursor.continue();
}
};
}, callback); }, callback);
} }
add_test(function prepareDatabase() {
// Clear whole database to avoid starting tests with unknown state
// due to the previous tests.
clearStore('net_stats', function() {
clearStore('net_alarm', function() {
run_next_test();
});
});
});
function filterTimestamp(date) { function filterTimestamp(date) {
var sampleRate = netStatsDb.sampleRate; var sampleRate = netStatsDb.sampleRate;
var offset = date.getTimezoneOffset() * 60 * 1000; var offset = date.getTimezoneOffset() * 60 * 1000;
@ -122,15 +138,17 @@ add_test(function test_clear_interface() {
add_test(function test_internalSaveStats_singleSample() { add_test(function test_internalSaveStats_singleSample() {
var networks = getNetworks(); var networks = getNetworks();
var stats = { appId: 0, var stats = { appId: 0,
network: [networks[0].id, networks[0].type], network: [networks[0].id, networks[0].type],
timestamp: Date.now(), timestamp: Date.now(),
rxBytes: 0, rxBytes: 0,
txBytes: 0, txBytes: 0,
rxTotalBytes: 1234, rxSystemBytes: 1234,
txTotalBytes: 1234 }; txSystemBytes: 1234,
rxTotalBytes: 1234,
txTotalBytes: 1234 };
netStatsDb.dbNewTxn("readwrite", function(txn, store) { netStatsDb.dbNewTxn("net_stats", "readwrite", function(txn, store) {
netStatsDb._saveStats(txn, store, stats); netStatsDb._saveStats(txn, store, stats);
}, function(error, result) { }, function(error, result) {
do_check_eq(error, null); do_check_eq(error, null);
@ -143,6 +161,8 @@ add_test(function test_internalSaveStats_singleSample() {
do_check_eq(result[0].timestamp, stats.timestamp); do_check_eq(result[0].timestamp, stats.timestamp);
do_check_eq(result[0].rxBytes, stats.rxBytes); do_check_eq(result[0].rxBytes, stats.rxBytes);
do_check_eq(result[0].txBytes, stats.txBytes); do_check_eq(result[0].txBytes, stats.txBytes);
do_check_eq(result[0].rxSystemBytes, stats.rxSystemBytes);
do_check_eq(result[0].txSystemBytes, stats.txSystemBytes);
do_check_eq(result[0].rxTotalBytes, stats.rxTotalBytes); do_check_eq(result[0].rxTotalBytes, stats.rxTotalBytes);
do_check_eq(result[0].txTotalBytes, stats.txTotalBytes); do_check_eq(result[0].txTotalBytes, stats.txTotalBytes);
run_next_test(); run_next_test();
@ -161,16 +181,18 @@ add_test(function test_internalSaveStats_arraySamples() {
var samples = 2; var samples = 2;
var stats = []; var stats = [];
for (var i = 0; i < samples; i++) { for (var i = 0; i < samples; i++) {
stats.push({ appId: 0, stats.push({ appId: 0,
network: network, network: network,
timestamp: Date.now() + (10 * i), timestamp: Date.now() + (10 * i),
rxBytes: 0, rxBytes: 0,
txBytes: 0, txBytes: 0,
rxTotalBytes: 1234, rxSystemBytes: 1234,
txTotalBytes: 1234 }); txSystemBytes: 1234,
rxTotalBytes: 1234,
txTotalBytes: 1234 });
} }
netStatsDb.dbNewTxn("readwrite", function(txn, store) { netStatsDb.dbNewTxn("net_stats", "readwrite", function(txn, store) {
netStatsDb._saveStats(txn, store, stats); netStatsDb._saveStats(txn, store, stats);
}, function(error, result) { }, function(error, result) {
do_check_eq(error, null); do_check_eq(error, null);
@ -182,7 +204,6 @@ add_test(function test_internalSaveStats_arraySamples() {
// an empty sample to keep totalBytes synchronized with netd counters // an empty sample to keep totalBytes synchronized with netd counters
result.shift(); result.shift();
do_check_eq(result.length, samples); do_check_eq(result.length, samples);
var success = true; var success = true;
for (var i = 1; i < samples; i++) { for (var i = 1; i < samples; i++) {
if (result[i].appId != stats[i].appId || if (result[i].appId != stats[i].appId ||
@ -190,6 +211,8 @@ add_test(function test_internalSaveStats_arraySamples() {
result[i].timestamp != stats[i].timestamp || result[i].timestamp != stats[i].timestamp ||
result[i].rxBytes != stats[i].rxBytes || result[i].rxBytes != stats[i].rxBytes ||
result[i].txBytes != stats[i].txBytes || result[i].txBytes != stats[i].txBytes ||
result[i].rxSystemBytes != stats[i].rxSystemBytes ||
result[i].txSystemBytes != stats[i].txSystemBytes ||
result[i].rxTotalBytes != stats[i].rxTotalBytes || result[i].rxTotalBytes != stats[i].rxTotalBytes ||
result[i].txTotalBytes != stats[i].txTotalBytes) { result[i].txTotalBytes != stats[i].txTotalBytes) {
success = false; success = false;
@ -213,18 +236,20 @@ add_test(function test_internalRemoveOldStats() {
var samples = 10; var samples = 10;
var stats = []; var stats = [];
for (var i = 0; i < samples - 1; i++) { for (var i = 0; i < samples - 1; i++) {
stats.push({ appId: 0, stats.push({ appId: 0,
network: network, timestamp: Date.now() + (10 * i), network: network, timestamp: Date.now() + (10 * i),
rxBytes: 0, txBytes: 0, rxBytes: 0, txBytes: 0,
rxTotalBytes: 1234, txTotalBytes: 1234 }); rxSystemBytes: 1234, txSystemBytes: 1234,
rxTotalBytes: 1234, txTotalBytes: 1234 });
} }
stats.push({ appId: 0, stats.push({ appId: 0,
network: network, timestamp: Date.now() + (10 * samples), network: network, timestamp: Date.now() + (10 * samples),
rxBytes: 0, txBytes: 0, rxBytes: 0, txBytes: 0,
rxTotalBytes: 1234, txTotalBytes: 1234 }); rxSystemBytes: 1234, txSystemBytes: 1234,
rxTotalBytes: 1234, txTotalBytes: 1234 });
netStatsDb.dbNewTxn("readwrite", function(txn, store) { netStatsDb.dbNewTxn("net_stats", "readwrite", function(txn, store) {
netStatsDb._saveStats(txn, store, stats); netStatsDb._saveStats(txn, store, stats);
var date = stats[stats.length - 1].timestamp var date = stats[stats.length - 1].timestamp
+ (netStatsDb.sampleRate * netStatsDb.maxStorageSamples - 1) - 1; + (netStatsDb.sampleRate * netStatsDb.maxStorageSamples - 1) - 1;
@ -245,10 +270,10 @@ add_test(function test_internalRemoveOldStats() {
function processSamplesDiff(networks, lastStat, newStat, callback) { function processSamplesDiff(networks, lastStat, newStat, callback) {
netStatsDb.clearStats(networks, function (error, result){ netStatsDb.clearStats(networks, function (error, result){
do_check_eq(error, null); do_check_eq(error, null);
netStatsDb.dbNewTxn("readwrite", function(txn, store) { netStatsDb.dbNewTxn("net_stats", "readwrite", function(txn, store) {
netStatsDb._saveStats(txn, store, lastStat); netStatsDb._saveStats(txn, store, lastStat);
}, function(error, result) { }, function(error, result) {
netStatsDb.dbNewTxn("readwrite", function(txn, store) { netStatsDb.dbNewTxn("net_stats", "readwrite", function(txn, store) {
let request = store.index("network").openCursor(newStat.network, "prev"); let request = store.index("network").openCursor(newStat.network, "prev");
request.onsuccess = function onsuccess(event) { request.onsuccess = function onsuccess(event) {
let cursor = event.target.result; let cursor = event.target.result;
@ -273,25 +298,29 @@ add_test(function test_processSamplesDiffSameSample() {
var sampleRate = netStatsDb.sampleRate; var sampleRate = netStatsDb.sampleRate;
var date = filterTimestamp(new Date()); var date = filterTimestamp(new Date());
var lastStat = { appId: 0, var lastStat = { appId: 0,
network: network, timestamp: date, network: network, timestamp: date,
rxBytes: 0, txBytes: 0, rxBytes: 0, txBytes: 0,
rxTotalBytes: 1234, txTotalBytes: 1234 }; rxSystemBytes: 1234, txSystemBytes: 1234,
rxTotalBytes: 2234, txTotalBytes: 2234 };
var newStat = { appId: 0, var newStat = { appId: 0,
network: network, timestamp: date, network: network, timestamp: date,
rxBytes: 0, txBytes: 0, rxBytes: 0, txBytes: 0,
rxTotalBytes: 2234, txTotalBytes: 2234 }; rxSystemBytes: 2234, txSystemBytes: 2234,
rxTotalBytes: 2234, txTotalBytes: 2234 };
processSamplesDiff(networks, lastStat, newStat, function(result) { processSamplesDiff(networks, lastStat, newStat, function(result) {
do_check_eq(result.length, 1); do_check_eq(result.length, 1);
do_check_eq(result[0].appId, newStat.appId); do_check_eq(result[0].appId, newStat.appId);
do_check_true(compareNetworks(result[0].network, newStat.network)); do_check_true(compareNetworks(result[0].network, newStat.network));
do_check_eq(result[0].timestamp, newStat.timestamp); do_check_eq(result[0].timestamp, newStat.timestamp);
do_check_eq(result[0].rxBytes, newStat.rxTotalBytes - lastStat.rxTotalBytes); do_check_eq(result[0].rxBytes, newStat.rxSystemBytes - lastStat.rxSystemBytes);
do_check_eq(result[0].txBytes, newStat.txTotalBytes - lastStat.txTotalBytes); do_check_eq(result[0].txBytes, newStat.txSystemBytes - lastStat.txSystemBytes);
do_check_eq(result[0].rxTotalBytes, newStat.rxTotalBytes); do_check_eq(result[0].rxTotalBytes, lastStat.rxTotalBytes + newStat.rxSystemBytes - lastStat.rxSystemBytes);
do_check_eq(result[0].txTotalBytes, newStat.txTotalBytes); do_check_eq(result[0].txTotalBytes, lastStat.txTotalBytes + newStat.txSystemBytes - lastStat.txSystemBytes);
do_check_eq(result[0].rxSystemBytes, newStat.rxSystemBytes);
do_check_eq(result[0].txSystemBytes, newStat.txSystemBytes);
run_next_test(); run_next_test();
}); });
}); });
@ -303,25 +332,29 @@ add_test(function test_processSamplesDiffNextSample() {
var sampleRate = netStatsDb.sampleRate; var sampleRate = netStatsDb.sampleRate;
var date = filterTimestamp(new Date()); var date = filterTimestamp(new Date());
var lastStat = { appId: 0, var lastStat = { appId: 0,
network: network, timestamp: date, network: network, timestamp: date,
rxBytes: 0, txBytes: 0, rxBytes: 0, txBytes: 0,
rxTotalBytes: 1234, txTotalBytes: 1234 }; rxSystemBytes: 1234, txSystemBytes: 1234,
rxTotalBytes: 2234, txTotalBytes: 2234 };
var newStat = { appId: 0, var newStat = { appId: 0,
network: network, timestamp: date + sampleRate, network: network, timestamp: date + sampleRate,
rxBytes: 0, txBytes: 0, rxBytes: 0, txBytes: 0,
rxTotalBytes: 500, txTotalBytes: 500 }; rxSystemBytes: 1734, txSystemBytes: 1734,
rxTotalBytes: 0, txTotalBytes: 0 };
processSamplesDiff(networks, lastStat, newStat, function(result) { processSamplesDiff(networks, lastStat, newStat, function(result) {
do_check_eq(result.length, 2); do_check_eq(result.length, 2);
do_check_eq(result[1].appId, newStat.appId); do_check_eq(result[1].appId, newStat.appId);
do_check_true(compareNetworks(result[1].network, newStat.network)); do_check_true(compareNetworks(result[1].network, newStat.network));
do_check_eq(result[1].timestamp, newStat.timestamp); do_check_eq(result[1].timestamp, newStat.timestamp);
do_check_eq(result[1].rxBytes, newStat.rxTotalBytes); do_check_eq(result[1].rxBytes, newStat.rxSystemBytes - lastStat.rxSystemBytes);
do_check_eq(result[1].txBytes, newStat.txTotalBytes); do_check_eq(result[1].txBytes, newStat.txSystemBytes - lastStat.txSystemBytes);
do_check_eq(result[1].rxTotalBytes, newStat.rxTotalBytes); do_check_eq(result[1].rxSystemBytes, newStat.rxSystemBytes);
do_check_eq(result[1].txTotalBytes, newStat.txTotalBytes); do_check_eq(result[1].txSystemBytes, newStat.txSystemBytes);
do_check_eq(result[1].rxTotalBytes, lastStat.rxTotalBytes + newStat.rxSystemBytes - lastStat.rxSystemBytes);
do_check_eq(result[1].txTotalBytes, lastStat.txTotalBytes + newStat.txSystemBytes - lastStat.txSystemBytes);
run_next_test(); run_next_test();
}); });
}); });
@ -332,15 +365,17 @@ add_test(function test_processSamplesDiffSamplesLost() {
var samples = 5; var samples = 5;
var sampleRate = netStatsDb.sampleRate; var sampleRate = netStatsDb.sampleRate;
var date = filterTimestamp(new Date()); var date = filterTimestamp(new Date());
var lastStat = { appId: 0, var lastStat = { appId: 0,
network: network, timestamp: date, network: network, timestamp: date,
rxBytes: 0, txBytes: 0, rxBytes: 0, txBytes: 0,
rxTotalBytes: 1234, txTotalBytes: 1234 }; rxSystemBytes: 1234, txSystemBytes: 1234,
rxTotalBytes: 2234, txTotalBytes: 2234};
var newStat = { appId: 0, var newStat = { appId: 0,
network: network, timestamp: date + (sampleRate * samples), network: network, timestamp: date + (sampleRate * samples),
rxBytes: 0, txBytes: 0, rxBytes: 0, txBytes: 0,
rxTotalBytes: 2234, txTotalBytes: 2234 }; rxSystemBytes: 2234, txSystemBytes: 2234,
rxTotalBytes: 0, txTotalBytes: 0 };
processSamplesDiff(networks, lastStat, newStat, function(result) { processSamplesDiff(networks, lastStat, newStat, function(result) {
do_check_eq(result.length, samples + 1); do_check_eq(result.length, samples + 1);
@ -349,8 +384,10 @@ add_test(function test_processSamplesDiffSamplesLost() {
do_check_eq(result[samples].timestamp, newStat.timestamp); do_check_eq(result[samples].timestamp, newStat.timestamp);
do_check_eq(result[samples].rxBytes, newStat.rxTotalBytes - lastStat.rxTotalBytes); do_check_eq(result[samples].rxBytes, newStat.rxTotalBytes - lastStat.rxTotalBytes);
do_check_eq(result[samples].txBytes, newStat.txTotalBytes - lastStat.txTotalBytes); do_check_eq(result[samples].txBytes, newStat.txTotalBytes - lastStat.txTotalBytes);
do_check_eq(result[samples].rxTotalBytes, newStat.rxTotalBytes); do_check_eq(result[samples].rxSystemBytes, newStat.rxSystemBytes);
do_check_eq(result[samples].txTotalBytes, newStat.txTotalBytes); do_check_eq(result[samples].txSystemBytes, newStat.txSystemBytes);
do_check_eq(result[samples].rxTotalBytes, lastStat.rxTotalBytes + newStat.rxSystemBytes - lastStat.rxSystemBytes);
do_check_eq(result[samples].txTotalBytes, lastStat.txTotalBytes + newStat.txSystemBytes - lastStat.txSystemBytes);
run_next_test(); run_next_test();
}); });
}); });
@ -366,8 +403,7 @@ add_test(function test_saveStats() {
rxBytes: 2234, rxBytes: 2234,
txBytes: 2234}; txBytes: 2234};
netStatsDb.clearStats(networks, function (error, result) { clearStore('net_stats', function() {
do_check_eq(error, null);
netStatsDb.saveStats(stats, function(error, result) { netStatsDb.saveStats(stats, function(error, result) {
do_check_eq(error, null); do_check_eq(error, null);
netStatsDb.logAllRecords(function(error, result) { netStatsDb.logAllRecords(function(error, result) {
@ -377,8 +413,10 @@ add_test(function test_saveStats() {
do_check_true(compareNetworks(result[0].network, network)); do_check_true(compareNetworks(result[0].network, network));
let timestamp = filterTimestamp(stats.date); let timestamp = filterTimestamp(stats.date);
do_check_eq(result[0].timestamp, timestamp); do_check_eq(result[0].timestamp, timestamp);
do_check_eq(result[0].rxBytes, 0); do_check_eq(result[0].rxBytes, stats.rxBytes);
do_check_eq(result[0].txBytes, 0); do_check_eq(result[0].txBytes, stats.txBytes);
do_check_eq(result[0].rxSystemBytes, stats.rxBytes);
do_check_eq(result[0].txSystemBytes, stats.txBytes);
do_check_eq(result[0].rxTotalBytes, stats.rxBytes); do_check_eq(result[0].rxTotalBytes, stats.rxBytes);
do_check_eq(result[0].txTotalBytes, stats.txBytes); do_check_eq(result[0].txTotalBytes, stats.txBytes);
run_next_test(); run_next_test();
@ -416,6 +454,8 @@ add_test(function test_saveAppStats() {
do_check_eq(result[1].timestamp, timestamp); do_check_eq(result[1].timestamp, timestamp);
do_check_eq(result[1].rxBytes, stats.rxBytes); do_check_eq(result[1].rxBytes, stats.rxBytes);
do_check_eq(result[1].txBytes, stats.txBytes); do_check_eq(result[1].txBytes, stats.txBytes);
do_check_eq(result[1].rxSystemBytes, 0);
do_check_eq(result[1].txSystemBytes, 0);
do_check_eq(result[1].rxTotalBytes, 0); do_check_eq(result[1].rxTotalBytes, 0);
do_check_eq(result[1].txTotalBytes, 0); do_check_eq(result[1].txTotalBytes, 0);
run_next_test(); run_next_test();
@ -427,7 +467,7 @@ add_test(function test_saveAppStats() {
function prepareFind(network, stats, callback) { function prepareFind(network, stats, callback) {
netStatsDb.clearStats(network, function (error, result) { netStatsDb.clearStats(network, function (error, result) {
do_check_eq(error, null); do_check_eq(error, null);
netStatsDb.dbNewTxn("readwrite", function(txn, store) { netStatsDb.dbNewTxn("net_stats", "readwrite", function(txn, store) {
netStatsDb._saveStats(txn, store, stats); netStatsDb._saveStats(txn, store, stats);
}, function(error, result) { }, function(error, result) {
callback(error, result); callback(error, result);
@ -449,15 +489,18 @@ add_test(function test_find () {
start = new Date(start - sampleRate); start = new Date(start - sampleRate);
var stats = []; var stats = [];
for (var i = 0; i < samples; i++) { for (var i = 0; i < samples; i++) {
stats.push({ appId: appId, stats.push({ appId: appId,
network: networkWifi, timestamp: saveDate + (sampleRate * i), network: networkWifi, timestamp: saveDate + (sampleRate * i),
rxBytes: 0, txBytes: 10, rxBytes: 0, txBytes: 10,
rxTotalBytes: 0, txTotalBytes: 0 }); rxSystemBytes: 0, txSystemBytes: 0,
rxTotalBytes: 0, txTotalBytes: 0});
stats.push({ appId: appId,
network: networkMobile, timestamp: saveDate + (sampleRate * i), stats.push({ appId: appId,
rxBytes: 0, txBytes: 10, network: networkMobile, timestamp: saveDate + (sampleRate * i),
rxTotalBytes: 0, txTotalBytes: 0 }); rxBytes: 0, txBytes: 10,
rxSystemBytes: 0, txSystemBytes: 0,
rxTotalBytes: 0, txTotalBytes: 0});
} }
prepareFind(networks[0], stats, function(error, result) { prepareFind(networks[0], stats, function(error, result) {
@ -554,21 +597,22 @@ add_test(function test_saveMultipleAppStats () {
if (index == keys.length - 1) { if (index == keys.length - 1) {
netStatsDb.logAllRecords(function(error, result) { netStatsDb.logAllRecords(function(error, result) {
// Again, result has two samples more than expected samples because // Again, result has two samples more than expected samples because
// clear inserts one empty sample for each network to keep totalBytes // clear inserts one empty sample for each network to keep totalBytes
// synchronized with netd counters. so the first two samples have to // synchronized with netd counters. so the first two samples have to
// be discarted. // be discarted.
result.shift(); result.shift();
result.shift(); result.shift();
do_check_eq(error, null); do_check_eq(error, null);
do_check_eq(result.length, 4); do_check_eq(result.length, 4);
do_check_eq(result[0].appId, 1); do_check_eq(result[0].appId, 1);
do_check_true(compareNetworks(result[0].network,[networkWifi.id, networkWifi.type])); do_check_true(compareNetworks(result[0].network, [networkWifi.id, networkWifi.type]));
do_check_eq(result[0].rxBytes, 0); do_check_eq(result[0].rxBytes, 0);
do_check_eq(result[0].txBytes, 10); do_check_eq(result[0].txBytes, 10);
run_next_test(); run_next_test();
}); });
return;
} }
index += 1; index += 1;
@ -577,12 +621,188 @@ add_test(function test_saveMultipleAppStats () {
}); });
}); });
var networkWifi = '00';
var networkMobile = '11';
var examplePageURL = "http://example.com/index.html";
var exampleManifestURL = "http://example.com/manifest.webapp";
var testPageURL = "http://test.com/index.html";
var testManifestURL = "http://test.com/manifest.webapp";
var alarms = [{ id: null,
networkId: networkWifi,
threshold: 10000,
data: {foo: "something"},
pageURL: examplePageURL,
manifestURL: exampleManifestURL },
{ id: null,
networkId: networkWifi,
threshold: 1000,
data: {foo: "else"},
pageURL: examplePageURL,
manifestURL: exampleManifestURL },
{ id: null,
networkId: networkMobile,
threshold: 100,
data: {foo: "to"},
pageURL: examplePageURL,
manifestURL: exampleManifestURL },
{ id: null,
networkId: networkMobile,
threshold: 10,
data: {foo: "test"},
pageURL: testPageURL,
manifestURL: testManifestURL }];
var alarmsDbId = 1;
add_test(function test_addAlarm() {
// Add alarms[0] -> DB: [ alarms[0] (id: 1) ]
// Check the insertion is OK.
netStatsDb.addAlarm(alarms[0], function(error, result) {
do_check_eq(error, null);
alarmsDbId = result;
netStatsDb.getAlarms(Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, exampleManifestURL, function(error, result) {
do_check_eq(error, null);
do_check_eq(result.length, 1);
do_check_eq(result[0].id, alarmsDbId);
do_check_eq(result[0].networkId, alarms[0].networkId);
do_check_eq(result[0].threshold, alarms[0].threshold);
do_check_eq(result[0].data.foo, alarms[0].data.foo);
run_next_test();
});
});
});
add_test(function test_getFirstAlarm() {
// Add alarms[1] -> DB: [ alarms[0] (id: 1), alarms[1] (id: 2) ]
// Check first alarm is alarms[1] because threshold is lower.
alarmsDbId += 1;
netStatsDb.addAlarm(alarms[1], function (error, result) {
do_check_eq(error, null);
do_check_eq(result, alarmsDbId);
netStatsDb.getFirstAlarm(networkWifi, function(error, result) {
do_check_eq(error, null);
do_check_eq(result.id, alarmsDbId);
do_check_eq(result.networkId, alarms[1].networkId);
do_check_eq(result.threshold, alarms[1].threshold);
do_check_eq(result.data.foo, alarms[1].data.foo);
do_check_eq(result.pageURL, alarms[1].pageURL);
do_check_eq(result.manifestURL, alarms[1].manifestURL);
run_next_test();
});
});
});
add_test(function test_removeAlarm() {
// Remove alarms[1] (id: 2) -> DB: [ alarms[0] (id: 1) ]
// Check get first return alarms[0].
netStatsDb.removeAlarm(alarmsDbId, alarms[0].manifestURL, function (error, result) {
do_check_eq(error, null);
netStatsDb.getFirstAlarm(networkWifi, function(error, result) {
do_check_eq(error, null);
do_check_eq(result.id, alarmsDbId - 1);
do_check_eq(result.networkId, alarms[0].networkId);
do_check_eq(result.threshold, alarms[0].threshold);
do_check_eq(result.data.foo, alarms[0].data.foo);
do_check_eq(result.pageURL, alarms[0].pageURL);
do_check_eq(result.manifestURL, alarms[0].manifestURL);
run_next_test();
});
});
});
add_test(function test_removeAppAlarm() {
// Remove alarms[0] (id: 1) -> DB: [ ]
netStatsDb.removeAlarm(alarmsDbId - 1, alarms[0].manifestURL, function (error, result) {
do_check_eq(error, null);
netStatsDb.getAlarms(networkWifi, exampleManifestURL, function(error, result) {
do_check_eq(error, null);
do_check_eq(result.length, 0);
run_next_test();
});
});
});
add_test(function test_getAlarms() {
// Add all alarms -> DB: [ alarms[0] (id: 3),
// alarms[1] (id: 4),
// alarms[2] (id: 5),
// alarms[3] (id: 6) ]
// Check that getAlarms for wifi returns 2 alarms.
// Check that getAlarms for all connections returns 3 alarms.
var callback = function () {
netStatsDb.getAlarms(networkWifi, exampleManifestURL, function(error, result) {
do_check_eq(error, null);
do_check_eq(result.length, 2);
netStatsDb.getAlarms(null, exampleManifestURL, function(error, result) {
do_check_eq(error, null);
do_check_eq(result.length, 3);
run_next_test();
});
});
};
var index = 0;
var addFunction = function () {
alarmsDbId += 1;
netStatsDb.addAlarm(alarms[index], function (error, result) {
do_check_eq(error, null);
index += 1;
do_check_eq(result, alarmsDbId);
if (index >= alarms.length) {
callback();
return;
}
addFunction();
});
};
addFunction();
});
add_test(function test_removeAppAllAlarms() {
// Remove all alarms for exampleManifestURL -> DB: [ alarms[3] (id: 6) ]
netStatsDb.removeAlarms(exampleManifestURL, function (error, result) {
do_check_eq(error, null);
netStatsDb.getAlarms(null, exampleManifestURL, function(error, result) {
do_check_eq(error, null);
do_check_eq(result.length, 0);
netStatsDb.getAlarms(null, testManifestURL, function(error, result) {
do_check_eq(error, null);
do_check_eq(result.length, 1);
run_next_test();
});
});
});
});
add_test(function test_updateAlarm() {
// Update alarms[3] (id: 6) -> DB: [ alarms[3]* (id: 6) ]
var updatedAlarm = alarms[1];
updatedAlarm.id = alarmsDbId;
updatedAlarm.threshold = 10;
netStatsDb.updateAlarm(updatedAlarm, function (error, result) {
do_check_eq(error, null);
netStatsDb.getFirstAlarm(networkWifi, function(error, result) {
do_check_eq(error, null);
do_check_eq(result.id, updatedAlarm.id);
do_check_eq(result.networkId, updatedAlarm.networkId);
do_check_eq(result.threshold, updatedAlarm.threshold);
do_check_eq(result.data.foo, updatedAlarm.data.foo);
do_check_eq(result.pageURL, updatedAlarm.pageURL);
do_check_eq(result.manifestURL, updatedAlarm.manifestURL);
run_next_test();
});
});
});
function run_test() { function run_test() {
do_get_profile(); do_get_profile();
run_next_test();
// Clear whole database to avoid start tests with unknown state
// due to previous tests.
clearWholeDB(function(){
run_next_test();
});
} }

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

@ -139,9 +139,97 @@ add_test(function test_queue() {
do_check_eq(NetworkStatsService.updateQueue[0].callbacks[0], null); do_check_eq(NetworkStatsService.updateQueue[0].callbacks[0], null);
do_check_neq(NetworkStatsService.updateQueue[0].callbacks[1], null); do_check_neq(NetworkStatsService.updateQueue[0].callbacks[1], null);
// Clear queue because in test environment requests for mobile networks
// can not be handled.
NetworkStatsService.updateQueue = [];
run_next_test(); run_next_test();
}); });
var wifiId = '00';
add_test(function test_updateThreshold() {
let alarm = { networkId: wifiId, threshold: 10000 };
NetworkStatsService._updateThreshold(alarm, function onSet(error, threshold){
do_check_eq(error, null);
do_check_neq(threshold.systemThreshold, undefined);
do_check_neq(threshold.absoluteThreshold, undefined);
run_next_test();
});
});
var testPageURL = "http://test.com";
var testManifestURL = "http://test.com/manifest.webapp";
add_test(function test_setAlarm() {
let alarm = { id: null,
networkId: wifiId,
threshold: 10000,
absoluteThreshold: null,
alarmStart: null,
alarmEnd: null,
data: null,
pageURL: testPageURL,
manifestURL: testManifestURL };
NetworkStatsService._setAlarm(alarm, function onSet(error, result) {
do_check_eq(result, 1);
run_next_test();
});
});
add_test(function test_setAlarm_invalid_threshold() {
let alarm = { id: null,
networkId: wifiId,
threshold: -10000,
absoluteThreshold: null,
alarmStart: null,
alarmEnd: null,
data: null,
pageURL: testPageURL,
manifestURL: testManifestURL };
NetworkStatsService._setAlarm(alarm, function onSet(error, result) {
do_check_eq(error, "InvalidStateError");
run_next_test();
});
});
add_test(function test_fireAlarm() {
// Add a fake alarm into database.
let alarm = { id: null,
networkId: wifiId,
threshold: 10000,
absoluteThreshold: null,
alarmStart: null,
alarmEnd: null,
data: null,
pageURL: testPageURL,
manifestURL: testManifestURL };
NetworkStatsService._db.addAlarm(alarm, function addSuccessCb(error, newId) {
NetworkStatsService._db.getAlarms(Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
testManifestURL, function onGet(error, result) {
do_check_eq(error, null);
do_check_eq(result.length, 1);
// Result of getAlarms is based on expected child's data format, so
// some changes are needed to be able to use it.
result[0].networkId = wifiId;
result[0].pageURL = testPageURL;
result[0].manifestURL = testManifestURL;
NetworkStatsService._fireAlarm(result[0], false);
NetworkStatsService._db.getAlarms(Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
testManifestURL, function onGet(error, result) {
do_check_eq(error, undefined);
do_check_eq(result.length, 0);
run_next_test();
});
});
});
});
function run_test() { function run_test() {
do_get_profile(); do_get_profile();

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

@ -8,12 +8,33 @@
#include "MozNdefRecord.h" #include "MozNdefRecord.h"
#include "mozilla/dom/MozNdefRecordBinding.h" #include "mozilla/dom/MozNdefRecordBinding.h"
#include "mozilla/HoldDropJSObjects.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(MozNdefRecord, mWindow)
NS_IMPL_CYCLE_COLLECTION_CLASS(MozNdefRecord)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MozNdefRecord)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(MozNdefRecord)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(MozNdefRecord)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mType)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mId)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mPayload)
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(MozNdefRecord) NS_IMPL_CYCLE_COLLECTING_ADDREF(MozNdefRecord)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MozNdefRecord) NS_IMPL_CYCLE_COLLECTING_RELEASE(MozNdefRecord)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MozNdefRecord) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MozNdefRecord)
@ -21,11 +42,32 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MozNdefRecord)
NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END NS_INTERFACE_MAP_END
void
MozNdefRecord::HoldData()
{
mozilla::HoldJSObjects(this);
}
void
MozNdefRecord::DropData()
{
if (mType) {
mType = nullptr;
}
if (mId) {
mId = nullptr;
}
if (mPayload) {
mPayload = nullptr;
}
mozilla::DropJSObjects(this);
}
/* static */ /* static */
already_AddRefed<MozNdefRecord> already_AddRefed<MozNdefRecord>
MozNdefRecord::Constructor(const GlobalObject& aGlobal, MozNdefRecord::Constructor(const GlobalObject& aGlobal,
uint8_t aTnf, const nsAString& aType, uint8_t aTnf, const Uint8Array& aType,
const nsAString& aId, const nsAString& aPayload, const Uint8Array& aId, const Uint8Array& aPayload,
ErrorResult& aRv) ErrorResult& aRv)
{ {
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.GetAsSupports()); nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.GetAsSupports());
@ -33,25 +75,35 @@ MozNdefRecord::Constructor(const GlobalObject& aGlobal,
aRv.Throw(NS_ERROR_FAILURE); aRv.Throw(NS_ERROR_FAILURE);
return nullptr; return nullptr;
} }
nsRefPtr<MozNdefRecord> ndefrecord =
new MozNdefRecord(win, aTnf, aType, aId, aPayload); nsRefPtr<MozNdefRecord> ndefrecord = new MozNdefRecord(aGlobal.GetContext(),
win, aTnf, aType, aId,
aPayload);
if (!ndefrecord) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
return ndefrecord.forget(); return ndefrecord.forget();
} }
MozNdefRecord::MozNdefRecord(nsPIDOMWindow* aWindow, MozNdefRecord::MozNdefRecord(JSContext* aCx, nsPIDOMWindow* aWindow,
uint8_t aTnf, const nsAString& aType, uint8_t aTnf, const Uint8Array& aType,
const nsAString& aId, const nsAString& aPayload) const Uint8Array& aId, const Uint8Array& aPayload)
: mTnf(aTnf) : mTnf(aTnf)
, mType(aType)
, mId(aId)
, mPayload(aPayload)
{ {
mWindow = aWindow; mWindow = aWindow; // For GetParentObject()
mType = Uint8Array::Create(aCx, this, aType.Length(), aType.Data());
mId = Uint8Array::Create(aCx, this, aId.Length(), aId.Data());
mPayload = Uint8Array::Create(aCx, this, aPayload.Length(), aPayload.Data());
SetIsDOMBinding(); SetIsDOMBinding();
HoldData();
} }
MozNdefRecord::~MozNdefRecord() MozNdefRecord::~MozNdefRecord()
{ {
DropData();
} }
JSObject* JSObject*

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

@ -17,6 +17,10 @@
#include "nsIDocument.h" #include "nsIDocument.h"
#include "mozilla/dom/TypedArray.h"
#include "jsfriendapi.h"
#include "js/GCAPI.h"
struct JSContext; struct JSContext;
namespace mozilla { namespace mozilla {
@ -31,9 +35,9 @@ public:
public: public:
MozNdefRecord(nsPIDOMWindow* aWindow, MozNdefRecord(JSContext* aCx, nsPIDOMWindow* aWindow, uint8_t aTnf,
uint8_t aTnf, const nsAString& aType, const Uint8Array& aType, const Uint8Array& aId,
const nsAString& aId, const nsAString& aPlayload); const Uint8Array& aPlayload);
~MozNdefRecord(); ~MozNdefRecord();
@ -45,41 +49,56 @@ public:
virtual JSObject* WrapObject(JSContext* aCx, virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE; JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
static already_AddRefed<MozNdefRecord> Constructor( static already_AddRefed<MozNdefRecord>
const GlobalObject& aGlobal, Constructor(const GlobalObject& aGlobal, uint8_t aTnf,
uint8_t aTnf, const nsAString& aType, const Uint8Array& aType, const Uint8Array& aId,
const nsAString& aId, const Uint8Array& aPayload, ErrorResult& aRv);
const nsAString& aPayload,
ErrorResult& aRv);
uint8_t Tnf() const uint8_t Tnf() const
{ {
return mTnf; return mTnf;
} }
void GetType(nsString& aType) const JSObject* Type(JSContext* cx) const
{ {
aType = mType; return GetTypeObject();
}
JSObject* GetTypeObject() const
{
JS::ExposeObjectToActiveJS(mType);
return mType;
} }
void GetId(nsString& aId) const JSObject* Id(JSContext* cx) const
{ {
aId = mId; return GetIdObject();
}
JSObject* GetIdObject() const
{
JS::ExposeObjectToActiveJS(mId);
return mId;
} }
void GetPayload(nsString& aPayload) const JSObject* Payload(JSContext* cx) const
{ {
aPayload = mPayload; return GetPayloadObject();
}
JSObject* GetPayloadObject() const
{
JS::ExposeObjectToActiveJS(mPayload);
return mPayload;
} }
private: private:
MozNdefRecord() MOZ_DELETE; MozNdefRecord() MOZ_DELETE;
nsRefPtr<nsPIDOMWindow> mWindow; nsRefPtr<nsPIDOMWindow> mWindow;
void HoldData();
void DropData();
uint8_t mTnf; uint8_t mTnf;
nsString mType; JS::Heap<JSObject*> mType;
nsString mId; JS::Heap<JSObject*> mId;
nsString mPayload; JS::Heap<JSObject*> mPayload;
}; };
} // namespace dom } // namespace dom

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

@ -10,7 +10,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Services.jsm");
const NETWORKSERVICE_CONTRACTID = "@mozilla.org/network/service;1"; const NETWORKSERVICE_CONTRACTID = "@mozilla.org/network/service;1";
const NETWORKSERVICE_CID = Components.ID("{a6c58260-46df-11e3-8f96-0800200c9a66}"); const NETWORKSERVICE_CID = Components.ID("{c14cabaf-bb8e-470d-a2f1-2cb6de6c5e5c}");
// 1xx - Requested action is proceeding // 1xx - Requested action is proceeding
const NETD_COMMAND_PROCEEDING = 100; const NETD_COMMAND_PROCEEDING = 100;
@ -117,13 +117,89 @@ NetworkService.prototype = {
params.isAsync = true; params.isAsync = true;
this.controlMessage(params, function(result) { this.controlMessage(params, function(result) {
let success = result.resultCode >= NETD_COMMAND_OKAY && let success = !isError(result.resultCode);
result.resultCode < NETD_COMMAND_ERROR;
callback.networkStatsAvailable(success, result.rxBytes, callback.networkStatsAvailable(success, result.rxBytes,
result.txBytes, result.date); result.txBytes, result.date);
}); });
}, },
setNetworkInterfaceAlarm: function setNetworkInterfaceAlarm(networkName, threshold, callback) {
if (!networkName) {
callback.networkUsageAlarmResult(-1);
return;
}
if (threshold < 0) {
this._disableNetworkInterfaceAlarm(networkName, callback);
return;
}
this._setNetworkInterfaceAlarm(networkName, threshold, callback);
},
_setNetworkInterfaceAlarm: function _setNetworkInterfaceAlarm(networkName, threshold, callback) {
debug("setNetworkInterfaceAlarm for " + networkName + " at " + threshold + "bytes");
let params = {
cmd: "setNetworkInterfaceAlarm",
ifname: networkName,
threshold: threshold
};
params.report = true;
params.isAsync = true;
this.controlMessage(params, function(result) {
if (!isError(result.resultCode)) {
callback.networkUsageAlarmResult(null);
return;
}
this._enableNetworkInterfaceAlarm(networkName, threshold, callback);
});
},
_enableNetworkInterfaceAlarm: function _enableNetworkInterfaceAlarm(networkName, threshold, callback) {
debug("enableNetworkInterfaceAlarm for " + networkName + " at " + threshold + "bytes");
let params = {
cmd: "enableNetworkInterfaceAlarm",
ifname: networkName,
threshold: threshold
};
params.report = true;
params.isAsync = true;
this.controlMessage(params, function(result) {
if (!isError(result.resultCode)) {
callback.networkUsageAlarmResult(null);
return;
}
callback.networkUsageAlarmResult(result.reason);
});
},
_disableNetworkInterfaceAlarm: function _disableNetworkInterfaceAlarm(networkName, callback) {
debug("disableNetworkInterfaceAlarm for " + networkName);
let params = {
cmd: "disableNetworkInterfaceAlarm",
ifname: networkName,
};
params.report = true;
params.isAsync = true;
this.controlMessage(params, function(result) {
if (!isError(result.resultCode)) {
callback.networkUsageAlarmResult(null);
return;
}
callback.networkUsageAlarmResult(result.reason);
});
},
setWifiOperationMode: function setWifiOperationMode(interfaceName, mode, callback) { setWifiOperationMode: function setWifiOperationMode(interfaceName, mode, callback) {
if(DEBUG) debug("setWifiOperationMode on " + interfaceName + " to " + mode); if(DEBUG) debug("setWifiOperationMode on " + interfaceName + " to " + mode);

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

@ -1,3 +1,3 @@
# NetworkService.js # NetworkService.js
component {a6c58260-46df-11e3-8f96-0800200c9a66} NetworkService.js component {c14cabaf-bb8e-470d-a2f1-2cb6de6c5e5c} NetworkService.js
contract @mozilla.org/network/service;1 {a6c58260-46df-11e3-8f96-0800200c9a66} contract @mozilla.org/network/service;1 {c14cabaf-bb8e-470d-a2f1-2cb6de6c5e5c}

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

@ -151,7 +151,19 @@ function networkInterfaceStatsFail(params) {
function networkInterfaceStatsSuccess(params) { function networkInterfaceStatsSuccess(params) {
// Notify the main thread. // Notify the main thread.
params.txBytes = parseFloat(params.resultReason); params.txBytes = parseFloat(params.resultReason);
postMessage(params);
return true;
}
function networkInterfaceAlarmFail(params) {
// Notify the main thread.
postMessage(params);
return true;
}
function networkInterfaceAlarmSuccess(params) {
// Notify the main thread.
params.error = parseFloat(params.resultReason);
postMessage(params); postMessage(params);
return true; return true;
} }
@ -607,6 +619,31 @@ function getTxBytes(params, callback) {
return doCommand(command, callback); return doCommand(command, callback);
} }
function enableAlarm(params, callback) {
let command = "bandwidth enable";
return doCommand(command, callback);
}
function disableAlarm(params, callback) {
let command = "bandwidth disable";
return doCommand(command, callback);
}
function setQuota(params, callback) {
let command = "bandwidth setiquota " + params.ifname + " " + parseInt('0xffffffffffffffff');
return doCommand(command, callback);
}
function removeQuota(params, callback) {
let command = "bandwidth removeiquota " + params.ifname;
return doCommand(command, callback);
}
function setAlarm(params, callback) {
let command = "bandwidth setinterfacealert " + params.ifname + " " + params.threshold;
return doCommand(command, callback);
}
function escapeQuote(str) { function escapeQuote(str) {
str = str.replace(/\\/g, "\\\\"); str = str.replace(/\\/g, "\\\\");
return str.replace(/"/g, "\\\""); return str.replace(/"/g, "\\\"");
@ -914,6 +951,39 @@ function getNetworkInterfaceStats(params) {
return true; return true;
} }
let gNetworkInterfaceEnableAlarmChain = [enableAlarm,
setQuota,
setAlarm,
networkInterfaceAlarmSuccess];
function enableNetworkInterfaceAlarm(params) {
debug("enableNetworkInterfaceAlarms: " + params.ifname);
chain(params, gNetworkInterfaceEnableAlarmChain, networkInterfaceAlarmFail);
return true;
}
let gNetworkInterfaceDisableAlarmChain = [removeQuota,
disableAlarm,
networkInterfaceAlarmSuccess];
function disableNetworkInterfaceAlarm(params) {
debug("disableNetworkInterfaceAlarms: " + params.ifname);
chain(params, gNetworkInterfaceDisableAlarmChain, networkInterfaceAlarmFail);
return true;
}
let gNetworkInterfaceSetAlarmChain = [setAlarm,
networkInterfaceAlarmSuccess];
function setNetworkInterfaceAlarm(params) {
debug("setNetworkInterfaceAlarms: " + params.ifname);
chain(params, gNetworkInterfaceSetAlarmChain, networkInterfaceAlarmFail);
return true;
}
let gWifiOperationModeChain = [wifiFirmwareReload, let gWifiOperationModeChain = [wifiFirmwareReload,
wifiOperationModeSuccess]; wifiOperationModeSuccess];

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

@ -48,8 +48,7 @@ this.NFC_TECHS = {
0:'NDEF', 0:'NDEF',
1:'NDEF_WRITEABLE', 1:'NDEF_WRITEABLE',
2:'NDEF_FORMATABLE', 2:'NDEF_FORMATABLE',
3:'P2P', 3:'P2P'
4:'NFC_A'
}; };
// TODO: Bug 933595. Fill-in all error codes for Gonk/nfcd protocol // TODO: Bug 933595. Fill-in all error codes for Gonk/nfcd protocol

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

@ -112,33 +112,24 @@ let NfcWorker = {
let records = []; let records = [];
for (let i = 0; i < numOfRecords; i++) { for (let i = 0; i < numOfRecords; i++) {
let tnf = Buf.readInt32(); let tnf = Buf.readInt32() & 0xff;
let typeLength = Buf.readInt32(); let typeLength = Buf.readInt32();
let type = []; let type = Buf.readUint8Array(typeLength);
for (let i = 0; i < typeLength; i++) {
type.push(Buf.readUint8());
}
let padding = getPaddingLen(typeLength); let padding = getPaddingLen(typeLength);
for (let i = 0; i < padding; i++) { for (let i = 0; i < padding; i++) {
Buf.readUint8(); Buf.readUint8();
} }
let idLength = Buf.readInt32(); let idLength = Buf.readInt32();
let id = []; let id = Buf.readUint8Array(idLength);
for (let i = 0; i < idLength; i++) {
id.push(Buf.readUint8());
}
padding = getPaddingLen(idLength); padding = getPaddingLen(idLength);
for (let i = 0; i < padding; i++) { for (let i = 0; i < padding; i++) {
Buf.readUint8(); Buf.readUint8();
} }
let payloadLength = Buf.readInt32(); let payloadLength = Buf.readInt32();
let payload = []; let payload = Buf.readUint8Array(payloadLength);
for (let i = 0; i < payloadLength; i++) { padding = getPaddingLen(payloadLength);
payload.push(Buf.readUint8());
}
padding = getPaddingLen(payloadLength);
for (let i = 0; i < padding; i++) { for (let i = 0; i < padding; i++) {
Buf.readUint8(); Buf.readUint8();
} }
@ -196,30 +187,30 @@ let NfcWorker = {
let record = records[i]; let record = records[i];
Buf.writeInt32(record.tnf); Buf.writeInt32(record.tnf);
let typeLength = record.type.length; let typeLength = record.type ? record.type.length : 0;
Buf.writeInt32(typeLength); Buf.writeInt32(typeLength);
for (let j = 0; j < typeLength; j++) { for (let j = 0; j < typeLength; j++) {
Buf.writeUint8(record.type.charCodeAt(j)); Buf.writeUint8(record.type[j]);
} }
let padding = getPaddingLen(typeLength); let padding = getPaddingLen(typeLength);
for (let i = 0; i < padding; i++) { for (let i = 0; i < padding; i++) {
Buf.writeUint8(0x00); Buf.writeUint8(0x00);
} }
let idLength = record.id.length; let idLength = record.id ? record.id.length : 0;
Buf.writeInt32(idLength); Buf.writeInt32(idLength);
for (let j = 0; j < idLength; j++) { for (let j = 0; j < idLength; j++) {
Buf.writeUint8(record.id.charCodeAt(j)); Buf.writeUint8(record.id[j]);
} }
padding = getPaddingLen(idLength); padding = getPaddingLen(idLength);
for (let i = 0; i < padding; i++) { for (let i = 0; i < padding; i++) {
Buf.writeUint8(0x00); Buf.writeUint8(0x00);
} }
let payloadLength = record.payload && record.payload.length; let payloadLength = record.payload ? record.payload.length : 0;
Buf.writeInt32(payloadLength); Buf.writeInt32(payloadLength);
for (let j = 0; j < payloadLength; j++) { for (let j = 0; j < payloadLength; j++) {
Buf.writeUint8(record.payload.charCodeAt(j)); Buf.writeUint8(record.payload[j]);
} }
padding = getPaddingLen(payloadLength); padding = getPaddingLen(payloadLength);
for (let i = 0; i < padding; i++) { for (let i = 0; i < padding; i++) {
@ -382,7 +373,10 @@ NfcWorker[NFC_NOTIFICATION_TECH_DISCOVERED] = function NFC_NOTIFICATION_TECH_DIS
let sessionId = Buf.readInt32(); let sessionId = Buf.readInt32();
let techCount = Buf.readInt32(); let techCount = Buf.readInt32();
for (let count = 0; count < techCount; count++) { for (let count = 0; count < techCount; count++) {
techs.push(NFC_TECHS[Buf.readUint8()]); let tech = NFC_TECHS[Buf.readUint8()];
if (tech) {
techs.push(tech);
}
} }
let padding = getPaddingLen(techCount); let padding = getPaddingLen(techCount);

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

@ -28,6 +28,12 @@ interface nsINetworkStatsCallback : nsISupports
in jsval date); in jsval date);
}; };
[scriptable, function, uuid(0706bfa2-ac2d-11e2-9a8d-7b6d988d4767)]
interface nsINetworkUsageAlarmCallback : nsISupports
{
void networkUsageAlarmResult(in jsval error);
};
[scriptable, function, uuid(9ede8720-f8bc-11e2-b778-0800200c9a66)] [scriptable, function, uuid(9ede8720-f8bc-11e2-b778-0800200c9a66)]
interface nsIWifiOperationModeCallback : nsISupports interface nsIWifiOperationModeCallback : nsISupports
{ {
@ -98,7 +104,7 @@ interface nsIUpdateUpStreamCallback : nsISupports
/** /**
* Provide network services. * Provide network services.
*/ */
[scriptable, uuid(a6c58260-46df-11e3-8f96-0800200c9a66)] [scriptable, uuid(c14cabaf-bb8e-470d-a2f1-2cb6de6c5e5c)]
interface nsINetworkService : nsISupports interface nsINetworkService : nsISupports
{ {
/** /**
@ -151,6 +157,24 @@ interface nsINetworkService : nsISupports
*/ */
void getNetworkInterfaceStats(in DOMString networkName, in nsINetworkStatsCallback callback); void getNetworkInterfaceStats(in DOMString networkName, in nsINetworkStatsCallback callback);
/**
* Set Alarm of usage per interface
*
* @param networkName
* Select the Network interface to set an alarm.
*
* @param threshold
* Amount of data that will trigger the alarm.
*
* @param callback
* Callback to notify the result.
*
* @return false if there is no interface registered for the networkType param.
*/
boolean setNetworkInterfaceAlarm(in DOMString networkName,
in long threshold,
in nsINetworkUsageAlarmCallback callback);
/** /**
* Reload Wifi firmware to specific operation mode. * Reload Wifi firmware to specific operation mode.
* *

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

@ -3014,7 +3014,6 @@ let RIL = {
} }
ICCRecordHelper.fetchICCRecords(); ICCRecordHelper.fetchICCRecords();
this.reportStkServiceIsRunning();
} }
this.cardState = newCardState; this.cardState = newCardState;
@ -11225,6 +11224,7 @@ let ICCRecordHelper = {
if (DEBUG) debug("ICCID: " + RIL.iccInfo.iccid); if (DEBUG) debug("ICCID: " + RIL.iccInfo.iccid);
if (RIL.iccInfo.iccid) { if (RIL.iccInfo.iccid) {
ICCUtilsHelper.handleICCInfoChange(); ICCUtilsHelper.handleICCInfoChange();
RIL.reportStkServiceIsRunning();
} }
} }

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

@ -152,6 +152,12 @@ interface CameraControl {
[Throws] [Throws]
attribute any thumbnailSize; attribute any thumbnailSize;
/* the angle, in degrees, that the image sensor is mounted relative
to the display; e.g. if 'sensorAngle' is 270 degrees (or -90 degrees),
then the preview stream needs to be rotated +90 degrees to have the
same orientation as the real world. */
readonly attribute long sensorAngle;
/* tell the camera to attempt to focus the image */ /* tell the camera to attempt to focus the image */
[Throws] [Throws]
void autoFocus(CameraAutoFocusCallback onSuccess, optional CameraErrorCallback onError); void autoFocus(CameraAutoFocusCallback onSuccess, optional CameraErrorCallback onError);

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

@ -5,7 +5,7 @@
/* Copyright © 2013 Deutsche Telekom, Inc. */ /* Copyright © 2013 Deutsche Telekom, Inc. */
[Constructor(octet tnf, DOMString type, DOMString id, DOMString payload)] [Constructor(octet tnf, Uint8Array type, Uint8Array id, Uint8Array payload)]
interface MozNdefRecord interface MozNdefRecord
{ {
/** /**
@ -19,20 +19,25 @@ interface MozNdefRecord
* tnf_unchanged: 0x06 * tnf_unchanged: 0x06
* tnf_reserved: 0x07 * tnf_reserved: 0x07
*/ */
[Constant]
readonly attribute octet tnf; readonly attribute octet tnf;
/** /**
* type - Describes the content of the payload. This can be a mime type. * type - Describes the content of the payload. This can be a mime type.
*/ */
readonly attribute DOMString type; [Constant]
readonly attribute Uint8Array type;
/** /**
* id - Identifer is application dependent. * id - Identifer is application dependent.
*/ */
readonly attribute DOMString id; [Constant]
readonly attribute Uint8Array id;
/** /**
* payload - Binary data blob. The meaning of this field is application dependent. * payload - Binary data blob. The meaning of this field is application
* dependent.
*/ */
readonly attribute DOMString payload; [Constant]
readonly attribute Uint8Array payload;
}; };

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

@ -31,7 +31,7 @@ static float gMaxEventAcceleration = 999.0f;
/** /**
* Amount of friction applied during flings. * Amount of friction applied during flings.
*/ */
static float gFlingFriction = 0.006f; static float gFlingFriction = 0.002f;
/** /**
* Threshold for velocity beneath which we turn off any acceleration we had * Threshold for velocity beneath which we turn off any acceleration we had

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

@ -84,7 +84,7 @@ ThreadStackHelper::GetStack(Stack& aStack)
{ {
// Always run PrepareStackBuffer first to clear aStack // Always run PrepareStackBuffer first to clear aStack
if (!PrepareStackBuffer(aStack)) { if (!PrepareStackBuffer(aStack)) {
MOZ_ASSERT(false); // Skip and return empty aStack
return; return;
} }
@ -149,13 +149,23 @@ ThreadStackHelper::SigAction(int aSignal, siginfo_t* aInfo, void* aContext)
bool bool
ThreadStackHelper::PrepareStackBuffer(Stack& aStack) { ThreadStackHelper::PrepareStackBuffer(Stack& aStack) {
// Return false to skip getting the stack and return an empty stack
aStack.clear(); aStack.clear();
#ifdef MOZ_ENABLE_PROFILER_SPS #ifdef MOZ_ENABLE_PROFILER_SPS
/* Normally, provided the profiler is enabled, it would be an error if we
don't have a pseudostack here (the thread probably forgot to call
profiler_register_thread). However, on B2G, profiling secondary threads
may be disabled despite profiler being enabled. This is by-design and
is not an error. */
#ifdef MOZ_WIDGET_GONK
if (!mPseudoStack) { if (!mPseudoStack) {
return false; return false;
} }
#endif
MOZ_ASSERT(mPseudoStack);
mStackBuffer.clear(); mStackBuffer.clear();
return mStackBuffer.reserve(mMaxStackSize); MOZ_ALWAYS_TRUE(mStackBuffer.reserve(mMaxStackSize));
return true;
#else #else
return false; return false;
#endif #endif