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 "UtilityProcessChild.h"
8 #include "mozilla/AppShutdown.h"
9 #include "mozilla/Logging.h"
10 #include "mozilla/dom/ContentParent.h"
11 #include "mozilla/dom/JSOracleChild.h"
12 #include "mozilla/dom/MemoryReportRequest.h"
13 #include "mozilla/ipc/CrashReporterClient.h"
14 #include "mozilla/ipc/Endpoint.h"
15 #include "mozilla/ipc/UtilityProcessManager.h"
16 #include "mozilla/ipc/UtilityProcessSandboxing.h"
17 #include "mozilla/Preferences.h"
18 #include "mozilla/RemoteDecoderManagerParent.h"
20 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
21 # include "mozilla/Sandbox.h"
22 # include "mozilla/SandboxProfilerObserver.h"
25 #if defined(XP_OPENBSD) && defined(MOZ_SANDBOX)
26 # include "mozilla/SandboxSettings.h"
29 #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
30 # include "mozilla/SandboxTestingChild.h"
33 #include "mozilla/Telemetry.h"
36 # include "mozilla/WinDllServices.h"
37 # include "mozilla/dom/WindowsUtilsChild.h"
38 # include "mozilla/widget/filedialog/WinFileDialogChild.h"
41 #include "nsDebugImpl.h"
42 #include "nsIXULRuntime.h"
43 #include "nsThreadManager.h"
44 #include "GeckoProfiler.h"
46 #include "mozilla/ipc/ProcessChild.h"
47 #include "mozilla/FOGIPC.h"
48 #include "mozilla/glean/GleanMetrics.h"
50 #include "mozilla/Services.h"
52 namespace mozilla::ipc
{
54 using namespace layers
;
56 static StaticMutex sUtilityProcessChildMutex
;
57 static StaticRefPtr
<UtilityProcessChild
> sUtilityProcessChild
58 MOZ_GUARDED_BY(sUtilityProcessChildMutex
);
60 UtilityProcessChild::UtilityProcessChild() : mChildStartTime(TimeStamp::Now()) {
61 nsDebugImpl::SetMultiprocessMode("Utility");
64 UtilityProcessChild::~UtilityProcessChild() = default;
67 RefPtr
<UtilityProcessChild
> UtilityProcessChild::GetSingleton() {
68 MOZ_ASSERT(XRE_IsUtilityProcess());
69 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownFinal
)) {
72 StaticMutexAutoLock
lock(sUtilityProcessChildMutex
);
73 if (!sUtilityProcessChild
) {
74 sUtilityProcessChild
= new UtilityProcessChild();
76 return sUtilityProcessChild
;
80 RefPtr
<UtilityProcessChild
> UtilityProcessChild::Get() {
81 StaticMutexAutoLock
lock(sUtilityProcessChildMutex
);
82 return sUtilityProcessChild
;
85 bool UtilityProcessChild::Init(mozilla::ipc::UntypedEndpoint
&& aEndpoint
,
86 const nsCString
& aParentBuildID
,
87 uint64_t aSandboxingKind
) {
88 MOZ_ASSERT(NS_IsMainThread());
90 // Initialize the thread manager before starting IPC. Otherwise, messages
91 // may be posted to the main thread and we won't be able to process them.
92 if (NS_WARN_IF(NS_FAILED(nsThreadManager::get().Init()))) {
96 // Now it's safe to start IPC.
97 if (NS_WARN_IF(!aEndpoint
.Bind(this))) {
101 // This must be checked before any IPDL message, which may hit sentinel
102 // errors due to parent and content processes having different
104 MessageChannel
* channel
= GetIPCChannel();
105 if (channel
&& !channel
->SendBuildIDsMatchMessage(aParentBuildID
.get())) {
106 // We need to quit this process if the buildID doesn't match the parent's.
107 // This can occur when an update occurred in the background.
108 ipc::ProcessChild::QuickExit();
111 // Init crash reporter support.
112 ipc::CrashReporterClient::InitSingleton(this);
114 if (NS_FAILED(NS_InitMinimalXPCOM())) {
118 mSandbox
= (SandboxingKind
)aSandboxingKind
;
120 // At the moment, only ORB uses JSContext in the
121 // Utility Process and ORB uses GENERIC_UTILITY
122 if (mSandbox
== SandboxingKind::GENERIC_UTILITY
) {
123 if (!JS_FrontendOnlyInit()) {
126 #if defined(__OpenBSD__) && defined(MOZ_SANDBOX)
127 // Bug 1823458: delay pledge initialization, otherwise
128 // JS_FrontendOnlyInit triggers sysctl(KERN_PROC_ID) which isnt
129 // permitted with the current pledge.utility config
130 StartOpenBSDSandbox(GeckoProcessType_Utility
, mSandbox
);
134 profiler_set_process_name(nsCString("Utility Process"));
136 // Notify the parent process that we have finished our init and that it can
137 // now resolve the pending promise of process startup
140 PROFILER_MARKER_UNTYPED(
141 "UtilityProcessChild::SendInitCompleted", IPC
,
142 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
145 [sandboxKind
= mSandbox
] {
146 StaticMutexAutoLock
lock(sUtilityProcessChildMutex
);
147 sUtilityProcessChild
= nullptr;
148 if (sandboxKind
== SandboxingKind::GENERIC_UTILITY
) {
149 JS_FrontendOnlyShutDown();
152 ShutdownPhase::XPCOMShutdownFinal
);
157 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
159 void CGSShutdownServerConnections();
163 mozilla::ipc::IPCResult
UtilityProcessChild::RecvInit(
164 const Maybe
<FileDescriptor
>& aBrokerFd
,
165 const bool& aCanRecordReleaseTelemetry
,
166 const bool& aIsReadyForBackgroundProcessing
) {
167 // Do this now (before closing WindowServer on macOS) to avoid risking
168 // blocking in GetCurrentProcess() called on that platform
169 mozilla::ipc::SetThisProcessName("Utility Process");
171 #if defined(MOZ_SANDBOX)
172 # if defined(XP_MACOSX)
173 // Close all current connections to the WindowServer. This ensures that the
174 // Activity Monitor will not label the content process as "Not responding"
175 // because it's not running a native event loop. See bug 1384336.
176 CGSShutdownServerConnections();
178 # elif defined(XP_LINUX)
180 if (aBrokerFd
.isSome()) {
181 fd
= aBrokerFd
.value().ClonePlatformHandle().release();
184 RegisterProfilerObserversForSandboxProfiler();
185 SetUtilitySandbox(fd
, mSandbox
);
187 # endif // XP_MACOSX/XP_LINUX
188 #endif // MOZ_SANDBOX
191 if (aCanRecordReleaseTelemetry
) {
192 RefPtr
<DllServices
> dllSvc(DllServices::Get());
193 dllSvc
->StartUntrustedModulesProcessor(aIsReadyForBackgroundProcessing
);
195 #endif // defined(XP_WIN)
197 PROFILER_MARKER_UNTYPED(
198 "UtilityProcessChild::RecvInit", IPC
,
199 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
203 mozilla::ipc::IPCResult
UtilityProcessChild::RecvPreferenceUpdate(
205 Preferences::SetPreference(aPref
);
209 mozilla::ipc::IPCResult
UtilityProcessChild::RecvInitProfiler(
210 Endpoint
<PProfilerChild
>&& aEndpoint
) {
211 mProfilerController
= ChildProfilerController::Create(std::move(aEndpoint
));
215 mozilla::ipc::IPCResult
UtilityProcessChild::RecvRequestMemoryReport(
216 const uint32_t& aGeneration
, const bool& aAnonymize
,
217 const bool& aMinimizeMemoryUsage
, const Maybe
<FileDescriptor
>& aDMDFile
,
218 const RequestMemoryReportResolver
& aResolver
) {
219 nsPrintfCString
processName("Utility (pid %" PRIPID
220 ", sandboxingKind %" PRIu64
")",
221 base::GetCurrentProcId(), mSandbox
);
223 mozilla::dom::MemoryReportRequestClient::Start(
224 aGeneration
, aAnonymize
, aMinimizeMemoryUsage
, aDMDFile
, processName
,
225 [&](const MemoryReport
& aReport
) {
226 Unused
<< GetSingleton()->SendAddMemoryReport(aReport
);
232 #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
233 mozilla::ipc::IPCResult
UtilityProcessChild::RecvInitSandboxTesting(
234 Endpoint
<PSandboxTestingChild
>&& aEndpoint
) {
235 if (!SandboxTestingChild::Initialize(std::move(aEndpoint
))) {
237 this, "InitSandboxTesting failed to initialise the child process.");
243 mozilla::ipc::IPCResult
UtilityProcessChild::RecvFlushFOGData(
244 FlushFOGDataResolver
&& aResolver
) {
245 glean::FlushFOGData(std::move(aResolver
));
249 mozilla::ipc::IPCResult
UtilityProcessChild::RecvTestTriggerMetrics(
250 TestTriggerMetricsResolver
&& aResolve
) {
251 mozilla::glean::test_only_ipc::a_counter
.Add(
252 nsIXULRuntime::PROCESS_TYPE_UTILITY
);
257 mozilla::ipc::IPCResult
UtilityProcessChild::RecvTestTelemetryProbes() {
258 const uint32_t kExpectedUintValue
= 42;
259 Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_UTILITY_ONLY_UINT
,
264 mozilla::ipc::IPCResult
265 UtilityProcessChild::RecvStartUtilityAudioDecoderService(
266 Endpoint
<PUtilityAudioDecoderParent
>&& aEndpoint
,
267 nsTArray
<gfx::GfxVarUpdate
>&& aUpdates
) {
268 PROFILER_MARKER_UNTYPED(
269 "UtilityProcessChild::RecvStartUtilityAudioDecoderService", MEDIA
,
270 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
271 mUtilityAudioDecoderInstance
=
272 new UtilityAudioDecoderParent(std::move(aUpdates
));
273 if (!mUtilityAudioDecoderInstance
) {
274 return IPC_FAIL(this, "Failed to create UtilityAudioDecoderParent");
277 mUtilityAudioDecoderInstance
->Start(std::move(aEndpoint
));
281 mozilla::ipc::IPCResult
UtilityProcessChild::RecvStartJSOracleService(
282 Endpoint
<PJSOracleChild
>&& aEndpoint
) {
283 PROFILER_MARKER_UNTYPED(
284 "UtilityProcessChild::RecvStartJSOracleService", JS
,
285 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
286 mJSOracleInstance
= new mozilla::dom::JSOracleChild();
287 if (!mJSOracleInstance
) {
288 return IPC_FAIL(this, "Failed to create JSOracleParent");
291 mJSOracleInstance
->Start(std::move(aEndpoint
));
296 mozilla::ipc::IPCResult
UtilityProcessChild::RecvStartWindowsUtilsService(
297 Endpoint
<dom::PWindowsUtilsChild
>&& aEndpoint
) {
298 PROFILER_MARKER_UNTYPED(
299 "UtilityProcessChild::RecvStartWindowsUtilsService", OTHER
,
300 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
301 mWindowsUtilsInstance
= new dom::WindowsUtilsChild();
302 if (!mWindowsUtilsInstance
) {
303 return IPC_FAIL(this, "Failed to create WindowsUtilsChild");
306 [[maybe_unused
]] bool ok
= std::move(aEndpoint
).Bind(mWindowsUtilsInstance
);
311 mozilla::ipc::IPCResult
UtilityProcessChild::RecvStartWinFileDialogService(
312 Endpoint
<widget::filedialog::PWinFileDialogChild
>&& aEndpoint
) {
313 PROFILER_MARKER_UNTYPED(
314 "UtilityProcessChild::RecvStartWinFileDialogService", OTHER
,
315 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
317 auto instance
= MakeRefPtr
<widget::filedialog::WinFileDialogChild
>();
319 return IPC_FAIL(this, "Failed to create WinFileDialogChild");
322 bool const ok
= std::move(aEndpoint
).Bind(instance
.get());
324 return IPC_FAIL(this, "Failed to bind created WinFileDialogChild");
330 mozilla::ipc::IPCResult
UtilityProcessChild::RecvGetUntrustedModulesData(
331 GetUntrustedModulesDataResolver
&& aResolver
) {
332 RefPtr
<DllServices
> dllSvc(DllServices::Get());
333 dllSvc
->GetUntrustedModulesData()->Then(
334 GetMainThreadSerialEventTarget(), __func__
,
335 [aResolver
](Maybe
<UntrustedModulesData
>&& aData
) {
336 aResolver(std::move(aData
));
338 [aResolver
](nsresult aReason
) { aResolver(Nothing()); });
342 mozilla::ipc::IPCResult
343 UtilityProcessChild::RecvUnblockUntrustedModulesThread() {
344 if (nsCOMPtr
<nsIObserverService
> obs
=
345 mozilla::services::GetObserverService()) {
346 obs
->NotifyObservers(nullptr, "unblock-untrusted-modules-thread", nullptr);
350 #endif // defined(XP_WIN)
352 void UtilityProcessChild::ActorDestroy(ActorDestroyReason aWhy
) {
353 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
354 DestroySandboxProfiler();
357 if (AbnormalShutdown
== aWhy
) {
358 NS_WARNING("Shutting down Utility process early due to a crash!");
359 ipc::ProcessChild::QuickExit();
362 // Send the last bits of Glean data over to the main process.
364 [](ByteBuf
&& aBuf
) { glean::SendFOGData(std::move(aBuf
)); });
366 #ifndef NS_FREE_PERMANENT_DATA
367 ProcessChild::QuickExit();
370 if (mProfilerController
) {
371 mProfilerController
->Shutdown();
372 mProfilerController
= nullptr;
375 uint32_t timeout
= 0;
376 if (mUtilityAudioDecoderInstance
) {
377 mUtilityAudioDecoderInstance
= nullptr;
381 mJSOracleInstance
= nullptr;
384 mWindowsUtilsInstance
= nullptr;
387 // Wait until all RemoteDecoderManagerParent have closed.
388 // It is still possible some may not have clean up yet, and we might hit
389 // timeout. Our xpcom-shutdown listener should take care of cleaning the
390 // reference of our singleton.
392 // FIXME: Should move from using AsyncBlockers to proper
393 // nsIAsyncShutdownService once it is not JS, see bug 1760855
394 mShutdownBlockers
.WaitUntilClear(timeout
)->Then(
395 GetCurrentSerialEventTarget(), __func__
, [&]() {
398 RefPtr
<DllServices
> dllSvc(DllServices::Get());
399 dllSvc
->DisableFull();
401 # endif // defined(XP_WIN)
403 ipc::CrashReporterClient::DestroySingleton();
404 XRE_ShutdownChildProcess();
406 #endif // NS_FREE_PERMANENT_DATA
409 } // namespace mozilla::ipc