1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/system/gonk/NetworkWorker.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,287 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "NetworkWorker.h" 1.9 +#include "NetworkUtils.h" 1.10 +#include <nsThreadUtils.h> 1.11 +#include "mozilla/ModuleUtils.h" 1.12 +#include "mozilla/ClearOnShutdown.h" 1.13 +#include "nsXULAppAPI.h" 1.14 +#include "nsCxPusher.h" 1.15 + 1.16 +#define NS_NETWORKWORKER_CID \ 1.17 + { 0x6df093e1, 0x8127, 0x4fa7, {0x90, 0x13, 0xa3, 0xaa, 0xa7, 0x79, 0xbb, 0xdd} } 1.18 + 1.19 +using namespace mozilla; 1.20 +using namespace mozilla::dom; 1.21 +using namespace mozilla::ipc; 1.22 + 1.23 +namespace mozilla { 1.24 + 1.25 +nsCOMPtr<nsIThread> gWorkerThread; 1.26 + 1.27 +// The singleton network worker, to be used on the main thread. 1.28 +StaticRefPtr<NetworkWorker> gNetworkWorker; 1.29 + 1.30 +// The singleton networkutils class, that can be used on any thread. 1.31 +static nsAutoPtr<NetworkUtils> gNetworkUtils; 1.32 + 1.33 +// Runnable used dispatch command result on the main thread. 1.34 +class NetworkResultDispatcher : public nsRunnable 1.35 +{ 1.36 +public: 1.37 + NetworkResultDispatcher(const NetworkResultOptions& aResult) 1.38 + { 1.39 + MOZ_ASSERT(!NS_IsMainThread()); 1.40 + 1.41 +#define COPY_FIELD(prop) mResult.prop = aResult.prop; 1.42 + COPY_FIELD(mId) 1.43 + COPY_FIELD(mRet) 1.44 + COPY_FIELD(mBroadcast) 1.45 + COPY_FIELD(mTopic) 1.46 + COPY_FIELD(mReason) 1.47 + COPY_FIELD(mResultCode) 1.48 + COPY_FIELD(mResultReason) 1.49 + COPY_FIELD(mError) 1.50 + COPY_FIELD(mRxBytes) 1.51 + COPY_FIELD(mTxBytes) 1.52 + COPY_FIELD(mDate) 1.53 + COPY_FIELD(mEnable) 1.54 + COPY_FIELD(mResult) 1.55 + COPY_FIELD(mSuccess) 1.56 + COPY_FIELD(mCurExternalIfname) 1.57 + COPY_FIELD(mCurInternalIfname) 1.58 +#undef COPY_FIELD 1.59 + } 1.60 + 1.61 + NS_IMETHOD Run() 1.62 + { 1.63 + MOZ_ASSERT(NS_IsMainThread()); 1.64 + 1.65 + if (gNetworkWorker) { 1.66 + gNetworkWorker->DispatchNetworkResult(mResult); 1.67 + } 1.68 + return NS_OK; 1.69 + } 1.70 +private: 1.71 + NetworkResultOptions mResult; 1.72 +}; 1.73 + 1.74 +// Runnable used dispatch netd command on the worker thread. 1.75 +class NetworkCommandDispatcher : public nsRunnable 1.76 +{ 1.77 +public: 1.78 + NetworkCommandDispatcher(const NetworkParams& aParams) 1.79 + : mParams(aParams) 1.80 + { 1.81 + MOZ_ASSERT(NS_IsMainThread()); 1.82 + } 1.83 + 1.84 + NS_IMETHOD Run() 1.85 + { 1.86 + MOZ_ASSERT(!NS_IsMainThread()); 1.87 + 1.88 + if (gNetworkUtils) { 1.89 + gNetworkUtils->ExecuteCommand(mParams); 1.90 + } 1.91 + return NS_OK; 1.92 + } 1.93 +private: 1.94 + NetworkParams mParams; 1.95 +}; 1.96 + 1.97 +// Runnable used dispatch netd result on the worker thread. 1.98 +class NetdEventRunnable : public nsRunnable 1.99 +{ 1.100 +public: 1.101 + NetdEventRunnable(NetdCommand* aCommand) 1.102 + : mCommand(aCommand) 1.103 + { 1.104 + MOZ_ASSERT(!NS_IsMainThread()); 1.105 + } 1.106 + 1.107 + NS_IMETHOD Run() 1.108 + { 1.109 + MOZ_ASSERT(!NS_IsMainThread()); 1.110 + 1.111 + if (gNetworkUtils) { 1.112 + gNetworkUtils->onNetdMessage(mCommand); 1.113 + } 1.114 + return NS_OK; 1.115 + } 1.116 + 1.117 +private: 1.118 + nsAutoPtr<NetdCommand> mCommand; 1.119 +}; 1.120 + 1.121 +class NetdMessageConsumer : public NetdConsumer 1.122 +{ 1.123 +public: 1.124 + NetdMessageConsumer() 1.125 + { 1.126 + MOZ_ASSERT(NS_IsMainThread()); 1.127 + } 1.128 + 1.129 + void MessageReceived(NetdCommand* aCommand) 1.130 + { 1.131 + MOZ_ASSERT(!NS_IsMainThread()); 1.132 + 1.133 + nsCOMPtr<nsIRunnable> runnable = new NetdEventRunnable(aCommand); 1.134 + if (gWorkerThread) { 1.135 + gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL); 1.136 + } 1.137 + } 1.138 +}; 1.139 + 1.140 +NS_IMPL_ISUPPORTS(NetworkWorker, nsINetworkWorker) 1.141 + 1.142 +NetworkWorker::NetworkWorker() 1.143 +{ 1.144 + MOZ_ASSERT(NS_IsMainThread()); 1.145 + MOZ_ASSERT(!gNetworkWorker); 1.146 +} 1.147 + 1.148 +NetworkWorker::~NetworkWorker() 1.149 +{ 1.150 + MOZ_ASSERT(!gNetworkWorker); 1.151 + MOZ_ASSERT(!mListener); 1.152 +} 1.153 + 1.154 +already_AddRefed<NetworkWorker> 1.155 +NetworkWorker::FactoryCreate() 1.156 +{ 1.157 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.158 + return nullptr; 1.159 + } 1.160 + 1.161 + MOZ_ASSERT(NS_IsMainThread()); 1.162 + 1.163 + if (!gNetworkWorker) { 1.164 + gNetworkWorker = new NetworkWorker(); 1.165 + ClearOnShutdown(&gNetworkWorker); 1.166 + 1.167 + gNetworkUtils = new NetworkUtils(NetworkWorker::NotifyResult); 1.168 + ClearOnShutdown(&gNetworkUtils); 1.169 + } 1.170 + 1.171 + nsRefPtr<NetworkWorker> worker = gNetworkWorker.get(); 1.172 + return worker.forget(); 1.173 +} 1.174 + 1.175 +NS_IMETHODIMP 1.176 +NetworkWorker::Start(nsINetworkEventListener* aListener) 1.177 +{ 1.178 + MOZ_ASSERT(NS_IsMainThread()); 1.179 + MOZ_ASSERT(aListener); 1.180 + 1.181 + if (mListener) { 1.182 + return NS_OK; 1.183 + } 1.184 + 1.185 + nsresult rv; 1.186 + 1.187 + rv = NS_NewNamedThread("NetworkWorker", getter_AddRefs(gWorkerThread)); 1.188 + if (NS_FAILED(rv)) { 1.189 + NS_WARNING("Can't create network control thread"); 1.190 + return NS_ERROR_FAILURE; 1.191 + } 1.192 + 1.193 + StartNetd(new NetdMessageConsumer()); 1.194 + mListener = aListener; 1.195 + 1.196 + return NS_OK; 1.197 +} 1.198 + 1.199 +NS_IMETHODIMP 1.200 +NetworkWorker::Shutdown() 1.201 +{ 1.202 + MOZ_ASSERT(NS_IsMainThread()); 1.203 + 1.204 + if (!mListener) { 1.205 + return NS_OK; 1.206 + } 1.207 + 1.208 + StopNetd(); 1.209 + 1.210 + gWorkerThread->Shutdown(); 1.211 + gWorkerThread = nullptr; 1.212 + 1.213 + mListener = nullptr; 1.214 + return NS_OK; 1.215 +} 1.216 + 1.217 +// Receive command from main thread (NetworkService.js). 1.218 +NS_IMETHODIMP 1.219 +NetworkWorker::PostMessage(JS::Handle<JS::Value> aOptions, JSContext* aCx) 1.220 +{ 1.221 + MOZ_ASSERT(NS_IsMainThread()); 1.222 + 1.223 + NetworkCommandOptions options; 1.224 + if (!options.Init(aCx, aOptions)) { 1.225 + NS_WARNING("Bad dictionary passed to NetworkWorker::SendCommand"); 1.226 + return NS_ERROR_FAILURE; 1.227 + } 1.228 + 1.229 + // Dispatch the command to the control thread. 1.230 + NetworkParams NetworkParams(options); 1.231 + nsCOMPtr<nsIRunnable> runnable = new NetworkCommandDispatcher(NetworkParams); 1.232 + if (gWorkerThread) { 1.233 + gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL); 1.234 + } 1.235 + return NS_OK; 1.236 +} 1.237 + 1.238 +void 1.239 +NetworkWorker::DispatchNetworkResult(const NetworkResultOptions& aOptions) 1.240 +{ 1.241 + MOZ_ASSERT(NS_IsMainThread()); 1.242 + 1.243 + mozilla::AutoSafeJSContext cx; 1.244 + JS::RootedValue val(cx); 1.245 + 1.246 + if (!aOptions.ToObject(cx, &val)) { 1.247 + return; 1.248 + } 1.249 + 1.250 + // Call the listener with a JS value. 1.251 + if (mListener) { 1.252 + mListener->OnEvent(val); 1.253 + } 1.254 +} 1.255 + 1.256 +// Callback function from network worker thread to update result on main thread. 1.257 +void 1.258 +NetworkWorker::NotifyResult(NetworkResultOptions& aResult) 1.259 +{ 1.260 + MOZ_ASSERT(!NS_IsMainThread()); 1.261 + 1.262 + nsCOMPtr<nsIRunnable> runnable = new NetworkResultDispatcher(aResult); 1.263 + NS_DispatchToMainThread(runnable); 1.264 +} 1.265 + 1.266 +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(NetworkWorker, 1.267 + NetworkWorker::FactoryCreate) 1.268 + 1.269 +NS_DEFINE_NAMED_CID(NS_NETWORKWORKER_CID); 1.270 + 1.271 +static const mozilla::Module::CIDEntry kNetworkWorkerCIDs[] = { 1.272 + { &kNS_NETWORKWORKER_CID, false, nullptr, NetworkWorkerConstructor }, 1.273 + { nullptr } 1.274 +}; 1.275 + 1.276 +static const mozilla::Module::ContractIDEntry kNetworkWorkerContracts[] = { 1.277 + { "@mozilla.org/network/worker;1", &kNS_NETWORKWORKER_CID }, 1.278 + { nullptr } 1.279 +}; 1.280 + 1.281 +static const mozilla::Module kNetworkWorkerModule = { 1.282 + mozilla::Module::kVersion, 1.283 + kNetworkWorkerCIDs, 1.284 + kNetworkWorkerContracts, 1.285 + nullptr 1.286 +}; 1.287 + 1.288 +} // namespace mozilla 1.289 + 1.290 +NSMODULE_DEFN(NetworkWorkerModule) = &kNetworkWorkerModule;