ServiceWorkerShutdownState.cpp (5496B)
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 "ServiceWorkerShutdownState.h" 8 9 #include <array> 10 #include <type_traits> 11 12 #include "MainThreadUtils.h" 13 #include "ServiceWorkerUtils.h" 14 #include "mozilla/Assertions.h" 15 #include "mozilla/SchedulerGroup.h" 16 #include "mozilla/dom/ContentChild.h" 17 #include "mozilla/dom/RemoteWorkerService.h" 18 #include "mozilla/dom/ServiceWorkerManager.h" 19 #include "mozilla/dom/WorkerCommon.h" 20 #include "mozilla/ipc/BackgroundParent.h" 21 #include "nsDebug.h" 22 #include "nsThreadUtils.h" 23 #include "nsXULAppAPI.h" 24 25 namespace mozilla::dom { 26 27 using Progress = ServiceWorkerShutdownState::Progress; 28 29 namespace { 30 31 constexpr inline auto UnderlyingProgressValue(Progress aProgress) { 32 return std::underlying_type_t<Progress>(aProgress); 33 } 34 35 constexpr std::array<const char*, UnderlyingProgressValue(Progress::EndGuard_)> 36 gProgressStrings = {{ 37 // clang-format off 38 "parent process main thread", 39 "parent process IPDL background thread", 40 "content process worker launcher thread", 41 "content process main thread", 42 "shutdown completed" 43 // clang-format on 44 }}; 45 46 } // anonymous namespace 47 48 ServiceWorkerShutdownState::ServiceWorkerShutdownState() 49 : mProgress(Progress::ParentProcessMainThread) { 50 MOZ_ASSERT(XRE_IsParentProcess()); 51 MOZ_ASSERT(NS_IsMainThread()); 52 } 53 54 ServiceWorkerShutdownState::~ServiceWorkerShutdownState() { 55 (void)NS_WARN_IF(mProgress != Progress::ShutdownCompleted); 56 } 57 58 const char* ServiceWorkerShutdownState::GetProgressString() const { 59 return gProgressStrings[UnderlyingProgressValue(mProgress)]; 60 } 61 62 void ServiceWorkerShutdownState::SetProgress(Progress aProgress) { 63 MOZ_ASSERT(aProgress != Progress::EndGuard_); 64 // The Shutdown progress should be increased step by step. However, it could 65 // directly get into ShutdownCompleted state when shutting down starts during 66 // ServiceWorker spawning. 67 MOZ_RELEASE_ASSERT(UnderlyingProgressValue(mProgress) + 1 == 68 UnderlyingProgressValue(aProgress) || 69 aProgress == Progress::ShutdownCompleted); 70 71 mProgress = aProgress; 72 } 73 74 namespace { 75 76 void ReportProgressToServiceWorkerManager(uint32_t aShutdownStateId, 77 Progress aProgress) { 78 MOZ_ASSERT(XRE_IsParentProcess()); 79 MOZ_ASSERT(NS_IsMainThread()); 80 81 RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); 82 MOZ_RELEASE_ASSERT(swm, "ServiceWorkers should shutdown before SWM."); 83 84 swm->ReportServiceWorkerShutdownProgress(aShutdownStateId, aProgress); 85 } 86 87 void ReportProgressToParentProcess(uint32_t aShutdownStateId, 88 Progress aProgress) { 89 MOZ_ASSERT(XRE_IsContentProcess()); 90 MOZ_ASSERT(NS_IsMainThread()); 91 92 ContentChild* contentChild = ContentChild::GetSingleton(); 93 MOZ_ASSERT(contentChild); 94 95 contentChild->SendReportServiceWorkerShutdownProgress(aShutdownStateId, 96 aProgress); 97 } 98 99 void ReportServiceWorkerShutdownProgress(uint32_t aShutdownStateId, 100 Progress aProgress) { 101 MOZ_ASSERT(UnderlyingProgressValue(Progress::ParentProcessMainThread) < 102 UnderlyingProgressValue(aProgress)); 103 MOZ_ASSERT(UnderlyingProgressValue(aProgress) < 104 UnderlyingProgressValue(Progress::EndGuard_)); 105 106 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction( 107 __func__, [shutdownStateId = aShutdownStateId, progress = aProgress] { 108 if (XRE_IsParentProcess()) { 109 ReportProgressToServiceWorkerManager(shutdownStateId, progress); 110 } else { 111 ReportProgressToParentProcess(shutdownStateId, progress); 112 } 113 }); 114 115 if (NS_IsMainThread()) { 116 MOZ_ALWAYS_SUCCEEDS(r->Run()); 117 } else { 118 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r.forget())); 119 } 120 } 121 122 void ReportServiceWorkerShutdownProgress(uint32_t aShutdownStateId) { 123 Progress progress = Progress::EndGuard_; 124 125 if (XRE_IsParentProcess()) { 126 mozilla::ipc::AssertIsOnBackgroundThread(); 127 128 progress = Progress::ParentProcessIpdlBackgroundThread; 129 } else { 130 if (NS_IsMainThread()) { 131 progress = Progress::ContentProcessMainThread; 132 } else { 133 MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread()); 134 progress = Progress::ContentProcessWorkerLauncherThread; 135 } 136 } 137 138 ReportServiceWorkerShutdownProgress(aShutdownStateId, progress); 139 } 140 141 } // anonymous namespace 142 143 void MaybeReportServiceWorkerShutdownProgress(const ServiceWorkerOpArgs& aArgs, 144 bool aShutdownCompleted) { 145 if (XRE_IsParentProcess() && !XRE_IsE10sParentProcess()) { 146 return; 147 } 148 149 if (aShutdownCompleted) { 150 MOZ_ASSERT(aArgs.type() == 151 ServiceWorkerOpArgs::TServiceWorkerTerminateWorkerOpArgs); 152 153 ReportServiceWorkerShutdownProgress( 154 aArgs.get_ServiceWorkerTerminateWorkerOpArgs().shutdownStateId(), 155 Progress::ShutdownCompleted); 156 157 return; 158 } 159 160 if (aArgs.type() == 161 ServiceWorkerOpArgs::TServiceWorkerTerminateWorkerOpArgs) { 162 ReportServiceWorkerShutdownProgress( 163 aArgs.get_ServiceWorkerTerminateWorkerOpArgs().shutdownStateId()); 164 } 165 } 166 167 } // namespace mozilla::dom