summaryrefslogtreecommitdiffstats
path: root/netwerk/wifi/nsWifiMonitor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/wifi/nsWifiMonitor.cpp')
-rw-r--r--netwerk/wifi/nsWifiMonitor.cpp232
1 files changed, 232 insertions, 0 deletions
diff --git a/netwerk/wifi/nsWifiMonitor.cpp b/netwerk/wifi/nsWifiMonitor.cpp
new file mode 100644
index 0000000000..b886c3c318
--- /dev/null
+++ b/netwerk/wifi/nsWifiMonitor.cpp
@@ -0,0 +1,232 @@
+/* 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 "nsCOMPtr.h"
+#include "nsProxyRelease.h"
+#include "nsComponentManagerUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsThreadUtils.h"
+#include "nsXPCOM.h"
+#include "nsXPCOMCID.h"
+#include "nsIObserver.h"
+#include "nsIObserverService.h"
+#include "nsWifiMonitor.h"
+#include "nsWifiAccessPoint.h"
+
+#include "nsServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "mozilla/IntegerPrintfMacros.h"
+#include "mozilla/Services.h"
+
+using namespace mozilla;
+
+LazyLogModule gWifiMonitorLog("WifiMonitor");
+
+NS_IMPL_ISUPPORTS(nsWifiMonitor, nsIRunnable, nsIObserver, nsIWifiMonitor)
+
+nsWifiMonitor::nsWifiMonitor()
+ : mKeepGoing(true),
+ mThreadComplete(false),
+ mReentrantMonitor("nsWifiMonitor.mReentrantMonitor") {
+ nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
+ if (obsSvc) obsSvc->AddObserver(this, "xpcom-shutdown", false);
+
+ LOG(("@@@@@ wifimonitor created\n"));
+}
+
+NS_IMETHODIMP
+nsWifiMonitor::Observe(nsISupports* subject, const char* topic,
+ const char16_t* data) {
+ if (!strcmp(topic, "xpcom-shutdown")) {
+ LOG(("Shutting down\n"));
+
+ ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+ mKeepGoing = false;
+ mon.Notify();
+ mThread = nullptr;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsWifiMonitor::StartWatching(nsIWifiListener* aListener) {
+ LOG(("nsWifiMonitor::StartWatching %p thread %p listener %p\n", this,
+ mThread.get(), aListener));
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (!aListener) return NS_ERROR_NULL_POINTER;
+ if (!mKeepGoing) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ nsresult rv = NS_OK;
+
+ ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+ if (mThreadComplete) {
+ // generally there is just one thread for the lifetime of the service,
+ // but if DoScan returns with an error before shutdown (i.e. !mKeepGoing)
+ // then we will respawn the thread.
+ LOG(("nsWifiMonitor::StartWatching %p restarting thread\n", this));
+ mThreadComplete = false;
+ mThread = nullptr;
+ }
+
+ if (!mThread) {
+ rv = NS_NewNamedThread("Wifi Monitor", getter_AddRefs(mThread), this);
+ if (NS_FAILED(rv)) return rv;
+ }
+
+ mListeners.AppendElement(
+ nsWifiListener(new nsMainThreadPtrHolder<nsIWifiListener>(
+ "nsIWifiListener", aListener)));
+
+ // tell ourselves that we have a new watcher.
+ mon.Notify();
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsWifiMonitor::StopWatching(nsIWifiListener* aListener) {
+ LOG(("nsWifiMonitor::StopWatching %p thread %p listener %p\n", this,
+ mThread.get(), aListener));
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (!aListener) return NS_ERROR_NULL_POINTER;
+
+ ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+
+ for (uint32_t i = 0; i < mListeners.Length(); i++) {
+ if (mListeners[i].mListener == aListener) {
+ mListeners.RemoveElementAt(i);
+ break;
+ }
+ }
+
+ return NS_OK;
+}
+
+typedef nsTArray<nsMainThreadPtrHandle<nsIWifiListener>> WifiListenerArray;
+
+class nsPassErrorToWifiListeners final : public nsIRunnable {
+ public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIRUNNABLE
+
+ nsPassErrorToWifiListeners(UniquePtr<WifiListenerArray>&& aListeners,
+ nsresult aResult)
+ : mListeners(std::move(aListeners)), mResult(aResult) {}
+
+ private:
+ ~nsPassErrorToWifiListeners() = default;
+ UniquePtr<WifiListenerArray> mListeners;
+ nsresult mResult;
+};
+
+NS_IMPL_ISUPPORTS(nsPassErrorToWifiListeners, nsIRunnable)
+
+NS_IMETHODIMP nsPassErrorToWifiListeners::Run() {
+ LOG(("About to send error to the wifi listeners\n"));
+ for (size_t i = 0; i < mListeners->Length(); i++) {
+ (*mListeners)[i]->OnError(mResult);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsWifiMonitor::Run() {
+ LOG(("@@@@@ wifi monitor run called\n"));
+
+ nsresult rv = DoScan();
+ LOG(("@@@@@ wifi monitor run::doscan complete %" PRIx32 "\n",
+ static_cast<uint32_t>(rv)));
+
+ UniquePtr<WifiListenerArray> currentListeners;
+ bool doError = false;
+
+ {
+ ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+ if (mKeepGoing && NS_FAILED(rv)) {
+ doError = true;
+ currentListeners = MakeUnique<WifiListenerArray>(mListeners.Length());
+ for (uint32_t i = 0; i < mListeners.Length(); i++)
+ currentListeners->AppendElement(mListeners[i].mListener);
+ }
+ mThreadComplete = true;
+ }
+
+ if (doError) {
+ nsCOMPtr<nsIEventTarget> target = GetMainThreadEventTarget();
+ if (!target) return NS_ERROR_UNEXPECTED;
+
+ nsCOMPtr<nsIRunnable> runnable(
+ new nsPassErrorToWifiListeners(std::move(currentListeners), rv));
+ if (!runnable) return NS_ERROR_OUT_OF_MEMORY;
+
+ target->Dispatch(runnable, NS_DISPATCH_SYNC);
+ }
+
+ LOG(("@@@@@ wifi monitor run complete\n"));
+ return NS_OK;
+}
+
+class nsCallWifiListeners final : public nsIRunnable {
+ public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIRUNNABLE
+
+ nsCallWifiListeners(WifiListenerArray&& aListeners,
+ nsTArray<RefPtr<nsIWifiAccessPoint>>&& aAccessPoints)
+ : mListeners(std::move(aListeners)),
+ mAccessPoints(std::move(aAccessPoints)) {}
+
+ private:
+ ~nsCallWifiListeners() = default;
+ const WifiListenerArray mListeners;
+ const nsTArray<RefPtr<nsIWifiAccessPoint>> mAccessPoints;
+};
+
+NS_IMPL_ISUPPORTS(nsCallWifiListeners, nsIRunnable)
+
+NS_IMETHODIMP nsCallWifiListeners::Run() {
+ LOG(("About to send data to the wifi listeners\n"));
+ for (auto& listener : mListeners) {
+ listener->OnChange(mAccessPoints);
+ }
+ return NS_OK;
+}
+
+nsresult nsWifiMonitor::CallWifiListeners(
+ const nsCOMArray<nsWifiAccessPoint>& aAccessPoints,
+ bool aAccessPointsChanged) {
+ WifiListenerArray currentListeners;
+ {
+ ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+
+ currentListeners.SetCapacity(mListeners.Length());
+
+ for (auto& listener : mListeners) {
+ if (!listener.mHasSentData || aAccessPointsChanged) {
+ listener.mHasSentData = true;
+ currentListeners.AppendElement(listener.mListener);
+ }
+ }
+ }
+
+ if (!currentListeners.IsEmpty()) {
+ uint32_t resultCount = aAccessPoints.Count();
+ nsTArray<RefPtr<nsIWifiAccessPoint>> accessPoints(resultCount);
+
+ for (uint32_t i = 0; i < resultCount; i++) {
+ accessPoints.AppendElement(aAccessPoints[i]);
+ }
+
+ nsCOMPtr<nsIThread> thread = do_GetMainThread();
+ if (!thread) return NS_ERROR_UNEXPECTED;
+
+ nsCOMPtr<nsIRunnable> runnable(new nsCallWifiListeners(
+ std::move(currentListeners), std::move(accessPoints)));
+ if (!runnable) return NS_ERROR_OUT_OF_MEMORY;
+
+ thread->Dispatch(runnable, NS_DISPATCH_SYNC);
+ }
+
+ return NS_OK;
+}