Bug 746073 - Network Per-App Metering on HTTP layer. r=honzab

This commit is contained in:
John Shih 2013-06-28 11:35:46 +08:00
Родитель 56c88d861c
Коммит ab4aae2e25
2 изменённых файлов: 165 добавлений и 0 удалений

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

@ -34,6 +34,9 @@
#include "nsIOService.h"
#include <algorithm>
#ifdef MOZ_WIDGET_GONK
#include "nsINetworkStatsServiceProxy.h"
#endif
using namespace mozilla;
@ -121,6 +124,9 @@ nsHttpTransaction::nsHttpTransaction()
, mSubmittedRatePacing(false)
, mPassedRatePacing(false)
, mSynchronousRatePaceRequest(false)
, mCountRecv(0)
, mCountSent(0)
, mAppId(NECKO_NO_APP_ID)
{
LOG(("Creating nsHttpTransaction @%p\n", this));
gHttpHandler->GetMaxPipelineObjectSize(&mMaxPipelineObjectSize);
@ -224,6 +230,18 @@ nsHttpTransaction::Init(uint32_t caps,
mActivityDistributor = nullptr;
}
// obtain app info
bool isInBrowser;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(eventsink);
if (channel) {
NS_GetAppInfo(channel, &mAppId, &isInBrowser);
}
// obtain active connection type
if (mAppId != NECKO_NO_APP_ID) {
GetActiveNetwork();
}
// create transport event sink proxy. it coalesces all events if and only
// if the activity observer is not active. when the observer is active
// we need not to coalesce any events to get all expected notifications
@ -565,6 +583,7 @@ nsHttpTransaction::ReadRequestSegment(nsIInputStream *stream,
"net::http::first-write");
}
trans->CountSentBytes(*countRead);
trans->mSentData = true;
return NS_OK;
}
@ -641,6 +660,7 @@ nsHttpTransaction::WritePipeSegment(nsIOutputStream *stream,
}
MOZ_ASSERT(*countWritten > 0, "bad writer");
trans->CountRecvBytes(*countWritten);
trans->mReceivedData = true;
// Let the transaction "play" with the buffer. It is free to modify
@ -687,6 +707,118 @@ nsHttpTransaction::WriteSegments(nsAHttpSegmentWriter *writer,
return rv;
}
void
nsHttpTransaction::GetActiveNetwork()
{
#ifdef MOZ_WIDGET_GONK
MOZ_ASSERT(NS_IsMainThread());
nsresult rv;
nsCOMPtr<nsINetworkManager> networkManager =
do_GetService("@mozilla.org/network/manager;1", &rv);
if (NS_FAILED(rv) || !networkManager) {
mActiveNetwork = nullptr;
return;
}
nsCOMPtr<nsINetworkInterface> activeNetwork;
networkManager->GetActive(getter_AddRefs(activeNetwork));
mActiveNetwork =
new nsMainThreadPtrHolder<nsINetworkInterface>(activeNetwork);
#endif
}
//-----------------------------------------------------------------------------
// nsHttpTransaction save network statistics event
//-----------------------------------------------------------------------------
#ifdef MOZ_WIDGET_GONK
namespace {
class SaveNetworkStatsEvent : public nsRunnable {
public:
SaveNetworkStatsEvent(uint32_t aAppId,
nsMainThreadPtrHandle<nsINetworkInterface> &aActiveNetwork,
uint64_t aCountRecv,
uint64_t aCountSent)
: mAppId(aAppId),
mActiveNetwork(aActiveNetwork),
mCountRecv(aCountRecv),
mCountSent(aCountSent)
{
MOZ_ASSERT(mAppId != NECKO_NO_APP_ID);
MOZ_ASSERT(mActiveNetwork);
}
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread());
nsresult rv;
nsCOMPtr<nsINetworkStatsServiceProxy> mNetworkStatsServiceProxy =
do_GetService("@mozilla.org/networkstatsServiceProxy;1", &rv);
if (NS_FAILED(rv)) {
return rv;
}
// save the network stats through NetworkStatsServiceProxy
mNetworkStatsServiceProxy->SaveAppStats(mAppId,
mActiveNetwork,
PR_Now() / 1000,
mCountRecv,
mCountSent,
nullptr);
return NS_OK;
}
private:
uint32_t mAppId;
nsMainThreadPtrHandle<nsINetworkInterface> mActiveNetwork;
uint64_t mCountRecv;
uint64_t mCountSent;
};
};
#endif
nsresult
nsHttpTransaction::SaveNetworkStats(bool enforce)
{
#ifdef MOZ_WIDGET_GONK
// Check if active network and appid are valid.
if (!mActiveNetwork || mAppId == NECKO_NO_APP_ID) {
return NS_OK;
}
if (mCountRecv <= 0 && mCountSent <= 0) {
// There is no traffic, no need to save.
return NS_OK;
}
// If |enforce| is false, the traffic amount is saved
// only when the total amount exceeds the predefined
// threshold.
uint64_t totalBytes = mCountRecv + mCountSent;
if (!enforce && totalBytes < NETWORK_STATS_THRESHOLD) {
return NS_OK;
}
// Create the event to save the network statistics.
// the event is then dispathed to the main thread.
nsRefPtr<nsRunnable> event =
new SaveNetworkStatsEvent(mAppId, mActiveNetwork,
mCountRecv, mCountSent);
NS_DispatchToMainThread(event);
// Reset the counters after saving.
mCountSent = 0;
mCountRecv = 0;
return NS_OK;
#else
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
void
nsHttpTransaction::Close(nsresult reason)
{
@ -828,6 +960,9 @@ nsHttpTransaction::Close(nsresult reason)
if (relConn && mConnection)
NS_RELEASE(mConnection);
// save network statistics in the end of transaction
SaveNetworkStats(true);
mStatus = reason;
mTransactionDone = true; // forcibly flag the transaction as complete
mClosed = true;

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

@ -15,6 +15,11 @@
#include "nsILoadGroup.h"
#include "nsIInterfaceRequestor.h"
#include "TimingStruct.h"
#include "nsProxyRelease.h"
#ifdef MOZ_WIDGET_GONK
#include "nsINetworkManager.h"
#endif
//-----------------------------------------------------------------------------
@ -332,6 +337,31 @@ private:
bool mPassedRatePacing;
bool mSynchronousRatePaceRequest;
nsCOMPtr<nsICancelable> mTokenBucketCancel;
// These members are used for network per-app metering (bug 746073)
// Currently, they are only available on gonk.
public:
const static uint64_t NETWORK_STATS_THRESHOLD = 65536;
private:
uint64_t mCountRecv;
uint64_t mCountSent;
uint32_t mAppId;
#ifdef MOZ_WIDGET_GONK
nsMainThreadPtrHandle<nsINetworkInterface> mActiveNetwork;
#endif
nsresult SaveNetworkStats(bool);
void GetActiveNetwork();
void CountRecvBytes(uint64_t recvBytes)
{
mCountRecv += recvBytes;
SaveNetworkStats(false);
}
void CountSentBytes(uint64_t sentBytes)
{
mCountSent += sentBytes;
SaveNetworkStats(false);
}
};
#endif // nsHttpTransaction_h__