Bug 1946787 - Avoid creating redundant GradientCache::OnMaxEntriesBreached tasks...
[gecko.git] / dom / serviceworkers / ServiceWorkerPrivate.h
blob8257d4ff20e285b760b02de84227d0b59876f7a8
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 #ifndef mozilla_dom_serviceworkerprivate_h
8 #define mozilla_dom_serviceworkerprivate_h
10 #include <functional>
11 #include <type_traits>
13 #include "mozilla/Attributes.h"
14 #include "mozilla/Maybe.h"
15 #include "mozilla/MozPromise.h"
16 #include "mozilla/RefPtr.h"
17 #include "mozilla/TimeStamp.h"
18 #include "mozilla/UniquePtr.h"
19 #include "mozilla/dom/FetchService.h"
20 #include "mozilla/dom/Promise.h"
21 #include "mozilla/dom/RemoteWorkerController.h"
22 #include "mozilla/dom/RemoteWorkerTypes.h"
23 #include "mozilla/dom/ServiceWorkerLifetimeExtension.h"
24 #include "mozilla/dom/ServiceWorkerOpArgs.h"
25 #include "nsCOMPtr.h"
26 #include "nsISupportsImpl.h"
27 #include "nsTArray.h"
29 #define NOTIFICATION_CLICK_EVENT_NAME u"notificationclick"
30 #define NOTIFICATION_CLOSE_EVENT_NAME u"notificationclose"
32 class nsIInterceptedChannel;
33 class nsIWorkerDebugger;
35 namespace mozilla {
37 template <typename T>
38 class Maybe;
40 class JSObjectHolder;
42 namespace dom {
44 class PostMessageSource;
45 class RemoteWorkerControllerChild;
46 class ServiceWorkerCloneData;
47 class ServiceWorkerInfo;
48 class ServiceWorkerPrivate;
49 class ServiceWorkerRegistrationInfo;
51 namespace ipc {
52 class StructuredCloneData;
53 } // namespace ipc
55 class LifeCycleEventCallback : public Runnable {
56 public:
57 LifeCycleEventCallback() : Runnable("dom::LifeCycleEventCallback") {}
59 // Called on the worker thread.
60 virtual void SetResult(bool aResult) = 0;
63 // Used to keep track of pending waitUntil as well as in-flight extendable
64 // events. When the last token is released, we attempt to terminate the worker.
65 class KeepAliveToken final : public nsISupports {
66 public:
67 NS_DECL_ISUPPORTS
69 explicit KeepAliveToken(ServiceWorkerPrivate* aPrivate);
71 private:
72 ~KeepAliveToken();
74 RefPtr<ServiceWorkerPrivate> mPrivate;
77 class ServiceWorkerPrivate final : public RemoteWorkerObserver {
78 friend class KeepAliveToken;
80 public:
81 NS_INLINE_DECL_REFCOUNTING(ServiceWorkerPrivate, override);
83 using PromiseExtensionWorkerHasListener = MozPromise<bool, nsresult, false>;
85 public:
86 explicit ServiceWorkerPrivate(ServiceWorkerInfo* aInfo);
88 Maybe<ClientInfo> GetClientInfo() { return mClientInfo; }
90 nsresult SendMessageEvent(
91 RefPtr<ServiceWorkerCloneData>&& aData,
92 const ServiceWorkerLifetimeExtension& aLifetimeExtension,
93 const PostMessageSource& aSource);
95 // This is used to validate the worker script and continue the installation
96 // process.
97 nsresult CheckScriptEvaluation(
98 const ServiceWorkerLifetimeExtension& aLifetimeExtension,
99 RefPtr<LifeCycleEventCallback> aCallback);
101 nsresult SendLifeCycleEvent(
102 const nsAString& aEventType,
103 const ServiceWorkerLifetimeExtension& aLifetimeExtension,
104 const RefPtr<LifeCycleEventCallback>& aCallback);
106 nsresult SendPushEvent(const nsAString& aMessageId,
107 const Maybe<nsTArray<uint8_t>>& aData,
108 RefPtr<ServiceWorkerRegistrationInfo> aRegistration);
110 nsresult SendPushSubscriptionChangeEvent();
112 nsresult SendNotificationEvent(const nsAString& aEventName,
113 const nsAString& aID, const nsAString& aTitle,
114 const nsAString& aDir, const nsAString& aLang,
115 const nsAString& aBody, const nsAString& aTag,
116 const nsAString& aIcon, const nsAString& aData,
117 const nsAString& aScope);
119 nsresult SendFetchEvent(nsCOMPtr<nsIInterceptedChannel> aChannel,
120 nsILoadGroup* aLoadGroup, const nsAString& aClientId,
121 const nsAString& aResultingClientId);
123 Result<RefPtr<PromiseExtensionWorkerHasListener>, nsresult>
124 WakeForExtensionAPIEvent(const nsAString& aExtensionAPINamespace,
125 const nsAString& aEXtensionAPIEventName);
127 // This will terminate the current running worker thread and drop the
128 // workerPrivate reference.
129 // Called by ServiceWorkerInfo when [[Clear Registration]] is invoked
130 // or whenever the spec mandates that we terminate the worker.
131 // This is a no-op if the worker has already been stopped.
133 // Now takes an optional promise that will be resolved when the worker is
134 // dead, including if the worker was not running at all.
135 void TerminateWorker(Maybe<RefPtr<Promise>> aMaybePromise = Nothing());
137 void NoteDeadServiceWorkerInfo();
139 void NoteStoppedControllingDocuments();
141 void UpdateState(ServiceWorkerState aState);
143 void UpdateIsOnContentBlockingAllowList(bool aOnContentBlockingAllowList);
145 nsresult GetDebugger(nsIWorkerDebugger** aResult);
147 nsresult AttachDebugger();
149 nsresult DetachDebugger();
151 // Return the current lifetime deadline for this ServiceWorker; this value may
152 // be null or in the past.
154 // This value always only reflects the explicit lifetime extensions
155 // resulting from functional events and will never reflect the extra "grace
156 // period".
157 TimeStamp GetLifetimeDeadline() { return mIdleDeadline; }
159 uint32_t GetLaunchCount() { return mLaunchCount; }
161 bool IsIdle() const;
163 // This promise is used schedule clearing of the owning registrations and its
164 // associated Service Workers if that registration becomes "unreachable" by
165 // the ServiceWorkerManager. This occurs under two conditions, which are the
166 // preconditions to calling this method:
167 // - The owning registration must be unregistered.
168 // - The associated Service Worker must *not* be controlling clients.
170 // Additionally, perhaps stating the obvious, the associated Service Worker
171 // must *not* be idle (whatever must be done "when idle" can just be done
172 // immediately).
173 RefPtr<GenericPromise> GetIdlePromise();
175 void SetHandlesFetch(bool aValue);
177 RefPtr<GenericPromise> SetSkipWaitingFlag();
179 static void RunningShutdown() {
180 // Force a final update of the number of running ServiceWorkers
181 UpdateRunning(0, 0);
182 MOZ_ASSERT(sRunningServiceWorkers == 0);
183 MOZ_ASSERT(sRunningServiceWorkersFetch == 0);
187 * Update Telemetry for # of running ServiceWorkers
189 static void UpdateRunning(int32_t aDelta, int32_t aFetchDelta);
191 private:
192 // Timer callbacks
193 void NoteIdleWorkerCallback(nsITimer* aTimer);
195 void TerminateWorkerCallback(nsITimer* aTimer);
197 void RenewKeepAliveToken(
198 const ServiceWorkerLifetimeExtension& aLifetimeExtension);
200 void ResetIdleTimeout(
201 const ServiceWorkerLifetimeExtension& aLifetimeExtension);
203 void AddToken();
205 void ReleaseToken();
207 already_AddRefed<KeepAliveToken> CreateEventKeepAliveToken();
209 nsresult SpawnWorkerIfNeeded(
210 const ServiceWorkerLifetimeExtension& aLifetimeExtension);
212 ~ServiceWorkerPrivate();
214 nsresult Initialize();
216 void RegenerateClientInfo();
219 * RemoteWorkerObserver
221 void CreationFailed() override;
223 void CreationSucceeded() override;
225 void ErrorReceived(const ErrorValue& aError) override;
227 void LockNotified(bool aCreated) final {
228 // no-op for service workers
231 void WebTransportNotified(bool aCreated) final {
232 // no-op for service workers
235 void Terminated() override;
237 // Refreshes only the parts of mRemoteWorkerData that may change over time.
238 void RefreshRemoteWorkerData(
239 const RefPtr<ServiceWorkerRegistrationInfo>& aRegistration);
241 nsresult SendPushEventInternal(
242 RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
243 ServiceWorkerPushEventOpArgs&& aArgs);
245 // Setup the navigation preload by the intercepted channel and the
246 // RegistrationInfo.
247 RefPtr<FetchServicePromises> SetupNavigationPreload(
248 nsCOMPtr<nsIInterceptedChannel>& aChannel,
249 const RefPtr<ServiceWorkerRegistrationInfo>& aRegistration);
251 nsresult SendFetchEventInternal(
252 RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
253 ParentToParentServiceWorkerFetchEventOpArgs&& aArgs,
254 nsCOMPtr<nsIInterceptedChannel>&& aChannel,
255 RefPtr<FetchServicePromises>&& aPreloadResponseReadyPromises);
257 void Shutdown(Maybe<RefPtr<Promise>>&& aMaybePromise = Nothing());
259 RefPtr<GenericNonExclusivePromise> ShutdownInternal(
260 uint32_t aShutdownStateId);
262 nsresult ExecServiceWorkerOp(
263 ServiceWorkerOpArgs&& aArgs,
264 const ServiceWorkerLifetimeExtension& aLifetimeExtension,
265 std::function<void(ServiceWorkerOpResult&&)>&& aSuccessCallback,
266 std::function<void()>&& aFailureCallback = [] {});
268 class PendingFunctionalEvent {
269 public:
270 PendingFunctionalEvent(
271 ServiceWorkerPrivate* aOwner,
272 RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration);
274 virtual ~PendingFunctionalEvent();
276 virtual nsresult Send() = 0;
278 protected:
279 ServiceWorkerPrivate* const MOZ_NON_OWNING_REF mOwner;
280 RefPtr<ServiceWorkerRegistrationInfo> mRegistration;
283 class PendingPushEvent final : public PendingFunctionalEvent {
284 public:
285 PendingPushEvent(ServiceWorkerPrivate* aOwner,
286 RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
287 ServiceWorkerPushEventOpArgs&& aArgs);
289 nsresult Send() override;
291 private:
292 ServiceWorkerPushEventOpArgs mArgs;
295 class PendingFetchEvent final : public PendingFunctionalEvent {
296 public:
297 PendingFetchEvent(
298 ServiceWorkerPrivate* aOwner,
299 RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
300 ParentToParentServiceWorkerFetchEventOpArgs&& aArgs,
301 nsCOMPtr<nsIInterceptedChannel>&& aChannel,
302 RefPtr<FetchServicePromises>&& aPreloadResponseReadyPromises);
304 nsresult Send() override;
306 ~PendingFetchEvent();
308 private:
309 ParentToParentServiceWorkerFetchEventOpArgs mArgs;
310 nsCOMPtr<nsIInterceptedChannel> mChannel;
311 // The promises from FetchService. It indicates if the preload response is
312 // ready or not. The promise's resolve/reject value should be handled in
313 // FetchEventOpChild, such that the preload result can be propagated to the
314 // ServiceWorker through IPC. However, FetchEventOpChild creation could be
315 // pending here, so this member is needed. And it will be forwarded to
316 // FetchEventOpChild when crearting the FetchEventOpChild.
317 RefPtr<FetchServicePromises> mPreloadResponseReadyPromises;
320 nsTArray<UniquePtr<PendingFunctionalEvent>> mPendingFunctionalEvents;
323 * It's possible that there are still in-progress operations when a
324 * a termination operation is issued. In this case, it's important to keep
325 * the RemoteWorkerControllerChild actor alive until all pending operations
326 * have completed before destroying it with Send__delete__().
328 * RAIIActorPtrHolder holds a singular, owning reference to a
329 * RemoteWorkerControllerChild actor and is responsible for destroying the
330 * actor in its (i.e. the holder's) destructor. This implies that all
331 * in-progress operations must maintain a strong reference to their
332 * corresponding holders and release the reference once completed/canceled.
334 * Additionally a RAIIActorPtrHolder must be initialized with a non-null actor
335 * and cannot be moved or copied. Therefore, the identities of two held
336 * actors can be compared by simply comparing their holders' addresses.
338 class RAIIActorPtrHolder final {
339 public:
340 NS_INLINE_DECL_REFCOUNTING(RAIIActorPtrHolder)
342 explicit RAIIActorPtrHolder(
343 already_AddRefed<RemoteWorkerControllerChild> aActor);
345 RAIIActorPtrHolder(const RAIIActorPtrHolder& aOther) = delete;
346 RAIIActorPtrHolder& operator=(const RAIIActorPtrHolder& aOther) = delete;
348 RAIIActorPtrHolder(RAIIActorPtrHolder&& aOther) = delete;
349 RAIIActorPtrHolder& operator=(RAIIActorPtrHolder&& aOther) = delete;
351 RemoteWorkerControllerChild* operator->() const
352 MOZ_NO_ADDREF_RELEASE_ON_RETURN;
354 RemoteWorkerControllerChild* get() const;
356 RefPtr<GenericPromise> OnDestructor();
358 private:
359 ~RAIIActorPtrHolder();
361 MozPromiseHolder<GenericPromise> mDestructorPromiseHolder;
363 const RefPtr<RemoteWorkerControllerChild> mActor;
366 RefPtr<RAIIActorPtrHolder> mControllerChild;
368 RemoteWorkerData mRemoteWorkerData;
369 Maybe<ClientInfo> mClientInfo;
371 TimeStamp mServiceWorkerLaunchTimeStart;
373 // Counters for Telemetry - totals running simultaneously, and those that
374 // handle Fetch, plus Max values for each
375 static uint32_t sRunningServiceWorkers;
376 static uint32_t sRunningServiceWorkersFetch;
377 static uint32_t sRunningServiceWorkersMax;
378 static uint32_t sRunningServiceWorkersFetchMax;
380 // We know the state after we've evaluated the worker, and we then store
381 // it in the registration. The only valid state transition should be
382 // from Unknown to Enabled or Disabled.
383 enum { Unknown, Enabled, Disabled } mHandlesFetch{Unknown};
385 // The info object owns us. It is possible to outlive it for a brief period
386 // of time if there are pending waitUntil promises, in which case it
387 // will be null and |SpawnWorkerIfNeeded| will always fail.
388 ServiceWorkerInfo* MOZ_NON_OWNING_REF mInfo;
390 nsCOMPtr<nsITimer> mIdleWorkerTimer;
392 ServiceWorkerLifetimeExtension mPendingSpawnLifetime;
394 // This is the current time in the future that the idle timer is set to expire
395 // for keepalive purposes. This will not be updated for the
396 // "dom.serviceWorkers.idle_extended_timeout" grace period after the time
397 // first expires.
398 TimeStamp mIdleDeadline;
400 // We keep a token for |dom.serviceWorkers.idle_timeout| seconds to give the
401 // worker a grace period after each event.
402 RefPtr<KeepAliveToken> mIdleKeepAliveToken;
404 uint64_t mDebuggerCount;
406 uint64_t mTokenCount;
408 uint32_t mLaunchCount;
410 // Used by the owning `ServiceWorkerRegistrationInfo` when it wants to call
411 // `Clear` after being unregistered and isn't controlling any clients but this
412 // worker (i.e. the registration's active worker) isn't idle yet. Note that
413 // such an event should happen at most once in a
414 // `ServiceWorkerRegistrationInfo`s lifetime, so this promise should also only
415 // be obtained at most once.
416 MozPromiseHolder<GenericPromise> mIdlePromiseHolder;
418 #ifdef DEBUG
419 bool mIdlePromiseObtained = false;
420 #endif
423 } // namespace dom
424 } // namespace mozilla
426 #endif // mozilla_dom_serviceworkerprivate_h