diff options
Diffstat (limited to 'dom/serviceworkers/ServiceWorkerShutdownState.cpp')
-rw-r--r-- | dom/serviceworkers/ServiceWorkerShutdownState.cpp | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/dom/serviceworkers/ServiceWorkerShutdownState.cpp b/dom/serviceworkers/ServiceWorkerShutdownState.cpp new file mode 100644 index 0000000000..c47191888e --- /dev/null +++ b/dom/serviceworkers/ServiceWorkerShutdownState.cpp @@ -0,0 +1,168 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ServiceWorkerShutdownState.h" + +#include <array> +#include <type_traits> + +#include "MainThreadUtils.h" +#include "ServiceWorkerUtils.h" +#include "mozilla/Assertions.h" +#include "mozilla/SchedulerGroup.h" +#include "mozilla/Unused.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/RemoteWorkerService.h" +#include "mozilla/dom/ServiceWorkerManager.h" +#include "mozilla/dom/WorkerCommon.h" +#include "mozilla/ipc/BackgroundParent.h" +#include "nsDebug.h" +#include "nsThreadUtils.h" +#include "nsXULAppAPI.h" + +namespace mozilla { +namespace dom { + +using Progress = ServiceWorkerShutdownState::Progress; + +namespace { + +constexpr inline auto UnderlyingProgressValue(Progress aProgress) { + return std::underlying_type_t<Progress>(aProgress); +} + +constexpr std::array<const char*, UnderlyingProgressValue(Progress::EndGuard_)> + gProgressStrings = {{ + // clang-format off + "parent process main thread", + "parent process IPDL background thread", + "content process worker launcher thread", + "content process main thread", + "shutdown completed" + // clang-format on + }}; + +} // anonymous namespace + +ServiceWorkerShutdownState::ServiceWorkerShutdownState() + : mProgress(Progress::ParentProcessMainThread) { + MOZ_ASSERT(XRE_IsParentProcess()); + MOZ_ASSERT(NS_IsMainThread()); +} + +ServiceWorkerShutdownState::~ServiceWorkerShutdownState() { + Unused << NS_WARN_IF(mProgress != Progress::ShutdownCompleted); +} + +const char* ServiceWorkerShutdownState::GetProgressString() const { + return gProgressStrings[UnderlyingProgressValue(mProgress)]; +} + +void ServiceWorkerShutdownState::SetProgress(Progress aProgress) { + MOZ_ASSERT(aProgress != Progress::EndGuard_); + MOZ_RELEASE_ASSERT(UnderlyingProgressValue(mProgress) + 1 == + UnderlyingProgressValue(aProgress)); + + mProgress = aProgress; +} + +namespace { + +void ReportProgressToServiceWorkerManager(uint32_t aShutdownStateId, + Progress aProgress) { + MOZ_ASSERT(XRE_IsParentProcess()); + MOZ_ASSERT(NS_IsMainThread()); + + RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); + MOZ_RELEASE_ASSERT(swm, "ServiceWorkers should shutdown before SWM."); + + swm->ReportServiceWorkerShutdownProgress(aShutdownStateId, aProgress); +} + +void ReportProgressToParentProcess(uint32_t aShutdownStateId, + Progress aProgress) { + MOZ_ASSERT(XRE_IsContentProcess()); + MOZ_ASSERT(NS_IsMainThread()); + + ContentChild* contentChild = ContentChild::GetSingleton(); + MOZ_ASSERT(contentChild); + + contentChild->SendReportServiceWorkerShutdownProgress(aShutdownStateId, + aProgress); +} + +void ReportServiceWorkerShutdownProgress(uint32_t aShutdownStateId, + Progress aProgress) { + MOZ_ASSERT(UnderlyingProgressValue(Progress::ParentProcessMainThread) < + UnderlyingProgressValue(aProgress)); + MOZ_ASSERT(UnderlyingProgressValue(aProgress) < + UnderlyingProgressValue(Progress::EndGuard_)); + + nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction( + __func__, [shutdownStateId = aShutdownStateId, progress = aProgress] { + if (XRE_IsParentProcess()) { + ReportProgressToServiceWorkerManager(shutdownStateId, progress); + } else { + ReportProgressToParentProcess(shutdownStateId, progress); + } + }); + + if (NS_IsMainThread()) { + MOZ_ALWAYS_SUCCEEDS(r->Run()); + } else { + MOZ_ALWAYS_SUCCEEDS( + SchedulerGroup::Dispatch(TaskCategory::Other, r.forget())); + } +} + +void ReportServiceWorkerShutdownProgress(uint32_t aShutdownStateId) { + Progress progress = Progress::EndGuard_; + + if (XRE_IsParentProcess()) { + mozilla::ipc::AssertIsOnBackgroundThread(); + + progress = Progress::ParentProcessIpdlBackgroundThread; + } else { + if (NS_IsMainThread()) { + progress = Progress::ContentProcessMainThread; + } else { + MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread()); + progress = Progress::ContentProcessWorkerLauncherThread; + } + } + + ReportServiceWorkerShutdownProgress(aShutdownStateId, progress); +} + +} // anonymous namespace + +void MaybeReportServiceWorkerShutdownProgress(const ServiceWorkerOpArgs& aArgs, + bool aShutdownCompleted) { + if (!ServiceWorkerParentInterceptEnabled() || + (XRE_IsParentProcess() && !XRE_IsE10sParentProcess())) { + return; + } + + if (aShutdownCompleted) { + MOZ_ASSERT(aArgs.type() == + ServiceWorkerOpArgs::TServiceWorkerTerminateWorkerOpArgs); + + ReportServiceWorkerShutdownProgress( + aArgs.get_ServiceWorkerTerminateWorkerOpArgs().shutdownStateId(), + Progress::ShutdownCompleted); + + return; + } + + if (aArgs.type() == + ServiceWorkerOpArgs::TServiceWorkerTerminateWorkerOpArgs) { + ReportServiceWorkerShutdownProgress( + aArgs.get_ServiceWorkerTerminateWorkerOpArgs().shutdownStateId()); + } +} + +} // namespace dom +} // namespace mozilla |