michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsCOMPtr.h" michael@0: #include "nsProxyRelease.h" michael@0: #include "nsComponentManagerUtils.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsXPCOM.h" michael@0: #include "nsXPCOMCID.h" michael@0: #include "nsIObserver.h" michael@0: #include "nsIObserverService.h" michael@0: #include "nsWifiMonitor.h" michael@0: #include "nsWifiAccessPoint.h" michael@0: michael@0: #include "nsServiceManagerUtils.h" michael@0: #include "nsComponentManagerUtils.h" michael@0: #include "mozilla/Services.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: #if defined(PR_LOGGING) michael@0: PRLogModuleInfo *gWifiMonitorLog; michael@0: #endif michael@0: michael@0: NS_IMPL_ISUPPORTS(nsWifiMonitor, michael@0: nsIRunnable, michael@0: nsIObserver, michael@0: nsIWifiMonitor) michael@0: michael@0: nsWifiMonitor::nsWifiMonitor() michael@0: : mKeepGoing(true) michael@0: , mReentrantMonitor("nsWifiMonitor.mReentrantMonitor") michael@0: { michael@0: #if defined(PR_LOGGING) michael@0: gWifiMonitorLog = PR_NewLogModule("WifiMonitor"); michael@0: #endif michael@0: michael@0: nsCOMPtr obsSvc = mozilla::services::GetObserverService(); michael@0: if (obsSvc) michael@0: obsSvc->AddObserver(this, "xpcom-shutdown", false); michael@0: michael@0: LOG(("@@@@@ wifimonitor created\n")); michael@0: } michael@0: michael@0: nsWifiMonitor::~nsWifiMonitor() michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWifiMonitor::Observe(nsISupports *subject, const char *topic, michael@0: const char16_t *data) michael@0: { michael@0: if (!strcmp(topic, "xpcom-shutdown")) { michael@0: LOG(("Shutting down\n")); michael@0: mKeepGoing = false; michael@0: michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: mon.Notify(); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP nsWifiMonitor::StartWatching(nsIWifiListener *aListener) michael@0: { michael@0: if (!aListener) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsresult rv = NS_OK; michael@0: if (!mThread) { michael@0: rv = NS_NewThread(getter_AddRefs(mThread), this); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: } michael@0: michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: michael@0: mKeepGoing = true; michael@0: michael@0: mListeners.AppendElement(nsWifiListener(new nsMainThreadPtrHolder(aListener))); michael@0: michael@0: // tell ourselves that we have a new watcher. michael@0: mon.Notify(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsWifiMonitor::StopWatching(nsIWifiListener *aListener) michael@0: { michael@0: if (!aListener) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: LOG(("removing listener\n")); michael@0: michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: michael@0: for (uint32_t i = 0; i < mListeners.Length(); i++) { michael@0: michael@0: if (mListeners[i].mListener == aListener) { michael@0: mListeners.RemoveElementAt(i); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (mListeners.Length() == 0) { michael@0: mKeepGoing = false; michael@0: mon.Notify(); michael@0: mThread = nullptr; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: typedef nsTArray > WifiListenerArray; michael@0: michael@0: class nsPassErrorToWifiListeners MOZ_FINAL : public nsIRunnable michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIRUNNABLE michael@0: michael@0: nsPassErrorToWifiListeners(nsAutoPtr aListeners, michael@0: nsresult aResult) michael@0: : mListeners(aListeners), michael@0: mResult(aResult) michael@0: {} michael@0: michael@0: private: michael@0: nsAutoPtr mListeners; michael@0: nsresult mResult; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(nsPassErrorToWifiListeners, michael@0: nsIRunnable) michael@0: michael@0: NS_IMETHODIMP nsPassErrorToWifiListeners::Run() michael@0: { michael@0: LOG(("About to send error to the wifi listeners\n")); michael@0: for (size_t i = 0; i < mListeners->Length(); i++) { michael@0: (*mListeners)[i]->OnError(mResult); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsWifiMonitor::Run() michael@0: { michael@0: LOG(("@@@@@ wifi monitor run called\n")); michael@0: michael@0: PR_SetCurrentThreadName("Wifi Monitor"); michael@0: michael@0: nsresult rv = DoScan(); michael@0: michael@0: if (mKeepGoing && NS_FAILED(rv)) { michael@0: nsAutoPtr currentListeners( michael@0: new WifiListenerArray(mListeners.Length())); michael@0: if (!currentListeners) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: for (uint32_t i = 0; i < mListeners.Length(); i++) michael@0: currentListeners->AppendElement(mListeners[i].mListener); michael@0: michael@0: nsCOMPtr thread = do_GetMainThread(); michael@0: if (!thread) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: nsCOMPtr runnable(new nsPassErrorToWifiListeners(currentListeners, rv)); michael@0: if (!runnable) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: thread->Dispatch(runnable, NS_DISPATCH_SYNC); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: class nsCallWifiListeners MOZ_FINAL : public nsIRunnable michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIRUNNABLE michael@0: michael@0: nsCallWifiListeners(nsAutoPtr aListeners, michael@0: nsAutoPtr > aAccessPoints) michael@0: : mListeners(aListeners), michael@0: mAccessPoints(aAccessPoints) michael@0: {} michael@0: michael@0: private: michael@0: nsAutoPtr mListeners; michael@0: nsAutoPtr > mAccessPoints; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(nsCallWifiListeners, michael@0: nsIRunnable) michael@0: michael@0: NS_IMETHODIMP nsCallWifiListeners::Run() michael@0: { michael@0: LOG(("About to send data to the wifi listeners\n")); michael@0: for (size_t i = 0; i < mListeners->Length(); i++) { michael@0: (*mListeners)[i]->OnChange(mAccessPoints->Elements(), mAccessPoints->Length()); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsWifiMonitor::CallWifiListeners(const nsCOMArray &aAccessPoints, michael@0: bool aAccessPointsChanged) michael@0: { michael@0: nsAutoPtr currentListeners( michael@0: new WifiListenerArray(mListeners.Length())); michael@0: if (!currentListeners) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: michael@0: for (uint32_t i = 0; i < mListeners.Length(); i++) { michael@0: if (!mListeners[i].mHasSentData || aAccessPointsChanged) { michael@0: mListeners[i].mHasSentData = true; michael@0: currentListeners->AppendElement(mListeners[i].mListener); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (currentListeners->Length() > 0) michael@0: { michael@0: uint32_t resultCount = aAccessPoints.Count(); michael@0: nsAutoPtr > accessPoints( michael@0: new nsTArray(resultCount)); michael@0: if (!accessPoints) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: for (uint32_t i = 0; i < resultCount; i++) michael@0: accessPoints->AppendElement(aAccessPoints[i]); michael@0: michael@0: nsCOMPtr thread = do_GetMainThread(); michael@0: if (!thread) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: nsCOMPtr runnable( michael@0: new nsCallWifiListeners(currentListeners, accessPoints)); michael@0: if (!runnable) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: thread->Dispatch(runnable, NS_DISPATCH_SYNC); michael@0: } michael@0: michael@0: return NS_OK; michael@0: }