Line data Source code
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 "WorkerRunnable.h"
11 :
12 : namespace mozilla {
13 : namespace dom {
14 : namespace network {
15 :
16 : class ConnectionProxy final : public NetworkObserver
17 : , public WorkerHolder
18 : {
19 : public:
20 0 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ConnectionProxy)
21 :
22 : static already_AddRefed<ConnectionProxy>
23 0 : Create(WorkerPrivate* aWorkerPrivate, ConnectionWorker* aConnection)
24 : {
25 : RefPtr<ConnectionProxy> proxy =
26 0 : new ConnectionProxy(aWorkerPrivate, aConnection);
27 0 : if (!proxy->HoldWorker(aWorkerPrivate, Closing)) {
28 0 : proxy->mConnection = nullptr;
29 0 : return nullptr;
30 : }
31 :
32 0 : return proxy.forget();
33 : }
34 :
35 : // For IObserver - main-thread only.
36 : void Notify(const hal::NetworkInformation& aNetworkInfo) override;
37 :
38 : // Worker notification
39 0 : virtual bool Notify(Status aStatus) override
40 : {
41 0 : Shutdown();
42 0 : return true;
43 : }
44 :
45 : void Shutdown();
46 :
47 0 : void Update(ConnectionType aType, bool aIsWifi, uint32_t aDHCPGateway)
48 : {
49 0 : MOZ_ASSERT(mConnection);
50 0 : mWorkerPrivate->AssertIsOnWorkerThread();
51 0 : mConnection->Update(aType, aIsWifi, aDHCPGateway, true);
52 0 : }
53 :
54 : private:
55 0 : ConnectionProxy(WorkerPrivate* aWorkerPrivate, ConnectionWorker* aConnection)
56 0 : : mConnection(aConnection)
57 0 : , mWorkerPrivate(aWorkerPrivate)
58 : {
59 0 : MOZ_ASSERT(mWorkerPrivate);
60 0 : MOZ_ASSERT(mConnection);
61 0 : mWorkerPrivate->AssertIsOnWorkerThread();
62 0 : }
63 :
64 0 : ~ConnectionProxy() = default;
65 :
66 : // Raw pointer because the ConnectionWorker keeps alive the proxy.
67 : // This is touched only on the worker-thread and it's nullified when the
68 : // shutdown procedure starts.
69 : ConnectionWorker* mConnection;
70 :
71 : WorkerPrivate* mWorkerPrivate;
72 : };
73 :
74 : namespace {
75 :
76 : // This class initializes the hal observer on the main-thread.
77 0 : class InitializeRunnable : public WorkerMainThreadRunnable
78 : {
79 : private:
80 : // raw pointer because this is a sync runnable.
81 : ConnectionProxy* mProxy;
82 : hal::NetworkInformation& mNetworkInfo;
83 :
84 : public:
85 0 : InitializeRunnable(WorkerPrivate* aWorkerPrivate,
86 : ConnectionProxy* aProxy,
87 : hal::NetworkInformation& aNetworkInfo)
88 0 : : WorkerMainThreadRunnable(aWorkerPrivate,
89 0 : NS_LITERAL_CSTRING("ConnectionWorker :: Initialize"))
90 : , mProxy(aProxy)
91 0 : , mNetworkInfo(aNetworkInfo)
92 : {
93 0 : MOZ_ASSERT(aProxy);
94 0 : aWorkerPrivate->AssertIsOnWorkerThread();
95 0 : }
96 :
97 : bool
98 0 : MainThreadRun()
99 : {
100 0 : MOZ_ASSERT(NS_IsMainThread());
101 0 : hal::RegisterNetworkObserver(mProxy);
102 0 : hal::GetCurrentNetworkInformation(&mNetworkInfo);
103 0 : return true;
104 : }
105 : };
106 :
107 : // This class turns down the hal observer on the main-thread.
108 0 : class ShutdownRunnable : public WorkerMainThreadRunnable
109 : {
110 : private:
111 : // raw pointer because this is a sync runnable.
112 : ConnectionProxy* mProxy;
113 :
114 : public:
115 0 : ShutdownRunnable(WorkerPrivate* aWorkerPrivate, ConnectionProxy* aProxy)
116 0 : : WorkerMainThreadRunnable(aWorkerPrivate,
117 0 : NS_LITERAL_CSTRING("ConnectionWorker :: Shutdown"))
118 0 : , mProxy(aProxy)
119 : {
120 0 : MOZ_ASSERT(aProxy);
121 0 : aWorkerPrivate->AssertIsOnWorkerThread();
122 0 : }
123 :
124 : bool
125 0 : MainThreadRun()
126 : {
127 0 : MOZ_ASSERT(NS_IsMainThread());
128 0 : hal::UnregisterNetworkObserver(mProxy);
129 0 : return true;
130 : }
131 : };
132 :
133 0 : class NotifyRunnable : public WorkerRunnable
134 : {
135 : private:
136 : RefPtr<ConnectionProxy> mProxy;
137 :
138 : const ConnectionType mConnectionType;
139 : const bool mIsWifi;
140 : const uint32_t mDHCPGateway;
141 :
142 : public:
143 0 : NotifyRunnable(WorkerPrivate* aWorkerPrivate,
144 : ConnectionProxy* aProxy, ConnectionType aType,
145 : bool aIsWifi, uint32_t aDHCPGateway)
146 0 : : WorkerRunnable(aWorkerPrivate)
147 : , mProxy(aProxy)
148 : , mConnectionType(aType)
149 : , mIsWifi(aIsWifi)
150 0 : , mDHCPGateway(aDHCPGateway)
151 : {
152 0 : MOZ_ASSERT(aProxy);
153 0 : MOZ_ASSERT(NS_IsMainThread());
154 0 : }
155 :
156 : bool
157 0 : WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
158 : {
159 0 : aWorkerPrivate->AssertIsOnWorkerThread();
160 0 : mProxy->Update(mConnectionType, mIsWifi, mDHCPGateway);
161 0 : return true;
162 : }
163 : };
164 :
165 : } // anonymous namespace
166 :
167 : /* static */ already_AddRefed<ConnectionWorker>
168 0 : ConnectionWorker::Create(WorkerPrivate* aWorkerPrivate, ErrorResult& aRv)
169 : {
170 0 : RefPtr<ConnectionWorker> c = new ConnectionWorker(aWorkerPrivate);
171 0 : c->mProxy = ConnectionProxy::Create(aWorkerPrivate, c);
172 0 : if (!c->mProxy) {
173 0 : aRv.ThrowTypeError<MSG_WORKER_THREAD_SHUTTING_DOWN>();
174 0 : return nullptr;
175 : }
176 :
177 0 : hal::NetworkInformation networkInfo;
178 : RefPtr<InitializeRunnable> runnable =
179 0 : new InitializeRunnable(aWorkerPrivate, c->mProxy, networkInfo);
180 :
181 0 : runnable->Dispatch(Terminating, aRv);
182 0 : if (NS_WARN_IF(aRv.Failed())) {
183 0 : return nullptr;
184 : }
185 :
186 0 : c->Update(static_cast<ConnectionType>(networkInfo.type()),
187 0 : networkInfo.isWifi(), networkInfo.dhcpGateway(), false);
188 0 : return c.forget();
189 : }
190 :
191 0 : ConnectionWorker::ConnectionWorker(WorkerPrivate* aWorkerPrivate)
192 : : Connection(nullptr)
193 0 : , mWorkerPrivate(aWorkerPrivate)
194 : {
195 0 : MOZ_ASSERT(aWorkerPrivate);
196 0 : aWorkerPrivate->AssertIsOnWorkerThread();
197 0 : }
198 :
199 0 : ConnectionWorker::~ConnectionWorker()
200 : {
201 0 : Shutdown();
202 0 : }
203 :
204 : void
205 0 : ConnectionWorker::ShutdownInternal()
206 : {
207 0 : mWorkerPrivate->AssertIsOnWorkerThread();
208 0 : mProxy->Shutdown();
209 0 : }
210 :
211 : void
212 0 : ConnectionProxy::Notify(const hal::NetworkInformation& aNetworkInfo)
213 : {
214 0 : MOZ_ASSERT(NS_IsMainThread());
215 :
216 : RefPtr<NotifyRunnable> runnable =
217 : new NotifyRunnable(mWorkerPrivate, this,
218 0 : static_cast<ConnectionType>(aNetworkInfo.type()),
219 0 : aNetworkInfo.isWifi(), aNetworkInfo.dhcpGateway());
220 0 : runnable->Dispatch();
221 0 : }
222 :
223 : void
224 0 : ConnectionProxy::Shutdown()
225 : {
226 0 : mWorkerPrivate->AssertIsOnWorkerThread();
227 :
228 : // Already shut down.
229 0 : if (!mConnection) {
230 0 : return;
231 : }
232 :
233 0 : mConnection = nullptr;
234 :
235 : RefPtr<ShutdownRunnable> runnable =
236 0 : new ShutdownRunnable(mWorkerPrivate, this);
237 :
238 0 : ErrorResult rv;
239 : // This runnable _must_ be executed.
240 0 : runnable->Dispatch(Killing, rv);
241 0 : if (NS_WARN_IF(rv.Failed())) {
242 0 : rv.SuppressException();
243 : }
244 :
245 0 : ReleaseWorker();
246 : }
247 :
248 : } // namespace network
249 : } // namespace dom
250 : } // namespace mozilla
|