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/StaticPrefs_dom.h"
13 #include "nsIEventTarget.h"
14 #include "nsIInputStream.h"
15 #include "nsILineInputStream.h"
16 #include "nsIObserverService.h"
17 #include "nsIOutputStream.h"
18 #include "nsISafeOutputStream.h"
19 #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
) {
70 nsresult rv
= NS_NewURI(getter_AddRefs(url
), aURL
);
71 if (NS_WARN_IF(NS_FAILED(rv
))) {
75 OriginAttributes attrs
;
76 nsCOMPtr
<nsIPrincipal
> principal
=
77 BasePrincipal::CreateContentPrincipal(url
, attrs
);
79 return NS_ERROR_NULL_POINTER
;
82 rv
= principal
->GetOriginNoSuffix(aOrigin
);
83 if (NS_WARN_IF(NS_FAILED(rv
))) {
87 rv
= principal
->GetBaseDomain(aBaseDomain
);
88 if (NS_WARN_IF(NS_FAILED(rv
))) {
95 nsresult
ReadLine(nsILineInputStream
* aStream
, nsACString
& aValue
) {
97 nsresult rv
= aStream
->ReadLine(aValue
, &hasMoreLines
);
98 if (NS_WARN_IF(NS_FAILED(rv
))) {
102 if (NS_WARN_IF(!hasMoreLines
)) {
103 return NS_ERROR_FAILURE
;
109 nsresult
CreatePrincipalInfo(nsILineInputStream
* aStream
,
110 ServiceWorkerRegistrationData
* aEntry
,
111 bool aSkipSpec
= false) {
112 nsAutoCString suffix
;
113 nsresult rv
= ReadLine(aStream
, suffix
);
114 if (NS_WARN_IF(NS_FAILED(rv
))) {
118 OriginAttributes attrs
;
119 if (!attrs
.PopulateFromSuffix(suffix
)) {
120 return NS_ERROR_INVALID_ARG
;
124 nsAutoCString unused
;
125 nsresult rv
= ReadLine(aStream
, unused
);
126 if (NS_WARN_IF(NS_FAILED(rv
))) {
131 rv
= ReadLine(aStream
, aEntry
->scope());
132 if (NS_WARN_IF(NS_FAILED(rv
))) {
137 nsCString baseDomain
;
138 rv
= GetOriginAndBaseDomain(aEntry
->scope(), origin
, baseDomain
);
139 if (NS_WARN_IF(NS_FAILED(rv
))) {
143 aEntry
->principal() = mozilla::ipc::ContentPrincipalInfo(
144 attrs
, origin
, aEntry
->scope(), Nothing(), baseDomain
);
149 const IPCNavigationPreloadState
gDefaultNavigationPreloadState(false,
154 NS_IMPL_ISUPPORTS(ServiceWorkerRegistrar
, nsIObserver
, nsIAsyncShutdownBlocker
)
156 void ServiceWorkerRegistrar::Initialize() {
157 MOZ_ASSERT(!gServiceWorkerRegistrar
);
159 if (!XRE_IsParentProcess()) {
163 gServiceWorkerRegistrar
= new ServiceWorkerRegistrar();
164 ClearOnShutdown(&gServiceWorkerRegistrar
);
166 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
168 DebugOnly
<nsresult
> rv
= obs
->AddObserver(gServiceWorkerRegistrar
,
169 "profile-after-change", false);
170 MOZ_ASSERT(NS_SUCCEEDED(rv
));
175 already_AddRefed
<ServiceWorkerRegistrar
> ServiceWorkerRegistrar::Get() {
176 MOZ_ASSERT(XRE_IsParentProcess());
178 MOZ_ASSERT(gServiceWorkerRegistrar
);
179 RefPtr
<ServiceWorkerRegistrar
> service
= gServiceWorkerRegistrar
.get();
180 return service
.forget();
183 ServiceWorkerRegistrar::ServiceWorkerRegistrar()
184 : mMonitor("ServiceWorkerRegistrar.mMonitor"),
186 mDataGeneration(kInvalidGeneration
),
187 mFileGeneration(kInvalidGeneration
),
189 mShuttingDown(false),
190 mSaveDataRunnableDispatched(false) {
191 MOZ_ASSERT(NS_IsMainThread());
194 ServiceWorkerRegistrar::~ServiceWorkerRegistrar() {
195 MOZ_ASSERT(!mSaveDataRunnableDispatched
);
198 void ServiceWorkerRegistrar::GetRegistrations(
199 nsTArray
<ServiceWorkerRegistrationData
>& aValues
) {
200 MOZ_ASSERT(NS_IsMainThread());
201 MOZ_ASSERT(aValues
.IsEmpty());
203 MonitorAutoLock
lock(mMonitor
);
205 // If we don't have the profile directory, profile is not started yet (and
206 // probably we are in a utest).
211 // We care just about the first execution because this can be blocked by
212 // loading data from disk.
213 static bool firstTime
= true;
217 startTime
= TimeStamp::NowLoRes();
220 // Waiting for data loaded.
221 mMonitor
.AssertCurrentThreadOwns();
222 while (!mDataLoaded
) {
226 aValues
.AppendElements(mData
);
228 MaybeResetGeneration();
229 MOZ_DIAGNOSTIC_ASSERT(mDataGeneration
!= kInvalidGeneration
);
230 MOZ_DIAGNOSTIC_ASSERT(mFileGeneration
!= kInvalidGeneration
);
234 Telemetry::AccumulateTimeDelta(
235 Telemetry::SERVICE_WORKER_REGISTRATION_LOADING
, startTime
);
241 bool Equivalent(const ServiceWorkerRegistrationData
& aLeft
,
242 const ServiceWorkerRegistrationData
& aRight
) {
243 MOZ_ASSERT(aLeft
.principal().type() ==
244 mozilla::ipc::PrincipalInfo::TContentPrincipalInfo
);
245 MOZ_ASSERT(aRight
.principal().type() ==
246 mozilla::ipc::PrincipalInfo::TContentPrincipalInfo
);
248 const auto& leftPrincipal
= aLeft
.principal().get_ContentPrincipalInfo();
249 const auto& rightPrincipal
= aRight
.principal().get_ContentPrincipalInfo();
251 // Only compare the attributes, not the spec part of the principal.
252 // The scope comparison above already covers the origin and codebase
253 // principals include the full path in their spec which is not what
255 return aLeft
.scope() == aRight
.scope() &&
256 leftPrincipal
.attrs() == rightPrincipal
.attrs();
259 } // anonymous namespace
261 void ServiceWorkerRegistrar::RegisterServiceWorker(
262 const ServiceWorkerRegistrationData
& aData
) {
263 AssertIsOnBackgroundThread();
266 NS_WARNING("Failed to register a serviceWorker during shutting down.");
271 MonitorAutoLock
lock(mMonitor
);
272 MOZ_ASSERT(mDataLoaded
);
273 RegisterServiceWorkerInternal(aData
);
276 MaybeScheduleSaveData();
277 StorageActivityService::SendActivity(aData
.principal());
280 void ServiceWorkerRegistrar::UnregisterServiceWorker(
281 const PrincipalInfo
& aPrincipalInfo
, const nsACString
& aScope
) {
282 AssertIsOnBackgroundThread();
285 NS_WARNING("Failed to unregister a serviceWorker during shutting down.");
289 bool deleted
= false;
292 MonitorAutoLock
lock(mMonitor
);
293 MOZ_ASSERT(mDataLoaded
);
295 ServiceWorkerRegistrationData tmp
;
296 tmp
.principal() = aPrincipalInfo
;
297 tmp
.scope() = aScope
;
299 for (uint32_t i
= 0; i
< mData
.Length(); ++i
) {
300 if (Equivalent(tmp
, mData
[i
])) {
301 gServiceWorkersRegistered
--;
302 if (mData
[i
].currentWorkerHandlesFetch()) {
303 gServiceWorkersRegisteredFetch
--;
306 Telemetry::ScalarSet(Telemetry::ScalarID::SERVICEWORKER_REGISTRATIONS
,
307 u
"All"_ns
, gServiceWorkersRegistered
);
308 Telemetry::ScalarSet(Telemetry::ScalarID::SERVICEWORKER_REGISTRATIONS
,
309 u
"Fetch"_ns
, gServiceWorkersRegisteredFetch
);
310 LOG(("Unregister ServiceWorker: %u, fetch %u\n",
311 gServiceWorkersRegistered
, gServiceWorkersRegisteredFetch
));
313 mData
.RemoveElementAt(i
);
314 mDataGeneration
= GetNextGeneration();
322 MaybeScheduleSaveData();
323 StorageActivityService::SendActivity(aPrincipalInfo
);
327 void ServiceWorkerRegistrar::RemoveAll() {
328 AssertIsOnBackgroundThread();
331 NS_WARNING("Failed to remove all the serviceWorkers during shutting down.");
335 bool deleted
= false;
337 nsTArray
<ServiceWorkerRegistrationData
> data
;
339 MonitorAutoLock
lock(mMonitor
);
340 MOZ_ASSERT(mDataLoaded
);
342 // Let's take a copy in order to inform StorageActivityService.
343 data
= mData
.Clone();
345 deleted
= !mData
.IsEmpty();
348 mDataGeneration
= GetNextGeneration();
355 MaybeScheduleSaveData();
357 for (uint32_t i
= 0, len
= data
.Length(); i
< len
; ++i
) {
358 StorageActivityService::SendActivity(data
[i
].principal());
362 void ServiceWorkerRegistrar::LoadData() {
363 MOZ_ASSERT(!NS_IsMainThread());
366 MonitorAutoLock
lock(mMonitor
);
367 MOZ_ASSERT(!mDataLoaded
);
371 nsresult rv
= ReadData();
373 if (NS_WARN_IF(NS_FAILED(rv
))) {
375 // Also if the reading failed we have to notify what is waiting for data.
378 MonitorAutoLock
lock(mMonitor
);
379 MOZ_ASSERT(!mDataLoaded
);
384 bool ServiceWorkerRegistrar::ReloadDataForTest() {
385 if (NS_WARN_IF(!StaticPrefs::dom_serviceWorkers_testing_enabled())) {
389 MOZ_ASSERT(NS_IsMainThread());
390 MonitorAutoLock
lock(mMonitor
);
394 nsCOMPtr
<nsIEventTarget
> target
=
395 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
396 MOZ_ASSERT(target
, "Must have stream transport service");
398 nsCOMPtr
<nsIRunnable
> runnable
=
399 NewRunnableMethod("dom::ServiceWorkerRegistrar::LoadData", this,
400 &ServiceWorkerRegistrar::LoadData
);
401 nsresult rv
= target
->Dispatch(runnable
.forget(), NS_DISPATCH_NORMAL
);
403 NS_WARNING("Failed to dispatch the LoadDataRunnable.");
407 mMonitor
.AssertCurrentThreadOwns();
408 while (!mDataLoaded
) {
415 nsresult
ServiceWorkerRegistrar::ReadData() {
416 // We cannot assert about the correct thread because normally this method
417 // runs on a IO thread, but in gTests we call it from the main-thread.
419 nsCOMPtr
<nsIFile
> file
;
422 MonitorAutoLock
lock(mMonitor
);
425 return NS_ERROR_FAILURE
;
428 nsresult rv
= mProfileDir
->Clone(getter_AddRefs(file
));
429 if (NS_WARN_IF(NS_FAILED(rv
))) {
434 nsresult rv
= file
->Append(nsLiteralString(SERVICEWORKERREGISTRAR_FILE
));
435 if (NS_WARN_IF(NS_FAILED(rv
))) {
440 rv
= file
->Exists(&exists
);
441 if (NS_WARN_IF(NS_FAILED(rv
))) {
449 nsCOMPtr
<nsIInputStream
> stream
;
450 rv
= NS_NewLocalFileInputStream(getter_AddRefs(stream
), file
);
451 if (NS_WARN_IF(NS_FAILED(rv
))) {
455 nsCOMPtr
<nsILineInputStream
> lineInputStream
= do_QueryInterface(stream
);
456 MOZ_ASSERT(lineInputStream
);
458 nsAutoCString version
;
460 rv
= lineInputStream
->ReadLine(version
, &hasMoreLines
);
461 if (NS_WARN_IF(NS_FAILED(rv
))) {
465 if (!IsSupportedVersion(version
)) {
466 nsContentUtils::LogMessageToConsole(
467 nsPrintfCString("Unsupported service worker registrar version: %s",
470 return NS_ERROR_FAILURE
;
473 nsTArray
<ServiceWorkerRegistrationData
> tmpData
;
475 bool overwrite
= false;
477 while (hasMoreLines
) {
478 ServiceWorkerRegistrationData
* entry
= tmpData
.AppendElement();
480 #define GET_LINE(x) \
481 rv = lineInputStream->ReadLine(x, &hasMoreLines); \
482 if (NS_WARN_IF(NS_FAILED(rv))) { \
485 if (NS_WARN_IF(!hasMoreLines)) { \
486 return NS_ERROR_FAILURE; \
490 if (version
.EqualsLiteral(SERVICEWORKERREGISTRAR_VERSION
)) {
491 rv
= CreatePrincipalInfo(lineInputStream
, entry
);
492 if (NS_WARN_IF(NS_FAILED(rv
))) {
496 GET_LINE(entry
->currentWorkerURL());
498 nsAutoCString fetchFlag
;
500 if (!fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
) &&
501 !fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE
)) {
502 return NS_ERROR_INVALID_ARG
;
504 entry
->currentWorkerHandlesFetch() =
505 fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
);
507 nsAutoCString cacheName
;
509 CopyUTF8toUTF16(cacheName
, entry
->cacheName());
511 nsAutoCString updateViaCache
;
512 GET_LINE(updateViaCache
);
513 entry
->updateViaCache() = updateViaCache
.ToInteger(&rv
, 16);
514 if (NS_WARN_IF(NS_FAILED(rv
))) {
517 if (entry
->updateViaCache() >
518 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_NONE
) {
519 return NS_ERROR_INVALID_ARG
;
522 nsAutoCString installedTimeStr
;
523 GET_LINE(installedTimeStr
);
524 int64_t installedTime
= installedTimeStr
.ToInteger64(&rv
);
525 if (NS_WARN_IF(NS_FAILED(rv
))) {
528 entry
->currentWorkerInstalledTime() = installedTime
;
530 nsAutoCString activatedTimeStr
;
531 GET_LINE(activatedTimeStr
);
532 int64_t activatedTime
= activatedTimeStr
.ToInteger64(&rv
);
533 if (NS_WARN_IF(NS_FAILED(rv
))) {
536 entry
->currentWorkerActivatedTime() = activatedTime
;
538 nsAutoCString lastUpdateTimeStr
;
539 GET_LINE(lastUpdateTimeStr
);
540 int64_t lastUpdateTime
= lastUpdateTimeStr
.ToInteger64(&rv
);
541 if (NS_WARN_IF(NS_FAILED(rv
))) {
544 entry
->lastUpdateTime() = lastUpdateTime
;
546 nsAutoCString navigationPreloadEnabledStr
;
547 GET_LINE(navigationPreloadEnabledStr
);
548 bool navigationPreloadEnabled
=
549 navigationPreloadEnabledStr
.ToInteger(&rv
);
550 if (NS_WARN_IF(NS_FAILED(rv
))) {
553 entry
->navigationPreloadState().enabled() = navigationPreloadEnabled
;
555 GET_LINE(entry
->navigationPreloadState().headerValue());
556 } else if (version
.EqualsLiteral("8")) {
557 rv
= CreatePrincipalInfo(lineInputStream
, entry
);
558 if (NS_WARN_IF(NS_FAILED(rv
))) {
562 GET_LINE(entry
->currentWorkerURL());
564 nsAutoCString fetchFlag
;
566 if (!fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
) &&
567 !fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE
)) {
568 return NS_ERROR_INVALID_ARG
;
570 entry
->currentWorkerHandlesFetch() =
571 fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
);
573 nsAutoCString cacheName
;
575 CopyUTF8toUTF16(cacheName
, entry
->cacheName());
577 nsAutoCString updateViaCache
;
578 GET_LINE(updateViaCache
);
579 entry
->updateViaCache() = updateViaCache
.ToInteger(&rv
, 16);
580 if (NS_WARN_IF(NS_FAILED(rv
))) {
583 if (entry
->updateViaCache() >
584 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_NONE
) {
585 return NS_ERROR_INVALID_ARG
;
588 nsAutoCString installedTimeStr
;
589 GET_LINE(installedTimeStr
);
590 int64_t installedTime
= installedTimeStr
.ToInteger64(&rv
);
591 if (NS_WARN_IF(NS_FAILED(rv
))) {
594 entry
->currentWorkerInstalledTime() = installedTime
;
596 nsAutoCString activatedTimeStr
;
597 GET_LINE(activatedTimeStr
);
598 int64_t activatedTime
= activatedTimeStr
.ToInteger64(&rv
);
599 if (NS_WARN_IF(NS_FAILED(rv
))) {
602 entry
->currentWorkerActivatedTime() = activatedTime
;
604 nsAutoCString lastUpdateTimeStr
;
605 GET_LINE(lastUpdateTimeStr
);
606 int64_t lastUpdateTime
= lastUpdateTimeStr
.ToInteger64(&rv
);
607 if (NS_WARN_IF(NS_FAILED(rv
))) {
610 entry
->lastUpdateTime() = lastUpdateTime
;
612 entry
->navigationPreloadState() = gDefaultNavigationPreloadState
;
613 } else if (version
.EqualsLiteral("7")) {
614 rv
= CreatePrincipalInfo(lineInputStream
, entry
);
615 if (NS_WARN_IF(NS_FAILED(rv
))) {
619 GET_LINE(entry
->currentWorkerURL());
621 nsAutoCString fetchFlag
;
623 if (!fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
) &&
624 !fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE
)) {
625 return NS_ERROR_INVALID_ARG
;
627 entry
->currentWorkerHandlesFetch() =
628 fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
);
630 nsAutoCString cacheName
;
632 CopyUTF8toUTF16(cacheName
, entry
->cacheName());
634 nsAutoCString loadFlags
;
636 entry
->updateViaCache() =
637 loadFlags
.ToInteger(&rv
, 16) == nsIRequest::LOAD_NORMAL
638 ? nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_ALL
639 : nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS
;
641 if (NS_WARN_IF(NS_FAILED(rv
))) {
645 nsAutoCString installedTimeStr
;
646 GET_LINE(installedTimeStr
);
647 int64_t installedTime
= installedTimeStr
.ToInteger64(&rv
);
648 if (NS_WARN_IF(NS_FAILED(rv
))) {
651 entry
->currentWorkerInstalledTime() = installedTime
;
653 nsAutoCString activatedTimeStr
;
654 GET_LINE(activatedTimeStr
);
655 int64_t activatedTime
= activatedTimeStr
.ToInteger64(&rv
);
656 if (NS_WARN_IF(NS_FAILED(rv
))) {
659 entry
->currentWorkerActivatedTime() = activatedTime
;
661 nsAutoCString lastUpdateTimeStr
;
662 GET_LINE(lastUpdateTimeStr
);
663 int64_t lastUpdateTime
= lastUpdateTimeStr
.ToInteger64(&rv
);
664 if (NS_WARN_IF(NS_FAILED(rv
))) {
667 entry
->lastUpdateTime() = lastUpdateTime
;
669 entry
->navigationPreloadState() = gDefaultNavigationPreloadState
;
670 } else if (version
.EqualsLiteral("6")) {
671 rv
= CreatePrincipalInfo(lineInputStream
, entry
);
672 if (NS_WARN_IF(NS_FAILED(rv
))) {
676 GET_LINE(entry
->currentWorkerURL());
678 nsAutoCString fetchFlag
;
680 if (!fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
) &&
681 !fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE
)) {
682 return NS_ERROR_INVALID_ARG
;
684 entry
->currentWorkerHandlesFetch() =
685 fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
);
687 nsAutoCString cacheName
;
689 CopyUTF8toUTF16(cacheName
, entry
->cacheName());
691 nsAutoCString loadFlags
;
693 entry
->updateViaCache() =
694 loadFlags
.ToInteger(&rv
, 16) == nsIRequest::LOAD_NORMAL
695 ? nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_ALL
696 : nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS
;
698 if (NS_WARN_IF(NS_FAILED(rv
))) {
702 entry
->currentWorkerInstalledTime() = 0;
703 entry
->currentWorkerActivatedTime() = 0;
704 entry
->lastUpdateTime() = 0;
706 entry
->navigationPreloadState() = gDefaultNavigationPreloadState
;
707 } else if (version
.EqualsLiteral("5")) {
711 rv
= CreatePrincipalInfo(lineInputStream
, entry
);
712 if (NS_WARN_IF(NS_FAILED(rv
))) {
716 GET_LINE(entry
->currentWorkerURL());
718 nsAutoCString fetchFlag
;
720 if (!fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
) &&
721 !fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE
)) {
722 return NS_ERROR_INVALID_ARG
;
724 entry
->currentWorkerHandlesFetch() =
725 fetchFlag
.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE
);
727 nsAutoCString cacheName
;
729 CopyUTF8toUTF16(cacheName
, entry
->cacheName());
731 entry
->updateViaCache() =
732 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS
;
734 entry
->currentWorkerInstalledTime() = 0;
735 entry
->currentWorkerActivatedTime() = 0;
736 entry
->lastUpdateTime() = 0;
738 entry
->navigationPreloadState() = gDefaultNavigationPreloadState
;
739 } else if (version
.EqualsLiteral("4")) {
743 rv
= CreatePrincipalInfo(lineInputStream
, entry
);
744 if (NS_WARN_IF(NS_FAILED(rv
))) {
748 GET_LINE(entry
->currentWorkerURL());
750 // default handlesFetch flag to Enabled
751 entry
->currentWorkerHandlesFetch() = true;
753 nsAutoCString cacheName
;
755 CopyUTF8toUTF16(cacheName
, entry
->cacheName());
757 entry
->updateViaCache() =
758 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS
;
760 entry
->currentWorkerInstalledTime() = 0;
761 entry
->currentWorkerActivatedTime() = 0;
762 entry
->lastUpdateTime() = 0;
764 entry
->navigationPreloadState() = gDefaultNavigationPreloadState
;
765 } else if (version
.EqualsLiteral("3")) {
769 rv
= CreatePrincipalInfo(lineInputStream
, entry
, true);
770 if (NS_WARN_IF(NS_FAILED(rv
))) {
774 GET_LINE(entry
->currentWorkerURL());
776 // default handlesFetch flag to Enabled
777 entry
->currentWorkerHandlesFetch() = true;
779 nsAutoCString cacheName
;
781 CopyUTF8toUTF16(cacheName
, entry
->cacheName());
783 entry
->updateViaCache() =
784 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS
;
786 entry
->currentWorkerInstalledTime() = 0;
787 entry
->currentWorkerActivatedTime() = 0;
788 entry
->lastUpdateTime() = 0;
790 entry
->navigationPreloadState() = gDefaultNavigationPreloadState
;
791 } else if (version
.EqualsLiteral("2")) {
795 rv
= CreatePrincipalInfo(lineInputStream
, entry
, true);
796 if (NS_WARN_IF(NS_FAILED(rv
))) {
800 // scriptSpec is no more used in latest version.
801 nsAutoCString unused
;
804 GET_LINE(entry
->currentWorkerURL());
806 // default handlesFetch flag to Enabled
807 entry
->currentWorkerHandlesFetch() = true;
809 nsAutoCString cacheName
;
811 CopyUTF8toUTF16(cacheName
, entry
->cacheName());
813 // waitingCacheName is no more used in latest version.
816 entry
->updateViaCache() =
817 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS
;
819 entry
->currentWorkerInstalledTime() = 0;
820 entry
->currentWorkerActivatedTime() = 0;
821 entry
->lastUpdateTime() = 0;
823 entry
->navigationPreloadState() = gDefaultNavigationPreloadState
;
825 MOZ_ASSERT_UNREACHABLE("Should never get here!");
830 rv
= lineInputStream
->ReadLine(line
, &hasMoreLines
);
831 if (NS_WARN_IF(NS_FAILED(rv
))) {
835 if (!line
.EqualsLiteral(SERVICEWORKERREGISTRAR_TERMINATOR
)) {
836 return NS_ERROR_FAILURE
;
842 // We currently only call this at startup where we block the main thread
843 // preventing further operation until it completes, however take the lock
844 // in case that changes
847 MonitorAutoLock
lock(mMonitor
);
848 // Copy data over to mData.
849 for (uint32_t i
= 0; i
< tmpData
.Length(); ++i
) {
850 // Older versions could sometimes write out empty, useless entries.
852 if (!ServiceWorkerRegistrationDataIsValid(tmpData
[i
])) {
858 MOZ_ASSERT(overwrite
);
859 // If this is an old profile, then we might need to deduplicate. In
860 // theory this can be removed in the future (Bug 1248449)
861 for (uint32_t j
= 0; j
< mData
.Length(); ++j
) {
862 // Use same comparison as RegisterServiceWorker. Scope contains
863 // basic origin information. Combine with any principal attributes.
864 if (Equivalent(tmpData
[i
], mData
[j
])) {
865 // Last match wins, just like legacy loading used to do in
866 // the ServiceWorkerManager.
867 mData
[j
] = tmpData
[i
];
868 // Dupe found, so overwrite file with reduced list.
875 // Otherwise assert no duplications in debug builds.
876 for (uint32_t j
= 0; j
< mData
.Length(); ++j
) {
877 MOZ_ASSERT(!Equivalent(tmpData
[i
], mData
[j
]));
882 mData
.AppendElement(tmpData
[i
]);
886 // Overwrite previous version.
887 // Cannot call SaveData directly because gtest uses main-thread.
889 // XXX NOTE: if we could be accessed multi-threaded here, we would need to
890 // find a way to lock around access to mData. Since we can't, suppress the
891 // thread-safety warnings.
892 MOZ_PUSH_IGNORE_THREAD_SAFETY
893 if (overwrite
&& NS_FAILED(WriteData(mData
))) {
894 NS_WARNING("Failed to write data for the ServiceWorker Registations.");
897 MOZ_POP_THREAD_SAFETY
902 void ServiceWorkerRegistrar::DeleteData() {
903 // We cannot assert about the correct thread because normally this method
904 // runs on a IO thread, but in gTests we call it from the main-thread.
906 nsCOMPtr
<nsIFile
> file
;
909 MonitorAutoLock
lock(mMonitor
);
916 nsresult rv
= mProfileDir
->Clone(getter_AddRefs(file
));
917 if (NS_WARN_IF(NS_FAILED(rv
))) {
922 nsresult rv
= file
->Append(nsLiteralString(SERVICEWORKERREGISTRAR_FILE
));
923 if (NS_WARN_IF(NS_FAILED(rv
))) {
927 rv
= file
->Remove(false);
928 if (rv
== NS_ERROR_FILE_NOT_FOUND
) {
932 if (NS_WARN_IF(NS_FAILED(rv
))) {
937 void ServiceWorkerRegistrar::RegisterServiceWorkerInternal(
938 const ServiceWorkerRegistrationData
& aData
) {
940 for (uint32_t i
= 0, len
= mData
.Length(); i
< len
; ++i
) {
941 if (Equivalent(aData
, mData
[i
])) {
943 if (mData
[i
].currentWorkerHandlesFetch()) {
944 // Decrement here if we found it, in case the new registration no
945 // longer handles Fetch. If it continues to handle fetch, we'll
946 // bump it back later.
947 gServiceWorkersRegisteredFetch
--;
955 MOZ_ASSERT(ServiceWorkerRegistrationDataIsValid(aData
));
956 mData
.AppendElement(aData
);
957 // We didn't find an entry to update, so we have 1 more
958 gServiceWorkersRegistered
++;
960 // Handles bumping both for new registrations and updates
961 if (aData
.currentWorkerHandlesFetch()) {
962 gServiceWorkersRegisteredFetch
++;
965 Telemetry::ScalarSet(Telemetry::ScalarID::SERVICEWORKER_REGISTRATIONS
,
966 u
"All"_ns
, gServiceWorkersRegistered
);
967 Telemetry::ScalarSet(Telemetry::ScalarID::SERVICEWORKER_REGISTRATIONS
,
968 u
"Fetch"_ns
, gServiceWorkersRegisteredFetch
);
969 LOG(("Register: %u, fetch %u\n", gServiceWorkersRegistered
,
970 gServiceWorkersRegisteredFetch
));
972 mDataGeneration
= GetNextGeneration();
975 class ServiceWorkerRegistrarSaveDataRunnable final
: public Runnable
{
976 nsCOMPtr
<nsIEventTarget
> mEventTarget
;
977 const nsTArray
<ServiceWorkerRegistrationData
> mData
;
978 const uint32_t mGeneration
;
981 ServiceWorkerRegistrarSaveDataRunnable(
982 nsTArray
<ServiceWorkerRegistrationData
>&& aData
, uint32_t aGeneration
)
983 : Runnable("dom::ServiceWorkerRegistrarSaveDataRunnable"),
984 mEventTarget(GetCurrentSerialEventTarget()),
985 mData(std::move(aData
)),
986 mGeneration(aGeneration
) {
987 AssertIsOnBackgroundThread();
988 MOZ_DIAGNOSTIC_ASSERT(mGeneration
!= kInvalidGeneration
);
993 RefPtr
<ServiceWorkerRegistrar
> service
= ServiceWorkerRegistrar::Get();
996 uint32_t fileGeneration
= kInvalidGeneration
;
998 if (NS_SUCCEEDED(service
->SaveData(mData
))) {
999 fileGeneration
= mGeneration
;
1002 RefPtr
<Runnable
> runnable
= NewRunnableMethod
<uint32_t>(
1003 "ServiceWorkerRegistrar::DataSaved", service
,
1004 &ServiceWorkerRegistrar::DataSaved
, fileGeneration
);
1005 MOZ_ALWAYS_SUCCEEDS(
1006 mEventTarget
->Dispatch(runnable
.forget(), NS_DISPATCH_NORMAL
));
1012 void ServiceWorkerRegistrar::MaybeScheduleSaveData() {
1013 AssertIsOnBackgroundThread();
1014 MOZ_ASSERT(!mShuttingDown
);
1016 if (mShuttingDown
|| mSaveDataRunnableDispatched
||
1017 mDataGeneration
<= mFileGeneration
) {
1021 nsCOMPtr
<nsIEventTarget
> target
=
1022 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
1023 MOZ_ASSERT(target
, "Must have stream transport service");
1025 uint32_t generation
= kInvalidGeneration
;
1026 nsTArray
<ServiceWorkerRegistrationData
> data
;
1029 MonitorAutoLock
lock(mMonitor
);
1030 generation
= mDataGeneration
;
1031 data
.AppendElements(mData
);
1034 RefPtr
<Runnable
> runnable
=
1035 new ServiceWorkerRegistrarSaveDataRunnable(std::move(data
), generation
);
1036 nsresult rv
= target
->Dispatch(runnable
.forget(), NS_DISPATCH_NORMAL
);
1037 NS_ENSURE_SUCCESS_VOID(rv
);
1039 mSaveDataRunnableDispatched
= true;
1042 void ServiceWorkerRegistrar::ShutdownCompleted() {
1043 MOZ_ASSERT(NS_IsMainThread());
1045 DebugOnly
<nsresult
> rv
= GetShutdownPhase()->RemoveBlocker(this);
1046 MOZ_ASSERT(NS_SUCCEEDED(rv
));
1049 nsresult
ServiceWorkerRegistrar::SaveData(
1050 const nsTArray
<ServiceWorkerRegistrationData
>& aData
) {
1051 MOZ_ASSERT(!NS_IsMainThread());
1053 nsresult rv
= WriteData(aData
);
1054 if (NS_FAILED(rv
)) {
1055 NS_WARNING("Failed to write data for the ServiceWorker Registations.");
1056 // Don't touch the file or in-memory state. Writing files can
1057 // sometimes fail due to virus scanning, etc. We should just leave
1058 // things as is so the next save operation can pick up any changes
1059 // without losing data.
1064 void ServiceWorkerRegistrar::DataSaved(uint32_t aFileGeneration
) {
1065 AssertIsOnBackgroundThread();
1066 MOZ_ASSERT(mSaveDataRunnableDispatched
);
1068 mSaveDataRunnableDispatched
= false;
1070 // Check for shutdown before possibly triggering any more saves
1072 MaybeScheduleShutdownCompleted();
1073 if (mShuttingDown
) {
1077 // If we got a valid generation, then the save was successful.
1078 if (aFileGeneration
!= kInvalidGeneration
) {
1079 // Update the file generation. We also check to see if we
1080 // can reset the generation back to zero if the file and data
1081 // are now in sync. This allows us to avoid dealing with wrap
1082 // around of the generation count.
1083 mFileGeneration
= aFileGeneration
;
1084 MaybeResetGeneration();
1086 // Successful write resets the retry count.
1089 // Possibly schedule another save operation if more data
1090 // has come in while processing this one.
1091 MaybeScheduleSaveData();
1096 // Otherwise, the save failed since the generation is invalid. We
1097 // want to retry the save, but only a limited number of times.
1098 static const uint32_t kMaxRetryCount
= 2;
1099 if (mRetryCount
>= kMaxRetryCount
) {
1104 MaybeScheduleSaveData();
1107 void ServiceWorkerRegistrar::MaybeScheduleShutdownCompleted() {
1108 AssertIsOnBackgroundThread();
1110 if (mSaveDataRunnableDispatched
|| !mShuttingDown
) {
1114 RefPtr
<Runnable
> runnable
=
1115 NewRunnableMethod("dom::ServiceWorkerRegistrar::ShutdownCompleted", this,
1116 &ServiceWorkerRegistrar::ShutdownCompleted
);
1117 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable
.forget()));
1120 uint32_t ServiceWorkerRegistrar::GetNextGeneration() {
1121 uint32_t ret
= mDataGeneration
+ 1;
1122 if (ret
== kInvalidGeneration
) {
1128 void ServiceWorkerRegistrar::MaybeResetGeneration() {
1129 if (mDataGeneration
!= mFileGeneration
) {
1132 mDataGeneration
= mFileGeneration
= 0;
1135 bool ServiceWorkerRegistrar::IsSupportedVersion(
1136 const nsACString
& aVersion
) const {
1137 uint32_t numVersions
= ArrayLength(gSupportedRegistrarVersions
);
1138 for (uint32_t i
= 0; i
< numVersions
; i
++) {
1139 if (aVersion
.EqualsASCII(gSupportedRegistrarVersions
[i
])) {
1146 nsresult
ServiceWorkerRegistrar::WriteData(
1147 const nsTArray
<ServiceWorkerRegistrationData
>& aData
) {
1148 // We cannot assert about the correct thread because normally this method
1149 // runs on a IO thread, but in gTests we call it from the main-thread.
1151 nsCOMPtr
<nsIFile
> file
;
1154 MonitorAutoLock
lock(mMonitor
);
1157 return NS_ERROR_FAILURE
;
1160 nsresult rv
= mProfileDir
->Clone(getter_AddRefs(file
));
1161 if (NS_WARN_IF(NS_FAILED(rv
))) {
1166 nsresult rv
= file
->Append(nsLiteralString(SERVICEWORKERREGISTRAR_FILE
));
1167 if (NS_WARN_IF(NS_FAILED(rv
))) {
1171 nsCOMPtr
<nsIOutputStream
> stream
;
1172 rv
= NS_NewSafeLocalFileOutputStream(getter_AddRefs(stream
), file
);
1173 if (NS_WARN_IF(NS_FAILED(rv
))) {
1177 nsAutoCString buffer
;
1178 buffer
.AppendLiteral(SERVICEWORKERREGISTRAR_VERSION
);
1179 buffer
.Append('\n');
1182 rv
= stream
->Write(buffer
.Data(), buffer
.Length(), &count
);
1183 if (NS_WARN_IF(NS_FAILED(rv
))) {
1187 if (count
!= buffer
.Length()) {
1188 return NS_ERROR_UNEXPECTED
;
1191 for (uint32_t i
= 0, len
= aData
.Length(); i
< len
; ++i
) {
1192 // We have an assertion further up the stack, but as a last
1193 // resort avoid writing out broken entries here.
1194 if (!ServiceWorkerRegistrationDataIsValid(aData
[i
])) {
1198 const mozilla::ipc::PrincipalInfo
& info
= aData
[i
].principal();
1200 MOZ_ASSERT(info
.type() ==
1201 mozilla::ipc::PrincipalInfo::TContentPrincipalInfo
);
1203 const mozilla::ipc::ContentPrincipalInfo
& cInfo
=
1204 info
.get_ContentPrincipalInfo();
1206 nsAutoCString suffix
;
1207 cInfo
.attrs().CreateSuffix(suffix
);
1210 buffer
.Append(suffix
.get());
1211 buffer
.Append('\n');
1213 buffer
.Append(aData
[i
].scope());
1214 buffer
.Append('\n');
1216 buffer
.Append(aData
[i
].currentWorkerURL());
1217 buffer
.Append('\n');
1219 buffer
.Append(aData
[i
].currentWorkerHandlesFetch()
1220 ? SERVICEWORKERREGISTRAR_TRUE
1221 : SERVICEWORKERREGISTRAR_FALSE
);
1222 buffer
.Append('\n');
1224 buffer
.Append(NS_ConvertUTF16toUTF8(aData
[i
].cacheName()));
1225 buffer
.Append('\n');
1227 buffer
.AppendInt(aData
[i
].updateViaCache(), 16);
1228 buffer
.Append('\n');
1229 MOZ_DIAGNOSTIC_ASSERT(
1230 aData
[i
].updateViaCache() ==
1231 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS
||
1232 aData
[i
].updateViaCache() ==
1233 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_ALL
||
1234 aData
[i
].updateViaCache() ==
1235 nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_NONE
);
1237 static_assert(nsIRequest::LOAD_NORMAL
== 0,
1238 "LOAD_NORMAL matches serialized value.");
1239 static_assert(nsIRequest::VALIDATE_ALWAYS
== (1 << 11),
1240 "VALIDATE_ALWAYS matches serialized value");
1242 buffer
.AppendInt(aData
[i
].currentWorkerInstalledTime());
1243 buffer
.Append('\n');
1245 buffer
.AppendInt(aData
[i
].currentWorkerActivatedTime());
1246 buffer
.Append('\n');
1248 buffer
.AppendInt(aData
[i
].lastUpdateTime());
1249 buffer
.Append('\n');
1252 static_cast<int32_t>(aData
[i
].navigationPreloadState().enabled()));
1253 buffer
.Append('\n');
1255 buffer
.Append(aData
[i
].navigationPreloadState().headerValue());
1256 buffer
.Append('\n');
1258 buffer
.AppendLiteral(SERVICEWORKERREGISTRAR_TERMINATOR
);
1259 buffer
.Append('\n');
1261 rv
= stream
->Write(buffer
.Data(), buffer
.Length(), &count
);
1262 if (NS_WARN_IF(NS_FAILED(rv
))) {
1266 if (count
!= buffer
.Length()) {
1267 return NS_ERROR_UNEXPECTED
;
1271 nsCOMPtr
<nsISafeOutputStream
> safeStream
= do_QueryInterface(stream
);
1272 MOZ_ASSERT(safeStream
);
1274 rv
= safeStream
->Finish();
1275 if (NS_WARN_IF(NS_FAILED(rv
))) {
1282 void ServiceWorkerRegistrar::ProfileStarted() {
1283 MOZ_ASSERT(NS_IsMainThread());
1285 MonitorAutoLock
lock(mMonitor
);
1286 MOZ_DIAGNOSTIC_ASSERT(!mProfileDir
);
1288 nsresult rv
= NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR
,
1289 getter_AddRefs(mProfileDir
));
1290 if (NS_WARN_IF(NS_FAILED(rv
))) {
1294 nsAutoString blockerName
;
1295 MOZ_ALWAYS_SUCCEEDS(GetName(blockerName
));
1297 rv
= GetShutdownPhase()->AddBlocker(
1298 this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__
), __LINE__
, blockerName
);
1299 if (NS_WARN_IF(NS_FAILED(rv
))) {
1303 nsCOMPtr
<nsIEventTarget
> target
=
1304 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
1305 MOZ_ASSERT(target
, "Must have stream transport service");
1307 nsCOMPtr
<nsIRunnable
> runnable
=
1308 NewRunnableMethod("dom::ServiceWorkerRegistrar::LoadData", this,
1309 &ServiceWorkerRegistrar::LoadData
);
1310 rv
= target
->Dispatch(runnable
.forget(), NS_DISPATCH_NORMAL
);
1311 if (NS_FAILED(rv
)) {
1312 NS_WARNING("Failed to dispatch the LoadDataRunnable.");
1316 void ServiceWorkerRegistrar::ProfileStopped() {
1317 MOZ_ASSERT(NS_IsMainThread());
1319 MonitorAutoLock
lock(mMonitor
);
1322 nsresult rv
= NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR
,
1323 getter_AddRefs(mProfileDir
));
1324 if (NS_WARN_IF(NS_FAILED(rv
))) {
1325 // If we do not have a profile directory, we are somehow screwed.
1326 MOZ_DIAGNOSTIC_ASSERT(
1328 "NS_GetSpecialDirectory for NS_APP_USER_PROFILE_50_DIR failed!");
1332 // Mutations to the ServiceWorkerRegistrar happen on the PBackground thread,
1333 // issued by the ServiceWorkerManagerService, so the appropriate place to
1334 // trigger shutdown is on that thread.
1336 // However, it's quite possible that the PBackground thread was not brought
1337 // into existence for xpcshell tests. We don't cause it to be created
1338 // ourselves for any reason, for example.
1340 // In this scenario, we know that:
1341 // - We will receive exactly one call to ourself from BlockShutdown() and
1342 // BlockShutdown() will be called (at most) once.
1343 // - The only way our Shutdown() method gets called is via
1344 // BackgroundParentImpl::RecvShutdownServiceWorkerRegistrar() being
1345 // invoked, which only happens if we get to that send below here that we
1347 // - All Shutdown() does is set mShuttingDown=true (essential for
1348 // invariants) and invoke MaybeScheduleShutdownCompleted().
1349 // - Since there is no PBackground thread, mSaveDataRunnableDispatched must
1350 // be false because only MaybeScheduleSaveData() set it and it only runs
1351 // on the background thread, so it cannot have run. And so we would
1352 // expect MaybeScheduleShutdownCompleted() to schedule an invocation of
1353 // ShutdownCompleted on the main thread.
1354 PBackgroundChild
* child
= BackgroundChild::GetForCurrentThread();
1355 if (mProfileDir
&& child
) {
1356 if (child
->SendShutdownServiceWorkerRegistrar()) {
1357 // Normal shutdown sequence has been initiated, go home.
1360 // If we get here, the PBackground thread has probably gone nuts and we
1362 MOZ_DIAGNOSTIC_ASSERT(
1363 false, "Unable to send the ShutdownServiceWorkerRegistrar message.");
1366 // On any error it's appropriate to set mShuttingDown=true (as Shutdown
1367 // would do) and directly invoke ShutdownCompleted() (as Shutdown would
1368 // indirectly do via MaybeScheduleShutdownCompleted) in order to unblock
1370 mShuttingDown
= true;
1371 ShutdownCompleted();
1374 // Async shutdown blocker methods
1377 ServiceWorkerRegistrar::BlockShutdown(nsIAsyncShutdownClient
* aClient
) {
1383 ServiceWorkerRegistrar::GetName(nsAString
& aName
) {
1384 aName
= u
"ServiceWorkerRegistrar: Flushing data"_ns
;
1389 ServiceWorkerRegistrar::GetState(nsIPropertyBag
** aBagOut
) {
1390 nsCOMPtr
<nsIWritablePropertyBag2
> propertyBag
=
1391 do_CreateInstance("@mozilla.org/hash-property-bag;1");
1393 MOZ_TRY(propertyBag
->SetPropertyAsBool(u
"shuttingDown"_ns
, mShuttingDown
));
1395 MOZ_TRY(propertyBag
->SetPropertyAsBool(u
"saveDataRunnableDispatched"_ns
,
1396 mSaveDataRunnableDispatched
));
1398 propertyBag
.forget(aBagOut
);
1403 #define RELEASE_ASSERT_SUCCEEDED(rv, name) \
1405 if (NS_FAILED(rv)) { \
1406 if ((rv) == NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS) { \
1407 if (auto* context = CycleCollectedJSContext::Get()) { \
1408 if (RefPtr<Exception> exn = context->GetPendingException()) { \
1409 MOZ_CRASH_UNSAFE_PRINTF("Failed to get " name ": %s", \
1410 exn->GetMessageMoz().get()); \
1415 nsAutoCString errorName; \
1416 GetErrorName(rv, errorName); \
1417 MOZ_CRASH_UNSAFE_PRINTF("Failed to get " name ": %s", errorName.get()); \
1421 nsCOMPtr
<nsIAsyncShutdownClient
> ServiceWorkerRegistrar::GetShutdownPhase()
1424 nsCOMPtr
<nsIAsyncShutdownService
> svc
=
1425 do_GetService("@mozilla.org/async-shutdown-service;1", &rv
);
1426 // If this fails, something is very wrong on the JS side (or we're out of
1427 // memory), and there's no point in continuing startup. Include as much
1428 // information as possible in the crash report.
1429 RELEASE_ASSERT_SUCCEEDED(rv
, "async shutdown service");
1431 nsCOMPtr
<nsIAsyncShutdownClient
> client
;
1432 rv
= svc
->GetProfileBeforeChange(getter_AddRefs(client
));
1433 RELEASE_ASSERT_SUCCEEDED(rv
, "profileBeforeChange shutdown blocker");
1437 #undef RELEASE_ASSERT_SUCCEEDED
1439 void ServiceWorkerRegistrar::Shutdown() {
1440 AssertIsOnBackgroundThread();
1441 MOZ_ASSERT(!mShuttingDown
);
1443 mShuttingDown
= true;
1444 MaybeScheduleShutdownCompleted();
1448 ServiceWorkerRegistrar::Observe(nsISupports
* aSubject
, const char* aTopic
,
1449 const char16_t
* aData
) {
1450 MOZ_ASSERT(NS_IsMainThread());
1452 if (!strcmp(aTopic
, "profile-after-change")) {
1453 nsCOMPtr
<nsIObserverService
> observerService
=
1454 services::GetObserverService();
1455 observerService
->RemoveObserver(this, "profile-after-change");
1457 // The profile is fully loaded, now we can proceed with the loading of data
1464 MOZ_ASSERT(false, "ServiceWorkerRegistrar got unexpected topic!");
1465 return NS_ERROR_UNEXPECTED
;
1468 } // namespace mozilla::dom