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