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/GleanTestsTestMetrics.h"
50 #include "mozilla/Services.h"
52 namespace TelemetryScalar
{
53 void Set(mozilla::Telemetry::ScalarID aId
, uint32_t aValue
);
56 namespace mozilla::ipc
{
58 using namespace layers
;
60 static StaticMutex sUtilityProcessChildMutex
;
61 static StaticRefPtr
<UtilityProcessChild
> sUtilityProcessChild
62 MOZ_GUARDED_BY(sUtilityProcessChildMutex
);
64 UtilityProcessChild::UtilityProcessChild() : mChildStartTime(TimeStamp::Now()) {
65 nsDebugImpl::SetMultiprocessMode("Utility");
68 UtilityProcessChild::~UtilityProcessChild() = default;
71 RefPtr
<UtilityProcessChild
> UtilityProcessChild::GetSingleton() {
72 MOZ_ASSERT(XRE_IsUtilityProcess());
73 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownFinal
)) {
76 StaticMutexAutoLock
lock(sUtilityProcessChildMutex
);
77 if (!sUtilityProcessChild
) {
78 sUtilityProcessChild
= new UtilityProcessChild();
80 return sUtilityProcessChild
;
84 RefPtr
<UtilityProcessChild
> UtilityProcessChild::Get() {
85 StaticMutexAutoLock
lock(sUtilityProcessChildMutex
);
86 return sUtilityProcessChild
;
89 bool UtilityProcessChild::Init(mozilla::ipc::UntypedEndpoint
&& aEndpoint
,
90 const nsCString
& aParentBuildID
,
91 uint64_t aSandboxingKind
) {
92 MOZ_ASSERT(NS_IsMainThread());
94 // Initialize the thread manager before starting IPC. Otherwise, messages
95 // may be posted to the main thread and we won't be able to process them.
96 if (NS_WARN_IF(NS_FAILED(nsThreadManager::get().Init()))) {
100 // Now it's safe to start IPC.
101 if (NS_WARN_IF(!aEndpoint
.Bind(this))) {
105 // This must be checked before any IPDL message, which may hit sentinel
106 // errors due to parent and content processes having different
108 MessageChannel
* channel
= GetIPCChannel();
109 if (channel
&& !channel
->SendBuildIDsMatchMessage(aParentBuildID
.get())) {
110 // We need to quit this process if the buildID doesn't match the parent's.
111 // This can occur when an update occurred in the background.
112 ipc::ProcessChild::QuickExit();
115 // Init crash reporter support.
116 ipc::CrashReporterClient::InitSingleton(this);
118 if (NS_FAILED(NS_InitMinimalXPCOM())) {
122 mSandbox
= (SandboxingKind
)aSandboxingKind
;
124 // At the moment, only ORB uses JSContext in the
125 // Utility Process and ORB uses GENERIC_UTILITY
126 if (mSandbox
== SandboxingKind::GENERIC_UTILITY
) {
127 if (!JS_FrontendOnlyInit()) {
130 #if defined(__OpenBSD__) && defined(MOZ_SANDBOX)
131 // Bug 1823458: delay pledge initialization, otherwise
132 // JS_FrontendOnlyInit triggers sysctl(KERN_PROC_ID) which isnt
133 // permitted with the current pledge.utility config
134 StartOpenBSDSandbox(GeckoProcessType_Utility
, mSandbox
);
138 profiler_set_process_name(nsCString("Utility Process"));
140 // Notify the parent process that we have finished our init and that it can
141 // now resolve the pending promise of process startup
144 PROFILER_MARKER_UNTYPED(
145 "UtilityProcessChild::SendInitCompleted", IPC
,
146 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
149 [sandboxKind
= mSandbox
] {
150 StaticMutexAutoLock
lock(sUtilityProcessChildMutex
);
151 sUtilityProcessChild
= nullptr;
152 if (sandboxKind
== SandboxingKind::GENERIC_UTILITY
) {
153 JS_FrontendOnlyShutDown();
156 ShutdownPhase::XPCOMShutdownFinal
);
161 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
163 void CGSShutdownServerConnections();
167 mozilla::ipc::IPCResult
UtilityProcessChild::RecvInit(
168 const Maybe
<FileDescriptor
>& aBrokerFd
,
169 const bool& aCanRecordReleaseTelemetry
,
170 const bool& aIsReadyForBackgroundProcessing
) {
171 // Do this now (before closing WindowServer on macOS) to avoid risking
172 // blocking in GetCurrentProcess() called on that platform
173 mozilla::ipc::SetThisProcessName("Utility Process");
175 #if defined(MOZ_SANDBOX)
176 # if defined(XP_MACOSX)
177 // Close all current connections to the WindowServer. This ensures that the
178 // Activity Monitor will not label the content process as "Not responding"
179 // because it's not running a native event loop. See bug 1384336.
180 CGSShutdownServerConnections();
182 # elif defined(XP_LINUX)
184 if (aBrokerFd
.isSome()) {
185 fd
= aBrokerFd
.value().ClonePlatformHandle().release();
188 RegisterProfilerObserversForSandboxProfiler();
189 SetUtilitySandbox(fd
, mSandbox
);
191 # endif // XP_MACOSX/XP_LINUX
192 #endif // MOZ_SANDBOX
195 if (aCanRecordReleaseTelemetry
) {
196 RefPtr
<DllServices
> dllSvc(DllServices::Get());
197 dllSvc
->StartUntrustedModulesProcessor(aIsReadyForBackgroundProcessing
);
199 #endif // defined(XP_WIN)
201 PROFILER_MARKER_UNTYPED(
202 "UtilityProcessChild::RecvInit", IPC
,
203 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
207 mozilla::ipc::IPCResult
UtilityProcessChild::RecvPreferenceUpdate(
209 Preferences::SetPreference(aPref
);
213 mozilla::ipc::IPCResult
UtilityProcessChild::RecvInitProfiler(
214 Endpoint
<PProfilerChild
>&& aEndpoint
) {
215 mProfilerController
= ChildProfilerController::Create(std::move(aEndpoint
));
219 mozilla::ipc::IPCResult
UtilityProcessChild::RecvRequestMemoryReport(
220 const uint32_t& aGeneration
, const bool& aAnonymize
,
221 const bool& aMinimizeMemoryUsage
, const Maybe
<FileDescriptor
>& aDMDFile
,
222 const RequestMemoryReportResolver
& aResolver
) {
223 nsPrintfCString
processName("Utility (pid %" PRIPID
224 ", sandboxingKind %" PRIu64
")",
225 base::GetCurrentProcId(), mSandbox
);
227 mozilla::dom::MemoryReportRequestClient::Start(
228 aGeneration
, aAnonymize
, aMinimizeMemoryUsage
, aDMDFile
, processName
,
229 [&](const MemoryReport
& aReport
) {
230 Unused
<< GetSingleton()->SendAddMemoryReport(aReport
);
236 #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
237 mozilla::ipc::IPCResult
UtilityProcessChild::RecvInitSandboxTesting(
238 Endpoint
<PSandboxTestingChild
>&& aEndpoint
) {
239 if (!SandboxTestingChild::Initialize(std::move(aEndpoint
))) {
241 this, "InitSandboxTesting failed to initialise the child process.");
247 mozilla::ipc::IPCResult
UtilityProcessChild::RecvFlushFOGData(
248 FlushFOGDataResolver
&& aResolver
) {
249 glean::FlushFOGData(std::move(aResolver
));
253 mozilla::ipc::IPCResult
UtilityProcessChild::RecvTestTriggerMetrics(
254 TestTriggerMetricsResolver
&& aResolve
) {
255 mozilla::glean::test_only_ipc::a_counter
.Add(
256 nsIXULRuntime::PROCESS_TYPE_UTILITY
);
261 mozilla::ipc::IPCResult
UtilityProcessChild::RecvTestTelemetryProbes() {
262 const uint32_t kExpectedUintValue
= 42;
263 TelemetryScalar::Set(Telemetry::ScalarID::TELEMETRY_TEST_UTILITY_ONLY_UINT
,
268 mozilla::ipc::IPCResult
269 UtilityProcessChild::RecvStartUtilityAudioDecoderService(
270 Endpoint
<PUtilityAudioDecoderParent
>&& aEndpoint
,
271 nsTArray
<gfx::GfxVarUpdate
>&& aUpdates
) {
272 PROFILER_MARKER_UNTYPED(
273 "UtilityProcessChild::RecvStartUtilityAudioDecoderService", MEDIA
,
274 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
275 mUtilityAudioDecoderInstance
=
276 new UtilityAudioDecoderParent(std::move(aUpdates
));
277 if (!mUtilityAudioDecoderInstance
) {
278 return IPC_FAIL(this, "Failed to create UtilityAudioDecoderParent");
281 mUtilityAudioDecoderInstance
->Start(std::move(aEndpoint
));
285 mozilla::ipc::IPCResult
UtilityProcessChild::RecvStartJSOracleService(
286 Endpoint
<PJSOracleChild
>&& aEndpoint
) {
287 PROFILER_MARKER_UNTYPED(
288 "UtilityProcessChild::RecvStartJSOracleService", JS
,
289 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
290 mJSOracleInstance
= new mozilla::dom::JSOracleChild();
291 if (!mJSOracleInstance
) {
292 return IPC_FAIL(this, "Failed to create JSOracleParent");
295 mJSOracleInstance
->Start(std::move(aEndpoint
));
300 mozilla::ipc::IPCResult
UtilityProcessChild::RecvStartWindowsUtilsService(
301 Endpoint
<dom::PWindowsUtilsChild
>&& aEndpoint
) {
302 PROFILER_MARKER_UNTYPED(
303 "UtilityProcessChild::RecvStartWindowsUtilsService", OTHER
,
304 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
305 mWindowsUtilsInstance
= new dom::WindowsUtilsChild();
306 if (!mWindowsUtilsInstance
) {
307 return IPC_FAIL(this, "Failed to create WindowsUtilsChild");
310 [[maybe_unused
]] bool ok
= std::move(aEndpoint
).Bind(mWindowsUtilsInstance
);
315 mozilla::ipc::IPCResult
UtilityProcessChild::RecvStartWinFileDialogService(
316 Endpoint
<widget::filedialog::PWinFileDialogChild
>&& aEndpoint
) {
317 PROFILER_MARKER_UNTYPED(
318 "UtilityProcessChild::RecvStartWinFileDialogService", OTHER
,
319 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime
)));
321 auto instance
= MakeRefPtr
<widget::filedialog::WinFileDialogChild
>();
323 return IPC_FAIL(this, "Failed to create WinFileDialogChild");
326 bool const ok
= std::move(aEndpoint
).Bind(instance
.get());
328 return IPC_FAIL(this, "Failed to bind created WinFileDialogChild");
334 mozilla::ipc::IPCResult
UtilityProcessChild::RecvGetUntrustedModulesData(
335 GetUntrustedModulesDataResolver
&& aResolver
) {
336 RefPtr
<DllServices
> dllSvc(DllServices::Get());
337 dllSvc
->GetUntrustedModulesData()->Then(
338 GetMainThreadSerialEventTarget(), __func__
,
339 [aResolver
](Maybe
<UntrustedModulesData
>&& aData
) {
340 aResolver(std::move(aData
));
342 [aResolver
](nsresult aReason
) { aResolver(Nothing()); });
346 mozilla::ipc::IPCResult
347 UtilityProcessChild::RecvUnblockUntrustedModulesThread() {
348 if (nsCOMPtr
<nsIObserverService
> obs
=
349 mozilla::services::GetObserverService()) {
350 obs
->NotifyObservers(nullptr, "unblock-untrusted-modules-thread", nullptr);
354 #endif // defined(XP_WIN)
356 void UtilityProcessChild::ActorDestroy(ActorDestroyReason aWhy
) {
357 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
358 DestroySandboxProfiler();
361 if (AbnormalShutdown
== aWhy
) {
362 NS_WARNING("Shutting down Utility process early due to a crash!");
363 ipc::ProcessChild::QuickExit();
366 // Send the last bits of Glean data over to the main process.
368 [](ByteBuf
&& aBuf
) { glean::SendFOGData(std::move(aBuf
)); });
370 #ifndef NS_FREE_PERMANENT_DATA
371 ProcessChild::QuickExit();
374 if (mProfilerController
) {
375 mProfilerController
->Shutdown();
376 mProfilerController
= nullptr;
379 uint32_t timeout
= 0;
380 if (mUtilityAudioDecoderInstance
) {
381 mUtilityAudioDecoderInstance
= nullptr;
385 mJSOracleInstance
= nullptr;
388 mWindowsUtilsInstance
= nullptr;
391 // Wait until all RemoteDecoderManagerParent have closed.
392 // It is still possible some may not have clean up yet, and we might hit
393 // timeout. Our xpcom-shutdown listener should take care of cleaning the
394 // reference of our singleton.
396 // FIXME: Should move from using AsyncBlockers to proper
397 // nsIAsyncShutdownService once it is not JS, see bug 1760855
398 mShutdownBlockers
.WaitUntilClear(timeout
)->Then(
399 GetCurrentSerialEventTarget(), __func__
, [&]() {
402 RefPtr
<DllServices
> dllSvc(DllServices::Get());
403 dllSvc
->DisableFull();
405 # endif // defined(XP_WIN)
407 ipc::CrashReporterClient::DestroySingleton();
408 XRE_ShutdownChildProcess();
410 #endif // NS_FREE_PERMANENT_DATA
413 } // namespace mozilla::ipc