Coverage Report

Created: 2018-09-25 14:53

/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
}