summaryrefslogtreecommitdiffstats
path: root/dom/workers/ServiceWorkerPrivate.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/workers/ServiceWorkerPrivate.h')
-rw-r--r--dom/workers/ServiceWorkerPrivate.h236
1 files changed, 236 insertions, 0 deletions
diff --git a/dom/workers/ServiceWorkerPrivate.h b/dom/workers/ServiceWorkerPrivate.h
new file mode 100644
index 000000000..8d59ea1d0
--- /dev/null
+++ b/dom/workers/ServiceWorkerPrivate.h
@@ -0,0 +1,236 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_workers_serviceworkerprivate_h
+#define mozilla_dom_workers_serviceworkerprivate_h
+
+#include "nsCOMPtr.h"
+
+#include "WorkerPrivate.h"
+
+#define NOTIFICATION_CLICK_EVENT_NAME "notificationclick"
+#define NOTIFICATION_CLOSE_EVENT_NAME "notificationclose"
+
+class nsIInterceptedChannel;
+
+namespace mozilla {
+namespace dom {
+namespace workers {
+
+class ServiceWorkerInfo;
+class ServiceWorkerRegistrationInfo;
+class KeepAliveToken;
+
+class LifeCycleEventCallback : public Runnable
+{
+public:
+ // Called on the worker thread.
+ virtual void
+ SetResult(bool aResult) = 0;
+};
+
+// ServiceWorkerPrivate is a wrapper for managing the on-demand aspect of
+// service workers. It handles all event dispatching to the worker and ensures
+// the worker thread is running when needed.
+//
+// Lifetime management: To spin up the worker thread we own a |WorkerPrivate|
+// object which can be cancelled if no events are received for a certain
+// amount of time. The worker is kept alive by holding a |KeepAliveToken|
+// reference.
+//
+// Extendable events hold tokens for the duration of their handler execution
+// and until their waitUntil promise is resolved, while ServiceWorkerPrivate
+// will hold a token for |dom.serviceWorkers.idle_timeout| seconds after each
+// new event.
+//
+// Note: All timer events must be handled on the main thread because the
+// worker may block indefinitely the worker thread (e. g. infinite loop in the
+// script).
+//
+// There are 3 cases where we may ignore keep alive tokens:
+// 1. When ServiceWorkerPrivate's token expired, if there are still waitUntil
+// handlers holding tokens, we wait another |dom.serviceWorkers.idle_extended_timeout|
+// seconds before forcibly terminating the worker.
+// 2. If the worker stopped controlling documents and it is not handling push
+// events.
+// 3. The content process is shutting down.
+//
+// Adding an API function for a new event requires calling |SpawnWorkerIfNeeded|
+// with an appropriate reason before any runnable is dispatched to the worker.
+// If the event is extendable then the runnable should inherit
+// ExtendableEventWorkerRunnable.
+class ServiceWorkerPrivate final : public nsIObserver
+{
+ friend class KeepAliveToken;
+
+public:
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_CLASS(ServiceWorkerPrivate)
+ NS_DECL_NSIOBSERVER
+
+ explicit ServiceWorkerPrivate(ServiceWorkerInfo* aInfo);
+
+ nsresult
+ SendMessageEvent(JSContext* aCx, JS::Handle<JS::Value> aMessage,
+ const Optional<Sequence<JS::Value>>& aTransferable,
+ UniquePtr<ServiceWorkerClientInfo>&& aClientInfo);
+
+ // This is used to validate the worker script and continue the installation
+ // process.
+ nsresult
+ CheckScriptEvaluation(LifeCycleEventCallback* aCallback);
+
+ nsresult
+ SendLifeCycleEvent(const nsAString& aEventType,
+ LifeCycleEventCallback* aCallback,
+ nsIRunnable* aLoadFailure);
+
+ nsresult
+ SendPushEvent(const nsAString& aMessageId,
+ const Maybe<nsTArray<uint8_t>>& aData,
+ ServiceWorkerRegistrationInfo* aRegistration);
+
+ nsresult
+ SendPushSubscriptionChangeEvent();
+
+ nsresult
+ SendNotificationEvent(const nsAString& aEventName,
+ const nsAString& aID,
+ const nsAString& aTitle,
+ const nsAString& aDir,
+ const nsAString& aLang,
+ const nsAString& aBody,
+ const nsAString& aTag,
+ const nsAString& aIcon,
+ const nsAString& aData,
+ const nsAString& aBehavior,
+ const nsAString& aScope);
+
+ nsresult
+ SendFetchEvent(nsIInterceptedChannel* aChannel,
+ nsILoadGroup* aLoadGroup,
+ const nsAString& aDocumentId,
+ bool aIsReload);
+
+ void
+ StoreISupports(nsISupports* aSupports);
+
+ void
+ RemoveISupports(nsISupports* aSupports);
+
+ // This will terminate the current running worker thread and drop the
+ // workerPrivate reference.
+ // Called by ServiceWorkerInfo when [[Clear Registration]] is invoked
+ // or whenever the spec mandates that we terminate the worker.
+ // This is a no-op if the worker has already been stopped.
+ void
+ TerminateWorker();
+
+ void
+ NoteDeadServiceWorkerInfo();
+
+ void
+ NoteStoppedControllingDocuments();
+
+ void
+ Activated();
+
+ nsresult
+ GetDebugger(nsIWorkerDebugger** aResult);
+
+ nsresult
+ AttachDebugger();
+
+ nsresult
+ DetachDebugger();
+
+ bool
+ IsIdle() const;
+
+ void
+ AddPendingWindow(Runnable* aPendingWindow);
+
+private:
+ enum WakeUpReason {
+ FetchEvent = 0,
+ PushEvent,
+ PushSubscriptionChangeEvent,
+ MessageEvent,
+ NotificationClickEvent,
+ NotificationCloseEvent,
+ LifeCycleEvent,
+ AttachEvent
+ };
+
+ // Timer callbacks
+ void
+ NoteIdleWorkerCallback(nsITimer* aTimer);
+
+ void
+ TerminateWorkerCallback(nsITimer* aTimer);
+
+ void
+ RenewKeepAliveToken(WakeUpReason aWhy);
+
+ void
+ ResetIdleTimeout();
+
+ void
+ AddToken();
+
+ void
+ ReleaseToken();
+
+ // |aLoadFailedRunnable| is a runnable dispatched to the main thread
+ // if the script loader failed for some reason, but can be null.
+ nsresult
+ SpawnWorkerIfNeeded(WakeUpReason aWhy,
+ nsIRunnable* aLoadFailedRunnable,
+ nsILoadGroup* aLoadGroup = nullptr);
+
+ ~ServiceWorkerPrivate();
+
+ already_AddRefed<KeepAliveToken>
+ CreateEventKeepAliveToken();
+
+ // The info object owns us. It is possible to outlive it for a brief period
+ // of time if there are pending waitUntil promises, in which case it
+ // will be null and |SpawnWorkerIfNeeded| will always fail.
+ ServiceWorkerInfo* MOZ_NON_OWNING_REF mInfo;
+
+ // The WorkerPrivate object can only be closed by this class or by the
+ // RuntimeService class if gecko is shutting down. Closing the worker
+ // multiple times is OK, since the second attempt will be a no-op.
+ RefPtr<WorkerPrivate> mWorkerPrivate;
+
+ nsCOMPtr<nsITimer> mIdleWorkerTimer;
+
+ // We keep a token for |dom.serviceWorkers.idle_timeout| seconds to give the
+ // worker a grace period after each event.
+ RefPtr<KeepAliveToken> mIdleKeepAliveToken;
+
+ uint64_t mDebuggerCount;
+
+ uint64_t mTokenCount;
+
+ // Meant for keeping objects alive while handling requests from the worker
+ // on the main thread. Access to this array is provided through
+ // |StoreISupports| and |RemoveISupports|. Note that the array is also
+ // cleared whenever the worker is terminated.
+ nsTArray<nsCOMPtr<nsISupports>> mSupportsArray;
+
+ // Array of function event worker runnables that are pending due to
+ // the worker activating. Main thread only.
+ nsTArray<RefPtr<WorkerRunnable>> mPendingFunctionalEvents;
+
+ nsTArray<Runnable*> pendingWindows;
+};
+
+} // namespace workers
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_workers_serviceworkerprivate_h