diff -r 000000000000 -r 6474c204b198 dom/system/gonk/NetworkWorker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/system/gonk/NetworkWorker.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,287 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NetworkWorker.h" +#include "NetworkUtils.h" +#include +#include "mozilla/ModuleUtils.h" +#include "mozilla/ClearOnShutdown.h" +#include "nsXULAppAPI.h" +#include "nsCxPusher.h" + +#define NS_NETWORKWORKER_CID \ + { 0x6df093e1, 0x8127, 0x4fa7, {0x90, 0x13, 0xa3, 0xaa, 0xa7, 0x79, 0xbb, 0xdd} } + +using namespace mozilla; +using namespace mozilla::dom; +using namespace mozilla::ipc; + +namespace mozilla { + +nsCOMPtr gWorkerThread; + +// The singleton network worker, to be used on the main thread. +StaticRefPtr gNetworkWorker; + +// The singleton networkutils class, that can be used on any thread. +static nsAutoPtr gNetworkUtils; + +// Runnable used dispatch command result on the main thread. +class NetworkResultDispatcher : public nsRunnable +{ +public: + NetworkResultDispatcher(const NetworkResultOptions& aResult) + { + MOZ_ASSERT(!NS_IsMainThread()); + +#define COPY_FIELD(prop) mResult.prop = aResult.prop; + COPY_FIELD(mId) + COPY_FIELD(mRet) + COPY_FIELD(mBroadcast) + COPY_FIELD(mTopic) + COPY_FIELD(mReason) + COPY_FIELD(mResultCode) + COPY_FIELD(mResultReason) + COPY_FIELD(mError) + COPY_FIELD(mRxBytes) + COPY_FIELD(mTxBytes) + COPY_FIELD(mDate) + COPY_FIELD(mEnable) + COPY_FIELD(mResult) + COPY_FIELD(mSuccess) + COPY_FIELD(mCurExternalIfname) + COPY_FIELD(mCurInternalIfname) +#undef COPY_FIELD + } + + NS_IMETHOD Run() + { + MOZ_ASSERT(NS_IsMainThread()); + + if (gNetworkWorker) { + gNetworkWorker->DispatchNetworkResult(mResult); + } + return NS_OK; + } +private: + NetworkResultOptions mResult; +}; + +// Runnable used dispatch netd command on the worker thread. +class NetworkCommandDispatcher : public nsRunnable +{ +public: + NetworkCommandDispatcher(const NetworkParams& aParams) + : mParams(aParams) + { + MOZ_ASSERT(NS_IsMainThread()); + } + + NS_IMETHOD Run() + { + MOZ_ASSERT(!NS_IsMainThread()); + + if (gNetworkUtils) { + gNetworkUtils->ExecuteCommand(mParams); + } + return NS_OK; + } +private: + NetworkParams mParams; +}; + +// Runnable used dispatch netd result on the worker thread. +class NetdEventRunnable : public nsRunnable +{ +public: + NetdEventRunnable(NetdCommand* aCommand) + : mCommand(aCommand) + { + MOZ_ASSERT(!NS_IsMainThread()); + } + + NS_IMETHOD Run() + { + MOZ_ASSERT(!NS_IsMainThread()); + + if (gNetworkUtils) { + gNetworkUtils->onNetdMessage(mCommand); + } + return NS_OK; + } + +private: + nsAutoPtr mCommand; +}; + +class NetdMessageConsumer : public NetdConsumer +{ +public: + NetdMessageConsumer() + { + MOZ_ASSERT(NS_IsMainThread()); + } + + void MessageReceived(NetdCommand* aCommand) + { + MOZ_ASSERT(!NS_IsMainThread()); + + nsCOMPtr runnable = new NetdEventRunnable(aCommand); + if (gWorkerThread) { + gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL); + } + } +}; + +NS_IMPL_ISUPPORTS(NetworkWorker, nsINetworkWorker) + +NetworkWorker::NetworkWorker() +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!gNetworkWorker); +} + +NetworkWorker::~NetworkWorker() +{ + MOZ_ASSERT(!gNetworkWorker); + MOZ_ASSERT(!mListener); +} + +already_AddRefed +NetworkWorker::FactoryCreate() +{ + if (XRE_GetProcessType() != GeckoProcessType_Default) { + return nullptr; + } + + MOZ_ASSERT(NS_IsMainThread()); + + if (!gNetworkWorker) { + gNetworkWorker = new NetworkWorker(); + ClearOnShutdown(&gNetworkWorker); + + gNetworkUtils = new NetworkUtils(NetworkWorker::NotifyResult); + ClearOnShutdown(&gNetworkUtils); + } + + nsRefPtr worker = gNetworkWorker.get(); + return worker.forget(); +} + +NS_IMETHODIMP +NetworkWorker::Start(nsINetworkEventListener* aListener) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aListener); + + if (mListener) { + return NS_OK; + } + + nsresult rv; + + rv = NS_NewNamedThread("NetworkWorker", getter_AddRefs(gWorkerThread)); + if (NS_FAILED(rv)) { + NS_WARNING("Can't create network control thread"); + return NS_ERROR_FAILURE; + } + + StartNetd(new NetdMessageConsumer()); + mListener = aListener; + + return NS_OK; +} + +NS_IMETHODIMP +NetworkWorker::Shutdown() +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (!mListener) { + return NS_OK; + } + + StopNetd(); + + gWorkerThread->Shutdown(); + gWorkerThread = nullptr; + + mListener = nullptr; + return NS_OK; +} + +// Receive command from main thread (NetworkService.js). +NS_IMETHODIMP +NetworkWorker::PostMessage(JS::Handle aOptions, JSContext* aCx) +{ + MOZ_ASSERT(NS_IsMainThread()); + + NetworkCommandOptions options; + if (!options.Init(aCx, aOptions)) { + NS_WARNING("Bad dictionary passed to NetworkWorker::SendCommand"); + return NS_ERROR_FAILURE; + } + + // Dispatch the command to the control thread. + NetworkParams NetworkParams(options); + nsCOMPtr runnable = new NetworkCommandDispatcher(NetworkParams); + if (gWorkerThread) { + gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL); + } + return NS_OK; +} + +void +NetworkWorker::DispatchNetworkResult(const NetworkResultOptions& aOptions) +{ + MOZ_ASSERT(NS_IsMainThread()); + + mozilla::AutoSafeJSContext cx; + JS::RootedValue val(cx); + + if (!aOptions.ToObject(cx, &val)) { + return; + } + + // Call the listener with a JS value. + if (mListener) { + mListener->OnEvent(val); + } +} + +// Callback function from network worker thread to update result on main thread. +void +NetworkWorker::NotifyResult(NetworkResultOptions& aResult) +{ + MOZ_ASSERT(!NS_IsMainThread()); + + nsCOMPtr runnable = new NetworkResultDispatcher(aResult); + NS_DispatchToMainThread(runnable); +} + +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(NetworkWorker, + NetworkWorker::FactoryCreate) + +NS_DEFINE_NAMED_CID(NS_NETWORKWORKER_CID); + +static const mozilla::Module::CIDEntry kNetworkWorkerCIDs[] = { + { &kNS_NETWORKWORKER_CID, false, nullptr, NetworkWorkerConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kNetworkWorkerContracts[] = { + { "@mozilla.org/network/worker;1", &kNS_NETWORKWORKER_CID }, + { nullptr } +}; + +static const mozilla::Module kNetworkWorkerModule = { + mozilla::Module::kVersion, + kNetworkWorkerCIDs, + kNetworkWorkerContracts, + nullptr +}; + +} // namespace mozilla + +NSMODULE_DEFN(NetworkWorkerModule) = &kNetworkWorkerModule;