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 : #ifndef mozilla_dom_workers_serviceworkerprivate_h
8 : #define mozilla_dom_workers_serviceworkerprivate_h
9 :
10 : #include "nsCOMPtr.h"
11 :
12 : #include "WorkerPrivate.h"
13 :
14 : #define NOTIFICATION_CLICK_EVENT_NAME "notificationclick"
15 : #define NOTIFICATION_CLOSE_EVENT_NAME "notificationclose"
16 :
17 : class nsIInterceptedChannel;
18 :
19 : namespace mozilla {
20 : namespace dom {
21 : namespace workers {
22 :
23 : class ServiceWorkerInfo;
24 : class ServiceWorkerRegistrationInfo;
25 : class KeepAliveToken;
26 :
27 0 : class LifeCycleEventCallback : public Runnable
28 : {
29 : public:
30 0 : LifeCycleEventCallback() : Runnable("dom::workers::LifeCycleEventCallback") {}
31 :
32 : // Called on the worker thread.
33 : virtual void
34 : SetResult(bool aResult) = 0;
35 : };
36 :
37 : // ServiceWorkerPrivate is a wrapper for managing the on-demand aspect of
38 : // service workers. It handles all event dispatching to the worker and ensures
39 : // the worker thread is running when needed.
40 : //
41 : // Lifetime management: To spin up the worker thread we own a |WorkerPrivate|
42 : // object which can be cancelled if no events are received for a certain
43 : // amount of time. The worker is kept alive by holding a |KeepAliveToken|
44 : // reference.
45 : //
46 : // Extendable events hold tokens for the duration of their handler execution
47 : // and until their waitUntil promise is resolved, while ServiceWorkerPrivate
48 : // will hold a token for |dom.serviceWorkers.idle_timeout| seconds after each
49 : // new event.
50 : //
51 : // Note: All timer events must be handled on the main thread because the
52 : // worker may block indefinitely the worker thread (e. g. infinite loop in the
53 : // script).
54 : //
55 : // There are 3 cases where we may ignore keep alive tokens:
56 : // 1. When ServiceWorkerPrivate's token expired, if there are still waitUntil
57 : // handlers holding tokens, we wait another |dom.serviceWorkers.idle_extended_timeout|
58 : // seconds before forcibly terminating the worker.
59 : // 2. If the worker stopped controlling documents and it is not handling push
60 : // events.
61 : // 3. The content process is shutting down.
62 : //
63 : // Adding an API function for a new event requires calling |SpawnWorkerIfNeeded|
64 : // with an appropriate reason before any runnable is dispatched to the worker.
65 : // If the event is extendable then the runnable should inherit
66 : // ExtendableEventWorkerRunnable.
67 : class ServiceWorkerPrivate final
68 : {
69 : friend class KeepAliveToken;
70 :
71 : public:
72 : NS_IMETHOD_(MozExternalRefCountType) AddRef();
73 : NS_IMETHOD_(MozExternalRefCountType) Release();
74 0 : NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ServiceWorkerPrivate)
75 :
76 : typedef mozilla::FalseType HasThreadSafeRefCnt;
77 :
78 : protected:
79 : nsCycleCollectingAutoRefCnt mRefCnt;
80 : NS_DECL_OWNINGTHREAD
81 :
82 : public:
83 : explicit ServiceWorkerPrivate(ServiceWorkerInfo* aInfo);
84 :
85 : nsresult
86 : SendMessageEvent(JSContext* aCx, JS::Handle<JS::Value> aMessage,
87 : const Sequence<JSObject*>& aTransferable,
88 : UniquePtr<ServiceWorkerClientInfo>&& aClientInfo);
89 :
90 : // This is used to validate the worker script and continue the installation
91 : // process.
92 : nsresult
93 : CheckScriptEvaluation(LifeCycleEventCallback* aCallback);
94 :
95 : nsresult
96 : SendLifeCycleEvent(const nsAString& aEventType,
97 : LifeCycleEventCallback* aCallback,
98 : nsIRunnable* aLoadFailure);
99 :
100 : nsresult
101 : SendPushEvent(const nsAString& aMessageId,
102 : const Maybe<nsTArray<uint8_t>>& aData,
103 : ServiceWorkerRegistrationInfo* aRegistration);
104 :
105 : nsresult
106 : SendPushSubscriptionChangeEvent();
107 :
108 : nsresult
109 : SendNotificationEvent(const nsAString& aEventName,
110 : const nsAString& aID,
111 : const nsAString& aTitle,
112 : const nsAString& aDir,
113 : const nsAString& aLang,
114 : const nsAString& aBody,
115 : const nsAString& aTag,
116 : const nsAString& aIcon,
117 : const nsAString& aData,
118 : const nsAString& aBehavior,
119 : const nsAString& aScope);
120 :
121 : nsresult
122 : SendFetchEvent(nsIInterceptedChannel* aChannel,
123 : nsILoadGroup* aLoadGroup,
124 : const nsAString& aDocumentId,
125 : bool aIsReload);
126 :
127 : void
128 : StoreISupports(nsISupports* aSupports);
129 :
130 : void
131 : RemoveISupports(nsISupports* aSupports);
132 :
133 : // This will terminate the current running worker thread and drop the
134 : // workerPrivate reference.
135 : // Called by ServiceWorkerInfo when [[Clear Registration]] is invoked
136 : // or whenever the spec mandates that we terminate the worker.
137 : // This is a no-op if the worker has already been stopped.
138 : void
139 : TerminateWorker();
140 :
141 : void
142 : NoteDeadServiceWorkerInfo();
143 :
144 : void
145 : NoteStoppedControllingDocuments();
146 :
147 : void
148 : Activated();
149 :
150 : nsresult
151 : GetDebugger(nsIWorkerDebugger** aResult);
152 :
153 : nsresult
154 : AttachDebugger();
155 :
156 : nsresult
157 : DetachDebugger();
158 :
159 : bool
160 : IsIdle() const;
161 :
162 : void
163 : SetHandlesFetch(bool aValue);
164 :
165 : private:
166 : enum WakeUpReason {
167 : FetchEvent = 0,
168 : PushEvent,
169 : PushSubscriptionChangeEvent,
170 : MessageEvent,
171 : NotificationClickEvent,
172 : NotificationCloseEvent,
173 : LifeCycleEvent,
174 : AttachEvent
175 : };
176 :
177 : // Timer callbacks
178 : void
179 : NoteIdleWorkerCallback(nsITimer* aTimer);
180 :
181 : void
182 : TerminateWorkerCallback(nsITimer* aTimer);
183 :
184 : void
185 : RenewKeepAliveToken(WakeUpReason aWhy);
186 :
187 : void
188 : ResetIdleTimeout();
189 :
190 : void
191 : AddToken();
192 :
193 : void
194 : ReleaseToken();
195 :
196 : // |aLoadFailedRunnable| is a runnable dispatched to the main thread
197 : // if the script loader failed for some reason, but can be null.
198 : nsresult
199 : SpawnWorkerIfNeeded(WakeUpReason aWhy,
200 : nsIRunnable* aLoadFailedRunnable,
201 : bool* aNewWorkerCreated = nullptr,
202 : nsILoadGroup* aLoadGroup = nullptr);
203 :
204 : ~ServiceWorkerPrivate();
205 :
206 : already_AddRefed<KeepAliveToken>
207 : CreateEventKeepAliveToken();
208 :
209 : // The info object owns us. It is possible to outlive it for a brief period
210 : // of time if there are pending waitUntil promises, in which case it
211 : // will be null and |SpawnWorkerIfNeeded| will always fail.
212 : ServiceWorkerInfo* MOZ_NON_OWNING_REF mInfo;
213 :
214 : // The WorkerPrivate object can only be closed by this class or by the
215 : // RuntimeService class if gecko is shutting down. Closing the worker
216 : // multiple times is OK, since the second attempt will be a no-op.
217 : RefPtr<WorkerPrivate> mWorkerPrivate;
218 :
219 : nsCOMPtr<nsITimer> mIdleWorkerTimer;
220 :
221 : // We keep a token for |dom.serviceWorkers.idle_timeout| seconds to give the
222 : // worker a grace period after each event.
223 : RefPtr<KeepAliveToken> mIdleKeepAliveToken;
224 :
225 : uint64_t mDebuggerCount;
226 :
227 : uint64_t mTokenCount;
228 :
229 : // Meant for keeping objects alive while handling requests from the worker
230 : // on the main thread. Access to this array is provided through
231 : // |StoreISupports| and |RemoveISupports|. Note that the array is also
232 : // cleared whenever the worker is terminated.
233 : nsTArray<nsCOMPtr<nsISupports>> mSupportsArray;
234 :
235 : // Array of function event worker runnables that are pending due to
236 : // the worker activating. Main thread only.
237 : nsTArray<RefPtr<WorkerRunnable>> mPendingFunctionalEvents;
238 : };
239 :
240 : } // namespace workers
241 : } // namespace dom
242 : } // namespace mozilla
243 :
244 : #endif // mozilla_dom_workers_serviceworkerprivate_h
|