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