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