dom/wifi/WifiProxyService.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include "WifiProxyService.h"
michael@0 6 #include "nsServiceManagerUtils.h"
michael@0 7 #include "mozilla/ModuleUtils.h"
michael@0 8 #include "mozilla/ClearOnShutdown.h"
michael@0 9 #include "nsXULAppAPI.h"
michael@0 10 #include "WifiUtils.h"
michael@0 11 #include "nsCxPusher.h"
michael@0 12
michael@0 13 #ifdef MOZ_TASK_TRACER
michael@0 14 #include "GeckoTaskTracer.h"
michael@0 15 using namespace mozilla::tasktracer;
michael@0 16 #endif
michael@0 17
michael@0 18 #define NS_WIFIPROXYSERVICE_CID \
michael@0 19 { 0xc6c9be7e, 0x744f, 0x4222, {0xb2, 0x03, 0xcd, 0x55, 0xdf, 0xc8, 0xbc, 0x12} }
michael@0 20
michael@0 21 using namespace mozilla;
michael@0 22 using namespace mozilla::dom;
michael@0 23
michael@0 24 namespace mozilla {
michael@0 25
michael@0 26 // The singleton Wifi service, to be used on the main thread.
michael@0 27 static StaticRefPtr<WifiProxyService> gWifiProxyService;
michael@0 28
michael@0 29 // The singleton supplicant class, that can be used on any thread.
michael@0 30 static nsAutoPtr<WpaSupplicant> gWpaSupplicant;
michael@0 31
michael@0 32 // Runnable used dispatch the WaitForEvent result on the main thread.
michael@0 33 class WifiEventDispatcher : public nsRunnable
michael@0 34 {
michael@0 35 public:
michael@0 36 WifiEventDispatcher(const nsAString& aEvent, const nsACString& aInterface)
michael@0 37 : mEvent(aEvent)
michael@0 38 , mInterface(aInterface)
michael@0 39 {
michael@0 40 MOZ_ASSERT(!NS_IsMainThread());
michael@0 41 }
michael@0 42
michael@0 43 NS_IMETHOD Run()
michael@0 44 {
michael@0 45 MOZ_ASSERT(NS_IsMainThread());
michael@0 46 gWifiProxyService->DispatchWifiEvent(mEvent, mInterface);
michael@0 47 return NS_OK;
michael@0 48 }
michael@0 49
michael@0 50 private:
michael@0 51 nsString mEvent;
michael@0 52 nsCString mInterface;
michael@0 53 };
michael@0 54
michael@0 55 // Runnable used to call WaitForEvent on the event thread.
michael@0 56 class EventRunnable : public nsRunnable
michael@0 57 {
michael@0 58 public:
michael@0 59 EventRunnable(const nsACString& aInterface)
michael@0 60 : mInterface(aInterface)
michael@0 61 {
michael@0 62 MOZ_ASSERT(NS_IsMainThread());
michael@0 63 }
michael@0 64
michael@0 65 NS_IMETHOD Run()
michael@0 66 {
michael@0 67 MOZ_ASSERT(!NS_IsMainThread());
michael@0 68 nsAutoString event;
michael@0 69 gWpaSupplicant->WaitForEvent(event, mInterface);
michael@0 70 if (!event.IsEmpty()) {
michael@0 71 #ifdef MOZ_TASK_TRACER
michael@0 72 // Make wifi initialization events to be the source events of TaskTracer,
michael@0 73 // and originate the rest correlation tasks from here.
michael@0 74 AutoSourceEvent taskTracerEvent(SourceEventType::WIFI);
michael@0 75 AddLabel("%s %s", mInterface.get(), NS_ConvertUTF16toUTF8(event).get());
michael@0 76 #endif
michael@0 77 nsCOMPtr<nsIRunnable> runnable = new WifiEventDispatcher(event, mInterface);
michael@0 78 NS_DispatchToMainThread(runnable);
michael@0 79 }
michael@0 80 return NS_OK;
michael@0 81 }
michael@0 82
michael@0 83 private:
michael@0 84 nsCString mInterface;
michael@0 85 };
michael@0 86
michael@0 87 // Runnable used dispatch the Command result on the main thread.
michael@0 88 class WifiResultDispatcher : public nsRunnable
michael@0 89 {
michael@0 90 public:
michael@0 91 WifiResultDispatcher(WifiResultOptions& aResult, const nsACString& aInterface)
michael@0 92 : mInterface(aInterface)
michael@0 93 {
michael@0 94 MOZ_ASSERT(!NS_IsMainThread());
michael@0 95
michael@0 96 // XXX: is there a better way to copy webidl dictionnaries?
michael@0 97 // the copy constructor is private.
michael@0 98 #define COPY_FIELD(prop) mResult.prop = aResult.prop;
michael@0 99
michael@0 100 COPY_FIELD(mId)
michael@0 101 COPY_FIELD(mStatus)
michael@0 102 COPY_FIELD(mReply)
michael@0 103 COPY_FIELD(mRoute)
michael@0 104 COPY_FIELD(mError)
michael@0 105 COPY_FIELD(mValue)
michael@0 106 COPY_FIELD(mIpaddr_str)
michael@0 107 COPY_FIELD(mGateway_str)
michael@0 108 COPY_FIELD(mDns1_str)
michael@0 109 COPY_FIELD(mDns2_str)
michael@0 110 COPY_FIELD(mMask_str)
michael@0 111 COPY_FIELD(mServer_str)
michael@0 112 COPY_FIELD(mVendor_str)
michael@0 113 COPY_FIELD(mLease)
michael@0 114 COPY_FIELD(mMask)
michael@0 115 COPY_FIELD(mIpaddr)
michael@0 116 COPY_FIELD(mGateway)
michael@0 117 COPY_FIELD(mDns1)
michael@0 118 COPY_FIELD(mDns2)
michael@0 119 COPY_FIELD(mServer)
michael@0 120
michael@0 121 #undef COPY_FIELD
michael@0 122 }
michael@0 123
michael@0 124 NS_IMETHOD Run()
michael@0 125 {
michael@0 126 MOZ_ASSERT(NS_IsMainThread());
michael@0 127 gWifiProxyService->DispatchWifiResult(mResult, mInterface);
michael@0 128 return NS_OK;
michael@0 129 }
michael@0 130
michael@0 131 private:
michael@0 132 WifiResultOptions mResult;
michael@0 133 nsCString mInterface;
michael@0 134 };
michael@0 135
michael@0 136 // Runnable used to call SendCommand on the control thread.
michael@0 137 class ControlRunnable : public nsRunnable
michael@0 138 {
michael@0 139 public:
michael@0 140 ControlRunnable(CommandOptions aOptions, const nsACString& aInterface)
michael@0 141 : mOptions(aOptions)
michael@0 142 , mInterface(aInterface)
michael@0 143 {
michael@0 144 MOZ_ASSERT(NS_IsMainThread());
michael@0 145 }
michael@0 146
michael@0 147 NS_IMETHOD Run()
michael@0 148 {
michael@0 149 WifiResultOptions result;
michael@0 150 if (gWpaSupplicant->ExecuteCommand(mOptions, result, mInterface)) {
michael@0 151 nsCOMPtr<nsIRunnable> runnable = new WifiResultDispatcher(result, mInterface);
michael@0 152 NS_DispatchToMainThread(runnable);
michael@0 153 }
michael@0 154 return NS_OK;
michael@0 155 }
michael@0 156 private:
michael@0 157 CommandOptions mOptions;
michael@0 158 nsCString mInterface;
michael@0 159 };
michael@0 160
michael@0 161 NS_IMPL_ISUPPORTS(WifiProxyService, nsIWifiProxyService)
michael@0 162
michael@0 163 WifiProxyService::WifiProxyService()
michael@0 164 {
michael@0 165 MOZ_ASSERT(NS_IsMainThread());
michael@0 166 MOZ_ASSERT(!gWifiProxyService);
michael@0 167 }
michael@0 168
michael@0 169 WifiProxyService::~WifiProxyService()
michael@0 170 {
michael@0 171 MOZ_ASSERT(!gWifiProxyService);
michael@0 172 }
michael@0 173
michael@0 174 already_AddRefed<WifiProxyService>
michael@0 175 WifiProxyService::FactoryCreate()
michael@0 176 {
michael@0 177 if (XRE_GetProcessType() != GeckoProcessType_Default) {
michael@0 178 return nullptr;
michael@0 179 }
michael@0 180
michael@0 181 MOZ_ASSERT(NS_IsMainThread());
michael@0 182
michael@0 183 if (!gWifiProxyService) {
michael@0 184 gWifiProxyService = new WifiProxyService();
michael@0 185 ClearOnShutdown(&gWifiProxyService);
michael@0 186
michael@0 187 gWpaSupplicant = new WpaSupplicant();
michael@0 188 ClearOnShutdown(&gWpaSupplicant);
michael@0 189 }
michael@0 190
michael@0 191 nsRefPtr<WifiProxyService> service = gWifiProxyService.get();
michael@0 192 return service.forget();
michael@0 193 }
michael@0 194
michael@0 195 NS_IMETHODIMP
michael@0 196 WifiProxyService::Start(nsIWifiEventListener* aListener,
michael@0 197 const char ** aInterfaces,
michael@0 198 uint32_t aNumOfInterfaces)
michael@0 199 {
michael@0 200 MOZ_ASSERT(NS_IsMainThread());
michael@0 201 MOZ_ASSERT(aListener);
michael@0 202
michael@0 203 nsresult rv;
michael@0 204
michael@0 205 // Since EventRunnable runs in the manner of blocking, we have to
michael@0 206 // spin a thread for each interface.
michael@0 207 // (See the WpaSupplicant::WaitForEvent)
michael@0 208 mEventThreadList.SetLength(aNumOfInterfaces);
michael@0 209 for (uint32_t i = 0; i < aNumOfInterfaces; i++) {
michael@0 210 mEventThreadList[i].mInterface = aInterfaces[i];
michael@0 211 rv = NS_NewThread(getter_AddRefs(mEventThreadList[i].mThread));
michael@0 212 if (NS_FAILED(rv)) {
michael@0 213 NS_WARNING("Can't create wifi event thread");
michael@0 214 Shutdown();
michael@0 215 return NS_ERROR_FAILURE;
michael@0 216 }
michael@0 217 }
michael@0 218
michael@0 219 rv = NS_NewThread(getter_AddRefs(mControlThread));
michael@0 220 if (NS_FAILED(rv)) {
michael@0 221 NS_WARNING("Can't create wifi control thread");
michael@0 222 Shutdown();
michael@0 223 return NS_ERROR_FAILURE;
michael@0 224 }
michael@0 225
michael@0 226 mListener = aListener;
michael@0 227
michael@0 228 return NS_OK;
michael@0 229 }
michael@0 230
michael@0 231 NS_IMETHODIMP
michael@0 232 WifiProxyService::Shutdown()
michael@0 233 {
michael@0 234 MOZ_ASSERT(NS_IsMainThread());
michael@0 235 for (size_t i = 0; i < mEventThreadList.Length(); i++) {
michael@0 236 if (mEventThreadList[i].mThread) {
michael@0 237 mEventThreadList[i].mThread->Shutdown();
michael@0 238 mEventThreadList[i].mThread = nullptr;
michael@0 239 }
michael@0 240 }
michael@0 241 mEventThreadList.Clear();
michael@0 242 if (mControlThread) {
michael@0 243 mControlThread->Shutdown();
michael@0 244 mControlThread = nullptr;
michael@0 245 }
michael@0 246 return NS_OK;
michael@0 247 }
michael@0 248
michael@0 249 NS_IMETHODIMP
michael@0 250 WifiProxyService::SendCommand(JS::Handle<JS::Value> aOptions,
michael@0 251 const nsACString& aInterface,
michael@0 252 JSContext* aCx)
michael@0 253 {
michael@0 254 MOZ_ASSERT(NS_IsMainThread());
michael@0 255 WifiCommandOptions options;
michael@0 256
michael@0 257 if (!options.Init(aCx, aOptions)) {
michael@0 258 NS_WARNING("Bad dictionary passed to WifiProxyService::SendCommand");
michael@0 259 return NS_ERROR_FAILURE;
michael@0 260 }
michael@0 261
michael@0 262 // Dispatch the command to the control thread.
michael@0 263 CommandOptions commandOptions(options);
michael@0 264 nsCOMPtr<nsIRunnable> runnable = new ControlRunnable(commandOptions, aInterface);
michael@0 265 mControlThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
michael@0 266 return NS_OK;
michael@0 267 }
michael@0 268
michael@0 269 NS_IMETHODIMP
michael@0 270 WifiProxyService::WaitForEvent(const nsACString& aInterface)
michael@0 271 {
michael@0 272 MOZ_ASSERT(NS_IsMainThread());
michael@0 273
michael@0 274 // Dispatch to the event thread which has the given interface name
michael@0 275 for (size_t i = 0; i < mEventThreadList.Length(); i++) {
michael@0 276 if (mEventThreadList[i].mInterface.Equals(aInterface)) {
michael@0 277 nsCOMPtr<nsIRunnable> runnable = new EventRunnable(aInterface);
michael@0 278 mEventThreadList[i].mThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
michael@0 279 return NS_OK;
michael@0 280 }
michael@0 281 }
michael@0 282
michael@0 283 return NS_ERROR_FAILURE;
michael@0 284 }
michael@0 285
michael@0 286 void
michael@0 287 WifiProxyService::DispatchWifiResult(const WifiResultOptions& aOptions, const nsACString& aInterface)
michael@0 288 {
michael@0 289 MOZ_ASSERT(NS_IsMainThread());
michael@0 290
michael@0 291 mozilla::AutoSafeJSContext cx;
michael@0 292 JS::Rooted<JS::Value> val(cx);
michael@0 293
michael@0 294 if (!aOptions.ToObject(cx, &val)) {
michael@0 295 return;
michael@0 296 }
michael@0 297
michael@0 298 // Call the listener with a JS value.
michael@0 299 mListener->OnCommand(val, aInterface);
michael@0 300 }
michael@0 301
michael@0 302 void
michael@0 303 WifiProxyService::DispatchWifiEvent(const nsAString& aEvent, const nsACString& aInterface)
michael@0 304 {
michael@0 305 MOZ_ASSERT(NS_IsMainThread());
michael@0 306 nsAutoString event;
michael@0 307 if (StringBeginsWith(aEvent, NS_LITERAL_STRING("IFNAME"))) {
michael@0 308 // Jump over IFNAME for gonk-kk.
michael@0 309 event = Substring(aEvent, aEvent.FindChar(' ') + 1);
michael@0 310 }
michael@0 311 else {
michael@0 312 event = aEvent;
michael@0 313 }
michael@0 314 // Call the listener.
michael@0 315 mListener->OnWaitEvent(event, aInterface);
michael@0 316 }
michael@0 317
michael@0 318 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(WifiProxyService,
michael@0 319 WifiProxyService::FactoryCreate)
michael@0 320
michael@0 321 NS_DEFINE_NAMED_CID(NS_WIFIPROXYSERVICE_CID);
michael@0 322
michael@0 323 static const mozilla::Module::CIDEntry kWifiProxyServiceCIDs[] = {
michael@0 324 { &kNS_WIFIPROXYSERVICE_CID, false, nullptr, WifiProxyServiceConstructor },
michael@0 325 { nullptr }
michael@0 326 };
michael@0 327
michael@0 328 static const mozilla::Module::ContractIDEntry kWifiProxyServiceContracts[] = {
michael@0 329 { "@mozilla.org/wifi/service;1", &kNS_WIFIPROXYSERVICE_CID },
michael@0 330 { nullptr }
michael@0 331 };
michael@0 332
michael@0 333 static const mozilla::Module kWifiProxyServiceModule = {
michael@0 334 mozilla::Module::kVersion,
michael@0 335 kWifiProxyServiceCIDs,
michael@0 336 kWifiProxyServiceContracts,
michael@0 337 nullptr
michael@0 338 };
michael@0 339
michael@0 340 } // namespace mozilla
michael@0 341
michael@0 342 NSMODULE_DEFN(WifiProxyServiceModule) = &kWifiProxyServiceModule;

mercurial