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
, dom::ContentParentId aChildId
,
315 SandboxingKind aSandbox
) {
316 // Not supported kinds.
317 if (aSandbox
!= SandboxingKind::GENERIC_UTILITY
318 #ifdef MOZ_APPLEMEDIA
319 && aSandbox
!= SandboxingKind::UTILITY_AUDIO_DECODING_APPLE_MEDIA
322 && aSandbox
!= SandboxingKind::UTILITY_AUDIO_DECODING_WMF
324 #ifdef MOZ_WMF_MEDIA_ENGINE
325 && aSandbox
!= SandboxingKind::MF_MEDIA_ENGINE_CDM
328 return StartRemoteDecodingUtilityPromise::CreateAndReject(NS_ERROR_FAILURE
,
331 TimeStamp remoteDecodingStart
= TimeStamp::Now();
333 RefPtr
<UtilityProcessManager
> self
= this;
334 RefPtr
<UtilityAudioDecoderChild
> uadc
=
335 UtilityAudioDecoderChild::GetSingleton(aSandbox
);
336 MOZ_ASSERT(uadc
, "Unable to get a singleton for UtilityAudioDecoderChild");
337 return StartUtility(uadc
, aSandbox
)
339 GetMainThreadSerialEventTarget(), __func__
,
340 [self
, uadc
, aOtherProcess
, aChildId
, aSandbox
,
341 remoteDecodingStart
]() {
342 RefPtr
<UtilityProcessParent
> parent
=
343 self
->GetProcessParent(aSandbox
);
345 NS_WARNING("UtilityAudioDecoderParent lost in the middle");
346 return StartRemoteDecodingUtilityPromise::CreateAndReject(
347 NS_ERROR_FAILURE
, __func__
);
350 if (!uadc
->CanSend()) {
351 NS_WARNING("UtilityAudioDecoderChild lost in the middle");
352 return StartRemoteDecodingUtilityPromise::CreateAndReject(
353 NS_ERROR_FAILURE
, __func__
);
356 base::ProcessId process
= parent
->OtherPid();
358 Endpoint
<PRemoteDecoderManagerChild
> childPipe
;
359 Endpoint
<PRemoteDecoderManagerParent
> parentPipe
;
360 nsresult rv
= PRemoteDecoderManager::CreateEndpoints(
361 process
, aOtherProcess
, &parentPipe
, &childPipe
);
363 MOZ_ASSERT(false, "Could not create content remote decoder");
364 return StartRemoteDecodingUtilityPromise::CreateAndReject(
368 if (!uadc
->SendNewContentRemoteDecoderManager(std::move(parentPipe
),
370 MOZ_ASSERT(false, "SendNewContentRemoteDecoderManager failure");
371 return StartRemoteDecodingUtilityPromise::CreateAndReject(
372 NS_ERROR_FAILURE
, __func__
);
375 #ifdef MOZ_WMF_MEDIA_ENGINE
376 if (aSandbox
== SandboxingKind::MF_MEDIA_ENGINE_CDM
&&
377 !uadc
->CreateVideoBridge()) {
378 MOZ_ASSERT(false, "Failed to create video bridge");
379 return StartRemoteDecodingUtilityPromise::CreateAndReject(
380 NS_ERROR_FAILURE
, __func__
);
383 PROFILER_MARKER_TEXT(
384 "UtilityProcessManager::StartProcessForRemoteMediaDecoding",
387 MarkerTiming::IntervalUntilNowFrom(remoteDecodingStart
)),
389 return StartRemoteDecodingUtilityPromise::CreateAndResolve(
390 std::move(childPipe
), __func__
);
392 [self
, remoteDecodingStart
](nsresult aError
) {
394 "Reject StartProcessForRemoteMediaDecoding() for "
395 "StartUtility() rejection");
396 PROFILER_MARKER_TEXT(
397 "UtilityProcessManager::StartProcessForRemoteMediaDecoding",
400 MarkerTiming::IntervalUntilNowFrom(remoteDecodingStart
)),
402 return StartRemoteDecodingUtilityPromise::CreateAndReject(aError
,
407 RefPtr
<UtilityProcessManager::JSOraclePromise
>
408 UtilityProcessManager::StartJSOracle(dom::JSOracleParent
* aParent
) {
409 return StartUtility(RefPtr
{aParent
}, SandboxingKind::GENERIC_UTILITY
);
416 RefPtr
<UtilityProcessManager::WindowsUtilsPromise
>
417 UtilityProcessManager::GetWindowsUtilsPromise() {
418 TimeStamp windowsUtilsStart
= TimeStamp::Now();
419 RefPtr
<UtilityProcessManager
> self
= this;
420 if (!mWindowsUtils
) {
421 mWindowsUtils
= new dom::WindowsUtilsParent();
424 RefPtr
<dom::WindowsUtilsParent
> wup
= mWindowsUtils
;
425 MOZ_ASSERT(wup
, "Unable to get a singleton for WindowsUtils");
426 return StartUtility(wup
, SandboxingKind::WINDOWS_UTILS
)
428 GetMainThreadSerialEventTarget(), __func__
,
429 [self
, wup
, windowsUtilsStart
]() {
430 if (!wup
->CanSend()) {
431 MOZ_ASSERT(false, "WindowsUtilsParent can't send");
432 return WindowsUtilsPromise::CreateAndReject(NS_ERROR_FAILURE
,
435 PROFILER_MARKER_TEXT(
436 "UtilityProcessManager::GetWindowsUtilsPromise", OTHER
,
438 MarkerTiming::IntervalUntilNowFrom(windowsUtilsStart
)),
440 return WindowsUtilsPromise::CreateAndResolve(wup
, __func__
);
442 [self
, windowsUtilsStart
](nsresult aError
) {
443 NS_WARNING("StartUtility rejected promise for PWindowsUtils");
444 PROFILER_MARKER_TEXT(
445 "UtilityProcessManager::GetWindowsUtilsPromise", OTHER
,
447 MarkerTiming::IntervalUntilNowFrom(windowsUtilsStart
)),
449 return WindowsUtilsPromise::CreateAndReject(aError
, __func__
);
453 void UtilityProcessManager::ReleaseWindowsUtils() { mWindowsUtils
= nullptr; }
455 RefPtr
<UtilityProcessManager::WinFileDialogPromise
>
456 UtilityProcessManager::CreateWinFileDialogActor() {
457 using Promise
= WinFileDialogPromise
;
458 TimeStamp startTime
= TimeStamp::Now();
459 auto wfdp
= MakeRefPtr
<widget::filedialog::WinFileDialogParent
>();
461 return StartUtility(wfdp
, SandboxingKind::WINDOWS_FILE_DIALOG
)
463 GetMainThreadSerialEventTarget(), __PRETTY_FUNCTION__
,
464 [wfdp
, startTime
]() mutable {
465 LOGD("CreateWinFileDialogAsync() resolve: wfdp = [%p]", wfdp
.get());
466 if (!wfdp
->CanSend()) {
467 MOZ_ASSERT(false, "WinFileDialogParent can't send");
468 return Promise::CreateAndReject(NS_ERROR_FAILURE
,
469 __PRETTY_FUNCTION__
);
471 PROFILER_MARKER_TEXT(
472 "UtilityProcessManager::CreateWinFileDialogAsync", OTHER
,
473 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(startTime
)),
476 return Promise::CreateAndResolve(
477 widget::filedialog::ProcessProxy(std::move(wfdp
)),
478 __PRETTY_FUNCTION__
);
480 [self
= RefPtr(this), startTime
](nsresult error
) {
481 LOGD("CreateWinFileDialogAsync() reject");
482 if (!self
->IsShutdown()) {
483 MOZ_ASSERT_UNREACHABLE("failure when starting file-dialog actor");
485 PROFILER_MARKER_TEXT(
486 "UtilityProcessManager::CreateWinFileDialogAsync", OTHER
,
487 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(startTime
)),
490 return Promise::CreateAndReject(error
, __PRETTY_FUNCTION__
);
496 bool UtilityProcessManager::IsProcessLaunching(SandboxingKind aSandbox
) {
497 MOZ_ASSERT(NS_IsMainThread());
499 RefPtr
<ProcessFields
> p
= GetProcess(aSandbox
);
501 MOZ_CRASH("Cannot check process launching with no process");
505 return p
->mProcess
&& !(p
->mProcessParent
);
508 bool UtilityProcessManager::IsProcessDestroyed(SandboxingKind aSandbox
) {
509 MOZ_ASSERT(NS_IsMainThread());
510 RefPtr
<ProcessFields
> p
= GetProcess(aSandbox
);
512 MOZ_CRASH("Cannot check process destroyed with no process");
515 return !p
->mProcess
&& !p
->mProcessParent
;
518 void UtilityProcessManager::OnProcessUnexpectedShutdown(
519 UtilityProcessHost
* aHost
) {
520 MOZ_ASSERT(NS_IsMainThread());
522 for (auto& it
: mProcesses
) {
523 if (it
&& it
->mProcess
&& it
->mProcess
== aHost
) {
524 it
->mNumUnexpectedCrashes
++;
525 DestroyProcess(it
->mSandbox
);
531 "Called UtilityProcessManager::OnProcessUnexpectedShutdown with invalid "
535 void UtilityProcessManager::CleanShutdownAllProcesses() {
536 LOGD("[%p] UtilityProcessManager::CleanShutdownAllProcesses", this);
538 for (auto& it
: mProcesses
) {
540 DestroyProcess(it
->mSandbox
);
545 void UtilityProcessManager::CleanShutdown(SandboxingKind aSandbox
) {
546 LOGD("[%p] UtilityProcessManager::CleanShutdown SandboxingKind=%" PRIu64
,
549 DestroyProcess(aSandbox
);
552 uint16_t UtilityProcessManager::AliveProcesses() {
554 for (auto& p
: mProcesses
) {
562 bool UtilityProcessManager::NoMoreProcesses() { return AliveProcesses() == 0; }
564 void UtilityProcessManager::DestroyProcess(SandboxingKind aSandbox
) {
565 LOGD("[%p] UtilityProcessManager::DestroyProcess SandboxingKind=%" PRIu64
,
568 MOZ_RELEASE_ASSERT(NS_IsMainThread());
570 if (AliveProcesses() <= 1) {
572 Preferences::RemoveObserver(mObserver
, "");
578 RefPtr
<ProcessFields
> p
= GetProcess(aSandbox
);
583 p
->mQueuedPrefs
.Clear();
584 p
->mProcessParent
= nullptr;
590 p
->mProcess
->Shutdown();
591 p
->mProcess
= nullptr;
593 mProcesses
[aSandbox
] = nullptr;
595 CrashReporter::AnnotateCrashReport(
596 CrashReporter::Annotation::UtilityProcessStatus
, "Destroyed"_ns
);
598 if (NoMoreProcesses()) {
599 sSingleton
= nullptr;
603 Maybe
<base::ProcessId
> UtilityProcessManager::ProcessPid(
604 SandboxingKind aSandbox
) {
605 MOZ_ASSERT(NS_IsMainThread());
606 RefPtr
<ProcessFields
> p
= GetProcess(aSandbox
);
610 if (p
->mProcessParent
) {
611 return Some(p
->mProcessParent
->OtherPid());
616 class UtilityMemoryReporter
: public MemoryReportingProcess
{
618 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(UtilityMemoryReporter
, override
)
620 explicit UtilityMemoryReporter(UtilityProcessParent
* aParent
) {
624 bool IsAlive() const override
{ return bool(GetParent()); }
626 bool SendRequestMemoryReport(
627 const uint32_t& aGeneration
, const bool& aAnonymize
,
628 const bool& aMinimizeMemoryUsage
,
629 const Maybe
<ipc::FileDescriptor
>& aDMDFile
) override
{
630 RefPtr
<UtilityProcessParent
> parent
= GetParent();
635 return parent
->SendRequestMemoryReport(aGeneration
, aAnonymize
,
636 aMinimizeMemoryUsage
, aDMDFile
);
639 int32_t Pid() const override
{
640 if (RefPtr
<UtilityProcessParent
> parent
= GetParent()) {
641 return (int32_t)parent
->OtherPid();
647 RefPtr
<UtilityProcessParent
> GetParent() const { return mParent
; }
649 RefPtr
<UtilityProcessParent
> mParent
= nullptr;
652 ~UtilityMemoryReporter() = default;
655 RefPtr
<MemoryReportingProcess
> UtilityProcessManager::GetProcessMemoryReporter(
656 UtilityProcessParent
* parent
) {
657 return new UtilityMemoryReporter(parent
);
660 } // namespace mozilla::ipc