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() {
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
139 [sandboxKind
= mSandbox
] {
140 StaticMutexAutoLock
lock(sUtilityProcessChildMutex
);
141 sUtilityProcessChild
= nullptr;
142 if (sandboxKind
== SandboxingKind::GENERIC_UTILITY
) {
146 ShutdownPhase::XPCOMShutdownFinal
);
151 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
153 void CGSShutdownServerConnections();
157 mozilla::ipc::IPCResult
UtilityProcessChild::RecvInit(
158 const Maybe
<FileDescriptor
>& aBrokerFd
,
159 const bool& aCanRecordReleaseTelemetry
,
160 const bool& aIsReadyForBackgroundProcessing
) {
161 // Do this now (before closing WindowServer on macOS) to avoid risking
162 // blocking in GetCurrentProcess() called on that platform
163 mozilla::ipc::SetThisProcessName("Utility Process");
165 #if defined(MOZ_SANDBOX)
166 # if defined(XP_MACOSX)
167 // Close all current connections to the WindowServer. This ensures that the
168 // Activity Monitor will not label the content process as "Not responding"
169 // because it's not running a native event loop. See bug 1384336.
170 CGSShutdownServerConnections();
172 # elif defined(XP_LINUX)
174 if (aBrokerFd
.isSome()) {
175 fd
= aBrokerFd
.value().ClonePlatformHandle().release();
178 SetUtilitySandbox(fd
, mSandbox
);
180 # endif // XP_MACOSX/XP_LINUX
181 #endif // MOZ_SANDBOX
184 if (aCanRecordReleaseTelemetry
) {
185 RefPtr
<DllServices
> dllSvc(DllServices::Get());
186 dllSvc
->StartUntrustedModulesProcessor(aIsReadyForBackgroundProcessing
);
188 #endif // defined(XP_WIN)
192 mozilla::ipc::IPCResult
UtilityProcessChild::RecvPreferenceUpdate(
194 Preferences::SetPreference(aPref
);
198 mozilla::ipc::IPCResult
UtilityProcessChild::RecvInitProfiler(
199 Endpoint
<PProfilerChild
>&& aEndpoint
) {
200 mProfilerController
= ChildProfilerController::Create(std::move(aEndpoint
));
204 mozilla::ipc::IPCResult
UtilityProcessChild::RecvRequestMemoryReport(
205 const uint32_t& aGeneration
, const bool& aAnonymize
,
206 const bool& aMinimizeMemoryUsage
, const Maybe
<FileDescriptor
>& aDMDFile
,
207 const RequestMemoryReportResolver
& aResolver
) {
208 nsPrintfCString
processName("Utility (pid %" PRIPID
209 ", sandboxingKind %" PRIu64
")",
210 base::GetCurrentProcId(), mSandbox
);
212 mozilla::dom::MemoryReportRequestClient::Start(
213 aGeneration
, aAnonymize
, aMinimizeMemoryUsage
, aDMDFile
, processName
,
214 [&](const MemoryReport
& aReport
) {
215 Unused
<< GetSingleton()->SendAddMemoryReport(aReport
);
221 #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
222 mozilla::ipc::IPCResult
UtilityProcessChild::RecvInitSandboxTesting(
223 Endpoint
<PSandboxTestingChild
>&& aEndpoint
) {
224 if (!SandboxTestingChild::Initialize(std::move(aEndpoint
))) {
226 this, "InitSandboxTesting failed to initialise the child process.");
232 mozilla::ipc::IPCResult
UtilityProcessChild::RecvFlushFOGData(
233 FlushFOGDataResolver
&& aResolver
) {
234 glean::FlushFOGData(std::move(aResolver
));
238 mozilla::ipc::IPCResult
UtilityProcessChild::RecvTestTriggerMetrics(
239 TestTriggerMetricsResolver
&& aResolve
) {
240 mozilla::glean::test_only_ipc::a_counter
.Add(
241 nsIXULRuntime::PROCESS_TYPE_UTILITY
);
246 mozilla::ipc::IPCResult
UtilityProcessChild::RecvTestTelemetryProbes() {
247 const uint32_t kExpectedUintValue
= 42;
248 Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_UTILITY_ONLY_UINT
,
253 mozilla::ipc::IPCResult
254 UtilityProcessChild::RecvStartUtilityAudioDecoderService(
255 Endpoint
<PUtilityAudioDecoderParent
>&& aEndpoint
) {
256 mUtilityAudioDecoderInstance
= new UtilityAudioDecoderParent();
257 if (!mUtilityAudioDecoderInstance
) {
258 return IPC_FAIL(this, "Failing to create UtilityAudioDecoderParent");
261 mUtilityAudioDecoderInstance
->Start(std::move(aEndpoint
));
265 mozilla::ipc::IPCResult
UtilityProcessChild::RecvStartJSOracleService(
266 Endpoint
<PJSOracleChild
>&& aEndpoint
) {
267 mJSOracleInstance
= new mozilla::dom::JSOracleChild();
268 if (!mJSOracleInstance
) {
269 return IPC_FAIL(this, "Failing to create JSOracleParent");
272 mJSOracleInstance
->Start(std::move(aEndpoint
));
277 mozilla::ipc::IPCResult
UtilityProcessChild::RecvStartWindowsUtilsService(
278 Endpoint
<dom::PWindowsUtilsChild
>&& aEndpoint
) {
279 mWindowsUtilsInstance
= new dom::WindowsUtilsChild();
280 if (!mWindowsUtilsInstance
) {
281 return IPC_FAIL(this, "Failed to create WindowsUtilsChild");
284 [[maybe_unused
]] bool ok
= std::move(aEndpoint
).Bind(mWindowsUtilsInstance
);
289 mozilla::ipc::IPCResult
UtilityProcessChild::RecvGetUntrustedModulesData(
290 GetUntrustedModulesDataResolver
&& aResolver
) {
291 RefPtr
<DllServices
> dllSvc(DllServices::Get());
292 dllSvc
->GetUntrustedModulesData()->Then(
293 GetMainThreadSerialEventTarget(), __func__
,
294 [aResolver
](Maybe
<UntrustedModulesData
>&& aData
) {
295 aResolver(std::move(aData
));
297 [aResolver
](nsresult aReason
) { aResolver(Nothing()); });
301 mozilla::ipc::IPCResult
302 UtilityProcessChild::RecvUnblockUntrustedModulesThread() {
303 if (nsCOMPtr
<nsIObserverService
> obs
=
304 mozilla::services::GetObserverService()) {
305 obs
->NotifyObservers(nullptr, "unblock-untrusted-modules-thread", nullptr);
309 #endif // defined(XP_WIN)
311 void UtilityProcessChild::ActorDestroy(ActorDestroyReason aWhy
) {
312 if (AbnormalShutdown
== aWhy
) {
313 NS_WARNING("Shutting down Utility process early due to a crash!");
314 ipc::ProcessChild::QuickExit();
317 // Send the last bits of Glean data over to the main process.
319 [](ByteBuf
&& aBuf
) { glean::SendFOGData(std::move(aBuf
)); });
321 #ifndef NS_FREE_PERMANENT_DATA
322 ProcessChild::QuickExit();
325 if (mProfilerController
) {
326 mProfilerController
->Shutdown();
327 mProfilerController
= nullptr;
330 uint32_t timeout
= 0;
331 if (mUtilityAudioDecoderInstance
) {
332 mUtilityAudioDecoderInstance
= nullptr;
336 mJSOracleInstance
= nullptr;
339 mWindowsUtilsInstance
= nullptr;
342 // Wait until all RemoteDecoderManagerParent have closed.
343 // It is still possible some may not have clean up yet, and we might hit
344 // timeout. Our xpcom-shutdown listener should take care of cleaning the
345 // reference of our singleton.
347 // FIXME: Should move from using AsyncBlockers to proper
348 // nsIAsyncShutdownService once it is not JS, see bug 1760855
349 mShutdownBlockers
.WaitUntilClear(timeout
)->Then(
350 GetCurrentSerialEventTarget(), __func__
, [&]() {
353 RefPtr
<DllServices
> dllSvc(DllServices::Get());
354 dllSvc
->DisableFull();
356 # endif // defined(XP_WIN)
358 ipc::CrashReporterClient::DestroySingleton();
359 XRE_ShutdownChildProcess();
361 #endif // NS_FREE_PERMANENT_DATA
364 } // namespace mozilla::ipc