/src/mozilla-central/dom/serviceworkers/ServiceWorkerRegistrationInfo.cpp
Line | Count | Source (jump to first uncovered line) |
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 "ServiceWorkerRegistrationInfo.h" |
8 | | |
9 | | #include "ServiceWorkerManager.h" |
10 | | #include "ServiceWorkerPrivate.h" |
11 | | #include "ServiceWorkerRegistrationListener.h" |
12 | | |
13 | | namespace mozilla { |
14 | | namespace dom { |
15 | | |
16 | | namespace { |
17 | | |
18 | | class ContinueActivateRunnable final : public LifeCycleEventCallback |
19 | | { |
20 | | nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration; |
21 | | bool mSuccess; |
22 | | |
23 | | public: |
24 | | explicit ContinueActivateRunnable(const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration) |
25 | | : mRegistration(aRegistration) |
26 | | , mSuccess(false) |
27 | 0 | { |
28 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
29 | 0 | } |
30 | | |
31 | | void |
32 | | SetResult(bool aResult) override |
33 | 0 | { |
34 | 0 | mSuccess = aResult; |
35 | 0 | } |
36 | | |
37 | | NS_IMETHOD |
38 | | Run() override |
39 | 0 | { |
40 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
41 | 0 | mRegistration->FinishActivate(mSuccess); |
42 | 0 | mRegistration = nullptr; |
43 | 0 | return NS_OK; |
44 | 0 | } |
45 | | }; |
46 | | |
47 | | } // anonymous namespace |
48 | | |
49 | | void |
50 | | ServiceWorkerRegistrationInfo::Clear() |
51 | 0 | { |
52 | 0 | if (mEvaluatingWorker) { |
53 | 0 | mEvaluatingWorker = nullptr; |
54 | 0 | } |
55 | 0 |
|
56 | 0 | RefPtr<ServiceWorkerInfo> installing = mInstallingWorker.forget(); |
57 | 0 | RefPtr<ServiceWorkerInfo> waiting = mWaitingWorker.forget(); |
58 | 0 | RefPtr<ServiceWorkerInfo> active = mActiveWorker.forget(); |
59 | 0 |
|
60 | 0 | if (installing) { |
61 | 0 | installing->UpdateState(ServiceWorkerState::Redundant); |
62 | 0 | installing->UpdateRedundantTime(); |
63 | 0 | installing->WorkerPrivate()->NoteDeadServiceWorkerInfo(); |
64 | 0 | // FIXME(nsm): Abort any inflight requests from installing worker. |
65 | 0 | } |
66 | 0 |
|
67 | 0 | if (waiting) { |
68 | 0 | waiting->UpdateState(ServiceWorkerState::Redundant); |
69 | 0 | waiting->UpdateRedundantTime(); |
70 | 0 | waiting->WorkerPrivate()->NoteDeadServiceWorkerInfo(); |
71 | 0 | } |
72 | 0 |
|
73 | 0 | if (active) { |
74 | 0 | active->UpdateState(ServiceWorkerState::Redundant); |
75 | 0 | active->UpdateRedundantTime(); |
76 | 0 | active->WorkerPrivate()->NoteDeadServiceWorkerInfo(); |
77 | 0 | } |
78 | 0 |
|
79 | 0 | UpdateRegistrationState(); |
80 | 0 | NotifyChromeRegistrationListeners(); |
81 | 0 | } |
82 | | |
83 | | void |
84 | | ServiceWorkerRegistrationInfo::ClearAsCorrupt() |
85 | 0 | { |
86 | 0 | mCorrupt = true; |
87 | 0 | Clear(); |
88 | 0 | } |
89 | | |
90 | | bool |
91 | | ServiceWorkerRegistrationInfo::IsCorrupt() const |
92 | 0 | { |
93 | 0 | return mCorrupt; |
94 | 0 | } |
95 | | |
96 | | ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo( |
97 | | const nsACString& aScope, |
98 | | nsIPrincipal* aPrincipal, |
99 | | ServiceWorkerUpdateViaCache aUpdateViaCache) |
100 | | : mPrincipal(aPrincipal) |
101 | | , mDescriptor(GetNextId(), GetNextVersion(), aPrincipal, aScope, |
102 | | aUpdateViaCache) |
103 | | , mControlledClientsCounter(0) |
104 | | , mDelayMultiplier(0) |
105 | | , mUpdateState(NoUpdate) |
106 | | , mCreationTime(PR_Now()) |
107 | | , mCreationTimeStamp(TimeStamp::Now()) |
108 | | , mLastUpdateTime(0) |
109 | | , mPendingUninstall(false) |
110 | | , mCorrupt(false) |
111 | 0 | { |
112 | 0 | MOZ_ASSERT_IF(ServiceWorkerParentInterceptEnabled(), |
113 | 0 | XRE_GetProcessType() == GeckoProcessType_Default); |
114 | 0 | } |
115 | | |
116 | | ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo() |
117 | 0 | { |
118 | 0 | MOZ_DIAGNOSTIC_ASSERT(!IsControllingClients()); |
119 | 0 | } |
120 | | |
121 | | void |
122 | | ServiceWorkerRegistrationInfo::AddInstance(ServiceWorkerRegistrationListener* aInstance, |
123 | | const ServiceWorkerRegistrationDescriptor& aDescriptor) |
124 | 0 | { |
125 | 0 | MOZ_DIAGNOSTIC_ASSERT(aInstance); |
126 | 0 | MOZ_ASSERT(!mInstanceList.Contains(aInstance)); |
127 | 0 | MOZ_DIAGNOSTIC_ASSERT(aDescriptor.Id() == mDescriptor.Id()); |
128 | 0 | MOZ_DIAGNOSTIC_ASSERT(aDescriptor.PrincipalInfo() == mDescriptor.PrincipalInfo()); |
129 | 0 | MOZ_DIAGNOSTIC_ASSERT(aDescriptor.Scope() == mDescriptor.Scope()); |
130 | 0 | MOZ_DIAGNOSTIC_ASSERT(aDescriptor.Version() <= mDescriptor.Version()); |
131 | 0 | uint64_t lastVersion = aDescriptor.Version(); |
132 | 0 | for (auto& entry : mVersionList) { |
133 | 0 | if (lastVersion > entry->mDescriptor.Version()) { |
134 | 0 | continue; |
135 | 0 | } |
136 | 0 | lastVersion = entry->mDescriptor.Version(); |
137 | 0 | aInstance->UpdateState(entry->mDescriptor); |
138 | 0 | } |
139 | 0 | // Note, the mDescriptor may be contained in the version list. Since the |
140 | 0 | // version list is aged out, though, it may also not be in the version list. |
141 | 0 | // So always check for the mDescriptor update here. |
142 | 0 | if (lastVersion < mDescriptor.Version()) { |
143 | 0 | aInstance->UpdateState(mDescriptor); |
144 | 0 | } |
145 | 0 | mInstanceList.AppendElement(aInstance); |
146 | 0 | } |
147 | | |
148 | | void |
149 | | ServiceWorkerRegistrationInfo::RemoveInstance(ServiceWorkerRegistrationListener* aInstance) |
150 | 0 | { |
151 | 0 | MOZ_DIAGNOSTIC_ASSERT(aInstance); |
152 | 0 | DebugOnly<bool> removed = mInstanceList.RemoveElement(aInstance); |
153 | 0 | MOZ_ASSERT(removed); |
154 | 0 | } |
155 | | |
156 | | const nsCString& |
157 | | ServiceWorkerRegistrationInfo::Scope() const |
158 | 0 | { |
159 | 0 | return mDescriptor.Scope(); |
160 | 0 | } |
161 | | |
162 | | nsIPrincipal* |
163 | | ServiceWorkerRegistrationInfo::Principal() const |
164 | 0 | { |
165 | 0 | return mPrincipal; |
166 | 0 | } |
167 | | |
168 | | bool |
169 | | ServiceWorkerRegistrationInfo::IsPendingUninstall() const |
170 | 0 | { |
171 | 0 | return mPendingUninstall; |
172 | 0 | } |
173 | | |
174 | | void |
175 | | ServiceWorkerRegistrationInfo::SetPendingUninstall() |
176 | 0 | { |
177 | 0 | mPendingUninstall = true; |
178 | 0 | } |
179 | | |
180 | | void |
181 | | ServiceWorkerRegistrationInfo::ClearPendingUninstall() |
182 | 0 | { |
183 | 0 | // If we are resurrecting an uninstalling registration, then persist |
184 | 0 | // it to disk again. We preemptively removed it earlier during |
185 | 0 | // unregister so that closing the window by shutting down the browser |
186 | 0 | // results in the registration being gone on restart. |
187 | 0 | if (mPendingUninstall && mActiveWorker) { |
188 | 0 | RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); |
189 | 0 | if (swm) { |
190 | 0 | swm->StoreRegistration(mPrincipal, this); |
191 | 0 | } |
192 | 0 | } |
193 | 0 | mPendingUninstall = false; |
194 | 0 | } |
195 | | |
196 | | NS_IMPL_ISUPPORTS(ServiceWorkerRegistrationInfo, nsIServiceWorkerRegistrationInfo) |
197 | | |
198 | | NS_IMETHODIMP |
199 | | ServiceWorkerRegistrationInfo::GetPrincipal(nsIPrincipal** aPrincipal) |
200 | 0 | { |
201 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
202 | 0 | NS_ADDREF(*aPrincipal = mPrincipal); |
203 | 0 | return NS_OK; |
204 | 0 | } |
205 | | |
206 | | NS_IMETHODIMP |
207 | | ServiceWorkerRegistrationInfo::GetScope(nsAString& aScope) |
208 | 0 | { |
209 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
210 | 0 | CopyUTF8toUTF16(Scope(), aScope); |
211 | 0 | return NS_OK; |
212 | 0 | } |
213 | | |
214 | | NS_IMETHODIMP |
215 | | ServiceWorkerRegistrationInfo::GetScriptSpec(nsAString& aScriptSpec) |
216 | 0 | { |
217 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
218 | 0 | RefPtr<ServiceWorkerInfo> newest = Newest(); |
219 | 0 | if (newest) { |
220 | 0 | CopyUTF8toUTF16(newest->ScriptSpec(), aScriptSpec); |
221 | 0 | } |
222 | 0 | return NS_OK; |
223 | 0 | } |
224 | | |
225 | | NS_IMETHODIMP |
226 | | ServiceWorkerRegistrationInfo::GetUpdateViaCache(uint16_t* aUpdateViaCache) |
227 | 0 | { |
228 | 0 | *aUpdateViaCache = static_cast<uint16_t>(GetUpdateViaCache()); |
229 | 0 | return NS_OK; |
230 | 0 | } |
231 | | |
232 | | NS_IMETHODIMP |
233 | | ServiceWorkerRegistrationInfo::GetLastUpdateTime(PRTime* _retval) |
234 | 0 | { |
235 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
236 | 0 | MOZ_ASSERT(_retval); |
237 | 0 | *_retval = mLastUpdateTime; |
238 | 0 | return NS_OK; |
239 | 0 | } |
240 | | |
241 | | NS_IMETHODIMP |
242 | | ServiceWorkerRegistrationInfo::GetInstallingWorker(nsIServiceWorkerInfo **aResult) |
243 | 0 | { |
244 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
245 | 0 | nsCOMPtr<nsIServiceWorkerInfo> info = do_QueryInterface(mInstallingWorker); |
246 | 0 | info.forget(aResult); |
247 | 0 | return NS_OK; |
248 | 0 | } |
249 | | |
250 | | NS_IMETHODIMP |
251 | | ServiceWorkerRegistrationInfo::GetWaitingWorker(nsIServiceWorkerInfo **aResult) |
252 | 0 | { |
253 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
254 | 0 | nsCOMPtr<nsIServiceWorkerInfo> info = do_QueryInterface(mWaitingWorker); |
255 | 0 | info.forget(aResult); |
256 | 0 | return NS_OK; |
257 | 0 | } |
258 | | |
259 | | NS_IMETHODIMP |
260 | | ServiceWorkerRegistrationInfo::GetActiveWorker(nsIServiceWorkerInfo **aResult) |
261 | 0 | { |
262 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
263 | 0 | nsCOMPtr<nsIServiceWorkerInfo> info = do_QueryInterface(mActiveWorker); |
264 | 0 | info.forget(aResult); |
265 | 0 | return NS_OK; |
266 | 0 | } |
267 | | |
268 | | NS_IMETHODIMP |
269 | | ServiceWorkerRegistrationInfo::GetWorkerByID(uint64_t aID, nsIServiceWorkerInfo **aResult) |
270 | 0 | { |
271 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
272 | 0 | MOZ_ASSERT(aResult); |
273 | 0 |
|
274 | 0 | RefPtr<ServiceWorkerInfo> info = GetServiceWorkerInfoById(aID); |
275 | 0 | // It is ok to return null for a missing service worker info. |
276 | 0 | info.forget(aResult); |
277 | 0 | return NS_OK; |
278 | 0 | } |
279 | | |
280 | | NS_IMETHODIMP |
281 | | ServiceWorkerRegistrationInfo::AddListener( |
282 | | nsIServiceWorkerRegistrationInfoListener *aListener) |
283 | 0 | { |
284 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
285 | 0 |
|
286 | 0 | if (!aListener || mListeners.Contains(aListener)) { |
287 | 0 | return NS_ERROR_INVALID_ARG; |
288 | 0 | } |
289 | 0 | |
290 | 0 | mListeners.AppendElement(aListener); |
291 | 0 |
|
292 | 0 | return NS_OK; |
293 | 0 | } |
294 | | |
295 | | NS_IMETHODIMP |
296 | | ServiceWorkerRegistrationInfo::RemoveListener( |
297 | | nsIServiceWorkerRegistrationInfoListener *aListener) |
298 | 0 | { |
299 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
300 | 0 |
|
301 | 0 | if (!aListener || !mListeners.Contains(aListener)) { |
302 | 0 | return NS_ERROR_INVALID_ARG; |
303 | 0 | } |
304 | 0 | |
305 | 0 | mListeners.RemoveElement(aListener); |
306 | 0 |
|
307 | 0 | return NS_OK; |
308 | 0 | } |
309 | | |
310 | | already_AddRefed<ServiceWorkerInfo> |
311 | | ServiceWorkerRegistrationInfo::GetServiceWorkerInfoById(uint64_t aId) |
312 | 0 | { |
313 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
314 | 0 |
|
315 | 0 | RefPtr<ServiceWorkerInfo> serviceWorker; |
316 | 0 | if (mEvaluatingWorker && mEvaluatingWorker->ID() == aId) { |
317 | 0 | serviceWorker = mEvaluatingWorker; |
318 | 0 | } else if (mInstallingWorker && mInstallingWorker->ID() == aId) { |
319 | 0 | serviceWorker = mInstallingWorker; |
320 | 0 | } else if (mWaitingWorker && mWaitingWorker->ID() == aId) { |
321 | 0 | serviceWorker = mWaitingWorker; |
322 | 0 | } else if (mActiveWorker && mActiveWorker->ID() == aId) { |
323 | 0 | serviceWorker = mActiveWorker; |
324 | 0 | } |
325 | 0 |
|
326 | 0 | return serviceWorker.forget(); |
327 | 0 | } |
328 | | |
329 | | void |
330 | | ServiceWorkerRegistrationInfo::TryToActivateAsync() |
331 | 0 | { |
332 | 0 | MOZ_ALWAYS_SUCCEEDS( |
333 | 0 | NS_DispatchToMainThread(NewRunnableMethod("ServiceWorkerRegistrationInfo::TryToActivate", |
334 | 0 | this, |
335 | 0 | &ServiceWorkerRegistrationInfo::TryToActivate))); |
336 | 0 | } |
337 | | |
338 | | /* |
339 | | * TryToActivate should not be called directly, use TryToActivateAsync instead. |
340 | | */ |
341 | | void |
342 | | ServiceWorkerRegistrationInfo::TryToActivate() |
343 | 0 | { |
344 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
345 | 0 | bool controlling = IsControllingClients(); |
346 | 0 | bool skipWaiting = mWaitingWorker && mWaitingWorker->SkipWaitingFlag(); |
347 | 0 | bool idle = IsIdle(); |
348 | 0 | if (idle && (!controlling || skipWaiting)) { |
349 | 0 | Activate(); |
350 | 0 | } |
351 | 0 | } |
352 | | |
353 | | void |
354 | | ServiceWorkerRegistrationInfo::Activate() |
355 | 0 | { |
356 | 0 | if (!mWaitingWorker) { |
357 | 0 | return; |
358 | 0 | } |
359 | 0 | |
360 | 0 | RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); |
361 | 0 | if (!swm) { |
362 | 0 | // browser shutdown began during async activation step |
363 | 0 | return; |
364 | 0 | } |
365 | 0 | |
366 | 0 | TransitionWaitingToActive(); |
367 | 0 |
|
368 | 0 | // FIXME(nsm): Unlink appcache if there is one. |
369 | 0 |
|
370 | 0 | // "Queue a task to fire a simple event named controllerchange..." |
371 | 0 | MOZ_DIAGNOSTIC_ASSERT(mActiveWorker); |
372 | 0 | swm->UpdateClientControllers(this); |
373 | 0 |
|
374 | 0 | nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> handle( |
375 | 0 | new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>( |
376 | 0 | "ServiceWorkerRegistrationInfoProxy", this)); |
377 | 0 | RefPtr<LifeCycleEventCallback> callback = new ContinueActivateRunnable(handle); |
378 | 0 |
|
379 | 0 | ServiceWorkerPrivate* workerPrivate = mActiveWorker->WorkerPrivate(); |
380 | 0 | MOZ_ASSERT(workerPrivate); |
381 | 0 | nsresult rv = workerPrivate->SendLifeCycleEvent(NS_LITERAL_STRING("activate"), |
382 | 0 | callback); |
383 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
384 | 0 | nsCOMPtr<nsIRunnable> failRunnable = NewRunnableMethod<bool>( |
385 | 0 | "dom::ServiceWorkerRegistrationInfo::FinishActivate", |
386 | 0 | this, |
387 | 0 | &ServiceWorkerRegistrationInfo::FinishActivate, |
388 | 0 | false /* success */); |
389 | 0 | MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(failRunnable.forget())); |
390 | 0 | return; |
391 | 0 | } |
392 | 0 | } |
393 | | |
394 | | void |
395 | | ServiceWorkerRegistrationInfo::FinishActivate(bool aSuccess) |
396 | 0 | { |
397 | 0 | if (mPendingUninstall || !mActiveWorker || |
398 | 0 | mActiveWorker->State() != ServiceWorkerState::Activating) { |
399 | 0 | return; |
400 | 0 | } |
401 | 0 | |
402 | 0 | // Activation never fails, so aSuccess is ignored. |
403 | 0 | mActiveWorker->UpdateState(ServiceWorkerState::Activated); |
404 | 0 | mActiveWorker->UpdateActivatedTime(); |
405 | 0 |
|
406 | 0 | UpdateRegistrationState(); |
407 | 0 | NotifyChromeRegistrationListeners(); |
408 | 0 |
|
409 | 0 | RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); |
410 | 0 | if (!swm) { |
411 | 0 | // browser shutdown started during async activation completion step |
412 | 0 | return; |
413 | 0 | } |
414 | 0 | swm->StoreRegistration(mPrincipal, this); |
415 | 0 | } |
416 | | |
417 | | void |
418 | | ServiceWorkerRegistrationInfo::RefreshLastUpdateCheckTime() |
419 | 0 | { |
420 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
421 | 0 |
|
422 | 0 | mLastUpdateTime = |
423 | 0 | mCreationTime + static_cast<PRTime>((TimeStamp::Now() - |
424 | 0 | mCreationTimeStamp).ToMicroseconds()); |
425 | 0 | NotifyChromeRegistrationListeners(); |
426 | 0 | } |
427 | | |
428 | | bool |
429 | | ServiceWorkerRegistrationInfo::IsLastUpdateCheckTimeOverOneDay() const |
430 | 0 | { |
431 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
432 | 0 |
|
433 | 0 | // For testing. |
434 | 0 | if (Preferences::GetBool("dom.serviceWorkers.testUpdateOverOneDay")) { |
435 | 0 | return true; |
436 | 0 | } |
437 | 0 | |
438 | 0 | const int64_t kSecondsPerDay = 86400; |
439 | 0 | const int64_t nowMicros = |
440 | 0 | mCreationTime + static_cast<PRTime>((TimeStamp::Now() - |
441 | 0 | mCreationTimeStamp).ToMicroseconds()); |
442 | 0 |
|
443 | 0 | // now < mLastUpdateTime if the system time is reset between storing |
444 | 0 | // and loading mLastUpdateTime from ServiceWorkerRegistrar. |
445 | 0 | if (nowMicros < mLastUpdateTime || |
446 | 0 | (nowMicros - mLastUpdateTime) / PR_USEC_PER_SEC > kSecondsPerDay) { |
447 | 0 | return true; |
448 | 0 | } |
449 | 0 | return false; |
450 | 0 | } |
451 | | |
452 | | void |
453 | | ServiceWorkerRegistrationInfo::UpdateRegistrationState() |
454 | 0 | { |
455 | 0 | UpdateRegistrationState(mDescriptor.UpdateViaCache()); |
456 | 0 | } |
457 | | |
458 | | void |
459 | | ServiceWorkerRegistrationInfo::UpdateRegistrationState(ServiceWorkerUpdateViaCache aUpdateViaCache) |
460 | 0 | { |
461 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
462 | 0 |
|
463 | 0 | TimeStamp oldest = TimeStamp::Now() - TimeDuration::FromSeconds(30); |
464 | 0 | if (!mVersionList.IsEmpty() && mVersionList[0]->mTimeStamp < oldest) { |
465 | 0 | nsTArray<UniquePtr<VersionEntry>> list; |
466 | 0 | mVersionList.SwapElements(list); |
467 | 0 | for (auto& entry : list) { |
468 | 0 | if (entry->mTimeStamp >= oldest) { |
469 | 0 | mVersionList.AppendElement(std::move(entry)); |
470 | 0 | } |
471 | 0 | } |
472 | 0 | } |
473 | 0 | mVersionList.AppendElement(MakeUnique<VersionEntry>(mDescriptor)); |
474 | 0 |
|
475 | 0 | // We are going to modify the descriptor, so increase its version number. |
476 | 0 | mDescriptor.SetVersion(GetNextVersion()); |
477 | 0 |
|
478 | 0 | // Note, this also sets the new version number on the ServiceWorkerInfo |
479 | 0 | // objects before we copy over their updated descriptors. |
480 | 0 | mDescriptor.SetWorkers(mInstallingWorker, mWaitingWorker, mActiveWorker); |
481 | 0 |
|
482 | 0 | mDescriptor.SetUpdateViaCache(aUpdateViaCache); |
483 | 0 |
|
484 | 0 | nsTObserverArray<ServiceWorkerRegistrationListener*>::ForwardIterator it(mInstanceList); |
485 | 0 | while (it.HasMore()) { |
486 | 0 | RefPtr<ServiceWorkerRegistrationListener> target = it.GetNext(); |
487 | 0 | target->UpdateState(mDescriptor); |
488 | 0 | } |
489 | 0 | } |
490 | | |
491 | | void |
492 | | ServiceWorkerRegistrationInfo::NotifyChromeRegistrationListeners() |
493 | 0 | { |
494 | 0 | nsTArray<nsCOMPtr<nsIServiceWorkerRegistrationInfoListener>> listeners(mListeners); |
495 | 0 | for (size_t index = 0; index < listeners.Length(); ++index) { |
496 | 0 | listeners[index]->OnChange(); |
497 | 0 | } |
498 | 0 | } |
499 | | |
500 | | void |
501 | | ServiceWorkerRegistrationInfo::MaybeScheduleTimeCheckAndUpdate() |
502 | 0 | { |
503 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
504 | 0 |
|
505 | 0 | RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); |
506 | 0 | if (!swm) { |
507 | 0 | // shutting down, do nothing |
508 | 0 | return; |
509 | 0 | } |
510 | 0 | |
511 | 0 | if (mUpdateState == NoUpdate) { |
512 | 0 | mUpdateState = NeedTimeCheckAndUpdate; |
513 | 0 | } |
514 | 0 |
|
515 | 0 | swm->ScheduleUpdateTimer(mPrincipal, Scope()); |
516 | 0 | } |
517 | | |
518 | | void |
519 | | ServiceWorkerRegistrationInfo::MaybeScheduleUpdate() |
520 | 0 | { |
521 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
522 | 0 |
|
523 | 0 | RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); |
524 | 0 | if (!swm) { |
525 | 0 | // shutting down, do nothing |
526 | 0 | return; |
527 | 0 | } |
528 | 0 | |
529 | 0 | mUpdateState = NeedUpdate; |
530 | 0 |
|
531 | 0 | swm->ScheduleUpdateTimer(mPrincipal, Scope()); |
532 | 0 | } |
533 | | |
534 | | bool |
535 | | ServiceWorkerRegistrationInfo::CheckAndClearIfUpdateNeeded() |
536 | 0 | { |
537 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
538 | 0 |
|
539 | 0 | bool result = mUpdateState == NeedUpdate || |
540 | 0 | (mUpdateState == NeedTimeCheckAndUpdate && |
541 | 0 | IsLastUpdateCheckTimeOverOneDay()); |
542 | 0 |
|
543 | 0 | mUpdateState = NoUpdate; |
544 | 0 |
|
545 | 0 | return result; |
546 | 0 | } |
547 | | |
548 | | ServiceWorkerInfo* |
549 | | ServiceWorkerRegistrationInfo::GetEvaluating() const |
550 | 0 | { |
551 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
552 | 0 | return mEvaluatingWorker; |
553 | 0 | } |
554 | | |
555 | | ServiceWorkerInfo* |
556 | | ServiceWorkerRegistrationInfo::GetInstalling() const |
557 | 0 | { |
558 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
559 | 0 | return mInstallingWorker; |
560 | 0 | } |
561 | | |
562 | | ServiceWorkerInfo* |
563 | | ServiceWorkerRegistrationInfo::GetWaiting() const |
564 | 0 | { |
565 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
566 | 0 | return mWaitingWorker; |
567 | 0 | } |
568 | | |
569 | | ServiceWorkerInfo* |
570 | | ServiceWorkerRegistrationInfo::GetActive() const |
571 | 0 | { |
572 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
573 | 0 | return mActiveWorker; |
574 | 0 | } |
575 | | |
576 | | ServiceWorkerInfo* |
577 | | ServiceWorkerRegistrationInfo::GetByDescriptor(const ServiceWorkerDescriptor& aDescriptor) const |
578 | 0 | { |
579 | 0 | if (mActiveWorker && mActiveWorker->Descriptor().Matches(aDescriptor)) { |
580 | 0 | return mActiveWorker; |
581 | 0 | } |
582 | 0 | if (mWaitingWorker && mWaitingWorker->Descriptor().Matches(aDescriptor)) { |
583 | 0 | return mWaitingWorker; |
584 | 0 | } |
585 | 0 | if (mInstallingWorker && mInstallingWorker->Descriptor().Matches(aDescriptor)) { |
586 | 0 | return mInstallingWorker; |
587 | 0 | } |
588 | 0 | if (mEvaluatingWorker && mEvaluatingWorker->Descriptor().Matches(aDescriptor)) { |
589 | 0 | return mEvaluatingWorker; |
590 | 0 | } |
591 | 0 | return nullptr; |
592 | 0 | } |
593 | | |
594 | | void |
595 | | ServiceWorkerRegistrationInfo::SetEvaluating(ServiceWorkerInfo* aServiceWorker) |
596 | 0 | { |
597 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
598 | 0 | MOZ_ASSERT(aServiceWorker); |
599 | 0 | MOZ_ASSERT(!mEvaluatingWorker); |
600 | 0 | MOZ_ASSERT(!mInstallingWorker); |
601 | 0 | MOZ_ASSERT(mWaitingWorker != aServiceWorker); |
602 | 0 | MOZ_ASSERT(mActiveWorker != aServiceWorker); |
603 | 0 |
|
604 | 0 | mEvaluatingWorker = aServiceWorker; |
605 | 0 | } |
606 | | |
607 | | void |
608 | | ServiceWorkerRegistrationInfo::ClearEvaluating() |
609 | 0 | { |
610 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
611 | 0 |
|
612 | 0 | if (!mEvaluatingWorker) { |
613 | 0 | return; |
614 | 0 | } |
615 | 0 | |
616 | 0 | mEvaluatingWorker->UpdateState(ServiceWorkerState::Redundant); |
617 | 0 | // We don't update the redundant time for the sw here, since we've not expose |
618 | 0 | // evalutingWorker yet. |
619 | 0 | mEvaluatingWorker = nullptr; |
620 | 0 | } |
621 | | |
622 | | void |
623 | | ServiceWorkerRegistrationInfo::ClearInstalling() |
624 | 0 | { |
625 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
626 | 0 |
|
627 | 0 | if (!mInstallingWorker) { |
628 | 0 | return; |
629 | 0 | } |
630 | 0 | |
631 | 0 | RefPtr<ServiceWorkerInfo> installing = mInstallingWorker.forget(); |
632 | 0 | installing->UpdateState(ServiceWorkerState::Redundant); |
633 | 0 | installing->UpdateRedundantTime(); |
634 | 0 |
|
635 | 0 | UpdateRegistrationState(); |
636 | 0 | NotifyChromeRegistrationListeners(); |
637 | 0 | } |
638 | | |
639 | | void |
640 | | ServiceWorkerRegistrationInfo::TransitionEvaluatingToInstalling() |
641 | 0 | { |
642 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
643 | 0 | MOZ_ASSERT(mEvaluatingWorker); |
644 | 0 | MOZ_ASSERT(!mInstallingWorker); |
645 | 0 |
|
646 | 0 | mInstallingWorker = mEvaluatingWorker.forget(); |
647 | 0 | mInstallingWorker->UpdateState(ServiceWorkerState::Installing); |
648 | 0 |
|
649 | 0 | UpdateRegistrationState(); |
650 | 0 | NotifyChromeRegistrationListeners(); |
651 | 0 | } |
652 | | |
653 | | void |
654 | | ServiceWorkerRegistrationInfo::TransitionInstallingToWaiting() |
655 | 0 | { |
656 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
657 | 0 | MOZ_ASSERT(mInstallingWorker); |
658 | 0 |
|
659 | 0 | if (mWaitingWorker) { |
660 | 0 | MOZ_ASSERT(mInstallingWorker->CacheName() != mWaitingWorker->CacheName()); |
661 | 0 | mWaitingWorker->UpdateState(ServiceWorkerState::Redundant); |
662 | 0 | mWaitingWorker->UpdateRedundantTime(); |
663 | 0 | } |
664 | 0 |
|
665 | 0 | mWaitingWorker = mInstallingWorker.forget(); |
666 | 0 | mWaitingWorker->UpdateState(ServiceWorkerState::Installed); |
667 | 0 | mWaitingWorker->UpdateInstalledTime(); |
668 | 0 |
|
669 | 0 | UpdateRegistrationState(); |
670 | 0 | NotifyChromeRegistrationListeners(); |
671 | 0 |
|
672 | 0 | // TODO: When bug 1426401 is implemented we will need to call |
673 | 0 | // StoreRegistration() here to persist the waiting worker. |
674 | 0 | } |
675 | | |
676 | | void |
677 | | ServiceWorkerRegistrationInfo::SetActive(ServiceWorkerInfo* aServiceWorker) |
678 | 0 | { |
679 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
680 | 0 | MOZ_ASSERT(aServiceWorker); |
681 | 0 |
|
682 | 0 | // TODO: Assert installing, waiting, and active are nullptr once the SWM |
683 | 0 | // moves to the parent process. After that happens this code will |
684 | 0 | // only run for browser initialization and not for cross-process |
685 | 0 | // overrides. |
686 | 0 | MOZ_ASSERT(mInstallingWorker != aServiceWorker); |
687 | 0 | MOZ_ASSERT(mWaitingWorker != aServiceWorker); |
688 | 0 | MOZ_ASSERT(mActiveWorker != aServiceWorker); |
689 | 0 |
|
690 | 0 | if (mActiveWorker) { |
691 | 0 | MOZ_ASSERT(aServiceWorker->CacheName() != mActiveWorker->CacheName()); |
692 | 0 | mActiveWorker->UpdateState(ServiceWorkerState::Redundant); |
693 | 0 | mActiveWorker->UpdateRedundantTime(); |
694 | 0 | } |
695 | 0 |
|
696 | 0 | // The active worker is being overriden due to initial load or |
697 | 0 | // another process activating a worker. Move straight to the |
698 | 0 | // Activated state. |
699 | 0 | mActiveWorker = aServiceWorker; |
700 | 0 | mActiveWorker->SetActivateStateUncheckedWithoutEvent(ServiceWorkerState::Activated); |
701 | 0 |
|
702 | 0 | // We don't need to update activated time when we load registration from |
703 | 0 | // registrar. |
704 | 0 | UpdateRegistrationState(); |
705 | 0 | NotifyChromeRegistrationListeners(); |
706 | 0 | } |
707 | | |
708 | | void |
709 | | ServiceWorkerRegistrationInfo::TransitionWaitingToActive() |
710 | 0 | { |
711 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
712 | 0 | MOZ_ASSERT(mWaitingWorker); |
713 | 0 |
|
714 | 0 | if (mActiveWorker) { |
715 | 0 | MOZ_ASSERT(mWaitingWorker->CacheName() != mActiveWorker->CacheName()); |
716 | 0 | mActiveWorker->UpdateState(ServiceWorkerState::Redundant); |
717 | 0 | mActiveWorker->UpdateRedundantTime(); |
718 | 0 | } |
719 | 0 |
|
720 | 0 | // We are transitioning from waiting to active normally, so go to |
721 | 0 | // the activating state. |
722 | 0 | mActiveWorker = mWaitingWorker.forget(); |
723 | 0 | mActiveWorker->UpdateState(ServiceWorkerState::Activating); |
724 | 0 |
|
725 | 0 | nsCOMPtr<nsIRunnable> r = |
726 | 0 | NS_NewRunnableFunction("ServiceWorkerRegistrationInfo::TransitionWaitingToActive", |
727 | 0 | [] { |
728 | 0 | RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); |
729 | 0 | if (swm) { |
730 | 0 | swm->CheckPendingReadyPromises(); |
731 | 0 | } |
732 | 0 | }); |
733 | 0 | MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget())); |
734 | 0 |
|
735 | 0 | UpdateRegistrationState(); |
736 | 0 | NotifyChromeRegistrationListeners(); |
737 | 0 | } |
738 | | |
739 | | bool |
740 | | ServiceWorkerRegistrationInfo::IsIdle() const |
741 | 0 | { |
742 | 0 | return !mActiveWorker || mActiveWorker->WorkerPrivate()->IsIdle(); |
743 | 0 | } |
744 | | |
745 | | ServiceWorkerUpdateViaCache |
746 | | ServiceWorkerRegistrationInfo::GetUpdateViaCache() const |
747 | 0 | { |
748 | 0 | return mDescriptor.UpdateViaCache(); |
749 | 0 | } |
750 | | |
751 | | void |
752 | | ServiceWorkerRegistrationInfo::SetUpdateViaCache( |
753 | | ServiceWorkerUpdateViaCache aUpdateViaCache) |
754 | 0 | { |
755 | 0 | UpdateRegistrationState(aUpdateViaCache); |
756 | 0 | } |
757 | | |
758 | | int64_t |
759 | | ServiceWorkerRegistrationInfo::GetLastUpdateTime() const |
760 | 0 | { |
761 | 0 | return mLastUpdateTime; |
762 | 0 | } |
763 | | |
764 | | void |
765 | | ServiceWorkerRegistrationInfo::SetLastUpdateTime(const int64_t aTime) |
766 | 0 | { |
767 | 0 | if (aTime == 0) { |
768 | 0 | return; |
769 | 0 | } |
770 | 0 | |
771 | 0 | mLastUpdateTime = aTime; |
772 | 0 | } |
773 | | |
774 | | const ServiceWorkerRegistrationDescriptor& |
775 | | ServiceWorkerRegistrationInfo::Descriptor() const |
776 | 0 | { |
777 | 0 | return mDescriptor; |
778 | 0 | } |
779 | | |
780 | | uint64_t |
781 | | ServiceWorkerRegistrationInfo::Id() const |
782 | 0 | { |
783 | 0 | return mDescriptor.Id(); |
784 | 0 | } |
785 | | |
786 | | uint64_t |
787 | | ServiceWorkerRegistrationInfo::Version() const |
788 | 0 | { |
789 | 0 | return mDescriptor.Version(); |
790 | 0 | } |
791 | | |
792 | | uint32_t |
793 | | ServiceWorkerRegistrationInfo::GetUpdateDelay() |
794 | 0 | { |
795 | 0 | uint32_t delay = Preferences::GetInt("dom.serviceWorkers.update_delay", |
796 | 0 | 1000); |
797 | 0 | // This can potentially happen if you spam registration->Update(). We don't |
798 | 0 | // want to wrap to a lower value. |
799 | 0 | if (mDelayMultiplier >= INT_MAX / (delay ? delay : 1)) { |
800 | 0 | return INT_MAX; |
801 | 0 | } |
802 | 0 | |
803 | 0 | delay *= mDelayMultiplier; |
804 | 0 |
|
805 | 0 | if (!mControlledClientsCounter && mDelayMultiplier < (INT_MAX / 30)) { |
806 | 0 | mDelayMultiplier = (mDelayMultiplier ? mDelayMultiplier : 1) * 30; |
807 | 0 | } |
808 | 0 |
|
809 | 0 | return delay; |
810 | 0 | } |
811 | | |
812 | | void |
813 | | ServiceWorkerRegistrationInfo::NotifyRemoved() |
814 | 0 | { |
815 | 0 | nsTObserverArray<ServiceWorkerRegistrationListener*>::ForwardIterator it(mInstanceList); |
816 | 0 | while (it.HasMore()) { |
817 | 0 | RefPtr<ServiceWorkerRegistrationListener> target = it.GetNext(); |
818 | 0 | target->RegistrationRemoved(); |
819 | 0 | } |
820 | 0 | } |
821 | | |
822 | | // static |
823 | | uint64_t |
824 | | ServiceWorkerRegistrationInfo::GetNextId() |
825 | 0 | { |
826 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
827 | 0 | static uint64_t sNextId = 0; |
828 | 0 | return ++sNextId; |
829 | 0 | } |
830 | | |
831 | | // static |
832 | | uint64_t |
833 | | ServiceWorkerRegistrationInfo::GetNextVersion() |
834 | 0 | { |
835 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
836 | 0 | static uint64_t sNextVersion = 0; |
837 | 0 | return ++sNextVersion; |
838 | 0 | } |
839 | | |
840 | | } // namespace dom |
841 | | } // namespace mozilla |