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"
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/UtilityAudioDecoderChild.h"
17 #include "mozilla/ipc/UtilityAudioDecoderParent.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"
26 # include "mozilla/dom/WindowsUtilsParent.h"
27 # include "mozilla/widget/filedialog/WinFileDialogParent.h"
30 #include "mozilla/GeckoArgs.h"
32 namespace mozilla::ipc
{
34 extern LazyLogModule gUtilityProcessLog
;
35 #define LOGD(...) MOZ_LOG(gUtilityProcessLog, LogLevel::Debug, (__VA_ARGS__))
37 static StaticRefPtr
<UtilityProcessManager
> sSingleton
;
39 static bool sXPCOMShutdown
= false;
41 bool UtilityProcessManager::IsShutdown() const {
42 MOZ_ASSERT(NS_IsMainThread());
43 return sXPCOMShutdown
|| !sSingleton
;
46 RefPtr
<UtilityProcessManager
> UtilityProcessManager::GetSingleton() {
47 MOZ_ASSERT(XRE_IsParentProcess());
48 MOZ_ASSERT(NS_IsMainThread());
50 if (!sXPCOMShutdown
&& sSingleton
== nullptr) {
51 sSingleton
= new UtilityProcessManager();
57 RefPtr
<UtilityProcessManager
> UtilityProcessManager::GetIfExists() {
58 MOZ_ASSERT(NS_IsMainThread());
62 UtilityProcessManager::UtilityProcessManager() {
63 LOGD("[%p] UtilityProcessManager::UtilityProcessManager", this);
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
, "");
74 UtilityProcessManager::~UtilityProcessManager() {
75 LOGD("[%p] UtilityProcessManager::~UtilityProcessManager", this);
77 // The Utility process should ALL have already been shut down.
78 MOZ_ASSERT(NoMoreProcesses());
81 NS_IMPL_ISUPPORTS(UtilityProcessManager::Observer
, nsIObserver
);
83 UtilityProcessManager::Observer::Observer(UtilityProcessManager
* aManager
)
84 : mManager(aManager
) {}
87 UtilityProcessManager::Observer::Observe(nsISupports
* aSubject
,
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
);
98 void UtilityProcessManager::OnXPCOMShutdown() {
99 LOGD("[%p] UtilityProcessManager::OnXPCOMShutdown", this);
101 MOZ_ASSERT(NS_IsMainThread());
102 sXPCOMShutdown
= true;
103 nsContentUtils::UnregisterShutdownObserver(mObserver
);
104 CleanShutdownAllProcesses();
107 void UtilityProcessManager::OnPreferenceChange(const char16_t
* aData
) {
108 MOZ_ASSERT(NS_IsMainThread());
109 if (NoMoreProcesses()) {
110 // Process hasn't been launched yet
113 // We know prefs are ASCII here.
114 NS_LossyConvertUTF16toASCII
strData(aData
);
116 mozilla::dom::Pref
pref(strData
, /* isLocked */ false,
117 /* isSanitized */ false, Nothing(), Nothing());
118 Preferences::GetPreference(&pref
, GeckoProcessType_Utility
,
119 /* remoteType */ ""_ns
);
121 for (auto& p
: mProcesses
) {
126 if (p
->mProcessParent
) {
127 Unused
<< p
->mProcessParent
->SendPreferenceUpdate(pref
);
128 } else if (IsProcessLaunching(p
->mSandbox
)) {
129 p
->mQueuedPrefs
.AppendElement(pref
);
134 RefPtr
<UtilityProcessManager::ProcessFields
> UtilityProcessManager::GetProcess(
135 SandboxingKind aSandbox
) {
136 if (!mProcesses
[aSandbox
]) {
140 return mProcesses
[aSandbox
];
143 RefPtr
<GenericNonExclusivePromise
> UtilityProcessManager::LaunchProcess(
144 SandboxingKind aSandbox
) {
145 LOGD("[%p] UtilityProcessManager::LaunchProcess SandboxingKind=%" PRIu64
,
148 MOZ_ASSERT(NS_IsMainThread());
151 NS_WARNING("Reject early LaunchProcess() for Shutdown");
152 return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE
,
156 RefPtr
<ProcessFields
> p
= GetProcess(aSandbox
);
157 if (p
&& p
->mNumProcessAttempts
) {
158 // We failed to start the Utility process earlier, abort now.
159 NS_WARNING("Reject LaunchProcess() for earlier mNumProcessAttempts");
160 return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE
,
164 if (p
&& p
->mLaunchPromise
&& p
->mProcess
) {
165 return p
->mLaunchPromise
;
169 p
= new ProcessFields(aSandbox
);
170 mProcesses
[aSandbox
] = p
;
173 std::vector
<std::string
> extraArgs
;
174 ProcessChild::AddPlatformBuildID(extraArgs
);
175 geckoargs::sSandboxingKind
.Put(aSandbox
, extraArgs
);
177 // The subprocess is launched asynchronously, so we
178 // wait for the promise to be resolved to acquire the IPDL actor.
179 p
->mProcess
= new UtilityProcessHost(aSandbox
, this);
180 if (!p
->mProcess
->Launch(extraArgs
)) {
181 p
->mNumProcessAttempts
++;
182 DestroyProcess(aSandbox
);
183 NS_WARNING("Reject LaunchProcess() for mNumProcessAttempts++");
184 return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE
,
188 RefPtr
<UtilityProcessManager
> self
= this;
189 p
->mLaunchPromise
= p
->mProcess
->LaunchPromise()->Then(
190 GetMainThreadSerialEventTarget(), __func__
,
191 [self
, p
, aSandbox
](bool) {
192 if (self
->IsShutdown()) {
194 "Reject LaunchProcess() after LaunchPromise() for Shutdown");
195 return GenericNonExclusivePromise::CreateAndReject(
196 NS_ERROR_NOT_AVAILABLE
, __func__
);
199 if (self
->IsProcessDestroyed(aSandbox
)) {
201 "Reject LaunchProcess() after LaunchPromise() for destroyed "
203 return GenericNonExclusivePromise::CreateAndReject(
204 NS_ERROR_NOT_AVAILABLE
, __func__
);
207 p
->mProcessParent
= p
->mProcess
->GetActor();
209 // Flush any pref updates that happened during
210 // launch and weren't included in the blobs set
211 // up in LaunchUtilityProcess.
212 for (const mozilla::dom::Pref
& pref
: p
->mQueuedPrefs
) {
213 Unused
<< NS_WARN_IF(!p
->mProcessParent
->SendPreferenceUpdate(pref
));
215 p
->mQueuedPrefs
.Clear();
217 CrashReporter::AnnotateCrashReport(
218 CrashReporter::Annotation::UtilityProcessStatus
, "Running"_ns
);
220 return GenericNonExclusivePromise::CreateAndResolve(true, __func__
);
222 [self
, p
, aSandbox
](nsresult aError
) {
223 if (GetSingleton()) {
224 p
->mNumProcessAttempts
++;
225 self
->DestroyProcess(aSandbox
);
227 NS_WARNING("Reject LaunchProcess() for LaunchPromise() rejection");
228 return GenericNonExclusivePromise::CreateAndReject(aError
, __func__
);
231 return p
->mLaunchPromise
;
234 template <typename Actor
>
235 RefPtr
<GenericNonExclusivePromise
> UtilityProcessManager::StartUtility(
236 RefPtr
<Actor
> aActor
, SandboxingKind aSandbox
) {
238 "[%p] UtilityProcessManager::StartUtility actor=%p "
239 "SandboxingKind=%" PRIu64
,
240 this, aActor
.get(), aSandbox
);
242 TimeStamp utilityStart
= TimeStamp::Now();
245 MOZ_ASSERT(false, "Actor singleton failure");
246 return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_FAILURE
,
250 if (aActor
->CanSend()) {
251 // Actor has already been setup, so we:
252 // - know the process has been launched
253 // - the ipc actors are ready
254 PROFILER_MARKER_TEXT(
255 "UtilityProcessManager::StartUtility", IPC
,
256 MarkerOptions(MarkerTiming::InstantNow()),
257 nsPrintfCString("SandboxingKind=%" PRIu64
" aActor->CanSend()",
259 return GenericNonExclusivePromise::CreateAndResolve(true, __func__
);
262 RefPtr
<UtilityProcessManager
> self
= this;
263 return LaunchProcess(aSandbox
)->Then(
264 GetMainThreadSerialEventTarget(), __func__
,
265 [self
, aActor
, aSandbox
, utilityStart
]() {
266 RefPtr
<UtilityProcessParent
> utilityParent
=
267 self
->GetProcessParent(aSandbox
);
268 if (!utilityParent
) {
269 NS_WARNING("Missing parent in StartUtility");
270 return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_FAILURE
,
274 // It is possible if multiple processes concurrently request a utility
275 // actor that the previous CanSend() check returned false for both but
276 // that by the time we have started our process for real, one of them
277 // has already been able to establish the IPC connection and thus we
278 // would perform more than one Open() call.
280 // The tests within browser_utility_multipleAudio.js should be able to
281 // catch that behavior.
282 if (!aActor
->CanSend()) {
283 nsresult rv
= aActor
->BindToUtilityProcess(utilityParent
);
285 MOZ_ASSERT(false, "Protocol endpoints failure");
286 return GenericNonExclusivePromise::CreateAndReject(rv
, __func__
);
289 MOZ_DIAGNOSTIC_ASSERT(aActor
->CanSend(), "IPC established for actor");
290 self
->RegisterActor(utilityParent
, aActor
->GetActorName());
293 PROFILER_MARKER_TEXT(
294 "UtilityProcessManager::StartUtility", IPC
,
295 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(utilityStart
)),
296 nsPrintfCString("SandboxingKind=%" PRIu64
" Resolve", aSandbox
));
297 return GenericNonExclusivePromise::CreateAndResolve(true, __func__
);
299 [self
, aSandbox
, utilityStart
](nsresult aError
) {
300 NS_WARNING("Reject StartUtility() for LaunchProcess() rejection");
301 if (!self
->IsShutdown()) {
302 NS_WARNING("Reject StartUtility() when !IsShutdown()");
304 PROFILER_MARKER_TEXT(
305 "UtilityProcessManager::StartUtility", IPC
,
306 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(utilityStart
)),
307 nsPrintfCString("SandboxingKind=%" PRIu64
" Reject", aSandbox
));
308 return GenericNonExclusivePromise::CreateAndReject(aError
, __func__
);
312 RefPtr
<UtilityProcessManager::StartRemoteDecodingUtilityPromise
>
313 UtilityProcessManager::StartProcessForRemoteMediaDecoding(
314 base::ProcessId aOtherProcess
, SandboxingKind aSandbox
) {
315 // Not supported kinds.
316 if (aSandbox
!= SandboxingKind::GENERIC_UTILITY
317 #ifdef MOZ_APPLEMEDIA
318 && aSandbox
!= SandboxingKind::UTILITY_AUDIO_DECODING_APPLE_MEDIA
321 && aSandbox
!= SandboxingKind::UTILITY_AUDIO_DECODING_WMF
323 #ifdef MOZ_WMF_MEDIA_ENGINE
324 && aSandbox
!= SandboxingKind::MF_MEDIA_ENGINE_CDM
327 return StartRemoteDecodingUtilityPromise::CreateAndReject(NS_ERROR_FAILURE
,
330 TimeStamp remoteDecodingStart
= TimeStamp::Now();
332 RefPtr
<UtilityProcessManager
> self
= this;
333 RefPtr
<UtilityAudioDecoderChild
> uadc
=
334 UtilityAudioDecoderChild::GetSingleton(aSandbox
);
335 MOZ_ASSERT(uadc
, "Unable to get a singleton for UtilityAudioDecoderChild");
336 return StartUtility(uadc
, aSandbox
)
338 GetMainThreadSerialEventTarget(), __func__
,
339 [self
, uadc
, aOtherProcess
, aSandbox
, remoteDecodingStart
]() {
340 RefPtr
<UtilityProcessParent
> parent
=
341 self
->GetProcessParent(aSandbox
);
343 NS_WARNING("UtilityAudioDecoderParent lost in the middle");
344 return StartRemoteDecodingUtilityPromise::CreateAndReject(
345 NS_ERROR_FAILURE
, __func__
);
348 if (!uadc
->CanSend()) {
349 NS_WARNING("UtilityAudioDecoderChild lost in the middle");
350 return StartRemoteDecodingUtilityPromise::CreateAndReject(
351 NS_ERROR_FAILURE
, __func__
);
354 base::ProcessId process
= parent
->OtherPid();
356 Endpoint
<PRemoteDecoderManagerChild
> childPipe
;
357 Endpoint
<PRemoteDecoderManagerParent
> parentPipe
;
358 nsresult rv
= PRemoteDecoderManager::CreateEndpoints(
359 process
, aOtherProcess
, &parentPipe
, &childPipe
);
361 MOZ_ASSERT(false, "Could not create content remote decoder");
362 return StartRemoteDecodingUtilityPromise::CreateAndReject(
366 if (!uadc
->SendNewContentRemoteDecoderManager(
367 std::move(parentPipe
))) {
368 MOZ_ASSERT(false, "SendNewContentRemoteDecoderManager failure");
369 return StartRemoteDecodingUtilityPromise::CreateAndReject(
370 NS_ERROR_FAILURE
, __func__
);
373 #ifdef MOZ_WMF_MEDIA_ENGINE
374 if (aSandbox
== SandboxingKind::MF_MEDIA_ENGINE_CDM
&&
375 !uadc
->CreateVideoBridge()) {
376 MOZ_ASSERT(false, "Failed to create video bridge");
377 return StartRemoteDecodingUtilityPromise::CreateAndReject(
378 NS_ERROR_FAILURE
, __func__
);
381 PROFILER_MARKER_TEXT(
382 "UtilityProcessManager::StartProcessForRemoteMediaDecoding",
385 MarkerTiming::IntervalUntilNowFrom(remoteDecodingStart
)),
387 return StartRemoteDecodingUtilityPromise::CreateAndResolve(
388 std::move(childPipe
), __func__
);
390 [self
, remoteDecodingStart
](nsresult aError
) {
392 "Reject StartProcessForRemoteMediaDecoding() for "
393 "StartUtility() rejection");
394 PROFILER_MARKER_TEXT(
395 "UtilityProcessManager::StartProcessForRemoteMediaDecoding",
398 MarkerTiming::IntervalUntilNowFrom(remoteDecodingStart
)),
400 return StartRemoteDecodingUtilityPromise::CreateAndReject(aError
,
405 RefPtr
<UtilityProcessManager::JSOraclePromise
>
406 UtilityProcessManager::StartJSOracle(dom::JSOracleParent
* aParent
) {
407 return StartUtility(RefPtr
{aParent
}, SandboxingKind::GENERIC_UTILITY
);
414 RefPtr
<UtilityProcessManager::WindowsUtilsPromise
>
415 UtilityProcessManager::GetWindowsUtilsPromise() {
416 TimeStamp windowsUtilsStart
= TimeStamp::Now();
417 RefPtr
<UtilityProcessManager
> self
= this;
418 if (!mWindowsUtils
) {
419 mWindowsUtils
= new dom::WindowsUtilsParent();
422 RefPtr
<dom::WindowsUtilsParent
> wup
= mWindowsUtils
;
423 MOZ_ASSERT(wup
, "Unable to get a singleton for WindowsUtils");
424 return StartUtility(wup
, SandboxingKind::WINDOWS_UTILS
)
426 GetMainThreadSerialEventTarget(), __func__
,
427 [self
, wup
, windowsUtilsStart
]() {
428 if (!wup
->CanSend()) {
429 MOZ_ASSERT(false, "WindowsUtilsParent can't send");
430 return WindowsUtilsPromise::CreateAndReject(NS_ERROR_FAILURE
,
433 PROFILER_MARKER_TEXT(
434 "UtilityProcessManager::GetWindowsUtilsPromise", OTHER
,
436 MarkerTiming::IntervalUntilNowFrom(windowsUtilsStart
)),
438 return WindowsUtilsPromise::CreateAndResolve(wup
, __func__
);
440 [self
, windowsUtilsStart
](nsresult aError
) {
441 NS_WARNING("StartUtility rejected promise for PWindowsUtils");
442 PROFILER_MARKER_TEXT(
443 "UtilityProcessManager::GetWindowsUtilsPromise", OTHER
,
445 MarkerTiming::IntervalUntilNowFrom(windowsUtilsStart
)),
447 return WindowsUtilsPromise::CreateAndReject(aError
, __func__
);
451 void UtilityProcessManager::ReleaseWindowsUtils() { mWindowsUtils
= nullptr; }
453 RefPtr
<UtilityProcessManager::WinFileDialogPromise
>
454 UtilityProcessManager::CreateWinFileDialogAsync() {
455 using Promise
= WinFileDialogPromise
;
456 TimeStamp startTime
= TimeStamp::Now();
457 auto wfdp
= MakeRefPtr
<widget::filedialog::WinFileDialogParent
>();
459 return StartUtility(wfdp
, SandboxingKind::WINDOWS_FILE_DIALOG
)
461 GetMainThreadSerialEventTarget(), __PRETTY_FUNCTION__
,
462 [wfdp
, startTime
]() mutable {
463 LOGD("CreateWinFileDialogAsync() resolve: wfdp = [%p]", wfdp
.get());
464 if (!wfdp
->CanSend()) {
465 MOZ_ASSERT(false, "WinFileDialogParent can't send");
466 return Promise::CreateAndReject(NS_ERROR_FAILURE
,
467 __PRETTY_FUNCTION__
);
469 PROFILER_MARKER_TEXT(
470 "UtilityProcessManager::CreateWinFileDialogAsync", OTHER
,
471 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(startTime
)),
474 return Promise::CreateAndResolve(
475 widget::filedialog::ProcessProxy(std::move(wfdp
)),
476 __PRETTY_FUNCTION__
);
478 [self
= RefPtr(this), startTime
](nsresult error
) {
479 LOGD("CreateWinFileDialogAsync() reject");
480 if (!self
->IsShutdown()) {
481 MOZ_ASSERT_UNREACHABLE("failure when starting file-dialog actor");
483 PROFILER_MARKER_TEXT(
484 "UtilityProcessManager::CreateWinFileDialogAsync", OTHER
,
485 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(startTime
)),
488 return Promise::CreateAndReject(error
, __PRETTY_FUNCTION__
);
494 bool UtilityProcessManager::IsProcessLaunching(SandboxingKind aSandbox
) {
495 MOZ_ASSERT(NS_IsMainThread());
497 RefPtr
<ProcessFields
> p
= GetProcess(aSandbox
);
499 MOZ_CRASH("Cannot check process launching with no process");
503 return p
->mProcess
&& !(p
->mProcessParent
);
506 bool UtilityProcessManager::IsProcessDestroyed(SandboxingKind aSandbox
) {
507 MOZ_ASSERT(NS_IsMainThread());
508 RefPtr
<ProcessFields
> p
= GetProcess(aSandbox
);
510 MOZ_CRASH("Cannot check process destroyed with no process");
513 return !p
->mProcess
&& !p
->mProcessParent
;
516 void UtilityProcessManager::OnProcessUnexpectedShutdown(
517 UtilityProcessHost
* aHost
) {
518 MOZ_ASSERT(NS_IsMainThread());
520 for (auto& it
: mProcesses
) {
521 if (it
&& it
->mProcess
&& it
->mProcess
== aHost
) {
522 it
->mNumUnexpectedCrashes
++;
523 DestroyProcess(it
->mSandbox
);
529 "Called UtilityProcessManager::OnProcessUnexpectedShutdown with invalid "
533 void UtilityProcessManager::CleanShutdownAllProcesses() {
534 LOGD("[%p] UtilityProcessManager::CleanShutdownAllProcesses", this);
536 for (auto& it
: mProcesses
) {
538 DestroyProcess(it
->mSandbox
);
543 void UtilityProcessManager::CleanShutdown(SandboxingKind aSandbox
) {
544 LOGD("[%p] UtilityProcessManager::CleanShutdown SandboxingKind=%" PRIu64
,
547 DestroyProcess(aSandbox
);
550 uint16_t UtilityProcessManager::AliveProcesses() {
552 for (auto& p
: mProcesses
) {
560 bool UtilityProcessManager::NoMoreProcesses() { return AliveProcesses() == 0; }
562 void UtilityProcessManager::DestroyProcess(SandboxingKind aSandbox
) {
563 LOGD("[%p] UtilityProcessManager::DestroyProcess SandboxingKind=%" PRIu64
,
566 MOZ_RELEASE_ASSERT(NS_IsMainThread());
568 if (AliveProcesses() <= 1) {
570 Preferences::RemoveObserver(mObserver
, "");
576 RefPtr
<ProcessFields
> p
= GetProcess(aSandbox
);
581 p
->mQueuedPrefs
.Clear();
582 p
->mProcessParent
= nullptr;
588 p
->mProcess
->Shutdown();
589 p
->mProcess
= nullptr;
591 mProcesses
[aSandbox
] = nullptr;
593 CrashReporter::AnnotateCrashReport(
594 CrashReporter::Annotation::UtilityProcessStatus
, "Destroyed"_ns
);
596 if (NoMoreProcesses()) {
597 sSingleton
= nullptr;
601 Maybe
<base::ProcessId
> UtilityProcessManager::ProcessPid(
602 SandboxingKind aSandbox
) {
603 MOZ_ASSERT(NS_IsMainThread());
604 RefPtr
<ProcessFields
> p
= GetProcess(aSandbox
);
608 if (p
->mProcessParent
) {
609 return Some(p
->mProcessParent
->OtherPid());
614 class UtilityMemoryReporter
: public MemoryReportingProcess
{
616 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(UtilityMemoryReporter
, override
)
618 explicit UtilityMemoryReporter(UtilityProcessParent
* aParent
) {
622 bool IsAlive() const override
{ return bool(GetParent()); }
624 bool SendRequestMemoryReport(
625 const uint32_t& aGeneration
, const bool& aAnonymize
,
626 const bool& aMinimizeMemoryUsage
,
627 const Maybe
<ipc::FileDescriptor
>& aDMDFile
) override
{
628 RefPtr
<UtilityProcessParent
> parent
= GetParent();
633 return parent
->SendRequestMemoryReport(aGeneration
, aAnonymize
,
634 aMinimizeMemoryUsage
, aDMDFile
);
637 int32_t Pid() const override
{
638 if (RefPtr
<UtilityProcessParent
> parent
= GetParent()) {
639 return (int32_t)parent
->OtherPid();
645 RefPtr
<UtilityProcessParent
> GetParent() const { return mParent
; }
647 RefPtr
<UtilityProcessParent
> mParent
= nullptr;
650 ~UtilityMemoryReporter() = default;
653 RefPtr
<MemoryReportingProcess
> UtilityProcessManager::GetProcessMemoryReporter(
654 UtilityProcessParent
* parent
) {
655 return new UtilityMemoryReporter(parent
);
658 } // namespace mozilla::ipc