From ab4aae2e250fe0f3da8d58a2bb9ec172d4f0201c Mon Sep 17 00:00:00 2001 From: John Shih Date: Fri, 28 Jun 2013 11:35:46 +0800 Subject: [PATCH] Bug 746073 - Network Per-App Metering on HTTP layer. r=honzab --- netwerk/protocol/http/nsHttpTransaction.cpp | 135 ++++++++++++++++++++ netwerk/protocol/http/nsHttpTransaction.h | 30 +++++ 2 files changed, 165 insertions(+) diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp index 69735dee507e..d58c4f06f147 100644 --- a/netwerk/protocol/http/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -34,6 +34,9 @@ #include "nsIOService.h" #include +#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 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 networkManager = + do_GetService("@mozilla.org/network/manager;1", &rv); + + if (NS_FAILED(rv) || !networkManager) { + mActiveNetwork = nullptr; + return; + } + + nsCOMPtr activeNetwork; + networkManager->GetActive(getter_AddRefs(activeNetwork)); + mActiveNetwork = + new nsMainThreadPtrHolder(activeNetwork); +#endif +} + +//----------------------------------------------------------------------------- +// nsHttpTransaction save network statistics event +//----------------------------------------------------------------------------- + +#ifdef MOZ_WIDGET_GONK +namespace { +class SaveNetworkStatsEvent : public nsRunnable { +public: + SaveNetworkStatsEvent(uint32_t aAppId, + nsMainThreadPtrHandle &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 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 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 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; diff --git a/netwerk/protocol/http/nsHttpTransaction.h b/netwerk/protocol/http/nsHttpTransaction.h index d2d8f9b3c6c9..70f13bee41d9 100644 --- a/netwerk/protocol/http/nsHttpTransaction.h +++ b/netwerk/protocol/http/nsHttpTransaction.h @@ -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 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 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__