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 #include "ServiceWorkerRegistrar.h"
8 #include "ServiceWorkerManager.h"
9 #include "mozilla/dom/ServiceWorkerRegistrarTypes.h"
10 #include "mozilla/dom/DOMException.h"
11 #include "mozilla/net/MozURL.h"
12 #include "mozilla/StaticPrefs_dom.h"
14 #include "nsIEventTarget.h"
15 #include "nsIInputStream.h"
16 #include "nsILineInputStream.h"
17 #include "nsIObserverService.h"
18 #include "nsIOutputStream.h"
19 #include "nsISafeOutputStream.h"
20 #include "nsIServiceWorkerManager.h"
21 #include "nsIWritablePropertyBag2.h"
23 #include "MainThreadUtils.h"
24 #include "mozilla/ClearOnShutdown.h"
25 #include "mozilla/CycleCollectedJSContext.h"
26 #include "mozilla/dom/StorageActivityService.h"
27 #include "mozilla/ErrorNames.h"
28 #include "mozilla/ipc/BackgroundChild.h"
29 #include "mozilla/ipc/BackgroundParent.h"
30 #include "mozilla/ipc/PBackgroundChild.h"
31 #include "mozilla/ModuleUtils.h"
32 #include "mozilla/Result.h"
33 #include "mozilla/ResultExtensions.h"
34 #include "mozilla/Services.h"
35 #include "mozilla/StaticPtr.h"
36 #include "nsAppDirectoryServiceDefs.h"
37 #include "nsComponentManagerUtils.h"
38 #include "nsContentUtils.h"
39 #include "nsDirectoryServiceUtils.h"
41 #include "nsNetUtil.h"
42 #include "nsServiceManagerUtils.h"
43 #include "nsThreadUtils.h"
44 #include "nsXULAppAPI.h"
45 #include "ServiceWorkerUtils.h"
47 using namespace mozilla::ipc
;
49 extern mozilla::LazyLogModule sWorkerTelemetryLog
;
54 #define LOG(_args) MOZ_LOG(sWorkerTelemetryLog, LogLevel::Debug, _args);
56 namespace mozilla::dom
{
60 static const char* gSupportedRegistrarVersions
[] = {
61 SERVICEWORKERREGISTRAR_VERSION
, "8", "7", "6", "5", "4", "3", "2"};
63 static const uint32_t kInvalidGeneration
= static_cast<uint32_t>(-1);
65 StaticRefPtr
<ServiceWorkerRegistrar
> gServiceWorkerRegistrar
;
67 nsresult
GetOriginAndBaseDomain(const nsACString
& aURL
, nsACString
& aOrigin
,
68 nsACString
& aBaseDomain
) {
69 RefPtr
<net::MozURL
> url
;
70 nsresult rv
= net::MozURL::Init(getter_AddRefs(url
), aURL
);
71 if (NS_WARN_IF(NS_FAILED(rv
))) {
77 rv
= url
->BaseDomain(aBaseDomain
);
78 if (NS_WARN_IF(NS_FAILED(rv
))) {
85 nsresult
ReadLine(nsILineInputStream
* aStream
, nsACString
& aValue
) {
87 nsresult rv
= aStream
->ReadLine(aValue
, &hasMoreLines
);
88 if (NS_WARN_IF(NS_FAILED(rv
))) {
92 if (NS_WARN_IF(!hasMoreLines
)) {
93 return NS_ERROR_FAILURE
;
99 nsresult
CreatePrincipalInfo(nsILineInputStream
* aStream
,
100 ServiceWorkerRegistrationData
* aEntry
,
101 bool aSkipSpec
= false) {
102 nsAutoCString suffix
;
103 nsresult rv
= ReadLine(aStream
, suffix
);
104 if (NS_WARN_IF(NS_FAILED(rv
))) {
108 OriginAttributes attrs
;
109 if (!attrs
.PopulateFromSuffix(suffix
)) {
110 return NS_ERROR_INVALID_ARG
;
114 nsAutoCString unused
;
115 nsresult rv
= ReadLine(aStream
, unused
);
116 if (NS_WARN_IF(NS_FAILED(rv
))) {
121 rv
= ReadLine(aStream
, aEntry
->scope());
122 if (NS_WARN_IF(NS_FAILED(rv
))) {
127 nsCString baseDomain
;
128 rv
= GetOriginAndBaseDomain(aEntry
->scope(), origin
, baseDomain
);
129 if (NS_WARN_IF(NS_FAILED(rv
))) {
133 aEntry
->principal() = mozilla::ipc::ContentPrincipalInfo(
134 attrs
, origin
, aEntry
->scope(), Nothing(), baseDomain
);
139 const IPCNavigationPreloadState
gDefaultNavigationPreloadState(false,
144 NS_IMPL_ISUPPORTS(ServiceWorkerRegistrar
, nsIObserver
, nsIAsyncShutdownBlocker
)
146 void ServiceWorkerRegistrar::Initialize() {
147 MOZ_ASSERT(!gServiceWorkerRegistrar
);
149 if (!XRE_IsParentProcess()) {
153 gServiceWorkerRegistrar
= new ServiceWorkerRegistrar();
154 ClearOnShutdown(&gServiceWorkerRegistrar
);
156 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
158 DebugOnly
<nsresult
> rv
= obs
->AddObserver(gServiceWorkerRegistrar
,
159 "profile-after-change", false);
160 MOZ_ASSERT(NS_SUCCEEDED(rv
));
165 already_AddRefed
<ServiceWorkerRegistrar
> ServiceWorkerRegistrar::Get() {
166 MOZ_ASSERT(XRE_IsParentProcess());
168 MOZ_ASSERT(gServiceWorkerRegistrar
);
169 RefPtr
<ServiceWorkerRegistrar
> service
= gServiceWorkerRegistrar
.get();
170 return service
.forget();
173 ServiceWorkerRegistrar::ServiceWorkerRegistrar()
174 : mMonitor("ServiceWorkerRegistrar.mMonitor"),
176 mDataGeneration(kInvalidGeneration
),
177 mFileGeneration(kInvalidGeneration
),
179 mShuttingDown(false),
180 mSaveDataRunnableDispatched(false) {
181 MOZ_ASSERT(NS_IsMainThread());
184 ServiceWorkerRegistrar::~ServiceWorkerRegistrar() {
185 MOZ_ASSERT(!mSaveDataRunnableDispatched
);
188 void ServiceWorkerRegistrar::GetRegistrations(
189 nsTArray
<ServiceWorkerRegistrationData
>& aValues
) {
190 MOZ_ASSERT(NS_IsMainThread());
191 MOZ_ASSERT(aValues
.IsEmpty());
193 MonitorAutoLock
lock(mMonitor
);
195 // If we don't have the profile directory, profile is not started yet (and
196 // probably we are in a utest).
201 // We care just about the first execution because this can be blocked by
202 // loading data from disk.
203 static bool firstTime
= true;
207 startTime
= TimeStamp::NowLoRes();
210 // Waiting for data loaded.
211 mMonitor
.AssertCurrentThreadOwns();
212 while (!mDataLoaded
) {
216 aValues
.AppendElements(mData
);
218 MaybeResetGeneration();
219 MOZ_DIAGNOSTIC_ASSERT(mDataGeneration
!= kInvalidGeneration
);
220 MOZ_DIAGNOSTIC_ASSERT(mFileGeneration
!= kInvalidGeneration
);
224 Telemetry::AccumulateTimeDelta(
225 Telemetry::SERVICE_WORKER_REGISTRATION_LOADING
, startTime
);
231 bool Equivalent(const ServiceWorkerRegistrationData
& aLeft
,
232 const ServiceWorkerRegistrationData
& aRight
) {
233 MOZ_ASSERT(aLeft
.principal().type() ==
234 mozilla::ipc::PrincipalInfo::TContentPrincipalInfo
);
235 MOZ_ASSERT(aRight
.principal().type() ==
236 mozilla::ipc::PrincipalInfo::TContentPrincipalInfo
);
238 const auto& leftPrincipal
= aLeft
.principal().get_ContentPrincipalInfo();
239 const auto& rightPrincipal
= aRight
.principal().get_ContentPrincipalInfo();
241 // Only compare the attributes, not the spec part of the principal.
242 // The scope comparison above already covers the origin and codebase
243 // principals include the full path in their spec which is not what
245 return aLeft
.scope() == aRight
.scope() &&
246 leftPrincipal
.attrs() == rightPrincipal
.attrs();
249 } // anonymous namespace
251 void ServiceWorkerRegistrar::RegisterServiceWorker(
252 const ServiceWorkerRegistrationData
& aData
) {
253 AssertIsOnBackgroundThread();
256 NS_WARNING("Failed to register a serviceWorker during shutting down.");
261 MonitorAutoLock
lock(mMonitor
);
262 MOZ_ASSERT(mDataLoaded
);
263 RegisterServiceWorkerInternal(aData
);
266 MaybeScheduleSaveData();
267 StorageActivityService::SendActivity(aData
.principal());
270 void ServiceWorkerRegistrar::UnregisterServiceWorker(
271 const PrincipalInfo
& aPrincipalInfo
, const nsACString
& aScope
) {
272 AssertIsOnBackgroundThread();
275 NS_WARNING("Failed to unregister a serviceWorker during shutting down.");
279 bool deleted
= false;
282 MonitorAutoLock
lock(mMonitor
);
283 MOZ_ASSERT(mDataLoaded
);
285 ServiceWorkerRegistrationData tmp
;
286 tmp
.principal() = aPrincipalInfo
;
287 tmp
.scope() = aScope
;
289 for (uint32_t i
= 0; i
< mData
.Length(); ++i
) {
290 if (Equivalent(tmp
, mData
[i
])) {
291 gServiceWorkersRegistered
--;
292 if (mData
[i
].currentWorkerHandlesFetch()) {
293 gServiceWorkersRegisteredFetch
--;
296 Telemetry::ScalarSet(Telemetry::ScalarID::SERVICEWORKER_REGISTRATIONS
,
297 u
"All"_ns
, gServiceWorkersRegistered
);
298 Telemetry::ScalarSet(Telemetry::ScalarID::SERVICEWORKER_REGISTRATIONS
,
299 u
"Fetch"_ns
, gServiceWorkersRegisteredFetch
);
300 LOG(("Unregister ServiceWorker: %u, fetch %u\n",
301 gServiceWorkersRegistered
, gServiceWorkersRegisteredFetch
));
303 mData
.RemoveElementAt(i
);
304 mDataGeneration
= GetNextGeneration();
312 MaybeScheduleSaveData();
313 StorageActivityService::SendActivity(aPrincipalInfo
);
317 void ServiceWorkerRegistrar::RemoveAll() {
318 AssertIsOnBackgroundThread();
321 NS_WARNING("Failed to remove all the serviceWorkers during shutting down.");
325 bool deleted
= false;
327 nsTArray
<ServiceWorkerRegistrationData
> data
;
329 MonitorAutoLock
lock(mMonitor
);
330 MOZ_ASSERT(mDataLoaded
);
332 // Let's take a copy in order to inform StorageActivityService.
333 data
= mData
.Clone();
335 deleted
= !mData
.IsEmpty();
338 mDataGeneration
= GetNextGeneration();
345 MaybeScheduleSaveData();
347 for (uint32_t i
= 0, len
= data
.Length(); i
< len
; ++i
) {
348 StorageActivityService::SendActivity(data
[i
].principal());
352 void ServiceWorkerRegistrar::LoadData() {
353 MOZ_ASSERT(!NS_IsMainThread());
356 MonitorAutoLock
lock(mMonitor
);
357 MOZ_ASSERT(!mDataLoaded
);
361 nsresult rv
= ReadData();
363 if (NS_WARN_IF(NS_FAILED(rv
))) {
365 // Also if the reading failed we have to notify what is waiting for data.
368 MonitorAutoLock
lock(mMonitor
);
369 MOZ_ASSERT(!mDataLoaded
);
374 bool ServiceWorkerRegistrar::ReloadDataForTest() {
375 if (NS_WARN_IF(!StaticPrefs::dom_serviceWorkers_testing_enabled())) {
379 MOZ_ASSERT(NS_IsMainThread());
380 MonitorAutoLock
lock(mMonitor
);
384 nsCOMPtr
<nsIEventTarget
> target
=
385 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
386 MOZ_ASSERT(target
, "Must have stream transport service");
388 nsCOMPtr
<nsIRunnable
> runnable
=
389 NewRunnableMethod("dom::ServiceWorkerRegistrar::LoadData", this,
390 &ServiceWorkerRegistrar::LoadData
);
391 nsresult rv
= target
->Dispatch(runnable
.forget(), NS_DISPATCH_NORMAL
);
393 NS_WARNING("Failed to dispatch the LoadDataRunnable.");
397 mMonitor
.AssertCurrentThreadOwns();
398 while (!mDataLoaded
) {
405 nsresult
ServiceWorkerRegistrar::ReadData() {
406 // We cannot assert about the correct thread because normally this method
407 // runs on a IO thread, but in gTests we call it from the main-thread.
409 nsCOMPtr
<nsIFile
> file
;
412 MonitorAutoLock
lock(mMonitor
);
415 return NS_ERROR_FAILURE
;
418 nsresult rv
= mProfileDir
->Clone(getter_AddRefs(file
));
419 if (NS_WARN_IF(NS_FAILED(rv
))) {
424 nsresult rv
= file
->Append(nsLiteralString(SERVICEWORKERREGISTRAR_FILE
));
425 if (NS_WARN_IF(NS_FAILED(rv
))) {
430 rv
= file
->Exists(&exists
);
431 if (NS_WARN_IF(NS_FAILED(rv
))) {
439 nsCOMPtr
<nsIInputStream
> stream
;
440 rv
= NS_NewLocalFileInputStream(getter_AddRefs(stream
), file
);
441 if (NS_WARN_IF(NS_FAILED(rv
))) {
445 nsCOMPtr
<nsILineInputStream
> lineInputStream
= do_QueryInterface(stream
);
446 MOZ_ASSERT(lineInputStream
);
448 nsAutoCString version
;
450 rv
= lineInputStream
->ReadLine(version
, &hasMoreLines
);
451 if (NS_WARN_IF(NS_FAILED(rv
))) {
455 if (!IsSupportedVersion(version
)) {
456 nsContentUtils::LogMessageToConsole(
457 nsPrintfCString("Unsupported service worker registrar version: %s",
460 return NS_ERROR_FAILURE
;
463 nsTArray
<ServiceWorkerRegistrationData
> tmpData
;
465 bool overwrite
= false;
467 while (hasMoreLines
) {
468 ServiceWorkerRegistrationData
* entry
= tmpData
.AppendElement();
470 #define GET_LINE(x) \
471 rv = lineInputStream->ReadLine(x, &hasMoreLines); \
472 if (NS_WARN_IF(NS_FAILED(rv))) { \
475 if (NS_WARN_IF(!hasMoreLines)) { \
476 return NS_ERROR_FAILURE; \
480 if (version
.EqualsLiteral(SERVICEWORKERREGISTRAR_VERSION
)) {
481 rv
= CreatePrincipalInfo(lineInputStream
, entry
);
482 if (NS_WARN_IF(NS_FAILED(rv
))) {
486 GET_LINE(entry
->currentWorkerURL());
488 nsAutoCString fetchFlag
;
490 if (!fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
) &&
491 !fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE
)) {
492 return NS_ERROR_INVALID_ARG
;
494 entry
->currentWorkerHandlesFetch() =
495 fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
);
497 nsAutoCString cacheName
;
499 CopyUTF8toUTF16(cacheName
, entry
->cacheName());
501 nsAutoCString updateViaCache
;
502 GET_LINE(updateViaCache
);
503 entry
->updateViaCache() = updateViaCache
.ToInteger(&rv
, 16);
504 if (NS_WARN_IF(NS_FAILED(rv
))) {
507 if (entry
->updateViaCache() >
508 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_NONE
) {
509 return NS_ERROR_INVALID_ARG
;
512 nsAutoCString installedTimeStr
;
513 GET_LINE(installedTimeStr
);
514 int64_t installedTime
= installedTimeStr
.ToInteger64(&rv
);
515 if (NS_WARN_IF(NS_FAILED(rv
))) {
518 entry
->currentWorkerInstalledTime() = installedTime
;
520 nsAutoCString activatedTimeStr
;
521 GET_LINE(activatedTimeStr
);
522 int64_t activatedTime
= activatedTimeStr
.ToInteger64(&rv
);
523 if (NS_WARN_IF(NS_FAILED(rv
))) {
526 entry
->currentWorkerActivatedTime() = activatedTime
;
528 nsAutoCString lastUpdateTimeStr
;
529 GET_LINE(lastUpdateTimeStr
);
530 int64_t lastUpdateTime
= lastUpdateTimeStr
.ToInteger64(&rv
);
531 if (NS_WARN_IF(NS_FAILED(rv
))) {
534 entry
->lastUpdateTime() = lastUpdateTime
;
536 nsAutoCString navigationPreloadEnabledStr
;
537 GET_LINE(navigationPreloadEnabledStr
);
538 bool navigationPreloadEnabled
=
539 navigationPreloadEnabledStr
.ToInteger(&rv
);
540 if (NS_WARN_IF(NS_FAILED(rv
))) {
543 entry
->navigationPreloadState().enabled() = navigationPreloadEnabled
;
545 GET_LINE(entry
->navigationPreloadState().headerValue());
546 } else if (version
.EqualsLiteral("8")) {
547 rv
= CreatePrincipalInfo(lineInputStream
, entry
);
548 if (NS_WARN_IF(NS_FAILED(rv
))) {
552 GET_LINE(entry
->currentWorkerURL());
554 nsAutoCString fetchFlag
;
556 if (!fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
) &&
557 !fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE
)) {
558 return NS_ERROR_INVALID_ARG
;
560 entry
->currentWorkerHandlesFetch() =
561 fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
);
563 nsAutoCString cacheName
;
565 CopyUTF8toUTF16(cacheName
, entry
->cacheName());
567 nsAutoCString updateViaCache
;
568 GET_LINE(updateViaCache
);
569 entry
->updateViaCache() = updateViaCache
.ToInteger(&rv
, 16);
570 if (NS_WARN_IF(NS_FAILED(rv
))) {
573 if (entry
->updateViaCache() >
574 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_NONE
) {
575 return NS_ERROR_INVALID_ARG
;
578 nsAutoCString installedTimeStr
;
579 GET_LINE(installedTimeStr
);
580 int64_t installedTime
= installedTimeStr
.ToInteger64(&rv
);
581 if (NS_WARN_IF(NS_FAILED(rv
))) {
584 entry
->currentWorkerInstalledTime() = installedTime
;
586 nsAutoCString activatedTimeStr
;
587 GET_LINE(activatedTimeStr
);
588 int64_t activatedTime
= activatedTimeStr
.ToInteger64(&rv
);
589 if (NS_WARN_IF(NS_FAILED(rv
))) {
592 entry
->currentWorkerActivatedTime() = activatedTime
;
594 nsAutoCString lastUpdateTimeStr
;
595 GET_LINE(lastUpdateTimeStr
);
596 int64_t lastUpdateTime
= lastUpdateTimeStr
.ToInteger64(&rv
);
597 if (NS_WARN_IF(NS_FAILED(rv
))) {
600 entry
->lastUpdateTime() = lastUpdateTime
;
602 entry
->navigationPreloadState() = gDefaultNavigationPreloadState
;
603 } else if (version
.EqualsLiteral("7")) {
604 rv
= CreatePrincipalInfo(lineInputStream
, entry
);
605 if (NS_WARN_IF(NS_FAILED(rv
))) {
609 GET_LINE(entry
->currentWorkerURL());
611 nsAutoCString fetchFlag
;
613 if (!fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
) &&
614 !fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE
)) {
615 return NS_ERROR_INVALID_ARG
;
617 entry
->currentWorkerHandlesFetch() =
618 fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
);
620 nsAutoCString cacheName
;
622 CopyUTF8toUTF16(cacheName
, entry
->cacheName());
624 nsAutoCString loadFlags
;
626 entry
->updateViaCache() =
627 loadFlags
.ToInteger(&rv
, 16) == nsIRequest::LOAD_NORMAL
628 ? nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_ALL
629 : nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS
;
631 if (NS_WARN_IF(NS_FAILED(rv
))) {
635 nsAutoCString installedTimeStr
;
636 GET_LINE(installedTimeStr
);
637 int64_t installedTime
= installedTimeStr
.ToInteger64(&rv
);
638 if (NS_WARN_IF(NS_FAILED(rv
))) {
641 entry
->currentWorkerInstalledTime() = installedTime
;
643 nsAutoCString activatedTimeStr
;
644 GET_LINE(activatedTimeStr
);
645 int64_t activatedTime
= activatedTimeStr
.ToInteger64(&rv
);
646 if (NS_WARN_IF(NS_FAILED(rv
))) {
649 entry
->currentWorkerActivatedTime() = activatedTime
;
651 nsAutoCString lastUpdateTimeStr
;
652 GET_LINE(lastUpdateTimeStr
);
653 int64_t lastUpdateTime
= lastUpdateTimeStr
.ToInteger64(&rv
);
654 if (NS_WARN_IF(NS_FAILED(rv
))) {
657 entry
->lastUpdateTime() = lastUpdateTime
;
659 entry
->navigationPreloadState() = gDefaultNavigationPreloadState
;
660 } else if (version
.EqualsLiteral("6")) {
661 rv
= CreatePrincipalInfo(lineInputStream
, entry
);
662 if (NS_WARN_IF(NS_FAILED(rv
))) {
666 GET_LINE(entry
->currentWorkerURL());
668 nsAutoCString fetchFlag
;
670 if (!fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
) &&
671 !fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE
)) {
672 return NS_ERROR_INVALID_ARG
;
674 entry
->currentWorkerHandlesFetch() =
675 fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
);
677 nsAutoCString cacheName
;
679 CopyUTF8toUTF16(cacheName
, entry
->cacheName());
681 nsAutoCString loadFlags
;
683 entry
->updateViaCache() =
684 loadFlags
.ToInteger(&rv
, 16) == nsIRequest::LOAD_NORMAL
685 ? nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_ALL
686 : nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS
;
688 if (NS_WARN_IF(NS_FAILED(rv
))) {
692 entry
->currentWorkerInstalledTime() = 0;
693 entry
->currentWorkerActivatedTime() = 0;
694 entry
->lastUpdateTime() = 0;
696 entry
->navigationPreloadState() = gDefaultNavigationPreloadState
;
697 } else if (version
.EqualsLiteral("5")) {
701 rv
= CreatePrincipalInfo(lineInputStream
, entry
);
702 if (NS_WARN_IF(NS_FAILED(rv
))) {
706 GET_LINE(entry
->currentWorkerURL());
708 nsAutoCString fetchFlag
;
710 if (!fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
) &&
711 !fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE
)) {
712 return NS_ERROR_INVALID_ARG
;
714 entry
->currentWorkerHandlesFetch() =
715 fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
);
717 nsAutoCString cacheName
;
719 CopyUTF8toUTF16(cacheName
, entry
->cacheName());
721 entry
->updateViaCache() =
722 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS
;
724 entry
->currentWorkerInstalledTime() = 0;
725 entry
->currentWorkerActivatedTime() = 0;
726 entry
->lastUpdateTime() = 0;
728 entry
->navigationPreloadState() = gDefaultNavigationPreloadState
;
729 } else if (version
.EqualsLiteral("4")) {
733 rv
= CreatePrincipalInfo(lineInputStream
, entry
);
734 if (NS_WARN_IF(NS_FAILED(rv
))) {
738 GET_LINE(entry
->currentWorkerURL());
740 // default handlesFetch flag to Enabled
741 entry
->currentWorkerHandlesFetch() = true;
743 nsAutoCString cacheName
;
745 CopyUTF8toUTF16(cacheName
, entry
->cacheName());
747 entry
->updateViaCache() =
748 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS
;
750 entry
->currentWorkerInstalledTime() = 0;
751 entry
->currentWorkerActivatedTime() = 0;
752 entry
->lastUpdateTime() = 0;
754 entry
->navigationPreloadState() = gDefaultNavigationPreloadState
;
755 } else if (version
.EqualsLiteral("3")) {
759 rv
= CreatePrincipalInfo(lineInputStream
, entry
, true);
760 if (NS_WARN_IF(NS_FAILED(rv
))) {
764 GET_LINE(entry
->currentWorkerURL());
766 // default handlesFetch flag to Enabled
767 entry
->currentWorkerHandlesFetch() = true;
769 nsAutoCString cacheName
;
771 CopyUTF8toUTF16(cacheName
, entry
->cacheName());
773 entry
->updateViaCache() =
774 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS
;
776 entry
->currentWorkerInstalledTime() = 0;
777 entry
->currentWorkerActivatedTime() = 0;
778 entry
->lastUpdateTime() = 0;
780 entry
->navigationPreloadState() = gDefaultNavigationPreloadState
;
781 } else if (version
.EqualsLiteral("2")) {
785 rv
= CreatePrincipalInfo(lineInputStream
, entry
, true);
786 if (NS_WARN_IF(NS_FAILED(rv
))) {
790 // scriptSpec is no more used in latest version.
791 nsAutoCString unused
;
794 GET_LINE(entry
->currentWorkerURL());
796 // default handlesFetch flag to Enabled
797 entry
->currentWorkerHandlesFetch() = true;
799 nsAutoCString cacheName
;
801 CopyUTF8toUTF16(cacheName
, entry
->cacheName());
803 // waitingCacheName is no more used in latest version.
806 entry
->updateViaCache() =
807 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS
;
809 entry
->currentWorkerInstalledTime() = 0;
810 entry
->currentWorkerActivatedTime() = 0;
811 entry
->lastUpdateTime() = 0;
813 entry
->navigationPreloadState() = gDefaultNavigationPreloadState
;
815 MOZ_ASSERT_UNREACHABLE("Should never get here!");
820 rv
= lineInputStream
->ReadLine(line
, &hasMoreLines
);
821 if (NS_WARN_IF(NS_FAILED(rv
))) {
825 if (!line
.EqualsLiteral(SERVICEWORKERREGISTRAR_TERMINATOR
)) {
826 return NS_ERROR_FAILURE
;
832 // We currently only call this at startup where we block the main thread
833 // preventing further operation until it completes, however take the lock
834 // in case that changes
837 MonitorAutoLock
lock(mMonitor
);
838 // Copy data over to mData.
839 for (uint32_t i
= 0; i
< tmpData
.Length(); ++i
) {
840 // Older versions could sometimes write out empty, useless entries.
842 if (!ServiceWorkerRegistrationDataIsValid(tmpData
[i
])) {
848 MOZ_ASSERT(overwrite
);
849 // If this is an old profile, then we might need to deduplicate. In
850 // theory this can be removed in the future (Bug 1248449)
851 for (uint32_t j
= 0; j
< mData
.Length(); ++j
) {
852 // Use same comparison as RegisterServiceWorker. Scope contains
853 // basic origin information. Combine with any principal attributes.
854 if (Equivalent(tmpData
[i
], mData
[j
])) {
855 // Last match wins, just like legacy loading used to do in
856 // the ServiceWorkerManager.
857 mData
[j
] = tmpData
[i
];
858 // Dupe found, so overwrite file with reduced list.
865 // Otherwise assert no duplications in debug builds.
866 for (uint32_t j
= 0; j
< mData
.Length(); ++j
) {
867 MOZ_ASSERT(!Equivalent(tmpData
[i
], mData
[j
]));
872 mData
.AppendElement(tmpData
[i
]);
876 // Overwrite previous version.
877 // Cannot call SaveData directly because gtest uses main-thread.
879 // XXX NOTE: if we could be accessed multi-threaded here, we would need to
880 // find a way to lock around access to mData. Since we can't, suppress the
881 // thread-safety warnings.
882 MOZ_PUSH_IGNORE_THREAD_SAFETY
883 if (overwrite
&& NS_FAILED(WriteData(mData
))) {
884 NS_WARNING("Failed to write data for the ServiceWorker Registations.");
887 MOZ_POP_THREAD_SAFETY
892 void ServiceWorkerRegistrar::DeleteData() {
893 // We cannot assert about the correct thread because normally this method
894 // runs on a IO thread, but in gTests we call it from the main-thread.
896 nsCOMPtr
<nsIFile
> file
;
899 MonitorAutoLock
lock(mMonitor
);
906 nsresult rv
= mProfileDir
->Clone(getter_AddRefs(file
));
907 if (NS_WARN_IF(NS_FAILED(rv
))) {
912 nsresult rv
= file
->Append(nsLiteralString(SERVICEWORKERREGISTRAR_FILE
));
913 if (NS_WARN_IF(NS_FAILED(rv
))) {
917 rv
= file
->Remove(false);
918 if (rv
== NS_ERROR_FILE_NOT_FOUND
) {
922 if (NS_WARN_IF(NS_FAILED(rv
))) {
927 void ServiceWorkerRegistrar::RegisterServiceWorkerInternal(
928 const ServiceWorkerRegistrationData
& aData
) {
930 for (uint32_t i
= 0, len
= mData
.Length(); i
< len
; ++i
) {
931 if (Equivalent(aData
, mData
[i
])) {
933 if (mData
[i
].currentWorkerHandlesFetch()) {
934 // Decrement here if we found it, in case the new registration no
935 // longer handles Fetch. If it continues to handle fetch, we'll
936 // bump it back later.
937 gServiceWorkersRegisteredFetch
--;
945 MOZ_ASSERT(ServiceWorkerRegistrationDataIsValid(aData
));
946 mData
.AppendElement(aData
);
947 // We didn't find an entry to update, so we have 1 more
948 gServiceWorkersRegistered
++;
950 // Handles bumping both for new registrations and updates
951 if (aData
.currentWorkerHandlesFetch()) {
952 gServiceWorkersRegisteredFetch
++;
955 Telemetry::ScalarSet(Telemetry::ScalarID::SERVICEWORKER_REGISTRATIONS
,
956 u
"All"_ns
, gServiceWorkersRegistered
);
957 Telemetry::ScalarSet(Telemetry::ScalarID::SERVICEWORKER_REGISTRATIONS
,
958 u
"Fetch"_ns
, gServiceWorkersRegisteredFetch
);
959 LOG(("Register: %u, fetch %u\n", gServiceWorkersRegistered
,
960 gServiceWorkersRegisteredFetch
));
962 mDataGeneration
= GetNextGeneration();
965 class ServiceWorkerRegistrarSaveDataRunnable final
: public Runnable
{
966 nsCOMPtr
<nsIEventTarget
> mEventTarget
;
967 const nsTArray
<ServiceWorkerRegistrationData
> mData
;
968 const uint32_t mGeneration
;
971 ServiceWorkerRegistrarSaveDataRunnable(
972 nsTArray
<ServiceWorkerRegistrationData
>&& aData
, uint32_t aGeneration
)
973 : Runnable("dom::ServiceWorkerRegistrarSaveDataRunnable"),
974 mEventTarget(GetCurrentSerialEventTarget()),
975 mData(std::move(aData
)),
976 mGeneration(aGeneration
) {
977 AssertIsOnBackgroundThread();
978 MOZ_DIAGNOSTIC_ASSERT(mGeneration
!= kInvalidGeneration
);
983 RefPtr
<ServiceWorkerRegistrar
> service
= ServiceWorkerRegistrar::Get();
986 uint32_t fileGeneration
= kInvalidGeneration
;
988 if (NS_SUCCEEDED(service
->SaveData(mData
))) {
989 fileGeneration
= mGeneration
;
992 RefPtr
<Runnable
> runnable
= NewRunnableMethod
<uint32_t>(
993 "ServiceWorkerRegistrar::DataSaved", service
,
994 &ServiceWorkerRegistrar::DataSaved
, fileGeneration
);
996 mEventTarget
->Dispatch(runnable
.forget(), NS_DISPATCH_NORMAL
));
1002 void ServiceWorkerRegistrar::MaybeScheduleSaveData() {
1003 AssertIsOnBackgroundThread();
1004 MOZ_ASSERT(!mShuttingDown
);
1006 if (mShuttingDown
|| mSaveDataRunnableDispatched
||
1007 mDataGeneration
<= mFileGeneration
) {
1011 nsCOMPtr
<nsIEventTarget
> target
=
1012 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
1013 MOZ_ASSERT(target
, "Must have stream transport service");
1015 uint32_t generation
= kInvalidGeneration
;
1016 nsTArray
<ServiceWorkerRegistrationData
> data
;
1019 MonitorAutoLock
lock(mMonitor
);
1020 generation
= mDataGeneration
;
1021 data
.AppendElements(mData
);
1024 RefPtr
<Runnable
> runnable
=
1025 new ServiceWorkerRegistrarSaveDataRunnable(std::move(data
), generation
);
1026 nsresult rv
= target
->Dispatch(runnable
.forget(), NS_DISPATCH_NORMAL
);
1027 NS_ENSURE_SUCCESS_VOID(rv
);
1029 mSaveDataRunnableDispatched
= true;
1032 void ServiceWorkerRegistrar::ShutdownCompleted() {
1033 MOZ_ASSERT(NS_IsMainThread());
1035 DebugOnly
<nsresult
> rv
= GetShutdownPhase()->RemoveBlocker(this);
1036 MOZ_ASSERT(NS_SUCCEEDED(rv
));
1039 nsresult
ServiceWorkerRegistrar::SaveData(
1040 const nsTArray
<ServiceWorkerRegistrationData
>& aData
) {
1041 MOZ_ASSERT(!NS_IsMainThread());
1043 nsresult rv
= WriteData(aData
);
1044 if (NS_FAILED(rv
)) {
1045 NS_WARNING("Failed to write data for the ServiceWorker Registations.");
1046 // Don't touch the file or in-memory state. Writing files can
1047 // sometimes fail due to virus scanning, etc. We should just leave
1048 // things as is so the next save operation can pick up any changes
1049 // without losing data.
1054 void ServiceWorkerRegistrar::DataSaved(uint32_t aFileGeneration
) {
1055 AssertIsOnBackgroundThread();
1056 MOZ_ASSERT(mSaveDataRunnableDispatched
);
1058 mSaveDataRunnableDispatched
= false;
1060 // Check for shutdown before possibly triggering any more saves
1062 MaybeScheduleShutdownCompleted();
1063 if (mShuttingDown
) {
1067 // If we got a valid generation, then the save was successful.
1068 if (aFileGeneration
!= kInvalidGeneration
) {
1069 // Update the file generation. We also check to see if we
1070 // can reset the generation back to zero if the file and data
1071 // are now in sync. This allows us to avoid dealing with wrap
1072 // around of the generation count.
1073 mFileGeneration
= aFileGeneration
;
1074 MaybeResetGeneration();
1076 // Successful write resets the retry count.
1079 // Possibly schedule another save operation if more data
1080 // has come in while processing this one.
1081 MaybeScheduleSaveData();
1086 // Otherwise, the save failed since the generation is invalid. We
1087 // want to retry the save, but only a limited number of times.
1088 static const uint32_t kMaxRetryCount
= 2;
1089 if (mRetryCount
>= kMaxRetryCount
) {
1094 MaybeScheduleSaveData();
1097 void ServiceWorkerRegistrar::MaybeScheduleShutdownCompleted() {
1098 AssertIsOnBackgroundThread();
1100 if (mSaveDataRunnableDispatched
|| !mShuttingDown
) {
1104 RefPtr
<Runnable
> runnable
=
1105 NewRunnableMethod("dom::ServiceWorkerRegistrar::ShutdownCompleted", this,
1106 &ServiceWorkerRegistrar::ShutdownCompleted
);
1107 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable
.forget()));
1110 uint32_t ServiceWorkerRegistrar::GetNextGeneration() {
1111 uint32_t ret
= mDataGeneration
+ 1;
1112 if (ret
== kInvalidGeneration
) {
1118 void ServiceWorkerRegistrar::MaybeResetGeneration() {
1119 if (mDataGeneration
!= mFileGeneration
) {
1122 mDataGeneration
= mFileGeneration
= 0;
1125 bool ServiceWorkerRegistrar::IsSupportedVersion(
1126 const nsACString
& aVersion
) const {
1127 uint32_t numVersions
= ArrayLength(gSupportedRegistrarVersions
);
1128 for (uint32_t i
= 0; i
< numVersions
; i
++) {
1129 if (aVersion
.EqualsASCII(gSupportedRegistrarVersions
[i
])) {
1136 nsresult
ServiceWorkerRegistrar::WriteData(
1137 const nsTArray
<ServiceWorkerRegistrationData
>& aData
) {
1138 // We cannot assert about the correct thread because normally this method
1139 // runs on a IO thread, but in gTests we call it from the main-thread.
1141 nsCOMPtr
<nsIFile
> file
;
1144 MonitorAutoLock
lock(mMonitor
);
1147 return NS_ERROR_FAILURE
;
1150 nsresult rv
= mProfileDir
->Clone(getter_AddRefs(file
));
1151 if (NS_WARN_IF(NS_FAILED(rv
))) {
1156 nsresult rv
= file
->Append(nsLiteralString(SERVICEWORKERREGISTRAR_FILE
));
1157 if (NS_WARN_IF(NS_FAILED(rv
))) {
1161 nsCOMPtr
<nsIOutputStream
> stream
;
1162 rv
= NS_NewSafeLocalFileOutputStream(getter_AddRefs(stream
), file
);
1163 if (NS_WARN_IF(NS_FAILED(rv
))) {
1167 nsAutoCString buffer
;
1168 buffer
.AppendLiteral(SERVICEWORKERREGISTRAR_VERSION
);
1169 buffer
.Append('\n');
1172 rv
= stream
->Write(buffer
.Data(), buffer
.Length(), &count
);
1173 if (NS_WARN_IF(NS_FAILED(rv
))) {
1177 if (count
!= buffer
.Length()) {
1178 return NS_ERROR_UNEXPECTED
;
1181 for (uint32_t i
= 0, len
= aData
.Length(); i
< len
; ++i
) {
1182 // We have an assertion further up the stack, but as a last
1183 // resort avoid writing out broken entries here.
1184 if (!ServiceWorkerRegistrationDataIsValid(aData
[i
])) {
1188 const mozilla::ipc::PrincipalInfo
& info
= aData
[i
].principal();
1190 MOZ_ASSERT(info
.type() ==
1191 mozilla::ipc::PrincipalInfo::TContentPrincipalInfo
);
1193 const mozilla::ipc::ContentPrincipalInfo
& cInfo
=
1194 info
.get_ContentPrincipalInfo();
1196 nsAutoCString suffix
;
1197 cInfo
.attrs().CreateSuffix(suffix
);
1200 buffer
.Append(suffix
.get());
1201 buffer
.Append('\n');
1203 buffer
.Append(aData
[i
].scope());
1204 buffer
.Append('\n');
1206 buffer
.Append(aData
[i
].currentWorkerURL());
1207 buffer
.Append('\n');
1209 buffer
.Append(aData
[i
].currentWorkerHandlesFetch()
1210 ? SERVICEWORKERREGISTRAR_TRUE
1211 : SERVICEWORKERREGISTRAR_FALSE
);
1212 buffer
.Append('\n');
1214 buffer
.Append(NS_ConvertUTF16toUTF8(aData
[i
].cacheName()));
1215 buffer
.Append('\n');
1217 buffer
.AppendInt(aData
[i
].updateViaCache(), 16);
1218 buffer
.Append('\n');
1219 MOZ_DIAGNOSTIC_ASSERT(
1220 aData
[i
].updateViaCache() ==
1221 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS
||
1222 aData
[i
].updateViaCache() ==
1223 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_ALL
||
1224 aData
[i
].updateViaCache() ==
1225 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_NONE
);
1227 static_assert(nsIRequest::LOAD_NORMAL
== 0,
1228 "LOAD_NORMAL matches serialized value.");
1229 static_assert(nsIRequest::VALIDATE_ALWAYS
== (1 << 11),
1230 "VALIDATE_ALWAYS matches serialized value");
1232 buffer
.AppendInt(aData
[i
].currentWorkerInstalledTime());
1233 buffer
.Append('\n');
1235 buffer
.AppendInt(aData
[i
].currentWorkerActivatedTime());
1236 buffer
.Append('\n');
1238 buffer
.AppendInt(aData
[i
].lastUpdateTime());
1239 buffer
.Append('\n');
1242 static_cast<int32_t>(aData
[i
].navigationPreloadState().enabled()));
1243 buffer
.Append('\n');
1245 buffer
.Append(aData
[i
].navigationPreloadState().headerValue());
1246 buffer
.Append('\n');
1248 buffer
.AppendLiteral(SERVICEWORKERREGISTRAR_TERMINATOR
);
1249 buffer
.Append('\n');
1251 rv
= stream
->Write(buffer
.Data(), buffer
.Length(), &count
);
1252 if (NS_WARN_IF(NS_FAILED(rv
))) {
1256 if (count
!= buffer
.Length()) {
1257 return NS_ERROR_UNEXPECTED
;
1261 nsCOMPtr
<nsISafeOutputStream
> safeStream
= do_QueryInterface(stream
);
1262 MOZ_ASSERT(safeStream
);
1264 rv
= safeStream
->Finish();
1265 if (NS_WARN_IF(NS_FAILED(rv
))) {
1272 void ServiceWorkerRegistrar::ProfileStarted() {
1273 MOZ_ASSERT(NS_IsMainThread());
1275 MonitorAutoLock
lock(mMonitor
);
1276 MOZ_DIAGNOSTIC_ASSERT(!mProfileDir
);
1278 nsresult rv
= NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR
,
1279 getter_AddRefs(mProfileDir
));
1280 if (NS_WARN_IF(NS_FAILED(rv
))) {
1284 nsAutoString blockerName
;
1285 MOZ_ALWAYS_SUCCEEDS(GetName(blockerName
));
1287 rv
= GetShutdownPhase()->AddBlocker(
1288 this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__
), __LINE__
, blockerName
);
1289 if (NS_WARN_IF(NS_FAILED(rv
))) {
1293 nsCOMPtr
<nsIEventTarget
> target
=
1294 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
1295 MOZ_ASSERT(target
, "Must have stream transport service");
1297 nsCOMPtr
<nsIRunnable
> runnable
=
1298 NewRunnableMethod("dom::ServiceWorkerRegistrar::LoadData", this,
1299 &ServiceWorkerRegistrar::LoadData
);
1300 rv
= target
->Dispatch(runnable
.forget(), NS_DISPATCH_NORMAL
);
1301 if (NS_FAILED(rv
)) {
1302 NS_WARNING("Failed to dispatch the LoadDataRunnable.");
1306 void ServiceWorkerRegistrar::ProfileStopped() {
1307 MOZ_ASSERT(NS_IsMainThread());
1309 MonitorAutoLock
lock(mMonitor
);
1312 nsresult rv
= NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR
,
1313 getter_AddRefs(mProfileDir
));
1314 if (NS_WARN_IF(NS_FAILED(rv
))) {
1315 // If we do not have a profile directory, we are somehow screwed.
1316 MOZ_DIAGNOSTIC_ASSERT(
1318 "NS_GetSpecialDirectory for NS_APP_USER_PROFILE_50_DIR failed!");
1322 // Mutations to the ServiceWorkerRegistrar happen on the PBackground thread,
1323 // issued by the ServiceWorkerManagerService, so the appropriate place to
1324 // trigger shutdown is on that thread.
1326 // However, it's quite possible that the PBackground thread was not brought
1327 // into existence for xpcshell tests. We don't cause it to be created
1328 // ourselves for any reason, for example.
1330 // In this scenario, we know that:
1331 // - We will receive exactly one call to ourself from BlockShutdown() and
1332 // BlockShutdown() will be called (at most) once.
1333 // - The only way our Shutdown() method gets called is via
1334 // BackgroundParentImpl::RecvShutdownServiceWorkerRegistrar() being
1335 // invoked, which only happens if we get to that send below here that we
1337 // - All Shutdown() does is set mShuttingDown=true (essential for
1338 // invariants) and invoke MaybeScheduleShutdownCompleted().
1339 // - Since there is no PBackground thread, mSaveDataRunnableDispatched must
1340 // be false because only MaybeScheduleSaveData() set it and it only runs
1341 // on the background thread, so it cannot have run. And so we would
1342 // expect MaybeScheduleShutdownCompleted() to schedule an invocation of
1343 // ShutdownCompleted on the main thread.
1344 PBackgroundChild
* child
= BackgroundChild::GetForCurrentThread();
1345 if (mProfileDir
&& child
) {
1346 if (child
->SendShutdownServiceWorkerRegistrar()) {
1347 // Normal shutdown sequence has been initiated, go home.
1350 // If we get here, the PBackground thread has probably gone nuts and we
1352 MOZ_DIAGNOSTIC_ASSERT(
1353 false, "Unable to send the ShutdownServiceWorkerRegistrar message.");
1356 // On any error it's appropriate to set mShuttingDown=true (as Shutdown
1357 // would do) and directly invoke ShutdownCompleted() (as Shutdown would
1358 // indirectly do via MaybeScheduleShutdownCompleted) in order to unblock
1360 mShuttingDown
= true;
1361 ShutdownCompleted();
1364 // Async shutdown blocker methods
1367 ServiceWorkerRegistrar::BlockShutdown(nsIAsyncShutdownClient
* aClient
) {
1373 ServiceWorkerRegistrar::GetName(nsAString
& aName
) {
1374 aName
= u
"ServiceWorkerRegistrar: Flushing data"_ns
;
1379 ServiceWorkerRegistrar::GetState(nsIPropertyBag
** aBagOut
) {
1380 nsCOMPtr
<nsIWritablePropertyBag2
> propertyBag
=
1381 do_CreateInstance("@mozilla.org/hash-property-bag;1");
1383 MOZ_TRY(propertyBag
->SetPropertyAsBool(u
"shuttingDown"_ns
, mShuttingDown
));
1385 MOZ_TRY(propertyBag
->SetPropertyAsBool(u
"saveDataRunnableDispatched"_ns
,
1386 mSaveDataRunnableDispatched
));
1388 propertyBag
.forget(aBagOut
);
1393 #define RELEASE_ASSERT_SUCCEEDED(rv, name) \
1395 if (NS_FAILED(rv)) { \
1396 if (rv == NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS) { \
1397 if (auto* context = CycleCollectedJSContext::Get()) { \
1398 if (RefPtr<Exception> exn = context->GetPendingException()) { \
1399 MOZ_CRASH_UNSAFE_PRINTF("Failed to get " name ": %s", \
1400 exn->GetMessageMoz().get()); \
1405 nsAutoCString errorName; \
1406 GetErrorName(rv, errorName); \
1407 MOZ_CRASH_UNSAFE_PRINTF("Failed to get " name ": %s", errorName.get()); \
1411 nsCOMPtr
<nsIAsyncShutdownClient
> ServiceWorkerRegistrar::GetShutdownPhase()
1414 nsCOMPtr
<nsIAsyncShutdownService
> svc
=
1415 do_GetService("@mozilla.org/async-shutdown-service;1", &rv
);
1416 // If this fails, something is very wrong on the JS side (or we're out of
1417 // memory), and there's no point in continuing startup. Include as much
1418 // information as possible in the crash report.
1419 RELEASE_ASSERT_SUCCEEDED(rv
, "async shutdown service");
1421 nsCOMPtr
<nsIAsyncShutdownClient
> client
;
1422 rv
= svc
->GetProfileBeforeChange(getter_AddRefs(client
));
1423 RELEASE_ASSERT_SUCCEEDED(rv
, "profileBeforeChange shutdown blocker");
1427 #undef RELEASE_ASSERT_SUCCEEDED
1429 void ServiceWorkerRegistrar::Shutdown() {
1430 AssertIsOnBackgroundThread();
1431 MOZ_ASSERT(!mShuttingDown
);
1433 mShuttingDown
= true;
1434 MaybeScheduleShutdownCompleted();
1438 ServiceWorkerRegistrar::Observe(nsISupports
* aSubject
, const char* aTopic
,
1439 const char16_t
* aData
) {
1440 MOZ_ASSERT(NS_IsMainThread());
1442 if (!strcmp(aTopic
, "profile-after-change")) {
1443 nsCOMPtr
<nsIObserverService
> observerService
=
1444 services::GetObserverService();
1445 observerService
->RemoveObserver(this, "profile-after-change");
1447 // The profile is fully loaded, now we can proceed with the loading of data
1454 MOZ_ASSERT(false, "ServiceWorkerRegistrar got unexpected topic!");
1455 return NS_ERROR_UNEXPECTED
;
1458 } // namespace mozilla::dom