nsWifiMonitor.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. #include "nsCOMPtr.h"
  5. #include "nsProxyRelease.h"
  6. #include "nsComponentManagerUtils.h"
  7. #include "nsServiceManagerUtils.h"
  8. #include "nsThreadUtils.h"
  9. #include "nsXPCOM.h"
  10. #include "nsXPCOMCID.h"
  11. #include "nsIObserver.h"
  12. #include "nsIObserverService.h"
  13. #include "nsWifiMonitor.h"
  14. #include "nsWifiAccessPoint.h"
  15. #include "nsServiceManagerUtils.h"
  16. #include "nsComponentManagerUtils.h"
  17. #include "mozilla/Services.h"
  18. using namespace mozilla;
  19. LazyLogModule gWifiMonitorLog("WifiMonitor");
  20. NS_IMPL_ISUPPORTS(nsWifiMonitor,
  21. nsIRunnable,
  22. nsIObserver,
  23. nsIWifiMonitor)
  24. nsWifiMonitor::nsWifiMonitor()
  25. : mKeepGoing(true)
  26. , mThreadComplete(false)
  27. , mReentrantMonitor("nsWifiMonitor.mReentrantMonitor")
  28. {
  29. nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
  30. if (obsSvc)
  31. obsSvc->AddObserver(this, "xpcom-shutdown", false);
  32. LOG(("@@@@@ wifimonitor created\n"));
  33. }
  34. nsWifiMonitor::~nsWifiMonitor()
  35. {
  36. }
  37. NS_IMETHODIMP
  38. nsWifiMonitor::Observe(nsISupports *subject, const char *topic,
  39. const char16_t *data)
  40. {
  41. if (!strcmp(topic, "xpcom-shutdown")) {
  42. LOG(("Shutting down\n"));
  43. ReentrantMonitorAutoEnter mon(mReentrantMonitor);
  44. mKeepGoing = false;
  45. mon.Notify();
  46. mThread = nullptr;
  47. }
  48. return NS_OK;
  49. }
  50. NS_IMETHODIMP nsWifiMonitor::StartWatching(nsIWifiListener *aListener)
  51. {
  52. LOG(("nsWifiMonitor::StartWatching %p thread %p listener %p\n",
  53. this, mThread.get(), aListener));
  54. MOZ_ASSERT(NS_IsMainThread());
  55. if (!aListener)
  56. return NS_ERROR_NULL_POINTER;
  57. if (!mKeepGoing) {
  58. return NS_ERROR_NOT_AVAILABLE;
  59. }
  60. nsresult rv = NS_OK;
  61. ReentrantMonitorAutoEnter mon(mReentrantMonitor);
  62. if (mThreadComplete) {
  63. // generally there is just one thread for the lifetime of the service,
  64. // but if DoScan returns with an error before shutdown (i.e. !mKeepGoing)
  65. // then we will respawn the thread.
  66. LOG(("nsWifiMonitor::StartWatching %p restarting thread\n", this));
  67. mThreadComplete = false;
  68. mThread = nullptr;
  69. }
  70. if (!mThread) {
  71. rv = NS_NewThread(getter_AddRefs(mThread), this);
  72. if (NS_FAILED(rv))
  73. return rv;
  74. }
  75. mListeners.AppendElement(nsWifiListener(new nsMainThreadPtrHolder<nsIWifiListener>(aListener)));
  76. // tell ourselves that we have a new watcher.
  77. mon.Notify();
  78. return NS_OK;
  79. }
  80. NS_IMETHODIMP nsWifiMonitor::StopWatching(nsIWifiListener *aListener)
  81. {
  82. LOG(("nsWifiMonitor::StopWatching %p thread %p listener %p\n",
  83. this, mThread.get(), aListener));
  84. MOZ_ASSERT(NS_IsMainThread());
  85. if (!aListener)
  86. return NS_ERROR_NULL_POINTER;
  87. ReentrantMonitorAutoEnter mon(mReentrantMonitor);
  88. for (uint32_t i = 0; i < mListeners.Length(); i++) {
  89. if (mListeners[i].mListener == aListener) {
  90. mListeners.RemoveElementAt(i);
  91. break;
  92. }
  93. }
  94. return NS_OK;
  95. }
  96. typedef nsTArray<nsMainThreadPtrHandle<nsIWifiListener> > WifiListenerArray;
  97. class nsPassErrorToWifiListeners final : public nsIRunnable
  98. {
  99. public:
  100. NS_DECL_THREADSAFE_ISUPPORTS
  101. NS_DECL_NSIRUNNABLE
  102. nsPassErrorToWifiListeners(nsAutoPtr<WifiListenerArray> aListeners,
  103. nsresult aResult)
  104. : mListeners(aListeners),
  105. mResult(aResult)
  106. {}
  107. private:
  108. ~nsPassErrorToWifiListeners() {}
  109. nsAutoPtr<WifiListenerArray> mListeners;
  110. nsresult mResult;
  111. };
  112. NS_IMPL_ISUPPORTS(nsPassErrorToWifiListeners,
  113. nsIRunnable)
  114. NS_IMETHODIMP nsPassErrorToWifiListeners::Run()
  115. {
  116. LOG(("About to send error to the wifi listeners\n"));
  117. for (size_t i = 0; i < mListeners->Length(); i++) {
  118. (*mListeners)[i]->OnError(mResult);
  119. }
  120. return NS_OK;
  121. }
  122. NS_IMETHODIMP nsWifiMonitor::Run()
  123. {
  124. LOG(("@@@@@ wifi monitor run called\n"));
  125. PR_SetCurrentThreadName("Wifi Monitor");
  126. nsresult rv = DoScan();
  127. LOG(("@@@@@ wifi monitor run::doscan complete %x\n", rv));
  128. nsAutoPtr<WifiListenerArray> currentListeners;
  129. bool doError = false;
  130. {
  131. ReentrantMonitorAutoEnter mon(mReentrantMonitor);
  132. if (mKeepGoing && NS_FAILED(rv)) {
  133. doError = true;
  134. currentListeners = new WifiListenerArray(mListeners.Length());
  135. for (uint32_t i = 0; i < mListeners.Length(); i++)
  136. currentListeners->AppendElement(mListeners[i].mListener);
  137. }
  138. mThreadComplete = true;
  139. }
  140. if (doError) {
  141. nsCOMPtr<nsIThread> thread = do_GetMainThread();
  142. if (!thread)
  143. return NS_ERROR_UNEXPECTED;
  144. nsCOMPtr<nsIRunnable> runnable(new nsPassErrorToWifiListeners(currentListeners, rv));
  145. if (!runnable)
  146. return NS_ERROR_OUT_OF_MEMORY;
  147. thread->Dispatch(runnable, NS_DISPATCH_SYNC);
  148. }
  149. LOG(("@@@@@ wifi monitor run complete\n"));
  150. return NS_OK;
  151. }
  152. class nsCallWifiListeners final : public nsIRunnable
  153. {
  154. public:
  155. NS_DECL_THREADSAFE_ISUPPORTS
  156. NS_DECL_NSIRUNNABLE
  157. nsCallWifiListeners(nsAutoPtr<WifiListenerArray> aListeners,
  158. nsAutoPtr<nsTArray<nsIWifiAccessPoint*> > aAccessPoints)
  159. : mListeners(aListeners),
  160. mAccessPoints(aAccessPoints)
  161. {}
  162. private:
  163. ~nsCallWifiListeners() {}
  164. nsAutoPtr<WifiListenerArray> mListeners;
  165. nsAutoPtr<nsTArray<nsIWifiAccessPoint*> > mAccessPoints;
  166. };
  167. NS_IMPL_ISUPPORTS(nsCallWifiListeners,
  168. nsIRunnable)
  169. NS_IMETHODIMP nsCallWifiListeners::Run()
  170. {
  171. LOG(("About to send data to the wifi listeners\n"));
  172. for (size_t i = 0; i < mListeners->Length(); i++) {
  173. (*mListeners)[i]->OnChange(mAccessPoints->Elements(), mAccessPoints->Length());
  174. }
  175. return NS_OK;
  176. }
  177. nsresult
  178. nsWifiMonitor::CallWifiListeners(const nsCOMArray<nsWifiAccessPoint> &aAccessPoints,
  179. bool aAccessPointsChanged)
  180. {
  181. nsAutoPtr<WifiListenerArray> currentListeners;
  182. {
  183. ReentrantMonitorAutoEnter mon(mReentrantMonitor);
  184. currentListeners = new WifiListenerArray(mListeners.Length());
  185. for (uint32_t i = 0; i < mListeners.Length(); i++) {
  186. if (!mListeners[i].mHasSentData || aAccessPointsChanged) {
  187. mListeners[i].mHasSentData = true;
  188. currentListeners->AppendElement(mListeners[i].mListener);
  189. }
  190. }
  191. }
  192. if (currentListeners->Length() > 0)
  193. {
  194. uint32_t resultCount = aAccessPoints.Count();
  195. nsAutoPtr<nsTArray<nsIWifiAccessPoint*> > accessPoints(
  196. new nsTArray<nsIWifiAccessPoint *>(resultCount));
  197. if (!accessPoints)
  198. return NS_ERROR_OUT_OF_MEMORY;
  199. for (uint32_t i = 0; i < resultCount; i++)
  200. accessPoints->AppendElement(aAccessPoints[i]);
  201. nsCOMPtr<nsIThread> thread = do_GetMainThread();
  202. if (!thread)
  203. return NS_ERROR_UNEXPECTED;
  204. nsCOMPtr<nsIRunnable> runnable(
  205. new nsCallWifiListeners(currentListeners, accessPoints));
  206. if (!runnable)
  207. return NS_ERROR_OUT_OF_MEMORY;
  208. thread->Dispatch(runnable, NS_DISPATCH_SYNC);
  209. }
  210. return NS_OK;
  211. }