Source code

Revision control

Other Tools

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