зеркало из https://github.com/mozilla/gecko-dev.git
Merge b2g-inbound to m-c.
This commit is contained in:
Коммит
e837de97ec
2
CLOBBER
2
CLOBBER
|
@ -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
|
||||||
|
|
Загрузка…
Ссылка в новой задаче