Bug 1883861 - Part 2: Remove unnecessary SSE2 check for x86 memory barrier. r=jandem
[gecko.git] / dom / ipc / ContentChild.cpp
blobdcecae0eb6d3d98db6cfe5c52a2fa18f0255432f
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=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/. */
7 #ifdef MOZ_WIDGET_ANDROID
8 # include "AndroidDecoderModule.h"
9 #endif
11 #include "BrowserChild.h"
12 #include "nsNSSComponent.h"
13 #include "ContentChild.h"
14 #include "GeckoProfiler.h"
15 #include "HandlerServiceChild.h"
16 #include "nsXPLookAndFeel.h"
17 #include "mozilla/AppShutdown.h"
18 #include "mozilla/Attributes.h"
19 #include "mozilla/BackgroundHangMonitor.h"
20 #include "mozilla/BenchmarkStorageChild.h"
21 #include "mozilla/FOGIPC.h"
22 #include "GMPServiceChild.h"
23 #include "Geolocation.h"
24 #include "imgLoader.h"
25 #include "ScrollingMetrics.h"
26 #include "mozilla/BasePrincipal.h"
27 #include "mozilla/ClipboardReadRequestChild.h"
28 #include "mozilla/Components.h"
29 #include "mozilla/HangDetails.h"
30 #include "mozilla/LoadInfo.h"
31 #include "mozilla/Logging.h"
32 #include "mozilla/LookAndFeel.h"
33 #include "mozilla/MemoryTelemetry.h"
34 #include "mozilla/NullPrincipal.h"
35 #include "mozilla/PerfStats.h"
36 #include "mozilla/Preferences.h"
37 #include "mozilla/ProcessHangMonitorIPC.h"
38 #include "mozilla/RemoteDecoderManagerChild.h"
39 #include "mozilla/RemoteLazyInputStreamChild.h"
40 #include "mozilla/SchedulerGroup.h"
41 #include "mozilla/ScopeExit.h"
42 #include "mozilla/SharedStyleSheetCache.h"
43 #include "mozilla/SimpleEnumerator.h"
44 #include "mozilla/SpinEventLoopUntil.h"
45 #include "mozilla/StaticPrefs_browser.h"
46 #include "mozilla/StaticPrefs_dom.h"
47 #include "mozilla/StaticPrefs_fission.h"
48 #include "mozilla/StaticPrefs_javascript.h"
49 #include "mozilla/StaticPrefs_media.h"
50 #include "mozilla/StaticPrefs_threads.h"
51 #include "mozilla/StorageAccessAPIHelper.h"
52 #include "mozilla/TelemetryIPC.h"
53 #include "mozilla/Unused.h"
54 #include "mozilla/WebBrowserPersistDocumentChild.h"
55 #include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h"
56 #include "mozilla/dom/AutoSuppressEventHandlingAndSuspend.h"
57 #include "mozilla/dom/BlobImpl.h"
58 #include "mozilla/dom/BrowserBridgeHost.h"
59 #include "mozilla/dom/BrowsingContext.h"
60 #include "mozilla/dom/BrowsingContextGroup.h"
61 #include "mozilla/dom/ChildProcessChannelListener.h"
62 #include "mozilla/dom/ChildProcessMessageManager.h"
63 #include "mozilla/dom/ClientManager.h"
64 #include "mozilla/dom/ContentParent.h"
65 #include "mozilla/dom/ContentProcessManager.h"
66 #include "mozilla/dom/ContentPlaybackController.h"
67 #include "mozilla/dom/ContentProcessMessageManager.h"
68 #include "mozilla/dom/DataTransfer.h"
69 #include "mozilla/dom/DocGroup.h"
70 #include "mozilla/dom/ExternalHelperAppChild.h"
71 #include "mozilla/dom/GetFilesHelper.h"
72 #include "mozilla/dom/IPCBlobUtils.h"
73 #include "mozilla/dom/InProcessChild.h"
74 #include "mozilla/dom/JSActorService.h"
75 #include "mozilla/dom/JSProcessActorBinding.h"
76 #include "mozilla/dom/JSProcessActorChild.h"
77 #include "mozilla/dom/LSObject.h"
78 #include "mozilla/dom/MemoryReportRequest.h"
79 #include "mozilla/dom/PSessionStorageObserverChild.h"
80 #include "mozilla/dom/PostMessageEvent.h"
81 #include "mozilla/dom/PushNotifier.h"
82 #include "mozilla/dom/RemoteWorkerService.h"
83 #include "mozilla/dom/ScreenOrientation.h"
84 #include "mozilla/dom/ServiceWorkerManager.h"
85 #include "mozilla/dom/SessionStorageManager.h"
86 #include "mozilla/dom/URLClassifierChild.h"
87 #include "mozilla/dom/UserActivation.h"
88 #include "mozilla/dom/WindowGlobalChild.h"
89 #include "mozilla/dom/WorkerDebugger.h"
90 #include "mozilla/dom/WorkerDebuggerManager.h"
91 #include "mozilla/dom/ipc/SharedMap.h"
92 #include "mozilla/extensions/ExtensionsChild.h"
93 #include "mozilla/extensions/StreamFilterParent.h"
94 #include "mozilla/gfx/Logging.h"
95 #include "mozilla/gfx/gfxVars.h"
96 #include "mozilla/hal_sandbox/PHalChild.h"
97 #include "mozilla/intl/L10nRegistry.h"
98 #include "mozilla/intl/LocaleService.h"
99 #include "mozilla/ipc/BackgroundChild.h"
100 #include "mozilla/ipc/Endpoint.h"
101 #include "mozilla/ipc/FileDescriptorUtils.h"
102 #include "mozilla/ipc/GeckoChildProcessHost.h"
103 #include "mozilla/ipc/ProcessChild.h"
104 #include "mozilla/ipc/TestShellChild.h"
105 #include "mozilla/layers/APZChild.h"
106 #include "mozilla/layers/CompositorManagerChild.h"
107 #include "mozilla/layers/ContentProcessController.h"
108 #include "mozilla/layers/ImageBridgeChild.h"
109 #ifdef NS_PRINTING
110 # include "mozilla/layout/RemotePrintJobChild.h"
111 #endif
112 #include "mozilla/loader/ScriptCacheActors.h"
113 #include "mozilla/media/MediaChild.h"
114 #include "mozilla/net/CaptivePortalService.h"
115 #include "mozilla/net/ChildDNSService.h"
116 #include "mozilla/net/CookieServiceChild.h"
117 #include "mozilla/net/DocumentChannelChild.h"
118 #include "mozilla/net/HttpChannelChild.h"
119 #include "mozilla/widget/RemoteLookAndFeel.h"
120 #include "mozilla/widget/ScreenManager.h"
121 #include "mozilla/widget/WidgetMessageUtils.h"
122 #include "nsBaseDragService.h"
123 #include "nsDocShellLoadTypes.h"
124 #include "nsFocusManager.h"
125 #include "nsHttpHandler.h"
126 #include "nsIConsoleService.h"
127 #include "nsIInputStreamChannel.h"
128 #include "nsILayoutHistoryState.h"
129 #include "nsILoadGroup.h"
130 #include "nsIOpenWindowInfo.h"
131 #include "nsISimpleEnumerator.h"
132 #include "nsIStringBundle.h"
133 #include "nsIURIMutator.h"
134 #include "nsQueryObject.h"
135 #include "nsRefreshDriver.h"
136 #include "nsSandboxFlags.h"
137 #include "mozmemory.h"
139 #include "ChildProfilerController.h"
141 #if defined(MOZ_SANDBOX)
142 # include "mozilla/SandboxSettings.h"
143 # if defined(XP_WIN)
144 # include "mozilla/sandboxTarget.h"
145 # elif defined(XP_LINUX)
146 # include "CubebUtils.h"
147 # include "mozilla/Sandbox.h"
148 # include "mozilla/SandboxInfo.h"
149 # elif defined(XP_MACOSX)
150 # include <CoreGraphics/CGError.h>
151 # include "mozilla/Sandbox.h"
152 # elif defined(__OpenBSD__)
153 # include <err.h>
154 # include <sys/stat.h>
155 # include <unistd.h>
157 # include <fstream>
159 # include "BinaryPath.h"
160 # include "SpecialSystemDirectory.h"
161 # include "nsILineInputStream.h"
162 # include "mozilla/ipc/UtilityProcessSandboxing.h"
163 # endif
164 # if defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
165 # include "mozilla/SandboxTestingChild.h"
166 # endif
167 #endif
169 #include "SandboxHal.h"
170 #include "mozInlineSpellChecker.h"
171 #include "mozilla/GlobalStyleSheetCache.h"
172 #include "nsAnonymousTemporaryFile.h"
173 #include "nsCategoryManagerUtils.h"
174 #include "nsClipboardProxy.h"
175 #include "nsContentPermissionHelper.h"
176 #include "nsDebugImpl.h"
177 #include "nsDirectoryService.h"
178 #include "nsDirectoryServiceDefs.h"
179 #include "nsDirectoryServiceUtils.h"
180 #include "nsDocShell.h"
181 #include "nsDocShellLoadState.h"
182 #include "nsHashPropertyBag.h"
183 #include "nsIConsoleListener.h"
184 #include "nsICycleCollectorListener.h"
185 #include "nsIDocShellTreeOwner.h"
186 #include "nsIDocumentViewer.h"
187 #include "nsIDragService.h"
188 #include "nsIInterfaceRequestorUtils.h"
189 #include "nsIMemoryInfoDumper.h"
190 #include "nsIMemoryReporter.h"
191 #include "nsIObserverService.h"
192 #include "nsIOService.h"
193 #include "nsIScriptError.h"
194 #include "nsIScriptSecurityManager.h"
195 #include "nsJSEnvironment.h"
196 #include "nsJSUtils.h"
197 #include "nsMemoryInfoDumper.h"
198 #include "nsServiceManagerUtils.h"
199 #include "nsStyleSheetService.h"
200 #include "nsThreadManager.h"
201 #include "nsVariant.h"
202 #include "nsXULAppAPI.h"
203 #include "IHistory.h"
204 #include "ReferrerInfo.h"
205 #include "base/message_loop.h"
206 #include "base/process_util.h"
207 #include "base/task.h"
208 #include "mozilla/dom/BlobURLProtocolHandler.h"
209 #include "mozilla/dom/PCycleCollectWithLogsChild.h"
210 #include "mozilla/dom/PerformanceStorage.h"
211 #include "nsChromeRegistryContent.h"
212 #include "nsFrameMessageManager.h"
213 #include "nsNetUtil.h"
214 #include "nsWindowMemoryReporter.h"
216 #ifdef MOZ_WEBRTC
217 # include "jsapi/WebrtcGlobalChild.h"
218 #endif
220 #include "PermissionMessageUtils.h"
221 #include "mozilla/Permission.h"
222 #include "mozilla/PermissionManager.h"
224 #if defined(MOZ_WIDGET_ANDROID)
225 # include "APKOpen.h"
226 # include <sched.h>
227 #endif
229 #ifdef XP_WIN
230 # include <process.h>
231 # define getpid _getpid
232 # include "mozilla/WinDllServices.h"
233 #endif
235 #if defined(XP_MACOSX)
236 # include "nsMacUtilsImpl.h"
237 # include <sys/qos.h>
238 #endif /* XP_MACOSX */
240 #ifdef MOZ_X11
241 # include "mozilla/X11Util.h"
242 #endif
244 #ifdef ACCESSIBILITY
245 # include "nsAccessibilityService.h"
246 # ifdef XP_WIN
247 # include "mozilla/a11y/AccessibleWrap.h"
248 # endif
249 # include "mozilla/a11y/DocAccessible.h"
250 # include "mozilla/a11y/DocManager.h"
251 # include "mozilla/a11y/OuterDocAccessible.h"
252 #endif
254 #include "mozilla/dom/File.h"
255 #include "mozilla/dom/MediaControllerBinding.h"
257 #ifdef MOZ_WEBSPEECH
258 # include "mozilla/dom/PSpeechSynthesisChild.h"
259 #endif
261 #include "ClearOnShutdown.h"
262 #include "DomainPolicy.h"
263 #include "GfxInfoBase.h"
264 #include "MMPrinter.h"
265 #include "mozilla/ipc/ProcessUtils.h"
266 #include "mozilla/ipc/URIUtils.h"
267 #include "VRManagerChild.h"
268 #include "gfxPlatform.h"
269 #include "gfxPlatformFontList.h"
270 #include "mozilla/RemoteSpellCheckEngineChild.h"
271 #include "mozilla/dom/TabContext.h"
272 #include "mozilla/dom/ipc/StructuredCloneData.h"
273 #include "mozilla/ipc/CrashReporterClient.h"
274 #include "mozilla/net/NeckoMessageUtils.h"
275 #include "mozilla/widget/PuppetBidiKeyboard.h"
276 #include "nsContentUtils.h"
277 #include "nsIPrincipal.h"
278 #include "nsString.h"
279 #include "nscore.h" // for NS_FREE_PERMANENT_DATA
280 #include "private/pprio.h"
282 #ifdef MOZ_WIDGET_GTK
283 # include "mozilla/WidgetUtilsGtk.h"
284 # include "nsAppRunner.h"
285 # include <gtk/gtk.h>
286 #endif
288 #ifdef MOZ_CODE_COVERAGE
289 # include "mozilla/CodeCoverageHandler.h"
290 #endif
292 extern mozilla::LazyLogModule gSHIPBFCacheLog;
294 using namespace mozilla;
295 using namespace mozilla::dom::ipc;
296 using namespace mozilla::media;
297 using namespace mozilla::embedding;
298 using namespace mozilla::gmp;
299 using namespace mozilla::hal_sandbox;
300 using namespace mozilla::ipc;
301 using namespace mozilla::intl;
302 using namespace mozilla::layers;
303 using namespace mozilla::layout;
304 using namespace mozilla::net;
305 using namespace mozilla::widget;
306 using mozilla::loader::PScriptCacheChild;
308 namespace geckoprofiler::markers {
309 struct ProcessPriorityChange {
310 static constexpr Span<const char> MarkerTypeName() {
311 return MakeStringSpan("ProcessPriorityChange");
313 static void StreamJSONMarkerData(baseprofiler::SpliceableJSONWriter& aWriter,
314 const ProfilerString8View& aPreviousPriority,
315 const ProfilerString8View& aNewPriority) {
316 aWriter.StringProperty("Before", aPreviousPriority);
317 aWriter.StringProperty("After", aNewPriority);
319 static MarkerSchema MarkerTypeDisplay() {
320 using MS = MarkerSchema;
321 MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
322 schema.AddKeyFormat("Before", MS::Format::String);
323 schema.AddKeyFormat("After", MS::Format::String);
324 schema.AddStaticLabelValue("Note",
325 "This is a notification of the priority change "
326 "that was done by the parent process");
327 schema.SetAllLabels(
328 "priority: {marker.data.Before} -> {marker.data.After}");
329 return schema;
333 struct ProcessPriority {
334 static constexpr Span<const char> MarkerTypeName() {
335 return MakeStringSpan("ProcessPriority");
337 static void StreamJSONMarkerData(baseprofiler::SpliceableJSONWriter& aWriter,
338 const ProfilerString8View& aPriority,
339 const ProfilingState& aProfilingState) {
340 aWriter.StringProperty("Priority", aPriority);
341 aWriter.StringProperty("Marker cause",
342 ProfilerString8View::WrapNullTerminatedString(
343 ProfilingStateToString(aProfilingState)));
345 static MarkerSchema MarkerTypeDisplay() {
346 using MS = MarkerSchema;
347 MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
348 schema.AddKeyFormat("Priority", MS::Format::String);
349 schema.AddKeyFormat("Marker cause", MS::Format::String);
350 schema.SetAllLabels("priority: {marker.data.Priority}");
351 return schema;
354 } // namespace geckoprofiler::markers
356 namespace mozilla {
357 namespace dom {
359 // IPC sender for remote GC/CC logging.
360 class CycleCollectWithLogsChild final : public PCycleCollectWithLogsChild {
361 public:
362 NS_INLINE_DECL_REFCOUNTING(CycleCollectWithLogsChild)
364 class Sink final : public nsICycleCollectorLogSink {
365 NS_DECL_ISUPPORTS
367 Sink(CycleCollectWithLogsChild* aActor, const FileDescriptor& aGCLog,
368 const FileDescriptor& aCCLog) {
369 mActor = aActor;
370 mGCLog = FileDescriptorToFILE(aGCLog, "w");
371 mCCLog = FileDescriptorToFILE(aCCLog, "w");
374 NS_IMETHOD Open(FILE** aGCLog, FILE** aCCLog) override {
375 if (NS_WARN_IF(!mGCLog) || NS_WARN_IF(!mCCLog)) {
376 return NS_ERROR_FAILURE;
378 *aGCLog = mGCLog;
379 *aCCLog = mCCLog;
380 return NS_OK;
383 NS_IMETHOD CloseGCLog() override {
384 MOZ_ASSERT(mGCLog);
385 fclose(mGCLog);
386 mGCLog = nullptr;
387 mActor->SendCloseGCLog();
388 return NS_OK;
391 NS_IMETHOD CloseCCLog() override {
392 MOZ_ASSERT(mCCLog);
393 fclose(mCCLog);
394 mCCLog = nullptr;
395 mActor->SendCloseCCLog();
396 return NS_OK;
399 NS_IMETHOD GetFilenameIdentifier(nsAString& aIdentifier) override {
400 return UnimplementedProperty();
403 NS_IMETHOD SetFilenameIdentifier(const nsAString& aIdentifier) override {
404 return UnimplementedProperty();
407 NS_IMETHOD GetProcessIdentifier(int32_t* aIdentifier) override {
408 return UnimplementedProperty();
411 NS_IMETHOD SetProcessIdentifier(int32_t aIdentifier) override {
412 return UnimplementedProperty();
415 NS_IMETHOD GetGcLog(nsIFile** aPath) override {
416 return UnimplementedProperty();
419 NS_IMETHOD GetCcLog(nsIFile** aPath) override {
420 return UnimplementedProperty();
423 private:
424 ~Sink() {
425 if (mGCLog) {
426 fclose(mGCLog);
427 mGCLog = nullptr;
429 if (mCCLog) {
430 fclose(mCCLog);
431 mCCLog = nullptr;
433 // The XPCOM refcount drives the IPC lifecycle;
434 Unused << mActor->Send__delete__(mActor);
437 nsresult UnimplementedProperty() {
438 MOZ_ASSERT(false,
439 "This object is a remote GC/CC logger;"
440 " this property isn't meaningful.");
441 return NS_ERROR_UNEXPECTED;
444 RefPtr<CycleCollectWithLogsChild> mActor;
445 FILE* mGCLog;
446 FILE* mCCLog;
449 private:
450 ~CycleCollectWithLogsChild() = default;
453 NS_IMPL_ISUPPORTS(CycleCollectWithLogsChild::Sink, nsICycleCollectorLogSink);
455 class AlertObserver {
456 public:
457 AlertObserver(nsIObserver* aObserver, const nsString& aData)
458 : mObserver(aObserver), mData(aData) {}
460 ~AlertObserver() = default;
462 nsCOMPtr<nsIObserver> mObserver;
463 nsString mData;
466 class ConsoleListener final : public nsIConsoleListener {
467 public:
468 explicit ConsoleListener(ContentChild* aChild) : mChild(aChild) {}
470 NS_DECL_ISUPPORTS
471 NS_DECL_NSICONSOLELISTENER
473 private:
474 ~ConsoleListener() = default;
476 ContentChild* mChild;
477 friend class ContentChild;
480 NS_IMPL_ISUPPORTS(ConsoleListener, nsIConsoleListener)
482 // Before we send the error to the parent process (which
483 // involves copying the memory), truncate any long lines. CSS
484 // errors in particular share the memory for long lines with
485 // repeated errors, but the IPC communication we're about to do
486 // will break that sharing, so we better truncate now.
487 static void TruncateString(nsAString& aString) {
488 if (aString.Length() > 1000) {
489 aString.Truncate(1000);
493 NS_IMETHODIMP
494 ConsoleListener::Observe(nsIConsoleMessage* aMessage) {
495 if (!mChild) {
496 return NS_OK;
499 nsCOMPtr<nsIScriptError> scriptError = do_QueryInterface(aMessage);
500 if (scriptError) {
501 nsAutoString msg, sourceName, sourceLine;
502 nsCString category;
503 uint32_t lineNum, colNum, flags;
504 bool fromPrivateWindow, fromChromeContext;
506 nsresult rv = scriptError->GetErrorMessage(msg);
507 NS_ENSURE_SUCCESS(rv, rv);
508 TruncateString(msg);
509 rv = scriptError->GetSourceName(sourceName);
510 NS_ENSURE_SUCCESS(rv, rv);
511 TruncateString(sourceName);
512 rv = scriptError->GetSourceLine(sourceLine);
513 NS_ENSURE_SUCCESS(rv, rv);
514 TruncateString(sourceLine);
516 rv = scriptError->GetCategory(getter_Copies(category));
517 NS_ENSURE_SUCCESS(rv, rv);
518 rv = scriptError->GetLineNumber(&lineNum);
519 NS_ENSURE_SUCCESS(rv, rv);
520 rv = scriptError->GetColumnNumber(&colNum);
521 NS_ENSURE_SUCCESS(rv, rv);
522 rv = scriptError->GetFlags(&flags);
523 NS_ENSURE_SUCCESS(rv, rv);
524 rv = scriptError->GetIsFromPrivateWindow(&fromPrivateWindow);
525 NS_ENSURE_SUCCESS(rv, rv);
526 rv = scriptError->GetIsFromChromeContext(&fromChromeContext);
527 NS_ENSURE_SUCCESS(rv, rv);
530 AutoJSAPI jsapi;
531 jsapi.Init();
532 JSContext* cx = jsapi.cx();
534 JS::Rooted<JS::Value> stack(cx);
535 rv = scriptError->GetStack(&stack);
536 NS_ENSURE_SUCCESS(rv, rv);
538 if (stack.isObject()) {
539 // Because |stack| might be a cross-compartment wrapper, we can't use it
540 // with JSAutoRealm. Use the stackGlobal for that.
541 JS::Rooted<JS::Value> stackGlobal(cx);
542 rv = scriptError->GetStackGlobal(&stackGlobal);
543 NS_ENSURE_SUCCESS(rv, rv);
545 JSAutoRealm ar(cx, &stackGlobal.toObject());
547 StructuredCloneData data;
548 ErrorResult err;
549 data.Write(cx, stack, err);
550 if (err.Failed()) {
551 return err.StealNSResult();
554 ClonedMessageData cloned;
555 if (!data.BuildClonedMessageData(cloned)) {
556 return NS_ERROR_FAILURE;
559 mChild->SendScriptErrorWithStack(
560 msg, sourceName, sourceLine, lineNum, colNum, flags, category,
561 fromPrivateWindow, fromChromeContext, cloned);
562 return NS_OK;
566 mChild->SendScriptError(msg, sourceName, sourceLine, lineNum, colNum, flags,
567 category, fromPrivateWindow, 0, fromChromeContext);
568 return NS_OK;
571 nsString msg;
572 nsresult rv = aMessage->GetMessageMoz(msg);
573 NS_ENSURE_SUCCESS(rv, rv);
574 mChild->SendConsoleMessage(msg);
575 return NS_OK;
578 #ifdef NIGHTLY_BUILD
580 * The singleton of this class is registered with the BackgroundHangMonitor as
581 * an annotator, so that the hang monitor can record whether or not there were
582 * pending input events when the thread hung.
584 class PendingInputEventHangAnnotator final : public BackgroundHangAnnotator {
585 public:
586 virtual void AnnotateHang(BackgroundHangAnnotations& aAnnotations) override {
587 int32_t pending = ContentChild::GetSingleton()->GetPendingInputEvents();
588 if (pending > 0) {
589 aAnnotations.AddAnnotation(u"PendingInput"_ns, pending);
593 static PendingInputEventHangAnnotator sSingleton;
595 PendingInputEventHangAnnotator PendingInputEventHangAnnotator::sSingleton;
596 #endif
598 class ContentChild::ShutdownCanary final {};
600 ContentChild* ContentChild::sSingleton;
601 StaticAutoPtr<ContentChild::ShutdownCanary> ContentChild::sShutdownCanary;
603 ContentChild::ContentChild()
604 : mID(uint64_t(-1)),
605 mIsForBrowser(false),
606 mIsAlive(true),
607 mShuttingDown(false) {
608 // This process is a content process, so it's clearly running in
609 // multiprocess mode!
610 nsDebugImpl::SetMultiprocessMode("Child");
612 // Our static analysis doesn't allow capturing ref-counted pointers in
613 // lambdas, so we need to hide it in a uintptr_t. This is safe because this
614 // lambda will be destroyed in ~ContentChild().
615 uintptr_t self = reinterpret_cast<uintptr_t>(this);
616 profiler_add_state_change_callback(
617 AllProfilingStates(),
618 [self](ProfilingState aProfilingState) {
619 const ContentChild* selfPtr =
620 reinterpret_cast<const ContentChild*>(self);
621 PROFILER_MARKER("Process Priority", OTHER,
622 mozilla::MarkerThreadId::MainThread(), ProcessPriority,
623 ProfilerString8View::WrapNullTerminatedString(
624 ProcessPriorityToString(selfPtr->mProcessPriority)),
625 aProfilingState);
627 self);
629 // When ContentChild is created, the observer service does not even exist.
630 // When ContentChild::RecvSetXPCOMProcessAttributes is called (the first
631 // IPDL call made on this object), shutdown may have already happened. Thus
632 // we create a canary here that relies upon getting cleared if shutdown
633 // happens without requiring the observer service at this time.
634 if (!sShutdownCanary) {
635 sShutdownCanary = new ShutdownCanary();
636 ClearOnShutdown(&sShutdownCanary, ShutdownPhase::XPCOMShutdown);
640 #ifdef _MSC_VER
641 # pragma warning(push)
642 # pragma warning( \
643 disable : 4722) /* Silence "destructor never returns" warning \
645 #endif
647 ContentChild::~ContentChild() {
648 profiler_remove_state_change_callback(reinterpret_cast<uintptr_t>(this));
650 #ifndef NS_FREE_PERMANENT_DATA
651 MOZ_CRASH("Content Child shouldn't be destroyed.");
652 #endif
655 #ifdef _MSC_VER
656 # pragma warning(pop)
657 #endif
659 NS_INTERFACE_MAP_BEGIN(ContentChild)
660 NS_INTERFACE_MAP_ENTRY(nsIDOMProcessChild)
661 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMProcessChild)
662 NS_INTERFACE_MAP_END
664 mozilla::ipc::IPCResult ContentChild::RecvSetXPCOMProcessAttributes(
665 XPCOMInitData&& aXPCOMInit, const StructuredCloneData& aInitialData,
666 FullLookAndFeel&& aLookAndFeelData, dom::SystemFontList&& aFontList,
667 Maybe<SharedMemoryHandle>&& aSharedUASheetHandle,
668 const uintptr_t& aSharedUASheetAddress,
669 nsTArray<SharedMemoryHandle>&& aSharedFontListBlocks,
670 const bool& aIsReadyForBackgroundProcessing) {
671 if (!sShutdownCanary) {
672 return IPC_OK();
675 mLookAndFeelData = std::move(aLookAndFeelData);
676 mFontList = std::move(aFontList);
677 mSharedFontListBlocks = std::move(aSharedFontListBlocks);
679 gfx::gfxVars::SetValuesForInitialize(aXPCOMInit.gfxNonDefaultVarUpdates());
680 PerfStats::SetCollectionMask(aXPCOMInit.perfStatsMask());
681 InitSharedUASheets(std::move(aSharedUASheetHandle), aSharedUASheetAddress);
682 InitXPCOM(std::move(aXPCOMInit), aInitialData,
683 aIsReadyForBackgroundProcessing);
684 InitGraphicsDeviceData(aXPCOMInit.contentDeviceData());
685 RefPtr<net::ChildDNSService> dnsServiceChild =
686 dont_AddRef(net::ChildDNSService::GetSingleton());
687 if (dnsServiceChild) {
688 dnsServiceChild->SetTRRDomain(aXPCOMInit.trrDomain());
689 dnsServiceChild->SetTRRModeInChild(aXPCOMInit.trrMode(),
690 aXPCOMInit.trrModeFromPref());
692 return IPC_OK();
695 class nsGtkNativeInitRunnable : public Runnable {
696 public:
697 nsGtkNativeInitRunnable() : Runnable("nsGtkNativeInitRunnable") {}
699 NS_IMETHOD Run() override {
700 LookAndFeel::NativeInit();
701 return NS_OK;
705 void ContentChild::Init(mozilla::ipc::UntypedEndpoint&& aEndpoint,
706 const char* aParentBuildID, uint64_t aChildID,
707 bool aIsForBrowser) {
708 #ifdef MOZ_WIDGET_GTK
709 // When running X11 only build we need to pass a display down
710 // to gtk_init because it's not going to use the one from the environment
711 // on its own when deciding which backend to use, and when starting under
712 // XWayland, it may choose to start with the wayland backend
713 // instead of the x11 backend.
714 // The DISPLAY environment variable is normally set by the parent process.
715 // The MOZ_GDK_DISPLAY environment variable is set from nsAppRunner.cpp
716 // when --display is set by the command line.
717 if (!gfxPlatform::IsHeadless()) {
718 const char* display_name = PR_GetEnv("MOZ_GDK_DISPLAY");
719 if (!display_name) {
720 bool waylandEnabled = false;
721 # ifdef MOZ_WAYLAND
722 waylandEnabled = IsWaylandEnabled();
723 # endif
724 if (!waylandEnabled) {
725 display_name = PR_GetEnv("DISPLAY");
728 if (display_name) {
729 int argc = 3;
730 char option_name[] = "--display";
731 char* argv[] = {
732 // argv0 is unused because g_set_prgname() was called in
733 // XRE_InitChildProcess().
734 nullptr, option_name, const_cast<char*>(display_name), nullptr};
735 char** argvp = argv;
736 gtk_init(&argc, &argvp);
737 } else {
738 gtk_init(nullptr, nullptr);
741 #endif
743 #ifdef MOZ_X11
744 if (!gfxPlatform::IsHeadless()) {
745 // Do this after initializing GDK, or GDK will install its own handler.
746 XRE_InstallX11ErrorHandler();
748 #endif
750 MOZ_ASSERT(!sSingleton, "only one ContentChild per child");
752 // Once we start sending IPC messages, we need the thread manager to be
753 // initialized so we can deal with the responses. Do that here before we
754 // try to construct the crash reporter.
755 nsresult rv = nsThreadManager::get().Init();
756 if (NS_WARN_IF(NS_FAILED(rv))) {
757 MOZ_CRASH("Failed to initialize the thread manager in ContentChild::Init");
760 if (!aEndpoint.Bind(this)) {
761 MOZ_CRASH("Bind failed in ContentChild::Init");
763 sSingleton = this;
765 // If communications with the parent have broken down, take the process
766 // down so it's not hanging around.
767 GetIPCChannel()->SetAbortOnError(true);
769 // This must be checked before any IPDL message, which may hit sentinel
770 // errors due to parent and content processes having different
771 // versions.
772 MessageChannel* channel = GetIPCChannel();
773 if (channel && !channel->SendBuildIDsMatchMessage(aParentBuildID)) {
774 // We need to quit this process if the buildID doesn't match the parent's.
775 // This can occur when an update occurred in the background.
776 ProcessChild::QuickExit();
779 #if defined(__OpenBSD__) && defined(MOZ_SANDBOX)
780 StartOpenBSDSandbox(GeckoProcessType_Content);
781 #endif
783 #ifdef MOZ_X11
784 # ifdef MOZ_WIDGET_GTK
785 if (GdkIsX11Display() && !gfxPlatform::IsHeadless()) {
786 // Send the parent our X socket to act as a proxy reference for our X
787 // resources.
788 int xSocketFd = ConnectionNumber(DefaultXDisplay());
789 SendBackUpXResources(FileDescriptor(xSocketFd));
791 # endif
792 #endif
794 CrashReporterClient::InitSingleton(this);
796 mID = aChildID;
797 mIsForBrowser = aIsForBrowser;
799 SetProcessName("Web Content"_ns);
801 #ifdef NIGHTLY_BUILD
802 // NOTE: We have to register the annotator on the main thread, as annotators
803 // only affect a single thread.
804 SchedulerGroup::Dispatch(
805 NS_NewRunnableFunction("RegisterPendingInputEventHangAnnotator", [] {
806 BackgroundHangMonitor::RegisterAnnotator(
807 PendingInputEventHangAnnotator::sSingleton);
808 }));
809 #endif
812 void ContentChild::AddProfileToProcessName(const nsACString& aProfile) {
813 nsCOMPtr<nsIPrincipal> isolationPrincipal =
814 ContentParent::CreateRemoteTypeIsolationPrincipal(mRemoteType);
815 if (isolationPrincipal) {
816 // DEFAULT_PRIVATE_BROWSING_ID is the value when it's not private
817 if (isolationPrincipal->OriginAttributesRef().mPrivateBrowsingId !=
818 nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID) {
819 return;
823 mProcessName = aProfile + ":"_ns + mProcessName; //<profile_name>:example.com
826 void ContentChild::SetProcessName(const nsACString& aName,
827 const nsACString* aSite,
828 const nsACString* aCurrentProfile) {
829 char* name;
830 if ((name = PR_GetEnv("MOZ_DEBUG_APP_PROCESS")) && aName.EqualsASCII(name)) {
831 #ifdef XP_UNIX
832 printf_stderr("\n\nCHILDCHILDCHILDCHILD\n [%s] debug me @%d\n\n", name,
833 getpid());
834 sleep(30);
835 #elif defined(XP_WIN)
836 // Windows has a decent JIT debugging story, so NS_DebugBreak does the
837 // right thing.
838 NS_DebugBreak(NS_DEBUG_BREAK,
839 "Invoking NS_DebugBreak() to debug child process", nullptr,
840 __FILE__, __LINE__);
841 #endif
844 if (aSite) {
845 profiler_set_process_name(aName, aSite);
846 } else {
847 profiler_set_process_name(aName);
850 mProcessName = aName;
852 // Requires pref flip
853 if (aSite && StaticPrefs::fission_processSiteNames()) {
854 nsCOMPtr<nsIPrincipal> isolationPrincipal =
855 ContentParent::CreateRemoteTypeIsolationPrincipal(mRemoteType);
856 if (isolationPrincipal) {
857 // DEFAULT_PRIVATE_BROWSING_ID is the value when it's not private
858 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
859 ("private = %d, pref = %d",
860 isolationPrincipal->OriginAttributesRef().mPrivateBrowsingId !=
861 nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID,
862 StaticPrefs::fission_processPrivateWindowSiteNames()));
863 if (isolationPrincipal->OriginAttributesRef().mPrivateBrowsingId ==
864 nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID
865 #ifdef NIGHTLY_BUILD
866 // Nightly can show site names for private windows, with a second pref
867 || StaticPrefs::fission_processPrivateWindowSiteNames()
868 #endif
870 #if !defined(XP_MACOSX)
871 // Mac doesn't have the 15-character limit Linux does
872 // Sets profiler process name
873 if (isolationPrincipal->SchemeIs("https")) {
874 nsAutoCString schemeless;
875 isolationPrincipal->GetHostPort(schemeless);
876 nsAutoCString originSuffix;
877 isolationPrincipal->GetOriginSuffix(originSuffix);
878 schemeless.Append(originSuffix);
879 mProcessName = schemeless;
880 } else
881 #endif
883 mProcessName = *aSite;
889 if (StaticPrefs::fission_processProfileName() && aCurrentProfile &&
890 !aCurrentProfile->IsEmpty()) {
891 AddProfileToProcessName(*aCurrentProfile);
894 // else private window, don't change process name, or the pref isn't set
895 // mProcessName is always flat (mProcessName == aName)
897 mozilla::ipc::SetThisProcessName(mProcessName.get());
899 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
900 ("Changed name of process %d to %s", getpid(),
901 PromiseFlatCString(mProcessName).get()));
904 static nsresult GetCreateWindowParams(nsIOpenWindowInfo* aOpenWindowInfo,
905 nsDocShellLoadState* aLoadState,
906 bool aForceNoReferrer,
907 nsIReferrerInfo** aReferrerInfo,
908 nsIPrincipal** aTriggeringPrincipal,
909 nsIContentSecurityPolicy** aCsp) {
910 if (!aTriggeringPrincipal || !aCsp) {
911 NS_ERROR("aTriggeringPrincipal || aCsp is null");
912 return NS_ERROR_FAILURE;
915 if (!aReferrerInfo) {
916 NS_ERROR("aReferrerInfo is null");
917 return NS_ERROR_FAILURE;
920 nsCOMPtr<nsIReferrerInfo> referrerInfo;
921 if (aForceNoReferrer) {
922 referrerInfo = new ReferrerInfo(nullptr, ReferrerPolicy::_empty, false);
924 if (aLoadState && !referrerInfo) {
925 referrerInfo = aLoadState->GetReferrerInfo();
928 RefPtr<BrowsingContext> parent = aOpenWindowInfo->GetParent();
929 nsCOMPtr<nsPIDOMWindowOuter> opener =
930 parent ? parent->GetDOMWindow() : nullptr;
931 if (!opener) {
932 nsCOMPtr<nsIPrincipal> nullPrincipal =
933 NullPrincipal::Create(aOpenWindowInfo->GetOriginAttributes());
934 if (!referrerInfo) {
935 referrerInfo = new ReferrerInfo(nullptr, ReferrerPolicy::_empty);
938 referrerInfo.swap(*aReferrerInfo);
939 NS_ADDREF(*aTriggeringPrincipal = nullPrincipal);
940 return NS_OK;
943 nsCOMPtr<Document> doc = opener->GetDoc();
944 NS_ADDREF(*aTriggeringPrincipal = doc->NodePrincipal());
946 nsCOMPtr<nsIContentSecurityPolicy> csp = doc->GetCsp();
947 if (csp) {
948 csp.forget(aCsp);
951 nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
952 if (!baseURI) {
953 NS_ERROR("Document didn't return a base URI");
954 return NS_ERROR_FAILURE;
957 if (!referrerInfo) {
958 referrerInfo = new ReferrerInfo(*doc);
961 referrerInfo.swap(*aReferrerInfo);
962 return NS_OK;
965 nsresult ContentChild::ProvideWindowCommon(
966 NotNull<BrowserChild*> aTabOpener, nsIOpenWindowInfo* aOpenWindowInfo,
967 uint32_t aChromeFlags, bool aCalledFromJS, nsIURI* aURI,
968 const nsAString& aName, const nsACString& aFeatures,
969 const UserActivation::Modifiers& aModifiers, bool aForceNoOpener,
970 bool aForceNoReferrer, bool aIsPopupRequested,
971 nsDocShellLoadState* aLoadState, bool* aWindowIsNew,
972 BrowsingContext** aReturn) {
973 *aReturn = nullptr;
975 nsAutoCString features(aFeatures);
976 nsAutoString name(aName);
978 nsresult rv;
980 RefPtr<BrowsingContext> parent = aOpenWindowInfo->GetParent();
981 MOZ_DIAGNOSTIC_ASSERT(parent, "We must have a parent BC");
983 // Block the attempt to open a new window if the opening BrowsingContext is
984 // not marked to use remote tabs. This ensures that the newly opened window is
985 // correctly remote.
986 if (NS_WARN_IF(!parent->UseRemoteTabs())) {
987 return NS_ERROR_ABORT;
990 bool useRemoteSubframes =
991 aChromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW;
993 uint32_t parentSandboxFlags = parent->SandboxFlags();
994 if (Document* doc = parent->GetDocument()) {
995 parentSandboxFlags = doc->GetSandboxFlags();
998 // Certain conditions complicate the process of creating the new
999 // BrowsingContext, and prevent us from using the
1000 // "CreateWindowInDifferentProcess" codepath.
1001 // * With Fission enabled, process selection will happen during the load, so
1002 // switching processes eagerly will not provide a benefit.
1003 // * Windows created for printing must be created within the current process
1004 // so that a static clone of the source document can be created.
1005 // * Sandboxed popups require the full window creation codepath.
1006 // * Loads with form or POST data require the full window creation codepath.
1007 bool cannotLoadInDifferentProcess =
1008 useRemoteSubframes || aOpenWindowInfo->GetIsForPrinting() ||
1009 (parentSandboxFlags &
1010 SANDBOX_PROPAGATES_TO_AUXILIARY_BROWSING_CONTEXTS) ||
1011 (aLoadState &&
1012 (aLoadState->IsFormSubmission() || aLoadState->PostDataStream()));
1013 if (!cannotLoadInDifferentProcess) {
1014 // If we're in a content process and we have noopener set, there's no reason
1015 // to load in our process, so let's load it elsewhere!
1016 bool loadInDifferentProcess =
1017 aForceNoOpener && StaticPrefs::dom_noopener_newprocess_enabled();
1018 if (loadInDifferentProcess) {
1019 nsCOMPtr<nsIPrincipal> triggeringPrincipal;
1020 nsCOMPtr<nsIContentSecurityPolicy> csp;
1021 nsCOMPtr<nsIReferrerInfo> referrerInfo;
1022 rv = GetCreateWindowParams(aOpenWindowInfo, aLoadState, aForceNoReferrer,
1023 getter_AddRefs(referrerInfo),
1024 getter_AddRefs(triggeringPrincipal),
1025 getter_AddRefs(csp));
1026 if (NS_WARN_IF(NS_FAILED(rv))) {
1027 return rv;
1030 if (name.LowerCaseEqualsLiteral("_blank")) {
1031 name.Truncate();
1034 MOZ_DIAGNOSTIC_ASSERT(!nsContentUtils::IsSpecialName(name));
1036 Unused << SendCreateWindowInDifferentProcess(
1037 aTabOpener, parent, aChromeFlags, aCalledFromJS, aURI, features,
1038 aModifiers, name, triggeringPrincipal, csp, referrerInfo,
1039 aOpenWindowInfo->GetOriginAttributes());
1041 // We return NS_ERROR_ABORT, so that the caller knows that we've abandoned
1042 // the window open as far as it is concerned.
1043 return NS_ERROR_ABORT;
1047 TabId tabId(nsContentUtils::GenerateTabId());
1049 // We need to assign a TabGroup to the PBrowser actor before we send it to the
1050 // parent. Otherwise, the parent could send messages to us before we have a
1051 // proper TabGroup for that actor.
1052 RefPtr<BrowsingContext> openerBC;
1053 if (!aForceNoOpener) {
1054 openerBC = parent;
1057 RefPtr<BrowsingContext> browsingContext = BrowsingContext::CreateDetached(
1058 nullptr, openerBC, nullptr, aName, BrowsingContext::Type::Content,
1059 aIsPopupRequested);
1060 MOZ_ALWAYS_SUCCEEDS(browsingContext->SetRemoteTabs(true));
1061 MOZ_ALWAYS_SUCCEEDS(browsingContext->SetRemoteSubframes(useRemoteSubframes));
1062 MOZ_ALWAYS_SUCCEEDS(browsingContext->SetOriginAttributes(
1063 aOpenWindowInfo->GetOriginAttributes()));
1065 browsingContext->InitPendingInitialization(true);
1066 auto unsetPending = MakeScopeExit([browsingContext]() {
1067 Unused << browsingContext->SetPendingInitialization(false);
1070 browsingContext->EnsureAttached();
1072 // The initial about:blank document we generate within the nsDocShell will
1073 // almost certainly be replaced at some point. Unfortunately, getting the
1074 // principal right here causes bugs due to frame scripts not getting events
1075 // they expect, due to the real initial about:blank not being created yet.
1077 // For this reason, we intentionally mispredict the initial principal here, so
1078 // that we can act the same as we did before when not predicting a result
1079 // principal. This `PWindowGlobal` will almost immediately be destroyed.
1080 nsCOMPtr<nsIPrincipal> initialPrincipal =
1081 NullPrincipal::Create(browsingContext->OriginAttributesRef());
1082 WindowGlobalInit windowInit = WindowGlobalActor::AboutBlankInitializer(
1083 browsingContext, initialPrincipal);
1085 RefPtr<WindowGlobalChild> windowChild =
1086 WindowGlobalChild::CreateDisconnected(windowInit);
1087 if (NS_WARN_IF(!windowChild)) {
1088 return NS_ERROR_ABORT;
1091 auto newChild = MakeNotNull<RefPtr<BrowserChild>>(
1092 this, tabId, *aTabOpener, browsingContext, aChromeFlags,
1093 /* aIsTopLevel */ true);
1095 if (IsShuttingDown()) {
1096 return NS_ERROR_ABORT;
1099 // Open a remote endpoint for our PBrowser actor.
1100 ManagedEndpoint<PBrowserParent> parentEp = OpenPBrowserEndpoint(newChild);
1101 if (NS_WARN_IF(!parentEp.IsValid())) {
1102 return NS_ERROR_ABORT;
1105 // Open a remote endpoint for our PWindowGlobal actor.
1106 ManagedEndpoint<PWindowGlobalParent> windowParentEp =
1107 newChild->OpenPWindowGlobalEndpoint(windowChild);
1108 if (NS_WARN_IF(!windowParentEp.IsValid())) {
1109 return NS_ERROR_ABORT;
1112 // Tell the parent process to set up its PBrowserParent.
1113 PopupIPCTabContext ipcContext(aTabOpener, 0);
1114 if (NS_WARN_IF(!SendConstructPopupBrowser(
1115 std::move(parentEp), std::move(windowParentEp), tabId, ipcContext,
1116 windowInit, aChromeFlags))) {
1117 return NS_ERROR_ABORT;
1120 windowChild->Init();
1121 auto guardNullWindowGlobal = MakeScopeExit([&] {
1122 if (!windowChild->GetWindowGlobal()) {
1123 windowChild->Destroy();
1127 // Now that |newChild| has had its IPC link established, call |Init| to set it
1128 // up.
1129 // XXX: This MOZ_KnownLive is only necessary because the static analysis can't
1130 // tell that NotNull<RefPtr<BrowserChild>> is a strong pointer.
1131 RefPtr<nsPIDOMWindowOuter> parentWindow =
1132 parent ? parent->GetDOMWindow() : nullptr;
1133 if (NS_FAILED(MOZ_KnownLive(newChild)->Init(parentWindow, windowChild))) {
1134 return NS_ERROR_ABORT;
1137 // Set to true when we're ready to return from this function.
1138 bool ready = false;
1140 // NOTE: Capturing by reference here is safe, as this function won't return
1141 // until one of these callbacks is called.
1142 auto resolve = [&](CreatedWindowInfo&& info) {
1143 MOZ_RELEASE_ASSERT(NS_IsMainThread());
1144 rv = info.rv();
1145 *aWindowIsNew = info.windowOpened();
1146 nsTArray<FrameScriptInfo> frameScripts(std::move(info.frameScripts()));
1147 uint32_t maxTouchPoints = info.maxTouchPoints();
1148 DimensionInfo dimensionInfo = std::move(info.dimensions());
1150 // Once this function exits, we should try to exit the nested event loop.
1151 ready = true;
1153 // NOTE: We have to handle this immediately in the resolve callback in order
1154 // to make sure that we don't process any more IPC messages before returning
1155 // from ProvideWindowCommon.
1157 // Handle the error which we got back from the parent process, if we got
1158 // one.
1159 if (NS_FAILED(rv)) {
1160 return;
1163 if (!*aWindowIsNew) {
1164 rv = NS_ERROR_ABORT;
1165 return;
1168 // If the BrowserChild has been torn down, we don't need to do this anymore.
1169 if (NS_WARN_IF(!newChild->IPCOpen() || newChild->IsDestroyed())) {
1170 rv = NS_ERROR_ABORT;
1171 return;
1174 ParentShowInfo showInfo(u""_ns, /* fakeShowInfo = */ true,
1175 /* isTransparent = */ false,
1176 newChild->WebWidget()->GetDPI(),
1177 newChild->WebWidget()->RoundsWidgetCoordinatesTo(),
1178 newChild->WebWidget()->GetDefaultScale().scale);
1180 newChild->SetMaxTouchPoints(maxTouchPoints);
1182 if (aForceNoOpener || !parent) {
1183 MOZ_DIAGNOSTIC_ASSERT(!browsingContext->HadOriginalOpener());
1184 MOZ_DIAGNOSTIC_ASSERT(browsingContext->GetOpenerId() == 0);
1185 } else {
1186 MOZ_DIAGNOSTIC_ASSERT(browsingContext->HadOriginalOpener());
1187 MOZ_DIAGNOSTIC_ASSERT(browsingContext->GetOpenerId() == parent->Id());
1190 // Unfortunately we don't get a window unless we've shown the frame. That's
1191 // pretty bogus; see bug 763602.
1192 newChild->DoFakeShow(showInfo);
1194 newChild->RecvUpdateDimensions(dimensionInfo);
1196 for (size_t i = 0; i < frameScripts.Length(); i++) {
1197 FrameScriptInfo& info = frameScripts[i];
1198 if (!newChild->RecvLoadRemoteScript(info.url(),
1199 info.runInGlobalScope())) {
1200 MOZ_CRASH();
1204 if (xpc::IsInAutomation()) {
1205 if (nsCOMPtr<nsPIDOMWindowOuter> outer =
1206 do_GetInterface(newChild->WebNavigation())) {
1207 nsCOMPtr<nsIObserverService> obs(services::GetObserverService());
1208 obs->NotifyObservers(
1209 outer, "dangerous:test-only:new-browser-child-ready", nullptr);
1213 browsingContext.forget(aReturn);
1216 // NOTE: Capturing by reference here is safe, as this function won't return
1217 // until one of these callbacks is called.
1218 auto reject = [&](ResponseRejectReason) {
1219 MOZ_RELEASE_ASSERT(NS_IsMainThread());
1220 NS_WARNING("windowCreated promise rejected");
1221 rv = NS_ERROR_NOT_AVAILABLE;
1222 ready = true;
1225 // Send down the request to open the window.
1226 nsCOMPtr<nsIPrincipal> triggeringPrincipal;
1227 nsCOMPtr<nsIContentSecurityPolicy> csp;
1228 nsCOMPtr<nsIReferrerInfo> referrerInfo;
1229 rv = GetCreateWindowParams(aOpenWindowInfo, aLoadState, aForceNoReferrer,
1230 getter_AddRefs(referrerInfo),
1231 getter_AddRefs(triggeringPrincipal),
1232 getter_AddRefs(csp));
1233 if (NS_WARN_IF(NS_FAILED(rv))) {
1234 return rv;
1237 SendCreateWindow(aTabOpener, parent, newChild, aChromeFlags, aCalledFromJS,
1238 aOpenWindowInfo->GetIsForPrinting(),
1239 aOpenWindowInfo->GetIsForWindowDotPrint(), aURI, features,
1240 aModifiers, triggeringPrincipal, csp, referrerInfo,
1241 aOpenWindowInfo->GetOriginAttributes(), std::move(resolve),
1242 std::move(reject));
1244 // =======================
1245 // Begin Nested Event Loop
1246 // =======================
1248 // We have to wait for a response from SendCreateWindow or with information
1249 // we're going to need to return from this function, So we spin a nested event
1250 // loop until they get back to us.
1253 // Suppress event handling for all contexts in our BrowsingContextGroup so
1254 // that event handlers cannot target our new window while it's still being
1255 // opened. Note that pending events that were suppressed while our blocker
1256 // was active will be dispatched asynchronously from a runnable dispatched
1257 // to the main event loop after this function returns, not immediately when
1258 // we leave this scope.
1259 AutoSuppressEventHandlingAndSuspend seh(browsingContext->Group());
1261 AutoNoJSAPI nojsapi;
1263 // Spin the event loop until we get a response. Callers of this function
1264 // already have to guard against an inner event loop spinning in the
1265 // non-e10s case because of the need to spin one to create a new chrome
1266 // window.
1267 SpinEventLoopUntil("ContentChild::ProvideWindowCommon"_ns,
1268 [&]() { return ready; });
1269 MOZ_RELEASE_ASSERT(ready,
1270 "We are on the main thread, so we should not exit this "
1271 "loop without ready being true.");
1274 // =====================
1275 // End Nested Event Loop
1276 // =====================
1278 // It's possible for our new BrowsingContext to become discarded during the
1279 // nested event loop, in which case we shouldn't return it, since our callers
1280 // will generally not be prepared to deal with that.
1281 if (*aReturn && (*aReturn)->IsDiscarded()) {
1282 NS_RELEASE(*aReturn);
1283 return NS_ERROR_ABORT;
1286 // We should have the results already set by the callbacks.
1287 MOZ_ASSERT_IF(NS_SUCCEEDED(rv), *aReturn);
1288 return rv;
1291 bool ContentChild::IsAlive() const { return mIsAlive; }
1293 bool ContentChild::IsShuttingDown() const { return mShuttingDown; }
1295 void ContentChild::GetProcessName(nsACString& aName) const {
1296 aName = mProcessName;
1299 /* static */
1300 void ContentChild::AppendProcessId(nsACString& aName) {
1301 if (!aName.IsEmpty()) {
1302 aName.Append(' ');
1304 unsigned pid = getpid();
1305 aName.Append(nsPrintfCString("(pid %u)", pid));
1308 void ContentChild::InitGraphicsDeviceData(const ContentDeviceData& aData) {
1309 gfxPlatform::InitChild(aData);
1312 void ContentChild::InitSharedUASheets(Maybe<SharedMemoryHandle>&& aHandle,
1313 uintptr_t aAddress) {
1314 MOZ_ASSERT_IF(!aHandle, !aAddress);
1316 if (!aAddress) {
1317 return;
1320 // Map the shared memory storing the user agent style sheets. Do this as
1321 // early as possible to maximize the chance of being able to map at the
1322 // address we want.
1323 GlobalStyleSheetCache::SetSharedMemory(std::move(*aHandle), aAddress);
1326 void ContentChild::InitXPCOM(
1327 XPCOMInitData&& aXPCOMInit,
1328 const mozilla::dom::ipc::StructuredCloneData& aInitialData,
1329 bool aIsReadyForBackgroundProcessing) {
1330 #ifdef MOZ_WIDGET_GTK
1331 // LookAndFeel::NativeInit takes a long time to run on Linux, here we schedule
1332 // it as soon as possible after BackgroundChild::Startup to give
1333 // it chance to run ahead of ConstructBrowser
1334 nsCOMPtr<nsIRunnable> event = new nsGtkNativeInitRunnable();
1335 NS_DispatchToMainThreadQueue(event.forget(), EventQueuePriority::Idle);
1336 #endif
1338 #if defined(XP_WIN)
1339 // DLL services untrusted modules processing depends on
1340 // BackgroundChild::Startup having been called
1341 RefPtr<DllServices> dllSvc(DllServices::Get());
1342 dllSvc->StartUntrustedModulesProcessor(aIsReadyForBackgroundProcessing);
1343 #endif // defined(XP_WIN)
1345 PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
1346 if (NS_WARN_IF(!actorChild)) {
1347 MOZ_ASSERT_UNREACHABLE("PBackground init can't fail at this point");
1348 return;
1351 ClientManager::Startup();
1353 // RemoteWorkerService will be initialized in RecvRemoteType, to avoid to
1354 // register it to the RemoteWorkerManager while it is still a prealloc
1355 // remoteType and defer it to the point the child process is assigned a.
1356 // actual remoteType.
1358 nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
1359 if (!svc) {
1360 NS_WARNING("Couldn't acquire console service");
1361 return;
1364 mConsoleListener = new ConsoleListener(this);
1365 if (NS_FAILED(svc->RegisterListener(mConsoleListener)))
1366 NS_WARNING("Couldn't register console listener for child process");
1368 mAvailableDictionaries = std::move(aXPCOMInit.dictionaries());
1370 RecvSetOffline(aXPCOMInit.isOffline());
1371 RecvSetConnectivity(aXPCOMInit.isConnected());
1373 LocaleService::GetInstance()->AssignAppLocales(aXPCOMInit.appLocales());
1374 LocaleService::GetInstance()->AssignRequestedLocales(
1375 aXPCOMInit.requestedLocales());
1377 L10nRegistry::RegisterFileSourcesFromParentProcess(
1378 aXPCOMInit.l10nFileSources());
1380 RecvSetCaptivePortalState(aXPCOMInit.captivePortalState());
1381 RecvBidiKeyboardNotify(aXPCOMInit.isLangRTL(),
1382 aXPCOMInit.haveBidiKeyboards());
1384 if (aXPCOMInit.domainPolicy().active()) {
1385 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
1386 MOZ_ASSERT(ssm);
1387 ssm->ActivateDomainPolicyInternal(getter_AddRefs(mPolicy));
1388 if (!mPolicy) {
1389 MOZ_CRASH("Failed to activate domain policy.");
1391 mPolicy->ApplyClone(&aXPCOMInit.domainPolicy());
1394 nsCOMPtr<nsIClipboard> clipboard(
1395 do_GetService("@mozilla.org/widget/clipboard;1"));
1396 if (nsCOMPtr<nsIClipboardProxy> clipboardProxy =
1397 do_QueryInterface(clipboard)) {
1398 clipboardProxy->SetCapabilities(aXPCOMInit.clipboardCaps());
1402 AutoJSAPI jsapi;
1403 if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) {
1404 MOZ_CRASH();
1406 ErrorResult rv;
1407 JS::Rooted<JS::Value> data(jsapi.cx());
1408 mozilla::dom::ipc::StructuredCloneData id;
1409 id.Copy(aInitialData);
1410 id.Read(jsapi.cx(), &data, rv);
1411 if (NS_WARN_IF(rv.Failed())) {
1412 MOZ_CRASH();
1414 auto* global = ContentProcessMessageManager::Get();
1415 global->SetInitialProcessData(data);
1418 // The stylesheet cache is not ready yet. Store this URL for future use.
1419 nsCOMPtr<nsIURI> ucsURL = std::move(aXPCOMInit.userContentSheetURL());
1420 GlobalStyleSheetCache::SetUserContentCSSURL(ucsURL);
1422 GfxInfoBase::SetFeatureStatus(std::move(aXPCOMInit.gfxFeatureStatus()));
1424 // Initialize the RemoteDecoderManager thread and its associated PBackground
1425 // channel.
1426 RemoteDecoderManagerChild::Init();
1428 Preferences::RegisterCallbackAndCall(&OnFissionBlocklistPrefChange,
1429 kFissionEnforceBlockList);
1430 Preferences::RegisterCallbackAndCall(&OnFissionBlocklistPrefChange,
1431 kFissionOmitBlockListValues);
1433 // Set the dynamic scalar definitions for this process.
1434 TelemetryIPC::AddDynamicScalarDefinitions(aXPCOMInit.dynamicScalarDefs());
1437 mozilla::ipc::IPCResult ContentChild::RecvRequestMemoryReport(
1438 const uint32_t& aGeneration, const bool& aAnonymize,
1439 const bool& aMinimizeMemoryUsage,
1440 const Maybe<mozilla::ipc::FileDescriptor>& aDMDFile,
1441 const RequestMemoryReportResolver& aResolver) {
1442 nsCString process;
1443 if (aAnonymize || mRemoteType.IsEmpty()) {
1444 GetProcessName(process);
1445 } else {
1446 process = mRemoteType;
1448 AppendProcessId(process);
1449 MOZ_ASSERT(!process.IsEmpty());
1451 MemoryReportRequestClient::Start(
1452 aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile, process,
1453 [&](const MemoryReport& aReport) {
1454 Unused << GetSingleton()->SendAddMemoryReport(aReport);
1456 aResolver);
1457 return IPC_OK();
1460 #if defined(XP_WIN)
1461 mozilla::ipc::IPCResult ContentChild::RecvGetUntrustedModulesData(
1462 GetUntrustedModulesDataResolver&& aResolver) {
1463 RefPtr<DllServices> dllSvc(DllServices::Get());
1464 dllSvc->GetUntrustedModulesData()->Then(
1465 GetMainThreadSerialEventTarget(), __func__,
1466 [aResolver](Maybe<UntrustedModulesData>&& aData) {
1467 aResolver(std::move(aData));
1469 [aResolver](nsresult aReason) { aResolver(Nothing()); });
1470 return IPC_OK();
1473 mozilla::ipc::IPCResult ContentChild::RecvUnblockUntrustedModulesThread() {
1474 if (nsCOMPtr<nsIObserverService> obs =
1475 mozilla::services::GetObserverService()) {
1476 obs->NotifyObservers(nullptr, "unblock-untrusted-modules-thread", nullptr);
1478 return IPC_OK();
1480 #endif // defined(XP_WIN)
1482 PCycleCollectWithLogsChild* ContentChild::AllocPCycleCollectWithLogsChild(
1483 const bool& aDumpAllTraces, const FileDescriptor& aGCLog,
1484 const FileDescriptor& aCCLog) {
1485 return do_AddRef(new CycleCollectWithLogsChild()).take();
1488 mozilla::ipc::IPCResult ContentChild::RecvPCycleCollectWithLogsConstructor(
1489 PCycleCollectWithLogsChild* aActor, const bool& aDumpAllTraces,
1490 const FileDescriptor& aGCLog, const FileDescriptor& aCCLog) {
1491 // The sink's destructor is called when the last reference goes away, which
1492 // will cause the actor to be closed down.
1493 auto* actor = static_cast<CycleCollectWithLogsChild*>(aActor);
1494 RefPtr<CycleCollectWithLogsChild::Sink> sink =
1495 new CycleCollectWithLogsChild::Sink(actor, aGCLog, aCCLog);
1497 // Invoke the dumper, which will take a reference to the sink.
1498 nsCOMPtr<nsIMemoryInfoDumper> dumper =
1499 do_GetService("@mozilla.org/memory-info-dumper;1");
1500 dumper->DumpGCAndCCLogsToSink(aDumpAllTraces, sink);
1501 return IPC_OK();
1504 bool ContentChild::DeallocPCycleCollectWithLogsChild(
1505 PCycleCollectWithLogsChild* aActor) {
1506 RefPtr<CycleCollectWithLogsChild> actor =
1507 dont_AddRef(static_cast<CycleCollectWithLogsChild*>(aActor));
1508 return true;
1511 mozilla::ipc::IPCResult ContentChild::RecvInitGMPService(
1512 Endpoint<PGMPServiceChild>&& aGMPService) {
1513 if (!GMPServiceChild::Create(std::move(aGMPService))) {
1514 return IPC_FAIL_NO_REASON(this);
1516 return IPC_OK();
1519 mozilla::ipc::IPCResult ContentChild::RecvInitProfiler(
1520 Endpoint<PProfilerChild>&& aEndpoint) {
1521 mProfilerController = ChildProfilerController::Create(std::move(aEndpoint));
1522 return IPC_OK();
1525 mozilla::ipc::IPCResult ContentChild::RecvGMPsChanged(
1526 nsTArray<GMPCapabilityData>&& capabilities) {
1527 GeckoMediaPluginServiceChild::UpdateGMPCapabilities(std::move(capabilities));
1528 return IPC_OK();
1531 mozilla::ipc::IPCResult ContentChild::RecvInitProcessHangMonitor(
1532 Endpoint<PProcessHangMonitorChild>&& aHangMonitor) {
1533 CreateHangMonitorChild(std::move(aHangMonitor));
1534 return IPC_OK();
1537 mozilla::ipc::IPCResult ContentChild::GetResultForRenderingInitFailure(
1538 base::ProcessId aOtherPid) {
1539 if (aOtherPid == base::GetCurrentProcId() || aOtherPid == OtherPid()) {
1540 // If we are talking to ourselves, or the UI process, then that is a fatal
1541 // protocol error.
1542 return IPC_FAIL_NO_REASON(this);
1545 // If we are talking to the GPU process, then we should recover from this on
1546 // the next ContentChild::RecvReinitRendering call.
1547 gfxCriticalNote << "Could not initialize rendering with GPU process";
1548 return IPC_OK();
1551 #if defined(XP_MACOSX)
1552 extern "C" {
1553 void CGSShutdownServerConnections();
1555 #endif
1557 mozilla::ipc::IPCResult ContentChild::RecvInitRendering(
1558 Endpoint<PCompositorManagerChild>&& aCompositor,
1559 Endpoint<PImageBridgeChild>&& aImageBridge,
1560 Endpoint<PVRManagerChild>&& aVRBridge,
1561 Endpoint<PRemoteDecoderManagerChild>&& aVideoManager,
1562 nsTArray<uint32_t>&& namespaces) {
1563 MOZ_ASSERT(namespaces.Length() == 3);
1565 // Note that for all of the methods below, if it can fail, it should only
1566 // return false if the failure is an IPDL error. In such situations,
1567 // ContentChild can reason about whether or not to wait for
1568 // RecvReinitRendering (because we surmised the GPU process crashed), or if it
1569 // should crash itself (because we are actually talking to the UI process). If
1570 // there are localized failures (e.g. failed to spawn a thread), then it
1571 // should MOZ_RELEASE_ASSERT or MOZ_CRASH as necessary instead.
1572 if (!CompositorManagerChild::Init(std::move(aCompositor), namespaces[0])) {
1573 return GetResultForRenderingInitFailure(aCompositor.OtherPid());
1575 if (!CompositorManagerChild::CreateContentCompositorBridge(namespaces[1])) {
1576 return GetResultForRenderingInitFailure(aCompositor.OtherPid());
1578 if (!ImageBridgeChild::InitForContent(std::move(aImageBridge),
1579 namespaces[2])) {
1580 return GetResultForRenderingInitFailure(aImageBridge.OtherPid());
1582 if (!gfx::VRManagerChild::InitForContent(std::move(aVRBridge))) {
1583 return GetResultForRenderingInitFailure(aVRBridge.OtherPid());
1585 RemoteDecoderManagerChild::InitForGPUProcess(std::move(aVideoManager));
1587 #if defined(XP_MACOSX) && !defined(MOZ_SANDBOX)
1588 // Close all current connections to the WindowServer. This ensures that the
1589 // Activity Monitor will not label the content process as "Not responding"
1590 // because it's not running a native event loop. See bug 1384336. When the
1591 // build is configured with sandbox support, this is called during sandbox
1592 // setup.
1593 CGSShutdownServerConnections();
1594 #endif
1596 return IPC_OK();
1599 mozilla::ipc::IPCResult ContentChild::RecvReinitRendering(
1600 Endpoint<PCompositorManagerChild>&& aCompositor,
1601 Endpoint<PImageBridgeChild>&& aImageBridge,
1602 Endpoint<PVRManagerChild>&& aVRBridge,
1603 Endpoint<PRemoteDecoderManagerChild>&& aVideoManager,
1604 nsTArray<uint32_t>&& namespaces) {
1605 MOZ_ASSERT(namespaces.Length() == 3);
1606 nsTArray<RefPtr<BrowserChild>> tabs = BrowserChild::GetAll();
1608 // Re-establish singleton bridges to the compositor.
1609 if (!CompositorManagerChild::Init(std::move(aCompositor), namespaces[0])) {
1610 return GetResultForRenderingInitFailure(aCompositor.OtherPid());
1612 if (!CompositorManagerChild::CreateContentCompositorBridge(namespaces[1])) {
1613 return GetResultForRenderingInitFailure(aCompositor.OtherPid());
1615 if (!ImageBridgeChild::ReinitForContent(std::move(aImageBridge),
1616 namespaces[2])) {
1617 return GetResultForRenderingInitFailure(aImageBridge.OtherPid());
1619 if (!gfx::VRManagerChild::InitForContent(std::move(aVRBridge))) {
1620 return GetResultForRenderingInitFailure(aVRBridge.OtherPid());
1622 gfxPlatform::GetPlatform()->CompositorUpdated();
1624 // Establish new PLayerTransactions.
1625 for (const auto& browserChild : tabs) {
1626 if (browserChild->GetLayersId().IsValid()) {
1627 browserChild->ReinitRendering();
1631 // Notify any observers that the compositor has been reinitialized,
1632 // eg the ZoomConstraintsClients for documents in this process.
1633 // This must occur after the ReinitRendering call above so that the
1634 // APZCTreeManagers have been connected.
1635 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1636 if (observerService) {
1637 observerService->NotifyObservers(nullptr, "compositor-reinitialized",
1638 nullptr);
1641 RemoteDecoderManagerChild::InitForGPUProcess(std::move(aVideoManager));
1642 return IPC_OK();
1645 mozilla::ipc::IPCResult ContentChild::RecvReinitRenderingForDeviceReset() {
1646 gfxPlatform::GetPlatform()->CompositorUpdated();
1648 nsTArray<RefPtr<BrowserChild>> tabs = BrowserChild::GetAll();
1649 for (const auto& browserChild : tabs) {
1650 if (browserChild->GetLayersId().IsValid()) {
1651 browserChild->ReinitRenderingForDeviceReset();
1654 return IPC_OK();
1657 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
1658 extern "C" {
1659 CGError CGSSetDenyWindowServerConnections(bool);
1662 static void DisconnectWindowServer(bool aIsSandboxEnabled) {
1663 // Close all current connections to the WindowServer. This ensures that the
1664 // Activity Monitor will not label the content process as "Not responding"
1665 // because it's not running a native event loop. See bug 1384336.
1666 // This is required with or without the sandbox enabled. Until the
1667 // window server is blocked as the policy level, this should be called
1668 // just before CGSSetDenyWindowServerConnections() so there are no
1669 // windowserver connections active when CGSSetDenyWindowServerConnections()
1670 // is called.
1671 CGSShutdownServerConnections();
1673 // Actual security benefits are only achieved when we additionally deny
1674 // future connections using the sandbox policy. WebGL must be remoted if
1675 // the windowserver connections are blocked. WebGL remoting is disabled
1676 // for some tests.
1677 if (aIsSandboxEnabled &&
1678 Preferences::GetBool(
1679 "security.sandbox.content.mac.disconnect-windowserver") &&
1680 Preferences::GetBool("webgl.out-of-process")) {
1681 CGError result = CGSSetDenyWindowServerConnections(true);
1682 MOZ_DIAGNOSTIC_ASSERT(result == kCGErrorSuccess);
1683 # if !MOZ_DIAGNOSTIC_ASSERT_ENABLED
1684 Unused << result;
1685 # endif
1688 #endif
1690 mozilla::ipc::IPCResult ContentChild::RecvSetProcessSandbox(
1691 const Maybe<mozilla::ipc::FileDescriptor>& aBroker) {
1692 // We may want to move the sandbox initialization somewhere else
1693 // at some point; see bug 880808.
1694 #if defined(MOZ_SANDBOX)
1696 bool sandboxEnabled = true;
1697 # if defined(XP_LINUX)
1698 // On Linux, we have to support systems that can't use any sandboxing.
1699 sandboxEnabled = SandboxInfo::Get().CanSandboxContent();
1701 if (sandboxEnabled && !StaticPrefs::media_cubeb_sandbox()) {
1702 // Pre-start audio before sandboxing; see bug 1443612.
1703 Unused << CubebUtils::GetCubeb();
1706 if (sandboxEnabled) {
1707 sandboxEnabled = SetContentProcessSandbox(
1708 ContentProcessSandboxParams::ForThisProcess(aBroker));
1710 # elif defined(XP_WIN)
1711 mozilla::SandboxTarget::Instance()->StartSandbox();
1712 # elif defined(XP_MACOSX)
1713 sandboxEnabled = (GetEffectiveContentSandboxLevel() >= 1);
1714 DisconnectWindowServer(sandboxEnabled);
1715 # endif
1717 CrashReporter::RecordAnnotationBool(
1718 CrashReporter::Annotation::ContentSandboxEnabled, sandboxEnabled);
1719 # if defined(XP_LINUX) && !defined(ANDROID)
1720 CrashReporter::RecordAnnotationU32(
1721 CrashReporter::Annotation::ContentSandboxCapabilities,
1722 SandboxInfo::Get().AsInteger());
1723 # endif /* XP_LINUX && !ANDROID */
1724 #endif /* MOZ_SANDBOX */
1726 return IPC_OK();
1729 mozilla::ipc::IPCResult ContentChild::RecvBidiKeyboardNotify(
1730 const bool& aIsLangRTL, const bool& aHaveBidiKeyboards) {
1731 // bidi is always of type PuppetBidiKeyboard* (because in the child, the only
1732 // possible implementation of nsIBidiKeyboard is PuppetBidiKeyboard).
1733 PuppetBidiKeyboard* bidi =
1734 static_cast<PuppetBidiKeyboard*>(nsContentUtils::GetBidiKeyboard());
1735 if (bidi) {
1736 bidi->SetBidiKeyboardInfo(aIsLangRTL, aHaveBidiKeyboards);
1738 return IPC_OK();
1741 static StaticRefPtr<CancelableRunnable> gFirstIdleTask;
1743 static void FirstIdle(void) {
1744 MOZ_ASSERT(gFirstIdleTask);
1745 gFirstIdleTask = nullptr;
1747 ContentChild::GetSingleton()->SendFirstIdle();
1750 mozilla::ipc::IPCResult ContentChild::RecvConstructBrowser(
1751 ManagedEndpoint<PBrowserChild>&& aBrowserEp,
1752 ManagedEndpoint<PWindowGlobalChild>&& aWindowEp, const TabId& aTabId,
1753 const IPCTabContext& aContext, const WindowGlobalInit& aWindowInit,
1754 const uint32_t& aChromeFlags, const ContentParentId& aCpID,
1755 const bool& aIsForBrowser, const bool& aIsTopLevel) {
1756 MOZ_DIAGNOSTIC_ASSERT(!IsShuttingDown());
1758 static bool hasRunOnce = false;
1759 if (!hasRunOnce) {
1760 hasRunOnce = true;
1761 MOZ_ASSERT(!gFirstIdleTask);
1762 RefPtr<CancelableRunnable> firstIdleTask =
1763 NewCancelableRunnableFunction("FirstIdleRunnable", FirstIdle);
1764 gFirstIdleTask = firstIdleTask;
1765 if (NS_FAILED(NS_DispatchToCurrentThreadQueue(firstIdleTask.forget(),
1766 EventQueuePriority::Idle))) {
1767 gFirstIdleTask = nullptr;
1768 hasRunOnce = false;
1772 RefPtr<BrowsingContext> browsingContext =
1773 BrowsingContext::Get(aWindowInit.context().mBrowsingContextId);
1774 if (!browsingContext || browsingContext->IsDiscarded()) {
1775 nsPrintfCString reason("%s initial %s BrowsingContext",
1776 browsingContext ? "discarded" : "missing",
1777 aIsTopLevel ? "top" : "frame");
1778 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning, ("%s", reason.get()));
1779 if (!aIsTopLevel) {
1780 // Recover if the BrowsingContext is missing for a new subframe. The
1781 // `ManagedEndpoint` instances will be automatically destroyed.
1782 NS_WARNING(reason.get());
1783 return IPC_OK();
1786 // (these are the only possible values of `reason` at this point)
1787 return browsingContext
1788 ? IPC_FAIL(this, "discarded initial top BrowsingContext")
1789 : IPC_FAIL(this, "missing initial top BrowsingContext");
1792 if (xpc::IsInAutomation() &&
1793 StaticPrefs::
1794 browser_tabs_remote_testOnly_failPBrowserCreation_enabled()) {
1795 nsAutoCString idString;
1796 if (NS_SUCCEEDED(Preferences::GetCString(
1797 "browser.tabs.remote.testOnly.failPBrowserCreation.browsingContext",
1798 idString))) {
1799 nsresult rv = NS_OK;
1800 uint64_t bcid = idString.ToInteger64(&rv);
1801 if (NS_SUCCEEDED(rv) && bcid == browsingContext->Id()) {
1802 NS_WARNING("Injecting artificial PBrowser creation failure");
1803 return IPC_OK();
1808 if (!aWindowInit.isInitialDocument() ||
1809 !NS_IsAboutBlank(aWindowInit.documentURI())) {
1810 return IPC_FAIL(this,
1811 "Logic in CreateDocumentViewerForActor currently requires "
1812 "actors to be initial about:blank documents");
1815 // We'll happily accept any kind of IPCTabContext here; we don't need to
1816 // check that it's of a certain type for security purposes, because we
1817 // believe whatever the parent process tells us.
1818 MaybeInvalidTabContext tc(aContext);
1819 if (!tc.IsValid()) {
1820 NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
1821 "the parent process. (%s) Crashing...",
1822 tc.GetInvalidReason())
1823 .get());
1824 MOZ_CRASH("Invalid TabContext received from the parent process.");
1827 RefPtr<WindowGlobalChild> windowChild =
1828 WindowGlobalChild::CreateDisconnected(aWindowInit);
1829 if (!windowChild) {
1830 return IPC_FAIL(this, "Failed to create initial WindowGlobalChild");
1833 RefPtr<BrowserChild> browserChild =
1834 BrowserChild::Create(this, aTabId, tc.GetTabContext(), browsingContext,
1835 aChromeFlags, aIsTopLevel);
1837 // Bind the created BrowserChild to IPC to actually link the actor.
1838 if (NS_WARN_IF(!BindPBrowserEndpoint(std::move(aBrowserEp), browserChild))) {
1839 return IPC_FAIL(this, "BindPBrowserEndpoint failed");
1842 if (NS_WARN_IF(!browserChild->BindPWindowGlobalEndpoint(std::move(aWindowEp),
1843 windowChild))) {
1844 return IPC_FAIL(this, "BindPWindowGlobalEndpoint failed");
1846 windowChild->Init();
1847 auto guardNullWindowGlobal = MakeScopeExit([&] {
1848 if (!windowChild->GetWindowGlobal()) {
1849 windowChild->Destroy();
1853 // Ensure that a BrowsingContext is set for our BrowserChild before
1854 // running `Init`.
1855 MOZ_RELEASE_ASSERT(browserChild->mBrowsingContext->Id() ==
1856 aWindowInit.context().mBrowsingContextId);
1858 if (NS_WARN_IF(
1859 NS_FAILED(browserChild->Init(/* aOpener */ nullptr, windowChild)))) {
1860 return IPC_FAIL(browserChild, "BrowserChild::Init failed");
1863 nsCOMPtr<nsIObserverService> os = services::GetObserverService();
1864 if (os) {
1865 os->NotifyObservers(static_cast<nsIBrowserChild*>(browserChild),
1866 "tab-child-created", nullptr);
1868 // Notify parent that we are ready to handle input events.
1869 browserChild->SendRemoteIsReadyToHandleInputEvents();
1870 return IPC_OK();
1873 void ContentChild::GetAvailableDictionaries(
1874 nsTArray<nsCString>& aDictionaries) {
1875 aDictionaries = mAvailableDictionaries.Clone();
1878 mozilla::PRemoteSpellcheckEngineChild*
1879 ContentChild::AllocPRemoteSpellcheckEngineChild() {
1880 MOZ_CRASH(
1881 "Default Constructor for PRemoteSpellcheckEngineChild should never be "
1882 "called");
1883 return nullptr;
1886 bool ContentChild::DeallocPRemoteSpellcheckEngineChild(
1887 PRemoteSpellcheckEngineChild* child) {
1888 delete child;
1889 return true;
1892 mozilla::ipc::IPCResult ContentChild::RecvNotifyEmptyHTTPCache() {
1893 MOZ_ASSERT(NS_IsMainThread());
1894 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
1895 obs->NotifyObservers(nullptr, "cacheservice:empty-cache", nullptr);
1896 return IPC_OK();
1899 PHalChild* ContentChild::AllocPHalChild() { return CreateHalChild(); }
1901 bool ContentChild::DeallocPHalChild(PHalChild* aHal) {
1902 delete aHal;
1903 return true;
1906 devtools::PHeapSnapshotTempFileHelperChild*
1907 ContentChild::AllocPHeapSnapshotTempFileHelperChild() {
1908 return devtools::HeapSnapshotTempFileHelperChild::Create();
1911 bool ContentChild::DeallocPHeapSnapshotTempFileHelperChild(
1912 devtools::PHeapSnapshotTempFileHelperChild* aHeapSnapshotHelper) {
1913 delete aHeapSnapshotHelper;
1914 return true;
1917 already_AddRefed<PTestShellChild> ContentChild::AllocPTestShellChild() {
1918 return MakeAndAddRef<TestShellChild>();
1921 mozilla::ipc::IPCResult ContentChild::RecvPTestShellConstructor(
1922 PTestShellChild* actor) {
1923 return IPC_OK();
1926 RefPtr<GenericPromise> ContentChild::UpdateCookieStatus(nsIChannel* aChannel) {
1927 RefPtr<CookieServiceChild> csChild = CookieServiceChild::GetSingleton();
1928 NS_ASSERTION(csChild, "Couldn't get CookieServiceChild");
1930 return csChild->TrackCookieLoad(aChannel);
1933 PScriptCacheChild* ContentChild::AllocPScriptCacheChild(
1934 const FileDescOrError& cacheFile, const bool& wantCacheData) {
1935 return new loader::ScriptCacheChild();
1938 bool ContentChild::DeallocPScriptCacheChild(PScriptCacheChild* cache) {
1939 delete static_cast<loader::ScriptCacheChild*>(cache);
1940 return true;
1943 mozilla::ipc::IPCResult ContentChild::RecvPScriptCacheConstructor(
1944 PScriptCacheChild* actor, const FileDescOrError& cacheFile,
1945 const bool& wantCacheData) {
1946 Maybe<FileDescriptor> fd;
1947 if (cacheFile.type() == cacheFile.TFileDescriptor) {
1948 fd.emplace(cacheFile.get_FileDescriptor());
1951 static_cast<loader::ScriptCacheChild*>(actor)->Init(fd, wantCacheData);
1953 // Some scripts listen for "app-startup" to start. However, in the content
1954 // process, this category runs before the ScriptPreloader is initialized so
1955 // these scripts wouldn't be added to the cache. Instead, if a script needs to
1956 // run on start up in the content process, it should listen for this category.
1957 NS_CreateServicesFromCategory("content-process-ready-for-script", nullptr,
1958 "content-process-ready-for-script", nullptr);
1960 return IPC_OK();
1963 mozilla::ipc::IPCResult ContentChild::RecvNetworkLinkTypeChange(
1964 const uint32_t& aType) {
1965 mNetworkLinkType = aType;
1966 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
1967 if (obs) {
1968 obs->NotifyObservers(nullptr, "contentchild:network-link-type-changed",
1969 nullptr);
1971 return IPC_OK();
1974 mozilla::ipc::IPCResult ContentChild::RecvSocketProcessCrashed() {
1975 nsIOService::IncreaseSocketProcessCrashCount();
1976 return IPC_OK();
1979 PRemotePrintJobChild* ContentChild::AllocPRemotePrintJobChild() {
1980 #ifdef NS_PRINTING
1981 return new RemotePrintJobChild();
1982 #else
1983 return nullptr;
1984 #endif
1987 already_AddRefed<PClipboardReadRequestChild>
1988 ContentChild::AllocPClipboardReadRequestChild(
1989 const nsTArray<nsCString>& aTypes) {
1990 return MakeAndAddRef<ClipboardReadRequestChild>(aTypes);
1993 media::PMediaChild* ContentChild::AllocPMediaChild() {
1994 return media::AllocPMediaChild();
1997 bool ContentChild::DeallocPMediaChild(media::PMediaChild* aActor) {
1998 return media::DeallocPMediaChild(aActor);
2001 PBenchmarkStorageChild* ContentChild::AllocPBenchmarkStorageChild() {
2002 return BenchmarkStorageChild::Instance();
2005 bool ContentChild::DeallocPBenchmarkStorageChild(
2006 PBenchmarkStorageChild* aActor) {
2007 delete aActor;
2008 return true;
2011 #ifdef MOZ_WEBRTC
2012 PWebrtcGlobalChild* ContentChild::AllocPWebrtcGlobalChild() {
2013 auto* child = new WebrtcGlobalChild();
2014 return child;
2017 bool ContentChild::DeallocPWebrtcGlobalChild(PWebrtcGlobalChild* aActor) {
2018 delete static_cast<WebrtcGlobalChild*>(aActor);
2019 return true;
2021 #endif
2023 mozilla::ipc::IPCResult ContentChild::RecvRegisterChrome(
2024 nsTArray<ChromePackage>&& packages,
2025 nsTArray<SubstitutionMapping>&& resources,
2026 nsTArray<OverrideMapping>&& overrides, const nsCString& locale,
2027 const bool& reset) {
2028 nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
2029 nsChromeRegistryContent* chromeRegistry =
2030 static_cast<nsChromeRegistryContent*>(registrySvc.get());
2031 if (!chromeRegistry) {
2032 return IPC_FAIL(this, "ChromeRegistryContent is null!");
2034 chromeRegistry->RegisterRemoteChrome(packages, resources, overrides, locale,
2035 reset);
2036 return IPC_OK();
2039 mozilla::ipc::IPCResult ContentChild::RecvRegisterChromeItem(
2040 const ChromeRegistryItem& item) {
2041 nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
2042 nsChromeRegistryContent* chromeRegistry =
2043 static_cast<nsChromeRegistryContent*>(registrySvc.get());
2044 if (!chromeRegistry) {
2045 return IPC_FAIL(this, "ChromeRegistryContent is null!");
2047 switch (item.type()) {
2048 case ChromeRegistryItem::TChromePackage:
2049 chromeRegistry->RegisterPackage(item.get_ChromePackage());
2050 break;
2052 case ChromeRegistryItem::TOverrideMapping:
2053 chromeRegistry->RegisterOverride(item.get_OverrideMapping());
2054 break;
2056 case ChromeRegistryItem::TSubstitutionMapping:
2057 chromeRegistry->RegisterSubstitution(item.get_SubstitutionMapping());
2058 break;
2060 default:
2061 MOZ_ASSERT(false, "bad chrome item");
2062 return IPC_FAIL_NO_REASON(this);
2065 return IPC_OK();
2067 mozilla::ipc::IPCResult ContentChild::RecvClearStyleSheetCache(
2068 const Maybe<RefPtr<nsIPrincipal>>& aForPrincipal,
2069 const Maybe<nsCString>& aBaseDomain) {
2070 nsIPrincipal* principal =
2071 aForPrincipal ? aForPrincipal.value().get() : nullptr;
2072 const nsCString* baseDomain = aBaseDomain ? aBaseDomain.ptr() : nullptr;
2073 SharedStyleSheetCache::Clear(principal, baseDomain);
2074 return IPC_OK();
2077 mozilla::ipc::IPCResult ContentChild::RecvClearImageCacheFromPrincipal(
2078 nsIPrincipal* aPrincipal) {
2079 imgLoader* loader;
2080 if (aPrincipal->OriginAttributesRef().mPrivateBrowsingId ==
2081 nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID) {
2082 loader = imgLoader::NormalLoader();
2083 } else {
2084 loader = imgLoader::PrivateBrowsingLoader();
2087 loader->RemoveEntriesInternal(aPrincipal, nullptr);
2088 return IPC_OK();
2091 mozilla::ipc::IPCResult ContentChild::RecvClearImageCacheFromBaseDomain(
2092 const nsCString& aBaseDomain) {
2093 imgLoader::NormalLoader()->RemoveEntriesInternal(nullptr, &aBaseDomain);
2094 imgLoader::PrivateBrowsingLoader()->RemoveEntriesInternal(nullptr,
2095 &aBaseDomain);
2097 return IPC_OK();
2100 mozilla::ipc::IPCResult ContentChild::RecvClearImageCache(
2101 const bool& privateLoader, const bool& chrome) {
2102 imgLoader* loader = privateLoader ? imgLoader::PrivateBrowsingLoader()
2103 : imgLoader::NormalLoader();
2105 loader->ClearCache(chrome);
2106 return IPC_OK();
2109 mozilla::ipc::IPCResult ContentChild::RecvSetOffline(const bool& offline) {
2110 nsCOMPtr<nsIIOService> io(do_GetIOService());
2111 NS_ASSERTION(io, "IO Service can not be null");
2113 io->SetOffline(offline);
2115 return IPC_OK();
2118 mozilla::ipc::IPCResult ContentChild::RecvSetConnectivity(
2119 const bool& connectivity) {
2120 nsCOMPtr<nsIIOService> io(do_GetIOService());
2121 nsCOMPtr<nsIIOServiceInternal> ioInternal(do_QueryInterface(io));
2122 NS_ASSERTION(ioInternal, "IO Service can not be null");
2124 ioInternal->SetConnectivity(connectivity);
2126 return IPC_OK();
2129 mozilla::ipc::IPCResult ContentChild::RecvSetCaptivePortalState(
2130 const int32_t& aState) {
2131 nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CID);
2132 if (!cps) {
2133 return IPC_OK();
2136 mozilla::net::CaptivePortalService* portal =
2137 static_cast<mozilla::net::CaptivePortalService*>(cps.get());
2138 portal->SetStateInChild(aState);
2140 return IPC_OK();
2143 mozilla::ipc::IPCResult ContentChild::RecvSetTRRMode(
2144 const nsIDNSService::ResolverMode& mode,
2145 const nsIDNSService::ResolverMode& modeFromPref) {
2146 RefPtr<net::ChildDNSService> dnsServiceChild =
2147 dont_AddRef(net::ChildDNSService::GetSingleton());
2148 if (dnsServiceChild) {
2149 dnsServiceChild->SetTRRModeInChild(mode, modeFromPref);
2151 return IPC_OK();
2154 void ContentChild::ActorDestroy(ActorDestroyReason why) {
2155 if (mForceKillTimer) {
2156 mForceKillTimer->Cancel();
2157 mForceKillTimer = nullptr;
2160 if (AbnormalShutdown == why) {
2161 NS_WARNING("shutting down early because of crash!");
2162 ProcessChild::QuickExit();
2165 #ifndef NS_FREE_PERMANENT_DATA
2166 // In release builds, there's no point in the content process
2167 // going through the full XPCOM shutdown path, because it doesn't
2168 // keep persistent state.
2169 ProcessChild::QuickExit();
2170 #else
2171 // Destroy our JSProcessActors, and reject any pending queries.
2172 JSActorDidDestroy();
2174 # if defined(XP_WIN)
2175 RefPtr<DllServices> dllSvc(DllServices::Get());
2176 dllSvc->DisableFull();
2177 # endif // defined(XP_WIN)
2179 if (gFirstIdleTask) {
2180 gFirstIdleTask->Cancel();
2181 gFirstIdleTask = nullptr;
2184 BlobURLProtocolHandler::RemoveDataEntries();
2186 mSharedData = nullptr;
2188 mAlertObservers.Clear();
2190 mIdleObservers.Clear();
2192 if (mConsoleListener) {
2193 nsCOMPtr<nsIConsoleService> svc(
2194 do_GetService(NS_CONSOLESERVICE_CONTRACTID));
2195 if (svc) {
2196 svc->UnregisterListener(mConsoleListener);
2197 mConsoleListener->mChild = nullptr;
2200 mIsAlive = false;
2202 CrashReporterClient::DestroySingleton();
2204 XRE_ShutdownChildProcess();
2205 #endif // NS_FREE_PERMANENT_DATA
2208 void ContentChild::ProcessingError(Result aCode, const char* aReason) {
2209 switch (aCode) {
2210 case MsgDropped:
2211 NS_WARNING("MsgDropped in ContentChild");
2212 return;
2214 case MsgNotKnown:
2215 case MsgNotAllowed:
2216 case MsgPayloadError:
2217 case MsgProcessingError:
2218 case MsgRouteError:
2219 case MsgValueError:
2220 break;
2222 default:
2223 MOZ_CRASH("not reached");
2226 CrashReporter::RecordAnnotationCString(
2227 CrashReporter::Annotation::ipc_channel_error, aReason);
2229 MOZ_CRASH("Content child abort due to IPC error");
2232 nsresult ContentChild::AddRemoteAlertObserver(const nsString& aData,
2233 nsIObserver* aObserver) {
2234 NS_ASSERTION(aObserver, "Adding a null observer?");
2235 mAlertObservers.AppendElement(new AlertObserver(aObserver, aData));
2236 return NS_OK;
2239 mozilla::ipc::IPCResult ContentChild::RecvPreferenceUpdate(const Pref& aPref) {
2240 Preferences::SetPreference(aPref);
2241 return IPC_OK();
2244 mozilla::ipc::IPCResult ContentChild::RecvVarUpdate(const GfxVarUpdate& aVar) {
2245 gfx::gfxVars::ApplyUpdate(aVar);
2246 return IPC_OK();
2249 mozilla::ipc::IPCResult ContentChild::RecvUpdatePerfStatsCollectionMask(
2250 const uint64_t& aMask) {
2251 PerfStats::SetCollectionMask(static_cast<PerfStats::MetricMask>(aMask));
2252 return IPC_OK();
2255 mozilla::ipc::IPCResult ContentChild::RecvCollectPerfStatsJSON(
2256 CollectPerfStatsJSONResolver&& aResolver) {
2257 aResolver(PerfStats::CollectLocalPerfStatsJSON());
2258 return IPC_OK();
2261 mozilla::ipc::IPCResult ContentChild::RecvCollectScrollingMetrics(
2262 CollectScrollingMetricsResolver&& aResolver) {
2263 auto metrics = ScrollingMetrics::CollectLocalScrollingMetrics();
2264 using ResolverArgs = std::tuple<const uint32_t&, const uint32_t&>;
2265 aResolver(ResolverArgs(std::get<0>(metrics), std::get<1>(metrics)));
2266 return IPC_OK();
2269 mozilla::ipc::IPCResult ContentChild::RecvNotifyAlertsObserver(
2270 const nsCString& aType, const nsString& aData) {
2271 nsTArray<nsCOMPtr<nsIObserver>> observersToNotify;
2273 mAlertObservers.RemoveElementsBy([&](UniquePtr<AlertObserver>& observer) {
2274 if (!observer->mData.Equals(aData)) {
2275 return false;
2278 // aType == alertfinished, this alert is done and we can remove the
2279 // observer.
2280 observersToNotify.AppendElement(observer->mObserver);
2281 return aType.EqualsLiteral("alertfinished");
2284 for (auto& observer : observersToNotify) {
2285 observer->Observe(nullptr, aType.get(), aData.get());
2288 return IPC_OK();
2291 mozilla::ipc::IPCResult ContentChild::RecvNotifyVisited(
2292 nsTArray<VisitedQueryResult>&& aURIs) {
2293 nsCOMPtr<IHistory> history = components::History::Service();
2294 if (!history) {
2295 return IPC_OK();
2297 for (const VisitedQueryResult& result : aURIs) {
2298 nsCOMPtr<nsIURI> newURI = result.uri();
2299 if (!newURI) {
2300 return IPC_FAIL_NO_REASON(this);
2302 auto status = result.visited() ? IHistory::VisitedStatus::Visited
2303 : IHistory::VisitedStatus::Unvisited;
2304 history->NotifyVisited(newURI, status);
2306 return IPC_OK();
2309 mozilla::ipc::IPCResult ContentChild::RecvThemeChanged(
2310 FullLookAndFeel&& aLookAndFeelData, widget::ThemeChangeKind aKind) {
2311 LookAndFeel::SetData(std::move(aLookAndFeelData));
2312 LookAndFeel::NotifyChangedAllWindows(aKind);
2313 return IPC_OK();
2316 mozilla::ipc::IPCResult ContentChild::RecvLoadProcessScript(
2317 const nsString& aURL) {
2318 auto* global = ContentProcessMessageManager::Get();
2319 global->LoadScript(aURL);
2320 return IPC_OK();
2323 mozilla::ipc::IPCResult ContentChild::RecvAsyncMessage(
2324 const nsString& aMsg, const ClonedMessageData& aData) {
2325 AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("ContentChild::RecvAsyncMessage",
2326 OTHER, aMsg);
2327 MMPrinter::Print("ContentChild::RecvAsyncMessage", aMsg, aData);
2329 RefPtr<nsFrameMessageManager> cpm =
2330 nsFrameMessageManager::GetChildProcessManager();
2331 if (cpm) {
2332 StructuredCloneData data;
2333 ipc::UnpackClonedMessageData(aData, data);
2334 cpm->ReceiveMessage(cpm, nullptr, aMsg, false, &data, nullptr,
2335 IgnoreErrors());
2337 return IPC_OK();
2340 mozilla::ipc::IPCResult ContentChild::RecvRegisterStringBundles(
2341 nsTArray<mozilla::dom::StringBundleDescriptor>&& aDescriptors) {
2342 nsCOMPtr<nsIStringBundleService> stringBundleService =
2343 components::StringBundle::Service();
2345 for (auto& descriptor : aDescriptors) {
2346 stringBundleService->RegisterContentBundle(
2347 descriptor.bundleURL(), descriptor.mapFile(), descriptor.mapSize());
2350 return IPC_OK();
2353 mozilla::ipc::IPCResult ContentChild::RecvUpdateL10nFileSources(
2354 nsTArray<mozilla::dom::L10nFileSourceDescriptor>&& aDescriptors) {
2355 L10nRegistry::RegisterFileSourcesFromParentProcess(aDescriptors);
2356 return IPC_OK();
2359 mozilla::ipc::IPCResult ContentChild::RecvUpdateSharedData(
2360 const FileDescriptor& aMapFile, const uint32_t& aMapSize,
2361 nsTArray<IPCBlob>&& aBlobs, nsTArray<nsCString>&& aChangedKeys) {
2362 nsTArray<RefPtr<BlobImpl>> blobImpls(aBlobs.Length());
2363 for (auto& ipcBlob : aBlobs) {
2364 blobImpls.AppendElement(IPCBlobUtils::Deserialize(ipcBlob));
2367 if (mSharedData) {
2368 mSharedData->Update(aMapFile, aMapSize, std::move(blobImpls),
2369 std::move(aChangedKeys));
2370 } else {
2371 mSharedData =
2372 new SharedMap(ContentProcessMessageManager::Get()->GetParentObject(),
2373 aMapFile, aMapSize, std::move(blobImpls));
2376 return IPC_OK();
2379 mozilla::ipc::IPCResult ContentChild::RecvFontListChanged() {
2380 gfxPlatformFontList::PlatformFontList()->FontListChanged();
2382 return IPC_OK();
2385 mozilla::ipc::IPCResult ContentChild::RecvForceGlobalReflow(
2386 bool aNeedsReframe) {
2387 gfxPlatform::ForceGlobalReflow(aNeedsReframe ? gfxPlatform::NeedsReframe::Yes
2388 : gfxPlatform::NeedsReframe::No);
2390 return IPC_OK();
2393 mozilla::ipc::IPCResult ContentChild::RecvGeolocationUpdate(
2394 nsIDOMGeoPosition* aPosition) {
2395 RefPtr<nsGeolocationService> gs =
2396 nsGeolocationService::GetGeolocationService();
2397 if (!gs) {
2398 return IPC_OK();
2400 gs->Update(aPosition);
2401 return IPC_OK();
2404 mozilla::ipc::IPCResult ContentChild::RecvGeolocationError(
2405 const uint16_t& errorCode) {
2406 RefPtr<nsGeolocationService> gs =
2407 nsGeolocationService::GetGeolocationService();
2408 if (!gs) {
2409 return IPC_OK();
2411 gs->NotifyError(errorCode);
2412 return IPC_OK();
2415 mozilla::ipc::IPCResult ContentChild::RecvUpdateDictionaryList(
2416 nsTArray<nsCString>&& aDictionaries) {
2417 mAvailableDictionaries = std::move(aDictionaries);
2418 mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking();
2419 return IPC_OK();
2422 mozilla::ipc::IPCResult ContentChild::RecvUpdateFontList(
2423 dom::SystemFontList&& aFontList) {
2424 mFontList = std::move(aFontList);
2425 if (gfxPlatform::Initialized()) {
2426 gfxPlatform::GetPlatform()->UpdateFontList(true);
2428 return IPC_OK();
2431 mozilla::ipc::IPCResult ContentChild::RecvRebuildFontList(
2432 const bool& aFullRebuild) {
2433 if (gfxPlatform::Initialized()) {
2434 gfxPlatform::GetPlatform()->UpdateFontList(aFullRebuild);
2436 return IPC_OK();
2439 mozilla::ipc::IPCResult ContentChild::RecvFontListShmBlockAdded(
2440 const uint32_t& aGeneration, const uint32_t& aIndex,
2441 base::SharedMemoryHandle&& aHandle) {
2442 if (gfxPlatform::Initialized()) {
2443 gfxPlatformFontList::PlatformFontList()->ShmBlockAdded(aGeneration, aIndex,
2444 std::move(aHandle));
2446 return IPC_OK();
2449 mozilla::ipc::IPCResult ContentChild::RecvUpdateAppLocales(
2450 nsTArray<nsCString>&& aAppLocales) {
2451 LocaleService::GetInstance()->AssignAppLocales(aAppLocales);
2452 return IPC_OK();
2455 mozilla::ipc::IPCResult ContentChild::RecvUpdateRequestedLocales(
2456 nsTArray<nsCString>&& aRequestedLocales) {
2457 LocaleService::GetInstance()->AssignRequestedLocales(aRequestedLocales);
2458 return IPC_OK();
2461 mozilla::ipc::IPCResult ContentChild::RecvSystemTimezoneChanged() {
2462 nsJSUtils::ResetTimeZone();
2463 return IPC_OK();
2466 mozilla::ipc::IPCResult ContentChild::RecvAddPermission(
2467 const IPC::Permission& permission) {
2468 nsCOMPtr<nsIPermissionManager> permissionManagerIface =
2469 components::PermissionManager::Service();
2470 PermissionManager* permissionManager =
2471 static_cast<PermissionManager*>(permissionManagerIface.get());
2472 MOZ_ASSERT(permissionManager,
2473 "We have no permissionManager in the Content process !");
2475 // note we do not need to force mUserContextId to the default here because
2476 // the permission manager does that internally.
2477 nsAutoCString originNoSuffix;
2478 OriginAttributes attrs;
2479 bool success = attrs.PopulateFromOrigin(permission.origin, originNoSuffix);
2480 NS_ENSURE_TRUE(success, IPC_FAIL_NO_REASON(this));
2482 nsCOMPtr<nsIURI> uri;
2483 nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix);
2484 NS_ENSURE_SUCCESS(rv, IPC_OK());
2486 nsCOMPtr<nsIPrincipal> principal =
2487 mozilla::BasePrincipal::CreateContentPrincipal(uri, attrs);
2489 // child processes don't care about modification time.
2490 int64_t modificationTime = 0;
2492 permissionManager->AddInternal(
2493 principal, nsCString(permission.type), permission.capability, 0,
2494 permission.expireType, permission.expireTime, modificationTime,
2495 PermissionManager::eNotify, PermissionManager::eNoDBOperation);
2497 return IPC_OK();
2500 mozilla::ipc::IPCResult ContentChild::RecvRemoveAllPermissions() {
2501 nsCOMPtr<nsIPermissionManager> permissionManagerIface =
2502 components::PermissionManager::Service();
2503 PermissionManager* permissionManager =
2504 static_cast<PermissionManager*>(permissionManagerIface.get());
2505 MOZ_ASSERT(permissionManager,
2506 "We have no permissionManager in the Content process !");
2508 permissionManager->RemoveAllFromIPC();
2509 return IPC_OK();
2512 mozilla::ipc::IPCResult ContentChild::RecvFlushMemory(const nsString& reason) {
2513 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
2514 if (!mShuttingDown && os) {
2515 os->NotifyObservers(nullptr, "memory-pressure", reason.get());
2517 return IPC_OK();
2520 mozilla::ipc::IPCResult ContentChild::RecvActivateA11y() {
2521 #ifdef ACCESSIBILITY
2522 // Start accessibility in content process if it's running in chrome
2523 // process.
2524 GetOrCreateAccService(nsAccessibilityService::eMainProcess);
2525 #endif // ACCESSIBILITY
2526 return IPC_OK();
2529 mozilla::ipc::IPCResult ContentChild::RecvShutdownA11y() {
2530 #ifdef ACCESSIBILITY
2531 // Try to shutdown accessibility in content process if it's shutting down in
2532 // chrome process.
2533 MaybeShutdownAccService(nsAccessibilityService::eMainProcess);
2534 #endif
2535 return IPC_OK();
2538 mozilla::ipc::IPCResult ContentChild::RecvApplicationForeground() {
2539 // Rebroadcast the "application-foreground"
2540 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
2541 if (obs) {
2542 obs->NotifyObservers(nullptr, "application-foreground", nullptr);
2544 return IPC_OK();
2547 mozilla::ipc::IPCResult ContentChild::RecvApplicationBackground() {
2548 // Rebroadcast the "application-background"
2549 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
2550 if (obs) {
2551 obs->NotifyObservers(nullptr, "application-background", nullptr);
2553 return IPC_OK();
2556 mozilla::ipc::IPCResult ContentChild::RecvGarbageCollect() {
2557 // Rebroadcast the "child-gc-request" so that workers will GC.
2558 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
2559 if (obs) {
2560 obs->NotifyObservers(nullptr, "child-gc-request", nullptr);
2562 nsJSContext::GarbageCollectNow(JS::GCReason::DOM_IPC);
2563 return IPC_OK();
2566 mozilla::ipc::IPCResult ContentChild::RecvCycleCollect() {
2567 // Rebroadcast the "child-cc-request" so that workers will CC.
2568 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
2569 if (obs) {
2570 obs->NotifyObservers(nullptr, "child-cc-request", nullptr);
2572 nsJSContext::CycleCollectNow(CCReason::IPC_MESSAGE);
2573 return IPC_OK();
2576 mozilla::ipc::IPCResult ContentChild::RecvUnlinkGhosts() {
2577 #ifdef DEBUG
2578 nsWindowMemoryReporter::UnlinkGhostWindows();
2579 #endif
2580 return IPC_OK();
2583 mozilla::ipc::IPCResult ContentChild::RecvAppInfo(
2584 const nsCString& version, const nsCString& buildID, const nsCString& name,
2585 const nsCString& UAName, const nsCString& ID, const nsCString& vendor,
2586 const nsCString& sourceURL, const nsCString& updateURL) {
2587 mAppInfo.version.Assign(version);
2588 mAppInfo.buildID.Assign(buildID);
2589 mAppInfo.name.Assign(name);
2590 mAppInfo.UAName.Assign(UAName);
2591 mAppInfo.ID.Assign(ID);
2592 mAppInfo.vendor.Assign(vendor);
2593 mAppInfo.sourceURL.Assign(sourceURL);
2594 mAppInfo.updateURL.Assign(updateURL);
2596 return IPC_OK();
2599 mozilla::ipc::IPCResult ContentChild::RecvRemoteType(
2600 const nsCString& aRemoteType, const nsCString& aProfile) {
2601 if (aRemoteType == mRemoteType) {
2602 // Allocation of preallocated processes that are still launching can
2603 // cause this
2604 return IPC_OK();
2607 if (!mRemoteType.IsVoid()) {
2608 // Preallocated processes are type PREALLOC_REMOTE_TYPE; they may not
2609 // become a File: process, or Privileged About Content Process
2610 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2611 ("Changing remoteType of process %d from %s to %s", getpid(),
2612 mRemoteType.get(), aRemoteType.get()));
2613 // prealloc->anything (but file) or web->web allowed, and no-change
2614 MOZ_RELEASE_ASSERT(mRemoteType == PREALLOC_REMOTE_TYPE &&
2615 aRemoteType != FILE_REMOTE_TYPE &&
2616 aRemoteType != PRIVILEGEDABOUT_REMOTE_TYPE);
2617 } else {
2618 // Initial setting of remote type. Either to 'prealloc' or the actual
2619 // final type (if we didn't use a preallocated process)
2620 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2621 ("Setting remoteType of process %d to %s", getpid(),
2622 aRemoteType.get()));
2624 if (aRemoteType == PREALLOC_REMOTE_TYPE) {
2625 PreallocInit();
2629 auto remoteTypePrefix = RemoteTypePrefix(aRemoteType);
2631 // Must do before SetProcessName
2632 mRemoteType.Assign(aRemoteType);
2634 // Update the process name so about:memory's process names are more obvious.
2635 if (aRemoteType == FILE_REMOTE_TYPE) {
2636 SetProcessName("file:// Content"_ns, nullptr, &aProfile);
2637 } else if (aRemoteType == EXTENSION_REMOTE_TYPE) {
2638 SetProcessName("WebExtensions"_ns, nullptr, &aProfile);
2639 } else if (aRemoteType == PRIVILEGEDABOUT_REMOTE_TYPE) {
2640 SetProcessName("Privileged Content"_ns, nullptr, &aProfile);
2641 } else if (aRemoteType == PRIVILEGEDMOZILLA_REMOTE_TYPE) {
2642 SetProcessName("Privileged Mozilla"_ns, nullptr, &aProfile);
2643 } else if (remoteTypePrefix == WITH_COOP_COEP_REMOTE_TYPE) {
2644 // The profiler can sanitize out the eTLD+1
2645 nsDependentCSubstring etld =
2646 Substring(aRemoteType, WITH_COOP_COEP_REMOTE_TYPE.Length() + 1);
2647 #ifdef NIGHTLY_BUILD
2648 SetProcessName("WebCOOP+COEP Content"_ns, &etld, &aProfile);
2649 #else
2650 SetProcessName("Isolated Web Content"_ns, &etld,
2651 &aProfile); // to avoid confusing people
2652 #endif
2653 } else if (remoteTypePrefix == FISSION_WEB_REMOTE_TYPE) {
2654 // The profiler can sanitize out the eTLD+1
2655 nsDependentCSubstring etld =
2656 Substring(aRemoteType, FISSION_WEB_REMOTE_TYPE.Length() + 1);
2657 SetProcessName("Isolated Web Content"_ns, &etld, &aProfile);
2658 } else if (remoteTypePrefix == SERVICEWORKER_REMOTE_TYPE) {
2659 // The profiler can sanitize out the eTLD+1
2660 nsDependentCSubstring etld =
2661 Substring(aRemoteType, SERVICEWORKER_REMOTE_TYPE.Length() + 1);
2662 SetProcessName("Isolated Service Worker"_ns, &etld, &aProfile);
2663 } else {
2664 // else "prealloc" or "web" type -> "Web Content"
2665 SetProcessName("Web Content"_ns, nullptr, &aProfile);
2668 // Turn off Spectre mitigations in isolated web content processes.
2669 if (StaticPrefs::javascript_options_spectre_disable_for_isolated_content() &&
2670 (remoteTypePrefix == FISSION_WEB_REMOTE_TYPE ||
2671 remoteTypePrefix == SERVICEWORKER_REMOTE_TYPE ||
2672 remoteTypePrefix == WITH_COOP_COEP_REMOTE_TYPE ||
2673 aRemoteType == PRIVILEGEDABOUT_REMOTE_TYPE ||
2674 aRemoteType == PRIVILEGEDMOZILLA_REMOTE_TYPE)) {
2675 JS::DisableSpectreMitigationsAfterInit();
2678 // Use the prefix to avoid URIs from Fission isolated processes.
2679 CrashReporter::RecordAnnotationNSCString(
2680 CrashReporter::Annotation::RemoteType, remoteTypePrefix);
2682 // Defer RemoteWorkerService initialization until the child process does
2683 // receive its specific remoteType and can become actionable for the
2684 // RemoteWorkerManager in the parent process.
2685 if (mRemoteType != PREALLOC_REMOTE_TYPE) {
2686 RemoteWorkerService::Initialize();
2689 return IPC_OK();
2692 // A method to initialize anything we need during the preallocation phase
2693 void ContentChild::PreallocInit() {
2694 EnsureNSSInitializedChromeOrContent();
2696 // SetAcceptLanguages() needs to read localized strings (file access),
2697 // which is slow, so do this in prealloc
2698 nsHttpHandler::PresetAcceptLanguages();
2701 // Call RemoteTypePrefix() on the result to remove URIs if you want to use this
2702 // for telemetry.
2703 const nsACString& ContentChild::GetRemoteType() const { return mRemoteType; }
2705 mozilla::ipc::IPCResult ContentChild::RecvInitBlobURLs(
2706 nsTArray<BlobURLRegistrationData>&& aRegistrations) {
2707 for (uint32_t i = 0; i < aRegistrations.Length(); ++i) {
2708 BlobURLRegistrationData& registration = aRegistrations[i];
2709 RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(registration.blob());
2710 MOZ_ASSERT(blobImpl);
2712 BlobURLProtocolHandler::AddDataEntry(registration.url(),
2713 registration.principal(),
2714 registration.partitionKey(), blobImpl);
2715 // If we have received an already-revoked blobURL, we have to keep it alive
2716 // for a while (see BlobURLProtocolHandler) in order to support pending
2717 // operations such as navigation, download and so on.
2718 if (registration.revoked()) {
2719 BlobURLProtocolHandler::RemoveDataEntry(registration.url(), false);
2723 return IPC_OK();
2726 mozilla::ipc::IPCResult ContentChild::RecvInitJSActorInfos(
2727 nsTArray<JSProcessActorInfo>&& aContentInfos,
2728 nsTArray<JSWindowActorInfo>&& aWindowInfos) {
2729 RefPtr<JSActorService> actSvc = JSActorService::GetSingleton();
2730 actSvc->LoadJSActorInfos(aContentInfos, aWindowInfos);
2731 return IPC_OK();
2734 mozilla::ipc::IPCResult ContentChild::RecvUnregisterJSWindowActor(
2735 const nsCString& aName) {
2736 RefPtr<JSActorService> actSvc = JSActorService::GetSingleton();
2737 actSvc->UnregisterWindowActor(aName);
2738 return IPC_OK();
2741 mozilla::ipc::IPCResult ContentChild::RecvUnregisterJSProcessActor(
2742 const nsCString& aName) {
2743 RefPtr<JSActorService> actSvc = JSActorService::GetSingleton();
2744 actSvc->UnregisterProcessActor(aName);
2745 return IPC_OK();
2748 mozilla::ipc::IPCResult ContentChild::RecvLastPrivateDocShellDestroyed() {
2749 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
2750 obs->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
2751 return IPC_OK();
2754 mozilla::ipc::IPCResult ContentChild::RecvNotifyProcessPriorityChanged(
2755 const hal::ProcessPriority& aPriority) {
2756 nsCOMPtr<nsIObserverService> os = services::GetObserverService();
2757 NS_ENSURE_TRUE(os, IPC_OK());
2759 RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
2760 props->SetPropertyAsInt32(u"priority"_ns, static_cast<int32_t>(aPriority));
2762 PROFILER_MARKER("Process Priority", OTHER,
2763 mozilla::MarkerThreadId::MainThread(), ProcessPriorityChange,
2764 ProfilerString8View::WrapNullTerminatedString(
2765 ProcessPriorityToString(mProcessPriority)),
2766 ProfilerString8View::WrapNullTerminatedString(
2767 ProcessPriorityToString(aPriority)));
2769 // Record FOG data before the priority change.
2770 // Ignore the change if it's the first time we set the process priority.
2771 if (mProcessPriority != hal::PROCESS_PRIORITY_UNKNOWN) {
2772 glean::RecordPowerMetrics();
2775 ConfigureThreadPerformanceHints(aPriority);
2777 mProcessPriority = aPriority;
2779 os->NotifyObservers(static_cast<nsIPropertyBag2*>(props),
2780 "ipc:process-priority-changed", nullptr);
2781 if (StaticPrefs::
2782 dom_memory_foreground_content_processes_have_larger_page_cache()) {
2783 if (mProcessPriority >= hal::PROCESS_PRIORITY_FOREGROUND) {
2784 // Note: keep this in sync with the JS shell (js/src/shell/js.cpp).
2785 moz_set_max_dirty_page_modifier(4);
2786 } else if (mProcessPriority == hal::PROCESS_PRIORITY_BACKGROUND) {
2787 moz_set_max_dirty_page_modifier(-2);
2788 } else {
2789 moz_set_max_dirty_page_modifier(0);
2793 return IPC_OK();
2796 mozilla::ipc::IPCResult ContentChild::RecvMinimizeMemoryUsage() {
2797 nsCOMPtr<nsIMemoryReporterManager> mgr =
2798 do_GetService("@mozilla.org/memory-reporter-manager;1");
2799 NS_ENSURE_TRUE(mgr, IPC_OK());
2801 Unused << mgr->MinimizeMemoryUsage(/* callback = */ nullptr);
2802 return IPC_OK();
2805 void ContentChild::AddIdleObserver(nsIObserver* aObserver,
2806 uint32_t aIdleTimeInS) {
2807 MOZ_ASSERT(aObserver, "null idle observer");
2808 // Make sure aObserver isn't released while we wait for the parent
2809 aObserver->AddRef();
2810 SendAddIdleObserver(reinterpret_cast<uint64_t>(aObserver), aIdleTimeInS);
2811 mIdleObservers.Insert(aObserver);
2814 void ContentChild::RemoveIdleObserver(nsIObserver* aObserver,
2815 uint32_t aIdleTimeInS) {
2816 MOZ_ASSERT(aObserver, "null idle observer");
2817 SendRemoveIdleObserver(reinterpret_cast<uint64_t>(aObserver), aIdleTimeInS);
2818 aObserver->Release();
2819 mIdleObservers.Remove(aObserver);
2822 mozilla::ipc::IPCResult ContentChild::RecvNotifyIdleObserver(
2823 const uint64_t& aObserver, const nsCString& aTopic,
2824 const nsString& aTimeStr) {
2825 nsIObserver* observer = reinterpret_cast<nsIObserver*>(aObserver);
2826 if (mIdleObservers.Contains(observer)) {
2827 observer->Observe(nullptr, aTopic.get(), aTimeStr.get());
2828 } else {
2829 NS_WARNING("Received notification for an idle observer that was removed.");
2831 return IPC_OK();
2834 mozilla::ipc::IPCResult ContentChild::RecvLoadAndRegisterSheet(
2835 nsIURI* aURI, const uint32_t& aType) {
2836 if (!aURI) {
2837 return IPC_OK();
2840 nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
2841 if (sheetService) {
2842 sheetService->LoadAndRegisterSheet(aURI, aType);
2845 return IPC_OK();
2848 mozilla::ipc::IPCResult ContentChild::RecvUnregisterSheet(
2849 nsIURI* aURI, const uint32_t& aType) {
2850 if (!aURI) {
2851 return IPC_OK();
2854 nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
2855 if (sheetService) {
2856 sheetService->UnregisterSheet(aURI, aType);
2859 return IPC_OK();
2862 mozilla::ipc::IPCResult ContentChild::RecvDomainSetChanged(
2863 const uint32_t& aSetType, const uint32_t& aChangeType, nsIURI* aDomain) {
2864 if (aChangeType == ACTIVATE_POLICY) {
2865 if (mPolicy) {
2866 return IPC_OK();
2868 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
2869 MOZ_ASSERT(ssm);
2870 ssm->ActivateDomainPolicyInternal(getter_AddRefs(mPolicy));
2871 if (!mPolicy) {
2872 return IPC_FAIL_NO_REASON(this);
2874 return IPC_OK();
2876 if (!mPolicy) {
2877 MOZ_ASSERT_UNREACHABLE(
2878 "If the domain policy is not active yet,"
2879 " the first message should be ACTIVATE_POLICY");
2880 return IPC_FAIL_NO_REASON(this);
2883 NS_ENSURE_TRUE(mPolicy, IPC_FAIL_NO_REASON(this));
2885 if (aChangeType == DEACTIVATE_POLICY) {
2886 mPolicy->Deactivate();
2887 mPolicy = nullptr;
2888 return IPC_OK();
2891 nsCOMPtr<nsIDomainSet> set;
2892 switch (aSetType) {
2893 case BLOCKLIST:
2894 mPolicy->GetBlocklist(getter_AddRefs(set));
2895 break;
2896 case SUPER_BLOCKLIST:
2897 mPolicy->GetSuperBlocklist(getter_AddRefs(set));
2898 break;
2899 case ALLOWLIST:
2900 mPolicy->GetAllowlist(getter_AddRefs(set));
2901 break;
2902 case SUPER_ALLOWLIST:
2903 mPolicy->GetSuperAllowlist(getter_AddRefs(set));
2904 break;
2905 default:
2906 MOZ_ASSERT_UNREACHABLE("Unexpected setType");
2907 return IPC_FAIL_NO_REASON(this);
2910 MOZ_ASSERT(set);
2912 switch (aChangeType) {
2913 case ADD_DOMAIN:
2914 NS_ENSURE_TRUE(aDomain, IPC_FAIL_NO_REASON(this));
2915 set->Add(aDomain);
2916 break;
2917 case REMOVE_DOMAIN:
2918 NS_ENSURE_TRUE(aDomain, IPC_FAIL_NO_REASON(this));
2919 set->Remove(aDomain);
2920 break;
2921 case CLEAR_DOMAINS:
2922 set->Clear();
2923 break;
2924 default:
2925 MOZ_ASSERT_UNREACHABLE("Unexpected changeType");
2926 return IPC_FAIL_NO_REASON(this);
2929 return IPC_OK();
2932 void ContentChild::StartForceKillTimer() {
2933 if (mForceKillTimer) {
2934 return;
2937 int32_t timeoutSecs = StaticPrefs::dom_ipc_tabs_shutdownTimeoutSecs();
2938 if (timeoutSecs > 0) {
2939 NS_NewTimerWithFuncCallback(getter_AddRefs(mForceKillTimer),
2940 ContentChild::ForceKillTimerCallback, this,
2941 timeoutSecs * 1000, nsITimer::TYPE_ONE_SHOT,
2942 "dom::ContentChild::StartForceKillTimer");
2943 MOZ_ASSERT(mForceKillTimer);
2947 /* static */
2948 void ContentChild::ForceKillTimerCallback(nsITimer* aTimer, void* aClosure) {
2949 ProcessChild::QuickExit();
2952 mozilla::ipc::IPCResult ContentChild::RecvShutdownConfirmedHP() {
2953 ProcessChild::AppendToIPCShutdownStateAnnotation(
2954 "RecvShutdownConfirmedHP entry"_ns);
2956 // Bug 1755376: If we see "RecvShutdownConfirmedHP entry" often in
2957 // bug IPCError_ShutDownKill we might want to anticipate
2958 // ShutdownPhase::AppShutdownConfirmed to start here.
2960 return IPC_OK();
2963 mozilla::ipc::IPCResult ContentChild::RecvShutdown() {
2964 ProcessChild::AppendToIPCShutdownStateAnnotation("RecvShutdown entry"_ns);
2966 // Signal the ongoing shutdown to AppShutdown, this
2967 // will make abort nested SpinEventLoopUntilOrQuit loops
2968 AppShutdown::AdvanceShutdownPhaseWithoutNotify(
2969 ShutdownPhase::AppShutdownConfirmed);
2971 nsCOMPtr<nsIObserverService> os = services::GetObserverService();
2972 if (os) {
2973 ProcessChild::AppendToIPCShutdownStateAnnotation(
2974 "content-child-will-shutdown started"_ns);
2976 os->NotifyObservers(ToSupports(this), "content-child-will-shutdown",
2977 nullptr);
2980 ShutdownInternal();
2981 return IPC_OK();
2984 void ContentChild::ShutdownInternal() {
2985 ProcessChild::AppendToIPCShutdownStateAnnotation("ShutdownInternal entry"_ns);
2987 // If we receive the shutdown message from within a nested event loop, we want
2988 // to wait for that event loop to finish. Otherwise we could prematurely
2989 // terminate an "unload" or "pagehide" event handler (which might be doing a
2990 // sync XHR, for example).
2992 MOZ_ASSERT(NS_IsMainThread());
2993 RefPtr<nsThread> mainThread = nsThreadManager::get().GetCurrentThread();
2994 // Note that we only have to check the recursion count for the current
2995 // cooperative thread. Since the Shutdown message is not labeled with a
2996 // SchedulerGroup, there can be no other cooperative threads doing work while
2997 // we're running.
2998 if (mainThread && mainThread->RecursionDepth() > 1) {
2999 // We're in a nested event loop. Let's delay for an arbitrary period of
3000 // time (100ms) in the hopes that the event loop will have finished by
3001 // then.
3002 GetCurrentSerialEventTarget()->DelayedDispatch(
3003 NewRunnableMethod("dom::ContentChild::RecvShutdown", this,
3004 &ContentChild::ShutdownInternal),
3005 100);
3006 return;
3009 mShuttingDown = true;
3011 #ifdef NIGHTLY_BUILD
3012 BackgroundHangMonitor::UnregisterAnnotator(
3013 PendingInputEventHangAnnotator::sSingleton);
3014 #endif
3016 if (mPolicy) {
3017 mPolicy->Deactivate();
3018 mPolicy = nullptr;
3021 nsCOMPtr<nsIObserverService> os = services::GetObserverService();
3022 if (os) {
3023 ProcessChild::AppendToIPCShutdownStateAnnotation(
3024 "content-child-shutdown started"_ns);
3025 os->NotifyObservers(ToSupports(this), "content-child-shutdown", nullptr);
3028 GetIPCChannel()->SetAbortOnError(false);
3030 if (mProfilerController) {
3031 const bool isProfiling = profiler_is_active();
3032 CrashReporter::RecordAnnotationCString(
3033 CrashReporter::Annotation::ProfilerChildShutdownPhase,
3034 isProfiling ? "Profiling - GrabShutdownProfileAndShutdown"
3035 : "Not profiling - GrabShutdownProfileAndShutdown");
3036 ProfileAndAdditionalInformation shutdownProfileAndAdditionalInformation =
3037 mProfilerController->GrabShutdownProfileAndShutdown();
3038 CrashReporter::RecordAnnotationCString(
3039 CrashReporter::Annotation::ProfilerChildShutdownPhase,
3040 isProfiling ? "Profiling - Destroying ChildProfilerController"
3041 : "Not profiling - Destroying ChildProfilerController");
3042 mProfilerController = nullptr;
3043 CrashReporter::RecordAnnotationCString(
3044 CrashReporter::Annotation::ProfilerChildShutdownPhase,
3045 isProfiling ? "Profiling - SendShutdownProfile (sending)"
3046 : "Not profiling - SendShutdownProfile (sending)");
3047 if (const size_t len = shutdownProfileAndAdditionalInformation.SizeOf();
3048 len >= size_t(IPC::Channel::kMaximumMessageSize)) {
3049 shutdownProfileAndAdditionalInformation.mProfile = nsPrintfCString(
3050 "*Profile from pid %u bigger (%zu) than IPC max (%zu)",
3051 unsigned(profiler_current_process_id().ToNumber()), len,
3052 size_t(IPC::Channel::kMaximumMessageSize));
3054 // Send the shutdown profile to the parent process through our own
3055 // message channel, which we know will survive for long enough.
3056 bool sent =
3057 SendShutdownProfile(shutdownProfileAndAdditionalInformation.mProfile);
3058 CrashReporter::RecordAnnotationCString(
3059 CrashReporter::Annotation::ProfilerChildShutdownPhase,
3060 sent ? (isProfiling ? "Profiling - SendShutdownProfile (sent)"
3061 : "Not profiling - SendShutdownProfile (sent)")
3062 : (isProfiling ? "Profiling - SendShutdownProfile (failed)"
3063 : "Not profiling - SendShutdownProfile (failed)"));
3066 if (PerfStats::GetCollectionMask() != 0) {
3067 SendShutdownPerfStats(PerfStats::CollectLocalPerfStatsJSON());
3070 // Start a timer that will ensure we quickly exit after a reasonable period
3071 // of time. Prevents shutdown hangs after our connection to the parent
3072 // closes or when the parent is too busy to ever kill us.
3073 ProcessChild::AppendToIPCShutdownStateAnnotation("StartForceKillTimer"_ns);
3074 StartForceKillTimer();
3076 ProcessChild::AppendToIPCShutdownStateAnnotation(
3077 "SendFinishShutdown (sending)"_ns);
3079 // Notify the parent that we are done with shutdown. This is sent with high
3080 // priority and will just flag we are done.
3081 Unused << SendNotifyShutdownSuccess();
3083 // Now tell the parent to actually destroy our channel which will make end
3084 // our process. This is expected to be the last event the parent will
3085 // ever process for this ContentChild.
3086 bool sent = SendFinishShutdown();
3088 ProcessChild::AppendToIPCShutdownStateAnnotation(
3089 sent ? "SendFinishShutdown (sent)"_ns : "SendFinishShutdown (failed)"_ns);
3092 mozilla::ipc::IPCResult ContentChild::RecvUpdateWindow(
3093 const uintptr_t& aChildId) {
3094 MOZ_ASSERT(
3095 false,
3096 "ContentChild::RecvUpdateWindow calls unexpected on this platform.");
3097 return IPC_FAIL_NO_REASON(this);
3100 PContentPermissionRequestChild*
3101 ContentChild::AllocPContentPermissionRequestChild(
3102 Span<const PermissionRequest> aRequests, nsIPrincipal* aPrincipal,
3103 nsIPrincipal* aTopLevelPrincipal, const bool& aIsHandlingUserInput,
3104 const bool& aMaybeUnsafePermissionDelegate, const TabId& aTabId) {
3105 MOZ_CRASH("unused");
3106 return nullptr;
3109 bool ContentChild::DeallocPContentPermissionRequestChild(
3110 PContentPermissionRequestChild* actor) {
3111 nsContentPermissionUtils::NotifyRemoveContentPermissionRequestChild(actor);
3112 auto child = static_cast<RemotePermissionRequest*>(actor);
3113 child->IPDLRelease();
3114 return true;
3117 already_AddRefed<PWebBrowserPersistDocumentChild>
3118 ContentChild::AllocPWebBrowserPersistDocumentChild(
3119 PBrowserChild* aBrowser, const MaybeDiscarded<BrowsingContext>& aContext) {
3120 return MakeAndAddRef<WebBrowserPersistDocumentChild>();
3123 mozilla::ipc::IPCResult ContentChild::RecvPWebBrowserPersistDocumentConstructor(
3124 PWebBrowserPersistDocumentChild* aActor, PBrowserChild* aBrowser,
3125 const MaybeDiscarded<BrowsingContext>& aContext) {
3126 if (NS_WARN_IF(!aBrowser)) {
3127 return IPC_FAIL_NO_REASON(this);
3130 if (aContext.IsNullOrDiscarded()) {
3131 aActor->SendInitFailure(NS_ERROR_NO_CONTENT);
3132 return IPC_OK();
3135 nsCOMPtr<Document> foundDoc = aContext.get()->GetDocument();
3137 if (!foundDoc) {
3138 aActor->SendInitFailure(NS_ERROR_NO_CONTENT);
3139 } else {
3140 static_cast<WebBrowserPersistDocumentChild*>(aActor)->Start(foundDoc);
3142 return IPC_OK();
3145 static already_AddRefed<DataTransfer> ConvertToDataTransfer(
3146 nsTArray<IPCTransferableData>&& aTransferables, EventMessage aMessage) {
3147 // Check if we are receiving any file objects. If we are we will want
3148 // to hide any of the other objects coming in from content.
3149 bool hasFiles = false;
3150 for (uint32_t i = 0; i < aTransferables.Length() && !hasFiles; ++i) {
3151 auto& items = aTransferables[i].items();
3152 for (uint32_t j = 0; j < items.Length() && !hasFiles; ++j) {
3153 if (items[j].data().type() ==
3154 IPCTransferableDataType::TIPCTransferableDataBlob) {
3155 hasFiles = true;
3159 // Add the entries from the IPC to the new DataTransfer
3160 RefPtr<DataTransfer> dataTransfer =
3161 new DataTransfer(nullptr, aMessage, false, -1);
3162 for (uint32_t i = 0; i < aTransferables.Length(); ++i) {
3163 auto& items = aTransferables[i].items();
3164 for (uint32_t j = 0; j < items.Length(); ++j) {
3165 const IPCTransferableDataItem& item = items[j];
3166 RefPtr<nsVariantCC> variant = new nsVariantCC();
3167 nsresult rv =
3168 nsContentUtils::IPCTransferableDataItemToVariant(item, variant);
3169 if (NS_FAILED(rv)) {
3170 continue;
3173 // We should hide this data from content if we have a file, and we
3174 // aren't a file.
3175 bool hidden =
3176 hasFiles && item.data().type() !=
3177 IPCTransferableDataType::TIPCTransferableDataBlob;
3178 dataTransfer->SetDataWithPrincipalFromOtherProcess(
3179 NS_ConvertUTF8toUTF16(item.flavor()), variant, i,
3180 nsContentUtils::GetSystemPrincipal(), hidden);
3183 return dataTransfer.forget();
3186 mozilla::ipc::IPCResult ContentChild::RecvInvokeDragSession(
3187 const MaybeDiscarded<WindowContext>& aSourceWindowContext,
3188 const MaybeDiscarded<WindowContext>& aSourceTopWindowContext,
3189 nsTArray<IPCTransferableData>&& aTransferables, const uint32_t& aAction) {
3190 if (nsCOMPtr<nsIDragService> dragService =
3191 do_GetService("@mozilla.org/widget/dragservice;1")) {
3192 dragService->StartDragSession();
3193 nsCOMPtr<nsIDragSession> session;
3194 dragService->GetCurrentSession(getter_AddRefs(session));
3195 if (session) {
3196 session->SetSourceWindowContext(aSourceWindowContext.GetMaybeDiscarded());
3197 session->SetSourceTopWindowContext(
3198 aSourceTopWindowContext.GetMaybeDiscarded());
3199 session->SetDragAction(aAction);
3201 RefPtr<DataTransfer> dataTransfer =
3202 ConvertToDataTransfer(std::move(aTransferables), eDragStart);
3203 session->SetDataTransfer(dataTransfer);
3206 return IPC_OK();
3209 mozilla::ipc::IPCResult ContentChild::RecvUpdateDragSession(
3210 nsTArray<IPCTransferableData>&& aTransferables,
3211 EventMessage aEventMessage) {
3212 if (nsCOMPtr<nsIDragService> dragService =
3213 do_GetService("@mozilla.org/widget/dragservice;1")) {
3214 nsCOMPtr<nsIDragSession> session;
3215 dragService->GetCurrentSession(getter_AddRefs(session));
3216 if (session) {
3217 nsCOMPtr<DataTransfer> dataTransfer =
3218 ConvertToDataTransfer(std::move(aTransferables), aEventMessage);
3219 session->SetDataTransfer(dataTransfer);
3222 return IPC_OK();
3225 mozilla::ipc::IPCResult ContentChild::RecvEndDragSession(
3226 const bool& aDoneDrag, const bool& aUserCancelled,
3227 const LayoutDeviceIntPoint& aDragEndPoint, const uint32_t& aKeyModifiers,
3228 const uint32_t& aDropEffect) {
3229 nsCOMPtr<nsIDragService> dragService =
3230 do_GetService("@mozilla.org/widget/dragservice;1");
3231 if (dragService) {
3232 nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
3233 if (dragSession) {
3234 if (aUserCancelled) {
3235 dragSession->UserCancelled();
3238 RefPtr<DataTransfer> dataTransfer = dragSession->GetDataTransfer();
3239 if (dataTransfer) {
3240 dataTransfer->SetDropEffectInt(aDropEffect);
3244 static_cast<nsBaseDragService*>(dragService.get())
3245 ->SetDragEndPoint(aDragEndPoint);
3246 dragService->EndDragSession(aDoneDrag, aKeyModifiers);
3248 return IPC_OK();
3251 mozilla::ipc::IPCResult ContentChild::RecvPush(const nsCString& aScope,
3252 nsIPrincipal* aPrincipal,
3253 const nsString& aMessageId) {
3254 PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId, Nothing());
3255 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
3256 return IPC_OK();
3259 mozilla::ipc::IPCResult ContentChild::RecvPushWithData(
3260 const nsCString& aScope, nsIPrincipal* aPrincipal,
3261 const nsString& aMessageId, nsTArray<uint8_t>&& aData) {
3262 PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId,
3263 Some(std::move(aData)));
3264 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
3265 return IPC_OK();
3268 mozilla::ipc::IPCResult ContentChild::RecvPushSubscriptionChange(
3269 const nsCString& aScope, nsIPrincipal* aPrincipal) {
3270 PushSubscriptionChangeDispatcher dispatcher(aScope, aPrincipal);
3271 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
3272 return IPC_OK();
3275 mozilla::ipc::IPCResult ContentChild::RecvPushError(const nsCString& aScope,
3276 nsIPrincipal* aPrincipal,
3277 const nsString& aMessage,
3278 const uint32_t& aFlags) {
3279 PushErrorDispatcher dispatcher(aScope, aPrincipal, aMessage, aFlags);
3280 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
3281 return IPC_OK();
3284 mozilla::ipc::IPCResult
3285 ContentChild::RecvNotifyPushSubscriptionModifiedObservers(
3286 const nsCString& aScope, nsIPrincipal* aPrincipal) {
3287 PushSubscriptionModifiedDispatcher dispatcher(aScope, aPrincipal);
3288 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers()));
3289 return IPC_OK();
3292 mozilla::ipc::IPCResult ContentChild::RecvBlobURLRegistration(
3293 const nsCString& aURI, const IPCBlob& aBlob, nsIPrincipal* aPrincipal,
3294 const nsCString& aPartitionKey) {
3295 RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(aBlob);
3296 MOZ_ASSERT(blobImpl);
3298 BlobURLProtocolHandler::AddDataEntry(aURI, aPrincipal, aPartitionKey,
3299 blobImpl);
3300 return IPC_OK();
3303 mozilla::ipc::IPCResult ContentChild::RecvBlobURLUnregistration(
3304 const nsCString& aURI) {
3305 BlobURLProtocolHandler::RemoveDataEntry(
3306 aURI,
3307 /* aBroadcastToOtherProcesses = */ false);
3308 return IPC_OK();
3311 void ContentChild::CreateGetFilesRequest(const nsAString& aDirectoryPath,
3312 bool aRecursiveFlag, nsID& aUUID,
3313 GetFilesHelperChild* aChild) {
3314 MOZ_ASSERT(aChild);
3315 MOZ_ASSERT(!mGetFilesPendingRequests.Contains(aUUID));
3317 Unused << SendGetFilesRequest(aUUID, aDirectoryPath, aRecursiveFlag);
3318 mGetFilesPendingRequests.InsertOrUpdate(aUUID, RefPtr{aChild});
3321 void ContentChild::DeleteGetFilesRequest(nsID& aUUID,
3322 GetFilesHelperChild* aChild) {
3323 MOZ_ASSERT(aChild);
3324 MOZ_ASSERT(mGetFilesPendingRequests.Contains(aUUID));
3326 Unused << SendDeleteGetFilesRequest(aUUID);
3327 mGetFilesPendingRequests.Remove(aUUID);
3330 mozilla::ipc::IPCResult ContentChild::RecvGetFilesResponse(
3331 const nsID& aUUID, const GetFilesResponseResult& aResult) {
3332 RefPtr<GetFilesHelperChild> child;
3334 // This object can already been deleted in case DeleteGetFilesRequest has
3335 // been called when the response was sending by the parent.
3336 if (!mGetFilesPendingRequests.Remove(aUUID, getter_AddRefs(child))) {
3337 return IPC_OK();
3340 if (aResult.type() == GetFilesResponseResult::TGetFilesResponseFailure) {
3341 child->Finished(aResult.get_GetFilesResponseFailure().errorCode());
3342 } else {
3343 MOZ_ASSERT(aResult.type() ==
3344 GetFilesResponseResult::TGetFilesResponseSuccess);
3346 const nsTArray<IPCBlob>& ipcBlobs =
3347 aResult.get_GetFilesResponseSuccess().blobs();
3349 bool succeeded = true;
3350 for (uint32_t i = 0; succeeded && i < ipcBlobs.Length(); ++i) {
3351 RefPtr<BlobImpl> impl = IPCBlobUtils::Deserialize(ipcBlobs[i]);
3352 succeeded = child->AppendBlobImpl(impl);
3355 child->Finished(succeeded ? NS_OK : NS_ERROR_OUT_OF_MEMORY);
3357 return IPC_OK();
3360 /* static */
3361 void ContentChild::FatalErrorIfNotUsingGPUProcess(const char* const aErrorMsg,
3362 base::ProcessId aOtherPid) {
3363 // If we're communicating with the same process or the UI process then we
3364 // want to crash normally. Otherwise we want to just warn as the other end
3365 // must be the GPU process and it crashing shouldn't be fatal for us.
3366 if (aOtherPid == base::GetCurrentProcId() ||
3367 (GetSingleton() && GetSingleton()->OtherPid() == aOtherPid)) {
3368 mozilla::ipc::FatalError(aErrorMsg, false);
3369 } else {
3370 nsAutoCString formattedMessage("IPDL error: \"");
3371 formattedMessage.AppendASCII(aErrorMsg);
3372 formattedMessage.AppendLiteral(R"(".)");
3373 NS_WARNING(formattedMessage.get());
3377 PURLClassifierChild* ContentChild::AllocPURLClassifierChild(
3378 nsIPrincipal* aPrincipal, bool* aSuccess) {
3379 *aSuccess = true;
3380 return new URLClassifierChild();
3383 bool ContentChild::DeallocPURLClassifierChild(PURLClassifierChild* aActor) {
3384 MOZ_ASSERT(aActor);
3385 delete aActor;
3386 return true;
3389 PURLClassifierLocalChild* ContentChild::AllocPURLClassifierLocalChild(
3390 nsIURI* aUri, Span<const IPCURLClassifierFeature> aFeatures) {
3391 return new URLClassifierLocalChild();
3394 bool ContentChild::DeallocPURLClassifierLocalChild(
3395 PURLClassifierLocalChild* aActor) {
3396 MOZ_ASSERT(aActor);
3397 delete aActor;
3398 return true;
3401 PSessionStorageObserverChild*
3402 ContentChild::AllocPSessionStorageObserverChild() {
3403 MOZ_CRASH(
3404 "PSessionStorageObserverChild actors should be manually constructed!");
3407 bool ContentChild::DeallocPSessionStorageObserverChild(
3408 PSessionStorageObserverChild* aActor) {
3409 MOZ_ASSERT(aActor);
3411 delete aActor;
3412 return true;
3415 mozilla::ipc::IPCResult ContentChild::RecvProvideAnonymousTemporaryFile(
3416 const uint64_t& aID, const FileDescOrError& aFDOrError) {
3417 mozilla::UniquePtr<AnonymousTemporaryFileCallback> callback;
3418 mPendingAnonymousTemporaryFiles.Remove(aID, &callback);
3419 MOZ_ASSERT(callback);
3421 PRFileDesc* prfile = nullptr;
3422 if (aFDOrError.type() == FileDescOrError::Tnsresult) {
3423 DebugOnly<nsresult> rv = aFDOrError.get_nsresult();
3424 MOZ_ASSERT(NS_FAILED(rv));
3425 } else {
3426 auto rawFD = aFDOrError.get_FileDescriptor().ClonePlatformHandle();
3427 prfile = PR_ImportFile(PROsfd(rawFD.release()));
3429 (*callback)(prfile);
3430 return IPC_OK();
3433 nsresult ContentChild::AsyncOpenAnonymousTemporaryFile(
3434 const AnonymousTemporaryFileCallback& aCallback) {
3435 MOZ_ASSERT(NS_IsMainThread());
3437 static uint64_t id = 0;
3438 auto newID = id++;
3439 if (!SendRequestAnonymousTemporaryFile(newID)) {
3440 return NS_ERROR_FAILURE;
3443 // Remember the association with the callback.
3444 MOZ_ASSERT(!mPendingAnonymousTemporaryFiles.Get(newID));
3445 mPendingAnonymousTemporaryFiles.GetOrInsertNew(newID, aCallback);
3446 return NS_OK;
3449 mozilla::ipc::IPCResult ContentChild::RecvSetPermissionsWithKey(
3450 const nsCString& aPermissionKey, nsTArray<IPC::Permission>&& aPerms) {
3451 RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
3452 if (permManager) {
3453 permManager->SetPermissionsWithKey(aPermissionKey, aPerms);
3456 return IPC_OK();
3459 mozilla::ipc::IPCResult ContentChild::RecvRefreshScreens(
3460 nsTArray<ScreenDetails>&& aScreens) {
3461 ScreenManager& screenManager = ScreenManager::GetSingleton();
3462 screenManager.Refresh(std::move(aScreens));
3463 return IPC_OK();
3466 mozilla::ipc::IPCResult ContentChild::RecvShareCodeCoverageMutex(
3467 CrossProcessMutexHandle aHandle) {
3468 #ifdef MOZ_CODE_COVERAGE
3469 CodeCoverageHandler::Init(std::move(aHandle));
3470 return IPC_OK();
3471 #else
3472 MOZ_CRASH("Shouldn't receive this message in non-code coverage builds!");
3473 #endif
3476 mozilla::ipc::IPCResult ContentChild::RecvFlushCodeCoverageCounters(
3477 FlushCodeCoverageCountersResolver&& aResolver) {
3478 #ifdef MOZ_CODE_COVERAGE
3479 CodeCoverageHandler::FlushCounters();
3480 aResolver(/* unused */ true);
3481 return IPC_OK();
3482 #else
3483 MOZ_CRASH("Shouldn't receive this message in non-code coverage builds!");
3484 #endif
3487 mozilla::ipc::IPCResult ContentChild::RecvSetInputEventQueueEnabled() {
3488 nsThreadManager::get().EnableMainThreadEventPrioritization();
3489 return IPC_OK();
3492 mozilla::ipc::IPCResult ContentChild::RecvFlushInputEventQueue() {
3493 nsThreadManager::get().FlushInputEventPrioritization();
3494 return IPC_OK();
3497 mozilla::ipc::IPCResult ContentChild::RecvSuspendInputEventQueue() {
3498 nsThreadManager::get().SuspendInputEventPrioritization();
3499 return IPC_OK();
3502 mozilla::ipc::IPCResult ContentChild::RecvResumeInputEventQueue() {
3503 nsThreadManager::get().ResumeInputEventPrioritization();
3504 return IPC_OK();
3507 mozilla::ipc::IPCResult ContentChild::RecvAddDynamicScalars(
3508 nsTArray<DynamicScalarDefinition>&& aDefs) {
3509 TelemetryIPC::AddDynamicScalarDefinitions(aDefs);
3510 return IPC_OK();
3513 mozilla::ipc::IPCResult ContentChild::RecvCrossProcessRedirect(
3514 RedirectToRealChannelArgs&& aArgs,
3515 nsTArray<Endpoint<extensions::PStreamFilterParent>>&& aEndpoints,
3516 CrossProcessRedirectResolver&& aResolve) {
3517 nsCOMPtr<nsILoadInfo> loadInfo;
3518 nsresult rv = mozilla::ipc::LoadInfoArgsToLoadInfo(
3519 aArgs.loadInfo(), NOT_REMOTE_TYPE, getter_AddRefs(loadInfo));
3520 if (NS_FAILED(rv)) {
3521 MOZ_DIAGNOSTIC_ASSERT(false, "LoadInfoArgsToLoadInfo failed");
3522 return IPC_OK();
3525 nsCOMPtr<nsIChannel> newChannel;
3526 MOZ_ASSERT((aArgs.loadStateInternalLoadFlags() &
3527 nsDocShell::InternalLoad::INTERNAL_LOAD_FLAGS_IS_SRCDOC) ||
3528 aArgs.srcdocData().IsVoid());
3529 rv = nsDocShell::CreateRealChannelForDocument(
3530 getter_AddRefs(newChannel), aArgs.uri(), loadInfo, nullptr,
3531 aArgs.newLoadFlags(), aArgs.srcdocData(), aArgs.baseUri());
3533 if (RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(newChannel)) {
3534 httpChannel->SetEarlyHints(std::move(aArgs.earlyHints()));
3535 httpChannel->SetEarlyHintLinkType(aArgs.earlyHintLinkType());
3538 // This is used to report any errors back to the parent by calling
3539 // CrossProcessRedirectFinished.
3540 RefPtr<HttpChannelChild> httpChild = do_QueryObject(newChannel);
3541 auto resolve = [=](const nsresult& aRv) {
3542 nsresult rv = aRv;
3543 if (httpChild) {
3544 rv = httpChild->CrossProcessRedirectFinished(rv);
3546 aResolve(rv);
3548 auto scopeExit = MakeScopeExit([&]() { resolve(rv); });
3550 if (NS_FAILED(rv)) {
3551 return IPC_OK();
3554 if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel)) {
3555 rv = httpChannel->SetChannelId(aArgs.channelId());
3557 if (NS_FAILED(rv)) {
3558 return IPC_OK();
3561 rv = newChannel->SetOriginalURI(aArgs.originalURI());
3562 if (NS_FAILED(rv)) {
3563 return IPC_OK();
3566 if (nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
3567 do_QueryInterface(newChannel)) {
3568 rv = httpChannelInternal->SetRedirectMode(aArgs.redirectMode());
3570 if (NS_FAILED(rv)) {
3571 return IPC_OK();
3574 if (aArgs.init()) {
3575 HttpBaseChannel::ReplacementChannelConfig config(std::move(*aArgs.init()));
3576 HttpBaseChannel::ConfigureReplacementChannel(
3577 newChannel, config,
3578 HttpBaseChannel::ReplacementReason::DocumentChannel);
3581 if (aArgs.contentDisposition()) {
3582 newChannel->SetContentDisposition(*aArgs.contentDisposition());
3585 if (aArgs.contentDispositionFilename()) {
3586 newChannel->SetContentDispositionFilename(
3587 *aArgs.contentDispositionFilename());
3590 if (nsCOMPtr<nsIChildChannel> childChannel = do_QueryInterface(newChannel)) {
3591 // Connect to the parent if this is a remote channel. If it's entirely
3592 // handled locally, then we'll call AsyncOpen from the docshell when
3593 // we complete the setup
3594 rv = childChannel->ConnectParent(
3595 aArgs.registrarId()); // creates parent channel
3596 if (NS_FAILED(rv)) {
3597 return IPC_OK();
3601 // We need to copy the property bag before signaling that the channel
3602 // is ready so that the nsDocShell can retrieve the history data when called.
3603 if (nsCOMPtr<nsIWritablePropertyBag> bag = do_QueryInterface(newChannel)) {
3604 nsHashPropertyBag::CopyFrom(bag, aArgs.properties());
3607 RefPtr<nsDocShellLoadState> loadState;
3608 rv = nsDocShellLoadState::CreateFromPendingChannel(
3609 newChannel, aArgs.loadIdentifier(), aArgs.registrarId(),
3610 getter_AddRefs(loadState));
3611 if (NS_WARN_IF(NS_FAILED(rv))) {
3612 return IPC_OK();
3614 loadState->SetLoadFlags(aArgs.loadStateExternalLoadFlags());
3615 loadState->SetInternalLoadFlags(aArgs.loadStateInternalLoadFlags());
3616 if (IsValidLoadType(aArgs.loadStateLoadType())) {
3617 loadState->SetLoadType(aArgs.loadStateLoadType());
3620 if (aArgs.loadingSessionHistoryInfo().isSome()) {
3621 loadState->SetLoadingSessionHistoryInfo(
3622 aArgs.loadingSessionHistoryInfo().ref());
3624 if (aArgs.originalUriString().isSome()) {
3625 loadState->SetOriginalURIString(aArgs.originalUriString().ref());
3628 RefPtr<ChildProcessChannelListener> processListener =
3629 ChildProcessChannelListener::GetSingleton();
3630 // The listener will call completeRedirectSetup or asyncOpen on the channel.
3631 processListener->OnChannelReady(loadState, aArgs.loadIdentifier(),
3632 std::move(aEndpoints), aArgs.timing(),
3633 std::move(resolve));
3634 scopeExit.release();
3636 // scopeExit will call CrossProcessRedirectFinished(rv) here
3637 return IPC_OK();
3640 mozilla::ipc::IPCResult ContentChild::RecvStartDelayedAutoplayMediaComponents(
3641 const MaybeDiscarded<BrowsingContext>& aContext) {
3642 if (NS_WARN_IF(aContext.IsNullOrDiscarded())) {
3643 return IPC_OK();
3646 aContext.get()->StartDelayedAutoplayMediaComponents();
3647 return IPC_OK();
3650 mozilla::ipc::IPCResult ContentChild::RecvUpdateMediaControlAction(
3651 const MaybeDiscarded<BrowsingContext>& aContext,
3652 const MediaControlAction& aAction) {
3653 if (NS_WARN_IF(aContext.IsNullOrDiscarded())) {
3654 return IPC_OK();
3657 ContentMediaControlKeyHandler::HandleMediaControlAction(aContext.get(),
3658 aAction);
3659 return IPC_OK();
3662 mozilla::ipc::IPCResult ContentChild::RecvOnAllowAccessFor(
3663 const MaybeDiscarded<BrowsingContext>& aContext,
3664 const nsCString& aTrackingOrigin, uint32_t aCookieBehavior,
3665 const ContentBlockingNotifier::StorageAccessPermissionGrantedReason&
3666 aReason) {
3667 MOZ_ASSERT(!aContext.IsNull(), "Browsing context cannot be null");
3669 StorageAccessAPIHelper::OnAllowAccessFor(
3670 aContext.GetMaybeDiscarded(), aTrackingOrigin, aCookieBehavior, aReason);
3672 return IPC_OK();
3675 mozilla::ipc::IPCResult ContentChild::RecvOnContentBlockingDecision(
3676 const MaybeDiscarded<BrowsingContext>& aContext,
3677 const ContentBlockingNotifier::BlockingDecision& aDecision,
3678 uint32_t aRejectedReason) {
3679 MOZ_ASSERT(!aContext.IsNull(), "Browsing context cannot be null");
3681 nsCOMPtr<nsPIDOMWindowOuter> outer = aContext.get()->GetDOMWindow();
3682 if (!outer) {
3683 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
3684 ("ChildIPC: Trying to send a message to a context without a outer "
3685 "window"));
3686 return IPC_OK();
3689 nsCOMPtr<nsPIDOMWindowInner> inner = outer->GetCurrentInnerWindow();
3690 if (!inner) {
3691 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
3692 ("ChildIPC: Trying to send a message to a context without a inner "
3693 "window"));
3694 return IPC_OK();
3697 ContentBlockingNotifier::OnDecision(inner, aDecision, aRejectedReason);
3698 return IPC_OK();
3701 #ifdef NIGHTLY_BUILD
3702 void ContentChild::OnChannelReceivedMessage(const Message& aMsg) {
3703 if (nsContentUtils::IsMessageInputEvent(aMsg)) {
3704 mPendingInputEvents++;
3708 PContentChild::Result ContentChild::OnMessageReceived(const Message& aMsg) {
3709 if (nsContentUtils::IsMessageInputEvent(aMsg)) {
3710 DebugOnly<uint32_t> prevEvts = mPendingInputEvents--;
3711 MOZ_ASSERT(prevEvts > 0);
3714 return PContentChild::OnMessageReceived(aMsg);
3717 PContentChild::Result ContentChild::OnMessageReceived(
3718 const Message& aMsg, UniquePtr<Message>& aReply) {
3719 return PContentChild::OnMessageReceived(aMsg, aReply);
3721 #endif
3723 mozilla::ipc::IPCResult ContentChild::RecvCreateBrowsingContext(
3724 uint64_t aGroupId, BrowsingContext::IPCInitializer&& aInit) {
3725 // We can't already have a BrowsingContext with this ID.
3726 if (RefPtr<BrowsingContext> existing = BrowsingContext::Get(aInit.mId)) {
3727 return IPC_FAIL(this, "Browsing context already exists");
3730 RefPtr<WindowContext> parent = WindowContext::GetById(aInit.mParentId);
3731 if (!parent && aInit.mParentId != 0) {
3732 // Handle this case by ignoring the request, as parent must be in the
3733 // process of being discarded.
3734 // In the future it would be nice to avoid sending this message to the child
3735 // at all.
3736 NS_WARNING("Attempt to attach BrowsingContext to discarded parent");
3737 return IPC_OK();
3740 RefPtr<BrowsingContextGroup> group =
3741 BrowsingContextGroup::GetOrCreate(aGroupId);
3742 return BrowsingContext::CreateFromIPC(std::move(aInit), group, nullptr);
3745 mozilla::ipc::IPCResult ContentChild::RecvDiscardBrowsingContext(
3746 const MaybeDiscarded<BrowsingContext>& aContext, bool aDoDiscard,
3747 DiscardBrowsingContextResolver&& aResolve) {
3748 if (BrowsingContext* context = aContext.GetMaybeDiscarded()) {
3749 if (aDoDiscard && !context->IsDiscarded()) {
3750 context->Detach(/* aFromIPC */ true);
3752 context->AddDiscardListener(aResolve);
3753 return IPC_OK();
3756 // Immediately resolve the promise, as we've received the message. This will
3757 // allow the parent process to discard references to this BC.
3758 aResolve(true);
3759 return IPC_OK();
3762 mozilla::ipc::IPCResult ContentChild::RecvRegisterBrowsingContextGroup(
3763 uint64_t aGroupId, nsTArray<SyncedContextInitializer>&& aInits) {
3764 RefPtr<BrowsingContextGroup> group =
3765 BrowsingContextGroup::GetOrCreate(aGroupId);
3767 // Each of the initializers in aInits is sorted in pre-order, so our parent
3768 // should always be available before the element itself.
3769 for (auto& initUnion : aInits) {
3770 switch (initUnion.type()) {
3771 case SyncedContextInitializer::TBrowsingContextInitializer: {
3772 auto& init = initUnion.get_BrowsingContextInitializer();
3773 #ifdef DEBUG
3774 RefPtr<BrowsingContext> existing = BrowsingContext::Get(init.mId);
3775 MOZ_ASSERT(!existing, "BrowsingContext must not exist yet!");
3777 RefPtr<WindowContext> parent = init.GetParent();
3778 MOZ_ASSERT_IF(parent, parent->Group() == group);
3779 #endif
3781 BrowsingContext::CreateFromIPC(std::move(init), group, nullptr);
3782 break;
3784 case SyncedContextInitializer::TWindowContextInitializer: {
3785 auto& init = initUnion.get_WindowContextInitializer();
3786 #ifdef DEBUG
3787 RefPtr<WindowContext> existing =
3788 WindowContext::GetById(init.mInnerWindowId);
3789 MOZ_ASSERT(!existing, "WindowContext must not exist yet!");
3790 RefPtr<BrowsingContext> parent =
3791 BrowsingContext::Get(init.mBrowsingContextId);
3792 MOZ_ASSERT(parent && parent->Group() == group);
3793 #endif
3795 WindowContext::CreateFromIPC(std::move(init));
3796 break;
3798 default:
3799 MOZ_ASSERT_UNREACHABLE();
3803 return IPC_OK();
3806 mozilla::ipc::IPCResult ContentChild::RecvDestroyBrowsingContextGroup(
3807 uint64_t aGroupId) {
3808 if (RefPtr<BrowsingContextGroup> group =
3809 BrowsingContextGroup::GetExisting(aGroupId)) {
3810 group->ChildDestroy();
3812 return IPC_OK();
3815 mozilla::ipc::IPCResult ContentChild::RecvWindowClose(
3816 const MaybeDiscarded<BrowsingContext>& aContext, bool aTrustedCaller) {
3817 if (aContext.IsNullOrDiscarded()) {
3818 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
3819 ("ChildIPC: Trying to send a message to dead or detached context"));
3820 return IPC_OK();
3823 nsCOMPtr<nsPIDOMWindowOuter> window = aContext.get()->GetDOMWindow();
3824 if (!window) {
3825 MOZ_LOG(
3826 BrowsingContext::GetLog(), LogLevel::Debug,
3827 ("ChildIPC: Trying to send a message to a context without a window"));
3828 return IPC_OK();
3831 // Call `GetDocument()` to force the document and its inner window to be
3832 // created, as it would be forced to be created if this call was being
3833 // performed in-process.
3834 if (NS_WARN_IF(!aContext.get()->GetDocument())) {
3835 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
3836 ("ChildIPC: Trying to send a message to a context but document "
3837 "creation failed"));
3838 return IPC_OK();
3841 nsGlobalWindowOuter::Cast(window)->CloseOuter(aTrustedCaller);
3842 return IPC_OK();
3845 mozilla::ipc::IPCResult ContentChild::RecvWindowFocus(
3846 const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType,
3847 uint64_t aActionId) {
3848 if (aContext.IsNullOrDiscarded()) {
3849 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
3850 ("ChildIPC: Trying to send a message to dead or detached context"));
3851 return IPC_OK();
3854 nsCOMPtr<nsPIDOMWindowOuter> window = aContext.get()->GetDOMWindow();
3855 if (!window) {
3856 MOZ_LOG(
3857 BrowsingContext::GetLog(), LogLevel::Debug,
3858 ("ChildIPC: Trying to send a message to a context without a window"));
3859 return IPC_OK();
3862 // Call `GetDocument()` to force the document and its inner window to be
3863 // created, as it would be forced to be created if this call was being
3864 // performed in-process.
3865 if (NS_WARN_IF(!aContext.get()->GetDocument())) {
3866 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
3867 ("ChildIPC: Trying to send a message to a context but document "
3868 "creation failed"));
3869 return IPC_OK();
3872 nsGlobalWindowOuter::Cast(window)->FocusOuter(
3873 aCallerType, /* aFromOtherProcess */ true, aActionId);
3874 return IPC_OK();
3877 mozilla::ipc::IPCResult ContentChild::RecvWindowBlur(
3878 const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType) {
3879 if (aContext.IsNullOrDiscarded()) {
3880 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
3881 ("ChildIPC: Trying to send a message to dead or detached context"));
3882 return IPC_OK();
3885 nsCOMPtr<nsPIDOMWindowOuter> window = aContext.get()->GetDOMWindow();
3886 if (!window) {
3887 MOZ_LOG(
3888 BrowsingContext::GetLog(), LogLevel::Debug,
3889 ("ChildIPC: Trying to send a message to a context without a window"));
3890 return IPC_OK();
3893 // Call `GetDocument()` to force the document and its inner window to be
3894 // created, as it would be forced to be created if this call was being
3895 // performed in-process.
3896 if (NS_WARN_IF(!aContext.get()->GetDocument())) {
3897 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
3898 ("ChildIPC: Trying to send a message to a context but document "
3899 "creation failed"));
3900 return IPC_OK();
3903 nsGlobalWindowOuter::Cast(window)->BlurOuter(aCallerType);
3904 return IPC_OK();
3907 mozilla::ipc::IPCResult ContentChild::RecvRaiseWindow(
3908 const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType,
3909 uint64_t aActionId) {
3910 if (aContext.IsNullOrDiscarded()) {
3911 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
3912 ("ChildIPC: Trying to send a message to dead or detached context"));
3913 return IPC_OK();
3916 nsCOMPtr<nsPIDOMWindowOuter> window = aContext.get()->GetDOMWindow();
3917 if (!window) {
3918 MOZ_LOG(
3919 BrowsingContext::GetLog(), LogLevel::Debug,
3920 ("ChildIPC: Trying to send a message to a context without a window"));
3921 return IPC_OK();
3924 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
3925 fm->RaiseWindow(window, aCallerType, aActionId);
3927 return IPC_OK();
3930 mozilla::ipc::IPCResult ContentChild::RecvAdjustWindowFocus(
3931 const MaybeDiscarded<BrowsingContext>& aContext, bool aIsVisible,
3932 uint64_t aActionId) {
3933 if (aContext.IsNullOrDiscarded()) {
3934 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
3935 ("ChildIPC: Trying to send a message to dead or detached context"));
3936 return IPC_OK();
3939 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
3940 RefPtr<BrowsingContext> bc = aContext.get();
3941 fm->AdjustInProcessWindowFocus(bc, false, aIsVisible, aActionId);
3943 return IPC_OK();
3946 mozilla::ipc::IPCResult ContentChild::RecvClearFocus(
3947 const MaybeDiscarded<BrowsingContext>& aContext) {
3948 if (aContext.IsNullOrDiscarded()) {
3949 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
3950 ("ChildIPC: Trying to send a message to dead or detached context"));
3951 return IPC_OK();
3954 nsCOMPtr<nsPIDOMWindowOuter> window = aContext.get()->GetDOMWindow();
3955 if (!window) {
3956 MOZ_LOG(
3957 BrowsingContext::GetLog(), LogLevel::Debug,
3958 ("ChildIPC: Trying to send a message to a context without a window"));
3959 return IPC_OK();
3962 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
3963 fm->ClearFocus(window);
3965 return IPC_OK();
3968 mozilla::ipc::IPCResult ContentChild::RecvSetFocusedBrowsingContext(
3969 const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
3970 if (aContext.IsNullOrDiscarded()) {
3971 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
3972 ("ChildIPC: Trying to send a message to dead or detached context"));
3973 return IPC_OK();
3976 nsFocusManager* fm = nsFocusManager::GetFocusManager();
3977 if (fm) {
3978 fm->SetFocusedBrowsingContextFromOtherProcess(aContext.get(), aActionId);
3980 return IPC_OK();
3983 mozilla::ipc::IPCResult ContentChild::RecvSetActiveBrowsingContext(
3984 const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
3985 if (aContext.IsNullOrDiscarded()) {
3986 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
3987 ("ChildIPC: Trying to send a message to dead or detached context"));
3988 return IPC_OK();
3991 nsFocusManager* fm = nsFocusManager::GetFocusManager();
3992 if (fm) {
3993 fm->SetActiveBrowsingContextFromOtherProcess(aContext.get(), aActionId);
3995 return IPC_OK();
3998 mozilla::ipc::IPCResult ContentChild::RecvAbortOrientationPendingPromises(
3999 const MaybeDiscarded<BrowsingContext>& aContext) {
4000 if (aContext.IsNullOrDiscarded()) {
4001 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
4002 ("ChildIPC: Trying to send a message to dead or detached context"));
4003 return IPC_OK();
4006 dom::ScreenOrientation::AbortInProcessOrientationPromises(aContext.get());
4007 return IPC_OK();
4010 mozilla::ipc::IPCResult ContentChild::RecvUnsetActiveBrowsingContext(
4011 const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
4012 if (aContext.IsNullOrDiscarded()) {
4013 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
4014 ("ChildIPC: Trying to send a message to dead or detached context"));
4015 return IPC_OK();
4018 nsFocusManager* fm = nsFocusManager::GetFocusManager();
4019 if (fm) {
4020 fm->UnsetActiveBrowsingContextFromOtherProcess(aContext.get(), aActionId);
4022 return IPC_OK();
4025 mozilla::ipc::IPCResult ContentChild::RecvSetFocusedElement(
4026 const MaybeDiscarded<BrowsingContext>& aContext, bool aNeedsFocus) {
4027 if (aContext.IsNullOrDiscarded()) {
4028 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
4029 ("ChildIPC: Trying to send a message to dead or detached context"));
4030 return IPC_OK();
4033 nsCOMPtr<nsPIDOMWindowOuter> window = aContext.get()->GetDOMWindow();
4034 if (!window) {
4035 MOZ_LOG(
4036 BrowsingContext::GetLog(), LogLevel::Debug,
4037 ("ChildIPC: Trying to send a message to a context without a window"));
4038 return IPC_OK();
4041 window->SetFocusedElement(nullptr, 0, aNeedsFocus);
4042 return IPC_OK();
4045 mozilla::ipc::IPCResult ContentChild::RecvFinalizeFocusOuter(
4046 const MaybeDiscarded<BrowsingContext>& aContext, bool aCanFocus,
4047 CallerType aCallerType) {
4048 if (aContext.IsNullOrDiscarded()) {
4049 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
4050 ("ChildIPC: Trying to send a message to dead or detached context"));
4051 return IPC_OK();
4054 if (Element* frame = aContext.get()->GetEmbedderElement()) {
4055 nsContentUtils::RequestFrameFocus(*frame, aCanFocus, aCallerType);
4058 return IPC_OK();
4061 mozilla::ipc::IPCResult ContentChild::RecvBlurToChild(
4062 const MaybeDiscarded<BrowsingContext>& aFocusedBrowsingContext,
4063 const MaybeDiscarded<BrowsingContext>& aBrowsingContextToClear,
4064 const MaybeDiscarded<BrowsingContext>& aAncestorBrowsingContextToFocus,
4065 bool aIsLeavingDocument, bool aAdjustWidget, uint64_t aActionId) {
4066 if (aFocusedBrowsingContext.IsNullOrDiscarded()) {
4067 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
4068 ("ChildIPC: Trying to send a message to dead or detached context"));
4069 return IPC_OK();
4072 RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager();
4073 if (MOZ_UNLIKELY(!fm)) {
4074 return IPC_OK();
4077 RefPtr<BrowsingContext> toClear = aBrowsingContextToClear.IsDiscarded()
4078 ? nullptr
4079 : aBrowsingContextToClear.get();
4080 RefPtr<BrowsingContext> toFocus =
4081 aAncestorBrowsingContextToFocus.IsDiscarded()
4082 ? nullptr
4083 : aAncestorBrowsingContextToFocus.get();
4085 RefPtr<BrowsingContext> focusedBrowsingContext =
4086 aFocusedBrowsingContext.get();
4088 fm->BlurFromOtherProcess(focusedBrowsingContext, toClear, toFocus,
4089 aIsLeavingDocument, aAdjustWidget, aActionId);
4090 return IPC_OK();
4093 mozilla::ipc::IPCResult ContentChild::RecvSetupFocusedAndActive(
4094 const MaybeDiscarded<BrowsingContext>& aFocusedBrowsingContext,
4095 uint64_t aActionIdForFocused,
4096 const MaybeDiscarded<BrowsingContext>& aActiveBrowsingContext,
4097 uint64_t aActionIdForActive) {
4098 nsFocusManager* fm = nsFocusManager::GetFocusManager();
4099 if (fm) {
4100 if (!aActiveBrowsingContext.IsNullOrDiscarded()) {
4101 fm->SetActiveBrowsingContextFromOtherProcess(aActiveBrowsingContext.get(),
4102 aActionIdForActive);
4104 if (!aFocusedBrowsingContext.IsNullOrDiscarded()) {
4105 fm->SetFocusedBrowsingContextFromOtherProcess(
4106 aFocusedBrowsingContext.get(), aActionIdForFocused);
4109 return IPC_OK();
4112 mozilla::ipc::IPCResult ContentChild::RecvReviseActiveBrowsingContext(
4113 uint64_t aOldActionId,
4114 const MaybeDiscarded<BrowsingContext>& aActiveBrowsingContext,
4115 uint64_t aNewActionId) {
4116 nsFocusManager* fm = nsFocusManager::GetFocusManager();
4117 if (fm && !aActiveBrowsingContext.IsNullOrDiscarded()) {
4118 fm->ReviseActiveBrowsingContext(aOldActionId, aActiveBrowsingContext.get(),
4119 aNewActionId);
4121 return IPC_OK();
4124 mozilla::ipc::IPCResult ContentChild::RecvReviseFocusedBrowsingContext(
4125 uint64_t aOldActionId,
4126 const MaybeDiscarded<BrowsingContext>& aFocusedBrowsingContext,
4127 uint64_t aNewActionId) {
4128 nsFocusManager* fm = nsFocusManager::GetFocusManager();
4129 if (fm && !aFocusedBrowsingContext.IsNullOrDiscarded()) {
4130 fm->ReviseFocusedBrowsingContext(
4131 aOldActionId, aFocusedBrowsingContext.get(), aNewActionId);
4133 return IPC_OK();
4136 mozilla::ipc::IPCResult ContentChild::RecvMaybeExitFullscreen(
4137 const MaybeDiscarded<BrowsingContext>& aContext) {
4138 if (aContext.IsNullOrDiscarded()) {
4139 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
4140 ("ChildIPC: Trying to send a message to dead or detached context"));
4141 return IPC_OK();
4144 nsIDocShell* shell = aContext.get()->GetDocShell();
4145 if (!shell) {
4146 return IPC_OK();
4149 Document* doc = shell->GetDocument();
4150 if (doc && doc->GetFullscreenElement()) {
4151 Document::AsyncExitFullscreen(doc);
4154 return IPC_OK();
4157 mozilla::ipc::IPCResult ContentChild::RecvWindowPostMessage(
4158 const MaybeDiscarded<BrowsingContext>& aContext,
4159 const ClonedOrErrorMessageData& aMessage, const PostMessageData& aData) {
4160 if (aContext.IsNullOrDiscarded()) {
4161 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
4162 ("ChildIPC: Trying to send a message to dead or detached context"));
4163 return IPC_OK();
4166 RefPtr<nsGlobalWindowOuter> window =
4167 nsGlobalWindowOuter::Cast(aContext.get()->GetDOMWindow());
4168 if (!window) {
4169 MOZ_LOG(
4170 BrowsingContext::GetLog(), LogLevel::Debug,
4171 ("ChildIPC: Trying to send a message to a context without a window"));
4172 return IPC_OK();
4175 nsCOMPtr<nsIPrincipal> providedPrincipal;
4176 if (!window->GetPrincipalForPostMessage(
4177 aData.targetOrigin(), aData.targetOriginURI(),
4178 aData.callerPrincipal(), *aData.subjectPrincipal(),
4179 getter_AddRefs(providedPrincipal))) {
4180 return IPC_OK();
4183 // Call `GetDocument()` to force the document and its inner window to be
4184 // created, as it would be forced to be created if this call was being
4185 // performed in-process.
4186 if (NS_WARN_IF(!aContext.get()->GetDocument())) {
4187 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
4188 ("ChildIPC: Trying to send a message to a context but document "
4189 "creation failed"));
4190 return IPC_OK();
4193 // It's OK if `sourceBc` has already been discarded, so long as we can
4194 // continue to wrap it.
4195 RefPtr<BrowsingContext> sourceBc = aData.source().GetMaybeDiscarded();
4197 // Create and asynchronously dispatch a runnable which will handle actual DOM
4198 // event creation and dispatch.
4199 RefPtr<PostMessageEvent> event =
4200 new PostMessageEvent(sourceBc, aData.origin(), window, providedPrincipal,
4201 aData.innerWindowId(), aData.callerURI(),
4202 aData.scriptLocation(), aData.isFromPrivateWindow());
4203 event->UnpackFrom(aMessage);
4205 event->DispatchToTargetThread(IgnoredErrorResult());
4206 return IPC_OK();
4209 mozilla::ipc::IPCResult ContentChild::RecvCommitBrowsingContextTransaction(
4210 const MaybeDiscarded<BrowsingContext>& aContext,
4211 BrowsingContext::BaseTransaction&& aTransaction, uint64_t aEpoch) {
4212 return aTransaction.CommitFromIPC(aContext, aEpoch, this);
4215 mozilla::ipc::IPCResult ContentChild::RecvCommitWindowContextTransaction(
4216 const MaybeDiscarded<WindowContext>& aContext,
4217 WindowContext::BaseTransaction&& aTransaction, uint64_t aEpoch) {
4218 return aTransaction.CommitFromIPC(aContext, aEpoch, this);
4221 mozilla::ipc::IPCResult ContentChild::RecvCreateWindowContext(
4222 WindowContext::IPCInitializer&& aInit) {
4223 RefPtr<BrowsingContext> bc = BrowsingContext::Get(aInit.mBrowsingContextId);
4224 if (!bc) {
4225 // Handle this case by ignoring the request, as bc must be in the process of
4226 // being discarded.
4227 // In the future it would be nice to avoid sending this message to the child
4228 // at all.
4229 NS_WARNING("Attempt to attach WindowContext to discarded parent");
4230 return IPC_OK();
4233 WindowContext::CreateFromIPC(std::move(aInit));
4234 return IPC_OK();
4237 mozilla::ipc::IPCResult ContentChild::RecvDiscardWindowContext(
4238 uint64_t aContextId, DiscardWindowContextResolver&& aResolve) {
4239 // Resolve immediately to acknowledge call
4240 aResolve(true);
4242 RefPtr<WindowContext> window = WindowContext::GetById(aContextId);
4243 if (NS_WARN_IF(!window) || NS_WARN_IF(window->IsDiscarded())) {
4244 return IPC_OK();
4247 window->Discard();
4248 return IPC_OK();
4251 mozilla::ipc::IPCResult ContentChild::RecvScriptError(
4252 const nsString& aMessage, const nsString& aSourceName,
4253 const nsString& aSourceLine, const uint32_t& aLineNumber,
4254 const uint32_t& aColNumber, const uint32_t& aFlags,
4255 const nsCString& aCategory, const bool& aFromPrivateWindow,
4256 const uint64_t& aInnerWindowId, const bool& aFromChromeContext) {
4257 nsresult rv = NS_OK;
4258 nsCOMPtr<nsIConsoleService> consoleService =
4259 do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
4260 NS_ENSURE_SUCCESS(rv, IPC_FAIL(this, "Failed to get console service"));
4262 nsCOMPtr<nsIScriptError> scriptError(
4263 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
4264 NS_ENSURE_TRUE(scriptError,
4265 IPC_FAIL(this, "Failed to construct nsIScriptError"));
4267 scriptError->InitWithWindowID(aMessage, aSourceName, aSourceLine, aLineNumber,
4268 aColNumber, aFlags, aCategory, aInnerWindowId,
4269 aFromChromeContext);
4270 rv = consoleService->LogMessage(scriptError);
4271 NS_ENSURE_SUCCESS(rv, IPC_FAIL(this, "Failed to log script error"));
4273 return IPC_OK();
4276 mozilla::ipc::IPCResult ContentChild::RecvReportFrameTimingData(
4277 const LoadInfoArgs& loadInfoArgs, const nsString& entryName,
4278 const nsString& initiatorType, UniquePtr<PerformanceTimingData>&& aData) {
4279 if (!aData) {
4280 return IPC_FAIL(this, "aData should not be null");
4283 nsCOMPtr<nsILoadInfo> loadInfo;
4284 nsresult rv = mozilla::ipc::LoadInfoArgsToLoadInfo(
4285 loadInfoArgs, NOT_REMOTE_TYPE, getter_AddRefs(loadInfo));
4286 if (NS_FAILED(rv)) {
4287 MOZ_DIAGNOSTIC_ASSERT(false, "LoadInfoArgsToLoadInfo failed");
4288 return IPC_OK();
4291 // It is important to call LoadInfo::GetPerformanceStorage instead of simply
4292 // getting the performance object via the innerWindowID in order to perform
4293 // necessary cross origin checks.
4294 if (PerformanceStorage* storage = loadInfo->GetPerformanceStorage()) {
4295 storage->AddEntry(entryName, initiatorType, std::move(aData));
4297 return IPC_OK();
4300 mozilla::ipc::IPCResult ContentChild::RecvLoadURI(
4301 const MaybeDiscarded<BrowsingContext>& aContext,
4302 nsDocShellLoadState* aLoadState, bool aSetNavigating,
4303 LoadURIResolver&& aResolve) {
4304 auto resolveOnExit = MakeScopeExit([&] { aResolve(true); });
4306 if (aContext.IsNullOrDiscarded()) {
4307 return IPC_OK();
4309 RefPtr<BrowsingContext> context = aContext.get();
4310 if (!context->IsInProcess()) {
4311 // The DocShell has been torn down or the BrowsingContext has changed
4312 // process in the middle of the load request. There's not much we can do at
4313 // this point, so just give up.
4314 return IPC_OK();
4317 context->LoadURI(aLoadState, aSetNavigating);
4319 nsCOMPtr<nsPIDOMWindowOuter> window = context->GetDOMWindow();
4320 BrowserChild* bc = BrowserChild::GetFrom(window);
4321 if (bc) {
4322 bc->NotifyNavigationFinished();
4325 #ifdef MOZ_CRASHREPORTER
4326 if (CrashReporter::GetEnabled()) {
4327 nsCOMPtr<nsIURI> annotationURI;
4329 nsresult rv = NS_MutateURI(aLoadState->URI())
4330 .SetUserPass(""_ns)
4331 .Finalize(annotationURI);
4333 if (NS_FAILED(rv)) {
4334 // Ignore failures on about: URIs.
4335 annotationURI = aLoadState->URI();
4338 CrashReporter::RecordAnnotationNSCString(CrashReporter::Annotation::URL,
4339 annotationURI->GetSpecOrDefault());
4341 #endif
4343 return IPC_OK();
4346 mozilla::ipc::IPCResult ContentChild::RecvInternalLoad(
4347 nsDocShellLoadState* aLoadState) {
4348 if (!aLoadState->Target().IsEmpty() ||
4349 aLoadState->TargetBrowsingContext().IsNull()) {
4350 return IPC_FAIL(this, "must already be retargeted");
4352 if (aLoadState->TargetBrowsingContext().IsDiscarded()) {
4353 return IPC_OK();
4355 RefPtr<BrowsingContext> context = aLoadState->TargetBrowsingContext().get();
4357 context->InternalLoad(aLoadState);
4359 #ifdef MOZ_CRASHREPORTER
4360 if (CrashReporter::GetEnabled()) {
4361 nsCOMPtr<nsIURI> annotationURI;
4363 nsresult rv = NS_MutateURI(aLoadState->URI())
4364 .SetUserPass(""_ns)
4365 .Finalize(annotationURI);
4367 if (NS_FAILED(rv)) {
4368 // Ignore failures on about: URIs.
4369 annotationURI = aLoadState->URI();
4372 CrashReporter::RecordAnnotationNSCString(CrashReporter::Annotation::URL,
4373 annotationURI->GetSpecOrDefault());
4375 #endif
4377 return IPC_OK();
4380 mozilla::ipc::IPCResult ContentChild::RecvDisplayLoadError(
4381 const MaybeDiscarded<BrowsingContext>& aContext, const nsAString& aURI) {
4382 if (aContext.IsNullOrDiscarded()) {
4383 return IPC_OK();
4385 RefPtr<BrowsingContext> context = aContext.get();
4387 context->DisplayLoadError(aURI);
4389 nsCOMPtr<nsPIDOMWindowOuter> window = context->GetDOMWindow();
4390 BrowserChild* bc = BrowserChild::GetFrom(window);
4391 if (bc) {
4392 bc->NotifyNavigationFinished();
4394 return IPC_OK();
4397 mozilla::ipc::IPCResult ContentChild::RecvHistoryCommitIndexAndLength(
4398 const MaybeDiscarded<BrowsingContext>& aContext, const uint32_t& aIndex,
4399 const uint32_t& aLength, const nsID& aChangeID) {
4400 if (!aContext.IsNullOrDiscarded()) {
4401 ChildSHistory* shistory = aContext.get()->GetChildSessionHistory();
4402 if (shistory) {
4403 shistory->SetIndexAndLength(aIndex, aLength, aChangeID);
4406 return IPC_OK();
4409 mozilla::ipc::IPCResult ContentChild::RecvGetLayoutHistoryState(
4410 const MaybeDiscarded<BrowsingContext>& aContext,
4411 GetLayoutHistoryStateResolver&& aResolver) {
4412 nsCOMPtr<nsILayoutHistoryState> state;
4413 nsIDocShell* docShell;
4414 mozilla::Maybe<mozilla::dom::Wireframe> wireframe;
4415 if (!aContext.IsNullOrDiscarded() &&
4416 (docShell = aContext.get()->GetDocShell())) {
4417 docShell->PersistLayoutHistoryState();
4418 docShell->GetLayoutHistoryState(getter_AddRefs(state));
4419 wireframe = static_cast<nsDocShell*>(docShell)->GetWireframe();
4421 aResolver(
4422 std::tuple<nsILayoutHistoryState*, const mozilla::Maybe<Wireframe>&>(
4423 state, wireframe));
4425 return IPC_OK();
4428 mozilla::ipc::IPCResult ContentChild::RecvDispatchLocationChangeEvent(
4429 const MaybeDiscarded<BrowsingContext>& aContext) {
4430 if (!aContext.IsNullOrDiscarded() && aContext.get()->GetDocShell()) {
4431 aContext.get()->GetDocShell()->DispatchLocationChangeEvent();
4433 return IPC_OK();
4436 mozilla::ipc::IPCResult ContentChild::RecvDispatchBeforeUnloadToSubtree(
4437 const MaybeDiscarded<BrowsingContext>& aStartingAt,
4438 DispatchBeforeUnloadToSubtreeResolver&& aResolver) {
4439 if (aStartingAt.IsNullOrDiscarded()) {
4440 aResolver(nsIDocumentViewer::eAllowNavigation);
4441 } else {
4442 DispatchBeforeUnloadToSubtree(aStartingAt.get(), std::move(aResolver));
4444 return IPC_OK();
4447 mozilla::ipc::IPCResult ContentChild::RecvDecoderSupportedMimeTypes(
4448 nsTArray<nsCString>&& aSupportedTypes) {
4449 #ifdef MOZ_WIDGET_ANDROID
4450 AndroidDecoderModule::SetSupportedMimeTypes(std::move(aSupportedTypes));
4451 #endif
4452 return IPC_OK();
4455 mozilla::ipc::IPCResult ContentChild::RecvInitNextGenLocalStorageEnabled(
4456 const bool& aEnabled) {
4457 mozilla::dom::RecvInitNextGenLocalStorageEnabled(aEnabled);
4459 return IPC_OK();
4462 /* static */ void ContentChild::DispatchBeforeUnloadToSubtree(
4463 BrowsingContext* aStartingAt,
4464 const DispatchBeforeUnloadToSubtreeResolver& aResolver) {
4465 bool resolved = false;
4467 aStartingAt->PreOrderWalk([&](dom::BrowsingContext* aBC) {
4468 if (aBC->GetDocShell()) {
4469 nsCOMPtr<nsIDocumentViewer> viewer;
4470 aBC->GetDocShell()->GetDocViewer(getter_AddRefs(viewer));
4471 if (viewer &&
4472 viewer->DispatchBeforeUnload() ==
4473 nsIDocumentViewer::eRequestBlockNavigation &&
4474 !resolved) {
4475 // Send our response as soon as we find any blocker, so that we can show
4476 // the permit unload prompt as soon as possible, without giving
4477 // subsequent handlers a chance to delay it.
4478 aResolver(nsIDocumentViewer::eRequestBlockNavigation);
4479 resolved = true;
4484 if (!resolved) {
4485 aResolver(nsIDocumentViewer::eAllowNavigation);
4489 mozilla::ipc::IPCResult ContentChild::RecvGoBack(
4490 const MaybeDiscarded<BrowsingContext>& aContext,
4491 const Maybe<int32_t>& aCancelContentJSEpoch, bool aRequireUserInteraction,
4492 bool aUserActivation) {
4493 if (aContext.IsNullOrDiscarded()) {
4494 return IPC_OK();
4496 BrowsingContext* bc = aContext.get();
4498 if (RefPtr<nsDocShell> docShell = nsDocShell::Cast(bc->GetDocShell())) {
4499 if (aCancelContentJSEpoch) {
4500 docShell->SetCancelContentJSEpoch(*aCancelContentJSEpoch);
4502 docShell->GoBack(aRequireUserInteraction, aUserActivation);
4504 if (BrowserChild* browserChild = BrowserChild::GetFrom(docShell)) {
4505 browserChild->NotifyNavigationFinished();
4509 return IPC_OK();
4512 mozilla::ipc::IPCResult ContentChild::RecvGoForward(
4513 const MaybeDiscarded<BrowsingContext>& aContext,
4514 const Maybe<int32_t>& aCancelContentJSEpoch, bool aRequireUserInteraction,
4515 bool aUserActivation) {
4516 if (aContext.IsNullOrDiscarded()) {
4517 return IPC_OK();
4519 BrowsingContext* bc = aContext.get();
4521 if (RefPtr<nsDocShell> docShell = nsDocShell::Cast(bc->GetDocShell())) {
4522 if (aCancelContentJSEpoch) {
4523 docShell->SetCancelContentJSEpoch(*aCancelContentJSEpoch);
4525 docShell->GoForward(aRequireUserInteraction, aUserActivation);
4527 if (BrowserChild* browserChild = BrowserChild::GetFrom(docShell)) {
4528 browserChild->NotifyNavigationFinished();
4532 return IPC_OK();
4535 mozilla::ipc::IPCResult ContentChild::RecvGoToIndex(
4536 const MaybeDiscarded<BrowsingContext>& aContext, const int32_t& aIndex,
4537 const Maybe<int32_t>& aCancelContentJSEpoch, bool aUserActivation) {
4538 if (aContext.IsNullOrDiscarded()) {
4539 return IPC_OK();
4541 BrowsingContext* bc = aContext.get();
4543 if (RefPtr<nsDocShell> docShell = nsDocShell::Cast(bc->GetDocShell())) {
4544 if (aCancelContentJSEpoch) {
4545 docShell->SetCancelContentJSEpoch(*aCancelContentJSEpoch);
4547 docShell->GotoIndex(aIndex, aUserActivation);
4549 if (BrowserChild* browserChild = BrowserChild::GetFrom(docShell)) {
4550 browserChild->NotifyNavigationFinished();
4554 return IPC_OK();
4557 mozilla::ipc::IPCResult ContentChild::RecvReload(
4558 const MaybeDiscarded<BrowsingContext>& aContext,
4559 const uint32_t aReloadFlags) {
4560 if (aContext.IsNullOrDiscarded()) {
4561 return IPC_OK();
4563 BrowsingContext* bc = aContext.get();
4565 if (RefPtr<nsDocShell> docShell = nsDocShell::Cast(bc->GetDocShell())) {
4566 docShell->Reload(aReloadFlags);
4569 return IPC_OK();
4572 mozilla::ipc::IPCResult ContentChild::RecvStopLoad(
4573 const MaybeDiscarded<BrowsingContext>& aContext,
4574 const uint32_t aStopFlags) {
4575 if (aContext.IsNullOrDiscarded()) {
4576 return IPC_OK();
4578 BrowsingContext* bc = aContext.get();
4580 if (auto* docShell = nsDocShell::Cast(bc->GetDocShell())) {
4581 docShell->Stop(aStopFlags);
4584 return IPC_OK();
4587 #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
4588 mozilla::ipc::IPCResult ContentChild::RecvInitSandboxTesting(
4589 Endpoint<PSandboxTestingChild>&& aEndpoint) {
4590 if (!SandboxTestingChild::Initialize(std::move(aEndpoint))) {
4591 return IPC_FAIL(
4592 this, "InitSandboxTesting failed to initialise the child process.");
4594 return IPC_OK();
4596 #endif
4598 NS_IMETHODIMP ContentChild::GetChildID(uint64_t* aOut) {
4599 *aOut = mID;
4600 return NS_OK;
4603 NS_IMETHODIMP ContentChild::GetActor(const nsACString& aName, JSContext* aCx,
4604 JSProcessActorChild** retval) {
4605 ErrorResult error;
4606 RefPtr<JSProcessActorChild> actor =
4607 JSActorManager::GetActor(aCx, aName, error)
4608 .downcast<JSProcessActorChild>();
4609 if (error.MaybeSetPendingException(aCx)) {
4610 return NS_ERROR_FAILURE;
4612 actor.forget(retval);
4613 return NS_OK;
4616 NS_IMETHODIMP ContentChild::GetExistingActor(const nsACString& aName,
4617 JSProcessActorChild** retval) {
4618 RefPtr<JSProcessActorChild> actor =
4619 JSActorManager::GetExistingActor(aName).downcast<JSProcessActorChild>();
4620 actor.forget(retval);
4621 return NS_OK;
4624 already_AddRefed<JSActor> ContentChild::InitJSActor(
4625 JS::Handle<JSObject*> aMaybeActor, const nsACString& aName,
4626 ErrorResult& aRv) {
4627 RefPtr<JSProcessActorChild> actor;
4628 if (aMaybeActor.get()) {
4629 aRv = UNWRAP_OBJECT(JSProcessActorChild, aMaybeActor.get(), actor);
4630 if (aRv.Failed()) {
4631 return nullptr;
4633 } else {
4634 actor = new JSProcessActorChild();
4637 MOZ_RELEASE_ASSERT(!actor->Manager(),
4638 "mManager was already initialized once!");
4639 actor->Init(aName, this);
4640 return actor.forget();
4643 IPCResult ContentChild::RecvRawMessage(const JSActorMessageMeta& aMeta,
4644 const Maybe<ClonedMessageData>& aData,
4645 const Maybe<ClonedMessageData>& aStack) {
4646 Maybe<StructuredCloneData> data;
4647 if (aData) {
4648 data.emplace();
4649 data->BorrowFromClonedMessageData(*aData);
4651 Maybe<StructuredCloneData> stack;
4652 if (aStack) {
4653 stack.emplace();
4654 stack->BorrowFromClonedMessageData(*aStack);
4656 ReceiveRawMessage(aMeta, std::move(data), std::move(stack));
4657 return IPC_OK();
4660 NS_IMETHODIMP ContentChild::GetCanSend(bool* aCanSend) {
4661 *aCanSend = CanSend();
4662 return NS_OK;
4665 ContentChild* ContentChild::AsContentChild() { return this; }
4667 JSActorManager* ContentChild::AsJSActorManager() { return this; }
4669 IPCResult ContentChild::RecvFlushFOGData(FlushFOGDataResolver&& aResolver) {
4670 glean::FlushFOGData(std::move(aResolver));
4671 return IPC_OK();
4674 IPCResult ContentChild::RecvUpdateMediaCodecsSupported(
4675 RemoteDecodeIn aLocation, const media::MediaCodecsSupported& aSupported) {
4676 RemoteDecoderManagerChild::SetSupported(aLocation, aSupported);
4678 return IPC_OK();
4681 void ContentChild::ConfigureThreadPerformanceHints(
4682 const hal::ProcessPriority& aPriority) {
4683 if (aPriority >= hal::PROCESS_PRIORITY_FOREGROUND) {
4684 static bool canUsePerformanceHintSession = true;
4685 if (!mPerformanceHintSession && canUsePerformanceHintSession) {
4686 nsTArray<PlatformThreadHandle> threads;
4687 Servo_ThreadPool_GetThreadHandles(&threads);
4688 #ifdef XP_WIN
4689 threads.AppendElement(GetCurrentThread());
4690 #else
4691 threads.AppendElement(pthread_self());
4692 #endif
4694 mPerformanceHintSession = hal::CreatePerformanceHintSession(
4695 threads, GetPerformanceHintTarget(TimeDuration::FromMilliseconds(
4696 nsRefreshDriver::DefaultInterval())));
4698 // Avoid repeatedly attempting to create a session if it is not
4699 // supported.
4700 canUsePerformanceHintSession = mPerformanceHintSession != nullptr;
4703 #ifdef MOZ_WIDGET_ANDROID
4704 // On Android if we are unable to use PerformanceHintManager then fall back
4705 // to setting the stylo threads' affinities to the performant cores. Android
4706 // automatically sets each thread's affinity to all cores when a process is
4707 // foregrounded, and to a subset of cores when the process is backgrounded.
4708 // We must therefore override this each time the process is foregrounded,
4709 // but we don't have to do anything when backgrounded.
4710 if (!mPerformanceHintSession) {
4711 if (const auto& cpuInfo = hal::GetHeterogeneousCpuInfo()) {
4712 // If CPUs are homogeneous there is no point setting affinity.
4713 if (cpuInfo->mBigCpus.Count() != cpuInfo->mTotalNumCpus) {
4714 BitSet<hal::HeterogeneousCpuInfo::MAX_CPUS> cpus = cpuInfo->mBigCpus;
4715 if (cpus.Count() < 2) {
4716 // From testing on a variety of devices it appears using only the
4717 // big cores gives best performance when there are 2 or more big
4718 // cores. If there are fewer than 2 big cores then additionally
4719 // using the medium cores performs better.
4720 cpus |= cpuInfo->mMediumCpus;
4723 static_assert(
4724 hal::HeterogeneousCpuInfo::MAX_CPUS <= CPU_SETSIZE,
4725 "HeterogeneousCpuInfo::MAX_CPUS is too large for CPU_SETSIZE");
4727 cpu_set_t cpuset;
4728 CPU_ZERO(&cpuset);
4729 for (size_t i = 0; i < cpuInfo->mTotalNumCpus; i++) {
4730 if (cpus.Test(i)) {
4731 CPU_SET(i, &cpuset);
4735 // Only set the affinity for the stylo threads, not the main thread.
4736 // Testing showed no difference in performance between the two
4737 // options, and as newly spawned threads automatically inherit their
4738 // parent's affinity mask there may be unintended consequences to
4739 // setting the main thread affinity.
4740 nsTArray<PlatformThreadHandle> threads;
4741 Servo_ThreadPool_GetThreadHandles(&threads);
4742 for (pthread_t thread : threads) {
4743 int ret = sched_setaffinity(pthread_gettid_np(thread),
4744 sizeof(cpu_set_t), &cpuset);
4745 // Occasionally sched_setaffinity fails, presumably due to a race
4746 // between us receiving the process foreground signal and whatever
4747 // is responsible for restricting which processes can use certain
4748 // cores. Trying again in a runnable seems to do the trick, but if
4749 // that still fails it's not the end of the world.
4750 if (ret < 0) {
4751 NS_DispatchToCurrentThread(NS_NewRunnableFunction(
4752 "ContentChild::ConfigureThreadPerformanceHints",
4753 [threads = std::move(threads), cpuset] {
4754 for (pthread_t thread : threads) {
4755 sched_setaffinity(pthread_gettid_np(thread),
4756 sizeof(cpu_set_t), &cpuset);
4758 }));
4759 break;
4765 #endif
4766 } else {
4767 mPerformanceHintSession = nullptr;
4771 } // namespace dom
4773 #if defined(__OpenBSD__) && defined(MOZ_SANDBOX)
4775 static LazyLogModule sPledgeLog("OpenBSDSandbox");
4777 NS_IMETHODIMP
4778 OpenBSDFindPledgeUnveilFilePath(const char* file, nsACString& result) {
4779 struct stat st;
4781 // Allow overriding files in /etc/$MOZ_APP_NAME
4782 result.Assign(nsPrintfCString("/etc/%s/%s", MOZ_APP_NAME, file));
4783 if (stat(PromiseFlatCString(result).get(), &st) == 0) {
4784 return NS_OK;
4787 // Or look in the system default directory
4788 result.Assign(nsPrintfCString(
4789 "/usr/local/lib/%s/browser/defaults/preferences/%s", MOZ_APP_NAME, file));
4790 if (stat(PromiseFlatCString(result).get(), &st) == 0) {
4791 return NS_OK;
4794 errx(1, "can't locate %s", file);
4797 NS_IMETHODIMP
4798 OpenBSDPledgePromises(const nsACString& aPath) {
4799 // Using NS_LOCAL_FILE_CONTRACTID/NS_LOCALFILEINPUTSTREAM_CONTRACTID requires
4800 // a lot of setup before they are supported and we want to pledge early on
4801 // before all of that, so read the file directly
4802 std::ifstream input(PromiseFlatCString(aPath).get());
4804 // Build up one line of pledge promises without comments
4805 nsAutoCString promises;
4806 bool disabled = false;
4807 int linenum = 0;
4808 for (std::string tLine; std::getline(input, tLine);) {
4809 nsAutoCString line(tLine.c_str());
4810 linenum++;
4812 // Cut off any comments at the end of the line, also catches lines
4813 // that are entirely a comment
4814 int32_t hash = line.FindChar('#');
4815 if (hash >= 0) {
4816 line = Substring(line, 0, hash);
4818 line.CompressWhitespace(true, true);
4819 if (line.IsEmpty()) {
4820 continue;
4823 if (linenum == 1 && line.EqualsLiteral("disable")) {
4824 disabled = true;
4825 break;
4828 if (!promises.IsEmpty()) {
4829 promises.Append(" ");
4831 promises.Append(line);
4833 input.close();
4835 if (disabled) {
4836 warnx("%s: disabled", PromiseFlatCString(aPath).get());
4837 } else {
4838 MOZ_LOG(
4839 sPledgeLog, LogLevel::Debug,
4840 ("%s: pledge(%s)\n", PromiseFlatCString(aPath).get(), promises.get()));
4841 if (pledge(promises.get(), nullptr) != 0) {
4842 err(1, "%s: pledge(%s) failed", PromiseFlatCString(aPath).get(),
4843 promises.get());
4847 return NS_OK;
4850 void ExpandUnveilPath(nsAutoCString& path) {
4851 // Expand $XDG_RUNTIME_DIR to the environment variable, or ~/.cache
4852 nsCString xdgRuntimeDir(PR_GetEnv("XDG_RUNTIME_DIR"));
4853 if (xdgRuntimeDir.IsEmpty()) {
4854 xdgRuntimeDir = "~/.cache";
4856 path.ReplaceSubstring("$XDG_RUNTIME_DIR", xdgRuntimeDir.get());
4858 // Expand $XDG_CONFIG_HOME to the environment variable, or ~/.config
4859 nsCString xdgConfigHome(PR_GetEnv("XDG_CONFIG_HOME"));
4860 if (xdgConfigHome.IsEmpty()) {
4861 xdgConfigHome = "~/.config";
4863 path.ReplaceSubstring("$XDG_CONFIG_HOME", xdgConfigHome.get());
4865 // Expand $XDG_CACHE_HOME to the environment variable, or ~/.cache
4866 nsCString xdgCacheHome(PR_GetEnv("XDG_CACHE_HOME"));
4867 if (xdgCacheHome.IsEmpty()) {
4868 xdgCacheHome = "~/.cache";
4870 path.ReplaceSubstring("$XDG_CACHE_HOME", xdgCacheHome.get());
4872 // Expand $XDG_DATA_HOME to the environment variable, or ~/.local/share
4873 nsCString xdgDataHome(PR_GetEnv("XDG_DATA_HOME"));
4874 if (xdgDataHome.IsEmpty()) {
4875 xdgDataHome = "~/.local/share";
4877 path.ReplaceSubstring("$XDG_DATA_HOME", xdgDataHome.get());
4879 // Expand leading ~ to the user's home directory
4880 nsCOMPtr<nsIFile> homeDir;
4881 nsresult rv =
4882 GetSpecialSystemDirectory(Unix_HomeDirectory, getter_AddRefs(homeDir));
4883 if (NS_FAILED(rv)) {
4884 errx(1, "failed getting home directory");
4886 if (path.FindChar('~') == 0) {
4887 nsCString tHome(homeDir->NativePath());
4888 tHome.Append(Substring(path, 1, path.Length() - 1));
4889 path = tHome.get();
4893 void MkdirP(nsAutoCString& path) {
4894 // nsLocalFile::CreateAllAncestors would be nice to use
4896 nsAutoCString tPath("");
4897 for (const nsACString& dir : path.Split('/')) {
4898 struct stat st;
4900 if (dir.IsEmpty()) {
4901 continue;
4904 tPath.Append("/");
4905 tPath.Append(dir);
4907 if (stat(tPath.get(), &st) == -1) {
4908 if (mkdir(tPath.get(), 0700) == -1) {
4909 err(1, "failed mkdir(%s) while MkdirP(%s)",
4910 PromiseFlatCString(tPath).get(), PromiseFlatCString(path).get());
4916 NS_IMETHODIMP
4917 OpenBSDUnveilPaths(const nsACString& uPath, const nsACString& pledgePath) {
4918 // Using NS_LOCAL_FILE_CONTRACTID/NS_LOCALFILEINPUTSTREAM_CONTRACTID requires
4919 // a lot of setup before they are allowed/supported and we want to pledge and
4920 // unveil early on before all of that is setup
4921 std::ifstream input(PromiseFlatCString(uPath).get());
4923 bool disabled = false;
4924 int linenum = 0;
4925 for (std::string tLine; std::getline(input, tLine);) {
4926 nsAutoCString line(tLine.c_str());
4927 linenum++;
4929 // Cut off any comments at the end of the line, also catches lines
4930 // that are entirely a comment
4931 int32_t hash = line.FindChar('#');
4932 if (hash >= 0) {
4933 line = Substring(line, 0, hash);
4935 line.CompressWhitespace(true, true);
4936 if (line.IsEmpty()) {
4937 continue;
4940 if (linenum == 1 && line.EqualsLiteral("disable")) {
4941 disabled = true;
4942 break;
4945 int32_t space = line.FindChar(' ');
4946 if (space <= 0) {
4947 errx(1, "%s: line %d: invalid format", PromiseFlatCString(uPath).get(),
4948 linenum);
4951 nsAutoCString uPath(Substring(line, 0, space));
4952 ExpandUnveilPath(uPath);
4954 nsAutoCString perms(Substring(line, space + 1, line.Length() - space - 1));
4956 MOZ_LOG(sPledgeLog, LogLevel::Debug,
4957 ("%s: unveil(%s, %s)\n", PromiseFlatCString(uPath).get(),
4958 uPath.get(), perms.get()));
4959 if (unveil(uPath.get(), perms.get()) == -1 && errno != ENOENT) {
4960 err(1, "%s: unveil(%s, %s) failed", PromiseFlatCString(uPath).get(),
4961 uPath.get(), perms.get());
4964 input.close();
4966 if (disabled) {
4967 warnx("%s: disabled", PromiseFlatCString(uPath).get());
4968 } else {
4969 struct stat st;
4971 // Only unveil the pledgePath file if it's not already unveiled, otherwise
4972 // some containing directory will lose visibility.
4973 if (stat(PromiseFlatCString(pledgePath).get(), &st) == -1) {
4974 if (errno == ENOENT) {
4975 if (unveil(PromiseFlatCString(pledgePath).get(), "r") == -1) {
4976 err(1, "unveil(%s, r) failed", PromiseFlatCString(pledgePath).get());
4978 } else {
4979 err(1, "stat(%s)", PromiseFlatCString(pledgePath).get());
4984 return NS_OK;
4987 bool StartOpenBSDSandbox(GeckoProcessType type, ipc::SandboxingKind kind) {
4988 nsAutoCString pledgeFile;
4989 nsAutoCString unveilFile;
4990 char binaryPath[MAXPATHLEN];
4992 switch (type) {
4993 case GeckoProcessType_Default: {
4994 OpenBSDFindPledgeUnveilFilePath("pledge.main", pledgeFile);
4995 OpenBSDFindPledgeUnveilFilePath("unveil.main", unveilFile);
4997 // Ensure dconf dir exists before we veil the filesystem
4998 nsAutoCString dConf("$XDG_RUNTIME_DIR/dconf");
4999 ExpandUnveilPath(dConf);
5000 MkdirP(dConf);
5001 break;
5004 case GeckoProcessType_Content:
5005 OpenBSDFindPledgeUnveilFilePath("pledge.content", pledgeFile);
5006 OpenBSDFindPledgeUnveilFilePath("unveil.content", unveilFile);
5007 break;
5009 case GeckoProcessType_GPU:
5010 OpenBSDFindPledgeUnveilFilePath("pledge.gpu", pledgeFile);
5011 OpenBSDFindPledgeUnveilFilePath("unveil.gpu", unveilFile);
5012 break;
5014 case GeckoProcessType_Socket:
5015 OpenBSDFindPledgeUnveilFilePath("pledge.socket", pledgeFile);
5016 OpenBSDFindPledgeUnveilFilePath("unveil.socket", unveilFile);
5017 break;
5019 case GeckoProcessType_RDD:
5020 OpenBSDFindPledgeUnveilFilePath("pledge.rdd", pledgeFile);
5021 OpenBSDFindPledgeUnveilFilePath("unveil.rdd", unveilFile);
5022 break;
5024 case GeckoProcessType_Utility: {
5025 MOZ_RELEASE_ASSERT(kind <= SandboxingKind::COUNT,
5026 "Should define a sandbox");
5027 switch (kind) {
5028 case ipc::SandboxingKind::GENERIC_UTILITY:
5029 default:
5030 OpenBSDFindPledgeUnveilFilePath("pledge.utility", pledgeFile);
5031 OpenBSDFindPledgeUnveilFilePath("unveil.utility", unveilFile);
5032 break;
5034 } break;
5036 default:
5037 MOZ_ASSERT(false, "unknown process type");
5038 return false;
5041 nsresult rv = mozilla::BinaryPath::Get(binaryPath);
5042 if (NS_FAILED(rv)) {
5043 errx(1, "failed to cache binary path ?");
5046 if (NS_WARN_IF(NS_FAILED(OpenBSDUnveilPaths(unveilFile, pledgeFile)))) {
5047 errx(1, "failed reading/parsing %s", unveilFile.get());
5050 if (NS_WARN_IF(NS_FAILED(OpenBSDPledgePromises(pledgeFile)))) {
5051 errx(1, "failed reading/parsing %s", pledgeFile.get());
5054 // Don't overwrite an existing session dbus address, but ensure it is set
5055 if (!PR_GetEnv("DBUS_SESSION_BUS_ADDRESS")) {
5056 PR_SetEnv("DBUS_SESSION_BUS_ADDRESS=");
5059 return true;
5061 #endif
5063 } // namespace mozilla
5065 /* static */
5066 nsIDOMProcessChild* nsIDOMProcessChild::GetSingleton() {
5067 if (XRE_IsContentProcess()) {
5068 return mozilla::dom::ContentChild::GetSingleton();
5070 return mozilla::dom::InProcessChild::Singleton();