Coverage Report

Created: 2018-09-25 14:53

/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