tor-browser

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

UtilityProcessManager.cpp (23613B)


      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 #include "UtilityProcessManager.h"
      7 
      8 #include "JSOracleParent.h"
      9 #include "mozilla/ipc/UtilityProcessHost.h"
     10 #include "mozilla/MemoryReportingProcess.h"
     11 #include "mozilla/Preferences.h"
     12 #include "mozilla/ProfilerMarkers.h"
     13 #include "mozilla/StaticPrefs_media.h"
     14 #include "mozilla/SyncRunnable.h"  // for LaunchUtilityProcess
     15 #include "mozilla/ipc/UtilityProcessParent.h"
     16 #include "mozilla/ipc/UtilityMediaServiceChild.h"
     17 #include "mozilla/ipc/UtilityMediaServiceParent.h"
     18 #include "mozilla/dom/ContentParent.h"
     19 #include "mozilla/ipc/Endpoint.h"
     20 #include "mozilla/ipc/UtilityProcessSandboxing.h"
     21 #include "mozilla/ipc/ProcessChild.h"
     22 #include "nsAppRunner.h"
     23 #include "nsContentUtils.h"
     24 
     25 #ifdef XP_WIN
     26 #  include "mozilla/dom/WindowsUtilsParent.h"
     27 #  include "mozilla/widget/filedialog/WinFileDialogParent.h"
     28 #endif
     29 
     30 #include "mozilla/GeckoArgs.h"
     31 
     32 namespace mozilla::ipc {
     33 
     34 extern LazyLogModule gUtilityProcessLog;
     35 #define LOGD(...) MOZ_LOG(gUtilityProcessLog, LogLevel::Debug, (__VA_ARGS__))
     36 
     37 static StaticRefPtr<UtilityProcessManager> sSingleton;
     38 
     39 static bool sXPCOMShutdown = false;
     40 
     41 bool UtilityProcessManager::IsShutdown() const {
     42  MOZ_ASSERT(NS_IsMainThread());
     43  return sXPCOMShutdown || !sSingleton;
     44 }
     45 
     46 RefPtr<UtilityProcessManager> UtilityProcessManager::GetSingleton() {
     47  MOZ_ASSERT(XRE_IsParentProcess());
     48  MOZ_ASSERT(NS_IsMainThread());
     49 
     50  if (!sXPCOMShutdown && sSingleton == nullptr) {
     51    sSingleton = new UtilityProcessManager();
     52    sSingleton->Init();
     53  }
     54  return sSingleton;
     55 }
     56 
     57 RefPtr<UtilityProcessManager> UtilityProcessManager::GetIfExists() {
     58  MOZ_ASSERT(NS_IsMainThread());
     59  return sSingleton;
     60 }
     61 
     62 UtilityProcessManager::UtilityProcessManager() {
     63  LOGD("[%p] UtilityProcessManager::UtilityProcessManager", this);
     64 }
     65 
     66 void UtilityProcessManager::Init() {
     67  // Start listening for pref changes so we can
     68  // forward them to the process once it is running.
     69  mObserver = new Observer(this);
     70  nsContentUtils::RegisterShutdownObserver(mObserver);
     71  Preferences::AddStrongObserver(mObserver, "");
     72 }
     73 
     74 UtilityProcessManager::~UtilityProcessManager() {
     75  LOGD("[%p] UtilityProcessManager::~UtilityProcessManager", this);
     76 
     77  // The Utility process should ALL have already been shut down.
     78  MOZ_ASSERT(NoMoreProcesses());
     79 }
     80 
     81 NS_IMPL_ISUPPORTS(UtilityProcessManager::Observer, nsIObserver);
     82 
     83 UtilityProcessManager::Observer::Observer(UtilityProcessManager* aManager)
     84    : mManager(aManager) {}
     85 
     86 NS_IMETHODIMP
     87 UtilityProcessManager::Observer::Observe(nsISupports* aSubject,
     88                                         const char* aTopic,
     89                                         const char16_t* aData) {
     90  if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     91    mManager->OnXPCOMShutdown();
     92  } else if (!strcmp(aTopic, "nsPref:changed")) {
     93    mManager->OnPreferenceChange(aData);
     94  }
     95  return NS_OK;
     96 }
     97 
     98 void UtilityProcessManager::OnXPCOMShutdown() {
     99  LOGD("[%p] UtilityProcessManager::OnXPCOMShutdown", this);
    100 
    101  MOZ_ASSERT(NS_IsMainThread());
    102  sXPCOMShutdown = true;
    103  nsContentUtils::UnregisterShutdownObserver(mObserver);
    104  CleanShutdownAllProcesses();
    105 }
    106 
    107 void UtilityProcessManager::OnPreferenceChange(const char16_t* aData) {
    108  MOZ_ASSERT(NS_IsMainThread());
    109  if (NoMoreProcesses()) {
    110    // Process hasn't been launched yet
    111    return;
    112  }
    113  // We know prefs are ASCII here.
    114  NS_LossyConvertUTF16toASCII strData(aData);
    115 
    116  mozilla::dom::Pref pref(strData, /* isLocked */ false,
    117                          /* isSanitized */ false, Nothing(), Nothing());
    118  Preferences::GetPreference(&pref, GeckoProcessType_Utility,
    119                             /* remoteType */ ""_ns);
    120 
    121  for (auto& p : mProcesses) {
    122    if (!p) {
    123      continue;
    124    }
    125 
    126    if (p->mProcessParent) {
    127      (void)p->mProcessParent->SendPreferenceUpdate(pref);
    128    } else if (IsProcessLaunching(p->mSandbox)) {
    129      p->mQueuedPrefs.AppendElement(pref);
    130    }
    131  }
    132 }
    133 
    134 RefPtr<UtilityProcessManager::ProcessFields> UtilityProcessManager::GetProcess(
    135    SandboxingKind aSandbox) {
    136  if (!mProcesses[aSandbox]) {
    137    return nullptr;
    138  }
    139 
    140  return mProcesses[aSandbox];
    141 }
    142 
    143 RefPtr<UtilityProcessManager::SharedLaunchPromise<Ok>>
    144 UtilityProcessManager::LaunchProcess(SandboxingKind aSandbox) {
    145  LOGD("[%p] UtilityProcessManager::LaunchProcess SandboxingKind=%" PRIu64,
    146       this, aSandbox);
    147  using RetPromise = SharedLaunchPromise<Ok>;
    148 
    149  MOZ_ASSERT(NS_IsMainThread());
    150 
    151  if (IsShutdown()) {
    152    NS_WARNING("Reject early LaunchProcess() for Shutdown");
    153    return RetPromise::CreateAndReject(
    154        LaunchError("UPM::LaunchProcess(): IsShutdown()"), __func__);
    155  }
    156 
    157  RefPtr<ProcessFields> p = GetProcess(aSandbox);
    158  if (p && p->mNumProcessAttempts) {
    159    // We failed to start the Utility process earlier, abort now.
    160    NS_WARNING("Reject LaunchProcess() for earlier mNumProcessAttempts");
    161    return RetPromise::CreateAndReject(
    162        LaunchError("UPM::LaunchProcess(): p->mNumProcessAttempts"), __func__);
    163  }
    164 
    165  if (p && p->mLaunchPromise && p->mProcess) {
    166    return p->mLaunchPromise;
    167  }
    168 
    169  if (!p) {
    170    p = new ProcessFields(aSandbox);
    171    mProcesses[aSandbox] = p;
    172  }
    173 
    174  geckoargs::ChildProcessArgs extraArgs;
    175  ProcessChild::AddPlatformBuildID(extraArgs);
    176  geckoargs::sSandboxingKind.Put(aSandbox, extraArgs);
    177 
    178  // The subprocess is launched asynchronously, so we
    179  // wait for the promise to be resolved to acquire the IPDL actor.
    180  p->mProcess = new UtilityProcessHost(aSandbox, this);
    181  if (!p->mProcess->Launch(std::move(extraArgs))) {
    182    p->mNumProcessAttempts++;
    183    DestroyProcess(aSandbox);
    184    NS_WARNING("Reject LaunchProcess() for mNumProcessAttempts++");
    185    return RetPromise::CreateAndReject(
    186        LaunchError("UPM::LaunchProcess(): mNumProcessAttempts++"), __func__);
    187  }
    188 
    189  RefPtr<UtilityProcessManager> self = this;
    190  p->mLaunchPromise = p->mProcess->LaunchPromise()->Then(
    191      GetMainThreadSerialEventTarget(), __func__,
    192      [self, p, aSandbox](Ok) -> RefPtr<RetPromise> {
    193        if (self->IsShutdown()) {
    194          NS_WARNING(
    195              "Reject LaunchProcess() after LaunchPromise() for Shutdown");
    196          return RetPromise::CreateAndReject(
    197              LaunchError("UPM::LaunchProcess(): post-await IsShutdown()"),
    198              __func__);
    199        }
    200 
    201        if (self->IsProcessDestroyed(aSandbox)) {
    202          NS_WARNING(
    203              "Reject LaunchProcess() after LaunchPromise() for destroyed "
    204              "process");
    205          return RetPromise::CreateAndReject(
    206              LaunchError(
    207                  "UPM::LaunchProcess(): post-await IsProcessDestroyed()"),
    208              __func__);
    209        }
    210 
    211        p->mProcessParent = p->mProcess->GetActor();
    212 
    213        // Flush any pref updates that happened during
    214        // launch and weren't included in the blobs set
    215        // up in LaunchUtilityProcess.
    216        for (const mozilla::dom::Pref& pref : p->mQueuedPrefs) {
    217          (void)NS_WARN_IF(!p->mProcessParent->SendPreferenceUpdate(pref));
    218        }
    219        p->mQueuedPrefs.Clear();
    220 
    221        CrashReporter::RecordAnnotationCString(
    222            CrashReporter::Annotation::UtilityProcessStatus, "Running");
    223 
    224        return RetPromise::CreateAndResolve(Ok{}, __func__);
    225      },
    226      [self, p, aSandbox](LaunchError error) {
    227        if (GetSingleton()) {
    228          p->mNumProcessAttempts++;
    229          self->DestroyProcess(aSandbox);
    230        }
    231        NS_WARNING("Reject LaunchProcess() for LaunchPromise() rejection");
    232        return RetPromise::CreateAndReject(std::move(error), __func__);
    233      });
    234 
    235  return p->mLaunchPromise;
    236 }
    237 
    238 template <typename Actor>
    239 RefPtr<UtilityProcessManager::LaunchPromise<Ok>>
    240 UtilityProcessManager::StartUtility(RefPtr<Actor> aActor,
    241                                    SandboxingKind aSandbox) {
    242  using RetPromise = LaunchPromise<Ok>;
    243 
    244  LOGD(
    245      "[%p] UtilityProcessManager::StartUtility actor=%p "
    246      "SandboxingKind=%" PRIu64,
    247      this, aActor.get(), aSandbox);
    248 
    249  TimeStamp utilityStart = TimeStamp::Now();
    250 
    251  if (!aActor) {
    252    MOZ_ASSERT(false, "Actor singleton failure");
    253    return RetPromise::CreateAndReject(
    254        LaunchError("UPM::StartUtility: aActor is null"), __func__);
    255  }
    256 
    257  if (aActor->CanSend()) {
    258    // Actor has already been setup, so we:
    259    //   - know the process has been launched
    260    //   - the ipc actors are ready
    261    PROFILER_MARKER_TEXT(
    262        "UtilityProcessManager::StartUtility", IPC,
    263        MarkerOptions(MarkerTiming::InstantNow()),
    264        nsPrintfCString("SandboxingKind=%" PRIu64 " aActor->CanSend()",
    265                        aSandbox));
    266    return RetPromise::CreateAndResolve(Ok{}, __func__);
    267  }
    268 
    269  RefPtr<UtilityProcessManager> self = this;
    270  return LaunchProcess(aSandbox)->Then(
    271      GetMainThreadSerialEventTarget(), __func__,
    272      [self, aActor, aSandbox, utilityStart]() -> RefPtr<RetPromise> {
    273        RefPtr<UtilityProcessParent> utilityParent =
    274            self->GetProcessParent(aSandbox);
    275        if (!utilityParent) {
    276          NS_WARNING("Missing parent in StartUtility");
    277          return RetPromise::CreateAndReject(
    278              LaunchError("UPM::GetProcessParent"), __func__);
    279        }
    280 
    281        // It is possible if multiple processes concurrently request a utility
    282        // actor that the previous CanSend() check returned false for both but
    283        // that by the time we have started our process for real, one of them
    284        // has already been able to establish the IPC connection and thus we
    285        // would perform more than one Open() call.
    286        //
    287        // The tests within browser_utility_multipleAudio.js should be able to
    288        // catch that behavior.
    289        if (!aActor->CanSend()) {
    290          nsresult rv = aActor->BindToUtilityProcess(utilityParent);
    291          if (NS_FAILED(rv)) {
    292            MOZ_ASSERT(false, "Protocol endpoints failure");
    293            return RetPromise::CreateAndReject(
    294                LaunchError("BindToUtilityProcess", rv), __func__);
    295          }
    296 
    297          MOZ_DIAGNOSTIC_ASSERT(aActor->CanSend(), "IPC established for actor");
    298          self->RegisterActor(utilityParent, aActor->GetActorName());
    299        }
    300 
    301        PROFILER_MARKER_TEXT(
    302            "UtilityProcessManager::StartUtility", IPC,
    303            MarkerOptions(MarkerTiming::IntervalUntilNowFrom(utilityStart)),
    304            nsPrintfCString("SandboxingKind=%" PRIu64 " Resolve", aSandbox));
    305        return RetPromise::CreateAndResolve(Ok{}, __func__);
    306      },
    307      [self, aSandbox, utilityStart](LaunchError const& error) {
    308        NS_WARNING("Reject StartUtility() for LaunchProcess() rejection");
    309        if (!self->IsShutdown()) {
    310          NS_WARNING("Reject StartUtility() when !IsShutdown()");
    311        }
    312        PROFILER_MARKER_TEXT(
    313            "UtilityProcessManager::StartUtility", IPC,
    314            MarkerOptions(MarkerTiming::IntervalUntilNowFrom(utilityStart)),
    315            nsPrintfCString("SandboxingKind=%" PRIu64 " Reject", aSandbox));
    316        return RetPromise::CreateAndReject(error, __func__);
    317      });
    318 }
    319 
    320 RefPtr<UtilityProcessManager::StartRemoteDecodingUtilityPromise>
    321 UtilityProcessManager::StartProcessForRemoteMediaDecoding(
    322    EndpointProcInfo aOtherProcess, dom::ContentParentId aChildId,
    323    SandboxingKind aSandbox) {
    324  using RetPromise = StartRemoteDecodingUtilityPromise;
    325 
    326  // Not supported kinds.
    327  if (aSandbox != SandboxingKind::GENERIC_UTILITY
    328 #ifdef MOZ_APPLEMEDIA
    329      && aSandbox != SandboxingKind::UTILITY_AUDIO_DECODING_APPLE_MEDIA
    330 #endif
    331 #ifdef XP_WIN
    332      && aSandbox != SandboxingKind::UTILITY_AUDIO_DECODING_WMF
    333 #endif
    334 #ifdef MOZ_WMF_MEDIA_ENGINE
    335      && aSandbox != SandboxingKind::MF_MEDIA_ENGINE_CDM
    336 #endif
    337  ) {
    338    return RetPromise::CreateAndReject(
    339        LaunchError("Start...MediaDecoding: bad sandbox type"), __func__);
    340  }
    341  TimeStamp remoteDecodingStart = TimeStamp::Now();
    342 
    343  RefPtr<UtilityProcessManager> self = this;
    344  RefPtr<UtilityMediaServiceChild> umsc =
    345      UtilityMediaServiceChild::GetSingleton(aSandbox);
    346  MOZ_ASSERT(umsc, "Unable to get a singleton for UtilityMediaServiceChild");
    347  return StartUtility(umsc, aSandbox)
    348      ->Then(
    349          GetMainThreadSerialEventTarget(), __func__,
    350          [self, umsc, aOtherProcess, aChildId, aSandbox,
    351           remoteDecodingStart]() {
    352            RefPtr<UtilityProcessParent> parent =
    353                self->GetProcessParent(aSandbox);
    354            if (!parent) {
    355              NS_WARNING("UtilityMediaServiceParent lost in the middle");
    356              return RetPromise::CreateAndReject(
    357                  LaunchError("Start...MediaDecoding: parent lost"), __func__);
    358            }
    359 
    360            if (!umsc->CanSend()) {
    361              NS_WARNING("UtilityMediaServiceChild lost in the middle");
    362              return RetPromise::CreateAndReject(
    363                  LaunchError("Start...MediaDecoding: child lost"), __func__);
    364            }
    365 
    366            EndpointProcInfo process = parent->OtherEndpointProcInfo();
    367 
    368            Endpoint<PRemoteMediaManagerChild> childPipe;
    369            Endpoint<PRemoteMediaManagerParent> parentPipe;
    370            if (nsresult const rv = PRemoteMediaManager::CreateEndpoints(
    371                    process, aOtherProcess, &parentPipe, &childPipe);
    372                NS_FAILED(rv)) {
    373              MOZ_ASSERT(false, "Could not create content remote decoder");
    374              return RetPromise::CreateAndReject(
    375                  LaunchError("PRemoteMediaManager::CreateEndpoints", rv),
    376                  __func__);
    377            }
    378 
    379            if (!umsc->SendNewContentRemoteMediaManager(std::move(parentPipe),
    380                                                        aChildId)) {
    381              MOZ_ASSERT(false, "SendNewContentRemoteMediaManager failure");
    382              return RetPromise::CreateAndReject(
    383                  LaunchError("UMSC::SendNewCRDM"), __func__);
    384            }
    385 
    386 #ifdef MOZ_WMF_MEDIA_ENGINE
    387            if (aSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM &&
    388                !umsc->CreateVideoBridge(process)) {
    389              MOZ_ASSERT(false, "Failed to create video bridge");
    390              return RetPromise::CreateAndReject(
    391                  LaunchError("UMSC::CreateVideoBridge"), __func__);
    392            }
    393 #endif
    394            PROFILER_MARKER_TEXT(
    395                "UtilityProcessManager::StartProcessForRemoteMediaDecoding",
    396                MEDIA,
    397                MarkerOptions(
    398                    MarkerTiming::IntervalUntilNowFrom(remoteDecodingStart)),
    399                "Resolve"_ns);
    400            return RetPromise::CreateAndResolve(std::move(childPipe), __func__);
    401          },
    402          [self, remoteDecodingStart](LaunchError&& error) {
    403            NS_WARNING(
    404                "Reject StartProcessForRemoteMediaDecoding() for "
    405                "StartUtility() rejection");
    406            PROFILER_MARKER_TEXT(
    407                "UtilityProcessManager::StartProcessForRemoteMediaDecoding",
    408                MEDIA,
    409                MarkerOptions(
    410                    MarkerTiming::IntervalUntilNowFrom(remoteDecodingStart)),
    411                "Reject"_ns);
    412            return RetPromise::CreateAndReject(std::move(error), __func__);
    413          });
    414 }
    415 
    416 RefPtr<UtilityProcessManager::JSOraclePromise>
    417 UtilityProcessManager::StartJSOracle(dom::JSOracleParent* aParent) {
    418  using RetPromise = JSOraclePromise;
    419  return StartUtility(RefPtr{aParent}, SandboxingKind::GENERIC_UTILITY)
    420      ->Then(
    421          GetCurrentSerialEventTarget(), __func__,
    422          []() { return RetPromise::CreateAndResolve(true, __func__); },
    423          [](LaunchError const&) {
    424            return RetPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE,
    425                                               __func__);
    426          });
    427 }
    428 
    429 #ifdef XP_WIN
    430 
    431 // Windows Utils
    432 
    433 RefPtr<UtilityProcessManager::WindowsUtilsPromise>
    434 UtilityProcessManager::GetWindowsUtilsPromise() {
    435  TimeStamp windowsUtilsStart = TimeStamp::Now();
    436  RefPtr<UtilityProcessManager> self = this;
    437  if (!mWindowsUtils) {
    438    mWindowsUtils = new dom::WindowsUtilsParent();
    439  }
    440 
    441  RefPtr<dom::WindowsUtilsParent> wup = mWindowsUtils;
    442  MOZ_ASSERT(wup, "Unable to get a singleton for WindowsUtils");
    443  return StartUtility(wup, SandboxingKind::WINDOWS_UTILS)
    444      ->Then(
    445          GetMainThreadSerialEventTarget(), __func__,
    446          [self, wup, windowsUtilsStart]() {
    447            if (!wup->CanSend()) {
    448              MOZ_ASSERT(false, "WindowsUtilsParent can't send");
    449              return WindowsUtilsPromise::CreateAndReject(
    450                  LaunchError("GetWindowsUtilsPromise: !wup->CanSend()"),
    451                  __func__);
    452            }
    453            PROFILER_MARKER_TEXT(
    454                "UtilityProcessManager::GetWindowsUtilsPromise", OTHER,
    455                MarkerOptions(
    456                    MarkerTiming::IntervalUntilNowFrom(windowsUtilsStart)),
    457                "Resolve"_ns);
    458            return WindowsUtilsPromise::CreateAndResolve(wup, __func__);
    459          },
    460          [self, windowsUtilsStart](LaunchError&& error) {
    461            NS_WARNING("StartUtility rejected promise for PWindowsUtils");
    462            PROFILER_MARKER_TEXT(
    463                "UtilityProcessManager::GetWindowsUtilsPromise", OTHER,
    464                MarkerOptions(
    465                    MarkerTiming::IntervalUntilNowFrom(windowsUtilsStart)),
    466                "Reject"_ns);
    467            return WindowsUtilsPromise::CreateAndReject(std::move(error),
    468                                                        __func__);
    469          });
    470 }
    471 
    472 void UtilityProcessManager::ReleaseWindowsUtils() { mWindowsUtils = nullptr; }
    473 
    474 RefPtr<UtilityProcessManager::WinFileDialogPromise>
    475 UtilityProcessManager::CreateWinFileDialogActor() {
    476  using RetPromise = WinFileDialogPromise;
    477  TimeStamp startTime = TimeStamp::Now();
    478  auto wfdp = MakeRefPtr<widget::filedialog::WinFileDialogParent>();
    479 
    480  return StartUtility(wfdp, SandboxingKind::WINDOWS_FILE_DIALOG)
    481      ->Then(
    482          GetMainThreadSerialEventTarget(), __PRETTY_FUNCTION__,
    483          [wfdp, startTime]() mutable {
    484            LOGD("CreateWinFileDialogAsync() resolve: wfdp = [%p]", wfdp.get());
    485            if (!wfdp->CanSend()) {
    486              MOZ_ASSERT(false, "WinFileDialogParent can't send");
    487              return RetPromise::CreateAndReject(
    488                  LaunchError("CreateWinFileDialogActor: !wfdp->CanSend()"),
    489                  __PRETTY_FUNCTION__);
    490            }
    491            PROFILER_MARKER_TEXT(
    492                "UtilityProcessManager::CreateWinFileDialogAsync", OTHER,
    493                MarkerOptions(MarkerTiming::IntervalUntilNowFrom(startTime)),
    494                "Resolve"_ns);
    495 
    496            return RetPromise::CreateAndResolve(
    497                widget::filedialog::ProcessProxy(std::move(wfdp)),
    498                __PRETTY_FUNCTION__);
    499          },
    500          [self = RefPtr(this), startTime](LaunchError&& error) {
    501            LOGD("CreateWinFileDialogAsync() reject");
    502            if (!self->IsShutdown()) {
    503              MOZ_ASSERT_UNREACHABLE("failure when starting file-dialog actor");
    504            }
    505            PROFILER_MARKER_TEXT(
    506                "UtilityProcessManager::CreateWinFileDialogAsync", OTHER,
    507                MarkerOptions(MarkerTiming::IntervalUntilNowFrom(startTime)),
    508                "Reject"_ns);
    509 
    510            return RetPromise::CreateAndReject(std::move(error),
    511                                               __PRETTY_FUNCTION__);
    512          });
    513 }
    514 
    515 #endif  // XP_WIN
    516 
    517 bool UtilityProcessManager::IsProcessLaunching(SandboxingKind aSandbox) {
    518  MOZ_ASSERT(NS_IsMainThread());
    519 
    520  RefPtr<ProcessFields> p = GetProcess(aSandbox);
    521  if (!p) {
    522    MOZ_CRASH("Cannot check process launching with no process");
    523    return false;
    524  }
    525 
    526  return p->mProcess && !(p->mProcessParent);
    527 }
    528 
    529 bool UtilityProcessManager::IsProcessDestroyed(SandboxingKind aSandbox) {
    530  MOZ_ASSERT(NS_IsMainThread());
    531  RefPtr<ProcessFields> p = GetProcess(aSandbox);
    532  if (!p) {
    533    MOZ_CRASH("Cannot check process destroyed with no process");
    534    return false;
    535  }
    536  return !p->mProcess && !p->mProcessParent;
    537 }
    538 
    539 void UtilityProcessManager::OnProcessUnexpectedShutdown(
    540    UtilityProcessHost* aHost) {
    541  MOZ_ASSERT(NS_IsMainThread());
    542 
    543  for (auto& it : mProcesses) {
    544    if (it && it->mProcess && it->mProcess == aHost) {
    545      it->mNumUnexpectedCrashes++;
    546      DestroyProcess(it->mSandbox);
    547      return;
    548    }
    549  }
    550 
    551  MOZ_CRASH(
    552      "Called UtilityProcessManager::OnProcessUnexpectedShutdown with invalid "
    553      "aHost");
    554 }
    555 
    556 void UtilityProcessManager::CleanShutdownAllProcesses() {
    557  LOGD("[%p] UtilityProcessManager::CleanShutdownAllProcesses", this);
    558 
    559  for (auto& it : mProcesses) {
    560    if (it) {
    561      DestroyProcess(it->mSandbox);
    562    }
    563  }
    564 }
    565 
    566 void UtilityProcessManager::CleanShutdown(SandboxingKind aSandbox) {
    567  LOGD("[%p] UtilityProcessManager::CleanShutdown SandboxingKind=%" PRIu64,
    568       this, aSandbox);
    569 
    570  DestroyProcess(aSandbox);
    571 }
    572 
    573 uint16_t UtilityProcessManager::AliveProcesses() {
    574  uint16_t alive = 0;
    575  for (auto& p : mProcesses) {
    576    if (p != nullptr) {
    577      alive++;
    578    }
    579  }
    580  return alive;
    581 }
    582 
    583 bool UtilityProcessManager::NoMoreProcesses() { return AliveProcesses() == 0; }
    584 
    585 void UtilityProcessManager::DestroyProcess(SandboxingKind aSandbox) {
    586  LOGD("[%p] UtilityProcessManager::DestroyProcess SandboxingKind=%" PRIu64,
    587       this, aSandbox);
    588 
    589  MOZ_RELEASE_ASSERT(NS_IsMainThread());
    590 
    591  if (AliveProcesses() <= 1) {
    592    if (mObserver) {
    593      Preferences::RemoveObserver(mObserver, "");
    594    }
    595 
    596    mObserver = nullptr;
    597  }
    598 
    599  RefPtr<ProcessFields> p = GetProcess(aSandbox);
    600  if (!p) {
    601    return;
    602  }
    603 
    604  p->mQueuedPrefs.Clear();
    605  p->mProcessParent = nullptr;
    606 
    607  if (!p->mProcess) {
    608    return;
    609  }
    610 
    611  p->mProcess->Shutdown();
    612  p->mProcess = nullptr;
    613 
    614  mProcesses[aSandbox] = nullptr;
    615 
    616  CrashReporter::RecordAnnotationCString(
    617      CrashReporter::Annotation::UtilityProcessStatus, "Destroyed");
    618 
    619  if (NoMoreProcesses()) {
    620    sSingleton = nullptr;
    621  }
    622 }
    623 
    624 Maybe<base::ProcessId> UtilityProcessManager::ProcessPid(
    625    SandboxingKind aSandbox) {
    626  MOZ_ASSERT(NS_IsMainThread());
    627  RefPtr<ProcessFields> p = GetProcess(aSandbox);
    628  if (!p) {
    629    return Nothing();
    630  }
    631  if (p->mProcessParent) {
    632    return Some(p->mProcessParent->OtherPid());
    633  }
    634  return Nothing();
    635 }
    636 
    637 class UtilityMemoryReporter : public MemoryReportingProcess {
    638 public:
    639  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(UtilityMemoryReporter, override)
    640 
    641  explicit UtilityMemoryReporter(UtilityProcessParent* aParent) {
    642    mParent = aParent;
    643  }
    644 
    645  bool IsAlive() const override { return bool(GetParent()); }
    646 
    647  bool SendRequestMemoryReport(
    648      const uint32_t& aGeneration, const bool& aAnonymize,
    649      const bool& aMinimizeMemoryUsage,
    650      const Maybe<ipc::FileDescriptor>& aDMDFile) override {
    651    RefPtr<UtilityProcessParent> parent = GetParent();
    652    if (!parent) {
    653      return false;
    654    }
    655 
    656    return parent->SendRequestMemoryReport(aGeneration, aAnonymize,
    657                                           aMinimizeMemoryUsage, aDMDFile);
    658  }
    659 
    660  int32_t Pid() const override {
    661    if (RefPtr<UtilityProcessParent> parent = GetParent()) {
    662      return (int32_t)parent->OtherPid();
    663    }
    664    return 0;
    665  }
    666 
    667 private:
    668  RefPtr<UtilityProcessParent> GetParent() const { return mParent; }
    669 
    670  RefPtr<UtilityProcessParent> mParent = nullptr;
    671 
    672 protected:
    673  ~UtilityMemoryReporter() = default;
    674 };
    675 
    676 RefPtr<MemoryReportingProcess> UtilityProcessManager::GetProcessMemoryReporter(
    677    UtilityProcessParent* parent) {
    678  return new UtilityMemoryReporter(parent);
    679 }
    680 
    681 }  // namespace mozilla::ipc