Backed out 2 changesets (bug 1943998) for causing wd failures @ phases.py CLOSED...
[gecko.git] / ipc / glue / UtilityProcessChild.cpp
blob4ccff11176722f1f73ca150e2aa3fec8a7817f66
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"
23 #endif
25 #if defined(XP_OPENBSD) && defined(MOZ_SANDBOX)
26 # include "mozilla/SandboxSettings.h"
27 #endif
29 #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
30 # include "mozilla/SandboxTestingChild.h"
31 #endif
33 #include "mozilla/Telemetry.h"
35 #if defined(XP_WIN)
36 # include "mozilla/WinDllServices.h"
37 # include "mozilla/dom/WindowsUtilsChild.h"
38 # include "mozilla/widget/filedialog/WinFileDialogChild.h"
39 #endif
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;
70 /* static */
71 RefPtr<UtilityProcessChild> UtilityProcessChild::GetSingleton() {
72 MOZ_ASSERT(XRE_IsUtilityProcess());
73 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownFinal)) {
74 return nullptr;
76 StaticMutexAutoLock lock(sUtilityProcessChildMutex);
77 if (!sUtilityProcessChild) {
78 sUtilityProcessChild = new UtilityProcessChild();
80 return sUtilityProcessChild;
83 /* static */
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()))) {
97 return false;
100 // Now it's safe to start IPC.
101 if (NS_WARN_IF(!aEndpoint.Bind(this))) {
102 return false;
105 // This must be checked before any IPDL message, which may hit sentinel
106 // errors due to parent and content processes having different
107 // versions.
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())) {
119 return false;
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()) {
128 return false;
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);
135 #endif
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
142 SendInitCompleted();
144 PROFILER_MARKER_UNTYPED(
145 "UtilityProcessChild::SendInitCompleted", IPC,
146 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime)));
148 RunOnShutdown(
149 [sandboxKind = mSandbox] {
150 StaticMutexAutoLock lock(sUtilityProcessChildMutex);
151 sUtilityProcessChild = nullptr;
152 if (sandboxKind == SandboxingKind::GENERIC_UTILITY) {
153 JS_FrontendOnlyShutDown();
156 ShutdownPhase::XPCOMShutdownFinal);
158 return true;
161 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
162 extern "C" {
163 void CGSShutdownServerConnections();
165 #endif
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)
183 int fd = -1;
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
194 #if defined(XP_WIN)
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)));
204 return IPC_OK();
207 mozilla::ipc::IPCResult UtilityProcessChild::RecvPreferenceUpdate(
208 const Pref& aPref) {
209 Preferences::SetPreference(aPref);
210 return IPC_OK();
213 mozilla::ipc::IPCResult UtilityProcessChild::RecvInitProfiler(
214 Endpoint<PProfilerChild>&& aEndpoint) {
215 mProfilerController = ChildProfilerController::Create(std::move(aEndpoint));
216 return IPC_OK();
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);
232 aResolver);
233 return IPC_OK();
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))) {
240 return IPC_FAIL(
241 this, "InitSandboxTesting failed to initialise the child process.");
243 return IPC_OK();
245 #endif
247 mozilla::ipc::IPCResult UtilityProcessChild::RecvFlushFOGData(
248 FlushFOGDataResolver&& aResolver) {
249 glean::FlushFOGData(std::move(aResolver));
250 return IPC_OK();
253 mozilla::ipc::IPCResult UtilityProcessChild::RecvTestTriggerMetrics(
254 TestTriggerMetricsResolver&& aResolve) {
255 mozilla::glean::test_only_ipc::a_counter.Add(
256 nsIXULRuntime::PROCESS_TYPE_UTILITY);
257 aResolve(true);
258 return IPC_OK();
261 mozilla::ipc::IPCResult UtilityProcessChild::RecvTestTelemetryProbes() {
262 const uint32_t kExpectedUintValue = 42;
263 TelemetryScalar::Set(Telemetry::ScalarID::TELEMETRY_TEST_UTILITY_ONLY_UINT,
264 kExpectedUintValue);
265 return IPC_OK();
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));
282 return IPC_OK();
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));
296 return IPC_OK();
299 #if defined(XP_WIN)
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);
311 MOZ_ASSERT(ok);
312 return IPC_OK();
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>();
322 if (!instance) {
323 return IPC_FAIL(this, "Failed to create WinFileDialogChild");
326 bool const ok = std::move(aEndpoint).Bind(instance.get());
327 if (!ok) {
328 return IPC_FAIL(this, "Failed to bind created WinFileDialogChild");
331 return IPC_OK();
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()); });
343 return IPC_OK();
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);
352 return IPC_OK();
354 #endif // defined(XP_WIN)
356 void UtilityProcessChild::ActorDestroy(ActorDestroyReason aWhy) {
357 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
358 DestroySandboxProfiler();
359 #endif
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.
367 glean::FlushFOGData(
368 [](ByteBuf&& aBuf) { glean::SendFOGData(std::move(aBuf)); });
370 #ifndef NS_FREE_PERMANENT_DATA
371 ProcessChild::QuickExit();
372 #else
374 if (mProfilerController) {
375 mProfilerController->Shutdown();
376 mProfilerController = nullptr;
379 uint32_t timeout = 0;
380 if (mUtilityAudioDecoderInstance) {
381 mUtilityAudioDecoderInstance = nullptr;
382 timeout = 10 * 1000;
385 mJSOracleInstance = nullptr;
387 # ifdef XP_WIN
388 mWindowsUtilsInstance = nullptr;
389 # endif
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__, [&]() {
400 # ifdef XP_WIN
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