Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/network/ConnectionWorker.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include <limits>
8
#include "mozilla/Hal.h"
9
#include "ConnectionWorker.h"
10
#include "mozilla/dom/WorkerRef.h"
11
#include "mozilla/dom/WorkerRunnable.h"
12
13
namespace mozilla {
14
namespace dom {
15
namespace network {
16
17
class ConnectionProxy final : public hal::NetworkObserver
18
{
19
public:
20
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ConnectionProxy)
21
22
  static already_AddRefed<ConnectionProxy>
23
  Create(WorkerPrivate* aWorkerPrivate, ConnectionWorker* aConnection)
24
0
  {
25
0
    RefPtr<ConnectionProxy> proxy = new ConnectionProxy(aConnection);
26
0
27
0
    RefPtr<StrongWorkerRef> workerRef =
28
0
      StrongWorkerRef::Create(aWorkerPrivate, "ConnectionProxy",
29
0
                              [proxy]() { proxy->Shutdown(); });
30
0
    if (NS_WARN_IF(!workerRef)) {
31
0
      return nullptr;
32
0
    }
33
0
34
0
    proxy->mWorkerRef = new ThreadSafeWorkerRef(workerRef);
35
0
    return proxy.forget();
36
0
  }
37
38
0
  ThreadSafeWorkerRef* WorkerRef() const { return mWorkerRef; }
39
40
  // For IObserver - main-thread only.
41
  void Notify(const hal::NetworkInformation& aNetworkInfo) override;
42
43
  void Shutdown();
44
45
  void Update(ConnectionType aType, bool aIsWifi, uint32_t aDHCPGateway)
46
0
  {
47
0
    MOZ_ASSERT(mConnection);
48
0
    MOZ_ASSERT(IsCurrentThreadRunningWorker());
49
0
    mConnection->Update(aType, aIsWifi, aDHCPGateway, true);
50
0
  }
51
52
private:
53
  explicit ConnectionProxy(ConnectionWorker* aConnection)
54
    : mConnection(aConnection)
55
0
  {}
56
57
0
  ~ConnectionProxy() = default;
58
59
  // Raw pointer because the ConnectionWorker keeps alive the proxy.
60
  // This is touched only on the worker-thread and it's nullified when the
61
  // shutdown procedure starts.
62
  ConnectionWorker* mConnection;
63
64
  RefPtr<ThreadSafeWorkerRef> mWorkerRef;
65
};
66
67
namespace {
68
69
// This class initializes the hal observer on the main-thread.
70
class InitializeRunnable : public WorkerMainThreadRunnable
71
{
72
private:
73
  // raw pointer because this is a sync runnable.
74
  ConnectionProxy* mProxy;
75
  hal::NetworkInformation& mNetworkInfo;
76
77
public:
78
  InitializeRunnable(WorkerPrivate* aWorkerPrivate,
79
                     ConnectionProxy* aProxy,
80
                     hal::NetworkInformation& aNetworkInfo)
81
    : WorkerMainThreadRunnable(aWorkerPrivate,
82
                               NS_LITERAL_CSTRING("ConnectionWorker :: Initialize"))
83
    , mProxy(aProxy)
84
    , mNetworkInfo(aNetworkInfo)
85
0
  {
86
0
    MOZ_ASSERT(aProxy);
87
0
    aWorkerPrivate->AssertIsOnWorkerThread();
88
0
  }
89
90
  bool
91
  MainThreadRun() override
92
0
  {
93
0
    MOZ_ASSERT(NS_IsMainThread());
94
0
    hal::RegisterNetworkObserver(mProxy);
95
0
    hal::GetCurrentNetworkInformation(&mNetworkInfo);
96
0
    return true;
97
0
  }
98
};
99
100
// This class turns down the hal observer on the main-thread.
101
class ShutdownRunnable : public WorkerMainThreadRunnable
102
{
103
private:
104
  // raw pointer because this is a sync runnable.
105
  ConnectionProxy* mProxy;
106
107
public:
108
  ShutdownRunnable(WorkerPrivate* aWorkerPrivate, ConnectionProxy* aProxy)
109
    : WorkerMainThreadRunnable(aWorkerPrivate,
110
                               NS_LITERAL_CSTRING("ConnectionWorker :: Shutdown"))
111
    , mProxy(aProxy)
112
0
  {
113
0
    MOZ_ASSERT(aProxy);
114
0
    aWorkerPrivate->AssertIsOnWorkerThread();
115
0
  }
116
117
  bool
118
  MainThreadRun() override
119
0
  {
120
0
    MOZ_ASSERT(NS_IsMainThread());
121
0
    hal::UnregisterNetworkObserver(mProxy);
122
0
    return true;
123
0
  }
124
};
125
126
class NotifyRunnable : public WorkerRunnable
127
{
128
private:
129
  RefPtr<ConnectionProxy> mProxy;
130
131
  const ConnectionType mConnectionType;
132
  const bool mIsWifi;
133
  const uint32_t mDHCPGateway;
134
135
public:
136
  NotifyRunnable(WorkerPrivate* aWorkerPrivate,
137
                 ConnectionProxy* aProxy, ConnectionType aType,
138
                 bool aIsWifi, uint32_t aDHCPGateway)
139
    : WorkerRunnable(aWorkerPrivate)
140
    , mProxy(aProxy)
141
    , mConnectionType(aType)
142
    , mIsWifi(aIsWifi)
143
    , mDHCPGateway(aDHCPGateway)
144
0
  {
145
0
    MOZ_ASSERT(aProxy);
146
0
    MOZ_ASSERT(NS_IsMainThread());
147
0
  }
148
149
  bool
150
  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
151
0
  {
152
0
    aWorkerPrivate->AssertIsOnWorkerThread();
153
0
    mProxy->Update(mConnectionType, mIsWifi, mDHCPGateway);
154
0
    return true;
155
0
  }
156
};
157
158
} // anonymous namespace
159
160
/* static */ already_AddRefed<ConnectionWorker>
161
ConnectionWorker::Create(WorkerPrivate* aWorkerPrivate, ErrorResult& aRv)
162
0
{
163
0
  RefPtr<ConnectionWorker> c = new ConnectionWorker();
164
0
  c->mProxy = ConnectionProxy::Create(aWorkerPrivate, c);
165
0
  if (!c->mProxy) {
166
0
    aRv.ThrowTypeError<MSG_WORKER_THREAD_SHUTTING_DOWN>();
167
0
    return nullptr;
168
0
  }
169
0
170
0
  hal::NetworkInformation networkInfo;
171
0
  RefPtr<InitializeRunnable> runnable =
172
0
    new InitializeRunnable(aWorkerPrivate, c->mProxy, networkInfo);
173
0
174
0
  runnable->Dispatch(Canceling, aRv);
175
0
  if (NS_WARN_IF(aRv.Failed())) {
176
0
    return nullptr;
177
0
  }
178
0
179
0
  c->Update(static_cast<ConnectionType>(networkInfo.type()),
180
0
            networkInfo.isWifi(), networkInfo.dhcpGateway(), false);
181
0
  return c.forget();
182
0
}
183
184
ConnectionWorker::ConnectionWorker()
185
  : Connection(nullptr)
186
0
{
187
0
  MOZ_ASSERT(IsCurrentThreadRunningWorker());
188
0
}
189
190
ConnectionWorker::~ConnectionWorker()
191
0
{
192
0
  Shutdown();
193
0
}
194
195
void
196
ConnectionWorker::ShutdownInternal()
197
0
{
198
0
  MOZ_ASSERT(IsCurrentThreadRunningWorker());
199
0
  mProxy->Shutdown();
200
0
}
201
202
void
203
ConnectionProxy::Notify(const hal::NetworkInformation& aNetworkInfo)
204
0
{
205
0
  MOZ_ASSERT(NS_IsMainThread());
206
0
207
0
  RefPtr<NotifyRunnable> runnable =
208
0
    new NotifyRunnable(mWorkerRef->Private(), this,
209
0
                       static_cast<ConnectionType>(aNetworkInfo.type()),
210
0
                       aNetworkInfo.isWifi(), aNetworkInfo.dhcpGateway());
211
0
  runnable->Dispatch();
212
0
}
213
214
void
215
ConnectionProxy::Shutdown()
216
0
{
217
0
  MOZ_ASSERT(IsCurrentThreadRunningWorker());
218
0
219
0
  // Already shut down.
220
0
  if (!mConnection) {
221
0
    return;
222
0
  }
223
0
224
0
  mConnection = nullptr;
225
0
226
0
  RefPtr<ShutdownRunnable> runnable =
227
0
    new ShutdownRunnable(mWorkerRef->Private(), this);
228
0
229
0
  ErrorResult rv;
230
0
  // This runnable _must_ be executed.
231
0
  runnable->Dispatch(Killing, rv);
232
0
  if (NS_WARN_IF(rv.Failed())) {
233
0
    rv.SuppressException();
234
0
  }
235
0
236
0
  mWorkerRef = nullptr;
237
0
}
238
239
} // namespace network
240
} // namespace dom
241
} // namespace mozilla