Bug 1826784 - Collect Third-Party Modules informations for Utility processes r=gstoll
[gecko.git] / ipc / glue / UtilityProcessChild.cpp
blobdbed89dd1e69b819bad11627f2a745aca123a3b9
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"
21 #endif
23 #if defined(XP_OPENBSD) && defined(MOZ_SANDBOX)
24 # include "mozilla/SandboxSettings.h"
25 #endif
27 #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
28 # include "mozilla/SandboxTestingChild.h"
29 #endif
31 #include "mozilla/Telemetry.h"
33 #if defined(XP_WIN)
34 # include "mozilla/WinDllServices.h"
35 # include "mozilla/dom/WindowsUtilsChild.h"
36 #endif
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;
63 /* static */
64 RefPtr<UtilityProcessChild> UtilityProcessChild::GetSingleton() {
65 MOZ_ASSERT(XRE_IsUtilityProcess());
66 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownFinal)) {
67 return nullptr;
69 StaticMutexAutoLock lock(sUtilityProcessChildMutex);
70 if (!sUtilityProcessChild) {
71 sUtilityProcessChild = new UtilityProcessChild();
73 return sUtilityProcessChild;
76 /* static */
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()))) {
90 return false;
93 // Now it's safe to start IPC.
94 if (NS_WARN_IF(!aEndpoint.Bind(this))) {
95 return false;
98 // This must be checked before any IPDL message, which may hit sentinel
99 // errors due to parent and content processes having different
100 // versions.
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())) {
112 return false;
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();
121 if (!JS_Init()) {
122 return false;
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);
129 #endif
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
136 SendInitCompleted();
138 RunOnShutdown(
139 [sandboxKind = mSandbox] {
140 StaticMutexAutoLock lock(sUtilityProcessChildMutex);
141 sUtilityProcessChild = nullptr;
142 if (sandboxKind == SandboxingKind::GENERIC_UTILITY) {
143 JS_ShutDown();
146 ShutdownPhase::XPCOMShutdownFinal);
148 return true;
151 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
152 extern "C" {
153 void CGSShutdownServerConnections();
155 #endif
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)
173 int fd = -1;
174 if (aBrokerFd.isSome()) {
175 fd = aBrokerFd.value().ClonePlatformHandle().release();
178 SetUtilitySandbox(fd, mSandbox);
180 # endif // XP_MACOSX/XP_LINUX
181 #endif // MOZ_SANDBOX
183 #if defined(XP_WIN)
184 if (aCanRecordReleaseTelemetry) {
185 RefPtr<DllServices> dllSvc(DllServices::Get());
186 dllSvc->StartUntrustedModulesProcessor(aIsReadyForBackgroundProcessing);
188 #endif // defined(XP_WIN)
189 return IPC_OK();
192 mozilla::ipc::IPCResult UtilityProcessChild::RecvPreferenceUpdate(
193 const Pref& aPref) {
194 Preferences::SetPreference(aPref);
195 return IPC_OK();
198 mozilla::ipc::IPCResult UtilityProcessChild::RecvInitProfiler(
199 Endpoint<PProfilerChild>&& aEndpoint) {
200 mProfilerController = ChildProfilerController::Create(std::move(aEndpoint));
201 return IPC_OK();
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);
217 aResolver);
218 return IPC_OK();
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))) {
225 return IPC_FAIL(
226 this, "InitSandboxTesting failed to initialise the child process.");
228 return IPC_OK();
230 #endif
232 mozilla::ipc::IPCResult UtilityProcessChild::RecvFlushFOGData(
233 FlushFOGDataResolver&& aResolver) {
234 glean::FlushFOGData(std::move(aResolver));
235 return IPC_OK();
238 mozilla::ipc::IPCResult UtilityProcessChild::RecvTestTriggerMetrics(
239 TestTriggerMetricsResolver&& aResolve) {
240 mozilla::glean::test_only_ipc::a_counter.Add(
241 nsIXULRuntime::PROCESS_TYPE_UTILITY);
242 aResolve(true);
243 return IPC_OK();
246 mozilla::ipc::IPCResult UtilityProcessChild::RecvTestTelemetryProbes() {
247 const uint32_t kExpectedUintValue = 42;
248 Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_UTILITY_ONLY_UINT,
249 kExpectedUintValue);
250 return IPC_OK();
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));
262 return IPC_OK();
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));
273 return IPC_OK();
276 #if defined(XP_WIN)
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);
285 MOZ_ASSERT(ok);
286 return IPC_OK();
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()); });
298 return IPC_OK();
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);
307 return IPC_OK();
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.
318 glean::FlushFOGData(
319 [](ByteBuf&& aBuf) { glean::SendFOGData(std::move(aBuf)); });
321 #ifndef NS_FREE_PERMANENT_DATA
322 ProcessChild::QuickExit();
323 #else
325 if (mProfilerController) {
326 mProfilerController->Shutdown();
327 mProfilerController = nullptr;
330 uint32_t timeout = 0;
331 if (mUtilityAudioDecoderInstance) {
332 mUtilityAudioDecoderInstance = nullptr;
333 timeout = 10 * 1000;
336 mJSOracleInstance = nullptr;
338 # ifdef XP_WIN
339 mWindowsUtilsInstance = nullptr;
340 # endif
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__, [&]() {
351 # ifdef XP_WIN
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