Bug 1857841 - pt 3. Add a new page kind named "fresh" r=glandium
[gecko.git] / dom / network / ConnectionWorker.cpp
blobe0773455df1cc356352aabf0eadd8ea343679f3d
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/. */
7 #include <limits>
8 #include "mozilla/Hal.h"
9 #include "ConnectionWorker.h"
10 #include "mozilla/dom/WorkerPrivate.h"
11 #include "mozilla/dom/WorkerRef.h"
12 #include "mozilla/dom/WorkerRunnable.h"
13 #include "mozilla/dom/WorkerScope.h"
15 namespace mozilla::dom::network {
17 class ConnectionProxy final : public hal::NetworkObserver {
18 public:
19 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ConnectionProxy)
21 static already_AddRefed<ConnectionProxy> Create(
22 WorkerPrivate* aWorkerPrivate, ConnectionWorker* aConnection) {
23 RefPtr<ConnectionProxy> proxy = new ConnectionProxy(aConnection);
25 RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create(
26 aWorkerPrivate, "ConnectionProxy", [proxy]() { proxy->Shutdown(); });
27 if (NS_WARN_IF(!workerRef)) {
28 return nullptr;
31 proxy->mWorkerRef = new ThreadSafeWorkerRef(workerRef);
32 return proxy.forget();
35 ThreadSafeWorkerRef* WorkerRef() const { return mWorkerRef; }
37 // For IObserver - main-thread only.
38 void Notify(const hal::NetworkInformation& aNetworkInfo) override;
40 void Shutdown();
42 void Update(ConnectionType aType, bool aIsWifi, uint32_t aDHCPGateway) {
43 MOZ_ASSERT(mConnection);
44 MOZ_ASSERT(IsCurrentThreadRunningWorker());
45 mConnection->Update(aType, aIsWifi, aDHCPGateway, true);
48 private:
49 explicit ConnectionProxy(ConnectionWorker* aConnection)
50 : mConnection(aConnection) {}
52 ~ConnectionProxy() = default;
54 // Raw pointer because the ConnectionWorker keeps alive the proxy.
55 // This is touched only on the worker-thread and it's nullified when the
56 // shutdown procedure starts.
57 ConnectionWorker* mConnection;
59 RefPtr<ThreadSafeWorkerRef> mWorkerRef;
62 namespace {
64 // This class initializes the hal observer on the main-thread.
65 class InitializeRunnable : public WorkerMainThreadRunnable {
66 private:
67 // raw pointer because this is a sync runnable.
68 ConnectionProxy* mProxy;
69 hal::NetworkInformation& mNetworkInfo;
71 public:
72 InitializeRunnable(WorkerPrivate* aWorkerPrivate, ConnectionProxy* aProxy,
73 hal::NetworkInformation& aNetworkInfo)
74 : WorkerMainThreadRunnable(aWorkerPrivate,
75 "ConnectionWorker :: Initialize"_ns),
76 mProxy(aProxy),
77 mNetworkInfo(aNetworkInfo) {
78 MOZ_ASSERT(aProxy);
79 aWorkerPrivate->AssertIsOnWorkerThread();
82 bool MainThreadRun() override {
83 MOZ_ASSERT(NS_IsMainThread());
84 hal::RegisterNetworkObserver(mProxy);
85 hal::GetCurrentNetworkInformation(&mNetworkInfo);
86 return true;
90 // This class turns down the hal observer on the main-thread.
91 class ShutdownRunnable : public WorkerMainThreadRunnable {
92 private:
93 // raw pointer because this is a sync runnable.
94 ConnectionProxy* mProxy;
96 public:
97 ShutdownRunnable(WorkerPrivate* aWorkerPrivate, ConnectionProxy* aProxy)
98 : WorkerMainThreadRunnable(aWorkerPrivate,
99 "ConnectionWorker :: Shutdown"_ns),
100 mProxy(aProxy) {
101 MOZ_ASSERT(aProxy);
102 aWorkerPrivate->AssertIsOnWorkerThread();
105 bool MainThreadRun() override {
106 MOZ_ASSERT(NS_IsMainThread());
107 hal::UnregisterNetworkObserver(mProxy);
108 return true;
112 class NotifyRunnable final : public WorkerRunnable {
113 private:
114 RefPtr<ConnectionProxy> mProxy;
116 const ConnectionType mConnectionType;
117 const bool mIsWifi;
118 const uint32_t mDHCPGateway;
120 public:
121 NotifyRunnable(WorkerPrivate* aWorkerPrivate, ConnectionProxy* aProxy,
122 ConnectionType aType, bool aIsWifi, uint32_t aDHCPGateway)
123 : WorkerRunnable(aWorkerPrivate, "NotifyRunnable"),
124 mProxy(aProxy),
125 mConnectionType(aType),
126 mIsWifi(aIsWifi),
127 mDHCPGateway(aDHCPGateway) {
128 MOZ_ASSERT(aProxy);
129 MOZ_ASSERT(NS_IsMainThread());
132 bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
133 aWorkerPrivate->AssertIsOnWorkerThread();
134 mProxy->Update(mConnectionType, mIsWifi, mDHCPGateway);
135 return true;
139 } // anonymous namespace
141 /* static */
142 already_AddRefed<ConnectionWorker> ConnectionWorker::Create(
143 WorkerPrivate* aWorkerPrivate, ErrorResult& aRv) {
144 bool shouldResistFingerprinting = aWorkerPrivate->ShouldResistFingerprinting(
145 RFPTarget::NavigatorConnection);
146 RefPtr<ConnectionWorker> c = new ConnectionWorker(shouldResistFingerprinting);
147 c->mProxy = ConnectionProxy::Create(aWorkerPrivate, c);
148 if (!c->mProxy) {
149 aRv.ThrowTypeError("The Worker thread is shutting down.");
150 return nullptr;
153 hal::NetworkInformation networkInfo;
154 RefPtr<InitializeRunnable> runnable =
155 new InitializeRunnable(aWorkerPrivate, c->mProxy, networkInfo);
157 runnable->Dispatch(Canceling, aRv);
158 if (NS_WARN_IF(aRv.Failed())) {
159 return nullptr;
162 c->Update(static_cast<ConnectionType>(networkInfo.type()),
163 networkInfo.isWifi(), networkInfo.dhcpGateway(), false);
164 return c.forget();
167 ConnectionWorker::ConnectionWorker(bool aShouldResistFingerprinting)
168 : Connection(nullptr, aShouldResistFingerprinting) {
169 MOZ_ASSERT(IsCurrentThreadRunningWorker());
172 ConnectionWorker::~ConnectionWorker() { Shutdown(); }
174 void ConnectionWorker::ShutdownInternal() {
175 MOZ_ASSERT(IsCurrentThreadRunningWorker());
176 mProxy->Shutdown();
179 void ConnectionProxy::Notify(const hal::NetworkInformation& aNetworkInfo) {
180 MOZ_ASSERT(NS_IsMainThread());
182 RefPtr<NotifyRunnable> runnable =
183 new NotifyRunnable(mWorkerRef->Private(), this,
184 static_cast<ConnectionType>(aNetworkInfo.type()),
185 aNetworkInfo.isWifi(), aNetworkInfo.dhcpGateway());
186 runnable->Dispatch();
189 void ConnectionProxy::Shutdown() {
190 MOZ_ASSERT(IsCurrentThreadRunningWorker());
192 // Already shut down.
193 if (!mConnection) {
194 return;
197 mConnection = nullptr;
199 RefPtr<ShutdownRunnable> runnable =
200 new ShutdownRunnable(mWorkerRef->Private(), this);
202 ErrorResult rv;
203 // This runnable _must_ be executed.
204 runnable->Dispatch(Killing, rv);
205 if (NS_WARN_IF(rv.Failed())) {
206 rv.SuppressException();
209 mWorkerRef = nullptr;
212 } // namespace mozilla::dom::network