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