tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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