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/ipc/UtilityProcessManager.h"
9 #include "mozilla/ipc/UtilityProcessSandboxing.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/AppShutdown.h"
16 #include "mozilla/Preferences.h"
17 #include "mozilla/RemoteDecoderManagerParent.h"
19 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
20 # include "mozilla/Sandbox.h"
23 #if defined(XP_OPENBSD) && defined(MOZ_SANDBOX)
24 # include "mozilla/SandboxSettings.h"
27 #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
28 # include "mozilla/SandboxTestingChild.h"
31 #include "mozilla/Telemetry.h"
34 # include "mozilla/WinDllServices.h"
35 # include "mozilla/dom/WindowsUtilsChild.h"
38 #include "nsDebugImpl.h"
39 #include "nsIXULRuntime.h"
40 #include "nsThreadManager.h"
41 #include "GeckoProfiler.h"
43 #include "mozilla/ipc/ProcessChild.h"
44 #include "mozilla/FOGIPC.h"
45 #include "mozilla/glean/GleanMetrics.h"
47 #include "mozilla/Services.h"
49 namespace mozilla::ipc
{
51 using namespace layers
;
53 static StaticMutex sUtilityProcessChildMutex
;
54 static StaticRefPtr
<UtilityProcessChild
> sUtilityProcessChild
55 MOZ_GUARDED_BY(sUtilityProcessChildMutex
);
57 UtilityProcessChild::UtilityProcessChild() : mChildStartTime(TimeStamp::Now()) {
58 nsDebugImpl::SetMultiprocessMode("Utility");
61 UtilityProcessChild::~UtilityProcessChild() = default;
64 RefPtr
<UtilityProcessChild
> UtilityProcessChild::GetSingleton() {
65 MOZ_ASSERT(XRE_IsUtilityProcess());
66 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownFinal
)) {
69 StaticMutexAutoLock
lock(sUtilityProcessChildMutex
);
70 if (!sUtilityProcessChild
) {
71 sUtilityProcessChild
= new UtilityProcessChild();
73 return sUtilityProcessChild
;
77 RefPtr
<UtilityProcessChild
> UtilityProcessChild::Get() {
78 StaticMutexAutoLock
lock(sUtilityProcessChildMutex
);
79 return sUtilityProcessChild
;
82 bool UtilityProcessChild::Init(mozilla::ipc::UntypedEndpoint
&& aEndpoint
,
83 const nsCString
& aParentBuildID
,
84 uint64_t aSandboxingKind
) {
85 MOZ_ASSERT(NS_IsMainThread());
87 // Initialize the thread manager before starting IPC. Otherwise, messages
88 // may be posted to the main thread and we won't be able to process them.
89 if (NS_WARN_IF(NS_FAILED(nsThreadManager::get().Init()))) {
93 // Now it's safe to start IPC.
94 if (NS_WARN_IF(!aEndpoint
.Bind(this))) {
98 // This must be checked before any IPDL message, which may hit sentinel
99 // errors due to parent and content processes having different
101 MessageChannel
* channel
= GetIPCChannel();
102 if (channel
&& !channel
->SendBuildIDsMatchMessage(aParentBuildID
.get())) {
103 // We need to quit this process if the buildID doesn't match the parent's.
104 // This can occur when an update occurred in the background.
105 ipc::ProcessChild::QuickExit();
108 // Init crash reporter support.
109 ipc::CrashReporterClient::InitSingleton(this);
111 if (NS_FAILED(NS_InitMinimalXPCOM())) {
115 mSandbox
= (SandboxingKind
)aSandboxingKind
;
117 // At the moment, only ORB uses JSContext in the
118 // Utility Process and ORB uses GENERIC_UTILITY
119 if (mSandbox
== SandboxingKind::GENERIC_UTILITY
) {
120 JS::DisableJitBackend();
124 #if defined(__OpenBSD__) && defined(MOZ_SANDBOX)
125 // Bug 1823458: delay pledge initialization, otherwise
126 // JS_Init triggers sysctl(KERN_PROC_ID) which isnt
127 // permitted with the current pledge.utility config
128 StartOpenBSDSandbox(GeckoProcessType_Utility
, mSandbox
);
132 profiler_set_process_name(nsCString("Utility Process"));
134 // Notify the parent process that we have finished our init and that it can
135 // now resolve the pending promise of process startup
138 PROFILER_MARKER_UNTYPED(
139 "UtilityProcessChild::SendInitCompleted", IPC
,
140 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
143 [sandboxKind
= mSandbox
] {
144 StaticMutexAutoLock
lock(sUtilityProcessChildMutex
);
145 sUtilityProcessChild
= nullptr;
146 if (sandboxKind
== SandboxingKind::GENERIC_UTILITY
) {
150 ShutdownPhase::XPCOMShutdownFinal
);
155 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
157 void CGSShutdownServerConnections();
161 mozilla::ipc::IPCResult
UtilityProcessChild::RecvInit(
162 const Maybe
<FileDescriptor
>& aBrokerFd
,
163 const bool& aCanRecordReleaseTelemetry
,
164 const bool& aIsReadyForBackgroundProcessing
) {
165 // Do this now (before closing WindowServer on macOS) to avoid risking
166 // blocking in GetCurrentProcess() called on that platform
167 mozilla::ipc::SetThisProcessName("Utility Process");
169 #if defined(MOZ_SANDBOX)
170 # if defined(XP_MACOSX)
171 // Close all current connections to the WindowServer. This ensures that the
172 // Activity Monitor will not label the content process as "Not responding"
173 // because it's not running a native event loop. See bug 1384336.
174 CGSShutdownServerConnections();
176 # elif defined(XP_LINUX)
178 if (aBrokerFd
.isSome()) {
179 fd
= aBrokerFd
.value().ClonePlatformHandle().release();
182 SetUtilitySandbox(fd
, mSandbox
);
184 # endif // XP_MACOSX/XP_LINUX
185 #endif // MOZ_SANDBOX
188 if (aCanRecordReleaseTelemetry
) {
189 RefPtr
<DllServices
> dllSvc(DllServices::Get());
190 dllSvc
->StartUntrustedModulesProcessor(aIsReadyForBackgroundProcessing
);
192 #endif // defined(XP_WIN)
194 PROFILER_MARKER_UNTYPED(
195 "UtilityProcessChild::RecvInit", IPC
,
196 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
200 mozilla::ipc::IPCResult
UtilityProcessChild::RecvPreferenceUpdate(
202 Preferences::SetPreference(aPref
);
206 mozilla::ipc::IPCResult
UtilityProcessChild::RecvInitProfiler(
207 Endpoint
<PProfilerChild
>&& aEndpoint
) {
208 mProfilerController
= ChildProfilerController::Create(std::move(aEndpoint
));
212 mozilla::ipc::IPCResult
UtilityProcessChild::RecvRequestMemoryReport(
213 const uint32_t& aGeneration
, const bool& aAnonymize
,
214 const bool& aMinimizeMemoryUsage
, const Maybe
<FileDescriptor
>& aDMDFile
,
215 const RequestMemoryReportResolver
& aResolver
) {
216 nsPrintfCString
processName("Utility (pid %" PRIPID
217 ", sandboxingKind %" PRIu64
")",
218 base::GetCurrentProcId(), mSandbox
);
220 mozilla::dom::MemoryReportRequestClient::Start(
221 aGeneration
, aAnonymize
, aMinimizeMemoryUsage
, aDMDFile
, processName
,
222 [&](const MemoryReport
& aReport
) {
223 Unused
<< GetSingleton()->SendAddMemoryReport(aReport
);
229 #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
230 mozilla::ipc::IPCResult
UtilityProcessChild::RecvInitSandboxTesting(
231 Endpoint
<PSandboxTestingChild
>&& aEndpoint
) {
232 if (!SandboxTestingChild::Initialize(std::move(aEndpoint
))) {
234 this, "InitSandboxTesting failed to initialise the child process.");
240 mozilla::ipc::IPCResult
UtilityProcessChild::RecvFlushFOGData(
241 FlushFOGDataResolver
&& aResolver
) {
242 glean::FlushFOGData(std::move(aResolver
));
246 mozilla::ipc::IPCResult
UtilityProcessChild::RecvTestTriggerMetrics(
247 TestTriggerMetricsResolver
&& aResolve
) {
248 mozilla::glean::test_only_ipc::a_counter
.Add(
249 nsIXULRuntime::PROCESS_TYPE_UTILITY
);
254 mozilla::ipc::IPCResult
UtilityProcessChild::RecvTestTelemetryProbes() {
255 const uint32_t kExpectedUintValue
= 42;
256 Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_UTILITY_ONLY_UINT
,
261 mozilla::ipc::IPCResult
262 UtilityProcessChild::RecvStartUtilityAudioDecoderService(
263 Endpoint
<PUtilityAudioDecoderParent
>&& aEndpoint
) {
264 PROFILER_MARKER_UNTYPED(
265 "UtilityProcessChild::RecvStartUtilityAudioDecoderService", MEDIA
,
266 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
267 mUtilityAudioDecoderInstance
= new UtilityAudioDecoderParent();
268 if (!mUtilityAudioDecoderInstance
) {
269 return IPC_FAIL(this, "Failing to create UtilityAudioDecoderParent");
272 mUtilityAudioDecoderInstance
->Start(std::move(aEndpoint
));
276 mozilla::ipc::IPCResult
UtilityProcessChild::RecvStartJSOracleService(
277 Endpoint
<PJSOracleChild
>&& aEndpoint
) {
278 PROFILER_MARKER_UNTYPED(
279 "UtilityProcessChild::RecvStartJSOracleService", JS
,
280 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
281 mJSOracleInstance
= new mozilla::dom::JSOracleChild();
282 if (!mJSOracleInstance
) {
283 return IPC_FAIL(this, "Failing to create JSOracleParent");
286 mJSOracleInstance
->Start(std::move(aEndpoint
));
291 mozilla::ipc::IPCResult
UtilityProcessChild::RecvStartWindowsUtilsService(
292 Endpoint
<dom::PWindowsUtilsChild
>&& aEndpoint
) {
293 PROFILER_MARKER_UNTYPED(
294 "UtilityProcessChild::RecvStartWindowsUtilsService", OTHER
,
295 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
296 mWindowsUtilsInstance
= new dom::WindowsUtilsChild();
297 if (!mWindowsUtilsInstance
) {
298 return IPC_FAIL(this, "Failed to create WindowsUtilsChild");
301 [[maybe_unused
]] bool ok
= std::move(aEndpoint
).Bind(mWindowsUtilsInstance
);
306 mozilla::ipc::IPCResult
UtilityProcessChild::RecvGetUntrustedModulesData(
307 GetUntrustedModulesDataResolver
&& aResolver
) {
308 RefPtr
<DllServices
> dllSvc(DllServices::Get());
309 dllSvc
->GetUntrustedModulesData()->Then(
310 GetMainThreadSerialEventTarget(), __func__
,
311 [aResolver
](Maybe
<UntrustedModulesData
>&& aData
) {
312 aResolver(std::move(aData
));
314 [aResolver
](nsresult aReason
) { aResolver(Nothing()); });
318 mozilla::ipc::IPCResult
319 UtilityProcessChild::RecvUnblockUntrustedModulesThread() {
320 if (nsCOMPtr
<nsIObserverService
> obs
=
321 mozilla::services::GetObserverService()) {
322 obs
->NotifyObservers(nullptr, "unblock-untrusted-modules-thread", nullptr);
326 #endif // defined(XP_WIN)
328 void UtilityProcessChild::ActorDestroy(ActorDestroyReason aWhy
) {
329 if (AbnormalShutdown
== aWhy
) {
330 NS_WARNING("Shutting down Utility process early due to a crash!");
331 ipc::ProcessChild::QuickExit();
334 // Send the last bits of Glean data over to the main process.
336 [](ByteBuf
&& aBuf
) { glean::SendFOGData(std::move(aBuf
)); });
338 #ifndef NS_FREE_PERMANENT_DATA
339 ProcessChild::QuickExit();
342 if (mProfilerController
) {
343 mProfilerController
->Shutdown();
344 mProfilerController
= nullptr;
347 uint32_t timeout
= 0;
348 if (mUtilityAudioDecoderInstance
) {
349 mUtilityAudioDecoderInstance
= nullptr;
353 mJSOracleInstance
= nullptr;
356 mWindowsUtilsInstance
= nullptr;
359 // Wait until all RemoteDecoderManagerParent have closed.
360 // It is still possible some may not have clean up yet, and we might hit
361 // timeout. Our xpcom-shutdown listener should take care of cleaning the
362 // reference of our singleton.
364 // FIXME: Should move from using AsyncBlockers to proper
365 // nsIAsyncShutdownService once it is not JS, see bug 1760855
366 mShutdownBlockers
.WaitUntilClear(timeout
)->Then(
367 GetCurrentSerialEventTarget(), __func__
, [&]() {
370 RefPtr
<DllServices
> dllSvc(DllServices::Get());
371 dllSvc
->DisableFull();
373 # endif // defined(XP_WIN)
375 ipc::CrashReporterClient::DestroySingleton();
376 XRE_ShutdownChildProcess();
378 #endif // NS_FREE_PERMANENT_DATA
381 } // namespace mozilla::ipc