forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			5067 lines
		
	
	
	
		
			172 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			5067 lines
		
	
	
	
		
			172 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #ifdef MOZ_WIDGET_ANDROID
 | |
| #  include "AndroidDecoderModule.h"
 | |
| #endif
 | |
| 
 | |
| #include "BrowserChild.h"
 | |
| #include "nsNSSComponent.h"
 | |
| #include "ContentChild.h"
 | |
| #include "GeckoProfiler.h"
 | |
| #include "HandlerServiceChild.h"
 | |
| #include "nsXPLookAndFeel.h"
 | |
| #include "mozilla/AppShutdown.h"
 | |
| #include "mozilla/Attributes.h"
 | |
| #include "mozilla/BackgroundHangMonitor.h"
 | |
| #include "mozilla/BenchmarkStorageChild.h"
 | |
| #include "mozilla/FOGIPC.h"
 | |
| #include "GMPServiceChild.h"
 | |
| #include "Geolocation.h"
 | |
| #include "imgLoader.h"
 | |
| #include "ScrollingMetrics.h"
 | |
| #include "mozilla/BasePrincipal.h"
 | |
| #include "mozilla/ClipboardReadRequestChild.h"
 | |
| #include "mozilla/Components.h"
 | |
| #include "mozilla/HangDetails.h"
 | |
| #include "mozilla/LoadInfo.h"
 | |
| #include "mozilla/Logging.h"
 | |
| #include "mozilla/LookAndFeel.h"
 | |
| #include "mozilla/MemoryTelemetry.h"
 | |
| #include "mozilla/NullPrincipal.h"
 | |
| #include "mozilla/PerfStats.h"
 | |
| #include "mozilla/Preferences.h"
 | |
| #include "mozilla/ProcessHangMonitorIPC.h"
 | |
| #include "mozilla/RemoteDecoderManagerChild.h"
 | |
| #include "mozilla/RemoteLazyInputStreamChild.h"
 | |
| #include "mozilla/SchedulerGroup.h"
 | |
| #include "mozilla/ScopeExit.h"
 | |
| #include "mozilla/SharedStyleSheetCache.h"
 | |
| #include "mozilla/SimpleEnumerator.h"
 | |
| #include "mozilla/SpinEventLoopUntil.h"
 | |
| #include "mozilla/StaticPrefs_browser.h"
 | |
| #include "mozilla/StaticPrefs_dom.h"
 | |
| #include "mozilla/StaticPrefs_fission.h"
 | |
| #include "mozilla/StaticPrefs_javascript.h"
 | |
| #include "mozilla/StaticPrefs_media.h"
 | |
| #include "mozilla/StaticPrefs_threads.h"
 | |
| #include "mozilla/StorageAccessAPIHelper.h"
 | |
| #include "mozilla/TelemetryIPC.h"
 | |
| #include "mozilla/Unused.h"
 | |
| #include "mozilla/WebBrowserPersistDocumentChild.h"
 | |
| #include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h"
 | |
| #include "mozilla/dom/AutoSuppressEventHandlingAndSuspend.h"
 | |
| #include "mozilla/dom/BlobImpl.h"
 | |
| #include "mozilla/dom/BrowserBridgeHost.h"
 | |
| #include "mozilla/dom/BrowsingContext.h"
 | |
| #include "mozilla/dom/BrowsingContextGroup.h"
 | |
| #include "mozilla/dom/ChildProcessChannelListener.h"
 | |
| #include "mozilla/dom/ChildProcessMessageManager.h"
 | |
| #include "mozilla/dom/ClientManager.h"
 | |
| #include "mozilla/dom/ContentParent.h"
 | |
| #include "mozilla/dom/ContentProcessManager.h"
 | |
| #include "mozilla/dom/ContentPlaybackController.h"
 | |
| #include "mozilla/dom/ContentProcessMessageManager.h"
 | |
| #include "mozilla/dom/DataTransfer.h"
 | |
| #include "mozilla/dom/DocGroup.h"
 | |
| #include "mozilla/dom/ExternalHelperAppChild.h"
 | |
| #include "mozilla/dom/GetFilesHelper.h"
 | |
| #include "mozilla/dom/IPCBlobUtils.h"
 | |
| #include "mozilla/dom/InProcessChild.h"
 | |
| #include "mozilla/dom/JSActorService.h"
 | |
| #include "mozilla/dom/JSProcessActorBinding.h"
 | |
| #include "mozilla/dom/JSProcessActorChild.h"
 | |
| #include "mozilla/dom/LSObject.h"
 | |
| #include "mozilla/dom/MemoryReportRequest.h"
 | |
| #include "mozilla/dom/PSessionStorageObserverChild.h"
 | |
| #include "mozilla/dom/PostMessageEvent.h"
 | |
| #include "mozilla/dom/PushNotifier.h"
 | |
| #include "mozilla/dom/RemoteWorkerService.h"
 | |
| #include "mozilla/dom/ScreenOrientation.h"
 | |
| #include "mozilla/dom/ServiceWorkerManager.h"
 | |
| #include "mozilla/dom/SessionStorageManager.h"
 | |
| #include "mozilla/dom/URLClassifierChild.h"
 | |
| #include "mozilla/dom/UserActivation.h"
 | |
| #include "mozilla/dom/WindowGlobalChild.h"
 | |
| #include "mozilla/dom/WorkerDebugger.h"
 | |
| #include "mozilla/dom/WorkerDebuggerManager.h"
 | |
| #include "mozilla/dom/ipc/SharedMap.h"
 | |
| #include "mozilla/extensions/ExtensionsChild.h"
 | |
| #include "mozilla/extensions/StreamFilterParent.h"
 | |
| #include "mozilla/gfx/Logging.h"
 | |
| #include "mozilla/gfx/gfxVars.h"
 | |
| #include "mozilla/hal_sandbox/PHalChild.h"
 | |
| #include "mozilla/intl/L10nRegistry.h"
 | |
| #include "mozilla/intl/LocaleService.h"
 | |
| #include "mozilla/ipc/BackgroundChild.h"
 | |
| #include "mozilla/ipc/Endpoint.h"
 | |
| #include "mozilla/ipc/FileDescriptorUtils.h"
 | |
| #include "mozilla/ipc/GeckoChildProcessHost.h"
 | |
| #include "mozilla/ipc/ProcessChild.h"
 | |
| #include "mozilla/ipc/TestShellChild.h"
 | |
| #include "mozilla/layers/APZChild.h"
 | |
| #include "mozilla/layers/CompositorManagerChild.h"
 | |
| #include "mozilla/layers/ContentProcessController.h"
 | |
| #include "mozilla/layers/ImageBridgeChild.h"
 | |
| #ifdef NS_PRINTING
 | |
| #  include "mozilla/layout/RemotePrintJobChild.h"
 | |
| #endif
 | |
| #include "mozilla/loader/ScriptCacheActors.h"
 | |
| #include "mozilla/media/MediaChild.h"
 | |
| #include "mozilla/net/CaptivePortalService.h"
 | |
| #include "mozilla/net/ChildDNSService.h"
 | |
| #include "mozilla/net/CookieServiceChild.h"
 | |
| #include "mozilla/net/DocumentChannelChild.h"
 | |
| #include "mozilla/net/HttpChannelChild.h"
 | |
| #include "mozilla/widget/RemoteLookAndFeel.h"
 | |
| #include "mozilla/widget/ScreenManager.h"
 | |
| #include "mozilla/widget/WidgetMessageUtils.h"
 | |
| #include "nsBaseDragService.h"
 | |
| #include "nsDocShellLoadTypes.h"
 | |
| #include "nsFocusManager.h"
 | |
| #include "nsHttpHandler.h"
 | |
| #include "nsIConsoleService.h"
 | |
| #include "nsIInputStreamChannel.h"
 | |
| #include "nsILayoutHistoryState.h"
 | |
| #include "nsILoadGroup.h"
 | |
| #include "nsIOpenWindowInfo.h"
 | |
| #include "nsISimpleEnumerator.h"
 | |
| #include "nsIStringBundle.h"
 | |
| #include "nsIURIMutator.h"
 | |
| #include "nsQueryObject.h"
 | |
| #include "nsRefreshDriver.h"
 | |
| #include "nsSandboxFlags.h"
 | |
| #include "mozmemory.h"
 | |
| 
 | |
| #include "ChildProfilerController.h"
 | |
| 
 | |
| #if defined(MOZ_SANDBOX)
 | |
| #  include "mozilla/SandboxSettings.h"
 | |
| #  if defined(XP_WIN)
 | |
| #    include "mozilla/sandboxTarget.h"
 | |
| #  elif defined(XP_LINUX)
 | |
| #    include "CubebUtils.h"
 | |
| #    include "mozilla/Sandbox.h"
 | |
| #    include "mozilla/SandboxInfo.h"
 | |
| #  elif defined(XP_MACOSX)
 | |
| #    include <CoreGraphics/CGError.h>
 | |
| #    include "mozilla/Sandbox.h"
 | |
| #  elif defined(__OpenBSD__)
 | |
| #    include <err.h>
 | |
| #    include <sys/stat.h>
 | |
| #    include <unistd.h>
 | |
| 
 | |
| #    include <fstream>
 | |
| 
 | |
| #    include "BinaryPath.h"
 | |
| #    include "SpecialSystemDirectory.h"
 | |
| #    include "nsILineInputStream.h"
 | |
| #    include "mozilla/ipc/UtilityProcessSandboxing.h"
 | |
| #  endif
 | |
| #  if defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
 | |
| #    include "mozilla/SandboxTestingChild.h"
 | |
| #  endif
 | |
| #endif
 | |
| 
 | |
| #include "SandboxHal.h"
 | |
| #include "mozInlineSpellChecker.h"
 | |
| #include "mozilla/GlobalStyleSheetCache.h"
 | |
| #include "nsAnonymousTemporaryFile.h"
 | |
| #include "nsCategoryManagerUtils.h"
 | |
| #include "nsClipboardProxy.h"
 | |
| #include "nsContentPermissionHelper.h"
 | |
| #include "nsDebugImpl.h"
 | |
| #include "nsDirectoryService.h"
 | |
| #include "nsDirectoryServiceDefs.h"
 | |
| #include "nsDirectoryServiceUtils.h"
 | |
| #include "nsDocShell.h"
 | |
| #include "nsDocShellLoadState.h"
 | |
| #include "nsHashPropertyBag.h"
 | |
| #include "nsIConsoleListener.h"
 | |
| #include "nsICycleCollectorListener.h"
 | |
| #include "nsIDocShellTreeOwner.h"
 | |
| #include "nsIDocumentViewer.h"
 | |
| #include "nsIDragService.h"
 | |
| #include "nsIInterfaceRequestorUtils.h"
 | |
| #include "nsIMemoryInfoDumper.h"
 | |
| #include "nsIMemoryReporter.h"
 | |
| #include "nsIObserverService.h"
 | |
| #include "nsIOService.h"
 | |
| #include "nsIScriptError.h"
 | |
| #include "nsIScriptSecurityManager.h"
 | |
| #include "nsJSEnvironment.h"
 | |
| #include "nsJSUtils.h"
 | |
| #include "nsMemoryInfoDumper.h"
 | |
| #include "nsServiceManagerUtils.h"
 | |
| #include "nsStyleSheetService.h"
 | |
| #include "nsThreadManager.h"
 | |
| #include "nsVariant.h"
 | |
| #include "nsXULAppAPI.h"
 | |
| #include "IHistory.h"
 | |
| #include "ReferrerInfo.h"
 | |
| #include "base/message_loop.h"
 | |
| #include "base/process_util.h"
 | |
| #include "base/task.h"
 | |
| #include "mozilla/dom/BlobURLProtocolHandler.h"
 | |
| #include "mozilla/dom/PCycleCollectWithLogsChild.h"
 | |
| #include "mozilla/dom/PerformanceStorage.h"
 | |
| #include "nsChromeRegistryContent.h"
 | |
| #include "nsFrameMessageManager.h"
 | |
| #include "nsNetUtil.h"
 | |
| #include "nsWindowMemoryReporter.h"
 | |
| 
 | |
| #ifdef MOZ_WEBRTC
 | |
| #  include "jsapi/WebrtcGlobalChild.h"
 | |
| #endif
 | |
| 
 | |
| #include "PermissionMessageUtils.h"
 | |
| #include "mozilla/Permission.h"
 | |
| #include "mozilla/PermissionManager.h"
 | |
| 
 | |
| #if defined(MOZ_WIDGET_ANDROID)
 | |
| #  include "APKOpen.h"
 | |
| #  include <sched.h>
 | |
| #endif
 | |
| 
 | |
| #ifdef XP_WIN
 | |
| #  include <process.h>
 | |
| #  define getpid _getpid
 | |
| #  include "mozilla/WinDllServices.h"
 | |
| #endif
 | |
| 
 | |
| #if defined(XP_MACOSX)
 | |
| #  include "nsMacUtilsImpl.h"
 | |
| #  include <sys/qos.h>
 | |
| #endif /* XP_MACOSX */
 | |
| 
 | |
| #ifdef MOZ_X11
 | |
| #  include "mozilla/X11Util.h"
 | |
| #endif
 | |
| 
 | |
| #ifdef ACCESSIBILITY
 | |
| #  include "nsAccessibilityService.h"
 | |
| #  ifdef XP_WIN
 | |
| #    include "mozilla/a11y/AccessibleWrap.h"
 | |
| #  endif
 | |
| #  include "mozilla/a11y/DocAccessible.h"
 | |
| #  include "mozilla/a11y/DocManager.h"
 | |
| #  include "mozilla/a11y/OuterDocAccessible.h"
 | |
| #endif
 | |
| 
 | |
| #include "mozilla/dom/File.h"
 | |
| #include "mozilla/dom/MediaControllerBinding.h"
 | |
| 
 | |
| #ifdef MOZ_WEBSPEECH
 | |
| #  include "mozilla/dom/PSpeechSynthesisChild.h"
 | |
| #endif
 | |
| 
 | |
| #include "ClearOnShutdown.h"
 | |
| #include "DomainPolicy.h"
 | |
| #include "GfxInfoBase.h"
 | |
| #include "MMPrinter.h"
 | |
| #include "mozilla/ipc/ProcessUtils.h"
 | |
| #include "mozilla/ipc/URIUtils.h"
 | |
| #include "VRManagerChild.h"
 | |
| #include "gfxPlatform.h"
 | |
| #include "gfxPlatformFontList.h"
 | |
| #include "mozilla/RemoteSpellCheckEngineChild.h"
 | |
| #include "mozilla/dom/TabContext.h"
 | |
| #include "mozilla/dom/ipc/StructuredCloneData.h"
 | |
| #include "mozilla/ipc/CrashReporterClient.h"
 | |
| #include "mozilla/net/NeckoMessageUtils.h"
 | |
| #include "mozilla/widget/PuppetBidiKeyboard.h"
 | |
| #include "nsContentUtils.h"
 | |
| #include "nsIPrincipal.h"
 | |
| #include "nsString.h"
 | |
| #include "nscore.h"  // for NS_FREE_PERMANENT_DATA
 | |
| #include "private/pprio.h"
 | |
| 
 | |
| #ifdef MOZ_WIDGET_GTK
 | |
| #  include "mozilla/WidgetUtilsGtk.h"
 | |
| #  include "nsAppRunner.h"
 | |
| #  include <gtk/gtk.h>
 | |
| #endif
 | |
| 
 | |
| #ifdef MOZ_CODE_COVERAGE
 | |
| #  include "mozilla/CodeCoverageHandler.h"
 | |
| #endif
 | |
| 
 | |
| extern mozilla::LazyLogModule gSHIPBFCacheLog;
 | |
| 
 | |
| using namespace mozilla;
 | |
| using namespace mozilla::dom::ipc;
 | |
| using namespace mozilla::media;
 | |
| using namespace mozilla::embedding;
 | |
| using namespace mozilla::gmp;
 | |
| using namespace mozilla::hal_sandbox;
 | |
| using namespace mozilla::ipc;
 | |
| using namespace mozilla::intl;
 | |
| using namespace mozilla::layers;
 | |
| using namespace mozilla::layout;
 | |
| using namespace mozilla::net;
 | |
| using namespace mozilla::widget;
 | |
| using mozilla::loader::PScriptCacheChild;
 | |
| 
 | |
| namespace geckoprofiler::markers {
 | |
| struct ProcessPriorityChange {
 | |
|   static constexpr Span<const char> MarkerTypeName() {
 | |
|     return MakeStringSpan("ProcessPriorityChange");
 | |
|   }
 | |
|   static void StreamJSONMarkerData(baseprofiler::SpliceableJSONWriter& aWriter,
 | |
|                                    const ProfilerString8View& aPreviousPriority,
 | |
|                                    const ProfilerString8View& aNewPriority) {
 | |
|     aWriter.StringProperty("Before", aPreviousPriority);
 | |
|     aWriter.StringProperty("After", aNewPriority);
 | |
|   }
 | |
|   static MarkerSchema MarkerTypeDisplay() {
 | |
|     using MS = MarkerSchema;
 | |
|     MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
 | |
|     schema.AddKeyFormat("Before", MS::Format::String);
 | |
|     schema.AddKeyFormat("After", MS::Format::String);
 | |
|     schema.AddStaticLabelValue("Note",
 | |
|                                "This is a notification of the priority change "
 | |
|                                "that was done by the parent process");
 | |
|     schema.SetAllLabels(
 | |
|         "priority: {marker.data.Before} -> {marker.data.After}");
 | |
|     return schema;
 | |
|   }
 | |
| };
 | |
| 
 | |
| struct ProcessPriority {
 | |
|   static constexpr Span<const char> MarkerTypeName() {
 | |
|     return MakeStringSpan("ProcessPriority");
 | |
|   }
 | |
|   static void StreamJSONMarkerData(baseprofiler::SpliceableJSONWriter& aWriter,
 | |
|                                    const ProfilerString8View& aPriority,
 | |
|                                    const ProfilingState& aProfilingState) {
 | |
|     aWriter.StringProperty("Priority", aPriority);
 | |
|     aWriter.StringProperty("Marker cause",
 | |
|                            ProfilerString8View::WrapNullTerminatedString(
 | |
|                                ProfilingStateToString(aProfilingState)));
 | |
|   }
 | |
|   static MarkerSchema MarkerTypeDisplay() {
 | |
|     using MS = MarkerSchema;
 | |
|     MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
 | |
|     schema.AddKeyFormat("Priority", MS::Format::String);
 | |
|     schema.AddKeyFormat("Marker cause", MS::Format::String);
 | |
|     schema.SetAllLabels("priority: {marker.data.Priority}");
 | |
|     return schema;
 | |
|   }
 | |
| };
 | |
| }  // namespace geckoprofiler::markers
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace dom {
 | |
| 
 | |
| // IPC sender for remote GC/CC logging.
 | |
| class CycleCollectWithLogsChild final : public PCycleCollectWithLogsChild {
 | |
|  public:
 | |
|   NS_INLINE_DECL_REFCOUNTING(CycleCollectWithLogsChild)
 | |
| 
 | |
|   class Sink final : public nsICycleCollectorLogSink {
 | |
|     NS_DECL_ISUPPORTS
 | |
| 
 | |
|     Sink(CycleCollectWithLogsChild* aActor, const FileDescriptor& aGCLog,
 | |
|          const FileDescriptor& aCCLog) {
 | |
|       mActor = aActor;
 | |
|       mGCLog = FileDescriptorToFILE(aGCLog, "w");
 | |
|       mCCLog = FileDescriptorToFILE(aCCLog, "w");
 | |
|     }
 | |
| 
 | |
|     NS_IMETHOD Open(FILE** aGCLog, FILE** aCCLog) override {
 | |
|       if (NS_WARN_IF(!mGCLog) || NS_WARN_IF(!mCCLog)) {
 | |
|         return NS_ERROR_FAILURE;
 | |
|       }
 | |
|       *aGCLog = mGCLog;
 | |
|       *aCCLog = mCCLog;
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     NS_IMETHOD CloseGCLog() override {
 | |
|       MOZ_ASSERT(mGCLog);
 | |
|       fclose(mGCLog);
 | |
|       mGCLog = nullptr;
 | |
|       mActor->SendCloseGCLog();
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     NS_IMETHOD CloseCCLog() override {
 | |
|       MOZ_ASSERT(mCCLog);
 | |
|       fclose(mCCLog);
 | |
|       mCCLog = nullptr;
 | |
|       mActor->SendCloseCCLog();
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     NS_IMETHOD GetFilenameIdentifier(nsAString& aIdentifier) override {
 | |
|       return UnimplementedProperty();
 | |
|     }
 | |
| 
 | |
|     NS_IMETHOD SetFilenameIdentifier(const nsAString& aIdentifier) override {
 | |
|       return UnimplementedProperty();
 | |
|     }
 | |
| 
 | |
|     NS_IMETHOD GetProcessIdentifier(int32_t* aIdentifier) override {
 | |
|       return UnimplementedProperty();
 | |
|     }
 | |
| 
 | |
|     NS_IMETHOD SetProcessIdentifier(int32_t aIdentifier) override {
 | |
|       return UnimplementedProperty();
 | |
|     }
 | |
| 
 | |
|     NS_IMETHOD GetGcLog(nsIFile** aPath) override {
 | |
|       return UnimplementedProperty();
 | |
|     }
 | |
| 
 | |
|     NS_IMETHOD GetCcLog(nsIFile** aPath) override {
 | |
|       return UnimplementedProperty();
 | |
|     }
 | |
| 
 | |
|    private:
 | |
|     ~Sink() {
 | |
|       if (mGCLog) {
 | |
|         fclose(mGCLog);
 | |
|         mGCLog = nullptr;
 | |
|       }
 | |
|       if (mCCLog) {
 | |
|         fclose(mCCLog);
 | |
|         mCCLog = nullptr;
 | |
|       }
 | |
|       // The XPCOM refcount drives the IPC lifecycle;
 | |
|       Unused << mActor->Send__delete__(mActor);
 | |
|     }
 | |
| 
 | |
|     nsresult UnimplementedProperty() {
 | |
|       MOZ_ASSERT(false,
 | |
|                  "This object is a remote GC/CC logger;"
 | |
|                  " this property isn't meaningful.");
 | |
|       return NS_ERROR_UNEXPECTED;
 | |
|     }
 | |
| 
 | |
|     RefPtr<CycleCollectWithLogsChild> mActor;
 | |
|     FILE* mGCLog;
 | |
|     FILE* mCCLog;
 | |
|   };
 | |
| 
 | |
|  private:
 | |
|   ~CycleCollectWithLogsChild() = default;
 | |
| };
 | |
| 
 | |
| NS_IMPL_ISUPPORTS(CycleCollectWithLogsChild::Sink, nsICycleCollectorLogSink);
 | |
| 
 | |
| class AlertObserver {
 | |
|  public:
 | |
|   AlertObserver(nsIObserver* aObserver, const nsString& aData)
 | |
|       : mObserver(aObserver), mData(aData) {}
 | |
| 
 | |
|   ~AlertObserver() = default;
 | |
| 
 | |
|   nsCOMPtr<nsIObserver> mObserver;
 | |
|   nsString mData;
 | |
| };
 | |
| 
 | |
| class ConsoleListener final : public nsIConsoleListener {
 | |
|  public:
 | |
|   explicit ConsoleListener(ContentChild* aChild) : mChild(aChild) {}
 | |
| 
 | |
|   NS_DECL_ISUPPORTS
 | |
|   NS_DECL_NSICONSOLELISTENER
 | |
| 
 | |
|  private:
 | |
|   ~ConsoleListener() = default;
 | |
| 
 | |
|   ContentChild* mChild;
 | |
|   friend class ContentChild;
 | |
| };
 | |
| 
 | |
| NS_IMPL_ISUPPORTS(ConsoleListener, nsIConsoleListener)
 | |
| 
 | |
| // Before we send the error to the parent process (which
 | |
| // involves copying the memory), truncate any long lines.  CSS
 | |
| // errors in particular share the memory for long lines with
 | |
| // repeated errors, but the IPC communication we're about to do
 | |
| // will break that sharing, so we better truncate now.
 | |
| static void TruncateString(nsAString& aString) {
 | |
|   if (aString.Length() > 1000) {
 | |
|     aString.Truncate(1000);
 | |
|   }
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| ConsoleListener::Observe(nsIConsoleMessage* aMessage) {
 | |
|   if (!mChild) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIScriptError> scriptError = do_QueryInterface(aMessage);
 | |
|   if (scriptError) {
 | |
|     nsAutoString msg, sourceName, sourceLine;
 | |
|     nsCString category;
 | |
|     uint32_t lineNum, colNum, flags;
 | |
|     bool fromPrivateWindow, fromChromeContext;
 | |
| 
 | |
|     nsresult rv = scriptError->GetErrorMessage(msg);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
|     TruncateString(msg);
 | |
|     rv = scriptError->GetSourceName(sourceName);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
|     TruncateString(sourceName);
 | |
|     rv = scriptError->GetSourceLine(sourceLine);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
|     TruncateString(sourceLine);
 | |
| 
 | |
|     rv = scriptError->GetCategory(getter_Copies(category));
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
|     rv = scriptError->GetLineNumber(&lineNum);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
|     rv = scriptError->GetColumnNumber(&colNum);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
|     rv = scriptError->GetFlags(&flags);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
|     rv = scriptError->GetIsFromPrivateWindow(&fromPrivateWindow);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
|     rv = scriptError->GetIsFromChromeContext(&fromChromeContext);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|     {
 | |
|       AutoJSAPI jsapi;
 | |
|       jsapi.Init();
 | |
|       JSContext* cx = jsapi.cx();
 | |
| 
 | |
|       JS::Rooted<JS::Value> stack(cx);
 | |
|       rv = scriptError->GetStack(&stack);
 | |
|       NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|       if (stack.isObject()) {
 | |
|         // Because |stack| might be a cross-compartment wrapper, we can't use it
 | |
|         // with JSAutoRealm. Use the stackGlobal for that.
 | |
|         JS::Rooted<JS::Value> stackGlobal(cx);
 | |
|         rv = scriptError->GetStackGlobal(&stackGlobal);
 | |
|         NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|         JSAutoRealm ar(cx, &stackGlobal.toObject());
 | |
| 
 | |
|         StructuredCloneData data;
 | |
|         ErrorResult err;
 | |
|         data.Write(cx, stack, err);
 | |
|         if (err.Failed()) {
 | |
|           return err.StealNSResult();
 | |
|         }
 | |
| 
 | |
|         ClonedMessageData cloned;
 | |
|         if (!data.BuildClonedMessageData(cloned)) {
 | |
|           return NS_ERROR_FAILURE;
 | |
|         }
 | |
| 
 | |
|         mChild->SendScriptErrorWithStack(
 | |
|             msg, sourceName, sourceLine, lineNum, colNum, flags, category,
 | |
|             fromPrivateWindow, fromChromeContext, cloned);
 | |
|         return NS_OK;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     mChild->SendScriptError(msg, sourceName, sourceLine, lineNum, colNum, flags,
 | |
|                             category, fromPrivateWindow, 0, fromChromeContext);
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   nsString msg;
 | |
|   nsresult rv = aMessage->GetMessageMoz(msg);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
|   mChild->SendConsoleMessage(msg);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| #ifdef NIGHTLY_BUILD
 | |
| /**
 | |
|  * The singleton of this class is registered with the BackgroundHangMonitor as
 | |
|  * an annotator, so that the hang monitor can record whether or not there were
 | |
|  * pending input events when the thread hung.
 | |
|  */
 | |
| class PendingInputEventHangAnnotator final : public BackgroundHangAnnotator {
 | |
|  public:
 | |
|   virtual void AnnotateHang(BackgroundHangAnnotations& aAnnotations) override {
 | |
|     int32_t pending = ContentChild::GetSingleton()->GetPendingInputEvents();
 | |
|     if (pending > 0) {
 | |
|       aAnnotations.AddAnnotation(u"PendingInput"_ns, pending);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   static PendingInputEventHangAnnotator sSingleton;
 | |
| };
 | |
| PendingInputEventHangAnnotator PendingInputEventHangAnnotator::sSingleton;
 | |
| #endif
 | |
| 
 | |
| class ContentChild::ShutdownCanary final {};
 | |
| 
 | |
| ContentChild* ContentChild::sSingleton;
 | |
| StaticAutoPtr<ContentChild::ShutdownCanary> ContentChild::sShutdownCanary;
 | |
| 
 | |
| ContentChild::ContentChild()
 | |
|     : mID(uint64_t(-1)),
 | |
|       mIsForBrowser(false),
 | |
|       mIsAlive(true),
 | |
|       mShuttingDown(false) {
 | |
|   // This process is a content process, so it's clearly running in
 | |
|   // multiprocess mode!
 | |
|   nsDebugImpl::SetMultiprocessMode("Child");
 | |
| 
 | |
|   // Our static analysis doesn't allow capturing ref-counted pointers in
 | |
|   // lambdas, so we need to hide it in a uintptr_t. This is safe because this
 | |
|   // lambda will be destroyed in ~ContentChild().
 | |
|   uintptr_t self = reinterpret_cast<uintptr_t>(this);
 | |
|   profiler_add_state_change_callback(
 | |
|       AllProfilingStates(),
 | |
|       [self](ProfilingState aProfilingState) {
 | |
|         const ContentChild* selfPtr =
 | |
|             reinterpret_cast<const ContentChild*>(self);
 | |
|         PROFILER_MARKER("Process Priority", OTHER,
 | |
|                         mozilla::MarkerThreadId::MainThread(), ProcessPriority,
 | |
|                         ProfilerString8View::WrapNullTerminatedString(
 | |
|                             ProcessPriorityToString(selfPtr->mProcessPriority)),
 | |
|                         aProfilingState);
 | |
|       },
 | |
|       self);
 | |
| 
 | |
|   // When ContentChild is created, the observer service does not even exist.
 | |
|   // When ContentChild::RecvSetXPCOMProcessAttributes is called (the first
 | |
|   // IPDL call made on this object), shutdown may have already happened. Thus
 | |
|   // we create a canary here that relies upon getting cleared if shutdown
 | |
|   // happens without requiring the observer service at this time.
 | |
|   if (!sShutdownCanary) {
 | |
|     sShutdownCanary = new ShutdownCanary();
 | |
|     ClearOnShutdown(&sShutdownCanary, ShutdownPhase::XPCOMShutdown);
 | |
|   }
 | |
| }
 | |
| 
 | |
| #ifdef _MSC_VER
 | |
| #  pragma warning(push)
 | |
| #  pragma warning(                                                  \
 | |
|       disable : 4722) /* Silence "destructor never returns" warning \
 | |
|                        */
 | |
| #endif
 | |
| 
 | |
| ContentChild::~ContentChild() {
 | |
|   profiler_remove_state_change_callback(reinterpret_cast<uintptr_t>(this));
 | |
| 
 | |
| #ifndef NS_FREE_PERMANENT_DATA
 | |
|   MOZ_CRASH("Content Child shouldn't be destroyed.");
 | |
| #endif
 | |
| }
 | |
| 
 | |
| #ifdef _MSC_VER
 | |
| #  pragma warning(pop)
 | |
| #endif
 | |
| 
 | |
| NS_INTERFACE_MAP_BEGIN(ContentChild)
 | |
|   NS_INTERFACE_MAP_ENTRY(nsIDOMProcessChild)
 | |
|   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMProcessChild)
 | |
| NS_INTERFACE_MAP_END
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvSetXPCOMProcessAttributes(
 | |
|     XPCOMInitData&& aXPCOMInit, const StructuredCloneData& aInitialData,
 | |
|     FullLookAndFeel&& aLookAndFeelData, dom::SystemFontList&& aFontList,
 | |
|     Maybe<SharedMemoryHandle>&& aSharedUASheetHandle,
 | |
|     const uintptr_t& aSharedUASheetAddress,
 | |
|     nsTArray<SharedMemoryHandle>&& aSharedFontListBlocks,
 | |
|     const bool& aIsReadyForBackgroundProcessing) {
 | |
|   if (!sShutdownCanary) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   mLookAndFeelData = std::move(aLookAndFeelData);
 | |
|   mFontList = std::move(aFontList);
 | |
|   mSharedFontListBlocks = std::move(aSharedFontListBlocks);
 | |
| 
 | |
|   gfx::gfxVars::SetValuesForInitialize(aXPCOMInit.gfxNonDefaultVarUpdates());
 | |
|   PerfStats::SetCollectionMask(aXPCOMInit.perfStatsMask());
 | |
|   InitSharedUASheets(std::move(aSharedUASheetHandle), aSharedUASheetAddress);
 | |
|   InitXPCOM(std::move(aXPCOMInit), aInitialData,
 | |
|             aIsReadyForBackgroundProcessing);
 | |
|   InitGraphicsDeviceData(aXPCOMInit.contentDeviceData());
 | |
|   RefPtr<net::ChildDNSService> dnsServiceChild =
 | |
|       dont_AddRef(net::ChildDNSService::GetSingleton());
 | |
|   if (dnsServiceChild) {
 | |
|     dnsServiceChild->SetTRRDomain(aXPCOMInit.trrDomain());
 | |
|     dnsServiceChild->SetTRRModeInChild(aXPCOMInit.trrMode(),
 | |
|                                        aXPCOMInit.trrModeFromPref());
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| class nsGtkNativeInitRunnable : public Runnable {
 | |
|  public:
 | |
|   nsGtkNativeInitRunnable() : Runnable("nsGtkNativeInitRunnable") {}
 | |
| 
 | |
|   NS_IMETHOD Run() override {
 | |
|     LookAndFeel::NativeInit();
 | |
|     return NS_OK;
 | |
|   }
 | |
| };
 | |
| 
 | |
| void ContentChild::Init(mozilla::ipc::UntypedEndpoint&& aEndpoint,
 | |
|                         const char* aParentBuildID, uint64_t aChildID,
 | |
|                         bool aIsForBrowser) {
 | |
| #ifdef MOZ_WIDGET_GTK
 | |
|   // When running X11 only build we need to pass a display down
 | |
|   // to gtk_init because it's not going to use the one from the environment
 | |
|   // on its own when deciding which backend to use, and when starting under
 | |
|   // XWayland, it may choose to start with the wayland backend
 | |
|   // instead of the x11 backend.
 | |
|   // The DISPLAY environment variable is normally set by the parent process.
 | |
|   // The MOZ_GDK_DISPLAY environment variable is set from nsAppRunner.cpp
 | |
|   // when --display is set by the command line.
 | |
|   if (!gfxPlatform::IsHeadless()) {
 | |
|     const char* display_name = PR_GetEnv("MOZ_GDK_DISPLAY");
 | |
|     if (!display_name) {
 | |
|       bool waylandEnabled = false;
 | |
| #  ifdef MOZ_WAYLAND
 | |
|       waylandEnabled = IsWaylandEnabled();
 | |
| #  endif
 | |
|       if (!waylandEnabled) {
 | |
|         display_name = PR_GetEnv("DISPLAY");
 | |
|       }
 | |
|     }
 | |
|     if (display_name) {
 | |
|       int argc = 3;
 | |
|       char option_name[] = "--display";
 | |
|       char* argv[] = {
 | |
|           // argv0 is unused because g_set_prgname() was called in
 | |
|           // XRE_InitChildProcess().
 | |
|           nullptr, option_name, const_cast<char*>(display_name), nullptr};
 | |
|       char** argvp = argv;
 | |
|       gtk_init(&argc, &argvp);
 | |
|     } else {
 | |
|       gtk_init(nullptr, nullptr);
 | |
|     }
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| #ifdef MOZ_X11
 | |
|   if (!gfxPlatform::IsHeadless()) {
 | |
|     // Do this after initializing GDK, or GDK will install its own handler.
 | |
|     XRE_InstallX11ErrorHandler();
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   MOZ_ASSERT(!sSingleton, "only one ContentChild per child");
 | |
| 
 | |
|   // Once we start sending IPC messages, we need the thread manager to be
 | |
|   // initialized so we can deal with the responses. Do that here before we
 | |
|   // try to construct the crash reporter.
 | |
|   nsresult rv = nsThreadManager::get().Init();
 | |
|   if (NS_WARN_IF(NS_FAILED(rv))) {
 | |
|     MOZ_CRASH("Failed to initialize the thread manager in ContentChild::Init");
 | |
|   }
 | |
| 
 | |
|   if (!aEndpoint.Bind(this)) {
 | |
|     MOZ_CRASH("Bind failed in ContentChild::Init");
 | |
|   }
 | |
|   sSingleton = this;
 | |
| 
 | |
|   // If communications with the parent have broken down, take the process
 | |
|   // down so it's not hanging around.
 | |
|   GetIPCChannel()->SetAbortOnError(true);
 | |
| 
 | |
|   // This must be checked before any IPDL message, which may hit sentinel
 | |
|   // errors due to parent and content processes having different
 | |
|   // versions.
 | |
|   MessageChannel* channel = GetIPCChannel();
 | |
|   if (channel && !channel->SendBuildIDsMatchMessage(aParentBuildID)) {
 | |
|     // We need to quit this process if the buildID doesn't match the parent's.
 | |
|     // This can occur when an update occurred in the background.
 | |
|     ProcessChild::QuickExit();
 | |
|   }
 | |
| 
 | |
| #if defined(__OpenBSD__) && defined(MOZ_SANDBOX)
 | |
|   StartOpenBSDSandbox(GeckoProcessType_Content);
 | |
| #endif
 | |
| 
 | |
| #ifdef MOZ_X11
 | |
| #  ifdef MOZ_WIDGET_GTK
 | |
|   if (GdkIsX11Display() && !gfxPlatform::IsHeadless()) {
 | |
|     // Send the parent our X socket to act as a proxy reference for our X
 | |
|     // resources.
 | |
|     int xSocketFd = ConnectionNumber(DefaultXDisplay());
 | |
|     SendBackUpXResources(FileDescriptor(xSocketFd));
 | |
|   }
 | |
| #  endif
 | |
| #endif
 | |
| 
 | |
|   CrashReporterClient::InitSingleton(this);
 | |
| 
 | |
|   mID = aChildID;
 | |
|   mIsForBrowser = aIsForBrowser;
 | |
| 
 | |
|   SetProcessName("Web Content"_ns);
 | |
| 
 | |
| #ifdef NIGHTLY_BUILD
 | |
|   // NOTE: We have to register the annotator on the main thread, as annotators
 | |
|   // only affect a single thread.
 | |
|   SchedulerGroup::Dispatch(
 | |
|       NS_NewRunnableFunction("RegisterPendingInputEventHangAnnotator", [] {
 | |
|         BackgroundHangMonitor::RegisterAnnotator(
 | |
|             PendingInputEventHangAnnotator::sSingleton);
 | |
|       }));
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void ContentChild::AddProfileToProcessName(const nsACString& aProfile) {
 | |
|   nsCOMPtr<nsIPrincipal> isolationPrincipal =
 | |
|       ContentParent::CreateRemoteTypeIsolationPrincipal(mRemoteType);
 | |
|   if (isolationPrincipal) {
 | |
|     // DEFAULT_PRIVATE_BROWSING_ID is the value when it's not private
 | |
|     if (isolationPrincipal->OriginAttributesRef().mPrivateBrowsingId !=
 | |
|         nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID) {
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   mProcessName = aProfile + ":"_ns + mProcessName;  //<profile_name>:example.com
 | |
| }
 | |
| 
 | |
| void ContentChild::SetProcessName(const nsACString& aName,
 | |
|                                   const nsACString* aSite,
 | |
|                                   const nsACString* aCurrentProfile) {
 | |
|   char* name;
 | |
|   if ((name = PR_GetEnv("MOZ_DEBUG_APP_PROCESS")) && aName.EqualsASCII(name)) {
 | |
| #ifdef XP_UNIX
 | |
|     printf_stderr("\n\nCHILDCHILDCHILDCHILD\n  [%s] debug me @%d\n\n", name,
 | |
|                   getpid());
 | |
|     sleep(30);
 | |
| #elif defined(XP_WIN)
 | |
|     // Windows has a decent JIT debugging story, so NS_DebugBreak does the
 | |
|     // right thing.
 | |
|     NS_DebugBreak(NS_DEBUG_BREAK,
 | |
|                   "Invoking NS_DebugBreak() to debug child process", nullptr,
 | |
|                   __FILE__, __LINE__);
 | |
| #endif
 | |
|   }
 | |
| 
 | |
|   if (aSite) {
 | |
|     profiler_set_process_name(aName, aSite);
 | |
|   } else {
 | |
|     profiler_set_process_name(aName);
 | |
|   }
 | |
| 
 | |
|   mProcessName = aName;
 | |
| 
 | |
|   // Requires pref flip
 | |
|   if (aSite && StaticPrefs::fission_processSiteNames()) {
 | |
|     nsCOMPtr<nsIPrincipal> isolationPrincipal =
 | |
|         ContentParent::CreateRemoteTypeIsolationPrincipal(mRemoteType);
 | |
|     if (isolationPrincipal) {
 | |
|       // DEFAULT_PRIVATE_BROWSING_ID is the value when it's not private
 | |
|       MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | |
|               ("private = %d, pref = %d",
 | |
|                isolationPrincipal->OriginAttributesRef().mPrivateBrowsingId !=
 | |
|                    nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID,
 | |
|                StaticPrefs::fission_processPrivateWindowSiteNames()));
 | |
|       if (isolationPrincipal->OriginAttributesRef().mPrivateBrowsingId ==
 | |
|               nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID
 | |
| #ifdef NIGHTLY_BUILD
 | |
|           // Nightly can show site names for private windows, with a second pref
 | |
|           || StaticPrefs::fission_processPrivateWindowSiteNames()
 | |
| #endif
 | |
|       ) {
 | |
| #if !defined(XP_MACOSX)
 | |
|         // Mac doesn't have the 15-character limit Linux does
 | |
|         // Sets profiler process name
 | |
|         if (isolationPrincipal->SchemeIs("https")) {
 | |
|           nsAutoCString schemeless;
 | |
|           isolationPrincipal->GetHostPort(schemeless);
 | |
|           nsAutoCString originSuffix;
 | |
|           isolationPrincipal->GetOriginSuffix(originSuffix);
 | |
|           schemeless.Append(originSuffix);
 | |
|           mProcessName = schemeless;
 | |
|         } else
 | |
| #endif
 | |
|         {
 | |
|           mProcessName = *aSite;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (StaticPrefs::fission_processProfileName() && aCurrentProfile &&
 | |
|       !aCurrentProfile->IsEmpty()) {
 | |
|     AddProfileToProcessName(*aCurrentProfile);
 | |
|   }
 | |
| 
 | |
|   // else private window, don't change process name, or the pref isn't set
 | |
|   // mProcessName is always flat (mProcessName == aName)
 | |
| 
 | |
|   mozilla::ipc::SetThisProcessName(mProcessName.get());
 | |
| 
 | |
|   MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | |
|           ("Changed name of process %d to %s", getpid(),
 | |
|            PromiseFlatCString(mProcessName).get()));
 | |
| }
 | |
| 
 | |
| static nsresult GetCreateWindowParams(nsIOpenWindowInfo* aOpenWindowInfo,
 | |
|                                       nsDocShellLoadState* aLoadState,
 | |
|                                       bool aForceNoReferrer,
 | |
|                                       nsIReferrerInfo** aReferrerInfo,
 | |
|                                       nsIPrincipal** aTriggeringPrincipal,
 | |
|                                       nsIContentSecurityPolicy** aCsp) {
 | |
|   if (!aTriggeringPrincipal || !aCsp) {
 | |
|     NS_ERROR("aTriggeringPrincipal || aCsp is null");
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   if (!aReferrerInfo) {
 | |
|     NS_ERROR("aReferrerInfo is null");
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIReferrerInfo> referrerInfo;
 | |
|   if (aForceNoReferrer) {
 | |
|     referrerInfo = new ReferrerInfo(nullptr, ReferrerPolicy::_empty, false);
 | |
|   }
 | |
|   if (aLoadState && !referrerInfo) {
 | |
|     referrerInfo = aLoadState->GetReferrerInfo();
 | |
|   }
 | |
| 
 | |
|   RefPtr<BrowsingContext> parent = aOpenWindowInfo->GetParent();
 | |
|   nsCOMPtr<nsPIDOMWindowOuter> opener =
 | |
|       parent ? parent->GetDOMWindow() : nullptr;
 | |
|   if (!opener) {
 | |
|     nsCOMPtr<nsIPrincipal> nullPrincipal =
 | |
|         NullPrincipal::Create(aOpenWindowInfo->GetOriginAttributes());
 | |
|     if (!referrerInfo) {
 | |
|       referrerInfo = new ReferrerInfo(nullptr, ReferrerPolicy::_empty);
 | |
|     }
 | |
| 
 | |
|     referrerInfo.swap(*aReferrerInfo);
 | |
|     NS_ADDREF(*aTriggeringPrincipal = nullPrincipal);
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<Document> doc = opener->GetDoc();
 | |
|   NS_ADDREF(*aTriggeringPrincipal = doc->NodePrincipal());
 | |
| 
 | |
|   nsCOMPtr<nsIContentSecurityPolicy> csp = doc->GetCsp();
 | |
|   if (csp) {
 | |
|     csp.forget(aCsp);
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
 | |
|   if (!baseURI) {
 | |
|     NS_ERROR("Document didn't return a base URI");
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   if (!referrerInfo) {
 | |
|     referrerInfo = new ReferrerInfo(*doc);
 | |
|   }
 | |
| 
 | |
|   referrerInfo.swap(*aReferrerInfo);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult ContentChild::ProvideWindowCommon(
 | |
|     NotNull<BrowserChild*> aTabOpener, nsIOpenWindowInfo* aOpenWindowInfo,
 | |
|     uint32_t aChromeFlags, bool aCalledFromJS, nsIURI* aURI,
 | |
|     const nsAString& aName, const nsACString& aFeatures,
 | |
|     const UserActivation::Modifiers& aModifiers, bool aForceNoOpener,
 | |
|     bool aForceNoReferrer, bool aIsPopupRequested,
 | |
|     nsDocShellLoadState* aLoadState, bool* aWindowIsNew,
 | |
|     BrowsingContext** aReturn) {
 | |
|   *aReturn = nullptr;
 | |
| 
 | |
|   nsAutoCString features(aFeatures);
 | |
|   nsAutoString name(aName);
 | |
| 
 | |
|   nsresult rv;
 | |
| 
 | |
|   RefPtr<BrowsingContext> parent = aOpenWindowInfo->GetParent();
 | |
|   MOZ_DIAGNOSTIC_ASSERT(parent, "We must have a parent BC");
 | |
| 
 | |
|   // Block the attempt to open a new window if the opening BrowsingContext is
 | |
|   // not marked to use remote tabs. This ensures that the newly opened window is
 | |
|   // correctly remote.
 | |
|   if (NS_WARN_IF(!parent->UseRemoteTabs())) {
 | |
|     return NS_ERROR_ABORT;
 | |
|   }
 | |
| 
 | |
|   bool useRemoteSubframes =
 | |
|       aChromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW;
 | |
| 
 | |
|   uint32_t parentSandboxFlags = parent->SandboxFlags();
 | |
|   if (Document* doc = parent->GetDocument()) {
 | |
|     parentSandboxFlags = doc->GetSandboxFlags();
 | |
|   }
 | |
| 
 | |
|   // Certain conditions complicate the process of creating the new
 | |
|   // BrowsingContext, and prevent us from using the
 | |
|   // "CreateWindowInDifferentProcess" codepath.
 | |
|   //  * With Fission enabled, process selection will happen during the load, so
 | |
|   //    switching processes eagerly will not provide a benefit.
 | |
|   //  * Windows created for printing must be created within the current process
 | |
|   //    so that a static clone of the source document can be created.
 | |
|   //  * Sandboxed popups require the full window creation codepath.
 | |
|   //  * Loads with form or POST data require the full window creation codepath.
 | |
|   bool cannotLoadInDifferentProcess =
 | |
|       useRemoteSubframes || aOpenWindowInfo->GetIsForPrinting() ||
 | |
|       (parentSandboxFlags &
 | |
|        SANDBOX_PROPAGATES_TO_AUXILIARY_BROWSING_CONTEXTS) ||
 | |
|       (aLoadState &&
 | |
|        (aLoadState->IsFormSubmission() || aLoadState->PostDataStream()));
 | |
|   if (!cannotLoadInDifferentProcess) {
 | |
|     // If we're in a content process and we have noopener set, there's no reason
 | |
|     // to load in our process, so let's load it elsewhere!
 | |
|     bool loadInDifferentProcess =
 | |
|         aForceNoOpener && StaticPrefs::dom_noopener_newprocess_enabled();
 | |
|     if (loadInDifferentProcess) {
 | |
|       nsCOMPtr<nsIPrincipal> triggeringPrincipal;
 | |
|       nsCOMPtr<nsIContentSecurityPolicy> csp;
 | |
|       nsCOMPtr<nsIReferrerInfo> referrerInfo;
 | |
|       rv = GetCreateWindowParams(aOpenWindowInfo, aLoadState, aForceNoReferrer,
 | |
|                                  getter_AddRefs(referrerInfo),
 | |
|                                  getter_AddRefs(triggeringPrincipal),
 | |
|                                  getter_AddRefs(csp));
 | |
|       if (NS_WARN_IF(NS_FAILED(rv))) {
 | |
|         return rv;
 | |
|       }
 | |
| 
 | |
|       if (name.LowerCaseEqualsLiteral("_blank")) {
 | |
|         name.Truncate();
 | |
|       }
 | |
| 
 | |
|       MOZ_DIAGNOSTIC_ASSERT(!nsContentUtils::IsSpecialName(name));
 | |
| 
 | |
|       Unused << SendCreateWindowInDifferentProcess(
 | |
|           aTabOpener, parent, aChromeFlags, aCalledFromJS, aURI, features,
 | |
|           aModifiers, name, triggeringPrincipal, csp, referrerInfo,
 | |
|           aOpenWindowInfo->GetOriginAttributes());
 | |
| 
 | |
|       // We return NS_ERROR_ABORT, so that the caller knows that we've abandoned
 | |
|       // the window open as far as it is concerned.
 | |
|       return NS_ERROR_ABORT;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   TabId tabId(nsContentUtils::GenerateTabId());
 | |
| 
 | |
|   // We need to assign a TabGroup to the PBrowser actor before we send it to the
 | |
|   // parent. Otherwise, the parent could send messages to us before we have a
 | |
|   // proper TabGroup for that actor.
 | |
|   RefPtr<BrowsingContext> openerBC;
 | |
|   if (!aForceNoOpener) {
 | |
|     openerBC = parent;
 | |
|   }
 | |
| 
 | |
|   RefPtr<BrowsingContext> browsingContext = BrowsingContext::CreateDetached(
 | |
|       nullptr, openerBC, nullptr, aName, BrowsingContext::Type::Content,
 | |
|       aIsPopupRequested);
 | |
|   MOZ_ALWAYS_SUCCEEDS(browsingContext->SetRemoteTabs(true));
 | |
|   MOZ_ALWAYS_SUCCEEDS(browsingContext->SetRemoteSubframes(useRemoteSubframes));
 | |
|   MOZ_ALWAYS_SUCCEEDS(browsingContext->SetOriginAttributes(
 | |
|       aOpenWindowInfo->GetOriginAttributes()));
 | |
| 
 | |
|   browsingContext->InitPendingInitialization(true);
 | |
|   auto unsetPending = MakeScopeExit([browsingContext]() {
 | |
|     Unused << browsingContext->SetPendingInitialization(false);
 | |
|   });
 | |
| 
 | |
|   browsingContext->EnsureAttached();
 | |
| 
 | |
|   // The initial about:blank document we generate within the nsDocShell will
 | |
|   // almost certainly be replaced at some point. Unfortunately, getting the
 | |
|   // principal right here causes bugs due to frame scripts not getting events
 | |
|   // they expect, due to the real initial about:blank not being created yet.
 | |
|   //
 | |
|   // For this reason, we intentionally mispredict the initial principal here, so
 | |
|   // that we can act the same as we did before when not predicting a result
 | |
|   // principal. This `PWindowGlobal` will almost immediately be destroyed.
 | |
|   nsCOMPtr<nsIPrincipal> initialPrincipal =
 | |
|       NullPrincipal::Create(browsingContext->OriginAttributesRef());
 | |
|   WindowGlobalInit windowInit = WindowGlobalActor::AboutBlankInitializer(
 | |
|       browsingContext, initialPrincipal);
 | |
| 
 | |
|   RefPtr<WindowGlobalChild> windowChild =
 | |
|       WindowGlobalChild::CreateDisconnected(windowInit);
 | |
|   if (NS_WARN_IF(!windowChild)) {
 | |
|     return NS_ERROR_ABORT;
 | |
|   }
 | |
| 
 | |
|   auto newChild = MakeNotNull<RefPtr<BrowserChild>>(
 | |
|       this, tabId, *aTabOpener, browsingContext, aChromeFlags,
 | |
|       /* aIsTopLevel */ true);
 | |
| 
 | |
|   if (IsShuttingDown()) {
 | |
|     return NS_ERROR_ABORT;
 | |
|   }
 | |
| 
 | |
|   // Open a remote endpoint for our PBrowser actor.
 | |
|   ManagedEndpoint<PBrowserParent> parentEp = OpenPBrowserEndpoint(newChild);
 | |
|   if (NS_WARN_IF(!parentEp.IsValid())) {
 | |
|     return NS_ERROR_ABORT;
 | |
|   }
 | |
| 
 | |
|   // Open a remote endpoint for our PWindowGlobal actor.
 | |
|   ManagedEndpoint<PWindowGlobalParent> windowParentEp =
 | |
|       newChild->OpenPWindowGlobalEndpoint(windowChild);
 | |
|   if (NS_WARN_IF(!windowParentEp.IsValid())) {
 | |
|     return NS_ERROR_ABORT;
 | |
|   }
 | |
| 
 | |
|   // Tell the parent process to set up its PBrowserParent.
 | |
|   PopupIPCTabContext ipcContext(aTabOpener, 0);
 | |
|   if (NS_WARN_IF(!SendConstructPopupBrowser(
 | |
|           std::move(parentEp), std::move(windowParentEp), tabId, ipcContext,
 | |
|           windowInit, aChromeFlags))) {
 | |
|     return NS_ERROR_ABORT;
 | |
|   }
 | |
| 
 | |
|   windowChild->Init();
 | |
|   auto guardNullWindowGlobal = MakeScopeExit([&] {
 | |
|     if (!windowChild->GetWindowGlobal()) {
 | |
|       windowChild->Destroy();
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   // Now that |newChild| has had its IPC link established, call |Init| to set it
 | |
|   // up.
 | |
|   // XXX: This MOZ_KnownLive is only necessary because the static analysis can't
 | |
|   // tell that NotNull<RefPtr<BrowserChild>> is a strong pointer.
 | |
|   RefPtr<nsPIDOMWindowOuter> parentWindow =
 | |
|       parent ? parent->GetDOMWindow() : nullptr;
 | |
|   if (NS_FAILED(MOZ_KnownLive(newChild)->Init(parentWindow, windowChild))) {
 | |
|     return NS_ERROR_ABORT;
 | |
|   }
 | |
| 
 | |
|   // Set to true when we're ready to return from this function.
 | |
|   bool ready = false;
 | |
| 
 | |
|   // NOTE: Capturing by reference here is safe, as this function won't return
 | |
|   // until one of these callbacks is called.
 | |
|   auto resolve = [&](CreatedWindowInfo&& info) {
 | |
|     MOZ_RELEASE_ASSERT(NS_IsMainThread());
 | |
|     rv = info.rv();
 | |
|     *aWindowIsNew = info.windowOpened();
 | |
|     nsTArray<FrameScriptInfo> frameScripts(std::move(info.frameScripts()));
 | |
|     uint32_t maxTouchPoints = info.maxTouchPoints();
 | |
|     DimensionInfo dimensionInfo = std::move(info.dimensions());
 | |
| 
 | |
|     // Once this function exits, we should try to exit the nested event loop.
 | |
|     ready = true;
 | |
| 
 | |
|     // NOTE: We have to handle this immediately in the resolve callback in order
 | |
|     // to make sure that we don't process any more IPC messages before returning
 | |
|     // from ProvideWindowCommon.
 | |
| 
 | |
|     // Handle the error which we got back from the parent process, if we got
 | |
|     // one.
 | |
|     if (NS_FAILED(rv)) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     if (!*aWindowIsNew) {
 | |
|       rv = NS_ERROR_ABORT;
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     // If the BrowserChild has been torn down, we don't need to do this anymore.
 | |
|     if (NS_WARN_IF(!newChild->IPCOpen() || newChild->IsDestroyed())) {
 | |
|       rv = NS_ERROR_ABORT;
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     ParentShowInfo showInfo(u""_ns, /* fakeShowInfo = */ true,
 | |
|                             /* isTransparent = */ false,
 | |
|                             newChild->WebWidget()->GetDPI(),
 | |
|                             newChild->WebWidget()->RoundsWidgetCoordinatesTo(),
 | |
|                             newChild->WebWidget()->GetDefaultScale().scale);
 | |
| 
 | |
|     newChild->SetMaxTouchPoints(maxTouchPoints);
 | |
| 
 | |
|     if (aForceNoOpener || !parent) {
 | |
|       MOZ_DIAGNOSTIC_ASSERT(!browsingContext->HadOriginalOpener());
 | |
|       MOZ_DIAGNOSTIC_ASSERT(browsingContext->GetOpenerId() == 0);
 | |
|     } else {
 | |
|       MOZ_DIAGNOSTIC_ASSERT(browsingContext->HadOriginalOpener());
 | |
|       MOZ_DIAGNOSTIC_ASSERT(browsingContext->GetOpenerId() == parent->Id());
 | |
|     }
 | |
| 
 | |
|     // Unfortunately we don't get a window unless we've shown the frame.  That's
 | |
|     // pretty bogus; see bug 763602.
 | |
|     newChild->DoFakeShow(showInfo);
 | |
| 
 | |
|     newChild->RecvUpdateDimensions(dimensionInfo);
 | |
| 
 | |
|     for (size_t i = 0; i < frameScripts.Length(); i++) {
 | |
|       FrameScriptInfo& info = frameScripts[i];
 | |
|       if (!newChild->RecvLoadRemoteScript(info.url(),
 | |
|                                           info.runInGlobalScope())) {
 | |
|         MOZ_CRASH();
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (xpc::IsInAutomation()) {
 | |
|       if (nsCOMPtr<nsPIDOMWindowOuter> outer =
 | |
|               do_GetInterface(newChild->WebNavigation())) {
 | |
|         nsCOMPtr<nsIObserverService> obs(services::GetObserverService());
 | |
|         obs->NotifyObservers(
 | |
|             outer, "dangerous:test-only:new-browser-child-ready", nullptr);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     browsingContext.forget(aReturn);
 | |
|   };
 | |
| 
 | |
|   // NOTE: Capturing by reference here is safe, as this function won't return
 | |
|   // until one of these callbacks is called.
 | |
|   auto reject = [&](ResponseRejectReason) {
 | |
|     MOZ_RELEASE_ASSERT(NS_IsMainThread());
 | |
|     NS_WARNING("windowCreated promise rejected");
 | |
|     rv = NS_ERROR_NOT_AVAILABLE;
 | |
|     ready = true;
 | |
|   };
 | |
| 
 | |
|   // Send down the request to open the window.
 | |
|   nsCOMPtr<nsIPrincipal> triggeringPrincipal;
 | |
|   nsCOMPtr<nsIContentSecurityPolicy> csp;
 | |
|   nsCOMPtr<nsIReferrerInfo> referrerInfo;
 | |
|   rv = GetCreateWindowParams(aOpenWindowInfo, aLoadState, aForceNoReferrer,
 | |
|                              getter_AddRefs(referrerInfo),
 | |
|                              getter_AddRefs(triggeringPrincipal),
 | |
|                              getter_AddRefs(csp));
 | |
|   if (NS_WARN_IF(NS_FAILED(rv))) {
 | |
|     return rv;
 | |
|   }
 | |
| 
 | |
|   SendCreateWindow(aTabOpener, parent, newChild, aChromeFlags, aCalledFromJS,
 | |
|                    aOpenWindowInfo->GetIsForPrinting(),
 | |
|                    aOpenWindowInfo->GetIsForWindowDotPrint(), aURI, features,
 | |
|                    aModifiers, triggeringPrincipal, csp, referrerInfo,
 | |
|                    aOpenWindowInfo->GetOriginAttributes(), std::move(resolve),
 | |
|                    std::move(reject));
 | |
| 
 | |
|   // =======================
 | |
|   // Begin Nested Event Loop
 | |
|   // =======================
 | |
| 
 | |
|   // We have to wait for a response from SendCreateWindow or with information
 | |
|   // we're going to need to return from this function, So we spin a nested event
 | |
|   // loop until they get back to us.
 | |
| 
 | |
|   {
 | |
|     // Suppress event handling for all contexts in our BrowsingContextGroup so
 | |
|     // that event handlers cannot target our new window while it's still being
 | |
|     // opened. Note that pending events that were suppressed while our blocker
 | |
|     // was active will be dispatched asynchronously from a runnable dispatched
 | |
|     // to the main event loop after this function returns, not immediately when
 | |
|     // we leave this scope.
 | |
|     AutoSuppressEventHandlingAndSuspend seh(browsingContext->Group());
 | |
| 
 | |
|     AutoNoJSAPI nojsapi;
 | |
| 
 | |
|     // Spin the event loop until we get a response. Callers of this function
 | |
|     // already have to guard against an inner event loop spinning in the
 | |
|     // non-e10s case because of the need to spin one to create a new chrome
 | |
|     // window.
 | |
|     SpinEventLoopUntil("ContentChild::ProvideWindowCommon"_ns,
 | |
|                        [&]() { return ready; });
 | |
|     MOZ_RELEASE_ASSERT(ready,
 | |
|                        "We are on the main thread, so we should not exit this "
 | |
|                        "loop without ready being true.");
 | |
|   }
 | |
| 
 | |
|   // =====================
 | |
|   // End Nested Event Loop
 | |
|   // =====================
 | |
| 
 | |
|   // It's possible for our new BrowsingContext to become discarded during the
 | |
|   // nested event loop, in which case we shouldn't return it, since our callers
 | |
|   // will generally not be prepared to deal with that.
 | |
|   if (*aReturn && (*aReturn)->IsDiscarded()) {
 | |
|     NS_RELEASE(*aReturn);
 | |
|     return NS_ERROR_ABORT;
 | |
|   }
 | |
| 
 | |
|   // We should have the results already set by the callbacks.
 | |
|   MOZ_ASSERT_IF(NS_SUCCEEDED(rv), *aReturn);
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| bool ContentChild::IsAlive() const { return mIsAlive; }
 | |
| 
 | |
| bool ContentChild::IsShuttingDown() const { return mShuttingDown; }
 | |
| 
 | |
| void ContentChild::GetProcessName(nsACString& aName) const {
 | |
|   aName = mProcessName;
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void ContentChild::AppendProcessId(nsACString& aName) {
 | |
|   if (!aName.IsEmpty()) {
 | |
|     aName.Append(' ');
 | |
|   }
 | |
|   unsigned pid = getpid();
 | |
|   aName.Append(nsPrintfCString("(pid %u)", pid));
 | |
| }
 | |
| 
 | |
| void ContentChild::InitGraphicsDeviceData(const ContentDeviceData& aData) {
 | |
|   gfxPlatform::InitChild(aData);
 | |
| }
 | |
| 
 | |
| void ContentChild::InitSharedUASheets(Maybe<SharedMemoryHandle>&& aHandle,
 | |
|                                       uintptr_t aAddress) {
 | |
|   MOZ_ASSERT_IF(!aHandle, !aAddress);
 | |
| 
 | |
|   if (!aAddress) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // Map the shared memory storing the user agent style sheets.  Do this as
 | |
|   // early as possible to maximize the chance of being able to map at the
 | |
|   // address we want.
 | |
|   GlobalStyleSheetCache::SetSharedMemory(std::move(*aHandle), aAddress);
 | |
| }
 | |
| 
 | |
| void ContentChild::InitXPCOM(
 | |
|     XPCOMInitData&& aXPCOMInit,
 | |
|     const mozilla::dom::ipc::StructuredCloneData& aInitialData,
 | |
|     bool aIsReadyForBackgroundProcessing) {
 | |
| #ifdef MOZ_WIDGET_GTK
 | |
|   // LookAndFeel::NativeInit takes a long time to run on Linux, here we schedule
 | |
|   // it as soon as possible after BackgroundChild::Startup to give
 | |
|   // it chance to run ahead of ConstructBrowser
 | |
|   nsCOMPtr<nsIRunnable> event = new nsGtkNativeInitRunnable();
 | |
|   NS_DispatchToMainThreadQueue(event.forget(), EventQueuePriority::Idle);
 | |
| #endif
 | |
| 
 | |
| #if defined(XP_WIN)
 | |
|   // DLL services untrusted modules processing depends on
 | |
|   // BackgroundChild::Startup having been called
 | |
|   RefPtr<DllServices> dllSvc(DllServices::Get());
 | |
|   dllSvc->StartUntrustedModulesProcessor(aIsReadyForBackgroundProcessing);
 | |
| #endif  // defined(XP_WIN)
 | |
| 
 | |
|   PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
 | |
|   if (NS_WARN_IF(!actorChild)) {
 | |
|     MOZ_ASSERT_UNREACHABLE("PBackground init can't fail at this point");
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   ClientManager::Startup();
 | |
| 
 | |
|   // RemoteWorkerService will be initialized in RecvRemoteType, to avoid to
 | |
|   // register it to the RemoteWorkerManager while it is still a prealloc
 | |
|   // remoteType and defer it to the point the child process is assigned a.
 | |
|   // actual remoteType.
 | |
| 
 | |
|   nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
 | |
|   if (!svc) {
 | |
|     NS_WARNING("Couldn't acquire console service");
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   mConsoleListener = new ConsoleListener(this);
 | |
|   if (NS_FAILED(svc->RegisterListener(mConsoleListener)))
 | |
|     NS_WARNING("Couldn't register console listener for child process");
 | |
| 
 | |
|   mAvailableDictionaries = std::move(aXPCOMInit.dictionaries());
 | |
| 
 | |
|   RecvSetOffline(aXPCOMInit.isOffline());
 | |
|   RecvSetConnectivity(aXPCOMInit.isConnected());
 | |
| 
 | |
|   LocaleService::GetInstance()->AssignAppLocales(aXPCOMInit.appLocales());
 | |
|   LocaleService::GetInstance()->AssignRequestedLocales(
 | |
|       aXPCOMInit.requestedLocales());
 | |
| 
 | |
|   L10nRegistry::RegisterFileSourcesFromParentProcess(
 | |
|       aXPCOMInit.l10nFileSources());
 | |
| 
 | |
|   RecvSetCaptivePortalState(aXPCOMInit.captivePortalState());
 | |
|   RecvBidiKeyboardNotify(aXPCOMInit.isLangRTL(),
 | |
|                          aXPCOMInit.haveBidiKeyboards());
 | |
| 
 | |
|   if (aXPCOMInit.domainPolicy().active()) {
 | |
|     nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
 | |
|     MOZ_ASSERT(ssm);
 | |
|     ssm->ActivateDomainPolicyInternal(getter_AddRefs(mPolicy));
 | |
|     if (!mPolicy) {
 | |
|       MOZ_CRASH("Failed to activate domain policy.");
 | |
|     }
 | |
|     mPolicy->ApplyClone(&aXPCOMInit.domainPolicy());
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIClipboard> clipboard(
 | |
|       do_GetService("@mozilla.org/widget/clipboard;1"));
 | |
|   if (nsCOMPtr<nsIClipboardProxy> clipboardProxy =
 | |
|           do_QueryInterface(clipboard)) {
 | |
|     clipboardProxy->SetCapabilities(aXPCOMInit.clipboardCaps());
 | |
|   }
 | |
| 
 | |
|   {
 | |
|     AutoJSAPI jsapi;
 | |
|     if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) {
 | |
|       MOZ_CRASH();
 | |
|     }
 | |
|     ErrorResult rv;
 | |
|     JS::Rooted<JS::Value> data(jsapi.cx());
 | |
|     mozilla::dom::ipc::StructuredCloneData id;
 | |
|     id.Copy(aInitialData);
 | |
|     id.Read(jsapi.cx(), &data, rv);
 | |
|     if (NS_WARN_IF(rv.Failed())) {
 | |
|       MOZ_CRASH();
 | |
|     }
 | |
|     auto* global = ContentProcessMessageManager::Get();
 | |
|     global->SetInitialProcessData(data);
 | |
|   }
 | |
| 
 | |
|   // The stylesheet cache is not ready yet. Store this URL for future use.
 | |
|   nsCOMPtr<nsIURI> ucsURL = std::move(aXPCOMInit.userContentSheetURL());
 | |
|   GlobalStyleSheetCache::SetUserContentCSSURL(ucsURL);
 | |
| 
 | |
|   GfxInfoBase::SetFeatureStatus(std::move(aXPCOMInit.gfxFeatureStatus()));
 | |
| 
 | |
|   // Initialize the RemoteDecoderManager thread and its associated PBackground
 | |
|   // channel.
 | |
|   RemoteDecoderManagerChild::Init();
 | |
| 
 | |
|   Preferences::RegisterCallbackAndCall(&OnFissionBlocklistPrefChange,
 | |
|                                        kFissionEnforceBlockList);
 | |
|   Preferences::RegisterCallbackAndCall(&OnFissionBlocklistPrefChange,
 | |
|                                        kFissionOmitBlockListValues);
 | |
| 
 | |
|   // Set the dynamic scalar definitions for this process.
 | |
|   TelemetryIPC::AddDynamicScalarDefinitions(aXPCOMInit.dynamicScalarDefs());
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvRequestMemoryReport(
 | |
|     const uint32_t& aGeneration, const bool& aAnonymize,
 | |
|     const bool& aMinimizeMemoryUsage,
 | |
|     const Maybe<mozilla::ipc::FileDescriptor>& aDMDFile,
 | |
|     const RequestMemoryReportResolver& aResolver) {
 | |
|   nsCString process;
 | |
|   if (aAnonymize || mRemoteType.IsEmpty()) {
 | |
|     GetProcessName(process);
 | |
|   } else {
 | |
|     process = mRemoteType;
 | |
|   }
 | |
|   AppendProcessId(process);
 | |
|   MOZ_ASSERT(!process.IsEmpty());
 | |
| 
 | |
|   MemoryReportRequestClient::Start(
 | |
|       aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile, process,
 | |
|       [&](const MemoryReport& aReport) {
 | |
|         Unused << GetSingleton()->SendAddMemoryReport(aReport);
 | |
|       },
 | |
|       aResolver);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| #if defined(XP_WIN)
 | |
| mozilla::ipc::IPCResult ContentChild::RecvGetUntrustedModulesData(
 | |
|     GetUntrustedModulesDataResolver&& aResolver) {
 | |
|   RefPtr<DllServices> dllSvc(DllServices::Get());
 | |
|   dllSvc->GetUntrustedModulesData()->Then(
 | |
|       GetMainThreadSerialEventTarget(), __func__,
 | |
|       [aResolver](Maybe<UntrustedModulesData>&& aData) {
 | |
|         aResolver(std::move(aData));
 | |
|       },
 | |
|       [aResolver](nsresult aReason) { aResolver(Nothing()); });
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvUnblockUntrustedModulesThread() {
 | |
|   if (nsCOMPtr<nsIObserverService> obs =
 | |
|           mozilla::services::GetObserverService()) {
 | |
|     obs->NotifyObservers(nullptr, "unblock-untrusted-modules-thread", nullptr);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| #endif  // defined(XP_WIN)
 | |
| 
 | |
| PCycleCollectWithLogsChild* ContentChild::AllocPCycleCollectWithLogsChild(
 | |
|     const bool& aDumpAllTraces, const FileDescriptor& aGCLog,
 | |
|     const FileDescriptor& aCCLog) {
 | |
|   return do_AddRef(new CycleCollectWithLogsChild()).take();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvPCycleCollectWithLogsConstructor(
 | |
|     PCycleCollectWithLogsChild* aActor, const bool& aDumpAllTraces,
 | |
|     const FileDescriptor& aGCLog, const FileDescriptor& aCCLog) {
 | |
|   // The sink's destructor is called when the last reference goes away, which
 | |
|   // will cause the actor to be closed down.
 | |
|   auto* actor = static_cast<CycleCollectWithLogsChild*>(aActor);
 | |
|   RefPtr<CycleCollectWithLogsChild::Sink> sink =
 | |
|       new CycleCollectWithLogsChild::Sink(actor, aGCLog, aCCLog);
 | |
| 
 | |
|   // Invoke the dumper, which will take a reference to the sink.
 | |
|   nsCOMPtr<nsIMemoryInfoDumper> dumper =
 | |
|       do_GetService("@mozilla.org/memory-info-dumper;1");
 | |
|   dumper->DumpGCAndCCLogsToSink(aDumpAllTraces, sink);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| bool ContentChild::DeallocPCycleCollectWithLogsChild(
 | |
|     PCycleCollectWithLogsChild* aActor) {
 | |
|   RefPtr<CycleCollectWithLogsChild> actor =
 | |
|       dont_AddRef(static_cast<CycleCollectWithLogsChild*>(aActor));
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvInitGMPService(
 | |
|     Endpoint<PGMPServiceChild>&& aGMPService) {
 | |
|   if (!GMPServiceChild::Create(std::move(aGMPService))) {
 | |
|     return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvInitProfiler(
 | |
|     Endpoint<PProfilerChild>&& aEndpoint) {
 | |
|   mProfilerController = ChildProfilerController::Create(std::move(aEndpoint));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvGMPsChanged(
 | |
|     nsTArray<GMPCapabilityData>&& capabilities) {
 | |
|   GeckoMediaPluginServiceChild::UpdateGMPCapabilities(std::move(capabilities));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvInitProcessHangMonitor(
 | |
|     Endpoint<PProcessHangMonitorChild>&& aHangMonitor) {
 | |
|   CreateHangMonitorChild(std::move(aHangMonitor));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::GetResultForRenderingInitFailure(
 | |
|     base::ProcessId aOtherPid) {
 | |
|   if (aOtherPid == base::GetCurrentProcId() || aOtherPid == OtherPid()) {
 | |
|     // If we are talking to ourselves, or the UI process, then that is a fatal
 | |
|     // protocol error.
 | |
|     return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   // If we are talking to the GPU process, then we should recover from this on
 | |
|   // the next ContentChild::RecvReinitRendering call.
 | |
|   gfxCriticalNote << "Could not initialize rendering with GPU process";
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| #if defined(XP_MACOSX)
 | |
| extern "C" {
 | |
| void CGSShutdownServerConnections();
 | |
| };
 | |
| #endif
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvInitRendering(
 | |
|     Endpoint<PCompositorManagerChild>&& aCompositor,
 | |
|     Endpoint<PImageBridgeChild>&& aImageBridge,
 | |
|     Endpoint<PVRManagerChild>&& aVRBridge,
 | |
|     Endpoint<PRemoteDecoderManagerChild>&& aVideoManager,
 | |
|     nsTArray<uint32_t>&& namespaces) {
 | |
|   MOZ_ASSERT(namespaces.Length() == 3);
 | |
| 
 | |
|   // Note that for all of the methods below, if it can fail, it should only
 | |
|   // return false if the failure is an IPDL error. In such situations,
 | |
|   // ContentChild can reason about whether or not to wait for
 | |
|   // RecvReinitRendering (because we surmised the GPU process crashed), or if it
 | |
|   // should crash itself (because we are actually talking to the UI process). If
 | |
|   // there are localized failures (e.g. failed to spawn a thread), then it
 | |
|   // should MOZ_RELEASE_ASSERT or MOZ_CRASH as necessary instead.
 | |
|   if (!CompositorManagerChild::Init(std::move(aCompositor), namespaces[0])) {
 | |
|     return GetResultForRenderingInitFailure(aCompositor.OtherPid());
 | |
|   }
 | |
|   if (!CompositorManagerChild::CreateContentCompositorBridge(namespaces[1])) {
 | |
|     return GetResultForRenderingInitFailure(aCompositor.OtherPid());
 | |
|   }
 | |
|   if (!ImageBridgeChild::InitForContent(std::move(aImageBridge),
 | |
|                                         namespaces[2])) {
 | |
|     return GetResultForRenderingInitFailure(aImageBridge.OtherPid());
 | |
|   }
 | |
|   if (!gfx::VRManagerChild::InitForContent(std::move(aVRBridge))) {
 | |
|     return GetResultForRenderingInitFailure(aVRBridge.OtherPid());
 | |
|   }
 | |
|   RemoteDecoderManagerChild::InitForGPUProcess(std::move(aVideoManager));
 | |
| 
 | |
| #if defined(XP_MACOSX) && !defined(MOZ_SANDBOX)
 | |
|   // Close all current connections to the WindowServer. This ensures that the
 | |
|   // Activity Monitor will not label the content process as "Not responding"
 | |
|   // because it's not running a native event loop. See bug 1384336. When the
 | |
|   // build is configured with sandbox support, this is called during sandbox
 | |
|   // setup.
 | |
|   CGSShutdownServerConnections();
 | |
| #endif
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvReinitRendering(
 | |
|     Endpoint<PCompositorManagerChild>&& aCompositor,
 | |
|     Endpoint<PImageBridgeChild>&& aImageBridge,
 | |
|     Endpoint<PVRManagerChild>&& aVRBridge,
 | |
|     Endpoint<PRemoteDecoderManagerChild>&& aVideoManager,
 | |
|     nsTArray<uint32_t>&& namespaces) {
 | |
|   MOZ_ASSERT(namespaces.Length() == 3);
 | |
|   nsTArray<RefPtr<BrowserChild>> tabs = BrowserChild::GetAll();
 | |
| 
 | |
|   // Re-establish singleton bridges to the compositor.
 | |
|   if (!CompositorManagerChild::Init(std::move(aCompositor), namespaces[0])) {
 | |
|     return GetResultForRenderingInitFailure(aCompositor.OtherPid());
 | |
|   }
 | |
|   if (!CompositorManagerChild::CreateContentCompositorBridge(namespaces[1])) {
 | |
|     return GetResultForRenderingInitFailure(aCompositor.OtherPid());
 | |
|   }
 | |
|   if (!ImageBridgeChild::ReinitForContent(std::move(aImageBridge),
 | |
|                                           namespaces[2])) {
 | |
|     return GetResultForRenderingInitFailure(aImageBridge.OtherPid());
 | |
|   }
 | |
|   if (!gfx::VRManagerChild::InitForContent(std::move(aVRBridge))) {
 | |
|     return GetResultForRenderingInitFailure(aVRBridge.OtherPid());
 | |
|   }
 | |
|   gfxPlatform::GetPlatform()->CompositorUpdated();
 | |
| 
 | |
|   // Establish new PLayerTransactions.
 | |
|   for (const auto& browserChild : tabs) {
 | |
|     if (browserChild->GetLayersId().IsValid()) {
 | |
|       browserChild->ReinitRendering();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Notify any observers that the compositor has been reinitialized,
 | |
|   // eg the ZoomConstraintsClients for documents in this process.
 | |
|   // This must occur after the ReinitRendering call above so that the
 | |
|   // APZCTreeManagers have been connected.
 | |
|   nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
 | |
|   if (observerService) {
 | |
|     observerService->NotifyObservers(nullptr, "compositor-reinitialized",
 | |
|                                      nullptr);
 | |
|   }
 | |
| 
 | |
|   RemoteDecoderManagerChild::InitForGPUProcess(std::move(aVideoManager));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvReinitRenderingForDeviceReset() {
 | |
|   gfxPlatform::GetPlatform()->CompositorUpdated();
 | |
| 
 | |
|   nsTArray<RefPtr<BrowserChild>> tabs = BrowserChild::GetAll();
 | |
|   for (const auto& browserChild : tabs) {
 | |
|     if (browserChild->GetLayersId().IsValid()) {
 | |
|       browserChild->ReinitRenderingForDeviceReset();
 | |
|     }
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
 | |
| extern "C" {
 | |
| CGError CGSSetDenyWindowServerConnections(bool);
 | |
| };
 | |
| 
 | |
| static void DisconnectWindowServer(bool aIsSandboxEnabled) {
 | |
|   // Close all current connections to the WindowServer. This ensures that the
 | |
|   // Activity Monitor will not label the content process as "Not responding"
 | |
|   // because it's not running a native event loop. See bug 1384336.
 | |
|   // This is required with or without the sandbox enabled. Until the
 | |
|   // window server is blocked as the policy level, this should be called
 | |
|   // just before CGSSetDenyWindowServerConnections() so there are no
 | |
|   // windowserver connections active when CGSSetDenyWindowServerConnections()
 | |
|   // is called.
 | |
|   CGSShutdownServerConnections();
 | |
| 
 | |
|   // Actual security benefits are only achieved when we additionally deny
 | |
|   // future connections using the sandbox policy. WebGL must be remoted if
 | |
|   // the windowserver connections are blocked. WebGL remoting is disabled
 | |
|   // for some tests.
 | |
|   if (aIsSandboxEnabled &&
 | |
|       Preferences::GetBool(
 | |
|           "security.sandbox.content.mac.disconnect-windowserver") &&
 | |
|       Preferences::GetBool("webgl.out-of-process")) {
 | |
|     CGError result = CGSSetDenyWindowServerConnections(true);
 | |
|     MOZ_DIAGNOSTIC_ASSERT(result == kCGErrorSuccess);
 | |
| #  if !MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | |
|     Unused << result;
 | |
| #  endif
 | |
|   }
 | |
| }
 | |
| #endif
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvSetProcessSandbox(
 | |
|     const Maybe<mozilla::ipc::FileDescriptor>& aBroker) {
 | |
|   // We may want to move the sandbox initialization somewhere else
 | |
|   // at some point; see bug 880808.
 | |
| #if defined(MOZ_SANDBOX)
 | |
| 
 | |
|   bool sandboxEnabled = true;
 | |
| #  if defined(XP_LINUX)
 | |
|   // On Linux, we have to support systems that can't use any sandboxing.
 | |
|   sandboxEnabled = SandboxInfo::Get().CanSandboxContent();
 | |
| 
 | |
|   if (sandboxEnabled && !StaticPrefs::media_cubeb_sandbox()) {
 | |
|     // Pre-start audio before sandboxing; see bug 1443612.
 | |
|     Unused << CubebUtils::GetCubeb();
 | |
|   }
 | |
| 
 | |
|   if (sandboxEnabled) {
 | |
|     sandboxEnabled = SetContentProcessSandbox(
 | |
|         ContentProcessSandboxParams::ForThisProcess(aBroker));
 | |
|   }
 | |
| #  elif defined(XP_WIN)
 | |
|   mozilla::SandboxTarget::Instance()->StartSandbox();
 | |
| #  elif defined(XP_MACOSX)
 | |
|   sandboxEnabled = (GetEffectiveContentSandboxLevel() >= 1);
 | |
|   DisconnectWindowServer(sandboxEnabled);
 | |
| #  endif
 | |
| 
 | |
|   CrashReporter::RecordAnnotationBool(
 | |
|       CrashReporter::Annotation::ContentSandboxEnabled, sandboxEnabled);
 | |
| #  if defined(XP_LINUX) && !defined(ANDROID)
 | |
|   CrashReporter::RecordAnnotationU32(
 | |
|       CrashReporter::Annotation::ContentSandboxCapabilities,
 | |
|       SandboxInfo::Get().AsInteger());
 | |
| #  endif /* XP_LINUX && !ANDROID */
 | |
| #endif   /* MOZ_SANDBOX */
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvBidiKeyboardNotify(
 | |
|     const bool& aIsLangRTL, const bool& aHaveBidiKeyboards) {
 | |
|   // bidi is always of type PuppetBidiKeyboard* (because in the child, the only
 | |
|   // possible implementation of nsIBidiKeyboard is PuppetBidiKeyboard).
 | |
|   PuppetBidiKeyboard* bidi =
 | |
|       static_cast<PuppetBidiKeyboard*>(nsContentUtils::GetBidiKeyboard());
 | |
|   if (bidi) {
 | |
|     bidi->SetBidiKeyboardInfo(aIsLangRTL, aHaveBidiKeyboards);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| static StaticRefPtr<CancelableRunnable> gFirstIdleTask;
 | |
| 
 | |
| static void FirstIdle(void) {
 | |
|   MOZ_ASSERT(gFirstIdleTask);
 | |
|   gFirstIdleTask = nullptr;
 | |
| 
 | |
|   ContentChild::GetSingleton()->SendFirstIdle();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvConstructBrowser(
 | |
|     ManagedEndpoint<PBrowserChild>&& aBrowserEp,
 | |
|     ManagedEndpoint<PWindowGlobalChild>&& aWindowEp, const TabId& aTabId,
 | |
|     const IPCTabContext& aContext, const WindowGlobalInit& aWindowInit,
 | |
|     const uint32_t& aChromeFlags, const ContentParentId& aCpID,
 | |
|     const bool& aIsForBrowser, const bool& aIsTopLevel) {
 | |
|   MOZ_DIAGNOSTIC_ASSERT(!IsShuttingDown());
 | |
| 
 | |
|   static bool hasRunOnce = false;
 | |
|   if (!hasRunOnce) {
 | |
|     hasRunOnce = true;
 | |
|     MOZ_ASSERT(!gFirstIdleTask);
 | |
|     RefPtr<CancelableRunnable> firstIdleTask =
 | |
|         NewCancelableRunnableFunction("FirstIdleRunnable", FirstIdle);
 | |
|     gFirstIdleTask = firstIdleTask;
 | |
|     if (NS_FAILED(NS_DispatchToCurrentThreadQueue(firstIdleTask.forget(),
 | |
|                                                   EventQueuePriority::Idle))) {
 | |
|       gFirstIdleTask = nullptr;
 | |
|       hasRunOnce = false;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   RefPtr<BrowsingContext> browsingContext =
 | |
|       BrowsingContext::Get(aWindowInit.context().mBrowsingContextId);
 | |
|   if (!browsingContext || browsingContext->IsDiscarded()) {
 | |
|     nsPrintfCString reason("%s initial %s BrowsingContext",
 | |
|                            browsingContext ? "discarded" : "missing",
 | |
|                            aIsTopLevel ? "top" : "frame");
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning, ("%s", reason.get()));
 | |
|     if (!aIsTopLevel) {
 | |
|       // Recover if the BrowsingContext is missing for a new subframe. The
 | |
|       // `ManagedEndpoint` instances will be automatically destroyed.
 | |
|       NS_WARNING(reason.get());
 | |
|       return IPC_OK();
 | |
|     }
 | |
| 
 | |
|     // (these are the only possible values of `reason` at this point)
 | |
|     return browsingContext
 | |
|                ? IPC_FAIL(this, "discarded initial top BrowsingContext")
 | |
|                : IPC_FAIL(this, "missing initial top BrowsingContext");
 | |
|   }
 | |
| 
 | |
|   if (xpc::IsInAutomation() &&
 | |
|       StaticPrefs::
 | |
|           browser_tabs_remote_testOnly_failPBrowserCreation_enabled()) {
 | |
|     nsAutoCString idString;
 | |
|     if (NS_SUCCEEDED(Preferences::GetCString(
 | |
|             "browser.tabs.remote.testOnly.failPBrowserCreation.browsingContext",
 | |
|             idString))) {
 | |
|       nsresult rv = NS_OK;
 | |
|       uint64_t bcid = idString.ToInteger64(&rv);
 | |
|       if (NS_SUCCEEDED(rv) && bcid == browsingContext->Id()) {
 | |
|         NS_WARNING("Injecting artificial PBrowser creation failure");
 | |
|         return IPC_OK();
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!aWindowInit.isInitialDocument() ||
 | |
|       !NS_IsAboutBlank(aWindowInit.documentURI())) {
 | |
|     return IPC_FAIL(this,
 | |
|                     "Logic in CreateDocumentViewerForActor currently requires "
 | |
|                     "actors to be initial about:blank documents");
 | |
|   }
 | |
| 
 | |
|   // We'll happily accept any kind of IPCTabContext here; we don't need to
 | |
|   // check that it's of a certain type for security purposes, because we
 | |
|   // believe whatever the parent process tells us.
 | |
|   MaybeInvalidTabContext tc(aContext);
 | |
|   if (!tc.IsValid()) {
 | |
|     NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
 | |
|                              "the parent process. (%s)  Crashing...",
 | |
|                              tc.GetInvalidReason())
 | |
|                  .get());
 | |
|     MOZ_CRASH("Invalid TabContext received from the parent process.");
 | |
|   }
 | |
| 
 | |
|   RefPtr<WindowGlobalChild> windowChild =
 | |
|       WindowGlobalChild::CreateDisconnected(aWindowInit);
 | |
|   if (!windowChild) {
 | |
|     return IPC_FAIL(this, "Failed to create initial WindowGlobalChild");
 | |
|   }
 | |
| 
 | |
|   RefPtr<BrowserChild> browserChild =
 | |
|       BrowserChild::Create(this, aTabId, tc.GetTabContext(), browsingContext,
 | |
|                            aChromeFlags, aIsTopLevel);
 | |
| 
 | |
|   // Bind the created BrowserChild to IPC to actually link the actor.
 | |
|   if (NS_WARN_IF(!BindPBrowserEndpoint(std::move(aBrowserEp), browserChild))) {
 | |
|     return IPC_FAIL(this, "BindPBrowserEndpoint failed");
 | |
|   }
 | |
| 
 | |
|   if (NS_WARN_IF(!browserChild->BindPWindowGlobalEndpoint(std::move(aWindowEp),
 | |
|                                                           windowChild))) {
 | |
|     return IPC_FAIL(this, "BindPWindowGlobalEndpoint failed");
 | |
|   }
 | |
|   windowChild->Init();
 | |
|   auto guardNullWindowGlobal = MakeScopeExit([&] {
 | |
|     if (!windowChild->GetWindowGlobal()) {
 | |
|       windowChild->Destroy();
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   // Ensure that a BrowsingContext is set for our BrowserChild before
 | |
|   // running `Init`.
 | |
|   MOZ_RELEASE_ASSERT(browserChild->mBrowsingContext->Id() ==
 | |
|                      aWindowInit.context().mBrowsingContextId);
 | |
| 
 | |
|   if (NS_WARN_IF(
 | |
|           NS_FAILED(browserChild->Init(/* aOpener */ nullptr, windowChild)))) {
 | |
|     return IPC_FAIL(browserChild, "BrowserChild::Init failed");
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
 | |
|   if (os) {
 | |
|     os->NotifyObservers(static_cast<nsIBrowserChild*>(browserChild),
 | |
|                         "tab-child-created", nullptr);
 | |
|   }
 | |
|   // Notify parent that we are ready to handle input events.
 | |
|   browserChild->SendRemoteIsReadyToHandleInputEvents();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| void ContentChild::GetAvailableDictionaries(
 | |
|     nsTArray<nsCString>& aDictionaries) {
 | |
|   aDictionaries = mAvailableDictionaries.Clone();
 | |
| }
 | |
| 
 | |
| mozilla::PRemoteSpellcheckEngineChild*
 | |
| ContentChild::AllocPRemoteSpellcheckEngineChild() {
 | |
|   MOZ_CRASH(
 | |
|       "Default Constructor for PRemoteSpellcheckEngineChild should never be "
 | |
|       "called");
 | |
|   return nullptr;
 | |
| }
 | |
| 
 | |
| bool ContentChild::DeallocPRemoteSpellcheckEngineChild(
 | |
|     PRemoteSpellcheckEngineChild* child) {
 | |
|   delete child;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvNotifyEmptyHTTPCache() {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
|   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
 | |
|   obs->NotifyObservers(nullptr, "cacheservice:empty-cache", nullptr);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| PHalChild* ContentChild::AllocPHalChild() { return CreateHalChild(); }
 | |
| 
 | |
| bool ContentChild::DeallocPHalChild(PHalChild* aHal) {
 | |
|   delete aHal;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| devtools::PHeapSnapshotTempFileHelperChild*
 | |
| ContentChild::AllocPHeapSnapshotTempFileHelperChild() {
 | |
|   return devtools::HeapSnapshotTempFileHelperChild::Create();
 | |
| }
 | |
| 
 | |
| bool ContentChild::DeallocPHeapSnapshotTempFileHelperChild(
 | |
|     devtools::PHeapSnapshotTempFileHelperChild* aHeapSnapshotHelper) {
 | |
|   delete aHeapSnapshotHelper;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| already_AddRefed<PTestShellChild> ContentChild::AllocPTestShellChild() {
 | |
|   return MakeAndAddRef<TestShellChild>();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvPTestShellConstructor(
 | |
|     PTestShellChild* actor) {
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| RefPtr<GenericPromise> ContentChild::UpdateCookieStatus(nsIChannel* aChannel) {
 | |
|   RefPtr<CookieServiceChild> csChild = CookieServiceChild::GetSingleton();
 | |
|   NS_ASSERTION(csChild, "Couldn't get CookieServiceChild");
 | |
| 
 | |
|   return csChild->TrackCookieLoad(aChannel);
 | |
| }
 | |
| 
 | |
| PScriptCacheChild* ContentChild::AllocPScriptCacheChild(
 | |
|     const FileDescOrError& cacheFile, const bool& wantCacheData) {
 | |
|   return new loader::ScriptCacheChild();
 | |
| }
 | |
| 
 | |
| bool ContentChild::DeallocPScriptCacheChild(PScriptCacheChild* cache) {
 | |
|   delete static_cast<loader::ScriptCacheChild*>(cache);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvPScriptCacheConstructor(
 | |
|     PScriptCacheChild* actor, const FileDescOrError& cacheFile,
 | |
|     const bool& wantCacheData) {
 | |
|   Maybe<FileDescriptor> fd;
 | |
|   if (cacheFile.type() == cacheFile.TFileDescriptor) {
 | |
|     fd.emplace(cacheFile.get_FileDescriptor());
 | |
|   }
 | |
| 
 | |
|   static_cast<loader::ScriptCacheChild*>(actor)->Init(fd, wantCacheData);
 | |
| 
 | |
|   // Some scripts listen for "app-startup" to start. However, in the content
 | |
|   // process, this category runs before the ScriptPreloader is initialized so
 | |
|   // these scripts wouldn't be added to the cache. Instead, if a script needs to
 | |
|   // run on start up in the content process, it should listen for this category.
 | |
|   NS_CreateServicesFromCategory("content-process-ready-for-script", nullptr,
 | |
|                                 "content-process-ready-for-script", nullptr);
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvNetworkLinkTypeChange(
 | |
|     const uint32_t& aType) {
 | |
|   mNetworkLinkType = aType;
 | |
|   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
 | |
|   if (obs) {
 | |
|     obs->NotifyObservers(nullptr, "contentchild:network-link-type-changed",
 | |
|                          nullptr);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvSocketProcessCrashed() {
 | |
|   nsIOService::IncreaseSocketProcessCrashCount();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| PRemotePrintJobChild* ContentChild::AllocPRemotePrintJobChild() {
 | |
| #ifdef NS_PRINTING
 | |
|   return new RemotePrintJobChild();
 | |
| #else
 | |
|   return nullptr;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| media::PMediaChild* ContentChild::AllocPMediaChild() {
 | |
|   return media::AllocPMediaChild();
 | |
| }
 | |
| 
 | |
| bool ContentChild::DeallocPMediaChild(media::PMediaChild* aActor) {
 | |
|   return media::DeallocPMediaChild(aActor);
 | |
| }
 | |
| 
 | |
| PBenchmarkStorageChild* ContentChild::AllocPBenchmarkStorageChild() {
 | |
|   return BenchmarkStorageChild::Instance();
 | |
| }
 | |
| 
 | |
| bool ContentChild::DeallocPBenchmarkStorageChild(
 | |
|     PBenchmarkStorageChild* aActor) {
 | |
|   delete aActor;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| #ifdef MOZ_WEBRTC
 | |
| PWebrtcGlobalChild* ContentChild::AllocPWebrtcGlobalChild() {
 | |
|   auto* child = new WebrtcGlobalChild();
 | |
|   return child;
 | |
| }
 | |
| 
 | |
| bool ContentChild::DeallocPWebrtcGlobalChild(PWebrtcGlobalChild* aActor) {
 | |
|   delete static_cast<WebrtcGlobalChild*>(aActor);
 | |
|   return true;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvRegisterChrome(
 | |
|     nsTArray<ChromePackage>&& packages,
 | |
|     nsTArray<SubstitutionMapping>&& resources,
 | |
|     nsTArray<OverrideMapping>&& overrides, const nsCString& locale,
 | |
|     const bool& reset) {
 | |
|   nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
 | |
|   nsChromeRegistryContent* chromeRegistry =
 | |
|       static_cast<nsChromeRegistryContent*>(registrySvc.get());
 | |
|   if (!chromeRegistry) {
 | |
|     return IPC_FAIL(this, "ChromeRegistryContent is null!");
 | |
|   }
 | |
|   chromeRegistry->RegisterRemoteChrome(packages, resources, overrides, locale,
 | |
|                                        reset);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvRegisterChromeItem(
 | |
|     const ChromeRegistryItem& item) {
 | |
|   nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
 | |
|   nsChromeRegistryContent* chromeRegistry =
 | |
|       static_cast<nsChromeRegistryContent*>(registrySvc.get());
 | |
|   if (!chromeRegistry) {
 | |
|     return IPC_FAIL(this, "ChromeRegistryContent is null!");
 | |
|   }
 | |
|   switch (item.type()) {
 | |
|     case ChromeRegistryItem::TChromePackage:
 | |
|       chromeRegistry->RegisterPackage(item.get_ChromePackage());
 | |
|       break;
 | |
| 
 | |
|     case ChromeRegistryItem::TOverrideMapping:
 | |
|       chromeRegistry->RegisterOverride(item.get_OverrideMapping());
 | |
|       break;
 | |
| 
 | |
|     case ChromeRegistryItem::TSubstitutionMapping:
 | |
|       chromeRegistry->RegisterSubstitution(item.get_SubstitutionMapping());
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       MOZ_ASSERT(false, "bad chrome item");
 | |
|       return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| mozilla::ipc::IPCResult ContentChild::RecvClearStyleSheetCache(
 | |
|     const Maybe<RefPtr<nsIPrincipal>>& aForPrincipal,
 | |
|     const Maybe<nsCString>& aBaseDomain) {
 | |
|   nsIPrincipal* principal =
 | |
|       aForPrincipal ? aForPrincipal.value().get() : nullptr;
 | |
|   const nsCString* baseDomain = aBaseDomain ? aBaseDomain.ptr() : nullptr;
 | |
|   SharedStyleSheetCache::Clear(principal, baseDomain);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvClearImageCacheFromPrincipal(
 | |
|     nsIPrincipal* aPrincipal) {
 | |
|   imgLoader* loader;
 | |
|   if (aPrincipal->OriginAttributesRef().mPrivateBrowsingId ==
 | |
|       nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID) {
 | |
|     loader = imgLoader::NormalLoader();
 | |
|   } else {
 | |
|     loader = imgLoader::PrivateBrowsingLoader();
 | |
|   }
 | |
| 
 | |
|   loader->RemoveEntriesInternal(aPrincipal, nullptr);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvClearImageCacheFromBaseDomain(
 | |
|     const nsCString& aBaseDomain) {
 | |
|   imgLoader::NormalLoader()->RemoveEntriesInternal(nullptr, &aBaseDomain);
 | |
|   imgLoader::PrivateBrowsingLoader()->RemoveEntriesInternal(nullptr,
 | |
|                                                             &aBaseDomain);
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvClearImageCache(
 | |
|     const bool& privateLoader, const bool& chrome) {
 | |
|   imgLoader* loader = privateLoader ? imgLoader::PrivateBrowsingLoader()
 | |
|                                     : imgLoader::NormalLoader();
 | |
| 
 | |
|   loader->ClearCache(chrome);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvSetOffline(const bool& offline) {
 | |
|   nsCOMPtr<nsIIOService> io(do_GetIOService());
 | |
|   NS_ASSERTION(io, "IO Service can not be null");
 | |
| 
 | |
|   io->SetOffline(offline);
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvSetConnectivity(
 | |
|     const bool& connectivity) {
 | |
|   nsCOMPtr<nsIIOService> io(do_GetIOService());
 | |
|   nsCOMPtr<nsIIOServiceInternal> ioInternal(do_QueryInterface(io));
 | |
|   NS_ASSERTION(ioInternal, "IO Service can not be null");
 | |
| 
 | |
|   ioInternal->SetConnectivity(connectivity);
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvSetCaptivePortalState(
 | |
|     const int32_t& aState) {
 | |
|   nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CID);
 | |
|   if (!cps) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   mozilla::net::CaptivePortalService* portal =
 | |
|       static_cast<mozilla::net::CaptivePortalService*>(cps.get());
 | |
|   portal->SetStateInChild(aState);
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvSetTRRMode(
 | |
|     const nsIDNSService::ResolverMode& mode,
 | |
|     const nsIDNSService::ResolverMode& modeFromPref) {
 | |
|   RefPtr<net::ChildDNSService> dnsServiceChild =
 | |
|       dont_AddRef(net::ChildDNSService::GetSingleton());
 | |
|   if (dnsServiceChild) {
 | |
|     dnsServiceChild->SetTRRModeInChild(mode, modeFromPref);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| void ContentChild::ActorDestroy(ActorDestroyReason why) {
 | |
|   if (mForceKillTimer) {
 | |
|     mForceKillTimer->Cancel();
 | |
|     mForceKillTimer = nullptr;
 | |
|   }
 | |
| 
 | |
|   if (AbnormalShutdown == why) {
 | |
|     NS_WARNING("shutting down early because of crash!");
 | |
|     ProcessChild::QuickExit();
 | |
|   }
 | |
| 
 | |
| #ifndef NS_FREE_PERMANENT_DATA
 | |
|   // In release builds, there's no point in the content process
 | |
|   // going through the full XPCOM shutdown path, because it doesn't
 | |
|   // keep persistent state.
 | |
|   ProcessChild::QuickExit();
 | |
| #else
 | |
|   // Destroy our JSProcessActors, and reject any pending queries.
 | |
|   JSActorDidDestroy();
 | |
| 
 | |
| #  if defined(XP_WIN)
 | |
|   RefPtr<DllServices> dllSvc(DllServices::Get());
 | |
|   dllSvc->DisableFull();
 | |
| #  endif  // defined(XP_WIN)
 | |
| 
 | |
|   if (gFirstIdleTask) {
 | |
|     gFirstIdleTask->Cancel();
 | |
|     gFirstIdleTask = nullptr;
 | |
|   }
 | |
| 
 | |
|   BlobURLProtocolHandler::RemoveDataEntries();
 | |
| 
 | |
|   mSharedData = nullptr;
 | |
| 
 | |
|   mAlertObservers.Clear();
 | |
| 
 | |
|   mIdleObservers.Clear();
 | |
| 
 | |
|   if (mConsoleListener) {
 | |
|     nsCOMPtr<nsIConsoleService> svc(
 | |
|         do_GetService(NS_CONSOLESERVICE_CONTRACTID));
 | |
|     if (svc) {
 | |
|       svc->UnregisterListener(mConsoleListener);
 | |
|       mConsoleListener->mChild = nullptr;
 | |
|     }
 | |
|   }
 | |
|   mIsAlive = false;
 | |
| 
 | |
|   CrashReporterClient::DestroySingleton();
 | |
| 
 | |
|   XRE_ShutdownChildProcess();
 | |
| #endif    // NS_FREE_PERMANENT_DATA
 | |
| }
 | |
| 
 | |
| void ContentChild::ProcessingError(Result aCode, const char* aReason) {
 | |
|   switch (aCode) {
 | |
|     case MsgDropped:
 | |
|       NS_WARNING("MsgDropped in ContentChild");
 | |
|       return;
 | |
| 
 | |
|     case MsgNotKnown:
 | |
|     case MsgNotAllowed:
 | |
|     case MsgPayloadError:
 | |
|     case MsgProcessingError:
 | |
|     case MsgRouteError:
 | |
|     case MsgValueError:
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       MOZ_CRASH("not reached");
 | |
|   }
 | |
| 
 | |
|   CrashReporter::RecordAnnotationCString(
 | |
|       CrashReporter::Annotation::ipc_channel_error, aReason);
 | |
| 
 | |
|   MOZ_CRASH("Content child abort due to IPC error");
 | |
| }
 | |
| 
 | |
| nsresult ContentChild::AddRemoteAlertObserver(const nsString& aData,
 | |
|                                               nsIObserver* aObserver) {
 | |
|   NS_ASSERTION(aObserver, "Adding a null observer?");
 | |
|   mAlertObservers.AppendElement(new AlertObserver(aObserver, aData));
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvPreferenceUpdate(const Pref& aPref) {
 | |
|   Preferences::SetPreference(aPref);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvVarUpdate(const GfxVarUpdate& aVar) {
 | |
|   gfx::gfxVars::ApplyUpdate(aVar);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvUpdatePerfStatsCollectionMask(
 | |
|     const uint64_t& aMask) {
 | |
|   PerfStats::SetCollectionMask(static_cast<PerfStats::MetricMask>(aMask));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvCollectPerfStatsJSON(
 | |
|     CollectPerfStatsJSONResolver&& aResolver) {
 | |
|   aResolver(PerfStats::CollectLocalPerfStatsJSON());
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvCollectScrollingMetrics(
 | |
|     CollectScrollingMetricsResolver&& aResolver) {
 | |
|   auto metrics = ScrollingMetrics::CollectLocalScrollingMetrics();
 | |
|   using ResolverArgs = std::tuple<const uint32_t&, const uint32_t&>;
 | |
|   aResolver(ResolverArgs(std::get<0>(metrics), std::get<1>(metrics)));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvNotifyAlertsObserver(
 | |
|     const nsCString& aType, const nsString& aData) {
 | |
|   nsTArray<nsCOMPtr<nsIObserver>> observersToNotify;
 | |
| 
 | |
|   mAlertObservers.RemoveElementsBy([&](UniquePtr<AlertObserver>& observer) {
 | |
|     if (!observer->mData.Equals(aData)) {
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // aType == alertfinished, this alert is done and we can remove the
 | |
|     // observer.
 | |
|     observersToNotify.AppendElement(observer->mObserver);
 | |
|     return aType.EqualsLiteral("alertfinished");
 | |
|   });
 | |
| 
 | |
|   for (auto& observer : observersToNotify) {
 | |
|     observer->Observe(nullptr, aType.get(), aData.get());
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvNotifyVisited(
 | |
|     nsTArray<VisitedQueryResult>&& aURIs) {
 | |
|   nsCOMPtr<IHistory> history = components::History::Service();
 | |
|   if (!history) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
|   for (const VisitedQueryResult& result : aURIs) {
 | |
|     nsCOMPtr<nsIURI> newURI = result.uri();
 | |
|     if (!newURI) {
 | |
|       return IPC_FAIL_NO_REASON(this);
 | |
|     }
 | |
|     auto status = result.visited() ? IHistory::VisitedStatus::Visited
 | |
|                                    : IHistory::VisitedStatus::Unvisited;
 | |
|     history->NotifyVisited(newURI, status);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvThemeChanged(
 | |
|     FullLookAndFeel&& aLookAndFeelData, widget::ThemeChangeKind aKind) {
 | |
|   LookAndFeel::SetData(std::move(aLookAndFeelData));
 | |
|   LookAndFeel::NotifyChangedAllWindows(aKind);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvLoadProcessScript(
 | |
|     const nsString& aURL) {
 | |
|   auto* global = ContentProcessMessageManager::Get();
 | |
|   if (global && global->LoadScript(aURL)) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
|   return IPC_FAIL(this, "ContentProcessMessageManager::LoadScript failed");
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvAsyncMessage(
 | |
|     const nsString& aMsg, const ClonedMessageData& aData) {
 | |
|   AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("ContentChild::RecvAsyncMessage",
 | |
|                                              OTHER, aMsg);
 | |
|   MMPrinter::Print("ContentChild::RecvAsyncMessage", aMsg, aData);
 | |
| 
 | |
|   RefPtr<nsFrameMessageManager> cpm =
 | |
|       nsFrameMessageManager::GetChildProcessManager();
 | |
|   if (cpm) {
 | |
|     StructuredCloneData data;
 | |
|     ipc::UnpackClonedMessageData(aData, data);
 | |
|     cpm->ReceiveMessage(cpm, nullptr, aMsg, false, &data, nullptr,
 | |
|                         IgnoreErrors());
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvRegisterStringBundles(
 | |
|     nsTArray<mozilla::dom::StringBundleDescriptor>&& aDescriptors) {
 | |
|   nsCOMPtr<nsIStringBundleService> stringBundleService =
 | |
|       components::StringBundle::Service();
 | |
| 
 | |
|   for (auto& descriptor : aDescriptors) {
 | |
|     stringBundleService->RegisterContentBundle(
 | |
|         descriptor.bundleURL(), descriptor.mapFile(), descriptor.mapSize());
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvUpdateL10nFileSources(
 | |
|     nsTArray<mozilla::dom::L10nFileSourceDescriptor>&& aDescriptors) {
 | |
|   L10nRegistry::RegisterFileSourcesFromParentProcess(aDescriptors);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvUpdateSharedData(
 | |
|     const FileDescriptor& aMapFile, const uint32_t& aMapSize,
 | |
|     nsTArray<IPCBlob>&& aBlobs, nsTArray<nsCString>&& aChangedKeys) {
 | |
|   nsTArray<RefPtr<BlobImpl>> blobImpls(aBlobs.Length());
 | |
|   for (auto& ipcBlob : aBlobs) {
 | |
|     blobImpls.AppendElement(IPCBlobUtils::Deserialize(ipcBlob));
 | |
|   }
 | |
| 
 | |
|   if (mSharedData) {
 | |
|     mSharedData->Update(aMapFile, aMapSize, std::move(blobImpls),
 | |
|                         std::move(aChangedKeys));
 | |
|   } else {
 | |
|     mSharedData =
 | |
|         new SharedMap(ContentProcessMessageManager::Get()->GetParentObject(),
 | |
|                       aMapFile, aMapSize, std::move(blobImpls));
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvFontListChanged() {
 | |
|   gfxPlatformFontList::PlatformFontList()->FontListChanged();
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvForceGlobalReflow(
 | |
|     bool aNeedsReframe) {
 | |
|   gfxPlatform::ForceGlobalReflow(aNeedsReframe ? gfxPlatform::NeedsReframe::Yes
 | |
|                                                : gfxPlatform::NeedsReframe::No);
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvGeolocationUpdate(
 | |
|     nsIDOMGeoPosition* aPosition) {
 | |
|   RefPtr<nsGeolocationService> gs =
 | |
|       nsGeolocationService::GetGeolocationService();
 | |
|   if (!gs) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
|   gs->Update(aPosition);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvGeolocationError(
 | |
|     const uint16_t& errorCode) {
 | |
|   RefPtr<nsGeolocationService> gs =
 | |
|       nsGeolocationService::GetGeolocationService();
 | |
|   if (!gs) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
|   gs->NotifyError(errorCode);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvUpdateDictionaryList(
 | |
|     nsTArray<nsCString>&& aDictionaries) {
 | |
|   mAvailableDictionaries = std::move(aDictionaries);
 | |
|   mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvUpdateFontList(
 | |
|     dom::SystemFontList&& aFontList) {
 | |
|   mFontList = std::move(aFontList);
 | |
|   if (gfxPlatform::Initialized()) {
 | |
|     gfxPlatform::GetPlatform()->UpdateFontList(true);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvRebuildFontList(
 | |
|     const bool& aFullRebuild) {
 | |
|   if (gfxPlatform::Initialized()) {
 | |
|     gfxPlatform::GetPlatform()->UpdateFontList(aFullRebuild);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvFontListShmBlockAdded(
 | |
|     const uint32_t& aGeneration, const uint32_t& aIndex,
 | |
|     base::SharedMemoryHandle&& aHandle) {
 | |
|   if (gfxPlatform::Initialized()) {
 | |
|     gfxPlatformFontList::PlatformFontList()->ShmBlockAdded(aGeneration, aIndex,
 | |
|                                                            std::move(aHandle));
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvUpdateAppLocales(
 | |
|     nsTArray<nsCString>&& aAppLocales) {
 | |
|   LocaleService::GetInstance()->AssignAppLocales(aAppLocales);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvUpdateRequestedLocales(
 | |
|     nsTArray<nsCString>&& aRequestedLocales) {
 | |
|   LocaleService::GetInstance()->AssignRequestedLocales(aRequestedLocales);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvSystemTimezoneChanged() {
 | |
|   nsJSUtils::ResetTimeZone();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvAddPermission(
 | |
|     const IPC::Permission& permission) {
 | |
|   nsCOMPtr<nsIPermissionManager> permissionManagerIface =
 | |
|       components::PermissionManager::Service();
 | |
|   PermissionManager* permissionManager =
 | |
|       static_cast<PermissionManager*>(permissionManagerIface.get());
 | |
|   MOZ_ASSERT(permissionManager,
 | |
|              "We have no permissionManager in the Content process !");
 | |
| 
 | |
|   // note we do not need to force mUserContextId to the default here because
 | |
|   // the permission manager does that internally.
 | |
|   nsAutoCString originNoSuffix;
 | |
|   OriginAttributes attrs;
 | |
|   bool success = attrs.PopulateFromOrigin(permission.origin, originNoSuffix);
 | |
|   NS_ENSURE_TRUE(success, IPC_FAIL_NO_REASON(this));
 | |
| 
 | |
|   nsCOMPtr<nsIURI> uri;
 | |
|   nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix);
 | |
|   NS_ENSURE_SUCCESS(rv, IPC_OK());
 | |
| 
 | |
|   nsCOMPtr<nsIPrincipal> principal =
 | |
|       mozilla::BasePrincipal::CreateContentPrincipal(uri, attrs);
 | |
| 
 | |
|   // child processes don't care about modification time.
 | |
|   int64_t modificationTime = 0;
 | |
| 
 | |
|   permissionManager->AddInternal(
 | |
|       principal, nsCString(permission.type), permission.capability, 0,
 | |
|       permission.expireType, permission.expireTime, modificationTime,
 | |
|       PermissionManager::eNotify, PermissionManager::eNoDBOperation);
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvRemoveAllPermissions() {
 | |
|   nsCOMPtr<nsIPermissionManager> permissionManagerIface =
 | |
|       components::PermissionManager::Service();
 | |
|   PermissionManager* permissionManager =
 | |
|       static_cast<PermissionManager*>(permissionManagerIface.get());
 | |
|   MOZ_ASSERT(permissionManager,
 | |
|              "We have no permissionManager in the Content process !");
 | |
| 
 | |
|   permissionManager->RemoveAllFromIPC();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvFlushMemory(const nsString& reason) {
 | |
|   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
 | |
|   if (!mShuttingDown && os) {
 | |
|     os->NotifyObservers(nullptr, "memory-pressure", reason.get());
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvActivateA11y() {
 | |
| #ifdef ACCESSIBILITY
 | |
|   // Start accessibility in content process if it's running in chrome
 | |
|   // process.
 | |
|   GetOrCreateAccService(nsAccessibilityService::eMainProcess);
 | |
| #endif  // ACCESSIBILITY
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvShutdownA11y() {
 | |
| #ifdef ACCESSIBILITY
 | |
|   // Try to shutdown accessibility in content process if it's shutting down in
 | |
|   // chrome process.
 | |
|   MaybeShutdownAccService(nsAccessibilityService::eMainProcess);
 | |
| #endif
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvApplicationForeground() {
 | |
|   // Rebroadcast the "application-foreground"
 | |
|   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
 | |
|   if (obs) {
 | |
|     obs->NotifyObservers(nullptr, "application-foreground", nullptr);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvApplicationBackground() {
 | |
|   // Rebroadcast the "application-background"
 | |
|   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
 | |
|   if (obs) {
 | |
|     obs->NotifyObservers(nullptr, "application-background", nullptr);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvGarbageCollect() {
 | |
|   // Rebroadcast the "child-gc-request" so that workers will GC.
 | |
|   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
 | |
|   if (obs) {
 | |
|     obs->NotifyObservers(nullptr, "child-gc-request", nullptr);
 | |
|   }
 | |
|   nsJSContext::GarbageCollectNow(JS::GCReason::DOM_IPC);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvCycleCollect() {
 | |
|   // Rebroadcast the "child-cc-request" so that workers will CC.
 | |
|   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
 | |
|   if (obs) {
 | |
|     obs->NotifyObservers(nullptr, "child-cc-request", nullptr);
 | |
|   }
 | |
|   nsJSContext::CycleCollectNow(CCReason::IPC_MESSAGE);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvUnlinkGhosts() {
 | |
| #ifdef DEBUG
 | |
|   nsWindowMemoryReporter::UnlinkGhostWindows();
 | |
| #endif
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvAppInfo(
 | |
|     const nsCString& version, const nsCString& buildID, const nsCString& name,
 | |
|     const nsCString& UAName, const nsCString& ID, const nsCString& vendor,
 | |
|     const nsCString& sourceURL, const nsCString& updateURL) {
 | |
|   mAppInfo.version.Assign(version);
 | |
|   mAppInfo.buildID.Assign(buildID);
 | |
|   mAppInfo.name.Assign(name);
 | |
|   mAppInfo.UAName.Assign(UAName);
 | |
|   mAppInfo.ID.Assign(ID);
 | |
|   mAppInfo.vendor.Assign(vendor);
 | |
|   mAppInfo.sourceURL.Assign(sourceURL);
 | |
|   mAppInfo.updateURL.Assign(updateURL);
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvRemoteType(
 | |
|     const nsCString& aRemoteType, const nsCString& aProfile) {
 | |
|   if (aRemoteType == mRemoteType) {
 | |
|     // Allocation of preallocated processes that are still launching can
 | |
|     // cause this
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   if (!mRemoteType.IsVoid()) {
 | |
|     // Preallocated processes are type PREALLOC_REMOTE_TYPE; they may not
 | |
|     // become a File: process, or Privileged About Content Process
 | |
|     MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | |
|             ("Changing remoteType of process %d from %s to %s", getpid(),
 | |
|              mRemoteType.get(), aRemoteType.get()));
 | |
|     // prealloc->anything (but file) or web->web allowed, and no-change
 | |
|     MOZ_RELEASE_ASSERT(mRemoteType == PREALLOC_REMOTE_TYPE &&
 | |
|                        aRemoteType != FILE_REMOTE_TYPE &&
 | |
|                        aRemoteType != PRIVILEGEDABOUT_REMOTE_TYPE);
 | |
|   } else {
 | |
|     // Initial setting of remote type.  Either to 'prealloc' or the actual
 | |
|     // final type (if we didn't use a preallocated process)
 | |
|     MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | |
|             ("Setting remoteType of process %d to %s", getpid(),
 | |
|              aRemoteType.get()));
 | |
| 
 | |
|     if (aRemoteType == PREALLOC_REMOTE_TYPE) {
 | |
|       PreallocInit();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   auto remoteTypePrefix = RemoteTypePrefix(aRemoteType);
 | |
| 
 | |
|   // Must do before SetProcessName
 | |
|   mRemoteType.Assign(aRemoteType);
 | |
| 
 | |
|   // Update the process name so about:memory's process names are more obvious.
 | |
|   if (aRemoteType == FILE_REMOTE_TYPE) {
 | |
|     SetProcessName("file:// Content"_ns, nullptr, &aProfile);
 | |
|   } else if (aRemoteType == EXTENSION_REMOTE_TYPE) {
 | |
|     SetProcessName("WebExtensions"_ns, nullptr, &aProfile);
 | |
|   } else if (aRemoteType == PRIVILEGEDABOUT_REMOTE_TYPE) {
 | |
|     SetProcessName("Privileged Content"_ns, nullptr, &aProfile);
 | |
|   } else if (aRemoteType == PRIVILEGEDMOZILLA_REMOTE_TYPE) {
 | |
|     SetProcessName("Privileged Mozilla"_ns, nullptr, &aProfile);
 | |
|   } else if (remoteTypePrefix == WITH_COOP_COEP_REMOTE_TYPE) {
 | |
|     // The profiler can sanitize out the eTLD+1
 | |
|     nsDependentCSubstring etld =
 | |
|         Substring(aRemoteType, WITH_COOP_COEP_REMOTE_TYPE.Length() + 1);
 | |
| #ifdef NIGHTLY_BUILD
 | |
|     SetProcessName("WebCOOP+COEP Content"_ns, &etld, &aProfile);
 | |
| #else
 | |
|     SetProcessName("Isolated Web Content"_ns, &etld,
 | |
|                    &aProfile);  // to avoid confusing people
 | |
| #endif
 | |
|   } else if (remoteTypePrefix == FISSION_WEB_REMOTE_TYPE) {
 | |
|     // The profiler can sanitize out the eTLD+1
 | |
|     nsDependentCSubstring etld =
 | |
|         Substring(aRemoteType, FISSION_WEB_REMOTE_TYPE.Length() + 1);
 | |
|     SetProcessName("Isolated Web Content"_ns, &etld, &aProfile);
 | |
|   } else if (remoteTypePrefix == SERVICEWORKER_REMOTE_TYPE) {
 | |
|     // The profiler can sanitize out the eTLD+1
 | |
|     nsDependentCSubstring etld =
 | |
|         Substring(aRemoteType, SERVICEWORKER_REMOTE_TYPE.Length() + 1);
 | |
|     SetProcessName("Isolated Service Worker"_ns, &etld, &aProfile);
 | |
|   } else {
 | |
|     // else "prealloc" or "web" type -> "Web Content"
 | |
|     SetProcessName("Web Content"_ns, nullptr, &aProfile);
 | |
|   }
 | |
| 
 | |
|   // Turn off Spectre mitigations in isolated web content processes.
 | |
|   if (StaticPrefs::javascript_options_spectre_disable_for_isolated_content() &&
 | |
|       (remoteTypePrefix == FISSION_WEB_REMOTE_TYPE ||
 | |
|        remoteTypePrefix == SERVICEWORKER_REMOTE_TYPE ||
 | |
|        remoteTypePrefix == WITH_COOP_COEP_REMOTE_TYPE ||
 | |
|        aRemoteType == PRIVILEGEDABOUT_REMOTE_TYPE ||
 | |
|        aRemoteType == PRIVILEGEDMOZILLA_REMOTE_TYPE)) {
 | |
|     JS::DisableSpectreMitigationsAfterInit();
 | |
|   }
 | |
| 
 | |
|   // Use the prefix to avoid URIs from Fission isolated processes.
 | |
|   CrashReporter::RecordAnnotationNSCString(
 | |
|       CrashReporter::Annotation::RemoteType, remoteTypePrefix);
 | |
| 
 | |
|   // Defer RemoteWorkerService initialization until the child process does
 | |
|   // receive its specific remoteType and can become actionable for the
 | |
|   // RemoteWorkerManager in the parent process.
 | |
|   if (mRemoteType != PREALLOC_REMOTE_TYPE) {
 | |
|     RemoteWorkerService::Initialize();
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| // A method to initialize anything we need during the preallocation phase
 | |
| void ContentChild::PreallocInit() {
 | |
|   EnsureNSSInitializedChromeOrContent();
 | |
| 
 | |
|   // SetAcceptLanguages() needs to read localized strings (file access),
 | |
|   // which is slow, so do this in prealloc
 | |
|   nsHttpHandler::PresetAcceptLanguages();
 | |
| }
 | |
| 
 | |
| // Call RemoteTypePrefix() on the result to remove URIs if you want to use this
 | |
| // for telemetry.
 | |
| const nsACString& ContentChild::GetRemoteType() const { return mRemoteType; }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvInitBlobURLs(
 | |
|     nsTArray<BlobURLRegistrationData>&& aRegistrations) {
 | |
|   for (uint32_t i = 0; i < aRegistrations.Length(); ++i) {
 | |
|     BlobURLRegistrationData& registration = aRegistrations[i];
 | |
|     RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(registration.blob());
 | |
|     MOZ_ASSERT(blobImpl);
 | |
| 
 | |
|     BlobURLProtocolHandler::AddDataEntry(registration.url(),
 | |
|                                          registration.principal(),
 | |
|                                          registration.partitionKey(), blobImpl);
 | |
|     // If we have received an already-revoked blobURL, we have to keep it alive
 | |
|     // for a while (see BlobURLProtocolHandler) in order to support pending
 | |
|     // operations such as navigation, download and so on.
 | |
|     if (registration.revoked()) {
 | |
|       BlobURLProtocolHandler::RemoveDataEntry(registration.url(), false);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvInitJSActorInfos(
 | |
|     nsTArray<JSProcessActorInfo>&& aContentInfos,
 | |
|     nsTArray<JSWindowActorInfo>&& aWindowInfos) {
 | |
|   RefPtr<JSActorService> actSvc = JSActorService::GetSingleton();
 | |
|   actSvc->LoadJSActorInfos(aContentInfos, aWindowInfos);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvUnregisterJSWindowActor(
 | |
|     const nsCString& aName) {
 | |
|   RefPtr<JSActorService> actSvc = JSActorService::GetSingleton();
 | |
|   actSvc->UnregisterWindowActor(aName);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvUnregisterJSProcessActor(
 | |
|     const nsCString& aName) {
 | |
|   RefPtr<JSActorService> actSvc = JSActorService::GetSingleton();
 | |
|   actSvc->UnregisterProcessActor(aName);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvLastPrivateDocShellDestroyed() {
 | |
|   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
 | |
|   obs->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvNotifyProcessPriorityChanged(
 | |
|     const hal::ProcessPriority& aPriority) {
 | |
|   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
 | |
|   NS_ENSURE_TRUE(os, IPC_OK());
 | |
| 
 | |
|   RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
 | |
|   props->SetPropertyAsInt32(u"priority"_ns, static_cast<int32_t>(aPriority));
 | |
| 
 | |
|   PROFILER_MARKER("Process Priority", OTHER,
 | |
|                   mozilla::MarkerThreadId::MainThread(), ProcessPriorityChange,
 | |
|                   ProfilerString8View::WrapNullTerminatedString(
 | |
|                       ProcessPriorityToString(mProcessPriority)),
 | |
|                   ProfilerString8View::WrapNullTerminatedString(
 | |
|                       ProcessPriorityToString(aPriority)));
 | |
| 
 | |
|   // Record FOG data before the priority change.
 | |
|   // Ignore the change if it's the first time we set the process priority.
 | |
|   if (mProcessPriority != hal::PROCESS_PRIORITY_UNKNOWN) {
 | |
|     glean::RecordPowerMetrics();
 | |
|   }
 | |
| 
 | |
|   ConfigureThreadPerformanceHints(aPriority);
 | |
| 
 | |
|   mProcessPriority = aPriority;
 | |
| 
 | |
|   os->NotifyObservers(static_cast<nsIPropertyBag2*>(props),
 | |
|                       "ipc:process-priority-changed", nullptr);
 | |
|   if (StaticPrefs::
 | |
|           dom_memory_foreground_content_processes_have_larger_page_cache()) {
 | |
|     if (mProcessPriority >= hal::PROCESS_PRIORITY_FOREGROUND) {
 | |
|       // Note: keep this in sync with the JS shell (js/src/shell/js.cpp).
 | |
|       moz_set_max_dirty_page_modifier(4);
 | |
|     } else if (mProcessPriority == hal::PROCESS_PRIORITY_BACKGROUND) {
 | |
|       moz_set_max_dirty_page_modifier(-2);
 | |
|     } else {
 | |
|       moz_set_max_dirty_page_modifier(0);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvMinimizeMemoryUsage() {
 | |
|   nsCOMPtr<nsIMemoryReporterManager> mgr =
 | |
|       do_GetService("@mozilla.org/memory-reporter-manager;1");
 | |
|   NS_ENSURE_TRUE(mgr, IPC_OK());
 | |
| 
 | |
|   Unused << mgr->MinimizeMemoryUsage(/* callback = */ nullptr);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| void ContentChild::AddIdleObserver(nsIObserver* aObserver,
 | |
|                                    uint32_t aIdleTimeInS) {
 | |
|   MOZ_ASSERT(aObserver, "null idle observer");
 | |
|   // Make sure aObserver isn't released while we wait for the parent
 | |
|   aObserver->AddRef();
 | |
|   SendAddIdleObserver(reinterpret_cast<uint64_t>(aObserver), aIdleTimeInS);
 | |
|   mIdleObservers.Insert(aObserver);
 | |
| }
 | |
| 
 | |
| void ContentChild::RemoveIdleObserver(nsIObserver* aObserver,
 | |
|                                       uint32_t aIdleTimeInS) {
 | |
|   MOZ_ASSERT(aObserver, "null idle observer");
 | |
|   SendRemoveIdleObserver(reinterpret_cast<uint64_t>(aObserver), aIdleTimeInS);
 | |
|   aObserver->Release();
 | |
|   mIdleObservers.Remove(aObserver);
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvNotifyIdleObserver(
 | |
|     const uint64_t& aObserver, const nsCString& aTopic,
 | |
|     const nsString& aTimeStr) {
 | |
|   nsIObserver* observer = reinterpret_cast<nsIObserver*>(aObserver);
 | |
|   if (mIdleObservers.Contains(observer)) {
 | |
|     observer->Observe(nullptr, aTopic.get(), aTimeStr.get());
 | |
|   } else {
 | |
|     NS_WARNING("Received notification for an idle observer that was removed.");
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvLoadAndRegisterSheet(
 | |
|     nsIURI* aURI, const uint32_t& aType) {
 | |
|   if (!aURI) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
 | |
|   if (sheetService) {
 | |
|     sheetService->LoadAndRegisterSheet(aURI, aType);
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvUnregisterSheet(
 | |
|     nsIURI* aURI, const uint32_t& aType) {
 | |
|   if (!aURI) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
 | |
|   if (sheetService) {
 | |
|     sheetService->UnregisterSheet(aURI, aType);
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvDomainSetChanged(
 | |
|     const uint32_t& aSetType, const uint32_t& aChangeType, nsIURI* aDomain) {
 | |
|   if (aChangeType == ACTIVATE_POLICY) {
 | |
|     if (mPolicy) {
 | |
|       return IPC_OK();
 | |
|     }
 | |
|     nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
 | |
|     MOZ_ASSERT(ssm);
 | |
|     ssm->ActivateDomainPolicyInternal(getter_AddRefs(mPolicy));
 | |
|     if (!mPolicy) {
 | |
|       return IPC_FAIL_NO_REASON(this);
 | |
|     }
 | |
|     return IPC_OK();
 | |
|   }
 | |
|   if (!mPolicy) {
 | |
|     MOZ_ASSERT_UNREACHABLE(
 | |
|         "If the domain policy is not active yet,"
 | |
|         " the first message should be ACTIVATE_POLICY");
 | |
|     return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   NS_ENSURE_TRUE(mPolicy, IPC_FAIL_NO_REASON(this));
 | |
| 
 | |
|   if (aChangeType == DEACTIVATE_POLICY) {
 | |
|     mPolicy->Deactivate();
 | |
|     mPolicy = nullptr;
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIDomainSet> set;
 | |
|   switch (aSetType) {
 | |
|     case BLOCKLIST:
 | |
|       mPolicy->GetBlocklist(getter_AddRefs(set));
 | |
|       break;
 | |
|     case SUPER_BLOCKLIST:
 | |
|       mPolicy->GetSuperBlocklist(getter_AddRefs(set));
 | |
|       break;
 | |
|     case ALLOWLIST:
 | |
|       mPolicy->GetAllowlist(getter_AddRefs(set));
 | |
|       break;
 | |
|     case SUPER_ALLOWLIST:
 | |
|       mPolicy->GetSuperAllowlist(getter_AddRefs(set));
 | |
|       break;
 | |
|     default:
 | |
|       MOZ_ASSERT_UNREACHABLE("Unexpected setType");
 | |
|       return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   MOZ_ASSERT(set);
 | |
| 
 | |
|   switch (aChangeType) {
 | |
|     case ADD_DOMAIN:
 | |
|       NS_ENSURE_TRUE(aDomain, IPC_FAIL_NO_REASON(this));
 | |
|       set->Add(aDomain);
 | |
|       break;
 | |
|     case REMOVE_DOMAIN:
 | |
|       NS_ENSURE_TRUE(aDomain, IPC_FAIL_NO_REASON(this));
 | |
|       set->Remove(aDomain);
 | |
|       break;
 | |
|     case CLEAR_DOMAINS:
 | |
|       set->Clear();
 | |
|       break;
 | |
|     default:
 | |
|       MOZ_ASSERT_UNREACHABLE("Unexpected changeType");
 | |
|       return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| void ContentChild::StartForceKillTimer() {
 | |
|   if (mForceKillTimer) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   int32_t timeoutSecs = StaticPrefs::dom_ipc_tabs_shutdownTimeoutSecs();
 | |
|   if (timeoutSecs > 0) {
 | |
|     NS_NewTimerWithFuncCallback(getter_AddRefs(mForceKillTimer),
 | |
|                                 ContentChild::ForceKillTimerCallback, this,
 | |
|                                 timeoutSecs * 1000, nsITimer::TYPE_ONE_SHOT,
 | |
|                                 "dom::ContentChild::StartForceKillTimer");
 | |
|     MOZ_ASSERT(mForceKillTimer);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void ContentChild::ForceKillTimerCallback(nsITimer* aTimer, void* aClosure) {
 | |
|   ProcessChild::QuickExit();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvShutdownConfirmedHP() {
 | |
|   ProcessChild::AppendToIPCShutdownStateAnnotation(
 | |
|       "RecvShutdownConfirmedHP entry"_ns);
 | |
| 
 | |
|   // Bug 1755376: If we see "RecvShutdownConfirmedHP entry" often in
 | |
|   // bug IPCError_ShutDownKill we might want to anticipate
 | |
|   // ShutdownPhase::AppShutdownConfirmed to start here.
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvShutdown() {
 | |
|   ProcessChild::AppendToIPCShutdownStateAnnotation("RecvShutdown entry"_ns);
 | |
| 
 | |
|   // Signal the ongoing shutdown to AppShutdown, this
 | |
|   // will make abort nested SpinEventLoopUntilOrQuit loops
 | |
|   AppShutdown::AdvanceShutdownPhaseWithoutNotify(
 | |
|       ShutdownPhase::AppShutdownConfirmed);
 | |
| 
 | |
|   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
 | |
|   if (os) {
 | |
|     ProcessChild::AppendToIPCShutdownStateAnnotation(
 | |
|         "content-child-will-shutdown started"_ns);
 | |
| 
 | |
|     os->NotifyObservers(ToSupports(this), "content-child-will-shutdown",
 | |
|                         nullptr);
 | |
|   }
 | |
| 
 | |
|   ShutdownInternal();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| void ContentChild::ShutdownInternal() {
 | |
|   ProcessChild::AppendToIPCShutdownStateAnnotation("ShutdownInternal entry"_ns);
 | |
| 
 | |
|   // If we receive the shutdown message from within a nested event loop, we want
 | |
|   // to wait for that event loop to finish. Otherwise we could prematurely
 | |
|   // terminate an "unload" or "pagehide" event handler (which might be doing a
 | |
|   // sync XHR, for example).
 | |
| 
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
|   RefPtr<nsThread> mainThread = nsThreadManager::get().GetCurrentThread();
 | |
|   // Note that we only have to check the recursion count for the current
 | |
|   // cooperative thread. Since the Shutdown message is not labeled with a
 | |
|   // SchedulerGroup, there can be no other cooperative threads doing work while
 | |
|   // we're running.
 | |
|   if (mainThread && mainThread->RecursionDepth() > 1) {
 | |
|     // We're in a nested event loop. Let's delay for an arbitrary period of
 | |
|     // time (100ms) in the hopes that the event loop will have finished by
 | |
|     // then.
 | |
|     GetCurrentSerialEventTarget()->DelayedDispatch(
 | |
|         NewRunnableMethod("dom::ContentChild::RecvShutdown", this,
 | |
|                           &ContentChild::ShutdownInternal),
 | |
|         100);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   mShuttingDown = true;
 | |
| 
 | |
| #ifdef NIGHTLY_BUILD
 | |
|   BackgroundHangMonitor::UnregisterAnnotator(
 | |
|       PendingInputEventHangAnnotator::sSingleton);
 | |
| #endif
 | |
| 
 | |
|   if (mPolicy) {
 | |
|     mPolicy->Deactivate();
 | |
|     mPolicy = nullptr;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
 | |
|   if (os) {
 | |
|     ProcessChild::AppendToIPCShutdownStateAnnotation(
 | |
|         "content-child-shutdown started"_ns);
 | |
|     os->NotifyObservers(ToSupports(this), "content-child-shutdown", nullptr);
 | |
|   }
 | |
| 
 | |
|   GetIPCChannel()->SetAbortOnError(false);
 | |
| 
 | |
|   if (mProfilerController) {
 | |
|     const bool isProfiling = profiler_is_active();
 | |
|     CrashReporter::RecordAnnotationCString(
 | |
|         CrashReporter::Annotation::ProfilerChildShutdownPhase,
 | |
|         isProfiling ? "Profiling - GrabShutdownProfileAndShutdown"
 | |
|                     : "Not profiling - GrabShutdownProfileAndShutdown");
 | |
|     ProfileAndAdditionalInformation shutdownProfileAndAdditionalInformation =
 | |
|         mProfilerController->GrabShutdownProfileAndShutdown();
 | |
|     CrashReporter::RecordAnnotationCString(
 | |
|         CrashReporter::Annotation::ProfilerChildShutdownPhase,
 | |
|         isProfiling ? "Profiling - Destroying ChildProfilerController"
 | |
|                     : "Not profiling - Destroying ChildProfilerController");
 | |
|     mProfilerController = nullptr;
 | |
|     CrashReporter::RecordAnnotationCString(
 | |
|         CrashReporter::Annotation::ProfilerChildShutdownPhase,
 | |
|         isProfiling ? "Profiling - SendShutdownProfile (sending)"
 | |
|                     : "Not profiling - SendShutdownProfile (sending)");
 | |
|     if (const size_t len = shutdownProfileAndAdditionalInformation.SizeOf();
 | |
|         len >= size_t(IPC::Channel::kMaximumMessageSize)) {
 | |
|       shutdownProfileAndAdditionalInformation.mProfile = nsPrintfCString(
 | |
|           "*Profile from pid %u bigger (%zu) than IPC max (%zu)",
 | |
|           unsigned(profiler_current_process_id().ToNumber()), len,
 | |
|           size_t(IPC::Channel::kMaximumMessageSize));
 | |
|     }
 | |
|     // Send the shutdown profile to the parent process through our own
 | |
|     // message channel, which we know will survive for long enough.
 | |
|     bool sent =
 | |
|         SendShutdownProfile(shutdownProfileAndAdditionalInformation.mProfile);
 | |
|     CrashReporter::RecordAnnotationCString(
 | |
|         CrashReporter::Annotation::ProfilerChildShutdownPhase,
 | |
|         sent ? (isProfiling ? "Profiling - SendShutdownProfile (sent)"
 | |
|                             : "Not profiling - SendShutdownProfile (sent)")
 | |
|              : (isProfiling ? "Profiling - SendShutdownProfile (failed)"
 | |
|                             : "Not profiling - SendShutdownProfile (failed)"));
 | |
|   }
 | |
| 
 | |
|   if (PerfStats::GetCollectionMask() != 0) {
 | |
|     SendShutdownPerfStats(PerfStats::CollectLocalPerfStatsJSON());
 | |
|   }
 | |
| 
 | |
|   // Start a timer that will ensure we quickly exit after a reasonable period
 | |
|   // of time. Prevents shutdown hangs after our connection to the parent
 | |
|   // closes or when the parent is too busy to ever kill us.
 | |
|   ProcessChild::AppendToIPCShutdownStateAnnotation("StartForceKillTimer"_ns);
 | |
|   StartForceKillTimer();
 | |
| 
 | |
|   ProcessChild::AppendToIPCShutdownStateAnnotation(
 | |
|       "SendFinishShutdown (sending)"_ns);
 | |
| 
 | |
|   // Notify the parent that we are done with shutdown. This is sent with high
 | |
|   // priority and will just flag we are done.
 | |
|   Unused << SendNotifyShutdownSuccess();
 | |
| 
 | |
|   // Now tell the parent to actually destroy our channel which will make end
 | |
|   // our process. This is expected to be the last event the parent will
 | |
|   // ever process for this ContentChild.
 | |
|   bool sent = SendFinishShutdown();
 | |
| 
 | |
|   ProcessChild::AppendToIPCShutdownStateAnnotation(
 | |
|       sent ? "SendFinishShutdown (sent)"_ns : "SendFinishShutdown (failed)"_ns);
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvUpdateWindow(
 | |
|     const uintptr_t& aChildId) {
 | |
|   MOZ_ASSERT(
 | |
|       false,
 | |
|       "ContentChild::RecvUpdateWindow calls unexpected on this platform.");
 | |
|   return IPC_FAIL_NO_REASON(this);
 | |
| }
 | |
| 
 | |
| PContentPermissionRequestChild*
 | |
| ContentChild::AllocPContentPermissionRequestChild(
 | |
|     Span<const PermissionRequest> aRequests, nsIPrincipal* aPrincipal,
 | |
|     nsIPrincipal* aTopLevelPrincipal, const bool& aIsHandlingUserInput,
 | |
|     const bool& aMaybeUnsafePermissionDelegate, const TabId& aTabId) {
 | |
|   MOZ_CRASH("unused");
 | |
|   return nullptr;
 | |
| }
 | |
| 
 | |
| bool ContentChild::DeallocPContentPermissionRequestChild(
 | |
|     PContentPermissionRequestChild* actor) {
 | |
|   nsContentPermissionUtils::NotifyRemoveContentPermissionRequestChild(actor);
 | |
|   auto child = static_cast<RemotePermissionRequest*>(actor);
 | |
|   child->IPDLRelease();
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| already_AddRefed<PWebBrowserPersistDocumentChild>
 | |
| ContentChild::AllocPWebBrowserPersistDocumentChild(
 | |
|     PBrowserChild* aBrowser, const MaybeDiscarded<BrowsingContext>& aContext) {
 | |
|   return MakeAndAddRef<WebBrowserPersistDocumentChild>();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvPWebBrowserPersistDocumentConstructor(
 | |
|     PWebBrowserPersistDocumentChild* aActor, PBrowserChild* aBrowser,
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext) {
 | |
|   if (NS_WARN_IF(!aBrowser)) {
 | |
|     return IPC_FAIL_NO_REASON(this);
 | |
|   }
 | |
| 
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     aActor->SendInitFailure(NS_ERROR_NO_CONTENT);
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<Document> foundDoc = aContext.get()->GetDocument();
 | |
| 
 | |
|   if (!foundDoc) {
 | |
|     aActor->SendInitFailure(NS_ERROR_NO_CONTENT);
 | |
|   } else {
 | |
|     static_cast<WebBrowserPersistDocumentChild*>(aActor)->Start(foundDoc);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| static already_AddRefed<DataTransfer> ConvertToDataTransfer(
 | |
|     nsTArray<IPCTransferableData>&& aTransferables, EventMessage aMessage) {
 | |
|   // Check if we are receiving any file objects. If we are we will want
 | |
|   // to hide any of the other objects coming in from content.
 | |
|   bool hasFiles = false;
 | |
|   for (uint32_t i = 0; i < aTransferables.Length() && !hasFiles; ++i) {
 | |
|     auto& items = aTransferables[i].items();
 | |
|     for (uint32_t j = 0; j < items.Length() && !hasFiles; ++j) {
 | |
|       if (items[j].data().type() ==
 | |
|           IPCTransferableDataType::TIPCTransferableDataBlob) {
 | |
|         hasFiles = true;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   // Add the entries from the IPC to the new DataTransfer
 | |
|   RefPtr<DataTransfer> dataTransfer =
 | |
|       new DataTransfer(nullptr, aMessage, false, -1);
 | |
|   for (uint32_t i = 0; i < aTransferables.Length(); ++i) {
 | |
|     auto& items = aTransferables[i].items();
 | |
|     for (uint32_t j = 0; j < items.Length(); ++j) {
 | |
|       const IPCTransferableDataItem& item = items[j];
 | |
|       RefPtr<nsVariantCC> variant = new nsVariantCC();
 | |
|       nsresult rv =
 | |
|           nsContentUtils::IPCTransferableDataItemToVariant(item, variant);
 | |
|       if (NS_FAILED(rv)) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       // We should hide this data from content if we have a file, and we
 | |
|       // aren't a file.
 | |
|       bool hidden =
 | |
|           hasFiles && item.data().type() !=
 | |
|                           IPCTransferableDataType::TIPCTransferableDataBlob;
 | |
|       dataTransfer->SetDataWithPrincipalFromOtherProcess(
 | |
|           NS_ConvertUTF8toUTF16(item.flavor()), variant, i,
 | |
|           nsContentUtils::GetSystemPrincipal(), hidden);
 | |
|     }
 | |
|   }
 | |
|   return dataTransfer.forget();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvInvokeDragSession(
 | |
|     const MaybeDiscarded<WindowContext>& aSourceWindowContext,
 | |
|     const MaybeDiscarded<WindowContext>& aSourceTopWindowContext,
 | |
|     nsTArray<IPCTransferableData>&& aTransferables, const uint32_t& aAction) {
 | |
|   if (nsCOMPtr<nsIDragService> dragService =
 | |
|           do_GetService("@mozilla.org/widget/dragservice;1")) {
 | |
|     dragService->StartDragSession();
 | |
|     nsCOMPtr<nsIDragSession> session;
 | |
|     dragService->GetCurrentSession(getter_AddRefs(session));
 | |
|     if (session) {
 | |
|       session->SetSourceWindowContext(aSourceWindowContext.GetMaybeDiscarded());
 | |
|       session->SetSourceTopWindowContext(
 | |
|           aSourceTopWindowContext.GetMaybeDiscarded());
 | |
|       session->SetDragAction(aAction);
 | |
| 
 | |
|       RefPtr<DataTransfer> dataTransfer =
 | |
|           ConvertToDataTransfer(std::move(aTransferables), eDragStart);
 | |
|       session->SetDataTransfer(dataTransfer);
 | |
|     }
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvUpdateDragSession(
 | |
|     nsTArray<IPCTransferableData>&& aTransferables,
 | |
|     EventMessage aEventMessage) {
 | |
|   if (nsCOMPtr<nsIDragService> dragService =
 | |
|           do_GetService("@mozilla.org/widget/dragservice;1")) {
 | |
|     nsCOMPtr<nsIDragSession> session;
 | |
|     dragService->GetCurrentSession(getter_AddRefs(session));
 | |
|     if (session) {
 | |
|       nsCOMPtr<DataTransfer> dataTransfer =
 | |
|           ConvertToDataTransfer(std::move(aTransferables), aEventMessage);
 | |
|       session->SetDataTransfer(dataTransfer);
 | |
|     }
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvEndDragSession(
 | |
|     const bool& aDoneDrag, const bool& aUserCancelled,
 | |
|     const LayoutDeviceIntPoint& aDragEndPoint, const uint32_t& aKeyModifiers,
 | |
|     const uint32_t& aDropEffect) {
 | |
|   nsCOMPtr<nsIDragService> dragService =
 | |
|       do_GetService("@mozilla.org/widget/dragservice;1");
 | |
|   if (dragService) {
 | |
|     nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
 | |
|     if (dragSession) {
 | |
|       if (aUserCancelled) {
 | |
|         dragSession->UserCancelled();
 | |
|       }
 | |
| 
 | |
|       RefPtr<DataTransfer> dataTransfer = dragSession->GetDataTransfer();
 | |
|       if (dataTransfer) {
 | |
|         dataTransfer->SetDropEffectInt(aDropEffect);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     static_cast<nsBaseDragService*>(dragService.get())
 | |
|         ->SetDragEndPoint(aDragEndPoint);
 | |
|     dragService->EndDragSession(aDoneDrag, aKeyModifiers);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvPush(const nsCString& aScope,
 | |
|                                                nsIPrincipal* aPrincipal,
 | |
|                                                const nsString& aMessageId) {
 | |
|   PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId, Nothing());
 | |
|   Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvPushWithData(
 | |
|     const nsCString& aScope, nsIPrincipal* aPrincipal,
 | |
|     const nsString& aMessageId, nsTArray<uint8_t>&& aData) {
 | |
|   PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId,
 | |
|                                    Some(std::move(aData)));
 | |
|   Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvPushSubscriptionChange(
 | |
|     const nsCString& aScope, nsIPrincipal* aPrincipal) {
 | |
|   PushSubscriptionChangeDispatcher dispatcher(aScope, aPrincipal);
 | |
|   Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvPushError(const nsCString& aScope,
 | |
|                                                     nsIPrincipal* aPrincipal,
 | |
|                                                     const nsString& aMessage,
 | |
|                                                     const uint32_t& aFlags) {
 | |
|   PushErrorDispatcher dispatcher(aScope, aPrincipal, aMessage, aFlags);
 | |
|   Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult
 | |
| ContentChild::RecvNotifyPushSubscriptionModifiedObservers(
 | |
|     const nsCString& aScope, nsIPrincipal* aPrincipal) {
 | |
|   PushSubscriptionModifiedDispatcher dispatcher(aScope, aPrincipal);
 | |
|   Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers()));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvBlobURLRegistration(
 | |
|     const nsCString& aURI, const IPCBlob& aBlob, nsIPrincipal* aPrincipal,
 | |
|     const nsCString& aPartitionKey) {
 | |
|   RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(aBlob);
 | |
|   MOZ_ASSERT(blobImpl);
 | |
| 
 | |
|   BlobURLProtocolHandler::AddDataEntry(aURI, aPrincipal, aPartitionKey,
 | |
|                                        blobImpl);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvBlobURLUnregistration(
 | |
|     const nsCString& aURI) {
 | |
|   BlobURLProtocolHandler::RemoveDataEntry(
 | |
|       aURI,
 | |
|       /* aBroadcastToOtherProcesses = */ false);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| void ContentChild::CreateGetFilesRequest(const nsAString& aDirectoryPath,
 | |
|                                          bool aRecursiveFlag, nsID& aUUID,
 | |
|                                          GetFilesHelperChild* aChild) {
 | |
|   MOZ_ASSERT(aChild);
 | |
|   MOZ_ASSERT(!mGetFilesPendingRequests.Contains(aUUID));
 | |
| 
 | |
|   Unused << SendGetFilesRequest(aUUID, aDirectoryPath, aRecursiveFlag);
 | |
|   mGetFilesPendingRequests.InsertOrUpdate(aUUID, RefPtr{aChild});
 | |
| }
 | |
| 
 | |
| void ContentChild::DeleteGetFilesRequest(nsID& aUUID,
 | |
|                                          GetFilesHelperChild* aChild) {
 | |
|   MOZ_ASSERT(aChild);
 | |
|   MOZ_ASSERT(mGetFilesPendingRequests.Contains(aUUID));
 | |
| 
 | |
|   Unused << SendDeleteGetFilesRequest(aUUID);
 | |
|   mGetFilesPendingRequests.Remove(aUUID);
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvGetFilesResponse(
 | |
|     const nsID& aUUID, const GetFilesResponseResult& aResult) {
 | |
|   RefPtr<GetFilesHelperChild> child;
 | |
| 
 | |
|   // This object can already been deleted in case DeleteGetFilesRequest has
 | |
|   // been called when the response was sending by the parent.
 | |
|   if (!mGetFilesPendingRequests.Remove(aUUID, getter_AddRefs(child))) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   if (aResult.type() == GetFilesResponseResult::TGetFilesResponseFailure) {
 | |
|     child->Finished(aResult.get_GetFilesResponseFailure().errorCode());
 | |
|   } else {
 | |
|     MOZ_ASSERT(aResult.type() ==
 | |
|                GetFilesResponseResult::TGetFilesResponseSuccess);
 | |
| 
 | |
|     const nsTArray<IPCBlob>& ipcBlobs =
 | |
|         aResult.get_GetFilesResponseSuccess().blobs();
 | |
| 
 | |
|     bool succeeded = true;
 | |
|     for (uint32_t i = 0; succeeded && i < ipcBlobs.Length(); ++i) {
 | |
|       RefPtr<BlobImpl> impl = IPCBlobUtils::Deserialize(ipcBlobs[i]);
 | |
|       succeeded = child->AppendBlobImpl(impl);
 | |
|     }
 | |
| 
 | |
|     child->Finished(succeeded ? NS_OK : NS_ERROR_OUT_OF_MEMORY);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void ContentChild::FatalErrorIfNotUsingGPUProcess(const char* const aErrorMsg,
 | |
|                                                   base::ProcessId aOtherPid) {
 | |
|   // If we're communicating with the same process or the UI process then we
 | |
|   // want to crash normally. Otherwise we want to just warn as the other end
 | |
|   // must be the GPU process and it crashing shouldn't be fatal for us.
 | |
|   if (aOtherPid == base::GetCurrentProcId() ||
 | |
|       (GetSingleton() && GetSingleton()->OtherPid() == aOtherPid)) {
 | |
|     mozilla::ipc::FatalError(aErrorMsg, false);
 | |
|   } else {
 | |
|     nsAutoCString formattedMessage("IPDL error: \"");
 | |
|     formattedMessage.AppendASCII(aErrorMsg);
 | |
|     formattedMessage.AppendLiteral(R"(".)");
 | |
|     NS_WARNING(formattedMessage.get());
 | |
|   }
 | |
| }
 | |
| 
 | |
| PURLClassifierChild* ContentChild::AllocPURLClassifierChild(
 | |
|     nsIPrincipal* aPrincipal, bool* aSuccess) {
 | |
|   *aSuccess = true;
 | |
|   return new URLClassifierChild();
 | |
| }
 | |
| 
 | |
| bool ContentChild::DeallocPURLClassifierChild(PURLClassifierChild* aActor) {
 | |
|   MOZ_ASSERT(aActor);
 | |
|   delete aActor;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| PURLClassifierLocalChild* ContentChild::AllocPURLClassifierLocalChild(
 | |
|     nsIURI* aUri, Span<const IPCURLClassifierFeature> aFeatures) {
 | |
|   return new URLClassifierLocalChild();
 | |
| }
 | |
| 
 | |
| bool ContentChild::DeallocPURLClassifierLocalChild(
 | |
|     PURLClassifierLocalChild* aActor) {
 | |
|   MOZ_ASSERT(aActor);
 | |
|   delete aActor;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| PSessionStorageObserverChild*
 | |
| ContentChild::AllocPSessionStorageObserverChild() {
 | |
|   MOZ_CRASH(
 | |
|       "PSessionStorageObserverChild actors should be manually constructed!");
 | |
| }
 | |
| 
 | |
| bool ContentChild::DeallocPSessionStorageObserverChild(
 | |
|     PSessionStorageObserverChild* aActor) {
 | |
|   MOZ_ASSERT(aActor);
 | |
| 
 | |
|   delete aActor;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvProvideAnonymousTemporaryFile(
 | |
|     const uint64_t& aID, const FileDescOrError& aFDOrError) {
 | |
|   mozilla::UniquePtr<AnonymousTemporaryFileCallback> callback;
 | |
|   mPendingAnonymousTemporaryFiles.Remove(aID, &callback);
 | |
|   MOZ_ASSERT(callback);
 | |
| 
 | |
|   PRFileDesc* prfile = nullptr;
 | |
|   if (aFDOrError.type() == FileDescOrError::Tnsresult) {
 | |
|     DebugOnly<nsresult> rv = aFDOrError.get_nsresult();
 | |
|     MOZ_ASSERT(NS_FAILED(rv));
 | |
|   } else {
 | |
|     auto rawFD = aFDOrError.get_FileDescriptor().ClonePlatformHandle();
 | |
|     prfile = PR_ImportFile(PROsfd(rawFD.release()));
 | |
|   }
 | |
|   (*callback)(prfile);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| nsresult ContentChild::AsyncOpenAnonymousTemporaryFile(
 | |
|     const AnonymousTemporaryFileCallback& aCallback) {
 | |
|   MOZ_ASSERT(NS_IsMainThread());
 | |
| 
 | |
|   static uint64_t id = 0;
 | |
|   auto newID = id++;
 | |
|   if (!SendRequestAnonymousTemporaryFile(newID)) {
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   // Remember the association with the callback.
 | |
|   MOZ_ASSERT(!mPendingAnonymousTemporaryFiles.Get(newID));
 | |
|   mPendingAnonymousTemporaryFiles.GetOrInsertNew(newID, aCallback);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvSetPermissionsWithKey(
 | |
|     const nsCString& aPermissionKey, nsTArray<IPC::Permission>&& aPerms) {
 | |
|   RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
 | |
|   if (permManager) {
 | |
|     permManager->SetPermissionsWithKey(aPermissionKey, aPerms);
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvRefreshScreens(
 | |
|     nsTArray<ScreenDetails>&& aScreens) {
 | |
|   ScreenManager& screenManager = ScreenManager::GetSingleton();
 | |
|   screenManager.Refresh(std::move(aScreens));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvShareCodeCoverageMutex(
 | |
|     CrossProcessMutexHandle aHandle) {
 | |
| #ifdef MOZ_CODE_COVERAGE
 | |
|   CodeCoverageHandler::Init(std::move(aHandle));
 | |
|   return IPC_OK();
 | |
| #else
 | |
|   MOZ_CRASH("Shouldn't receive this message in non-code coverage builds!");
 | |
| #endif
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvFlushCodeCoverageCounters(
 | |
|     FlushCodeCoverageCountersResolver&& aResolver) {
 | |
| #ifdef MOZ_CODE_COVERAGE
 | |
|   CodeCoverageHandler::FlushCounters();
 | |
|   aResolver(/* unused */ true);
 | |
|   return IPC_OK();
 | |
| #else
 | |
|   MOZ_CRASH("Shouldn't receive this message in non-code coverage builds!");
 | |
| #endif
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvSetInputEventQueueEnabled() {
 | |
|   nsThreadManager::get().EnableMainThreadEventPrioritization();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvFlushInputEventQueue() {
 | |
|   nsThreadManager::get().FlushInputEventPrioritization();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvSuspendInputEventQueue() {
 | |
|   nsThreadManager::get().SuspendInputEventPrioritization();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvResumeInputEventQueue() {
 | |
|   nsThreadManager::get().ResumeInputEventPrioritization();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvAddDynamicScalars(
 | |
|     nsTArray<DynamicScalarDefinition>&& aDefs) {
 | |
|   TelemetryIPC::AddDynamicScalarDefinitions(aDefs);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvCrossProcessRedirect(
 | |
|     RedirectToRealChannelArgs&& aArgs,
 | |
|     nsTArray<Endpoint<extensions::PStreamFilterParent>>&& aEndpoints,
 | |
|     CrossProcessRedirectResolver&& aResolve) {
 | |
|   nsCOMPtr<nsILoadInfo> loadInfo;
 | |
|   nsresult rv = mozilla::ipc::LoadInfoArgsToLoadInfo(
 | |
|       aArgs.loadInfo(), NOT_REMOTE_TYPE, getter_AddRefs(loadInfo));
 | |
|   if (NS_FAILED(rv)) {
 | |
|     MOZ_DIAGNOSTIC_ASSERT(false, "LoadInfoArgsToLoadInfo failed");
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIChannel> newChannel;
 | |
|   MOZ_ASSERT((aArgs.loadStateInternalLoadFlags() &
 | |
|               nsDocShell::InternalLoad::INTERNAL_LOAD_FLAGS_IS_SRCDOC) ||
 | |
|              aArgs.srcdocData().IsVoid());
 | |
|   rv = nsDocShell::CreateRealChannelForDocument(
 | |
|       getter_AddRefs(newChannel), aArgs.uri(), loadInfo, nullptr,
 | |
|       aArgs.newLoadFlags(), aArgs.srcdocData(), aArgs.baseUri());
 | |
| 
 | |
|   if (RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(newChannel)) {
 | |
|     httpChannel->SetEarlyHints(std::move(aArgs.earlyHints()));
 | |
|     httpChannel->SetEarlyHintLinkType(aArgs.earlyHintLinkType());
 | |
|   }
 | |
| 
 | |
|   // This is used to report any errors back to the parent by calling
 | |
|   // CrossProcessRedirectFinished.
 | |
|   RefPtr<HttpChannelChild> httpChild = do_QueryObject(newChannel);
 | |
|   auto resolve = [=](const nsresult& aRv) {
 | |
|     nsresult rv = aRv;
 | |
|     if (httpChild) {
 | |
|       rv = httpChild->CrossProcessRedirectFinished(rv);
 | |
|     }
 | |
|     aResolve(rv);
 | |
|   };
 | |
|   auto scopeExit = MakeScopeExit([&]() { resolve(rv); });
 | |
| 
 | |
|   if (NS_FAILED(rv)) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel)) {
 | |
|     rv = httpChannel->SetChannelId(aArgs.channelId());
 | |
|   }
 | |
|   if (NS_FAILED(rv)) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   rv = newChannel->SetOriginalURI(aArgs.originalURI());
 | |
|   if (NS_FAILED(rv)) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   if (nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
 | |
|           do_QueryInterface(newChannel)) {
 | |
|     rv = httpChannelInternal->SetRedirectMode(aArgs.redirectMode());
 | |
|   }
 | |
|   if (NS_FAILED(rv)) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   if (aArgs.init()) {
 | |
|     HttpBaseChannel::ReplacementChannelConfig config(std::move(*aArgs.init()));
 | |
|     HttpBaseChannel::ConfigureReplacementChannel(
 | |
|         newChannel, config,
 | |
|         HttpBaseChannel::ReplacementReason::DocumentChannel);
 | |
|   }
 | |
| 
 | |
|   if (aArgs.contentDisposition()) {
 | |
|     newChannel->SetContentDisposition(*aArgs.contentDisposition());
 | |
|   }
 | |
| 
 | |
|   if (aArgs.contentDispositionFilename()) {
 | |
|     newChannel->SetContentDispositionFilename(
 | |
|         *aArgs.contentDispositionFilename());
 | |
|   }
 | |
| 
 | |
|   if (nsCOMPtr<nsIChildChannel> childChannel = do_QueryInterface(newChannel)) {
 | |
|     // Connect to the parent if this is a remote channel. If it's entirely
 | |
|     // handled locally, then we'll call AsyncOpen from the docshell when
 | |
|     // we complete the setup
 | |
|     rv = childChannel->ConnectParent(
 | |
|         aArgs.registrarId());  // creates parent channel
 | |
|     if (NS_FAILED(rv)) {
 | |
|       return IPC_OK();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // We need to copy the property bag before signaling that the channel
 | |
|   // is ready so that the nsDocShell can retrieve the history data when called.
 | |
|   if (nsCOMPtr<nsIWritablePropertyBag> bag = do_QueryInterface(newChannel)) {
 | |
|     nsHashPropertyBag::CopyFrom(bag, aArgs.properties());
 | |
|   }
 | |
| 
 | |
|   RefPtr<nsDocShellLoadState> loadState;
 | |
|   rv = nsDocShellLoadState::CreateFromPendingChannel(
 | |
|       newChannel, aArgs.loadIdentifier(), aArgs.registrarId(),
 | |
|       getter_AddRefs(loadState));
 | |
|   if (NS_WARN_IF(NS_FAILED(rv))) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
|   loadState->SetLoadFlags(aArgs.loadStateExternalLoadFlags());
 | |
|   loadState->SetInternalLoadFlags(aArgs.loadStateInternalLoadFlags());
 | |
|   if (IsValidLoadType(aArgs.loadStateLoadType())) {
 | |
|     loadState->SetLoadType(aArgs.loadStateLoadType());
 | |
|   }
 | |
| 
 | |
|   if (aArgs.loadingSessionHistoryInfo().isSome()) {
 | |
|     loadState->SetLoadingSessionHistoryInfo(
 | |
|         aArgs.loadingSessionHistoryInfo().ref());
 | |
|   }
 | |
|   if (aArgs.originalUriString().isSome()) {
 | |
|     loadState->SetOriginalURIString(aArgs.originalUriString().ref());
 | |
|   }
 | |
| 
 | |
|   RefPtr<ChildProcessChannelListener> processListener =
 | |
|       ChildProcessChannelListener::GetSingleton();
 | |
|   // The listener will call completeRedirectSetup or asyncOpen on the channel.
 | |
|   processListener->OnChannelReady(loadState, aArgs.loadIdentifier(),
 | |
|                                   std::move(aEndpoints), aArgs.timing(),
 | |
|                                   std::move(resolve));
 | |
|   scopeExit.release();
 | |
| 
 | |
|   // scopeExit will call CrossProcessRedirectFinished(rv) here
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvStartDelayedAutoplayMediaComponents(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext) {
 | |
|   if (NS_WARN_IF(aContext.IsNullOrDiscarded())) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   aContext.get()->StartDelayedAutoplayMediaComponents();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvUpdateMediaControlAction(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext,
 | |
|     const MediaControlAction& aAction) {
 | |
|   if (NS_WARN_IF(aContext.IsNullOrDiscarded())) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   ContentMediaControlKeyHandler::HandleMediaControlAction(aContext.get(),
 | |
|                                                           aAction);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvOnAllowAccessFor(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext,
 | |
|     const nsCString& aTrackingOrigin, uint32_t aCookieBehavior,
 | |
|     const ContentBlockingNotifier::StorageAccessPermissionGrantedReason&
 | |
|         aReason) {
 | |
|   MOZ_ASSERT(!aContext.IsNull(), "Browsing context cannot be null");
 | |
| 
 | |
|   StorageAccessAPIHelper::OnAllowAccessFor(
 | |
|       aContext.GetMaybeDiscarded(), aTrackingOrigin, aCookieBehavior, aReason);
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvOnContentBlockingDecision(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext,
 | |
|     const ContentBlockingNotifier::BlockingDecision& aDecision,
 | |
|     uint32_t aRejectedReason) {
 | |
|   MOZ_ASSERT(!aContext.IsNull(), "Browsing context cannot be null");
 | |
| 
 | |
|   nsCOMPtr<nsPIDOMWindowOuter> outer = aContext.get()->GetDOMWindow();
 | |
|   if (!outer) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to a context without a outer "
 | |
|              "window"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsPIDOMWindowInner> inner = outer->GetCurrentInnerWindow();
 | |
|   if (!inner) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to a context without a inner "
 | |
|              "window"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   ContentBlockingNotifier::OnDecision(inner, aDecision, aRejectedReason);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| #ifdef NIGHTLY_BUILD
 | |
| void ContentChild::OnChannelReceivedMessage(const Message& aMsg) {
 | |
|   if (nsContentUtils::IsMessageInputEvent(aMsg)) {
 | |
|     mPendingInputEvents++;
 | |
|   }
 | |
| }
 | |
| 
 | |
| PContentChild::Result ContentChild::OnMessageReceived(const Message& aMsg) {
 | |
|   if (nsContentUtils::IsMessageInputEvent(aMsg)) {
 | |
|     DebugOnly<uint32_t> prevEvts = mPendingInputEvents--;
 | |
|     MOZ_ASSERT(prevEvts > 0);
 | |
|   }
 | |
| 
 | |
|   return PContentChild::OnMessageReceived(aMsg);
 | |
| }
 | |
| 
 | |
| PContentChild::Result ContentChild::OnMessageReceived(
 | |
|     const Message& aMsg, UniquePtr<Message>& aReply) {
 | |
|   return PContentChild::OnMessageReceived(aMsg, aReply);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvCreateBrowsingContext(
 | |
|     uint64_t aGroupId, BrowsingContext::IPCInitializer&& aInit) {
 | |
|   // We can't already have a BrowsingContext with this ID.
 | |
|   if (RefPtr<BrowsingContext> existing = BrowsingContext::Get(aInit.mId)) {
 | |
|     return IPC_FAIL(this, "Browsing context already exists");
 | |
|   }
 | |
| 
 | |
|   RefPtr<WindowContext> parent = WindowContext::GetById(aInit.mParentId);
 | |
|   if (!parent && aInit.mParentId != 0) {
 | |
|     // Handle this case by ignoring the request, as parent must be in the
 | |
|     // process of being discarded.
 | |
|     // In the future it would be nice to avoid sending this message to the child
 | |
|     // at all.
 | |
|     NS_WARNING("Attempt to attach BrowsingContext to discarded parent");
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   RefPtr<BrowsingContextGroup> group =
 | |
|       BrowsingContextGroup::GetOrCreate(aGroupId);
 | |
|   return BrowsingContext::CreateFromIPC(std::move(aInit), group, nullptr);
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvDiscardBrowsingContext(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext, bool aDoDiscard,
 | |
|     DiscardBrowsingContextResolver&& aResolve) {
 | |
|   if (BrowsingContext* context = aContext.GetMaybeDiscarded()) {
 | |
|     if (aDoDiscard && !context->IsDiscarded()) {
 | |
|       context->Detach(/* aFromIPC */ true);
 | |
|     }
 | |
|     context->AddDiscardListener(aResolve);
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   // Immediately resolve the promise, as we've received the message. This will
 | |
|   // allow the parent process to discard references to this BC.
 | |
|   aResolve(true);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvRegisterBrowsingContextGroup(
 | |
|     uint64_t aGroupId, nsTArray<SyncedContextInitializer>&& aInits) {
 | |
|   RefPtr<BrowsingContextGroup> group =
 | |
|       BrowsingContextGroup::GetOrCreate(aGroupId);
 | |
| 
 | |
|   // Each of the initializers in aInits is sorted in pre-order, so our parent
 | |
|   // should always be available before the element itself.
 | |
|   for (auto& initUnion : aInits) {
 | |
|     switch (initUnion.type()) {
 | |
|       case SyncedContextInitializer::TBrowsingContextInitializer: {
 | |
|         auto& init = initUnion.get_BrowsingContextInitializer();
 | |
| #ifdef DEBUG
 | |
|         RefPtr<BrowsingContext> existing = BrowsingContext::Get(init.mId);
 | |
|         MOZ_ASSERT(!existing, "BrowsingContext must not exist yet!");
 | |
| 
 | |
|         RefPtr<WindowContext> parent = init.GetParent();
 | |
|         MOZ_ASSERT_IF(parent, parent->Group() == group);
 | |
| #endif
 | |
| 
 | |
|         BrowsingContext::CreateFromIPC(std::move(init), group, nullptr);
 | |
|         break;
 | |
|       }
 | |
|       case SyncedContextInitializer::TWindowContextInitializer: {
 | |
|         auto& init = initUnion.get_WindowContextInitializer();
 | |
| #ifdef DEBUG
 | |
|         RefPtr<WindowContext> existing =
 | |
|             WindowContext::GetById(init.mInnerWindowId);
 | |
|         MOZ_ASSERT(!existing, "WindowContext must not exist yet!");
 | |
|         RefPtr<BrowsingContext> parent =
 | |
|             BrowsingContext::Get(init.mBrowsingContextId);
 | |
|         MOZ_ASSERT(parent && parent->Group() == group);
 | |
| #endif
 | |
| 
 | |
|         WindowContext::CreateFromIPC(std::move(init));
 | |
|         break;
 | |
|       };
 | |
|       default:
 | |
|         MOZ_ASSERT_UNREACHABLE();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvDestroyBrowsingContextGroup(
 | |
|     uint64_t aGroupId) {
 | |
|   if (RefPtr<BrowsingContextGroup> group =
 | |
|           BrowsingContextGroup::GetExisting(aGroupId)) {
 | |
|     group->ChildDestroy();
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvWindowClose(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext, bool aTrustedCaller) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to dead or detached context"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsPIDOMWindowOuter> window = aContext.get()->GetDOMWindow();
 | |
|   if (!window) {
 | |
|     MOZ_LOG(
 | |
|         BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|         ("ChildIPC: Trying to send a message to a context without a window"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   // Call `GetDocument()` to force the document and its inner window to be
 | |
|   // created, as it would be forced to be created if this call was being
 | |
|   // performed in-process.
 | |
|   if (NS_WARN_IF(!aContext.get()->GetDocument())) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to a context but document "
 | |
|              "creation failed"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsGlobalWindowOuter::Cast(window)->CloseOuter(aTrustedCaller);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvWindowFocus(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType,
 | |
|     uint64_t aActionId) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to dead or detached context"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsPIDOMWindowOuter> window = aContext.get()->GetDOMWindow();
 | |
|   if (!window) {
 | |
|     MOZ_LOG(
 | |
|         BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|         ("ChildIPC: Trying to send a message to a context without a window"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   // Call `GetDocument()` to force the document and its inner window to be
 | |
|   // created, as it would be forced to be created if this call was being
 | |
|   // performed in-process.
 | |
|   if (NS_WARN_IF(!aContext.get()->GetDocument())) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to a context but document "
 | |
|              "creation failed"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsGlobalWindowOuter::Cast(window)->FocusOuter(
 | |
|       aCallerType, /* aFromOtherProcess */ true, aActionId);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvWindowBlur(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to dead or detached context"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsPIDOMWindowOuter> window = aContext.get()->GetDOMWindow();
 | |
|   if (!window) {
 | |
|     MOZ_LOG(
 | |
|         BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|         ("ChildIPC: Trying to send a message to a context without a window"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   // Call `GetDocument()` to force the document and its inner window to be
 | |
|   // created, as it would be forced to be created if this call was being
 | |
|   // performed in-process.
 | |
|   if (NS_WARN_IF(!aContext.get()->GetDocument())) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to a context but document "
 | |
|              "creation failed"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsGlobalWindowOuter::Cast(window)->BlurOuter(aCallerType);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvRaiseWindow(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType,
 | |
|     uint64_t aActionId) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to dead or detached context"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsPIDOMWindowOuter> window = aContext.get()->GetDOMWindow();
 | |
|   if (!window) {
 | |
|     MOZ_LOG(
 | |
|         BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|         ("ChildIPC: Trying to send a message to a context without a window"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
 | |
|     fm->RaiseWindow(window, aCallerType, aActionId);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvAdjustWindowFocus(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext, bool aIsVisible,
 | |
|     uint64_t aActionId) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to dead or detached context"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
 | |
|     RefPtr<BrowsingContext> bc = aContext.get();
 | |
|     fm->AdjustInProcessWindowFocus(bc, false, aIsVisible, aActionId);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvClearFocus(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to dead or detached context"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsPIDOMWindowOuter> window = aContext.get()->GetDOMWindow();
 | |
|   if (!window) {
 | |
|     MOZ_LOG(
 | |
|         BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|         ("ChildIPC: Trying to send a message to a context without a window"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
 | |
|     fm->ClearFocus(window);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvSetFocusedBrowsingContext(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to dead or detached context"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsFocusManager* fm = nsFocusManager::GetFocusManager();
 | |
|   if (fm) {
 | |
|     fm->SetFocusedBrowsingContextFromOtherProcess(aContext.get(), aActionId);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvSetActiveBrowsingContext(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to dead or detached context"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsFocusManager* fm = nsFocusManager::GetFocusManager();
 | |
|   if (fm) {
 | |
|     fm->SetActiveBrowsingContextFromOtherProcess(aContext.get(), aActionId);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvAbortOrientationPendingPromises(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to dead or detached context"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   dom::ScreenOrientation::AbortInProcessOrientationPromises(aContext.get());
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvUnsetActiveBrowsingContext(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to dead or detached context"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsFocusManager* fm = nsFocusManager::GetFocusManager();
 | |
|   if (fm) {
 | |
|     fm->UnsetActiveBrowsingContextFromOtherProcess(aContext.get(), aActionId);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvSetFocusedElement(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext, bool aNeedsFocus) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to dead or detached context"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsPIDOMWindowOuter> window = aContext.get()->GetDOMWindow();
 | |
|   if (!window) {
 | |
|     MOZ_LOG(
 | |
|         BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|         ("ChildIPC: Trying to send a message to a context without a window"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   window->SetFocusedElement(nullptr, 0, aNeedsFocus);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvFinalizeFocusOuter(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext, bool aCanFocus,
 | |
|     CallerType aCallerType) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to dead or detached context"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   if (Element* frame = aContext.get()->GetEmbedderElement()) {
 | |
|     nsContentUtils::RequestFrameFocus(*frame, aCanFocus, aCallerType);
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvBlurToChild(
 | |
|     const MaybeDiscarded<BrowsingContext>& aFocusedBrowsingContext,
 | |
|     const MaybeDiscarded<BrowsingContext>& aBrowsingContextToClear,
 | |
|     const MaybeDiscarded<BrowsingContext>& aAncestorBrowsingContextToFocus,
 | |
|     bool aIsLeavingDocument, bool aAdjustWidget, uint64_t aActionId) {
 | |
|   if (aFocusedBrowsingContext.IsNullOrDiscarded()) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to dead or detached context"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager();
 | |
|   if (MOZ_UNLIKELY(!fm)) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   RefPtr<BrowsingContext> toClear = aBrowsingContextToClear.IsDiscarded()
 | |
|                                         ? nullptr
 | |
|                                         : aBrowsingContextToClear.get();
 | |
|   RefPtr<BrowsingContext> toFocus =
 | |
|       aAncestorBrowsingContextToFocus.IsDiscarded()
 | |
|           ? nullptr
 | |
|           : aAncestorBrowsingContextToFocus.get();
 | |
| 
 | |
|   RefPtr<BrowsingContext> focusedBrowsingContext =
 | |
|       aFocusedBrowsingContext.get();
 | |
| 
 | |
|   fm->BlurFromOtherProcess(focusedBrowsingContext, toClear, toFocus,
 | |
|                            aIsLeavingDocument, aAdjustWidget, aActionId);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvSetupFocusedAndActive(
 | |
|     const MaybeDiscarded<BrowsingContext>& aFocusedBrowsingContext,
 | |
|     uint64_t aActionIdForFocused,
 | |
|     const MaybeDiscarded<BrowsingContext>& aActiveBrowsingContext,
 | |
|     uint64_t aActionIdForActive) {
 | |
|   nsFocusManager* fm = nsFocusManager::GetFocusManager();
 | |
|   if (fm) {
 | |
|     if (!aActiveBrowsingContext.IsNullOrDiscarded()) {
 | |
|       fm->SetActiveBrowsingContextFromOtherProcess(aActiveBrowsingContext.get(),
 | |
|                                                    aActionIdForActive);
 | |
|     }
 | |
|     if (!aFocusedBrowsingContext.IsNullOrDiscarded()) {
 | |
|       fm->SetFocusedBrowsingContextFromOtherProcess(
 | |
|           aFocusedBrowsingContext.get(), aActionIdForFocused);
 | |
|     }
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvReviseActiveBrowsingContext(
 | |
|     uint64_t aOldActionId,
 | |
|     const MaybeDiscarded<BrowsingContext>& aActiveBrowsingContext,
 | |
|     uint64_t aNewActionId) {
 | |
|   nsFocusManager* fm = nsFocusManager::GetFocusManager();
 | |
|   if (fm && !aActiveBrowsingContext.IsNullOrDiscarded()) {
 | |
|     fm->ReviseActiveBrowsingContext(aOldActionId, aActiveBrowsingContext.get(),
 | |
|                                     aNewActionId);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvReviseFocusedBrowsingContext(
 | |
|     uint64_t aOldActionId,
 | |
|     const MaybeDiscarded<BrowsingContext>& aFocusedBrowsingContext,
 | |
|     uint64_t aNewActionId) {
 | |
|   nsFocusManager* fm = nsFocusManager::GetFocusManager();
 | |
|   if (fm && !aFocusedBrowsingContext.IsNullOrDiscarded()) {
 | |
|     fm->ReviseFocusedBrowsingContext(
 | |
|         aOldActionId, aFocusedBrowsingContext.get(), aNewActionId);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvMaybeExitFullscreen(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to dead or detached context"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsIDocShell* shell = aContext.get()->GetDocShell();
 | |
|   if (!shell) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   Document* doc = shell->GetDocument();
 | |
|   if (doc && doc->GetFullscreenElement()) {
 | |
|     Document::AsyncExitFullscreen(doc);
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvWindowPostMessage(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext,
 | |
|     const ClonedOrErrorMessageData& aMessage, const PostMessageData& aData) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to dead or detached context"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   RefPtr<nsGlobalWindowOuter> window =
 | |
|       nsGlobalWindowOuter::Cast(aContext.get()->GetDOMWindow());
 | |
|   if (!window) {
 | |
|     MOZ_LOG(
 | |
|         BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|         ("ChildIPC: Trying to send a message to a context without a window"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIPrincipal> providedPrincipal;
 | |
|   if (!window->GetPrincipalForPostMessage(
 | |
|           aData.targetOrigin(), aData.targetOriginURI(),
 | |
|           aData.callerPrincipal(), *aData.subjectPrincipal(),
 | |
|           getter_AddRefs(providedPrincipal))) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   // Call `GetDocument()` to force the document and its inner window to be
 | |
|   // created, as it would be forced to be created if this call was being
 | |
|   // performed in-process.
 | |
|   if (NS_WARN_IF(!aContext.get()->GetDocument())) {
 | |
|     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | |
|             ("ChildIPC: Trying to send a message to a context but document "
 | |
|              "creation failed"));
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   // It's OK if `sourceBc` has already been discarded, so long as we can
 | |
|   // continue to wrap it.
 | |
|   RefPtr<BrowsingContext> sourceBc = aData.source().GetMaybeDiscarded();
 | |
| 
 | |
|   // Create and asynchronously dispatch a runnable which will handle actual DOM
 | |
|   // event creation and dispatch.
 | |
|   RefPtr<PostMessageEvent> event =
 | |
|       new PostMessageEvent(sourceBc, aData.origin(), window, providedPrincipal,
 | |
|                            aData.innerWindowId(), aData.callerURI(),
 | |
|                            aData.scriptLocation(), aData.isFromPrivateWindow());
 | |
|   event->UnpackFrom(aMessage);
 | |
| 
 | |
|   event->DispatchToTargetThread(IgnoredErrorResult());
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvCommitBrowsingContextTransaction(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext,
 | |
|     BrowsingContext::BaseTransaction&& aTransaction, uint64_t aEpoch) {
 | |
|   return aTransaction.CommitFromIPC(aContext, aEpoch, this);
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvCommitWindowContextTransaction(
 | |
|     const MaybeDiscarded<WindowContext>& aContext,
 | |
|     WindowContext::BaseTransaction&& aTransaction, uint64_t aEpoch) {
 | |
|   return aTransaction.CommitFromIPC(aContext, aEpoch, this);
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvCreateWindowContext(
 | |
|     WindowContext::IPCInitializer&& aInit) {
 | |
|   RefPtr<BrowsingContext> bc = BrowsingContext::Get(aInit.mBrowsingContextId);
 | |
|   if (!bc) {
 | |
|     // Handle this case by ignoring the request, as bc must be in the process of
 | |
|     // being discarded.
 | |
|     // In the future it would be nice to avoid sending this message to the child
 | |
|     // at all.
 | |
|     NS_WARNING("Attempt to attach WindowContext to discarded parent");
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   WindowContext::CreateFromIPC(std::move(aInit));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvDiscardWindowContext(
 | |
|     uint64_t aContextId, DiscardWindowContextResolver&& aResolve) {
 | |
|   // Resolve immediately to acknowledge call
 | |
|   aResolve(true);
 | |
| 
 | |
|   RefPtr<WindowContext> window = WindowContext::GetById(aContextId);
 | |
|   if (NS_WARN_IF(!window) || NS_WARN_IF(window->IsDiscarded())) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   window->Discard();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvScriptError(
 | |
|     const nsString& aMessage, const nsString& aSourceName,
 | |
|     const nsString& aSourceLine, const uint32_t& aLineNumber,
 | |
|     const uint32_t& aColNumber, const uint32_t& aFlags,
 | |
|     const nsCString& aCategory, const bool& aFromPrivateWindow,
 | |
|     const uint64_t& aInnerWindowId, const bool& aFromChromeContext) {
 | |
|   nsresult rv = NS_OK;
 | |
|   nsCOMPtr<nsIConsoleService> consoleService =
 | |
|       do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
 | |
|   NS_ENSURE_SUCCESS(rv, IPC_FAIL(this, "Failed to get console service"));
 | |
| 
 | |
|   nsCOMPtr<nsIScriptError> scriptError(
 | |
|       do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
 | |
|   NS_ENSURE_TRUE(scriptError,
 | |
|                  IPC_FAIL(this, "Failed to construct nsIScriptError"));
 | |
| 
 | |
|   scriptError->InitWithWindowID(aMessage, aSourceName, aSourceLine, aLineNumber,
 | |
|                                 aColNumber, aFlags, aCategory, aInnerWindowId,
 | |
|                                 aFromChromeContext);
 | |
|   rv = consoleService->LogMessage(scriptError);
 | |
|   NS_ENSURE_SUCCESS(rv, IPC_FAIL(this, "Failed to log script error"));
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvReportFrameTimingData(
 | |
|     const LoadInfoArgs& loadInfoArgs, const nsString& entryName,
 | |
|     const nsString& initiatorType, UniquePtr<PerformanceTimingData>&& aData) {
 | |
|   if (!aData) {
 | |
|     return IPC_FAIL(this, "aData should not be null");
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsILoadInfo> loadInfo;
 | |
|   nsresult rv = mozilla::ipc::LoadInfoArgsToLoadInfo(
 | |
|       loadInfoArgs, NOT_REMOTE_TYPE, getter_AddRefs(loadInfo));
 | |
|   if (NS_FAILED(rv)) {
 | |
|     MOZ_DIAGNOSTIC_ASSERT(false, "LoadInfoArgsToLoadInfo failed");
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   // It is important to call LoadInfo::GetPerformanceStorage instead of simply
 | |
|   // getting the performance object via the innerWindowID in order to perform
 | |
|   // necessary cross origin checks.
 | |
|   if (PerformanceStorage* storage = loadInfo->GetPerformanceStorage()) {
 | |
|     storage->AddEntry(entryName, initiatorType, std::move(aData));
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvLoadURI(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext,
 | |
|     nsDocShellLoadState* aLoadState, bool aSetNavigating,
 | |
|     LoadURIResolver&& aResolve) {
 | |
|   auto resolveOnExit = MakeScopeExit([&] { aResolve(true); });
 | |
| 
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
|   RefPtr<BrowsingContext> context = aContext.get();
 | |
|   if (!context->IsInProcess()) {
 | |
|     // The DocShell has been torn down or the BrowsingContext has changed
 | |
|     // process in the middle of the load request. There's not much we can do at
 | |
|     // this point, so just give up.
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   context->LoadURI(aLoadState, aSetNavigating);
 | |
| 
 | |
|   nsCOMPtr<nsPIDOMWindowOuter> window = context->GetDOMWindow();
 | |
|   BrowserChild* bc = BrowserChild::GetFrom(window);
 | |
|   if (bc) {
 | |
|     bc->NotifyNavigationFinished();
 | |
|   }
 | |
| 
 | |
| #ifdef MOZ_CRASHREPORTER
 | |
|   if (CrashReporter::GetEnabled()) {
 | |
|     nsCOMPtr<nsIURI> annotationURI;
 | |
| 
 | |
|     nsresult rv = NS_MutateURI(aLoadState->URI())
 | |
|                       .SetUserPass(""_ns)
 | |
|                       .Finalize(annotationURI);
 | |
| 
 | |
|     if (NS_FAILED(rv)) {
 | |
|       // Ignore failures on about: URIs.
 | |
|       annotationURI = aLoadState->URI();
 | |
|     }
 | |
| 
 | |
|     CrashReporter::RecordAnnotationNSCString(CrashReporter::Annotation::URL,
 | |
|                                              annotationURI->GetSpecOrDefault());
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvInternalLoad(
 | |
|     nsDocShellLoadState* aLoadState) {
 | |
|   if (!aLoadState->Target().IsEmpty() ||
 | |
|       aLoadState->TargetBrowsingContext().IsNull()) {
 | |
|     return IPC_FAIL(this, "must already be retargeted");
 | |
|   }
 | |
|   if (aLoadState->TargetBrowsingContext().IsDiscarded()) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
|   RefPtr<BrowsingContext> context = aLoadState->TargetBrowsingContext().get();
 | |
| 
 | |
|   context->InternalLoad(aLoadState);
 | |
| 
 | |
| #ifdef MOZ_CRASHREPORTER
 | |
|   if (CrashReporter::GetEnabled()) {
 | |
|     nsCOMPtr<nsIURI> annotationURI;
 | |
| 
 | |
|     nsresult rv = NS_MutateURI(aLoadState->URI())
 | |
|                       .SetUserPass(""_ns)
 | |
|                       .Finalize(annotationURI);
 | |
| 
 | |
|     if (NS_FAILED(rv)) {
 | |
|       // Ignore failures on about: URIs.
 | |
|       annotationURI = aLoadState->URI();
 | |
|     }
 | |
| 
 | |
|     CrashReporter::RecordAnnotationNSCString(CrashReporter::Annotation::URL,
 | |
|                                              annotationURI->GetSpecOrDefault());
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvDisplayLoadError(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext, const nsAString& aURI) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
|   RefPtr<BrowsingContext> context = aContext.get();
 | |
| 
 | |
|   context->DisplayLoadError(aURI);
 | |
| 
 | |
|   nsCOMPtr<nsPIDOMWindowOuter> window = context->GetDOMWindow();
 | |
|   BrowserChild* bc = BrowserChild::GetFrom(window);
 | |
|   if (bc) {
 | |
|     bc->NotifyNavigationFinished();
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvHistoryCommitIndexAndLength(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext, const uint32_t& aIndex,
 | |
|     const uint32_t& aLength, const nsID& aChangeID) {
 | |
|   if (!aContext.IsNullOrDiscarded()) {
 | |
|     ChildSHistory* shistory = aContext.get()->GetChildSessionHistory();
 | |
|     if (shistory) {
 | |
|       shistory->SetIndexAndLength(aIndex, aLength, aChangeID);
 | |
|     }
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvGetLayoutHistoryState(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext,
 | |
|     GetLayoutHistoryStateResolver&& aResolver) {
 | |
|   nsCOMPtr<nsILayoutHistoryState> state;
 | |
|   nsIDocShell* docShell;
 | |
|   mozilla::Maybe<mozilla::dom::Wireframe> wireframe;
 | |
|   if (!aContext.IsNullOrDiscarded() &&
 | |
|       (docShell = aContext.get()->GetDocShell())) {
 | |
|     docShell->PersistLayoutHistoryState();
 | |
|     docShell->GetLayoutHistoryState(getter_AddRefs(state));
 | |
|     wireframe = static_cast<nsDocShell*>(docShell)->GetWireframe();
 | |
|   }
 | |
|   aResolver(
 | |
|       std::tuple<nsILayoutHistoryState*, const mozilla::Maybe<Wireframe>&>(
 | |
|           state, wireframe));
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvDispatchLocationChangeEvent(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext) {
 | |
|   if (!aContext.IsNullOrDiscarded() && aContext.get()->GetDocShell()) {
 | |
|     aContext.get()->GetDocShell()->DispatchLocationChangeEvent();
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvDispatchBeforeUnloadToSubtree(
 | |
|     const MaybeDiscarded<BrowsingContext>& aStartingAt,
 | |
|     DispatchBeforeUnloadToSubtreeResolver&& aResolver) {
 | |
|   if (aStartingAt.IsNullOrDiscarded()) {
 | |
|     aResolver(nsIDocumentViewer::eAllowNavigation);
 | |
|   } else {
 | |
|     DispatchBeforeUnloadToSubtree(aStartingAt.get(), std::move(aResolver));
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvDecoderSupportedMimeTypes(
 | |
|     nsTArray<nsCString>&& aSupportedTypes) {
 | |
| #ifdef MOZ_WIDGET_ANDROID
 | |
|   AndroidDecoderModule::SetSupportedMimeTypes(std::move(aSupportedTypes));
 | |
| #endif
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvInitNextGenLocalStorageEnabled(
 | |
|     const bool& aEnabled) {
 | |
|   mozilla::dom::RecvInitNextGenLocalStorageEnabled(aEnabled);
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| /* static */ void ContentChild::DispatchBeforeUnloadToSubtree(
 | |
|     BrowsingContext* aStartingAt,
 | |
|     const DispatchBeforeUnloadToSubtreeResolver& aResolver) {
 | |
|   bool resolved = false;
 | |
| 
 | |
|   aStartingAt->PreOrderWalk([&](dom::BrowsingContext* aBC) {
 | |
|     if (aBC->GetDocShell()) {
 | |
|       nsCOMPtr<nsIDocumentViewer> viewer;
 | |
|       aBC->GetDocShell()->GetDocViewer(getter_AddRefs(viewer));
 | |
|       if (viewer &&
 | |
|           viewer->DispatchBeforeUnload() ==
 | |
|               nsIDocumentViewer::eRequestBlockNavigation &&
 | |
|           !resolved) {
 | |
|         // Send our response as soon as we find any blocker, so that we can show
 | |
|         // the permit unload prompt as soon as possible, without giving
 | |
|         // subsequent handlers a chance to delay it.
 | |
|         aResolver(nsIDocumentViewer::eRequestBlockNavigation);
 | |
|         resolved = true;
 | |
|       }
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   if (!resolved) {
 | |
|     aResolver(nsIDocumentViewer::eAllowNavigation);
 | |
|   }
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvGoBack(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext,
 | |
|     const Maybe<int32_t>& aCancelContentJSEpoch, bool aRequireUserInteraction,
 | |
|     bool aUserActivation) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
|   BrowsingContext* bc = aContext.get();
 | |
| 
 | |
|   if (RefPtr<nsDocShell> docShell = nsDocShell::Cast(bc->GetDocShell())) {
 | |
|     if (aCancelContentJSEpoch) {
 | |
|       docShell->SetCancelContentJSEpoch(*aCancelContentJSEpoch);
 | |
|     }
 | |
|     docShell->GoBack(aRequireUserInteraction, aUserActivation);
 | |
| 
 | |
|     if (BrowserChild* browserChild = BrowserChild::GetFrom(docShell)) {
 | |
|       browserChild->NotifyNavigationFinished();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvGoForward(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext,
 | |
|     const Maybe<int32_t>& aCancelContentJSEpoch, bool aRequireUserInteraction,
 | |
|     bool aUserActivation) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
|   BrowsingContext* bc = aContext.get();
 | |
| 
 | |
|   if (RefPtr<nsDocShell> docShell = nsDocShell::Cast(bc->GetDocShell())) {
 | |
|     if (aCancelContentJSEpoch) {
 | |
|       docShell->SetCancelContentJSEpoch(*aCancelContentJSEpoch);
 | |
|     }
 | |
|     docShell->GoForward(aRequireUserInteraction, aUserActivation);
 | |
| 
 | |
|     if (BrowserChild* browserChild = BrowserChild::GetFrom(docShell)) {
 | |
|       browserChild->NotifyNavigationFinished();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvGoToIndex(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext, const int32_t& aIndex,
 | |
|     const Maybe<int32_t>& aCancelContentJSEpoch, bool aUserActivation) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
|   BrowsingContext* bc = aContext.get();
 | |
| 
 | |
|   if (RefPtr<nsDocShell> docShell = nsDocShell::Cast(bc->GetDocShell())) {
 | |
|     if (aCancelContentJSEpoch) {
 | |
|       docShell->SetCancelContentJSEpoch(*aCancelContentJSEpoch);
 | |
|     }
 | |
|     docShell->GotoIndex(aIndex, aUserActivation);
 | |
| 
 | |
|     if (BrowserChild* browserChild = BrowserChild::GetFrom(docShell)) {
 | |
|       browserChild->NotifyNavigationFinished();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvReload(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext,
 | |
|     const uint32_t aReloadFlags) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
|   BrowsingContext* bc = aContext.get();
 | |
| 
 | |
|   if (RefPtr<nsDocShell> docShell = nsDocShell::Cast(bc->GetDocShell())) {
 | |
|     docShell->Reload(aReloadFlags);
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult ContentChild::RecvStopLoad(
 | |
|     const MaybeDiscarded<BrowsingContext>& aContext,
 | |
|     const uint32_t aStopFlags) {
 | |
|   if (aContext.IsNullOrDiscarded()) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
|   BrowsingContext* bc = aContext.get();
 | |
| 
 | |
|   if (auto* docShell = nsDocShell::Cast(bc->GetDocShell())) {
 | |
|     docShell->Stop(aStopFlags);
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
 | |
| mozilla::ipc::IPCResult ContentChild::RecvInitSandboxTesting(
 | |
|     Endpoint<PSandboxTestingChild>&& aEndpoint) {
 | |
|   if (!SandboxTestingChild::Initialize(std::move(aEndpoint))) {
 | |
|     return IPC_FAIL(
 | |
|         this, "InitSandboxTesting failed to initialise the child process.");
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| #endif
 | |
| 
 | |
| NS_IMETHODIMP ContentChild::GetChildID(uint64_t* aOut) {
 | |
|   *aOut = mID;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP ContentChild::GetActor(const nsACString& aName, JSContext* aCx,
 | |
|                                      JSProcessActorChild** retval) {
 | |
|   ErrorResult error;
 | |
|   RefPtr<JSProcessActorChild> actor =
 | |
|       JSActorManager::GetActor(aCx, aName, error)
 | |
|           .downcast<JSProcessActorChild>();
 | |
|   if (error.MaybeSetPendingException(aCx)) {
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
|   actor.forget(retval);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP ContentChild::GetExistingActor(const nsACString& aName,
 | |
|                                              JSProcessActorChild** retval) {
 | |
|   RefPtr<JSProcessActorChild> actor =
 | |
|       JSActorManager::GetExistingActor(aName).downcast<JSProcessActorChild>();
 | |
|   actor.forget(retval);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| already_AddRefed<JSActor> ContentChild::InitJSActor(
 | |
|     JS::Handle<JSObject*> aMaybeActor, const nsACString& aName,
 | |
|     ErrorResult& aRv) {
 | |
|   RefPtr<JSProcessActorChild> actor;
 | |
|   if (aMaybeActor.get()) {
 | |
|     aRv = UNWRAP_OBJECT(JSProcessActorChild, aMaybeActor.get(), actor);
 | |
|     if (aRv.Failed()) {
 | |
|       return nullptr;
 | |
|     }
 | |
|   } else {
 | |
|     actor = new JSProcessActorChild();
 | |
|   }
 | |
| 
 | |
|   MOZ_RELEASE_ASSERT(!actor->Manager(),
 | |
|                      "mManager was already initialized once!");
 | |
|   actor->Init(aName, this);
 | |
|   return actor.forget();
 | |
| }
 | |
| 
 | |
| IPCResult ContentChild::RecvRawMessage(const JSActorMessageMeta& aMeta,
 | |
|                                        const Maybe<ClonedMessageData>& aData,
 | |
|                                        const Maybe<ClonedMessageData>& aStack) {
 | |
|   Maybe<StructuredCloneData> data;
 | |
|   if (aData) {
 | |
|     data.emplace();
 | |
|     data->BorrowFromClonedMessageData(*aData);
 | |
|   }
 | |
|   Maybe<StructuredCloneData> stack;
 | |
|   if (aStack) {
 | |
|     stack.emplace();
 | |
|     stack->BorrowFromClonedMessageData(*aStack);
 | |
|   }
 | |
|   ReceiveRawMessage(aMeta, std::move(data), std::move(stack));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP ContentChild::GetCanSend(bool* aCanSend) {
 | |
|   *aCanSend = CanSend();
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| ContentChild* ContentChild::AsContentChild() { return this; }
 | |
| 
 | |
| JSActorManager* ContentChild::AsJSActorManager() { return this; }
 | |
| 
 | |
| IPCResult ContentChild::RecvFlushFOGData(FlushFOGDataResolver&& aResolver) {
 | |
|   glean::FlushFOGData(std::move(aResolver));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| IPCResult ContentChild::RecvUpdateMediaCodecsSupported(
 | |
|     RemoteDecodeIn aLocation, const media::MediaCodecsSupported& aSupported) {
 | |
|   RemoteDecoderManagerChild::SetSupported(aLocation, aSupported);
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| void ContentChild::ConfigureThreadPerformanceHints(
 | |
|     const hal::ProcessPriority& aPriority) {
 | |
|   if (aPriority >= hal::PROCESS_PRIORITY_FOREGROUND) {
 | |
|     static bool canUsePerformanceHintSession = true;
 | |
|     if (!mPerformanceHintSession && canUsePerformanceHintSession) {
 | |
|       nsTArray<PlatformThreadHandle> threads;
 | |
|       Servo_ThreadPool_GetThreadHandles(&threads);
 | |
| #ifdef XP_WIN
 | |
|       threads.AppendElement(GetCurrentThread());
 | |
| #else
 | |
|       threads.AppendElement(pthread_self());
 | |
| #endif
 | |
| 
 | |
|       mPerformanceHintSession = hal::CreatePerformanceHintSession(
 | |
|           threads, GetPerformanceHintTarget(TimeDuration::FromMilliseconds(
 | |
|                        nsRefreshDriver::DefaultInterval())));
 | |
| 
 | |
|       // Avoid repeatedly attempting to create a session if it is not
 | |
|       // supported.
 | |
|       canUsePerformanceHintSession = mPerformanceHintSession != nullptr;
 | |
|     }
 | |
| 
 | |
| #ifdef MOZ_WIDGET_ANDROID
 | |
|     // On Android if we are unable to use PerformanceHintManager then fall back
 | |
|     // to setting the stylo threads' affinities to the performant cores. Android
 | |
|     // automatically sets each thread's affinity to all cores when a process is
 | |
|     // foregrounded, and to a subset of cores when the process is backgrounded.
 | |
|     // We must therefore override this each time the process is foregrounded,
 | |
|     // but we don't have to do anything when backgrounded.
 | |
|     if (!mPerformanceHintSession) {
 | |
|       if (const auto& cpuInfo = hal::GetHeterogeneousCpuInfo()) {
 | |
|         // If CPUs are homogeneous there is no point setting affinity.
 | |
|         if (cpuInfo->mBigCpus.Count() != cpuInfo->mTotalNumCpus) {
 | |
|           BitSet<hal::HeterogeneousCpuInfo::MAX_CPUS> cpus = cpuInfo->mBigCpus;
 | |
|           if (cpus.Count() < 2) {
 | |
|             // From testing on a variety of devices it appears using only the
 | |
|             // big cores gives best performance when there are 2 or more big
 | |
|             // cores. If there are fewer than 2 big cores then additionally
 | |
|             // using the medium cores performs better.
 | |
|             cpus |= cpuInfo->mMediumCpus;
 | |
|           }
 | |
| 
 | |
|           static_assert(
 | |
|               hal::HeterogeneousCpuInfo::MAX_CPUS <= CPU_SETSIZE,
 | |
|               "HeterogeneousCpuInfo::MAX_CPUS is too large for CPU_SETSIZE");
 | |
| 
 | |
|           cpu_set_t cpuset;
 | |
|           CPU_ZERO(&cpuset);
 | |
|           for (size_t i = 0; i < cpuInfo->mTotalNumCpus; i++) {
 | |
|             if (cpus.Test(i)) {
 | |
|               CPU_SET(i, &cpuset);
 | |
|             }
 | |
|           }
 | |
| 
 | |
|           // Only set the affinity for the stylo threads, not the main thread.
 | |
|           // Testing showed no difference in performance between the two
 | |
|           // options, and as newly spawned threads automatically inherit their
 | |
|           // parent's affinity mask there may be unintended consequences to
 | |
|           // setting the main thread affinity.
 | |
|           nsTArray<PlatformThreadHandle> threads;
 | |
|           Servo_ThreadPool_GetThreadHandles(&threads);
 | |
|           for (pthread_t thread : threads) {
 | |
|             int ret = sched_setaffinity(pthread_gettid_np(thread),
 | |
|                                         sizeof(cpu_set_t), &cpuset);
 | |
|             // Occasionally sched_setaffinity fails, presumably due to a race
 | |
|             // between us receiving the process foreground signal and whatever
 | |
|             // is responsible for restricting which processes can use certain
 | |
|             // cores. Trying again in a runnable seems to do the trick, but if
 | |
|             // that still fails it's not the end of the world.
 | |
|             if (ret < 0) {
 | |
|               NS_DispatchToCurrentThread(NS_NewRunnableFunction(
 | |
|                   "ContentChild::ConfigureThreadPerformanceHints",
 | |
|                   [threads = std::move(threads), cpuset] {
 | |
|                     for (pthread_t thread : threads) {
 | |
|                       sched_setaffinity(pthread_gettid_np(thread),
 | |
|                                         sizeof(cpu_set_t), &cpuset);
 | |
|                     }
 | |
|                   }));
 | |
|               break;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| #endif
 | |
|   } else {
 | |
|     mPerformanceHintSession = nullptr;
 | |
|   }
 | |
| }
 | |
| 
 | |
| }  // namespace dom
 | |
| 
 | |
| #if defined(__OpenBSD__) && defined(MOZ_SANDBOX)
 | |
| 
 | |
| static LazyLogModule sPledgeLog("OpenBSDSandbox");
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| OpenBSDFindPledgeUnveilFilePath(const char* file, nsACString& result) {
 | |
|   struct stat st;
 | |
| 
 | |
|   // Allow overriding files in /etc/$MOZ_APP_NAME
 | |
|   result.Assign(nsPrintfCString("/etc/%s/%s", MOZ_APP_NAME, file));
 | |
|   if (stat(PromiseFlatCString(result).get(), &st) == 0) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   // Or look in the system default directory
 | |
|   result.Assign(nsPrintfCString(
 | |
|       "/usr/local/lib/%s/browser/defaults/preferences/%s", MOZ_APP_NAME, file));
 | |
|   if (stat(PromiseFlatCString(result).get(), &st) == 0) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   errx(1, "can't locate %s", file);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| OpenBSDPledgePromises(const nsACString& aPath) {
 | |
|   // Using NS_LOCAL_FILE_CONTRACTID/NS_LOCALFILEINPUTSTREAM_CONTRACTID requires
 | |
|   // a lot of setup before they are supported and we want to pledge early on
 | |
|   // before all of that, so read the file directly
 | |
|   std::ifstream input(PromiseFlatCString(aPath).get());
 | |
| 
 | |
|   // Build up one line of pledge promises without comments
 | |
|   nsAutoCString promises;
 | |
|   bool disabled = false;
 | |
|   int linenum = 0;
 | |
|   for (std::string tLine; std::getline(input, tLine);) {
 | |
|     nsAutoCString line(tLine.c_str());
 | |
|     linenum++;
 | |
| 
 | |
|     // Cut off any comments at the end of the line, also catches lines
 | |
|     // that are entirely a comment
 | |
|     int32_t hash = line.FindChar('#');
 | |
|     if (hash >= 0) {
 | |
|       line = Substring(line, 0, hash);
 | |
|     }
 | |
|     line.CompressWhitespace(true, true);
 | |
|     if (line.IsEmpty()) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (linenum == 1 && line.EqualsLiteral("disable")) {
 | |
|       disabled = true;
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if (!promises.IsEmpty()) {
 | |
|       promises.Append(" ");
 | |
|     }
 | |
|     promises.Append(line);
 | |
|   }
 | |
|   input.close();
 | |
| 
 | |
|   if (disabled) {
 | |
|     warnx("%s: disabled", PromiseFlatCString(aPath).get());
 | |
|   } else {
 | |
|     MOZ_LOG(
 | |
|         sPledgeLog, LogLevel::Debug,
 | |
|         ("%s: pledge(%s)\n", PromiseFlatCString(aPath).get(), promises.get()));
 | |
|     if (pledge(promises.get(), nullptr) != 0) {
 | |
|       err(1, "%s: pledge(%s) failed", PromiseFlatCString(aPath).get(),
 | |
|           promises.get());
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| void ExpandUnveilPath(nsAutoCString& path) {
 | |
|   // Expand $XDG_RUNTIME_DIR to the environment variable, or ~/.cache
 | |
|   nsCString xdgRuntimeDir(PR_GetEnv("XDG_RUNTIME_DIR"));
 | |
|   if (xdgRuntimeDir.IsEmpty()) {
 | |
|     xdgRuntimeDir = "~/.cache";
 | |
|   }
 | |
|   path.ReplaceSubstring("$XDG_RUNTIME_DIR", xdgRuntimeDir.get());
 | |
| 
 | |
|   // Expand $XDG_CONFIG_HOME to the environment variable, or ~/.config
 | |
|   nsCString xdgConfigHome(PR_GetEnv("XDG_CONFIG_HOME"));
 | |
|   if (xdgConfigHome.IsEmpty()) {
 | |
|     xdgConfigHome = "~/.config";
 | |
|   }
 | |
|   path.ReplaceSubstring("$XDG_CONFIG_HOME", xdgConfigHome.get());
 | |
| 
 | |
|   // Expand $XDG_CACHE_HOME to the environment variable, or ~/.cache
 | |
|   nsCString xdgCacheHome(PR_GetEnv("XDG_CACHE_HOME"));
 | |
|   if (xdgCacheHome.IsEmpty()) {
 | |
|     xdgCacheHome = "~/.cache";
 | |
|   }
 | |
|   path.ReplaceSubstring("$XDG_CACHE_HOME", xdgCacheHome.get());
 | |
| 
 | |
|   // Expand $XDG_DATA_HOME to the environment variable, or ~/.local/share
 | |
|   nsCString xdgDataHome(PR_GetEnv("XDG_DATA_HOME"));
 | |
|   if (xdgDataHome.IsEmpty()) {
 | |
|     xdgDataHome = "~/.local/share";
 | |
|   }
 | |
|   path.ReplaceSubstring("$XDG_DATA_HOME", xdgDataHome.get());
 | |
| 
 | |
|   // Expand leading ~ to the user's home directory
 | |
|   nsCOMPtr<nsIFile> homeDir;
 | |
|   nsresult rv =
 | |
|       GetSpecialSystemDirectory(Unix_HomeDirectory, getter_AddRefs(homeDir));
 | |
|   if (NS_FAILED(rv)) {
 | |
|     errx(1, "failed getting home directory");
 | |
|   }
 | |
|   if (path.FindChar('~') == 0) {
 | |
|     nsCString tHome(homeDir->NativePath());
 | |
|     tHome.Append(Substring(path, 1, path.Length() - 1));
 | |
|     path = tHome.get();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void MkdirP(nsAutoCString& path) {
 | |
|   // nsLocalFile::CreateAllAncestors would be nice to use
 | |
| 
 | |
|   nsAutoCString tPath("");
 | |
|   for (const nsACString& dir : path.Split('/')) {
 | |
|     struct stat st;
 | |
| 
 | |
|     if (dir.IsEmpty()) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     tPath.Append("/");
 | |
|     tPath.Append(dir);
 | |
| 
 | |
|     if (stat(tPath.get(), &st) == -1) {
 | |
|       if (mkdir(tPath.get(), 0700) == -1) {
 | |
|         err(1, "failed mkdir(%s) while MkdirP(%s)",
 | |
|             PromiseFlatCString(tPath).get(), PromiseFlatCString(path).get());
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| OpenBSDUnveilPaths(const nsACString& uPath, const nsACString& pledgePath) {
 | |
|   // Using NS_LOCAL_FILE_CONTRACTID/NS_LOCALFILEINPUTSTREAM_CONTRACTID requires
 | |
|   // a lot of setup before they are allowed/supported and we want to pledge and
 | |
|   // unveil early on before all of that is setup
 | |
|   std::ifstream input(PromiseFlatCString(uPath).get());
 | |
| 
 | |
|   bool disabled = false;
 | |
|   int linenum = 0;
 | |
|   for (std::string tLine; std::getline(input, tLine);) {
 | |
|     nsAutoCString line(tLine.c_str());
 | |
|     linenum++;
 | |
| 
 | |
|     // Cut off any comments at the end of the line, also catches lines
 | |
|     // that are entirely a comment
 | |
|     int32_t hash = line.FindChar('#');
 | |
|     if (hash >= 0) {
 | |
|       line = Substring(line, 0, hash);
 | |
|     }
 | |
|     line.CompressWhitespace(true, true);
 | |
|     if (line.IsEmpty()) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (linenum == 1 && line.EqualsLiteral("disable")) {
 | |
|       disabled = true;
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     int32_t space = line.FindChar(' ');
 | |
|     if (space <= 0) {
 | |
|       errx(1, "%s: line %d: invalid format", PromiseFlatCString(uPath).get(),
 | |
|            linenum);
 | |
|     }
 | |
| 
 | |
|     nsAutoCString uPath(Substring(line, 0, space));
 | |
|     ExpandUnveilPath(uPath);
 | |
| 
 | |
|     nsAutoCString perms(Substring(line, space + 1, line.Length() - space - 1));
 | |
| 
 | |
|     MOZ_LOG(sPledgeLog, LogLevel::Debug,
 | |
|             ("%s: unveil(%s, %s)\n", PromiseFlatCString(uPath).get(),
 | |
|              uPath.get(), perms.get()));
 | |
|     if (unveil(uPath.get(), perms.get()) == -1 && errno != ENOENT) {
 | |
|       err(1, "%s: unveil(%s, %s) failed", PromiseFlatCString(uPath).get(),
 | |
|           uPath.get(), perms.get());
 | |
|     }
 | |
|   }
 | |
|   input.close();
 | |
| 
 | |
|   if (disabled) {
 | |
|     warnx("%s: disabled", PromiseFlatCString(uPath).get());
 | |
|   } else {
 | |
|     struct stat st;
 | |
| 
 | |
|     // Only unveil the pledgePath file if it's not already unveiled, otherwise
 | |
|     // some containing directory will lose visibility.
 | |
|     if (stat(PromiseFlatCString(pledgePath).get(), &st) == -1) {
 | |
|       if (errno == ENOENT) {
 | |
|         if (unveil(PromiseFlatCString(pledgePath).get(), "r") == -1) {
 | |
|           err(1, "unveil(%s, r) failed", PromiseFlatCString(pledgePath).get());
 | |
|         }
 | |
|       } else {
 | |
|         err(1, "stat(%s)", PromiseFlatCString(pledgePath).get());
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| bool StartOpenBSDSandbox(GeckoProcessType type, ipc::SandboxingKind kind) {
 | |
|   nsAutoCString pledgeFile;
 | |
|   nsAutoCString unveilFile;
 | |
|   char binaryPath[MAXPATHLEN];
 | |
| 
 | |
|   switch (type) {
 | |
|     case GeckoProcessType_Default: {
 | |
|       OpenBSDFindPledgeUnveilFilePath("pledge.main", pledgeFile);
 | |
|       OpenBSDFindPledgeUnveilFilePath("unveil.main", unveilFile);
 | |
| 
 | |
|       // Ensure dconf dir exists before we veil the filesystem
 | |
|       nsAutoCString dConf("$XDG_RUNTIME_DIR/dconf");
 | |
|       ExpandUnveilPath(dConf);
 | |
|       MkdirP(dConf);
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     case GeckoProcessType_Content:
 | |
|       OpenBSDFindPledgeUnveilFilePath("pledge.content", pledgeFile);
 | |
|       OpenBSDFindPledgeUnveilFilePath("unveil.content", unveilFile);
 | |
|       break;
 | |
| 
 | |
|     case GeckoProcessType_GPU:
 | |
|       OpenBSDFindPledgeUnveilFilePath("pledge.gpu", pledgeFile);
 | |
|       OpenBSDFindPledgeUnveilFilePath("unveil.gpu", unveilFile);
 | |
|       break;
 | |
| 
 | |
|     case GeckoProcessType_Socket:
 | |
|       OpenBSDFindPledgeUnveilFilePath("pledge.socket", pledgeFile);
 | |
|       OpenBSDFindPledgeUnveilFilePath("unveil.socket", unveilFile);
 | |
|       break;
 | |
| 
 | |
|     case GeckoProcessType_RDD:
 | |
|       OpenBSDFindPledgeUnveilFilePath("pledge.rdd", pledgeFile);
 | |
|       OpenBSDFindPledgeUnveilFilePath("unveil.rdd", unveilFile);
 | |
|       break;
 | |
| 
 | |
|     case GeckoProcessType_Utility: {
 | |
|       MOZ_RELEASE_ASSERT(kind <= SandboxingKind::COUNT,
 | |
|                          "Should define a sandbox");
 | |
|       switch (kind) {
 | |
|         case ipc::SandboxingKind::GENERIC_UTILITY:
 | |
|         default:
 | |
|           OpenBSDFindPledgeUnveilFilePath("pledge.utility", pledgeFile);
 | |
|           OpenBSDFindPledgeUnveilFilePath("unveil.utility", unveilFile);
 | |
|           break;
 | |
|       }
 | |
|     } break;
 | |
| 
 | |
|     default:
 | |
|       MOZ_ASSERT(false, "unknown process type");
 | |
|       return false;
 | |
|   }
 | |
| 
 | |
|   nsresult rv = mozilla::BinaryPath::Get(binaryPath);
 | |
|   if (NS_FAILED(rv)) {
 | |
|     errx(1, "failed to cache binary path ?");
 | |
|   }
 | |
| 
 | |
|   if (NS_WARN_IF(NS_FAILED(OpenBSDUnveilPaths(unveilFile, pledgeFile)))) {
 | |
|     errx(1, "failed reading/parsing %s", unveilFile.get());
 | |
|   }
 | |
| 
 | |
|   if (NS_WARN_IF(NS_FAILED(OpenBSDPledgePromises(pledgeFile)))) {
 | |
|     errx(1, "failed reading/parsing %s", pledgeFile.get());
 | |
|   }
 | |
| 
 | |
|   // Don't overwrite an existing session dbus address, but ensure it is set
 | |
|   if (!PR_GetEnv("DBUS_SESSION_BUS_ADDRESS")) {
 | |
|     PR_SetEnv("DBUS_SESSION_BUS_ADDRESS=");
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| }  // namespace mozilla
 | |
| 
 | |
| /* static */
 | |
| nsIDOMProcessChild* nsIDOMProcessChild::GetSingleton() {
 | |
|   if (XRE_IsContentProcess()) {
 | |
|     return mozilla::dom::ContentChild::GetSingleton();
 | |
|   }
 | |
|   return mozilla::dom::InProcessChild::Singleton();
 | |
| }
 | 
