mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 10:18:41 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			8283 lines
		
	
	
	
		
			282 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			8283 lines
		
	
	
	
		
			282 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/. */
 | 
						|
 | 
						|
#include "mozilla/AppShutdown.h"
 | 
						|
#include "mozilla/DebugOnly.h"
 | 
						|
 | 
						|
#include "base/basictypes.h"
 | 
						|
#include "base/shared_memory.h"
 | 
						|
 | 
						|
#include "ContentParent.h"
 | 
						|
#include "mozilla/ipc/ProcessUtils.h"
 | 
						|
#include "mozilla/CmdLineAndEnvUtils.h"
 | 
						|
#include "BrowserParent.h"
 | 
						|
 | 
						|
#include "chrome/common/process_watcher.h"
 | 
						|
#include "mozilla/Result.h"
 | 
						|
#include "mozilla/Services.h"
 | 
						|
#include "mozilla/XREAppData.h"
 | 
						|
#include "nsComponentManagerUtils.h"
 | 
						|
#include "nsIBrowserDOMWindow.h"
 | 
						|
#include "nsIPrivateAttributionService.h"
 | 
						|
 | 
						|
#include "GMPServiceParent.h"
 | 
						|
#include "HandlerServiceParent.h"
 | 
						|
#include "IHistory.h"
 | 
						|
#include <map>
 | 
						|
#include <utility>
 | 
						|
 | 
						|
#include "ContentProcessManager.h"
 | 
						|
#include "GeckoProfiler.h"
 | 
						|
#include "Geolocation.h"
 | 
						|
#include "GfxInfoBase.h"
 | 
						|
#include "MMPrinter.h"
 | 
						|
#include "PreallocatedProcessManager.h"
 | 
						|
#include "ProcessPriorityManager.h"
 | 
						|
#include "ProfilerParent.h"
 | 
						|
#include "SandboxHal.h"
 | 
						|
#include "SourceSurfaceRawData.h"
 | 
						|
#include "mozilla/ipc/URIUtils.h"
 | 
						|
#include "gfxPlatform.h"
 | 
						|
#include "gfxPlatformFontList.h"
 | 
						|
#include "nsDNSService2.h"
 | 
						|
#include "nsPIDNSService.h"
 | 
						|
#include "mozilla/AntiTrackingUtils.h"
 | 
						|
#include "mozilla/AppShutdown.h"
 | 
						|
#include "mozilla/AutoRestore.h"
 | 
						|
#include "mozilla/ClipboardContentAnalysisParent.h"
 | 
						|
#include "mozilla/BasePrincipal.h"
 | 
						|
#include "mozilla/BenchmarkStorageParent.h"
 | 
						|
#include "mozilla/Casting.h"
 | 
						|
#include "mozilla/ClearOnShutdown.h"
 | 
						|
#include "mozilla/ClipboardReadRequestParent.h"
 | 
						|
#include "mozilla/ClipboardWriteRequestParent.h"
 | 
						|
#include "mozilla/ContentBlockingUserInteraction.h"
 | 
						|
#include "mozilla/FOGIPC.h"
 | 
						|
#include "mozilla/GlobalStyleSheetCache.h"
 | 
						|
#include "mozilla/GeckoArgs.h"
 | 
						|
#include "mozilla/HangDetails.h"
 | 
						|
#include "mozilla/LookAndFeel.h"
 | 
						|
#include "mozilla/Maybe.h"
 | 
						|
#include "mozilla/NullPrincipal.h"
 | 
						|
#include "mozilla/Preferences.h"
 | 
						|
#include "mozilla/PresShell.h"
 | 
						|
#include "mozilla/ProcessHangMonitor.h"
 | 
						|
#include "mozilla/ProcessHangMonitorIPC.h"
 | 
						|
#include "mozilla/ProfilerLabels.h"
 | 
						|
#include "mozilla/ProfilerMarkers.h"
 | 
						|
#include "mozilla/RecursiveMutex.h"
 | 
						|
#include "mozilla/ScopeExit.h"
 | 
						|
#include "mozilla/ScriptPreloader.h"
 | 
						|
#include "mozilla/Components.h"
 | 
						|
#include "mozilla/Sprintf.h"
 | 
						|
#include "mozilla/StaticPrefs_dom.h"
 | 
						|
#include "mozilla/StaticPrefs_fission.h"
 | 
						|
#include "mozilla/StaticPrefs_media.h"
 | 
						|
#include "mozilla/StaticPrefs_network.h"
 | 
						|
#include "mozilla/StaticPrefs_threads.h"
 | 
						|
#include "mozilla/StaticPrefs_widget.h"
 | 
						|
#include "mozilla/StorageAccessAPIHelper.h"
 | 
						|
#include "mozilla/StyleSheet.h"
 | 
						|
#include "mozilla/StyleSheetInlines.h"
 | 
						|
#include "mozilla/TaskController.h"
 | 
						|
#include "mozilla/Telemetry.h"
 | 
						|
#include "mozilla/TelemetryIPC.h"
 | 
						|
#include "mozilla/ThreadSafety.h"
 | 
						|
#include "mozilla/Unused.h"
 | 
						|
#include "mozilla/WebBrowserPersistDocumentParent.h"
 | 
						|
#include "mozilla/devtools/HeapSnapshotTempFileHelperParent.h"
 | 
						|
#include "mozilla/dom/BlobURLProtocolHandler.h"
 | 
						|
#include "mozilla/dom/BrowserHost.h"
 | 
						|
#include "mozilla/dom/BrowsingContext.h"
 | 
						|
#include "mozilla/dom/BrowsingContextGroup.h"
 | 
						|
#include "mozilla/dom/CancelContentJSOptionsBinding.h"
 | 
						|
#include "mozilla/dom/CanonicalBrowsingContext.h"
 | 
						|
#include "mozilla/dom/ClientManager.h"
 | 
						|
#include "mozilla/dom/ContentChild.h"
 | 
						|
#include "mozilla/dom/DataTransfer.h"
 | 
						|
#include "mozilla/dom/Document.h"
 | 
						|
#include "mozilla/dom/Element.h"
 | 
						|
#include "mozilla/dom/ExternalHelperAppParent.h"
 | 
						|
#include "mozilla/dom/File.h"
 | 
						|
#include "mozilla/dom/FileSystemSecurity.h"
 | 
						|
#include "mozilla/dom/GeolocationBinding.h"
 | 
						|
#include "mozilla/dom/GeolocationPositionError.h"
 | 
						|
#include "mozilla/dom/GetFilesHelper.h"
 | 
						|
#include "mozilla/dom/IPCBlobUtils.h"
 | 
						|
#include "mozilla/dom/JSActorService.h"
 | 
						|
#include "mozilla/dom/JSProcessActorBinding.h"
 | 
						|
#include "mozilla/dom/LocalStorageCommon.h"
 | 
						|
#include "mozilla/dom/MediaController.h"
 | 
						|
#include "mozilla/dom/MemoryReportRequest.h"
 | 
						|
#include "mozilla/dom/MediaStatusManager.h"
 | 
						|
#include "mozilla/dom/Notification.h"
 | 
						|
#include "mozilla/dom/PContentPermissionRequestParent.h"
 | 
						|
#include "mozilla/dom/PCycleCollectWithLogsParent.h"
 | 
						|
#include "mozilla/dom/ParentProcessMessageManager.h"
 | 
						|
#include "mozilla/dom/Permissions.h"
 | 
						|
#include "mozilla/dom/ProcessMessageManager.h"
 | 
						|
#include "mozilla/dom/PushNotifier.h"
 | 
						|
#include "mozilla/dom/ServiceWorkerManager.h"
 | 
						|
#include "mozilla/dom/ServiceWorkerRegistrar.h"
 | 
						|
#include "mozilla/dom/ServiceWorkerUtils.h"
 | 
						|
#include "mozilla/dom/SessionHistoryEntry.h"
 | 
						|
#include "mozilla/dom/SessionStorageManager.h"
 | 
						|
#include "mozilla/dom/StorageIPC.h"
 | 
						|
#include "mozilla/dom/UserActivation.h"
 | 
						|
#include "mozilla/dom/URLClassifierParent.h"
 | 
						|
#include "mozilla/dom/WindowGlobalParent.h"
 | 
						|
#include "mozilla/dom/ipc/SharedMap.h"
 | 
						|
#include "mozilla/dom/ipc/StructuredCloneData.h"
 | 
						|
#include "mozilla/dom/nsMixedContentBlocker.h"
 | 
						|
#include "mozilla/dom/power/PowerManagerService.h"
 | 
						|
#include "mozilla/dom/quota/QuotaManagerService.h"
 | 
						|
#include "mozilla/extensions/ExtensionsParent.h"
 | 
						|
#include "mozilla/extensions/StreamFilterParent.h"
 | 
						|
#include "mozilla/gfx/GPUProcessManager.h"
 | 
						|
#include "mozilla/gfx/gfxVars.h"
 | 
						|
#include "mozilla/glean/GleanPings.h"
 | 
						|
#include "mozilla/hal_sandbox/PHalParent.h"
 | 
						|
#include "mozilla/intl/L10nRegistry.h"
 | 
						|
#include "mozilla/intl/LocaleService.h"
 | 
						|
#include "mozilla/ipc/BackgroundChild.h"
 | 
						|
#include "mozilla/ipc/BackgroundParent.h"
 | 
						|
#include "mozilla/ipc/ByteBuf.h"
 | 
						|
#include "mozilla/ipc/CrashReporterHost.h"
 | 
						|
#include "mozilla/ipc/Endpoint.h"
 | 
						|
#include "mozilla/ipc/FileDescriptorUtils.h"
 | 
						|
#include "mozilla/ipc/IPCStreamUtils.h"
 | 
						|
#include "mozilla/ipc/TestShellParent.h"
 | 
						|
#include "mozilla/layers/CompositorThread.h"
 | 
						|
#include "mozilla/layers/ImageBridgeParent.h"
 | 
						|
#include "mozilla/layers/LayerTreeOwnerTracker.h"
 | 
						|
#include "mozilla/layers/PAPZParent.h"
 | 
						|
#include "mozilla/loader/ScriptCacheActors.h"
 | 
						|
#include "mozilla/media/MediaParent.h"
 | 
						|
#include "mozilla/mozSpellChecker.h"
 | 
						|
#include "mozilla/net/CookieServiceParent.h"
 | 
						|
#include "mozilla/net/NeckoMessageUtils.h"
 | 
						|
#include "mozilla/net/NeckoParent.h"
 | 
						|
#include "mozilla/net/PCookieServiceParent.h"
 | 
						|
#include "mozilla/net/CookieKey.h"
 | 
						|
#include "mozilla/net/TRRService.h"
 | 
						|
#include "mozilla/TelemetryComms.h"
 | 
						|
#include "mozilla/TelemetryEventEnums.h"
 | 
						|
#include "mozilla/RemoteLazyInputStreamParent.h"
 | 
						|
#include "mozilla/widget/RemoteLookAndFeel.h"
 | 
						|
#include "mozilla/widget/ScreenManager.h"
 | 
						|
#include "mozilla/widget/TextRecognition.h"
 | 
						|
#include "nsAnonymousTemporaryFile.h"
 | 
						|
#include "nsAppRunner.h"
 | 
						|
#include "nsCExternalHandlerService.h"
 | 
						|
#include "nsCOMPtr.h"
 | 
						|
#include "nsChromeRegistryChrome.h"
 | 
						|
#include "nsConsoleMessage.h"
 | 
						|
#include "nsConsoleService.h"
 | 
						|
#include "nsContentPermissionHelper.h"
 | 
						|
#include "nsContentUtils.h"
 | 
						|
#include "nsCRT.h"
 | 
						|
#include "nsDebugImpl.h"
 | 
						|
#include "nsDirectoryServiceDefs.h"
 | 
						|
#include "nsDocShell.h"
 | 
						|
#include "nsEmbedCID.h"
 | 
						|
#include "nsFocusManager.h"
 | 
						|
#include "nsFrameLoader.h"
 | 
						|
#include "nsFrameMessageManager.h"
 | 
						|
#include "nsGlobalWindowOuter.h"
 | 
						|
#include "nsHashPropertyBag.h"
 | 
						|
#include "nsHyphenationManager.h"
 | 
						|
#include "nsIAlertsService.h"
 | 
						|
#include "nsIAppShell.h"
 | 
						|
#include "nsIAppWindow.h"
 | 
						|
#include "nsIAsyncInputStream.h"
 | 
						|
#include "nsIBidiKeyboard.h"
 | 
						|
#include "nsICaptivePortalService.h"
 | 
						|
#include "nsICertOverrideService.h"
 | 
						|
#include "nsIClipboard.h"
 | 
						|
#include "nsIContentAnalysis.h"
 | 
						|
#include "nsIContentProcess.h"
 | 
						|
#include "nsIContentSecurityPolicy.h"
 | 
						|
#include "nsICookie.h"
 | 
						|
#include "nsICrashService.h"
 | 
						|
#include "nsICycleCollectorListener.h"
 | 
						|
#include "nsIDocShell.h"
 | 
						|
#include "nsIDocShellTreeOwner.h"
 | 
						|
#include "nsIDragService.h"
 | 
						|
#include "nsIExternalProtocolService.h"
 | 
						|
#include "nsIGfxInfo.h"
 | 
						|
#include "nsIUserIdleService.h"
 | 
						|
#include "nsIInterfaceRequestorUtils.h"
 | 
						|
#include "nsILocalStorageManager.h"
 | 
						|
#include "nsIMemoryInfoDumper.h"
 | 
						|
#include "nsIMemoryReporter.h"
 | 
						|
#include "nsINetworkLinkService.h"
 | 
						|
#include "nsIObserverService.h"
 | 
						|
#include "nsIParentChannel.h"
 | 
						|
#include "nsIScriptError.h"
 | 
						|
#include "nsIScriptSecurityManager.h"
 | 
						|
#include "nsIServiceWorkerManager.h"
 | 
						|
#include "nsISiteSecurityService.h"
 | 
						|
#include "nsIStringBundle.h"
 | 
						|
#include "nsITimer.h"
 | 
						|
#include "nsIURL.h"
 | 
						|
#include "nsIWebBrowserChrome.h"
 | 
						|
#include "nsIX509Cert.h"
 | 
						|
#include "nsIXULRuntime.h"
 | 
						|
#include "nsICookieNotification.h"
 | 
						|
#if defined(MOZ_WIDGET_GTK) || defined(XP_WIN)
 | 
						|
#  include "nsIconChannel.h"
 | 
						|
#endif
 | 
						|
#include "nsMemoryInfoDumper.h"
 | 
						|
#include "nsMemoryReporterManager.h"
 | 
						|
#include "nsOpenURIInFrameParams.h"
 | 
						|
#include "nsPIWindowWatcher.h"
 | 
						|
#include "nsQueryObject.h"
 | 
						|
#include "nsReadableUtils.h"
 | 
						|
#include "nsSHistory.h"
 | 
						|
#include "nsScriptError.h"
 | 
						|
#include "nsServiceManagerUtils.h"
 | 
						|
#include "nsStreamUtils.h"
 | 
						|
#include "nsStyleSheetService.h"
 | 
						|
#include "nsThread.h"
 | 
						|
#include "nsThreadUtils.h"
 | 
						|
#include "nsWidgetsCID.h"
 | 
						|
#include "nsWindowWatcher.h"
 | 
						|
#include "prenv.h"
 | 
						|
#include "prio.h"
 | 
						|
#include "private/pprio.h"
 | 
						|
#include "xpcpublic.h"
 | 
						|
#include "nsOpenWindowInfo.h"
 | 
						|
#include "nsFrameLoaderOwner.h"
 | 
						|
 | 
						|
#ifdef MOZ_WEBRTC
 | 
						|
#  include "jsapi/WebrtcGlobalParent.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(XP_MACOSX)
 | 
						|
#  include "nsMacUtilsImpl.h"
 | 
						|
#  include "mozilla/AvailableMemoryWatcher.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(ANDROID) || defined(LINUX)
 | 
						|
#  include "nsSystemInfo.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(XP_LINUX)
 | 
						|
#  include "mozilla/Hal.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef ANDROID
 | 
						|
#  include "gfxAndroidPlatform.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#include "mozilla/PermissionManager.h"
 | 
						|
 | 
						|
#ifdef MOZ_WIDGET_ANDROID
 | 
						|
#  include "AndroidBridge.h"
 | 
						|
#  include "mozilla/java/GeckoProcessManagerWrappers.h"
 | 
						|
#  include "mozilla/java/GeckoProcessTypeWrappers.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef MOZ_WIDGET_GTK
 | 
						|
#  include <gdk/gdk.h>
 | 
						|
#  include "mozilla/WidgetUtilsGtk.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#include "mozilla/RemoteSpellCheckEngineParent.h"
 | 
						|
 | 
						|
#include "Crypto.h"
 | 
						|
 | 
						|
#ifdef MOZ_WEBSPEECH
 | 
						|
#  include "mozilla/dom/SpeechSynthesisParent.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(MOZ_SANDBOX)
 | 
						|
#  include "mozilla/SandboxSettings.h"
 | 
						|
#  if defined(XP_LINUX)
 | 
						|
#    include "mozilla/SandboxInfo.h"
 | 
						|
#    include "mozilla/SandboxBroker.h"
 | 
						|
#    include "mozilla/SandboxBrokerPolicyFactory.h"
 | 
						|
#  endif
 | 
						|
#  if defined(XP_MACOSX)
 | 
						|
#    include "mozilla/Sandbox.h"
 | 
						|
#  endif
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef XP_WIN
 | 
						|
#  include "mozilla/widget/AudioSession.h"
 | 
						|
#  include "mozilla/WinDllServices.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef MOZ_CODE_COVERAGE
 | 
						|
#  include "mozilla/CodeCoverageHandler.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef FUZZING_SNAPSHOT
 | 
						|
#  include "mozilla/fuzzing/IPCFuzzController.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef ENABLE_WEBDRIVER
 | 
						|
#  include "nsIMarionette.h"
 | 
						|
#  include "nsIRemoteAgent.h"
 | 
						|
#endif
 | 
						|
 | 
						|
// For VP9Benchmark::sBenchmarkFpsPref
 | 
						|
#include "Benchmark.h"
 | 
						|
 | 
						|
#include "mozilla/RemoteDecodeUtils.h"
 | 
						|
#include "nsIToolkitProfileService.h"
 | 
						|
#include "nsIToolkitProfile.h"
 | 
						|
 | 
						|
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
 | 
						|
 | 
						|
using base::KillProcess;
 | 
						|
 | 
						|
using namespace CrashReporter;
 | 
						|
using namespace mozilla::dom::power;
 | 
						|
using namespace mozilla::media;
 | 
						|
using namespace mozilla::embedding;
 | 
						|
using namespace mozilla::gfx;
 | 
						|
using namespace mozilla::gmp;
 | 
						|
using namespace mozilla::hal;
 | 
						|
using namespace mozilla::ipc;
 | 
						|
using namespace mozilla::intl;
 | 
						|
using namespace mozilla::layers;
 | 
						|
using namespace mozilla::layout;
 | 
						|
using namespace mozilla::net;
 | 
						|
using namespace mozilla::psm;
 | 
						|
using namespace mozilla::widget;
 | 
						|
using namespace mozilla::Telemetry;
 | 
						|
using mozilla::loader::PScriptCacheParent;
 | 
						|
using mozilla::Telemetry::ProcessID;
 | 
						|
 | 
						|
extern mozilla::LazyLogModule gFocusLog;
 | 
						|
 | 
						|
#define LOGFOCUS(args) MOZ_LOG(gFocusLog, mozilla::LogLevel::Debug, args)
 | 
						|
 | 
						|
extern mozilla::LazyLogModule sPDMLog;
 | 
						|
#define LOGPDM(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
 | 
						|
 | 
						|
namespace mozilla {
 | 
						|
namespace CubebUtils {
 | 
						|
extern FileDescriptor CreateAudioIPCConnection();
 | 
						|
}
 | 
						|
 | 
						|
namespace dom {
 | 
						|
 | 
						|
LazyLogModule gProcessLog("Process");
 | 
						|
 | 
						|
static std::map<RemoteDecodeIn, media::MediaCodecsSupported> sCodecsSupported;
 | 
						|
 | 
						|
/* static */
 | 
						|
uint32_t ContentParent::sMaxContentProcesses = 0;
 | 
						|
 | 
						|
/* static */
 | 
						|
LogModule* ContentParent::GetLog() { return gProcessLog; }
 | 
						|
 | 
						|
/* static */
 | 
						|
uint32_t ContentParent::sPageLoadEventCounter = 0;
 | 
						|
 | 
						|
#define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
 | 
						|
#define NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC "ipc:network:set-connectivity"
 | 
						|
 | 
						|
// IPC receiver for remote GC/CC logging.
 | 
						|
class CycleCollectWithLogsParent final : public PCycleCollectWithLogsParent {
 | 
						|
 public:
 | 
						|
  MOZ_COUNTED_DTOR(CycleCollectWithLogsParent)
 | 
						|
 | 
						|
  static bool AllocAndSendConstructor(ContentParent* aManager,
 | 
						|
                                      bool aDumpAllTraces,
 | 
						|
                                      nsICycleCollectorLogSink* aSink,
 | 
						|
                                      nsIDumpGCAndCCLogsCallback* aCallback) {
 | 
						|
    CycleCollectWithLogsParent* actor;
 | 
						|
    FILE* gcLog;
 | 
						|
    FILE* ccLog;
 | 
						|
    nsresult rv;
 | 
						|
 | 
						|
    actor = new CycleCollectWithLogsParent(aSink, aCallback);
 | 
						|
    rv = actor->mSink->Open(&gcLog, &ccLog);
 | 
						|
    if (NS_WARN_IF(NS_FAILED(rv))) {
 | 
						|
      delete actor;
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    return aManager->SendPCycleCollectWithLogsConstructor(
 | 
						|
        actor, aDumpAllTraces, FILEToFileDescriptor(gcLog),
 | 
						|
        FILEToFileDescriptor(ccLog));
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  virtual mozilla::ipc::IPCResult RecvCloseGCLog() override {
 | 
						|
    Unused << mSink->CloseGCLog();
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  virtual mozilla::ipc::IPCResult RecvCloseCCLog() override {
 | 
						|
    Unused << mSink->CloseCCLog();
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  virtual mozilla::ipc::IPCResult Recv__delete__() override {
 | 
						|
    // Report completion to mCallback only on successful
 | 
						|
    // completion of the protocol.
 | 
						|
    nsCOMPtr<nsIFile> gcLog, ccLog;
 | 
						|
    mSink->GetGcLog(getter_AddRefs(gcLog));
 | 
						|
    mSink->GetCcLog(getter_AddRefs(ccLog));
 | 
						|
    Unused << mCallback->OnDump(gcLog, ccLog, /* parent = */ false);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  virtual void ActorDestroy(ActorDestroyReason aReason) override {
 | 
						|
    // If the actor is unexpectedly destroyed, we deliberately
 | 
						|
    // don't call Close[GC]CLog on the sink, because the logs may
 | 
						|
    // be incomplete.  See also the nsCycleCollectorLogSinkToFile
 | 
						|
    // implementaiton of those methods, and its destructor.
 | 
						|
  }
 | 
						|
 | 
						|
  CycleCollectWithLogsParent(nsICycleCollectorLogSink* aSink,
 | 
						|
                             nsIDumpGCAndCCLogsCallback* aCallback)
 | 
						|
      : mSink(aSink), mCallback(aCallback) {
 | 
						|
    MOZ_COUNT_CTOR(CycleCollectWithLogsParent);
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsICycleCollectorLogSink> mSink;
 | 
						|
  nsCOMPtr<nsIDumpGCAndCCLogsCallback> mCallback;
 | 
						|
};
 | 
						|
 | 
						|
// A memory reporter for ContentParent objects themselves.
 | 
						|
class ContentParentsMemoryReporter final : public nsIMemoryReporter {
 | 
						|
  ~ContentParentsMemoryReporter() = default;
 | 
						|
 | 
						|
 public:
 | 
						|
  NS_DECL_ISUPPORTS
 | 
						|
  NS_DECL_NSIMEMORYREPORTER
 | 
						|
};
 | 
						|
 | 
						|
NS_IMPL_ISUPPORTS(ContentParentsMemoryReporter, nsIMemoryReporter)
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
ContentParentsMemoryReporter::CollectReports(
 | 
						|
    nsIHandleReportCallback* aHandleReport, nsISupports* aData,
 | 
						|
    bool aAnonymize) {
 | 
						|
  AutoTArray<ContentParent*, 16> cps;
 | 
						|
  ContentParent::GetAllEvenIfDead(cps);
 | 
						|
 | 
						|
  for (uint32_t i = 0; i < cps.Length(); i++) {
 | 
						|
    ContentParent* cp = cps[i];
 | 
						|
    MessageChannel* channel = cp->GetIPCChannel();
 | 
						|
 | 
						|
    nsString friendlyName;
 | 
						|
    cp->FriendlyName(friendlyName, aAnonymize);
 | 
						|
 | 
						|
    cp->AddRef();
 | 
						|
    nsrefcnt refcnt = cp->Release();
 | 
						|
 | 
						|
    const char* channelStr = "no channel";
 | 
						|
    uint32_t numQueuedMessages = 0;
 | 
						|
    if (channel) {
 | 
						|
      if (channel->IsClosed()) {
 | 
						|
        channelStr = "closed channel";
 | 
						|
      } else {
 | 
						|
        channelStr = "open channel";
 | 
						|
      }
 | 
						|
      numQueuedMessages =
 | 
						|
          0;  // XXX was channel->Unsound_NumQueuedMessages(); Bug 1754876
 | 
						|
    }
 | 
						|
 | 
						|
    nsPrintfCString path(
 | 
						|
        "queued-ipc-messages/content-parent"
 | 
						|
        "(%s, pid=%d, %s, 0x%p, refcnt=%" PRIuPTR ")",
 | 
						|
        NS_ConvertUTF16toUTF8(friendlyName).get(), cp->Pid(), channelStr,
 | 
						|
        static_cast<nsIObserver*>(cp), refcnt);
 | 
						|
 | 
						|
    constexpr auto desc =
 | 
						|
        "The number of unset IPC messages held in this ContentParent's "
 | 
						|
        "channel.  A large value here might indicate that we're leaking "
 | 
						|
        "messages.  Similarly, a ContentParent object for a process that's no "
 | 
						|
        "longer running could indicate that we're leaking ContentParents."_ns;
 | 
						|
 | 
						|
    aHandleReport->Callback(/* process */ ""_ns, path, KIND_OTHER, UNITS_COUNT,
 | 
						|
                            numQueuedMessages, desc, aData);
 | 
						|
  }
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
// A hashtable (by type) of processes/ContentParents.  This includes
 | 
						|
// processes that are in the Preallocator cache (which would be type
 | 
						|
// 'prealloc'), and recycled processes ('web' and in the future
 | 
						|
// eTLD+1-locked) processes).
 | 
						|
nsClassHashtable<nsCStringHashKey, nsTArray<ContentParent*>>*
 | 
						|
    ContentParent::sBrowserContentParents;
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
uint64_t ComputeLoadedOriginHash(nsIPrincipal* aPrincipal) {
 | 
						|
  uint32_t originNoSuffix =
 | 
						|
      BasePrincipal::Cast(aPrincipal)->GetOriginNoSuffixHash();
 | 
						|
  uint32_t originSuffix =
 | 
						|
      BasePrincipal::Cast(aPrincipal)->GetOriginSuffixHash();
 | 
						|
 | 
						|
  return ((uint64_t)originNoSuffix) << 32 | originSuffix;
 | 
						|
}
 | 
						|
 | 
						|
class ScriptableCPInfo final : public nsIContentProcessInfo {
 | 
						|
 public:
 | 
						|
  explicit ScriptableCPInfo(ContentParent* aParent) : mContentParent(aParent) {
 | 
						|
    MOZ_ASSERT(mContentParent);
 | 
						|
  }
 | 
						|
 | 
						|
  NS_DECL_ISUPPORTS
 | 
						|
  NS_DECL_NSICONTENTPROCESSINFO
 | 
						|
 | 
						|
  void ProcessDied() { mContentParent = nullptr; }
 | 
						|
 | 
						|
 private:
 | 
						|
  ~ScriptableCPInfo() { MOZ_ASSERT(!mContentParent, "must call ProcessDied"); }
 | 
						|
 | 
						|
  ContentParent* mContentParent;
 | 
						|
};
 | 
						|
 | 
						|
NS_IMPL_ISUPPORTS(ScriptableCPInfo, nsIContentProcessInfo)
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
ScriptableCPInfo::GetIsAlive(bool* aIsAlive) {
 | 
						|
  *aIsAlive = mContentParent != nullptr;
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
ScriptableCPInfo::GetProcessId(int32_t* aPID) {
 | 
						|
  if (!mContentParent) {
 | 
						|
    *aPID = -1;
 | 
						|
    return NS_ERROR_NOT_INITIALIZED;
 | 
						|
  }
 | 
						|
 | 
						|
  *aPID = mContentParent->Pid();
 | 
						|
  if (*aPID == -1) {
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
ScriptableCPInfo::GetTabCount(int32_t* aTabCount) {
 | 
						|
  if (!mContentParent) {
 | 
						|
    return NS_ERROR_NOT_INITIALIZED;
 | 
						|
  }
 | 
						|
 | 
						|
  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
 | 
						|
  *aTabCount = cpm->GetBrowserParentCountByProcessId(mContentParent->ChildID());
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
ScriptableCPInfo::GetMessageManager(nsISupports** aMessenger) {
 | 
						|
  *aMessenger = nullptr;
 | 
						|
  if (!mContentParent) {
 | 
						|
    return NS_ERROR_NOT_INITIALIZED;
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<ProcessMessageManager> manager = mContentParent->GetMessageManager();
 | 
						|
  manager.forget(aMessenger);
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
ProcessID GetTelemetryProcessID(const nsACString& remoteType) {
 | 
						|
  // OOP WebExtensions run in a content process.
 | 
						|
  // For Telemetry though we want to break out collected data from the
 | 
						|
  // WebExtensions process into a separate bucket, to make sure we can analyze
 | 
						|
  // it separately and avoid skewing normal content process metrics.
 | 
						|
  return remoteType == EXTENSION_REMOTE_TYPE ? ProcessID::Extension
 | 
						|
                                             : ProcessID::Content;
 | 
						|
}
 | 
						|
 | 
						|
}  // anonymous namespace
 | 
						|
 | 
						|
StaticAutoPtr<LinkedList<ContentParent>> ContentParent::sContentParents;
 | 
						|
StaticRefPtr<ContentParent> ContentParent::sRecycledE10SProcess;
 | 
						|
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
 | 
						|
StaticAutoPtr<SandboxBrokerPolicyFactory>
 | 
						|
    ContentParent::sSandboxBrokerPolicyFactory;
 | 
						|
#endif
 | 
						|
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
 | 
						|
StaticAutoPtr<std::vector<std::string>> ContentParent::sMacSandboxParams;
 | 
						|
#endif
 | 
						|
 | 
						|
// Set to true when the first content process gets created.
 | 
						|
static bool sCreatedFirstContentProcess = false;
 | 
						|
 | 
						|
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | 
						|
// True when we're running the process selection code, and do not expect to
 | 
						|
// enter code paths where processes may die.
 | 
						|
static bool sInProcessSelector = false;
 | 
						|
#endif
 | 
						|
 | 
						|
// The first content child has ID 1, so the chrome process can have ID 0.
 | 
						|
static uint64_t gContentChildID = 1;
 | 
						|
 | 
						|
static const char* sObserverTopics[] = {
 | 
						|
    NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
 | 
						|
    NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
 | 
						|
    NS_IPC_CAPTIVE_PORTAL_SET_STATE,
 | 
						|
    "application-background",
 | 
						|
    "application-foreground",
 | 
						|
    "memory-pressure",
 | 
						|
    "child-gc-request",
 | 
						|
    "child-cc-request",
 | 
						|
    "child-mmu-request",
 | 
						|
    "child-ghost-request",
 | 
						|
    "last-pb-context-exited",
 | 
						|
    "file-watcher-update",
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
    "a11y-init-or-shutdown",
 | 
						|
#endif
 | 
						|
    "cacheservice:empty-cache",
 | 
						|
    "intl:app-locales-changed",
 | 
						|
    "intl:requested-locales-changed",
 | 
						|
    "cookie-changed",
 | 
						|
    "private-cookie-changed",
 | 
						|
    NS_NETWORK_LINK_TYPE_TOPIC,
 | 
						|
    NS_NETWORK_TRR_MODE_CHANGED_TOPIC,
 | 
						|
    "network:socket-process-crashed",
 | 
						|
    DEFAULT_TIMEZONE_CHANGED_OBSERVER_TOPIC,
 | 
						|
};
 | 
						|
 | 
						|
void ContentParent_NotifyUpdatedDictionaries() {
 | 
						|
  ContentParent::NotifyUpdatedDictionaries();
 | 
						|
}
 | 
						|
 | 
						|
// PreallocateProcess is called by the PreallocatedProcessManager.
 | 
						|
// ContentParent then takes this process back within GetNewOrUsedBrowserProcess.
 | 
						|
/*static*/ already_AddRefed<ContentParent>
 | 
						|
ContentParent::MakePreallocProcess() {
 | 
						|
  RefPtr<ContentParent> process = new ContentParent(PREALLOC_REMOTE_TYPE);
 | 
						|
  return process.forget();
 | 
						|
}
 | 
						|
 | 
						|
/*static*/
 | 
						|
void ContentParent::StartUp() {
 | 
						|
  // FIXME Bug 1023701 - Stop using ContentParent static methods in
 | 
						|
  // child process
 | 
						|
  if (!XRE_IsParentProcess()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // From this point on, NS_WARNING, NS_ASSERTION, etc. should print out the
 | 
						|
  // PID along with the warning.
 | 
						|
  nsDebugImpl::SetMultiprocessMode("Parent");
 | 
						|
 | 
						|
  // Note: This reporter measures all ContentParents.
 | 
						|
  RegisterStrongMemoryReporter(new ContentParentsMemoryReporter());
 | 
						|
 | 
						|
  BackgroundChild::Startup();
 | 
						|
  ClientManager::Startup();
 | 
						|
 | 
						|
  Preferences::RegisterCallbackAndCall(&OnFissionBlocklistPrefChange,
 | 
						|
                                       kFissionEnforceBlockList);
 | 
						|
  Preferences::RegisterCallbackAndCall(&OnFissionBlocklistPrefChange,
 | 
						|
                                       kFissionOmitBlockListValues);
 | 
						|
 | 
						|
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
 | 
						|
  sSandboxBrokerPolicyFactory = new SandboxBrokerPolicyFactory();
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
 | 
						|
  sMacSandboxParams = new std::vector<std::string>();
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/*static*/
 | 
						|
void ContentParent::ShutDown() {
 | 
						|
  // For the most, we rely on normal process shutdown and
 | 
						|
  // ClearOnShutdown() to clean up our state.
 | 
						|
 | 
						|
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
 | 
						|
  sSandboxBrokerPolicyFactory = nullptr;
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
 | 
						|
  sMacSandboxParams = nullptr;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/*static*/
 | 
						|
uint32_t ContentParent::GetPoolSize(const nsACString& aContentProcessType) {
 | 
						|
  if (!sBrowserContentParents) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  nsTArray<ContentParent*>* parents =
 | 
						|
      sBrowserContentParents->Get(aContentProcessType);
 | 
						|
 | 
						|
  return parents ? parents->Length() : 0;
 | 
						|
}
 | 
						|
 | 
						|
/*static*/ nsTArray<ContentParent*>& ContentParent::GetOrCreatePool(
 | 
						|
    const nsACString& aContentProcessType) {
 | 
						|
  if (!sBrowserContentParents) {
 | 
						|
    sBrowserContentParents =
 | 
						|
        new nsClassHashtable<nsCStringHashKey, nsTArray<ContentParent*>>;
 | 
						|
  }
 | 
						|
 | 
						|
  return *sBrowserContentParents->GetOrInsertNew(aContentProcessType);
 | 
						|
}
 | 
						|
 | 
						|
nsDependentCSubstring RemoteTypePrefix(const nsACString& aContentProcessType) {
 | 
						|
  // The suffix after a `=` in a remoteType is dynamic, and used to control the
 | 
						|
  // process pool to use.
 | 
						|
  int32_t equalIdx = aContentProcessType.FindChar(L'=');
 | 
						|
  if (equalIdx == kNotFound) {
 | 
						|
    equalIdx = aContentProcessType.Length();
 | 
						|
  }
 | 
						|
  return StringHead(aContentProcessType, equalIdx);
 | 
						|
}
 | 
						|
 | 
						|
bool IsWebRemoteType(const nsACString& aContentProcessType) {
 | 
						|
  // Note: matches webIsolated, web, and webCOOP+COEP types.
 | 
						|
  return StringBeginsWith(aContentProcessType, DEFAULT_REMOTE_TYPE);
 | 
						|
}
 | 
						|
 | 
						|
bool IsWebCoopCoepRemoteType(const nsACString& aContentProcessType) {
 | 
						|
  return StringBeginsWith(aContentProcessType,
 | 
						|
                          WITH_COOP_COEP_REMOTE_TYPE_PREFIX);
 | 
						|
}
 | 
						|
 | 
						|
bool IsExtensionRemoteType(const nsACString& aContentProcessType) {
 | 
						|
  return aContentProcessType == EXTENSION_REMOTE_TYPE;
 | 
						|
}
 | 
						|
 | 
						|
/*static*/
 | 
						|
uint32_t ContentParent::GetMaxProcessCount(
 | 
						|
    const nsACString& aContentProcessType) {
 | 
						|
  // Max process count is based only on the prefix.
 | 
						|
  const nsDependentCSubstring processTypePrefix =
 | 
						|
      RemoteTypePrefix(aContentProcessType);
 | 
						|
 | 
						|
  // Check for the default remote type of "web", as it uses different prefs.
 | 
						|
  if (processTypePrefix == DEFAULT_REMOTE_TYPE) {
 | 
						|
    return GetMaxWebProcessCount();
 | 
						|
  }
 | 
						|
 | 
						|
  // Read the pref controling this remote type. `dom.ipc.processCount` is not
 | 
						|
  // used as a fallback, as it is intended to control the number of "web"
 | 
						|
  // content processes, checked in `mozilla::GetMaxWebProcessCount()`.
 | 
						|
  nsAutoCString processCountPref("dom.ipc.processCount.");
 | 
						|
  processCountPref.Append(processTypePrefix);
 | 
						|
 | 
						|
  int32_t maxContentParents = Preferences::GetInt(processCountPref.get(), 1);
 | 
						|
  if (maxContentParents < 1) {
 | 
						|
    maxContentParents = 1;
 | 
						|
  }
 | 
						|
 | 
						|
  return static_cast<uint32_t>(maxContentParents);
 | 
						|
}
 | 
						|
 | 
						|
/*static*/
 | 
						|
bool ContentParent::IsMaxProcessCountReached(
 | 
						|
    const nsACString& aContentProcessType) {
 | 
						|
  return GetPoolSize(aContentProcessType) >=
 | 
						|
         GetMaxProcessCount(aContentProcessType);
 | 
						|
}
 | 
						|
 | 
						|
// Really more ReleaseUnneededProcesses()
 | 
						|
/*static*/
 | 
						|
void ContentParent::ReleaseCachedProcesses() {
 | 
						|
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
          ("ReleaseCachedProcesses:"));
 | 
						|
  if (!sBrowserContentParents) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
  for (const auto& cps : *sBrowserContentParents) {
 | 
						|
    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
            ("%s: %zu processes", PromiseFlatCString(cps.GetKey()).get(),
 | 
						|
             cps.GetData()->Length()));
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  // First let's collect all processes and keep a grip.
 | 
						|
  AutoTArray<RefPtr<ContentParent>, 32> fixArray;
 | 
						|
  for (const auto& contentParents : sBrowserContentParents->Values()) {
 | 
						|
    for (auto* cp : *contentParents) {
 | 
						|
      fixArray.AppendElement(cp);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  for (const auto& cp : fixArray) {
 | 
						|
    // Ensure the process cannot be claimed between check and MarkAsDead.
 | 
						|
    RecursiveMutexAutoLock lock(cp->ThreadsafeHandleMutex());
 | 
						|
 | 
						|
    if (cp->ManagedPBrowserParent().Count() == 0 && !cp->HasActiveWorker() &&
 | 
						|
        cp->mRemoteType == DEFAULT_REMOTE_TYPE) {
 | 
						|
      MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
              ("  Shutdown %p (%s)", cp.get(), cp->mRemoteType.get()));
 | 
						|
 | 
						|
      PreallocatedProcessManager::Erase(cp);
 | 
						|
      // Make sure we don't select this process for new tabs or workers.
 | 
						|
      cp->MarkAsDead();
 | 
						|
      // Start a soft shutdown.
 | 
						|
      cp->ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
 | 
						|
      // Make sure that this process is no longer accessible from JS by its
 | 
						|
      // message manager.
 | 
						|
      cp->ShutDownMessageManager();
 | 
						|
    } else {
 | 
						|
      MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
              ("  Skipping %p (%s), count %d, HasActiveWorker %d", cp.get(),
 | 
						|
               cp->mRemoteType.get(), cp->ManagedPBrowserParent().Count(),
 | 
						|
               cp->HasActiveWorker()));
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*static*/
 | 
						|
already_AddRefed<ContentParent> ContentParent::MinTabSelect(
 | 
						|
    const nsTArray<ContentParent*>& aContentParents,
 | 
						|
    int32_t aMaxContentParents) {
 | 
						|
  uint32_t maxSelectable =
 | 
						|
      std::min(static_cast<uint32_t>(aContentParents.Length()),
 | 
						|
               static_cast<uint32_t>(aMaxContentParents));
 | 
						|
  uint32_t min = INT_MAX;
 | 
						|
  RefPtr<ContentParent> candidate;
 | 
						|
  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
 | 
						|
 | 
						|
  for (uint32_t i = 0; i < maxSelectable; i++) {
 | 
						|
    ContentParent* p = aContentParents[i];
 | 
						|
    MOZ_DIAGNOSTIC_ASSERT(!p->IsDead());
 | 
						|
 | 
						|
    // Ignore processes that were slated for removal but not yet removed from
 | 
						|
    // the pool (see also GetUsedBrowserProcess and BlockShutdown).
 | 
						|
    if (!p->IsShuttingDown()) {
 | 
						|
      uint32_t tabCount = cpm->GetBrowserParentCountByProcessId(p->ChildID());
 | 
						|
      if (tabCount < min) {
 | 
						|
        candidate = p;
 | 
						|
        min = tabCount;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // If all current processes have at least one tab and we have not yet reached
 | 
						|
  // the maximum, use a new process.
 | 
						|
  if (min > 0 &&
 | 
						|
      aContentParents.Length() < static_cast<uint32_t>(aMaxContentParents)) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  // Otherwise we return candidate.
 | 
						|
  return candidate.forget();
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
already_AddRefed<nsIPrincipal>
 | 
						|
ContentParent::CreateRemoteTypeIsolationPrincipal(
 | 
						|
    const nsACString& aRemoteType) {
 | 
						|
  if ((RemoteTypePrefix(aRemoteType) != FISSION_WEB_REMOTE_TYPE) &&
 | 
						|
      !StringBeginsWith(aRemoteType, WITH_COOP_COEP_REMOTE_TYPE_PREFIX)) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  int32_t offset = aRemoteType.FindChar('=') + 1;
 | 
						|
  MOZ_ASSERT(offset > 1, "can not extract origin from that remote type");
 | 
						|
  nsAutoCString origin(
 | 
						|
      Substring(aRemoteType, offset, aRemoteType.Length() - offset));
 | 
						|
 | 
						|
  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
 | 
						|
  nsCOMPtr<nsIPrincipal> principal;
 | 
						|
  ssm->CreateContentPrincipalFromOrigin(origin, getter_AddRefs(principal));
 | 
						|
  return principal.forget();
 | 
						|
}
 | 
						|
 | 
						|
/*static*/
 | 
						|
already_AddRefed<ContentParent> ContentParent::GetUsedBrowserProcess(
 | 
						|
    const nsACString& aRemoteType, nsTArray<ContentParent*>& aContentParents,
 | 
						|
    uint32_t aMaxContentParents, bool aPreferUsed, ProcessPriority aPriority) {
 | 
						|
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | 
						|
  AutoRestore ar(sInProcessSelector);
 | 
						|
  sInProcessSelector = true;
 | 
						|
#endif
 | 
						|
 | 
						|
  uint32_t numberOfParents = aContentParents.Length();
 | 
						|
  nsTArray<RefPtr<nsIContentProcessInfo>> infos(numberOfParents);
 | 
						|
  for (auto* cp : aContentParents) {
 | 
						|
    infos.AppendElement(cp->mScriptableHelper);
 | 
						|
  }
 | 
						|
 | 
						|
  if (aPreferUsed && numberOfParents) {
 | 
						|
    // If we prefer re-using existing content processes, we don't want to create
 | 
						|
    // a new process, and instead re-use an existing one, so pretend the process
 | 
						|
    // limit is at the current number of processes.
 | 
						|
    aMaxContentParents = numberOfParents;
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsIContentProcessProvider> cpp =
 | 
						|
      do_GetService("@mozilla.org/ipc/processselector;1");
 | 
						|
  int32_t index;
 | 
						|
  if (cpp && NS_SUCCEEDED(cpp->ProvideProcess(aRemoteType, infos,
 | 
						|
                                              aMaxContentParents, &index))) {
 | 
						|
    // If the provider returned an existing ContentParent, use that one.
 | 
						|
    if (0 <= index && static_cast<uint32_t>(index) <= aMaxContentParents) {
 | 
						|
      RefPtr<ContentParent> retval = aContentParents[index];
 | 
						|
      // Ignore processes that were slated for removal but not yet removed from
 | 
						|
      // the pool.
 | 
						|
      if (!retval->IsShuttingDown()) {
 | 
						|
        if (profiler_thread_is_being_profiled_for_markers()) {
 | 
						|
          nsPrintfCString marker("Reused process %u",
 | 
						|
                                 (unsigned int)retval->ChildID());
 | 
						|
          PROFILER_MARKER_TEXT("Process", DOM, {}, marker);
 | 
						|
        }
 | 
						|
        MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
                ("GetUsedProcess: Reused process %p (%u) for %s", retval.get(),
 | 
						|
                 (unsigned int)retval->ChildID(),
 | 
						|
                 PromiseFlatCString(aRemoteType).get()));
 | 
						|
        retval->AssertAlive();
 | 
						|
        retval->StopRecyclingE10SOnly(true);
 | 
						|
        return retval.forget();
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    // If there was a problem with the JS chooser, fall back to a random
 | 
						|
    // selection.
 | 
						|
    NS_WARNING("nsIContentProcessProvider failed to return a process");
 | 
						|
    RefPtr<ContentParent> random;
 | 
						|
    if ((random = MinTabSelect(aContentParents, aMaxContentParents))) {
 | 
						|
      MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
              ("GetUsedProcess: Reused random process %p (%d) for %s",
 | 
						|
               random.get(), (unsigned int)random->ChildID(),
 | 
						|
               PromiseFlatCString(aRemoteType).get()));
 | 
						|
      random->AssertAlive();
 | 
						|
      random->StopRecyclingE10SOnly(true);
 | 
						|
      return random.forget();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // If we are loading into the "web" remote type, are choosing to launch a new
 | 
						|
  // tab, and have a recycled E10S process, we should launch into that process.
 | 
						|
  if (aRemoteType == DEFAULT_REMOTE_TYPE && sRecycledE10SProcess) {
 | 
						|
    RefPtr<ContentParent> recycled = sRecycledE10SProcess;
 | 
						|
    MOZ_DIAGNOSTIC_ASSERT(recycled->GetRemoteType() == DEFAULT_REMOTE_TYPE);
 | 
						|
    recycled->AssertAlive();
 | 
						|
    recycled->StopRecyclingE10SOnly(true);
 | 
						|
    if (profiler_thread_is_being_profiled_for_markers()) {
 | 
						|
      nsPrintfCString marker("Recycled process %u (%p)",
 | 
						|
                             (unsigned int)recycled->ChildID(), recycled.get());
 | 
						|
      PROFILER_MARKER_TEXT("Process", DOM, {}, marker);
 | 
						|
    }
 | 
						|
    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
            ("Recycled process %p", recycled.get()));
 | 
						|
 | 
						|
    return recycled.forget();
 | 
						|
  }
 | 
						|
 | 
						|
  // Try to take a preallocated process except for certain remote types.
 | 
						|
  // Note: this process may not have finished launching yet
 | 
						|
  RefPtr<ContentParent> preallocated;
 | 
						|
  if (aRemoteType != FILE_REMOTE_TYPE &&
 | 
						|
      aRemoteType != PRIVILEGEDABOUT_REMOTE_TYPE &&
 | 
						|
      aRemoteType != EXTENSION_REMOTE_TYPE &&  // Bug 1638119
 | 
						|
      (preallocated = PreallocatedProcessManager::Take(aRemoteType))) {
 | 
						|
    MOZ_DIAGNOSTIC_ASSERT(preallocated->GetRemoteType() ==
 | 
						|
                          PREALLOC_REMOTE_TYPE);
 | 
						|
    MOZ_DIAGNOSTIC_ASSERT(sRecycledE10SProcess != preallocated);
 | 
						|
    preallocated->AssertAlive();
 | 
						|
 | 
						|
    if (profiler_thread_is_being_profiled_for_markers()) {
 | 
						|
      nsPrintfCString marker(
 | 
						|
          "Assigned preallocated process %u%s",
 | 
						|
          (unsigned int)preallocated->ChildID(),
 | 
						|
          preallocated->IsLaunching() ? " (still launching)" : "");
 | 
						|
      PROFILER_MARKER_TEXT("Process", DOM, {}, marker);
 | 
						|
    }
 | 
						|
    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
            ("Adopted preallocated process %p for type %s%s",
 | 
						|
             preallocated.get(), PromiseFlatCString(aRemoteType).get(),
 | 
						|
             preallocated->IsLaunching() ? " (still launching)" : ""));
 | 
						|
 | 
						|
    // This ensures that the preallocator won't shut down the process once
 | 
						|
    // it finishes starting
 | 
						|
    preallocated->mRemoteType.Assign(aRemoteType);
 | 
						|
    {
 | 
						|
      RecursiveMutexAutoLock lock(preallocated->mThreadsafeHandle->mMutex);
 | 
						|
      preallocated->mThreadsafeHandle->mRemoteType = preallocated->mRemoteType;
 | 
						|
    }
 | 
						|
    preallocated->mRemoteTypeIsolationPrincipal =
 | 
						|
        CreateRemoteTypeIsolationPrincipal(aRemoteType);
 | 
						|
    preallocated->mActivateTS = TimeStamp::Now();
 | 
						|
    preallocated->AddToPool(aContentParents);
 | 
						|
 | 
						|
    // rare, but will happen
 | 
						|
    if (!preallocated->IsLaunching()) {
 | 
						|
      // Specialize this process for the appropriate remote type, and activate
 | 
						|
      // it.
 | 
						|
 | 
						|
      Unused << preallocated->SendRemoteType(preallocated->mRemoteType,
 | 
						|
                                             preallocated->mProfile);
 | 
						|
 | 
						|
      nsCOMPtr<nsIObserverService> obs =
 | 
						|
          mozilla::services::GetObserverService();
 | 
						|
      if (obs) {
 | 
						|
        nsAutoString cpId;
 | 
						|
        cpId.AppendInt(static_cast<uint64_t>(preallocated->ChildID()));
 | 
						|
        obs->NotifyObservers(static_cast<nsIObserver*>(preallocated),
 | 
						|
                             "process-type-set", cpId.get());
 | 
						|
        preallocated->AssertAlive();
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return preallocated.forget();
 | 
						|
  }
 | 
						|
 | 
						|
  return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
/*static*/
 | 
						|
already_AddRefed<ContentParent>
 | 
						|
ContentParent::GetNewOrUsedLaunchingBrowserProcess(
 | 
						|
    const nsACString& aRemoteType, BrowsingContextGroup* aGroup,
 | 
						|
    ProcessPriority aPriority, bool aPreferUsed) {
 | 
						|
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
          ("GetNewOrUsedProcess for type %s",
 | 
						|
           PromiseFlatCString(aRemoteType).get()));
 | 
						|
 | 
						|
  // Fallback check (we really want our callers to avoid this).
 | 
						|
  if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
 | 
						|
    MOZ_DIAGNOSTIC_ASSERT(
 | 
						|
        false, "Late attempt to GetNewOrUsedLaunchingBrowserProcess!");
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  // If we have an existing host process attached to this BrowsingContextGroup,
 | 
						|
  // always return it, as we can never have multiple host processes within a
 | 
						|
  // single BrowsingContextGroup.
 | 
						|
  RefPtr<ContentParent> contentParent;
 | 
						|
  if (aGroup) {
 | 
						|
    contentParent = aGroup->GetHostProcess(aRemoteType);
 | 
						|
    Unused << NS_WARN_IF(contentParent && contentParent->IsShuttingDown());
 | 
						|
    if (contentParent && !contentParent->IsShuttingDown()) {
 | 
						|
      MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
              ("GetNewOrUsedProcess: Existing host process %p (launching %d)",
 | 
						|
               contentParent.get(), contentParent->IsLaunching()));
 | 
						|
      contentParent->AssertAlive();
 | 
						|
      contentParent->StopRecyclingE10SOnly(true);
 | 
						|
      return contentParent.forget();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  nsTArray<ContentParent*>& contentParents = GetOrCreatePool(aRemoteType);
 | 
						|
  uint32_t maxContentParents = GetMaxProcessCount(aRemoteType);
 | 
						|
 | 
						|
  // Let's try and reuse an existing process.
 | 
						|
  contentParent = GetUsedBrowserProcess(
 | 
						|
      aRemoteType, contentParents, maxContentParents, aPreferUsed, aPriority);
 | 
						|
 | 
						|
  if (!contentParent) {
 | 
						|
    // No reusable process. Let's create and launch one.
 | 
						|
    // The life cycle will be set to `LifecycleState::LAUNCHING`.
 | 
						|
    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
            ("Launching new process immediately for type %s",
 | 
						|
             PromiseFlatCString(aRemoteType).get()));
 | 
						|
 | 
						|
    contentParent = new ContentParent(aRemoteType);
 | 
						|
    if (NS_WARN_IF(!contentParent->BeginSubprocessLaunch(aPriority))) {
 | 
						|
      // Launch aborted because of shutdown. Bailout.
 | 
						|
      contentParent->LaunchSubprocessReject();
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
    // Until the new process is ready let's not allow to start up any
 | 
						|
    // preallocated processes. The blocker will be removed once we receive
 | 
						|
    // the first idle message.
 | 
						|
    contentParent->mIsAPreallocBlocker = true;
 | 
						|
    PreallocatedProcessManager::AddBlocker(aRemoteType, contentParent);
 | 
						|
 | 
						|
    // Store this process for future reuse.
 | 
						|
    contentParent->AddToPool(contentParents);
 | 
						|
 | 
						|
    MOZ_LOG(
 | 
						|
        ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
        ("GetNewOrUsedProcess: new immediate process %p", contentParent.get()));
 | 
						|
  }
 | 
						|
  // else we have an existing or preallocated process (which may be
 | 
						|
  // still launching)
 | 
						|
 | 
						|
  contentParent->AssertAlive();
 | 
						|
  contentParent->StopRecyclingE10SOnly(true);
 | 
						|
  if (aGroup) {
 | 
						|
    aGroup->EnsureHostProcess(contentParent);
 | 
						|
  }
 | 
						|
  return contentParent.forget();
 | 
						|
}
 | 
						|
 | 
						|
/*static*/
 | 
						|
RefPtr<ContentParent::LaunchPromise>
 | 
						|
ContentParent::GetNewOrUsedBrowserProcessAsync(const nsACString& aRemoteType,
 | 
						|
                                               BrowsingContextGroup* aGroup,
 | 
						|
                                               ProcessPriority aPriority,
 | 
						|
                                               bool aPreferUsed) {
 | 
						|
  // Obtain a `ContentParent` launched asynchronously.
 | 
						|
  RefPtr<ContentParent> contentParent = GetNewOrUsedLaunchingBrowserProcess(
 | 
						|
      aRemoteType, aGroup, aPriority, aPreferUsed);
 | 
						|
  if (!contentParent) {
 | 
						|
    // In case of launch error, stop here.
 | 
						|
    return LaunchPromise::CreateAndReject(NS_ERROR_ILLEGAL_DURING_SHUTDOWN,
 | 
						|
                                          __func__);
 | 
						|
  }
 | 
						|
  return contentParent->WaitForLaunchAsync(aPriority);
 | 
						|
}
 | 
						|
 | 
						|
/*static*/
 | 
						|
already_AddRefed<ContentParent> ContentParent::GetNewOrUsedBrowserProcess(
 | 
						|
    const nsACString& aRemoteType, BrowsingContextGroup* aGroup,
 | 
						|
    ProcessPriority aPriority, bool aPreferUsed) {
 | 
						|
  RefPtr<ContentParent> contentParent = GetNewOrUsedLaunchingBrowserProcess(
 | 
						|
      aRemoteType, aGroup, aPriority, aPreferUsed);
 | 
						|
  if (!contentParent || !contentParent->WaitForLaunchSync(aPriority)) {
 | 
						|
    // In case of launch error, stop here.
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  return contentParent.forget();
 | 
						|
}
 | 
						|
 | 
						|
RefPtr<ContentParent::LaunchPromise> ContentParent::WaitForLaunchAsync(
 | 
						|
    ProcessPriority aPriority) {
 | 
						|
  MOZ_DIAGNOSTIC_ASSERT(!IsDead());
 | 
						|
  if (!IsLaunching()) {
 | 
						|
    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
            ("WaitForLaunchAsync: launched"));
 | 
						|
    return LaunchPromise::CreateAndResolve(this, __func__);
 | 
						|
  }
 | 
						|
 | 
						|
  // We've started an async content process launch.
 | 
						|
  Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC, 0);
 | 
						|
 | 
						|
  // We have located a process that hasn't finished initializing, then attempt
 | 
						|
  // to finish initializing. Both `LaunchSubprocessResolve` and
 | 
						|
  // `LaunchSubprocessReject` are safe to call multiple times if we race with
 | 
						|
  // other `WaitForLaunchAsync` callbacks.
 | 
						|
  return mSubprocess->WhenProcessHandleReady()->Then(
 | 
						|
      GetCurrentSerialEventTarget(), __func__,
 | 
						|
      [self = RefPtr{this}, aPriority]() {
 | 
						|
        if (self->LaunchSubprocessResolve(/* aIsSync = */ false, aPriority)) {
 | 
						|
          MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
                  ("WaitForLaunchAsync: async, now launched"));
 | 
						|
          self->mActivateTS = TimeStamp::Now();
 | 
						|
          return LaunchPromise::CreateAndResolve(self, __func__);
 | 
						|
        }
 | 
						|
 | 
						|
        self->LaunchSubprocessReject();
 | 
						|
        return LaunchPromise::CreateAndReject(NS_ERROR_INVALID_ARG, __func__);
 | 
						|
      },
 | 
						|
      [self = RefPtr{this}]() {
 | 
						|
        MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
                ("WaitForLaunchAsync: async, rejected"));
 | 
						|
        self->LaunchSubprocessReject();
 | 
						|
        return LaunchPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
 | 
						|
      });
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::WaitForLaunchSync(ProcessPriority aPriority) {
 | 
						|
  MOZ_DIAGNOSTIC_ASSERT(!IsDead());
 | 
						|
  if (!IsLaunching()) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  // We've started a sync content process launch.
 | 
						|
  Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC, 1);
 | 
						|
 | 
						|
  // We're a process which hasn't finished initializing. We may be racing
 | 
						|
  // against whoever launched it (and whoever else is already racing). Since
 | 
						|
  // we're sync, we win the race and finish the initialization.
 | 
						|
  bool launchSuccess = mSubprocess->WaitForProcessHandle();
 | 
						|
  if (launchSuccess &&
 | 
						|
      LaunchSubprocessResolve(/* aIsSync = */ true, aPriority)) {
 | 
						|
    mActivateTS = TimeStamp::Now();
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  // In case of failure.
 | 
						|
  LaunchSubprocessReject();
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
static nsIDocShell* GetOpenerDocShellHelper(Element* aFrameElement) {
 | 
						|
  // Propagate the private-browsing status of the element's parent
 | 
						|
  // docshell to the remote docshell, via the chrome flags.
 | 
						|
  MOZ_ASSERT(aFrameElement);
 | 
						|
  nsPIDOMWindowOuter* win = aFrameElement->OwnerDoc()->GetWindow();
 | 
						|
  if (!win) {
 | 
						|
    NS_WARNING("Remote frame has no window");
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  nsIDocShell* docShell = win->GetDocShell();
 | 
						|
  if (!docShell) {
 | 
						|
    NS_WARNING("Remote frame has no docshell");
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  return docShell;
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvCreateClipboardContentAnalysis(
 | 
						|
    Endpoint<PClipboardContentAnalysisParent>&& aParentEndpoint) {
 | 
						|
  if (mClipboardContentAnalysisCreated) {
 | 
						|
    return IPC_FAIL(this, "ClipboardContentAnalysisParent already created");
 | 
						|
  }
 | 
						|
  mClipboardContentAnalysisCreated = true;
 | 
						|
 | 
						|
  if (!mClipboardContentAnalysisThread) {
 | 
						|
    nsresult rv = NS_NewNamedThread(
 | 
						|
        "BkgrndClipboard", getter_AddRefs(mClipboardContentAnalysisThread));
 | 
						|
    if (NS_WARN_IF(NS_FAILED(rv))) {
 | 
						|
      return IPC_FAIL(this, "NS_NewNamedThread failed");
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Bind the new endpoint to the backgroundClipboardContentAnalysis thread.
 | 
						|
  mClipboardContentAnalysisThread->Dispatch(
 | 
						|
      NS_NewRunnableFunction(
 | 
						|
          "Create ClipboardContentAnalysisParent",
 | 
						|
          [threadsafeHandle = RefPtr{ThreadsafeHandle()},
 | 
						|
           parentEndpoint = std::move(aParentEndpoint)]() mutable {
 | 
						|
            // Use a threadsafe handle here, so that it can
 | 
						|
            // be used to validate that the WindowContext comes from the
 | 
						|
            // correct content process.
 | 
						|
            RefPtr<ClipboardContentAnalysisParent> actor =
 | 
						|
                new ClipboardContentAnalysisParent(std::move(threadsafeHandle));
 | 
						|
            parentEndpoint.Bind(actor);
 | 
						|
          }),
 | 
						|
      NS_DISPATCH_NORMAL);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvCreateGMPService() {
 | 
						|
  Endpoint<PGMPServiceParent> parent;
 | 
						|
  Endpoint<PGMPServiceChild> child;
 | 
						|
 | 
						|
  if (mGMPCreated) {
 | 
						|
    return IPC_FAIL(this, "GMP Service already created");
 | 
						|
  }
 | 
						|
 | 
						|
  nsresult rv;
 | 
						|
  rv = PGMPService::CreateEndpoints(base::GetCurrentProcId(), OtherPid(),
 | 
						|
                                    &parent, &child);
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    return IPC_FAIL(this, "CreateEndpoints failed");
 | 
						|
  }
 | 
						|
 | 
						|
  if (!GMPServiceParent::Create(std::move(parent))) {
 | 
						|
    return IPC_FAIL(this, "GMPServiceParent::Create failed");
 | 
						|
  }
 | 
						|
 | 
						|
  if (!SendInitGMPService(std::move(child))) {
 | 
						|
    return IPC_FAIL(this, "SendInitGMPService failed");
 | 
						|
  }
 | 
						|
 | 
						|
  mGMPCreated = true;
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
IPCResult ContentParent::RecvAttributionEvent(
 | 
						|
    const nsACString& aHost, PrivateAttributionImpressionType aType,
 | 
						|
    uint32_t aIndex, const nsAString& aAd, const nsACString& aTargetHost) {
 | 
						|
  nsCOMPtr<nsIPrivateAttributionService> pa =
 | 
						|
      components::PrivateAttribution::Service();
 | 
						|
  if (NS_WARN_IF(!pa)) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  pa->OnAttributionEvent(aHost, GetEnumString(aType), aIndex, aAd, aTargetHost);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
IPCResult ContentParent::RecvAttributionConversion(
 | 
						|
    const nsACString& aHost, const nsAString& aTask, uint32_t aHistogramSize,
 | 
						|
    const Maybe<uint32_t>& aLoopbackDays,
 | 
						|
    const Maybe<PrivateAttributionImpressionType>& aImpressionType,
 | 
						|
    const nsTArray<nsString>& aAds, const nsTArray<nsCString>& aSourceHosts) {
 | 
						|
  nsCOMPtr<nsIPrivateAttributionService> pa =
 | 
						|
      components::PrivateAttribution::Service();
 | 
						|
  if (NS_WARN_IF(!pa)) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  pa->OnAttributionConversion(
 | 
						|
      aHost, aTask, aHistogramSize, aLoopbackDays.valueOr(0),
 | 
						|
      aImpressionType ? GetEnumString(*aImpressionType) : EmptyCString(), aAds,
 | 
						|
      aSourceHosts);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
Atomic<bool, mozilla::Relaxed> sContentParentTelemetryEventEnabled(false);
 | 
						|
 | 
						|
/*static*/
 | 
						|
void ContentParent::LogAndAssertFailedPrincipalValidationInfo(
 | 
						|
    nsIPrincipal* aPrincipal, const char* aMethod) {
 | 
						|
  // nsContentSecurityManager may also enable this same event, but that's okay
 | 
						|
  if (!sContentParentTelemetryEventEnabled.exchange(true)) {
 | 
						|
    sContentParentTelemetryEventEnabled = true;
 | 
						|
    Telemetry::SetEventRecordingEnabled("security"_ns, true);
 | 
						|
  }
 | 
						|
 | 
						|
  // Send Telemetry
 | 
						|
  nsAutoCString principalScheme, principalType, spec;
 | 
						|
  CopyableTArray<EventExtraEntry> extra(2);
 | 
						|
 | 
						|
  if (!aPrincipal) {
 | 
						|
    principalType.AssignLiteral("NullPtr");
 | 
						|
  } else if (aPrincipal->IsSystemPrincipal()) {
 | 
						|
    principalType.AssignLiteral("SystemPrincipal");
 | 
						|
  } else if (aPrincipal->GetIsExpandedPrincipal()) {
 | 
						|
    principalType.AssignLiteral("ExpandedPrincipal");
 | 
						|
  } else if (aPrincipal->GetIsContentPrincipal()) {
 | 
						|
    principalType.AssignLiteral("ContentPrincipal");
 | 
						|
    aPrincipal->GetSpec(spec);
 | 
						|
    aPrincipal->GetScheme(principalScheme);
 | 
						|
 | 
						|
    extra.AppendElement(EventExtraEntry{"scheme"_ns, principalScheme});
 | 
						|
  } else {
 | 
						|
    principalType.AssignLiteral("Unknown");
 | 
						|
  }
 | 
						|
 | 
						|
  extra.AppendElement(EventExtraEntry{"principalType"_ns, principalType});
 | 
						|
 | 
						|
  // Do not send telemetry when chrome-debugging is enabled
 | 
						|
  bool isChromeDebuggingEnabled =
 | 
						|
      Preferences::GetBool("devtools.chrome.enabled", false);
 | 
						|
  if (!isChromeDebuggingEnabled) {
 | 
						|
    Telemetry::EventID eventType =
 | 
						|
        Telemetry::EventID::Security_Fissionprincipals_Contentparent;
 | 
						|
    Telemetry::RecordEvent(eventType, mozilla::Some(aMethod),
 | 
						|
                           mozilla::Some(extra));
 | 
						|
  }
 | 
						|
 | 
						|
  // And log it
 | 
						|
  MOZ_LOG(
 | 
						|
      ContentParent::GetLog(), LogLevel::Error,
 | 
						|
      ("  Receiving unexpected Principal (%s) within %s",
 | 
						|
       aPrincipal && aPrincipal->GetIsContentPrincipal() ? spec.get()
 | 
						|
                                                         : principalType.get(),
 | 
						|
       aMethod));
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
  // Not only log but also ensure we do not receive an unexpected
 | 
						|
  // principal when running in debug mode.
 | 
						|
  MOZ_ASSERT(false, "Receiving unexpected Principal");
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::ValidatePrincipal(
 | 
						|
    nsIPrincipal* aPrincipal,
 | 
						|
    const EnumSet<ValidatePrincipalOptions>& aOptions) {
 | 
						|
  // If the pref says we should not validate, then there is nothing to do
 | 
						|
  if (!StaticPrefs::dom_security_enforceIPCBasedPrincipalVetting()) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  // If there is no principal, then there is nothing to validate!
 | 
						|
  if (!aPrincipal) {
 | 
						|
    return aOptions.contains(ValidatePrincipalOptions::AllowNullPtr);
 | 
						|
  }
 | 
						|
 | 
						|
  // We currently do not track relationships between specific null principals
 | 
						|
  // and content processes, so we can not validate much here - just allow all
 | 
						|
  // null principals we see because they are generally safe anyway!
 | 
						|
  if (aPrincipal->GetIsNullPrincipal()) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  // Only allow the system principal if the passed in options flags
 | 
						|
  // request permitting the system principal.
 | 
						|
  if (aPrincipal->IsSystemPrincipal()) {
 | 
						|
    return aOptions.contains(ValidatePrincipalOptions::AllowSystem);
 | 
						|
  }
 | 
						|
 | 
						|
  // XXXckerschb: we should eliminate the resource carve-out here and always
 | 
						|
  // validate the Principal, see Bug 1686200: Investigate Principal for pdf.js
 | 
						|
  if (aPrincipal->SchemeIs("resource")) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  // Validate each inner principal individually, allowing us to catch expanded
 | 
						|
  // principals containing the system principal, etc.
 | 
						|
  if (aPrincipal->GetIsExpandedPrincipal()) {
 | 
						|
    if (!aOptions.contains(ValidatePrincipalOptions::AllowExpanded)) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    // FIXME: There are more constraints on expanded principals in-practice,
 | 
						|
    // such as the structure of extension expanded principals. This may need
 | 
						|
    // to be investigated more in the future.
 | 
						|
    nsCOMPtr<nsIExpandedPrincipal> expandedPrincipal =
 | 
						|
        do_QueryInterface(aPrincipal);
 | 
						|
    const auto& allowList = expandedPrincipal->AllowList();
 | 
						|
    for (const auto& innerPrincipal : allowList) {
 | 
						|
      if (!ValidatePrincipal(innerPrincipal, aOptions)) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  // A URI with a file:// scheme can never load in a non-file content process
 | 
						|
  // due to sandboxing.
 | 
						|
  if (aPrincipal->SchemeIs("file")) {
 | 
						|
    // If we don't support a separate 'file' process, then we can return here.
 | 
						|
    if (!StaticPrefs::browser_tabs_remote_separateFileUriProcess()) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
    return mRemoteType == FILE_REMOTE_TYPE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (aPrincipal->SchemeIs("about")) {
 | 
						|
    uint32_t flags = 0;
 | 
						|
    nsresult rv = aPrincipal->GetAboutModuleFlags(&flags);
 | 
						|
    if (rv == nsresult::NS_ERROR_FACTORY_NOT_REGISTERED) {
 | 
						|
      // This happens in our tests. There is a race between an about page
 | 
						|
      // getting unregistered and the content process unregistering a blob URL
 | 
						|
      // which it was using.
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    // Block principals for about: URIs which can't load in this process.
 | 
						|
    if (!(flags & (nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
 | 
						|
                   nsIAboutModule::URI_MUST_LOAD_IN_CHILD))) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    if (flags & nsIAboutModule::URI_MUST_LOAD_IN_EXTENSION_PROCESS) {
 | 
						|
      return mRemoteType == EXTENSION_REMOTE_TYPE;
 | 
						|
    }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!mRemoteTypeIsolationPrincipal ||
 | 
						|
      RemoteTypePrefix(mRemoteType) != FISSION_WEB_REMOTE_TYPE) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  // Web content can contain extension content frames, so a content process may
 | 
						|
  // send us an extension's principal.
 | 
						|
  auto* addonPolicy = BasePrincipal::Cast(aPrincipal)->AddonPolicy();
 | 
						|
  if (addonPolicy) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  // Ensure that the expected site-origin matches the one specified by our
 | 
						|
  // mRemoteTypeIsolationPrincipal.
 | 
						|
  nsAutoCString siteOriginNoSuffix;
 | 
						|
  if (NS_FAILED(aPrincipal->GetSiteOriginNoSuffix(siteOriginNoSuffix))) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  nsAutoCString remoteTypeSiteOriginNoSuffix;
 | 
						|
  if (NS_FAILED(mRemoteTypeIsolationPrincipal->GetSiteOriginNoSuffix(
 | 
						|
          remoteTypeSiteOriginNoSuffix))) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  return remoteTypeSiteOriginNoSuffix.Equals(siteOriginNoSuffix);
 | 
						|
}
 | 
						|
 | 
						|
/*static*/
 | 
						|
already_AddRefed<RemoteBrowser> ContentParent::CreateBrowser(
 | 
						|
    const TabContext& aContext, Element* aFrameElement,
 | 
						|
    const nsACString& aRemoteType, BrowsingContext* aBrowsingContext,
 | 
						|
    ContentParent* aOpenerContentParent) {
 | 
						|
  AUTO_PROFILER_LABEL("ContentParent::CreateBrowser", OTHER);
 | 
						|
 | 
						|
  MOZ_DIAGNOSTIC_ASSERT(
 | 
						|
      !aBrowsingContext->Canonical()->GetBrowserParent(),
 | 
						|
      "BrowsingContext must not have BrowserParent, or have previous "
 | 
						|
      "BrowserParent cleared");
 | 
						|
 | 
						|
  // Don't bother creating new content browsers after entering shutdown. This
 | 
						|
  // could lead to starting a new content process, which may significantly delay
 | 
						|
  // shutdown, and the content is unlikely to be displayed.
 | 
						|
  if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
 | 
						|
    NS_WARNING("Ignoring remote browser creation request during shutdown");
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  nsAutoCString remoteType(aRemoteType);
 | 
						|
  if (remoteType.IsEmpty()) {
 | 
						|
    remoteType = DEFAULT_REMOTE_TYPE;
 | 
						|
  }
 | 
						|
 | 
						|
  TabId tabId(nsContentUtils::GenerateTabId());
 | 
						|
 | 
						|
  nsIDocShell* docShell = GetOpenerDocShellHelper(aFrameElement);
 | 
						|
  TabId openerTabId;
 | 
						|
  if (docShell) {
 | 
						|
    openerTabId = BrowserParent::GetTabIdFrom(docShell);
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<ContentParent> constructorSender;
 | 
						|
  MOZ_RELEASE_ASSERT(XRE_IsParentProcess(),
 | 
						|
                     "Cannot allocate BrowserParent in content process");
 | 
						|
  if (aOpenerContentParent && !aOpenerContentParent->IsShuttingDown()) {
 | 
						|
    constructorSender = aOpenerContentParent;
 | 
						|
  } else {
 | 
						|
    constructorSender = GetNewOrUsedBrowserProcess(
 | 
						|
        remoteType, aBrowsingContext->Group(), PROCESS_PRIORITY_FOREGROUND);
 | 
						|
    if (!constructorSender) {
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  aBrowsingContext->SetEmbedderElement(aFrameElement);
 | 
						|
 | 
						|
  // Ensure that the process which we're using to launch is set as the host
 | 
						|
  // process for this BrowsingContextGroup.
 | 
						|
  aBrowsingContext->Group()->EnsureHostProcess(constructorSender);
 | 
						|
 | 
						|
  nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
 | 
						|
  docShell->GetTreeOwner(getter_AddRefs(treeOwner));
 | 
						|
  if (!treeOwner) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsIWebBrowserChrome> wbc = do_GetInterface(treeOwner);
 | 
						|
  if (!wbc) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  uint32_t chromeFlags = 0;
 | 
						|
  wbc->GetChromeFlags(&chromeFlags);
 | 
						|
 | 
						|
  nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
 | 
						|
  if (loadContext && loadContext->UsePrivateBrowsing()) {
 | 
						|
    chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
 | 
						|
  }
 | 
						|
  if (loadContext && loadContext->UseRemoteTabs()) {
 | 
						|
    chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
 | 
						|
  }
 | 
						|
  if (loadContext && loadContext->UseRemoteSubframes()) {
 | 
						|
    chromeFlags |= nsIWebBrowserChrome::CHROME_FISSION_WINDOW;
 | 
						|
  }
 | 
						|
 | 
						|
  if (tabId == 0) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  aBrowsingContext->Canonical()->SetOwnerProcessId(
 | 
						|
      constructorSender->ChildID());
 | 
						|
 | 
						|
  RefPtr<BrowserParent> browserParent =
 | 
						|
      new BrowserParent(constructorSender, tabId, aContext,
 | 
						|
                        aBrowsingContext->Canonical(), chromeFlags);
 | 
						|
 | 
						|
  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
 | 
						|
  if (NS_WARN_IF(!cpm)) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  cpm->RegisterRemoteFrame(browserParent);
 | 
						|
 | 
						|
  // Open a remote endpoint for our PBrowser actor.
 | 
						|
  ManagedEndpoint<PBrowserChild> childEp =
 | 
						|
      constructorSender->OpenPBrowserEndpoint(browserParent);
 | 
						|
  if (NS_WARN_IF(!childEp.IsValid())) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsIPrincipal> initialPrincipal =
 | 
						|
      NullPrincipal::Create(aBrowsingContext->OriginAttributesRef());
 | 
						|
  WindowGlobalInit windowInit = WindowGlobalActor::AboutBlankInitializer(
 | 
						|
      aBrowsingContext, initialPrincipal);
 | 
						|
 | 
						|
  RefPtr<WindowGlobalParent> windowParent =
 | 
						|
      WindowGlobalParent::CreateDisconnected(windowInit);
 | 
						|
  if (NS_WARN_IF(!windowParent)) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  // Open a remote endpoint for the initial PWindowGlobal actor.
 | 
						|
  ManagedEndpoint<PWindowGlobalChild> windowEp =
 | 
						|
      browserParent->OpenPWindowGlobalEndpoint(windowParent);
 | 
						|
  if (NS_WARN_IF(!windowEp.IsValid())) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  // Tell the content process to set up its PBrowserChild.
 | 
						|
  bool ok = constructorSender->SendConstructBrowser(
 | 
						|
      std::move(childEp), std::move(windowEp), tabId,
 | 
						|
      aContext.AsIPCTabContext(), windowInit, chromeFlags,
 | 
						|
      constructorSender->ChildID(), constructorSender->IsForBrowser(),
 | 
						|
      /* aIsTopLevel */ true);
 | 
						|
  if (NS_WARN_IF(!ok)) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  // Ensure that we're marked as the current BrowserParent on our
 | 
						|
  // CanonicalBrowsingContext.
 | 
						|
  aBrowsingContext->Canonical()->SetCurrentBrowserParent(browserParent);
 | 
						|
 | 
						|
  windowParent->Init();
 | 
						|
 | 
						|
  RefPtr<BrowserHost> browserHost = new BrowserHost(browserParent);
 | 
						|
  browserParent->SetOwnerElement(aFrameElement);
 | 
						|
  return browserHost.forget();
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::GetAll(nsTArray<ContentParent*>& aArray) {
 | 
						|
  aArray.Clear();
 | 
						|
 | 
						|
  for (auto* cp : AllProcesses(eLive)) {
 | 
						|
    aArray.AppendElement(cp);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::GetAllEvenIfDead(nsTArray<ContentParent*>& aArray) {
 | 
						|
  aArray.Clear();
 | 
						|
 | 
						|
  for (auto* cp : AllProcesses(eAll)) {
 | 
						|
    aArray.AppendElement(cp);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::BroadcastStringBundle(
 | 
						|
    const StringBundleDescriptor& aBundle) {
 | 
						|
  AutoTArray<StringBundleDescriptor, 1> array;
 | 
						|
  array.AppendElement(aBundle);
 | 
						|
 | 
						|
  for (auto* cp : AllProcesses(eLive)) {
 | 
						|
    Unused << cp->SendRegisterStringBundles(array);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::BroadcastFontListChanged() {
 | 
						|
  for (auto* cp : AllProcesses(eLive)) {
 | 
						|
    Unused << cp->SendFontListChanged();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::BroadcastShmBlockAdded(uint32_t aGeneration,
 | 
						|
                                           uint32_t aIndex) {
 | 
						|
  auto* pfl = gfxPlatformFontList::PlatformFontList();
 | 
						|
  for (auto* cp : AllProcesses(eLive)) {
 | 
						|
    base::SharedMemoryHandle handle =
 | 
						|
        pfl->ShareShmBlockToProcess(aIndex, cp->Pid());
 | 
						|
    if (handle == base::SharedMemory::NULLHandle()) {
 | 
						|
      // If something went wrong here, we just skip it; the child will need to
 | 
						|
      // request the block as needed, at some performance cost.
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    Unused << cp->SendFontListShmBlockAdded(aGeneration, aIndex,
 | 
						|
                                            std::move(handle));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::BroadcastThemeUpdate(widget::ThemeChangeKind aKind) {
 | 
						|
  const FullLookAndFeel& lnf = *RemoteLookAndFeel::ExtractData();
 | 
						|
  for (auto* cp : AllProcesses(eLive)) {
 | 
						|
    Unused << cp->SendThemeChanged(lnf, aKind);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*static */
 | 
						|
void ContentParent::BroadcastMediaCodecsSupportedUpdate(
 | 
						|
    RemoteDecodeIn aLocation, const media::MediaCodecsSupported& aSupported) {
 | 
						|
  // Update processes and print the support info from the given location.
 | 
						|
  sCodecsSupported[aLocation] = aSupported;
 | 
						|
  for (auto* cp : AllProcesses(eAll)) {
 | 
						|
    Unused << cp->SendUpdateMediaCodecsSupported(aLocation, aSupported);
 | 
						|
  }
 | 
						|
  nsCString supportString;
 | 
						|
  media::MCSInfo::GetMediaCodecsSupportedString(supportString, aSupported);
 | 
						|
  LOGPDM("Broadcast support from '%s', support=%s",
 | 
						|
         RemoteDecodeInToStr(aLocation), supportString.get());
 | 
						|
 | 
						|
  // Merge incoming support with existing support list from other locations
 | 
						|
  media::MCSInfo::AddSupport(aSupported);
 | 
						|
  auto fullSupport = media::MCSInfo::GetSupport();
 | 
						|
 | 
						|
  // Generate + save FULL support string for display in about:support
 | 
						|
  supportString.Truncate();
 | 
						|
  media::MCSInfo::GetMediaCodecsSupportedString(supportString, fullSupport);
 | 
						|
  gfx::gfxVars::SetCodecSupportInfo(supportString);
 | 
						|
}
 | 
						|
 | 
						|
const nsACString& ContentParent::GetRemoteType() const { return mRemoteType; }
 | 
						|
 | 
						|
static StaticRefPtr<nsIAsyncShutdownClient> sXPCOMShutdownClient;
 | 
						|
static StaticRefPtr<nsIAsyncShutdownClient> sProfileBeforeChangeClient;
 | 
						|
static StaticRefPtr<nsIAsyncShutdownClient> sQuitApplicationGrantedClient;
 | 
						|
 | 
						|
void ContentParent::Init() {
 | 
						|
  MOZ_ASSERT(sXPCOMShutdownClient);
 | 
						|
 | 
						|
  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
 | 
						|
  if (obs) {
 | 
						|
    size_t length = ArrayLength(sObserverTopics);
 | 
						|
    for (size_t i = 0; i < length; ++i) {
 | 
						|
      obs->AddObserver(this, sObserverTopics[i], false);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (obs) {
 | 
						|
    nsAutoString cpId;
 | 
						|
    cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
 | 
						|
    obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-created",
 | 
						|
                         cpId.get());
 | 
						|
  }
 | 
						|
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
  // If accessibility is running in chrome process then start it in content
 | 
						|
  // process.
 | 
						|
  if (GetAccService()) {
 | 
						|
    Unused << SendActivateA11y();
 | 
						|
  }
 | 
						|
#endif  // #ifdef ACCESSIBILITY
 | 
						|
 | 
						|
  Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
 | 
						|
 | 
						|
  RefPtr<GeckoMediaPluginServiceParent> gmps(
 | 
						|
      GeckoMediaPluginServiceParent::GetSingleton());
 | 
						|
  if (gmps) {
 | 
						|
    gmps->UpdateContentProcessGMPCapabilities(this);
 | 
						|
  }
 | 
						|
 | 
						|
  // Flush any pref updates that happened during launch and weren't
 | 
						|
  // included in the blobs set up in BeginSubprocessLaunch.
 | 
						|
  for (const Pref& pref : mQueuedPrefs) {
 | 
						|
    Unused << NS_WARN_IF(!SendPreferenceUpdate(pref));
 | 
						|
  }
 | 
						|
  mQueuedPrefs.Clear();
 | 
						|
 | 
						|
  Unused << SendInitNextGenLocalStorageEnabled(NextGenLocalStorageEnabled());
 | 
						|
}
 | 
						|
 | 
						|
// Note that for E10S we can get a false here that will be overruled by
 | 
						|
// TryToRecycleE10SOnly as late as MaybeBeginShutdown. We cannot really
 | 
						|
// foresee its result here.
 | 
						|
bool ContentParent::CheckTabDestroyWillKeepAlive(
 | 
						|
    uint32_t aExpectedBrowserCount) {
 | 
						|
  return ManagedPBrowserParent().Count() != aExpectedBrowserCount ||
 | 
						|
         ShouldKeepProcessAlive();
 | 
						|
}
 | 
						|
 | 
						|
RecursiveMutex& ContentParent::ThreadsafeHandleMutex() {
 | 
						|
  return mThreadsafeHandle->mMutex;
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::NotifyTabWillDestroy() {
 | 
						|
  if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)
 | 
						|
#if !defined(MOZ_WIDGET_ANDROID)
 | 
						|
      /* on Android we keep processes alive more agressively, see
 | 
						|
         NotifyTabDestroying where we omit MaybeBeginShutdown */
 | 
						|
      || (/* we cannot trust CheckTabDestroyWillKeepAlive in E10S mode */
 | 
						|
          mozilla::FissionAutostart() &&
 | 
						|
          !CheckTabDestroyWillKeepAlive(mNumDestroyingTabs + 1))
 | 
						|
#endif
 | 
						|
  ) {
 | 
						|
    // Once we notify the impending shutdown, the content process will stop
 | 
						|
    // to process content JS on interrupt (among other things), so we need to
 | 
						|
    // be sure that the process will not be re-used after this point.
 | 
						|
    // The inverse is harmless, that is if we decide later to shut it down
 | 
						|
    // but did not notify here, it will be just notified later (but in rare
 | 
						|
    // cases too late to avoid a hang).
 | 
						|
    NotifyImpendingShutdown();
 | 
						|
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | 
						|
    mNotifiedImpendingShutdownOnTabWillDestroy = true;
 | 
						|
#endif
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::MaybeBeginShutDown(uint32_t aExpectedBrowserCount,
 | 
						|
                                       bool aSendShutDown) {
 | 
						|
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
 | 
						|
          ("MaybeBeginShutdown %p, %u vs %u", this,
 | 
						|
           ManagedPBrowserParent().Count(), aExpectedBrowserCount));
 | 
						|
  MOZ_ASSERT(NS_IsMainThread());
 | 
						|
 | 
						|
  // We need to lock our mutex here to ensure the state does not change
 | 
						|
  // between the check and the MarkAsDead.
 | 
						|
  // Note that if we come through BrowserParent::Destroy our mutex is
 | 
						|
  // already locked.
 | 
						|
  // TODO: We want to get rid of the ThreadsafeHandle, see bug 1683595.
 | 
						|
  RecursiveMutexAutoLock lock(mThreadsafeHandle->mMutex);
 | 
						|
 | 
						|
  // Both CheckTabDestroyWillKeepAlive and TryToRecycleE10SOnly will return
 | 
						|
  // false if IsInOrBeyond(AppShutdownConfirmed), so if the parent shuts
 | 
						|
  // down we will always shutdown the child.
 | 
						|
  if (CheckTabDestroyWillKeepAlive(aExpectedBrowserCount) ||
 | 
						|
      TryToRecycleE10SOnly()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_LOG(
 | 
						|
      ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
      ("Beginning ContentParent Shutdown %p (%s)", this, mRemoteType.get()));
 | 
						|
 | 
						|
  // We're dying now, prevent anything from re-using this process.
 | 
						|
  MarkAsDead();
 | 
						|
  SignalImpendingShutdownToContentJS();
 | 
						|
 | 
						|
  if (aSendShutDown) {
 | 
						|
    AsyncSendShutDownMessage();
 | 
						|
  } else {
 | 
						|
    // aSendShutDown is false only when we get called from
 | 
						|
    // NotifyTabDestroying where we expect a subsequent call from
 | 
						|
    // NotifyTabDestroyed triggered by a Browser actor destroy
 | 
						|
    // roundtrip through the content process that might never arrive.
 | 
						|
    StartSendShutdownTimer();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::AsyncSendShutDownMessage() {
 | 
						|
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
 | 
						|
          ("AsyncSendShutDownMessage %p", this));
 | 
						|
  MOZ_ASSERT(NS_IsMainThread());
 | 
						|
  MOZ_ASSERT(sRecycledE10SProcess != this);
 | 
						|
 | 
						|
  // In the case of normal shutdown, send a shutdown message to child to
 | 
						|
  // allow it to perform shutdown tasks.
 | 
						|
  GetCurrentSerialEventTarget()->Dispatch(NewRunnableMethod<ShutDownMethod>(
 | 
						|
      "dom::ContentParent::ShutDownProcess", this,
 | 
						|
      &ContentParent::ShutDownProcess, SEND_SHUTDOWN_MESSAGE));
 | 
						|
}
 | 
						|
 | 
						|
void MaybeLogBlockShutdownDiagnostics(ContentParent* aSelf, const char* aMsg,
 | 
						|
                                      const char* aFile, int32_t aLine) {
 | 
						|
#if defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
 | 
						|
  if (aSelf->IsBlockingShutdown()) {
 | 
						|
    MOZ_LOG(ContentParent::GetLog(), LogLevel::Info,
 | 
						|
            ("ContentParent: id=%p pid=%d - %s at %s(%d)", aSelf, aSelf->Pid(),
 | 
						|
             aMsg, aFile, aLine));
 | 
						|
  }
 | 
						|
#else
 | 
						|
  Unused << aSelf;
 | 
						|
  Unused << aMsg;
 | 
						|
  Unused << aFile;
 | 
						|
  Unused << aLine;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::ShutDownProcess(ShutDownMethod aMethod) {
 | 
						|
  bool result = false;
 | 
						|
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
          ("ShutDownProcess: %p", this));
 | 
						|
  // NB: must MarkAsDead() here so that this isn't accidentally
 | 
						|
  // returned from Get*() while in the midst of shutdown.
 | 
						|
  MarkAsDead();
 | 
						|
 | 
						|
  // Shutting down by sending a shutdown message works differently than the
 | 
						|
  // other methods. We first call Shutdown() in the child. After the child is
 | 
						|
  // ready, it calls FinishShutdown() on us. Then we close the channel.
 | 
						|
  if (aMethod == SEND_SHUTDOWN_MESSAGE) {
 | 
						|
    if (!mShutdownPending) {
 | 
						|
      if (CanSend()) {
 | 
						|
        // Stop sending input events with input priority when shutting down.
 | 
						|
        SetInputPriorityEventEnabled(false);
 | 
						|
        // If we did not earlier, let's signal the shutdown to JS now.
 | 
						|
        SignalImpendingShutdownToContentJS();
 | 
						|
 | 
						|
        // Adjust the QoS priorities for shutdown, if they exist.
 | 
						|
        if (StaticPrefs::threads_use_low_power_enabled() &&
 | 
						|
            StaticPrefs::
 | 
						|
                threads_lower_mainthread_priority_in_background_enabled()) {
 | 
						|
          SetMainThreadQoSPriority(nsIThread::QOS_PRIORITY_NORMAL);
 | 
						|
        }
 | 
						|
 | 
						|
        // Send a high priority announcement first. If this fails, SendShutdown
 | 
						|
        // will also fail.
 | 
						|
        Unused << SendShutdownConfirmedHP();
 | 
						|
        // Send the definite message with normal priority.
 | 
						|
        if (SendShutdown()) {
 | 
						|
          MaybeLogBlockShutdownDiagnostics(
 | 
						|
              this, "ShutDownProcess: Sent shutdown message.", __FILE__,
 | 
						|
              __LINE__);
 | 
						|
          mShutdownPending = true;
 | 
						|
          // We start the kill timer only after we asked our process to
 | 
						|
          // shutdown.
 | 
						|
          StartForceKillTimer();
 | 
						|
          result = true;
 | 
						|
        } else {
 | 
						|
          MaybeLogBlockShutdownDiagnostics(
 | 
						|
              this, "ShutDownProcess: !!! Send shutdown message failed! !!!",
 | 
						|
              __FILE__, __LINE__);
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        MaybeLogBlockShutdownDiagnostics(
 | 
						|
            this, "ShutDownProcess: !!! !CanSend !!!", __FILE__, __LINE__);
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      MaybeLogBlockShutdownDiagnostics(
 | 
						|
          this, "ShutDownProcess: Shutdown already pending.", __FILE__,
 | 
						|
          __LINE__);
 | 
						|
 | 
						|
      result = true;
 | 
						|
    }
 | 
						|
    // If call was not successful, the channel must have been broken
 | 
						|
    // somehow, and we will clean up the error in ActorDestroy.
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  using mozilla::dom::quota::QuotaManagerService;
 | 
						|
 | 
						|
  if (QuotaManagerService* qms = QuotaManagerService::GetOrCreate()) {
 | 
						|
    qms->AbortOperationsForProcess(mChildID);
 | 
						|
  }
 | 
						|
 | 
						|
  if (aMethod == CLOSE_CHANNEL) {
 | 
						|
    if (!mCalledClose) {
 | 
						|
      MaybeLogBlockShutdownDiagnostics(
 | 
						|
          this, "ShutDownProcess: Closing channel.", __FILE__, __LINE__);
 | 
						|
      // Close() can only be called once: It kicks off the destruction sequence.
 | 
						|
      mCalledClose = true;
 | 
						|
      Close();
 | 
						|
    }
 | 
						|
    result = true;
 | 
						|
  }
 | 
						|
 | 
						|
  // A ContentParent object might not get freed until after XPCOM shutdown has
 | 
						|
  // shut down the cycle collector.  But by then it's too late to release any
 | 
						|
  // CC'ed objects, so we need to null them out here, while we still can.  See
 | 
						|
  // bug 899761.
 | 
						|
  ShutDownMessageManager();
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvNotifyShutdownSuccess() {
 | 
						|
  if (!mShutdownPending) {
 | 
						|
    return IPC_FAIL(this, "RecvNotifyShutdownSuccess without mShutdownPending");
 | 
						|
  }
 | 
						|
 | 
						|
  mIsNotifiedShutdownSuccess = true;
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvFinishShutdown() {
 | 
						|
  if (!mShutdownPending) {
 | 
						|
    return IPC_FAIL(this, "RecvFinishShutdown without mShutdownPending");
 | 
						|
  }
 | 
						|
 | 
						|
  // At this point, we already called ShutDownProcess once with
 | 
						|
  // SEND_SHUTDOWN_MESSAGE. To actually close the channel, we call
 | 
						|
  // ShutDownProcess again with CLOSE_CHANNEL.
 | 
						|
  if (mCalledClose) {
 | 
						|
    MaybeLogBlockShutdownDiagnostics(
 | 
						|
        this, "RecvFinishShutdown: Channel already closed.", __FILE__,
 | 
						|
        __LINE__);
 | 
						|
  }
 | 
						|
 | 
						|
  ShutDownProcess(CLOSE_CHANNEL);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::ShutDownMessageManager() {
 | 
						|
  if (!mMessageManager) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  mMessageManager->SetOsPid(-1);
 | 
						|
  mMessageManager->Disconnect();
 | 
						|
  mMessageManager = nullptr;
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::AddToPool(nsTArray<ContentParent*>& aPool) {
 | 
						|
  MOZ_DIAGNOSTIC_ASSERT(!mIsInPool);
 | 
						|
  AssertAlive();
 | 
						|
  MOZ_DIAGNOSTIC_ASSERT(!mCalledKillHard);
 | 
						|
  aPool.AppendElement(this);
 | 
						|
  mIsInPool = true;
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::RemoveFromPool(nsTArray<ContentParent*>& aPool) {
 | 
						|
  MOZ_DIAGNOSTIC_ASSERT(mIsInPool);
 | 
						|
  aPool.RemoveElement(this);
 | 
						|
  mIsInPool = false;
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::AssertNotInPool() {
 | 
						|
  MOZ_RELEASE_ASSERT(!mIsInPool);
 | 
						|
 | 
						|
  MOZ_RELEASE_ASSERT(sRecycledE10SProcess != this);
 | 
						|
  MOZ_RELEASE_ASSERT(!sBrowserContentParents ||
 | 
						|
                     !sBrowserContentParents->Contains(mRemoteType) ||
 | 
						|
                     !sBrowserContentParents->Get(mRemoteType)->Contains(this));
 | 
						|
 | 
						|
  for (const auto& group : mGroups) {
 | 
						|
    MOZ_RELEASE_ASSERT(group->GetHostProcess(mRemoteType) != this,
 | 
						|
                       "still a host process for one of our groups?");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::AssertAlive() {
 | 
						|
  MOZ_DIAGNOSTIC_ASSERT(!mNotifiedImpendingShutdownOnTabWillDestroy);
 | 
						|
  MOZ_DIAGNOSTIC_ASSERT(!mIsSignaledImpendingShutdown);
 | 
						|
  MOZ_DIAGNOSTIC_ASSERT(!IsDead());
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::RemoveFromList() {
 | 
						|
  if (!mIsInPool) {
 | 
						|
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | 
						|
    AssertNotInPool();
 | 
						|
#endif
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // Ensure that this BrowsingContextGroup is no longer used to host new
 | 
						|
  // documents from any associated BrowsingContextGroups. It may become a host
 | 
						|
  // again in the future, if it is restored to the pool.
 | 
						|
  for (const auto& group : mGroups) {
 | 
						|
    group->RemoveHostProcess(this);
 | 
						|
  }
 | 
						|
 | 
						|
  StopRecyclingE10SOnly(/* aForeground */ false);
 | 
						|
 | 
						|
  if (sBrowserContentParents) {
 | 
						|
    if (auto entry = sBrowserContentParents->Lookup(mRemoteType)) {
 | 
						|
      const auto& contentParents = entry.Data();
 | 
						|
      RemoveFromPool(*contentParents);
 | 
						|
      if (contentParents->IsEmpty()) {
 | 
						|
        entry.Remove();
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (sBrowserContentParents->IsEmpty()) {
 | 
						|
      delete sBrowserContentParents;
 | 
						|
      sBrowserContentParents = nullptr;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::MarkAsDead() {
 | 
						|
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
 | 
						|
          ("Marking ContentProcess %p as dead", this));
 | 
						|
  MOZ_DIAGNOSTIC_ASSERT(!sInProcessSelector);
 | 
						|
  RemoveFromList();
 | 
						|
 | 
						|
  // Flag shutdown has started for us to our threadsafe handle.
 | 
						|
  {
 | 
						|
    // Depending on how we get here, the lock might or might not be set.
 | 
						|
    RecursiveMutexAutoLock lock(mThreadsafeHandle->mMutex);
 | 
						|
 | 
						|
    mThreadsafeHandle->mShutdownStarted = true;
 | 
						|
  }
 | 
						|
 | 
						|
  // Prevent this process from being re-used.
 | 
						|
  PreallocatedProcessManager::Erase(this);
 | 
						|
  StopRecyclingE10SOnly(false);
 | 
						|
 | 
						|
#if defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_PROFILE_GENERATE)
 | 
						|
  if (IsAlive()) {
 | 
						|
    // We're intentionally killing the content process at this point to ensure
 | 
						|
    // that we never have a "dead" content process sitting around and occupying
 | 
						|
    // an Android Service.
 | 
						|
    //
 | 
						|
    // The exception is in MOZ_PROFILE_GENERATE builds where we must allow the
 | 
						|
    // process to shutdown cleanly so that profile data can be dumped. This is
 | 
						|
    // okay as we will not reach our process limit during the profile run.
 | 
						|
    nsCOMPtr<nsIEventTarget> launcherThread(GetIPCLauncher());
 | 
						|
    MOZ_ASSERT(launcherThread);
 | 
						|
 | 
						|
    auto procType = java::GeckoProcessType::CONTENT();
 | 
						|
    auto selector =
 | 
						|
        java::GeckoProcessManager::Selector::New(procType, OtherPid());
 | 
						|
 | 
						|
    launcherThread->Dispatch(NS_NewRunnableFunction(
 | 
						|
        "ContentParent::MarkAsDead",
 | 
						|
        [selector =
 | 
						|
             java::GeckoProcessManager::Selector::GlobalRef(selector)]() {
 | 
						|
          java::GeckoProcessManager::ShutdownProcess(selector);
 | 
						|
        }));
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  if (mScriptableHelper) {
 | 
						|
    static_cast<ScriptableCPInfo*>(mScriptableHelper.get())->ProcessDied();
 | 
						|
    mScriptableHelper = nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  mLifecycleState = LifecycleState::DEAD;
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::ProcessingError(Result aCode, const char* aReason) {
 | 
						|
  if (MsgDropped == aCode) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  // Other errors are big deals.
 | 
						|
#ifndef FUZZING
 | 
						|
  KillHard(aReason);
 | 
						|
#endif
 | 
						|
  if (CanSend()) {
 | 
						|
    GetIPCChannel()->InduceConnectionError();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::ActorDestroy(ActorDestroyReason why) {
 | 
						|
#ifdef FUZZING_SNAPSHOT
 | 
						|
  MOZ_FUZZING_IPC_DROP_PEER("ContentParent::ActorDestroy");
 | 
						|
#endif
 | 
						|
 | 
						|
  // Gather process lifetime telemetry.
 | 
						|
  if (StringBeginsWith(mRemoteType, WEB_REMOTE_TYPE) ||
 | 
						|
      mRemoteType == FILE_REMOTE_TYPE || mRemoteType == EXTENSION_REMOTE_TYPE) {
 | 
						|
    TimeDuration runtime = TimeStamp::Now() - mActivateTS;
 | 
						|
    Telemetry::Accumulate(Telemetry::PROCESS_LIFETIME,
 | 
						|
                          uint64_t(runtime.ToSeconds()));
 | 
						|
  }
 | 
						|
 | 
						|
  if (mSendShutdownTimer) {
 | 
						|
    mSendShutdownTimer->Cancel();
 | 
						|
    mSendShutdownTimer = nullptr;
 | 
						|
  }
 | 
						|
  if (mForceKillTimer) {
 | 
						|
    mForceKillTimer->Cancel();
 | 
						|
    mForceKillTimer = nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  // Signal shutdown completion regardless of error state, so we can
 | 
						|
  // finish waiting in the xpcom-shutdown/profile-before-change observer.
 | 
						|
  RemoveShutdownBlockers();
 | 
						|
 | 
						|
  if (mHangMonitorActor) {
 | 
						|
    ProcessHangMonitor::RemoveProcess(mHangMonitorActor);
 | 
						|
    mHangMonitorActor = nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get();
 | 
						|
  if (fss) {
 | 
						|
    fss->Forget(ChildID());
 | 
						|
  }
 | 
						|
 | 
						|
  if (why == NormalShutdown && !mCalledClose) {
 | 
						|
    // If we shut down normally but haven't called Close, assume somebody
 | 
						|
    // else called Close on us. In that case, we still need to call
 | 
						|
    // ShutDownProcess below to perform other necessary clean up.
 | 
						|
    mCalledClose = true;
 | 
						|
  }
 | 
						|
 | 
						|
  // Make sure we always clean up.
 | 
						|
  ShutDownProcess(CLOSE_CHANNEL);
 | 
						|
 | 
						|
  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
 | 
						|
  if (obs) {
 | 
						|
    size_t length = ArrayLength(sObserverTopics);
 | 
						|
    for (size_t i = 0; i < length; ++i) {
 | 
						|
      obs->RemoveObserver(static_cast<nsIObserver*>(this), sObserverTopics[i]);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // remove the global remote preferences observers
 | 
						|
  Preferences::RemoveObserver(this, "");
 | 
						|
  gfxVars::RemoveReceiver(this);
 | 
						|
 | 
						|
  if (GPUProcessManager* gpu = GPUProcessManager::Get()) {
 | 
						|
    // Note: the manager could have shutdown already.
 | 
						|
    gpu->RemoveListener(this);
 | 
						|
  }
 | 
						|
 | 
						|
  RecvRemoveGeolocationListener();
 | 
						|
 | 
						|
  // Destroy our JSProcessActors, and reject any pending queries.
 | 
						|
  JSActorDidDestroy();
 | 
						|
 | 
						|
  if (obs) {
 | 
						|
    RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
 | 
						|
 | 
						|
    props->SetPropertyAsUint64(u"childID"_ns, mChildID);
 | 
						|
 | 
						|
    if (AbnormalShutdown == why) {
 | 
						|
      Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT, "content"_ns,
 | 
						|
                            1);
 | 
						|
 | 
						|
      props->SetPropertyAsBool(u"abnormal"_ns, true);
 | 
						|
 | 
						|
      nsAutoString dumpID;
 | 
						|
      // There's a window in which child processes can crash
 | 
						|
      // after IPC is established, but before a crash reporter
 | 
						|
      // is created.
 | 
						|
      if (mCrashReporter) {
 | 
						|
        // if mCreatedPairedMinidumps is true, we've already generated
 | 
						|
        // parent/child dumps for desktop crashes.
 | 
						|
        if (!mCreatedPairedMinidumps) {
 | 
						|
#if defined(XP_MACOSX)
 | 
						|
          RefPtr<nsAvailableMemoryWatcherBase> memWatcher;
 | 
						|
          memWatcher = nsAvailableMemoryWatcherBase::GetSingleton();
 | 
						|
          memWatcher->AddChildAnnotations(mCrashReporter);
 | 
						|
#endif
 | 
						|
 | 
						|
          mCrashReporter->GenerateCrashReport(OtherPid());
 | 
						|
        }
 | 
						|
 | 
						|
        if (mCrashReporter->HasMinidump()) {
 | 
						|
          dumpID = mCrashReporter->MinidumpID();
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        HandleOrphanedMinidump(&dumpID);
 | 
						|
      }
 | 
						|
 | 
						|
      if (!dumpID.IsEmpty()) {
 | 
						|
        props->SetPropertyAsAString(u"dumpID"_ns, dumpID);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    nsAutoString cpId;
 | 
						|
    cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
 | 
						|
    obs->NotifyObservers((nsIPropertyBag2*)props, "ipc:content-shutdown",
 | 
						|
                         cpId.get());
 | 
						|
  }
 | 
						|
 | 
						|
  // Remove any and all idle listeners.
 | 
						|
  if (mIdleListeners.Length() > 0) {
 | 
						|
    nsCOMPtr<nsIUserIdleService> idleService =
 | 
						|
        do_GetService("@mozilla.org/widget/useridleservice;1");
 | 
						|
    if (idleService) {
 | 
						|
      RefPtr<ParentIdleListener> listener;
 | 
						|
      for (const auto& lentry : mIdleListeners) {
 | 
						|
        listener = static_cast<ParentIdleListener*>(lentry.get());
 | 
						|
        idleService->RemoveIdleObserver(listener, listener->mTime);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    mIdleListeners.Clear();
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
 | 
						|
          ("destroying Subprocess in ActorDestroy: ContentParent %p "
 | 
						|
           "mSubprocess %p handle %" PRIuPTR,
 | 
						|
           this, mSubprocess,
 | 
						|
           mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
 | 
						|
  // FIXME (bug 1520997): does this really need an additional dispatch?
 | 
						|
  if (GetCurrentSerialEventTarget()) {
 | 
						|
    GetCurrentSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
 | 
						|
        "DelayedDeleteSubprocessRunnable", [subprocess = mSubprocess] {
 | 
						|
          MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
                  ("destroyed Subprocess in ActorDestroy: Subprocess %p handle "
 | 
						|
                   "%" PRIuPTR,
 | 
						|
                   subprocess,
 | 
						|
                   subprocess ? (uintptr_t)subprocess->GetChildProcessHandle()
 | 
						|
                              : -1));
 | 
						|
          subprocess->Destroy();
 | 
						|
        }));
 | 
						|
  }
 | 
						|
  mSubprocess = nullptr;
 | 
						|
 | 
						|
  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
 | 
						|
  if (cpm) {
 | 
						|
    cpm->RemoveContentProcess(this->ChildID());
 | 
						|
  }
 | 
						|
 | 
						|
  if (mDriverCrashGuard) {
 | 
						|
    mDriverCrashGuard->NotifyCrashed();
 | 
						|
  }
 | 
						|
 | 
						|
  // Unregister all the BlobURLs registered by the ContentChild.
 | 
						|
  for (uint32_t i = 0; i < mBlobURLs.Length(); ++i) {
 | 
						|
    BlobURLProtocolHandler::RemoveDataEntry(mBlobURLs[i]);
 | 
						|
  }
 | 
						|
 | 
						|
  mBlobURLs.Clear();
 | 
						|
 | 
						|
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | 
						|
  AssertNotInPool();
 | 
						|
#endif
 | 
						|
 | 
						|
  // As this process is going away, ensure that every BrowsingContext hosted by
 | 
						|
  // it has been detached, and every BrowsingContextGroup has been fully
 | 
						|
  // unsubscribed.
 | 
						|
  BrowsingContext::DiscardFromContentParent(this);
 | 
						|
 | 
						|
  const nsTHashSet<RefPtr<BrowsingContextGroup>> groups = std::move(mGroups);
 | 
						|
  for (const auto& group : groups) {
 | 
						|
    group->Unsubscribe(this);
 | 
						|
  }
 | 
						|
  MOZ_DIAGNOSTIC_ASSERT(mGroups.IsEmpty());
 | 
						|
 | 
						|
  mPendingLoadStates.Clear();
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::TryToRecycleE10SOnly() {
 | 
						|
  // Only try to recycle "web" content processes, as other remote types are
 | 
						|
  // generally more unique, and cannot be effectively re-used. This is disabled
 | 
						|
  // with Fission, as "web" content processes are no longer frequently used.
 | 
						|
  //
 | 
						|
  // Disabling the process pre-allocator will also disable process recycling,
 | 
						|
  // allowing for more consistent process counts under testing.
 | 
						|
  if (mRemoteType != DEFAULT_REMOTE_TYPE || mozilla::FissionAutostart() ||
 | 
						|
      !PreallocatedProcessManager::Enabled()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // This life time check should be replaced by a memory health check (memory
 | 
						|
  // usage + fragmentation).
 | 
						|
 | 
						|
  // Note that this is specifically to help with edge cases that rapidly
 | 
						|
  // create-and-destroy processes
 | 
						|
  const double kMaxLifeSpan = 5;
 | 
						|
  MOZ_LOG(
 | 
						|
      ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
      ("TryToRecycle ContentProcess %p (%u) with lifespan %f seconds", this,
 | 
						|
       (unsigned int)ChildID(), (TimeStamp::Now() - mActivateTS).ToSeconds()));
 | 
						|
 | 
						|
  if (mCalledKillHard || !IsAlive() ||
 | 
						|
      (TimeStamp::Now() - mActivateTS).ToSeconds() > kMaxLifeSpan) {
 | 
						|
    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
            ("TryToRecycle did not recycle %p", this));
 | 
						|
 | 
						|
    // It's possible that the process was already cached, and we're being called
 | 
						|
    // from a different path, and we're now past kMaxLifeSpan (or some other).
 | 
						|
    // Ensure that if we're going to kill this process we don't recycle it.
 | 
						|
    StopRecyclingE10SOnly(/* aForeground */ false);
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!sRecycledE10SProcess) {
 | 
						|
    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
            ("TryToRecycle began recycling %p", this));
 | 
						|
    sRecycledE10SProcess = this;
 | 
						|
 | 
						|
    ProcessPriorityManager::SetProcessPriority(this,
 | 
						|
                                               PROCESS_PRIORITY_BACKGROUND);
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  if (sRecycledE10SProcess == this) {
 | 
						|
    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
            ("TryToRecycle continue recycling %p", this));
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  // Some other process is already being recycled, just shut this one down.
 | 
						|
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
          ("TryToRecycle did not recycle %p (already recycling %p)", this,
 | 
						|
           sRecycledE10SProcess.get()));
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::StopRecyclingE10SOnly(bool aForeground) {
 | 
						|
  if (sRecycledE10SProcess != this) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  sRecycledE10SProcess = nullptr;
 | 
						|
  if (aForeground) {
 | 
						|
    ProcessPriorityManager::SetProcessPriority(this,
 | 
						|
                                               PROCESS_PRIORITY_FOREGROUND);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::HasActiveWorker() {
 | 
						|
  // If we have active workers, we need to stay alive.
 | 
						|
  {
 | 
						|
    // Most of the times we'll get here with the mutex acquired, but still.
 | 
						|
    RecursiveMutexAutoLock lock(mThreadsafeHandle->mMutex);
 | 
						|
    if (mThreadsafeHandle->mRemoteWorkerActorCount) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::ShouldKeepProcessAlive() {
 | 
						|
  if (HasActiveWorker()) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  if (mNumKeepaliveCalls > 0) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  if (IsLaunching()) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  // If we have already been marked as dead, don't prevent shutdown.
 | 
						|
  if (IsDead()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // If everything is going down, there is no need to keep us alive, neither.
 | 
						|
  if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!sBrowserContentParents) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  auto* contentParents = sBrowserContentParents->Get(mRemoteType);
 | 
						|
  if (!contentParents) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // We might want to keep some content processes alive for performance reasons.
 | 
						|
  // e.g. test runs and privileged content process for some about: pages.
 | 
						|
  // We don't want to alter behavior if the pref is not set, so default to 0.
 | 
						|
  int32_t processesToKeepAlive = 0;
 | 
						|
 | 
						|
  nsAutoCString keepAlivePref("dom.ipc.keepProcessesAlive.");
 | 
						|
 | 
						|
  if (StringBeginsWith(mRemoteType, FISSION_WEB_REMOTE_TYPE) &&
 | 
						|
      xpc::IsInAutomation()) {
 | 
						|
    keepAlivePref.Append(FISSION_WEB_REMOTE_TYPE);
 | 
						|
    keepAlivePref.AppendLiteral(".perOrigin");
 | 
						|
  } else {
 | 
						|
    keepAlivePref.Append(mRemoteType);
 | 
						|
  }
 | 
						|
  if (NS_FAILED(
 | 
						|
          Preferences::GetInt(keepAlivePref.get(), &processesToKeepAlive))) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  int32_t numberOfAliveProcesses = contentParents->Length();
 | 
						|
 | 
						|
  return numberOfAliveProcesses <= processesToKeepAlive;
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::NotifyTabDestroying() {
 | 
						|
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
          ("NotifyTabDestroying %p:", this));
 | 
						|
  // There can be more than one PBrowser for a given app process
 | 
						|
  // because of popup windows.  PBrowsers can also destroy
 | 
						|
  // concurrently.  When all the PBrowsers are destroying, kick off
 | 
						|
  // another task to ensure the child process *really* shuts down,
 | 
						|
  // even if the PBrowsers themselves never finish destroying.
 | 
						|
  ++mNumDestroyingTabs;
 | 
						|
 | 
						|
  /**
 | 
						|
   * We intentionally skip this code on Android:
 | 
						|
   * 1. Android has a fixed upper bound on the number of content processes, so
 | 
						|
   *    we prefer to re-use them whenever possible (as opposed to letting an
 | 
						|
   *    old process wind down while we launch a new one).
 | 
						|
   * 2. GeckoView always hard-kills content processes (and if it does not,
 | 
						|
   *    Android itself will), so we don't concern ourselves with the ForceKill
 | 
						|
   *    timer either.
 | 
						|
   */
 | 
						|
#if !defined(MOZ_WIDGET_ANDROID)
 | 
						|
  MaybeBeginShutDown(/* aExpectedBrowserCount */ mNumDestroyingTabs,
 | 
						|
                     /* aSendShutDown */ false);
 | 
						|
#endif  // !defined(MOZ_WIDGET_ANDROID)
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::AddKeepAlive() {
 | 
						|
  AssertAlive();
 | 
						|
  // Something wants to keep this content process alive.
 | 
						|
  ++mNumKeepaliveCalls;
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::RemoveKeepAlive() {
 | 
						|
  MOZ_DIAGNOSTIC_ASSERT(mNumKeepaliveCalls > 0);
 | 
						|
  --mNumKeepaliveCalls;
 | 
						|
 | 
						|
  MaybeBeginShutDown();
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::StartSendShutdownTimer() {
 | 
						|
  if (mSendShutdownTimer || !CanSend()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  uint32_t timeoutSecs = StaticPrefs::dom_ipc_tabs_shutdownTimeoutSecs();
 | 
						|
  if (timeoutSecs > 0) {
 | 
						|
    NS_NewTimerWithFuncCallback(getter_AddRefs(mSendShutdownTimer),
 | 
						|
                                ContentParent::SendShutdownTimerCallback, this,
 | 
						|
                                timeoutSecs * 1000, nsITimer::TYPE_ONE_SHOT,
 | 
						|
                                "dom::ContentParent::StartSendShutdownTimer");
 | 
						|
    MOZ_ASSERT(mSendShutdownTimer);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::StartForceKillTimer() {
 | 
						|
  if (mForceKillTimer || !CanSend()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  uint32_t timeoutSecs = StaticPrefs::dom_ipc_tabs_shutdownTimeoutSecs();
 | 
						|
  if (timeoutSecs > 0) {
 | 
						|
    NS_NewTimerWithFuncCallback(getter_AddRefs(mForceKillTimer),
 | 
						|
                                ContentParent::ForceKillTimerCallback, this,
 | 
						|
                                timeoutSecs * 1000, nsITimer::TYPE_ONE_SHOT,
 | 
						|
                                "dom::ContentParent::StartForceKillTimer");
 | 
						|
    MOZ_ASSERT(mForceKillTimer);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::NotifyTabDestroyed(const TabId& aTabId,
 | 
						|
                                       bool aNotifiedDestroying) {
 | 
						|
  if (aNotifiedDestroying) {
 | 
						|
    --mNumDestroyingTabs;
 | 
						|
  }
 | 
						|
 | 
						|
  nsTArray<PContentPermissionRequestParent*> parentArray =
 | 
						|
      nsContentPermissionUtils::GetContentPermissionRequestParentById(aTabId);
 | 
						|
 | 
						|
  // Need to close undeleted ContentPermissionRequestParents before tab is
 | 
						|
  // closed.
 | 
						|
  for (auto& permissionRequestParent : parentArray) {
 | 
						|
    Unused << PContentPermissionRequestParent::Send__delete__(
 | 
						|
        permissionRequestParent);
 | 
						|
  }
 | 
						|
 | 
						|
  // There can be more than one PBrowser for a given app process
 | 
						|
  // because of popup windows.  When the last one closes, shut
 | 
						|
  // us down.
 | 
						|
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
 | 
						|
          ("NotifyTabDestroyed %p", this));
 | 
						|
 | 
						|
  MaybeBeginShutDown();
 | 
						|
}
 | 
						|
 | 
						|
TestShellParent* ContentParent::CreateTestShell() {
 | 
						|
  RefPtr<TestShellParent> actor = new TestShellParent();
 | 
						|
  if (!SendPTestShellConstructor(actor)) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  return actor;
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::DestroyTestShell(TestShellParent* aTestShell) {
 | 
						|
  return PTestShellParent::Send__delete__(aTestShell);
 | 
						|
}
 | 
						|
 | 
						|
TestShellParent* ContentParent::GetTestShellSingleton() {
 | 
						|
  PTestShellParent* p = LoneManagedOrNullAsserts(ManagedPTestShellParent());
 | 
						|
  return static_cast<TestShellParent*>(p);
 | 
						|
}
 | 
						|
 | 
						|
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
 | 
						|
// Append the sandbox command line parameters that are not static. i.e.,
 | 
						|
// parameters that can be different for different child processes.
 | 
						|
void ContentParent::AppendDynamicSandboxParams(
 | 
						|
    std::vector<std::string>& aArgs) {
 | 
						|
  // For file content processes
 | 
						|
  if (GetRemoteType() == FILE_REMOTE_TYPE) {
 | 
						|
    MacSandboxInfo::AppendFileAccessParam(aArgs, true);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Generate the static sandbox command line parameters and store
 | 
						|
// them in the provided params vector to be used each time a new
 | 
						|
// content process is launched.
 | 
						|
static void CacheSandboxParams(std::vector<std::string>& aCachedParams) {
 | 
						|
  // This must only be called once and we should
 | 
						|
  // be starting with an empty list of parameters.
 | 
						|
  MOZ_ASSERT(aCachedParams.empty());
 | 
						|
 | 
						|
  MacSandboxInfo info;
 | 
						|
  info.type = MacSandboxType_Content;
 | 
						|
  info.level = GetEffectiveContentSandboxLevel();
 | 
						|
 | 
						|
  // Sandbox logging
 | 
						|
  if (Preferences::GetBool("security.sandbox.logging.enabled") ||
 | 
						|
      PR_GetEnv("MOZ_SANDBOX_LOGGING")) {
 | 
						|
    info.shouldLog = true;
 | 
						|
  }
 | 
						|
 | 
						|
  // Audio access
 | 
						|
  if (!StaticPrefs::media_cubeb_sandbox()) {
 | 
						|
    info.hasAudio = true;
 | 
						|
  }
 | 
						|
 | 
						|
  // Window server access. If the disconnect-windowserver pref is not
 | 
						|
  // "true" or out-of-process WebGL is not enabled, allow window server
 | 
						|
  // access in the sandbox policy.
 | 
						|
  if (!Preferences::GetBool(
 | 
						|
          "security.sandbox.content.mac.disconnect-windowserver") ||
 | 
						|
      !Preferences::GetBool("webgl.out-of-process")) {
 | 
						|
    info.hasWindowServer = true;
 | 
						|
  }
 | 
						|
 | 
						|
  // .app path (normalized)
 | 
						|
  nsAutoCString appPath;
 | 
						|
  if (!nsMacUtilsImpl::GetAppPath(appPath)) {
 | 
						|
    MOZ_CRASH("Failed to get app dir paths");
 | 
						|
  }
 | 
						|
  info.appPath = appPath.get();
 | 
						|
 | 
						|
  // TESTING_READ_PATH1
 | 
						|
  nsAutoCString testingReadPath1;
 | 
						|
  Preferences::GetCString("security.sandbox.content.mac.testing_read_path1",
 | 
						|
                          testingReadPath1);
 | 
						|
  if (!testingReadPath1.IsEmpty()) {
 | 
						|
    info.testingReadPath1 = testingReadPath1.get();
 | 
						|
  }
 | 
						|
 | 
						|
  // TESTING_READ_PATH2
 | 
						|
  nsAutoCString testingReadPath2;
 | 
						|
  Preferences::GetCString("security.sandbox.content.mac.testing_read_path2",
 | 
						|
                          testingReadPath2);
 | 
						|
  if (!testingReadPath2.IsEmpty()) {
 | 
						|
    info.testingReadPath2 = testingReadPath2.get();
 | 
						|
  }
 | 
						|
 | 
						|
  // TESTING_READ_PATH3, TESTING_READ_PATH4. In non-packaged builds,
 | 
						|
  // these are used to whitelist the repo dir and object dir respectively.
 | 
						|
  nsresult rv;
 | 
						|
  if (!mozilla::IsPackagedBuild()) {
 | 
						|
    // Repo dir
 | 
						|
    nsCOMPtr<nsIFile> repoDir;
 | 
						|
    rv = nsMacUtilsImpl::GetRepoDir(getter_AddRefs(repoDir));
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      MOZ_CRASH("Failed to get path to repo dir");
 | 
						|
    }
 | 
						|
    nsCString repoDirPath;
 | 
						|
    Unused << repoDir->GetNativePath(repoDirPath);
 | 
						|
    info.testingReadPath3 = repoDirPath.get();
 | 
						|
 | 
						|
    // Object dir
 | 
						|
    nsCOMPtr<nsIFile> objDir;
 | 
						|
    rv = nsMacUtilsImpl::GetObjDir(getter_AddRefs(objDir));
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      MOZ_CRASH("Failed to get path to build object dir");
 | 
						|
    }
 | 
						|
    nsCString objDirPath;
 | 
						|
    Unused << objDir->GetNativePath(objDirPath);
 | 
						|
    info.testingReadPath4 = objDirPath.get();
 | 
						|
  }
 | 
						|
 | 
						|
  // DEBUG_WRITE_DIR
 | 
						|
#  ifdef DEBUG
 | 
						|
  // For bloat/leak logging or when a content process dies intentionally
 | 
						|
  // (|NoteIntentionalCrash|) for tests, it wants to log that it did this.
 | 
						|
  // Allow writing to this location.
 | 
						|
  nsAutoCString bloatLogDirPath;
 | 
						|
  if (NS_SUCCEEDED(nsMacUtilsImpl::GetBloatLogDir(bloatLogDirPath))) {
 | 
						|
    info.debugWriteDir = bloatLogDirPath.get();
 | 
						|
  }
 | 
						|
#  endif  // DEBUG
 | 
						|
 | 
						|
  info.AppendAsParams(aCachedParams);
 | 
						|
}
 | 
						|
 | 
						|
// Append sandboxing command line parameters.
 | 
						|
void ContentParent::AppendSandboxParams(std::vector<std::string>& aArgs) {
 | 
						|
  MOZ_ASSERT(sMacSandboxParams != nullptr);
 | 
						|
 | 
						|
  // An empty sMacSandboxParams indicates this is the
 | 
						|
  // first invocation and we don't have cached params yet.
 | 
						|
  if (sMacSandboxParams->empty()) {
 | 
						|
    CacheSandboxParams(*sMacSandboxParams);
 | 
						|
    MOZ_ASSERT(!sMacSandboxParams->empty());
 | 
						|
  }
 | 
						|
 | 
						|
  // Append cached arguments.
 | 
						|
  aArgs.insert(aArgs.end(), sMacSandboxParams->begin(),
 | 
						|
               sMacSandboxParams->end());
 | 
						|
 | 
						|
  // Append remaining arguments.
 | 
						|
  AppendDynamicSandboxParams(aArgs);
 | 
						|
}
 | 
						|
#endif  // XP_MACOSX && MOZ_SANDBOX
 | 
						|
 | 
						|
bool ContentParent::BeginSubprocessLaunch(ProcessPriority aPriority) {
 | 
						|
  AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess", OTHER);
 | 
						|
 | 
						|
  // Ensure we will not rush through our shutdown phases while launching.
 | 
						|
  // LaunchSubprocessReject will remove them in case of failure,
 | 
						|
  // otherwise ActorDestroy will take care.
 | 
						|
  AddShutdownBlockers();
 | 
						|
 | 
						|
  if (!ContentProcessManager::GetSingleton()) {
 | 
						|
    MOZ_ASSERT(false, "Unable to acquire ContentProcessManager singleton!");
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  std::vector<std::string> extraArgs;
 | 
						|
  geckoargs::sChildID.Put(mChildID, extraArgs);
 | 
						|
  geckoargs::sIsForBrowser.Put(IsForBrowser(), extraArgs);
 | 
						|
  geckoargs::sNotForBrowser.Put(!IsForBrowser(), extraArgs);
 | 
						|
 | 
						|
  // Prefs information is passed via anonymous shared memory to avoid bloating
 | 
						|
  // the command line.
 | 
						|
 | 
						|
  // Instantiate the pref serializer. It will be cleaned up in
 | 
						|
  // `LaunchSubprocessReject`/`LaunchSubprocessResolve`.
 | 
						|
  mPrefSerializer = MakeUnique<mozilla::ipc::SharedPreferenceSerializer>();
 | 
						|
  if (!mPrefSerializer->SerializeToSharedMemory(GeckoProcessType_Content,
 | 
						|
                                                GetRemoteType())) {
 | 
						|
    NS_WARNING("SharedPreferenceSerializer::SerializeToSharedMemory failed");
 | 
						|
    MarkAsDead();
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  mPrefSerializer->AddSharedPrefCmdLineArgs(*mSubprocess, extraArgs);
 | 
						|
 | 
						|
  // The JS engine does some computation during the initialization which can be
 | 
						|
  // shared across processes. We add command line arguments to pass a file
 | 
						|
  // handle and its content length, to minimize the startup time of content
 | 
						|
  // processes.
 | 
						|
  ::mozilla::ipc::ExportSharedJSInit(*mSubprocess, extraArgs);
 | 
						|
 | 
						|
  // Register ContentParent as an observer for changes to any pref
 | 
						|
  // whose prefix matches the empty string, i.e. all of them.  The
 | 
						|
  // observation starts here in order to capture pref updates that
 | 
						|
  // happen during async launch.
 | 
						|
  Preferences::AddStrongObserver(this, "");
 | 
						|
 | 
						|
  if (gSafeMode) {
 | 
						|
    geckoargs::sSafeMode.Put(extraArgs);
 | 
						|
  }
 | 
						|
 | 
						|
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
 | 
						|
  if (IsContentSandboxEnabled()) {
 | 
						|
    AppendSandboxParams(extraArgs);
 | 
						|
    mSubprocess->DisableOSActivityMode();
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  nsCString parentBuildID(mozilla::PlatformBuildID());
 | 
						|
  geckoargs::sParentBuildID.Put(parentBuildID.get(), extraArgs);
 | 
						|
 | 
						|
#ifdef MOZ_WIDGET_GTK
 | 
						|
  // This is X11-only pending a solution for WebGL in Wayland mode.
 | 
						|
  if (StaticPrefs::dom_ipc_avoid_gtk() && widget::GdkIsX11Display()) {
 | 
						|
    mSubprocess->SetEnv("MOZ_HEADLESS", "1");
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  mLaunchYieldTS = TimeStamp::Now();
 | 
						|
  return mSubprocess->AsyncLaunch(std::move(extraArgs));
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::LaunchSubprocessReject() {
 | 
						|
  NS_WARNING("failed to launch child in the parent");
 | 
						|
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
 | 
						|
          ("failed to launch child in the parent"));
 | 
						|
  // Now that communication with the child is complete, we can cleanup
 | 
						|
  // the preference serializer.
 | 
						|
  mPrefSerializer = nullptr;
 | 
						|
  if (mIsAPreallocBlocker) {
 | 
						|
    PreallocatedProcessManager::RemoveBlocker(mRemoteType, this);
 | 
						|
    mIsAPreallocBlocker = false;
 | 
						|
  }
 | 
						|
  MarkAsDead();
 | 
						|
  RemoveShutdownBlockers();
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::LaunchSubprocessResolve(bool aIsSync,
 | 
						|
                                            ProcessPriority aPriority) {
 | 
						|
  AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess::resolve", OTHER);
 | 
						|
 | 
						|
  if (mLaunchResolved) {
 | 
						|
    // We've already been called, return.
 | 
						|
    MOZ_ASSERT(sCreatedFirstContentProcess);
 | 
						|
    MOZ_ASSERT(!mPrefSerializer);
 | 
						|
    MOZ_ASSERT(mLifecycleState != LifecycleState::LAUNCHING);
 | 
						|
    return mLaunchResolvedOk;
 | 
						|
  }
 | 
						|
  mLaunchResolved = true;
 | 
						|
 | 
						|
  // Now that communication with the child is complete, we can cleanup
 | 
						|
  // the preference serializer.
 | 
						|
  mPrefSerializer = nullptr;
 | 
						|
 | 
						|
  const auto launchResumeTS = TimeStamp::Now();
 | 
						|
  if (profiler_thread_is_being_profiled_for_markers()) {
 | 
						|
    nsPrintfCString marker("Process start%s for %u",
 | 
						|
                           mIsAPreallocBlocker ? " (immediate)" : "",
 | 
						|
                           (unsigned int)ChildID());
 | 
						|
    PROFILER_MARKER_TEXT(
 | 
						|
        mIsAPreallocBlocker ? ProfilerString8View("Process Immediate Launch")
 | 
						|
                            : ProfilerString8View("Process Launch"),
 | 
						|
        DOM, MarkerTiming::Interval(mLaunchTS, launchResumeTS), marker);
 | 
						|
  }
 | 
						|
 | 
						|
  if (!sCreatedFirstContentProcess) {
 | 
						|
    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
 | 
						|
    obs->NotifyObservers(nullptr, "ipc:first-content-process-created", nullptr);
 | 
						|
    sCreatedFirstContentProcess = true;
 | 
						|
  }
 | 
						|
 | 
						|
  mSubprocess->TakeInitialEndpoint().Bind(this);
 | 
						|
 | 
						|
  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
 | 
						|
  if (!cpm) {
 | 
						|
    NS_WARNING("immediately shutting-down caused by our shutdown");
 | 
						|
    ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  cpm->AddContentProcess(this);
 | 
						|
 | 
						|
#ifdef MOZ_CODE_COVERAGE
 | 
						|
  Unused << SendShareCodeCoverageMutex(
 | 
						|
      CodeCoverageHandler::Get()->GetMutexHandle());
 | 
						|
#endif
 | 
						|
 | 
						|
  // We must be in the LAUNCHING state still. If we've somehow already been
 | 
						|
  // marked as DEAD, fail the process launch, and immediately begin tearing down
 | 
						|
  // the content process.
 | 
						|
  if (IsDead()) {
 | 
						|
    NS_WARNING("immediately shutting-down already-dead process");
 | 
						|
    ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  MOZ_ASSERT(mLifecycleState == LifecycleState::LAUNCHING);
 | 
						|
  mLifecycleState = LifecycleState::ALIVE;
 | 
						|
 | 
						|
  if (!InitInternal(aPriority)) {
 | 
						|
    NS_WARNING("failed to initialize child in the parent");
 | 
						|
    // We've already called Open() by this point, so we need to close the
 | 
						|
    // channel to avoid leaking the process.
 | 
						|
    ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  mHangMonitorActor = ProcessHangMonitor::AddProcess(this);
 | 
						|
 | 
						|
  // Set a reply timeout for CPOWs.
 | 
						|
  SetReplyTimeoutMs(StaticPrefs::dom_ipc_cpow_timeout());
 | 
						|
 | 
						|
  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
 | 
						|
  if (obs) {
 | 
						|
    nsAutoString cpId;
 | 
						|
    cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
 | 
						|
    obs->NotifyObservers(static_cast<nsIObserver*>(this),
 | 
						|
                         "ipc:content-initializing", cpId.get());
 | 
						|
  }
 | 
						|
 | 
						|
  Init();
 | 
						|
 | 
						|
  mLifecycleState = LifecycleState::INITIALIZED;
 | 
						|
 | 
						|
  if (aIsSync) {
 | 
						|
    Telemetry::AccumulateTimeDelta(Telemetry::CONTENT_PROCESS_SYNC_LAUNCH_MS,
 | 
						|
                                   mLaunchTS);
 | 
						|
  } else {
 | 
						|
    Telemetry::AccumulateTimeDelta(Telemetry::CONTENT_PROCESS_LAUNCH_TOTAL_MS,
 | 
						|
                                   mLaunchTS);
 | 
						|
 | 
						|
    Telemetry::Accumulate(
 | 
						|
        Telemetry::CONTENT_PROCESS_LAUNCH_MAINTHREAD_MS,
 | 
						|
        static_cast<uint32_t>(
 | 
						|
            ((mLaunchYieldTS - mLaunchTS) + (TimeStamp::Now() - launchResumeTS))
 | 
						|
                .ToMilliseconds()));
 | 
						|
  }
 | 
						|
 | 
						|
  mLaunchResolvedOk = true;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::LaunchSubprocessSync(
 | 
						|
    hal::ProcessPriority aInitialPriority) {
 | 
						|
  // We've started a sync content process launch.
 | 
						|
  Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC, 1);
 | 
						|
 | 
						|
  if (BeginSubprocessLaunch(aInitialPriority)) {
 | 
						|
    const bool ok = mSubprocess->WaitForProcessHandle();
 | 
						|
    if (ok && LaunchSubprocessResolve(/* aIsSync = */ true, aInitialPriority)) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  LaunchSubprocessReject();
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
RefPtr<ContentParent::LaunchPromise> ContentParent::LaunchSubprocessAsync(
 | 
						|
    hal::ProcessPriority aInitialPriority) {
 | 
						|
  // We've started an async content process launch.
 | 
						|
  Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC, 0);
 | 
						|
 | 
						|
  if (!BeginSubprocessLaunch(aInitialPriority)) {
 | 
						|
    // Launch aborted because of shutdown. Bailout.
 | 
						|
    LaunchSubprocessReject();
 | 
						|
    return LaunchPromise::CreateAndReject(NS_ERROR_ILLEGAL_DURING_SHUTDOWN,
 | 
						|
                                          __func__);
 | 
						|
  }
 | 
						|
 | 
						|
  // Otherwise, wait until the process is ready.
 | 
						|
  RefPtr<ProcessHandlePromise> ready = mSubprocess->WhenProcessHandleReady();
 | 
						|
  RefPtr<ContentParent> self = this;
 | 
						|
  mLaunchYieldTS = TimeStamp::Now();
 | 
						|
 | 
						|
  return ready->Then(
 | 
						|
      GetCurrentSerialEventTarget(), __func__,
 | 
						|
      [self, aInitialPriority](
 | 
						|
          const ProcessHandlePromise::ResolveOrRejectValue& aValue) {
 | 
						|
        if (aValue.IsResolve() &&
 | 
						|
            self->LaunchSubprocessResolve(/* aIsSync = */ false,
 | 
						|
                                          aInitialPriority)) {
 | 
						|
          return LaunchPromise::CreateAndResolve(self, __func__);
 | 
						|
        }
 | 
						|
        self->LaunchSubprocessReject();
 | 
						|
        return LaunchPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
 | 
						|
      });
 | 
						|
}
 | 
						|
 | 
						|
ContentParent::ContentParent(const nsACString& aRemoteType)
 | 
						|
    : mSubprocess(nullptr),
 | 
						|
      mLaunchTS(TimeStamp::Now()),
 | 
						|
      mLaunchYieldTS(mLaunchTS),
 | 
						|
      mActivateTS(mLaunchTS),
 | 
						|
      mIsAPreallocBlocker(false),
 | 
						|
      mRemoteType(aRemoteType),
 | 
						|
      mChildID(gContentChildID++),
 | 
						|
      mGeolocationWatchID(-1),
 | 
						|
      mThreadsafeHandle(
 | 
						|
          new ThreadsafeContentParentHandle(this, mChildID, mRemoteType)),
 | 
						|
      mNumDestroyingTabs(0),
 | 
						|
      mNumKeepaliveCalls(0),
 | 
						|
      mLifecycleState(LifecycleState::LAUNCHING),
 | 
						|
      mIsForBrowser(!mRemoteType.IsEmpty()),
 | 
						|
      mCalledClose(false),
 | 
						|
      mCalledKillHard(false),
 | 
						|
      mCreatedPairedMinidumps(false),
 | 
						|
      mShutdownPending(false),
 | 
						|
      mLaunchResolved(false),
 | 
						|
      mLaunchResolvedOk(false),
 | 
						|
      mIsRemoteInputEventQueueEnabled(false),
 | 
						|
      mIsInputPriorityEventEnabled(false),
 | 
						|
      mIsInPool(false),
 | 
						|
      mGMPCreated(false),
 | 
						|
      mClipboardContentAnalysisCreated(false),
 | 
						|
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | 
						|
      mBlockShutdownCalled(false),
 | 
						|
#endif
 | 
						|
      mHangMonitorActor(nullptr) {
 | 
						|
  mRemoteTypeIsolationPrincipal =
 | 
						|
      CreateRemoteTypeIsolationPrincipal(aRemoteType);
 | 
						|
 | 
						|
  // Insert ourselves into the global linked list of ContentParent objects.
 | 
						|
  if (!sContentParents) {
 | 
						|
    sContentParents = new LinkedList<ContentParent>();
 | 
						|
  }
 | 
						|
  sContentParents->insertBack(this);
 | 
						|
 | 
						|
  mMessageManager = nsFrameMessageManager::NewProcessMessageManager(true);
 | 
						|
 | 
						|
#if defined(XP_WIN)
 | 
						|
  // Request Windows message deferral behavior on our side of the PContent
 | 
						|
  // channel. Generally only applies to the situation where we get caught in
 | 
						|
  // a deadlock with the plugin process when sending CPOWs.
 | 
						|
  GetIPCChannel()->SetChannelFlags(
 | 
						|
      MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
 | 
						|
#endif
 | 
						|
 | 
						|
  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 | 
						|
  bool isFile = mRemoteType == FILE_REMOTE_TYPE;
 | 
						|
  mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content, isFile);
 | 
						|
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
 | 
						|
          ("CreateSubprocess: ContentParent %p mSubprocess %p handle %" PRIuPTR,
 | 
						|
           this, mSubprocess,
 | 
						|
           mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
 | 
						|
 | 
						|
  // This is safe to do in the constructor, as it doesn't take a strong
 | 
						|
  // reference.
 | 
						|
  mScriptableHelper = new ScriptableCPInfo(this);
 | 
						|
}
 | 
						|
 | 
						|
ContentParent::~ContentParent() {
 | 
						|
  if (mSendShutdownTimer) {
 | 
						|
    mSendShutdownTimer->Cancel();
 | 
						|
  }
 | 
						|
  if (mForceKillTimer) {
 | 
						|
    mForceKillTimer->Cancel();
 | 
						|
  }
 | 
						|
 | 
						|
  AssertIsOnMainThread();
 | 
						|
 | 
						|
  // Clear the weak reference from the threadsafe handle back to this actor.
 | 
						|
  mThreadsafeHandle->mWeakActor = nullptr;
 | 
						|
 | 
						|
  if (mIsAPreallocBlocker) {
 | 
						|
    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
            ("Removing blocker on ContentProcess destruction"));
 | 
						|
    PreallocatedProcessManager::RemoveBlocker(mRemoteType, this);
 | 
						|
    mIsAPreallocBlocker = false;
 | 
						|
  }
 | 
						|
 | 
						|
  // We should be removed from all these lists in ActorDestroy.
 | 
						|
  AssertNotInPool();
 | 
						|
 | 
						|
  // Normally mSubprocess is destroyed in ActorDestroy, but that won't
 | 
						|
  // happen if the process wasn't launched or if it failed to launch.
 | 
						|
  if (mSubprocess) {
 | 
						|
    MOZ_LOG(
 | 
						|
        ContentParent::GetLog(), LogLevel::Verbose,
 | 
						|
        ("DestroySubprocess: ContentParent %p mSubprocess %p handle %" PRIuPTR,
 | 
						|
         this, mSubprocess,
 | 
						|
         mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
 | 
						|
    mSubprocess->Destroy();
 | 
						|
  }
 | 
						|
 | 
						|
  // Make sure to clear the connection from `mScriptableHelper` if it hasn't
 | 
						|
  // been cleared yet.
 | 
						|
  if (mScriptableHelper) {
 | 
						|
    static_cast<ScriptableCPInfo*>(mScriptableHelper.get())->ProcessDied();
 | 
						|
    mScriptableHelper = nullptr;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::InitInternal(ProcessPriority aInitialPriority) {
 | 
						|
  // We can't access the locale service after shutdown has started. Since we
 | 
						|
  // can't init the process without it, and since we're going to be canceling
 | 
						|
  // whatever load attempt that initiated this process creation anyway, just
 | 
						|
  // bail out now if shutdown has already started.
 | 
						|
  if (PastShutdownPhase(ShutdownPhase::XPCOMShutdown)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  XPCOMInitData xpcomInit;
 | 
						|
 | 
						|
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
 | 
						|
          ("ContentParent::InitInternal: %p", (void*)this));
 | 
						|
  nsCOMPtr<nsIIOService> io(do_GetIOService());
 | 
						|
  MOZ_ASSERT(io, "No IO service?");
 | 
						|
  DebugOnly<nsresult> rv = io->GetOffline(&xpcomInit.isOffline());
 | 
						|
  MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting offline?");
 | 
						|
 | 
						|
  rv = io->GetConnectivity(&xpcomInit.isConnected());
 | 
						|
  MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting connectivity?");
 | 
						|
 | 
						|
  xpcomInit.captivePortalState() = nsICaptivePortalService::UNKNOWN;
 | 
						|
  nsCOMPtr<nsICaptivePortalService> cps =
 | 
						|
      do_GetService(NS_CAPTIVEPORTAL_CONTRACTID);
 | 
						|
  if (cps) {
 | 
						|
    cps->GetState(&xpcomInit.captivePortalState());
 | 
						|
  }
 | 
						|
 | 
						|
  if (StaticPrefs::fission_processProfileName()) {
 | 
						|
    nsCOMPtr<nsIToolkitProfileService> profileSvc =
 | 
						|
        do_GetService(NS_PROFILESERVICE_CONTRACTID);
 | 
						|
    if (profileSvc) {
 | 
						|
      nsCOMPtr<nsIToolkitProfile> currentProfile;
 | 
						|
      nsresult rv =
 | 
						|
          profileSvc->GetCurrentProfile(getter_AddRefs(currentProfile));
 | 
						|
      if (NS_SUCCEEDED(rv) && currentProfile) {
 | 
						|
        currentProfile->GetName(mProfile);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  nsIBidiKeyboard* bidi = nsContentUtils::GetBidiKeyboard();
 | 
						|
 | 
						|
  xpcomInit.isLangRTL() = false;
 | 
						|
  xpcomInit.haveBidiKeyboards() = false;
 | 
						|
  if (bidi) {
 | 
						|
    bidi->IsLangRTL(&xpcomInit.isLangRTL());
 | 
						|
    bidi->GetHaveBidiKeyboards(&xpcomInit.haveBidiKeyboards());
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<mozSpellChecker> spellChecker(mozSpellChecker::Create());
 | 
						|
  MOZ_ASSERT(spellChecker, "No spell checker?");
 | 
						|
 | 
						|
  spellChecker->GetDictionaryList(&xpcomInit.dictionaries());
 | 
						|
 | 
						|
  LocaleService::GetInstance()->GetAppLocalesAsBCP47(xpcomInit.appLocales());
 | 
						|
  LocaleService::GetInstance()->GetRequestedLocales(
 | 
						|
      xpcomInit.requestedLocales());
 | 
						|
 | 
						|
  L10nRegistry::GetParentProcessFileSourceDescriptors(
 | 
						|
      xpcomInit.l10nFileSources());
 | 
						|
 | 
						|
  nsCOMPtr<nsIClipboard> clipboard(
 | 
						|
      do_GetService("@mozilla.org/widget/clipboard;1"));
 | 
						|
  MOZ_ASSERT(clipboard, "No clipboard?");
 | 
						|
  MOZ_ASSERT(
 | 
						|
      clipboard->IsClipboardTypeSupported(nsIClipboard::kGlobalClipboard),
 | 
						|
      "We should always support the global clipboard.");
 | 
						|
 | 
						|
  xpcomInit.clipboardCaps().supportsSelectionClipboard() =
 | 
						|
      clipboard->IsClipboardTypeSupported(nsIClipboard::kSelectionClipboard);
 | 
						|
 | 
						|
  xpcomInit.clipboardCaps().supportsFindClipboard() =
 | 
						|
      clipboard->IsClipboardTypeSupported(nsIClipboard::kFindClipboard);
 | 
						|
 | 
						|
  xpcomInit.clipboardCaps().supportsSelectionCache() =
 | 
						|
      clipboard->IsClipboardTypeSupported(nsIClipboard::kSelectionCache);
 | 
						|
 | 
						|
  // Let's copy the domain policy from the parent to the child (if it's active).
 | 
						|
  StructuredCloneData initialData;
 | 
						|
  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
 | 
						|
  if (ssm) {
 | 
						|
    ssm->CloneDomainPolicy(&xpcomInit.domainPolicy());
 | 
						|
 | 
						|
    if (ParentProcessMessageManager* mm =
 | 
						|
            nsFrameMessageManager::sParentProcessManager) {
 | 
						|
      AutoJSAPI jsapi;
 | 
						|
      if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) {
 | 
						|
        MOZ_CRASH();
 | 
						|
      }
 | 
						|
      JS::Rooted<JS::Value> init(jsapi.cx());
 | 
						|
      // We'll crash on failure, so use a IgnoredErrorResult (which also
 | 
						|
      // auto-suppresses exceptions).
 | 
						|
      IgnoredErrorResult rv;
 | 
						|
      mm->GetInitialProcessData(jsapi.cx(), &init, rv);
 | 
						|
      if (NS_WARN_IF(rv.Failed())) {
 | 
						|
        MOZ_CRASH();
 | 
						|
      }
 | 
						|
 | 
						|
      initialData.Write(jsapi.cx(), init, rv);
 | 
						|
      if (NS_WARN_IF(rv.Failed())) {
 | 
						|
        MOZ_CRASH();
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  // This is only implemented (returns a non-empty list) by MacOSX and Linux
 | 
						|
  // at present.
 | 
						|
  SystemFontList fontList;
 | 
						|
  gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList);
 | 
						|
 | 
						|
  const FullLookAndFeel& lnf = *RemoteLookAndFeel::ExtractData();
 | 
						|
 | 
						|
  // If the shared fontlist is in use, collect its shmem block handles to pass
 | 
						|
  // to the child.
 | 
						|
  nsTArray<SharedMemoryHandle> sharedFontListBlocks;
 | 
						|
  gfxPlatformFontList::PlatformFontList()->ShareFontListToProcess(
 | 
						|
      &sharedFontListBlocks, OtherPid());
 | 
						|
 | 
						|
  // Content processes have no permission to access profile directory, so we
 | 
						|
  // send the file URL instead.
 | 
						|
  auto* sheetCache = GlobalStyleSheetCache::Singleton();
 | 
						|
  if (StyleSheet* ucs = sheetCache->GetUserContentSheet()) {
 | 
						|
    xpcomInit.userContentSheetURL() = ucs->GetSheetURI();
 | 
						|
  } else {
 | 
						|
    xpcomInit.userContentSheetURL() = nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  // 1. Build ContentDeviceData first, as it may affect some gfxVars.
 | 
						|
  gfxPlatform::GetPlatform()->BuildContentDeviceData(
 | 
						|
      &xpcomInit.contentDeviceData());
 | 
						|
  // 2. Gather non-default gfxVars.
 | 
						|
  xpcomInit.gfxNonDefaultVarUpdates() = gfxVars::FetchNonDefaultVars();
 | 
						|
  // 3. Start listening for gfxVars updates, to notify content process later on.
 | 
						|
  gfxVars::AddReceiver(this);
 | 
						|
 | 
						|
  nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
 | 
						|
  if (gfxInfo) {
 | 
						|
    GfxInfoBase* gfxInfoRaw = static_cast<GfxInfoBase*>(gfxInfo.get());
 | 
						|
    xpcomInit.gfxFeatureStatus() = gfxInfoRaw->GetAllFeatures();
 | 
						|
  }
 | 
						|
 | 
						|
  // Send the dynamic scalar definitions to the new process.
 | 
						|
  TelemetryIPC::GetDynamicScalarDefinitions(xpcomInit.dynamicScalarDefs());
 | 
						|
 | 
						|
  for (auto const& [location, supported] : sCodecsSupported) {
 | 
						|
    Unused << SendUpdateMediaCodecsSupported(location, supported);
 | 
						|
  }
 | 
						|
 | 
						|
  // Must send screen info before send initialData
 | 
						|
  ScreenManager& screenManager = ScreenManager::GetSingleton();
 | 
						|
  screenManager.CopyScreensToRemote(this);
 | 
						|
 | 
						|
  // Send the UA sheet shared memory buffer and the address it is mapped at.
 | 
						|
  Maybe<SharedMemoryHandle> sharedUASheetHandle;
 | 
						|
  uintptr_t sharedUASheetAddress = sheetCache->GetSharedMemoryAddress();
 | 
						|
 | 
						|
  if (SharedMemoryHandle handle = sheetCache->CloneHandle()) {
 | 
						|
    sharedUASheetHandle.emplace(std::move(handle));
 | 
						|
  } else {
 | 
						|
    sharedUASheetAddress = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  bool isReadyForBackgroundProcessing = false;
 | 
						|
#if defined(XP_WIN)
 | 
						|
  RefPtr<DllServices> dllSvc(DllServices::Get());
 | 
						|
  isReadyForBackgroundProcessing = dllSvc->IsReadyForBackgroundProcessing();
 | 
						|
#endif
 | 
						|
 | 
						|
  xpcomInit.perfStatsMask() = PerfStats::GetCollectionMask();
 | 
						|
 | 
						|
  nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
 | 
						|
  dns->GetTrrDomain(xpcomInit.trrDomain());
 | 
						|
 | 
						|
  nsIDNSService::ResolverMode mode;
 | 
						|
  dns->GetCurrentTrrMode(&mode);
 | 
						|
  xpcomInit.trrMode() = mode;
 | 
						|
  xpcomInit.trrModeFromPref() =
 | 
						|
      static_cast<nsIDNSService::ResolverMode>(StaticPrefs::network_trr_mode());
 | 
						|
 | 
						|
  Unused << SendSetXPCOMProcessAttributes(
 | 
						|
      xpcomInit, initialData, lnf, fontList, std::move(sharedUASheetHandle),
 | 
						|
      sharedUASheetAddress, std::move(sharedFontListBlocks),
 | 
						|
      isReadyForBackgroundProcessing);
 | 
						|
 | 
						|
  ipc::WritableSharedMap* sharedData =
 | 
						|
      nsFrameMessageManager::sParentProcessManager->SharedData();
 | 
						|
  sharedData->Flush();
 | 
						|
  sharedData->SendTo(this);
 | 
						|
 | 
						|
  nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
 | 
						|
  nsChromeRegistryChrome* chromeRegistry =
 | 
						|
      static_cast<nsChromeRegistryChrome*>(registrySvc.get());
 | 
						|
  chromeRegistry->SendRegisteredChrome(this);
 | 
						|
 | 
						|
  nsCOMPtr<nsIStringBundleService> stringBundleService =
 | 
						|
      components::StringBundle::Service();
 | 
						|
  stringBundleService->SendContentBundles(this);
 | 
						|
 | 
						|
  if (gAppData) {
 | 
						|
    nsCString version(gAppData->version);
 | 
						|
    nsCString buildID(gAppData->buildID);
 | 
						|
    nsCString name(gAppData->name);
 | 
						|
    nsCString UAName(gAppData->UAName);
 | 
						|
    nsCString ID(gAppData->ID);
 | 
						|
    nsCString vendor(gAppData->vendor);
 | 
						|
    nsCString sourceURL(gAppData->sourceURL);
 | 
						|
    nsCString updateURL(gAppData->updateURL);
 | 
						|
 | 
						|
    // Sending all information to content process.
 | 
						|
    Unused << SendAppInfo(version, buildID, name, UAName, ID, vendor, sourceURL,
 | 
						|
                          updateURL);
 | 
						|
  }
 | 
						|
 | 
						|
  // Send the child its remote type. On Mac, this needs to be sent prior
 | 
						|
  // to the message we send to enable the Sandbox (SendStartProcessSandbox)
 | 
						|
  // because different remote types require different sandbox privileges.
 | 
						|
 | 
						|
  Unused << SendRemoteType(mRemoteType, mProfile);
 | 
						|
 | 
						|
  ScriptPreloader::InitContentChild(*this);
 | 
						|
 | 
						|
  // Initialize the message manager (and load delayed scripts) now that we
 | 
						|
  // have established communications with the child.
 | 
						|
  mMessageManager->InitWithCallback(this);
 | 
						|
  mMessageManager->SetOsPid(Pid());
 | 
						|
 | 
						|
  // Set the subprocess's priority.  We do this early on because we're likely
 | 
						|
  // /lowering/ the process's CPU and memory priority, which it has inherited
 | 
						|
  // from this process.
 | 
						|
  //
 | 
						|
  // This call can cause us to send IPC messages to the child process, so it
 | 
						|
  // must come after the Open() call above.
 | 
						|
  ProcessPriorityManager::SetProcessPriority(this, aInitialPriority);
 | 
						|
 | 
						|
  // NB: internally, this will send an IPC message to the child
 | 
						|
  // process to get it to create the CompositorBridgeChild.  This
 | 
						|
  // message goes through the regular IPC queue for this
 | 
						|
  // channel, so delivery will happen-before any other messages
 | 
						|
  // we send.  The CompositorBridgeChild must be created before any
 | 
						|
  // PBrowsers are created, because they rely on the Compositor
 | 
						|
  // already being around.  (Creation is async, so can't happen
 | 
						|
  // on demand.)
 | 
						|
  GPUProcessManager* gpm = GPUProcessManager::Get();
 | 
						|
 | 
						|
  Endpoint<PCompositorManagerChild> compositor;
 | 
						|
  Endpoint<PImageBridgeChild> imageBridge;
 | 
						|
  Endpoint<PVRManagerChild> vrBridge;
 | 
						|
  Endpoint<PRemoteDecoderManagerChild> videoManager;
 | 
						|
  AutoTArray<uint32_t, 3> namespaces;
 | 
						|
 | 
						|
  if (!gpm->CreateContentBridges(OtherPid(), &compositor, &imageBridge,
 | 
						|
                                 &vrBridge, &videoManager, mChildID,
 | 
						|
                                 &namespaces)) {
 | 
						|
    // This can fail if we've already started shutting down the compositor
 | 
						|
    // thread. See Bug 1562763 comment 8.
 | 
						|
    MOZ_ASSERT(AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown));
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  Unused << SendInitRendering(std::move(compositor), std::move(imageBridge),
 | 
						|
                              std::move(vrBridge), std::move(videoManager),
 | 
						|
                              namespaces);
 | 
						|
 | 
						|
  gpm->AddListener(this);
 | 
						|
 | 
						|
  nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
 | 
						|
  if (sheetService) {
 | 
						|
    // This looks like a lot of work, but in a normal browser session we just
 | 
						|
    // send two loads.
 | 
						|
    //
 | 
						|
    // The URIs of the Gecko and Servo sheets should be the same, so it
 | 
						|
    // shouldn't matter which we look at.
 | 
						|
 | 
						|
    for (StyleSheet* sheet : *sheetService->AgentStyleSheets()) {
 | 
						|
      Unused << SendLoadAndRegisterSheet(sheet->GetSheetURI(),
 | 
						|
                                         nsIStyleSheetService::AGENT_SHEET);
 | 
						|
    }
 | 
						|
 | 
						|
    for (StyleSheet* sheet : *sheetService->UserStyleSheets()) {
 | 
						|
      Unused << SendLoadAndRegisterSheet(sheet->GetSheetURI(),
 | 
						|
                                         nsIStyleSheetService::USER_SHEET);
 | 
						|
    }
 | 
						|
 | 
						|
    for (StyleSheet* sheet : *sheetService->AuthorStyleSheets()) {
 | 
						|
      Unused << SendLoadAndRegisterSheet(sheet->GetSheetURI(),
 | 
						|
                                         nsIStyleSheetService::AUTHOR_SHEET);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
#ifdef MOZ_SANDBOX
 | 
						|
  bool shouldSandbox = true;
 | 
						|
  Maybe<FileDescriptor> brokerFd;
 | 
						|
  // XXX: Checking the pref here makes it possible to enable/disable sandboxing
 | 
						|
  // during an active session. Currently the pref is only used for testing
 | 
						|
  // purpose. If the decision is made to permanently rely on the pref, this
 | 
						|
  // should be changed so that it is required to restart firefox for the change
 | 
						|
  // of value to take effect. Always send SetProcessSandbox message on macOS.
 | 
						|
#  if !defined(XP_MACOSX)
 | 
						|
  shouldSandbox = IsContentSandboxEnabled();
 | 
						|
#  endif
 | 
						|
 | 
						|
#  ifdef XP_LINUX
 | 
						|
  if (shouldSandbox) {
 | 
						|
    MOZ_ASSERT(!mSandboxBroker);
 | 
						|
    bool isFileProcess = mRemoteType == FILE_REMOTE_TYPE;
 | 
						|
    UniquePtr<SandboxBroker::Policy> policy =
 | 
						|
        sSandboxBrokerPolicyFactory->GetContentPolicy(Pid(), isFileProcess);
 | 
						|
    if (policy) {
 | 
						|
      brokerFd = Some(FileDescriptor());
 | 
						|
      mSandboxBroker =
 | 
						|
          SandboxBroker::Create(std::move(policy), Pid(), brokerFd.ref());
 | 
						|
      if (!mSandboxBroker) {
 | 
						|
        KillHard("SandboxBroker::Create failed");
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      MOZ_ASSERT(brokerFd.ref().IsValid());
 | 
						|
    }
 | 
						|
  }
 | 
						|
#  endif
 | 
						|
  if (shouldSandbox && !SendSetProcessSandbox(brokerFd)) {
 | 
						|
    KillHard("SandboxInitFailed");
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  // Ensure that the default set of permissions are avaliable in the content
 | 
						|
  // process before we try to load any URIs in it.
 | 
						|
  //
 | 
						|
  // NOTE: All default permissions has to be transmitted to the child process
 | 
						|
  // before the blob urls in the for loop below (See Bug 1738713 comment 12).
 | 
						|
  EnsurePermissionsByKey(""_ns, ""_ns);
 | 
						|
 | 
						|
  {
 | 
						|
    nsTArray<BlobURLRegistrationData> registrations;
 | 
						|
    BlobURLProtocolHandler::ForEachBlobURL([&](BlobImpl* aBlobImpl,
 | 
						|
                                               nsIPrincipal* aPrincipal,
 | 
						|
                                               const nsCString& aPartitionKey,
 | 
						|
                                               const nsACString& aURI,
 | 
						|
                                               bool aRevoked) {
 | 
						|
      // We send all moz-extension Blob URL's to all content processes
 | 
						|
      // because content scripts mean that a moz-extension can live in any
 | 
						|
      // process. Same thing for system principal Blob URLs. Content Blob
 | 
						|
      // URL's are sent for content principals on-demand by
 | 
						|
      // AboutToLoadHttpDocumentForChild and RemoteWorkerManager.
 | 
						|
      if (!BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal)) {
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
 | 
						|
      IPCBlob ipcBlob;
 | 
						|
      nsresult rv = IPCBlobUtils::Serialize(aBlobImpl, ipcBlob);
 | 
						|
      if (NS_WARN_IF(NS_FAILED(rv))) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      registrations.AppendElement(
 | 
						|
          BlobURLRegistrationData(nsCString(aURI), ipcBlob, aPrincipal,
 | 
						|
                                  nsCString(aPartitionKey), aRevoked));
 | 
						|
 | 
						|
      rv = TransmitPermissionsForPrincipal(aPrincipal);
 | 
						|
      Unused << NS_WARN_IF(NS_FAILED(rv));
 | 
						|
      return true;
 | 
						|
    });
 | 
						|
 | 
						|
    if (!registrations.IsEmpty()) {
 | 
						|
      Unused << SendInitBlobURLs(registrations);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Send down { Parent, Window }ActorOptions at startup to content process.
 | 
						|
  RefPtr<JSActorService> actorSvc = JSActorService::GetSingleton();
 | 
						|
  if (actorSvc) {
 | 
						|
    nsTArray<JSProcessActorInfo> contentInfos;
 | 
						|
    actorSvc->GetJSProcessActorInfos(contentInfos);
 | 
						|
 | 
						|
    nsTArray<JSWindowActorInfo> windowInfos;
 | 
						|
    actorSvc->GetJSWindowActorInfos(windowInfos);
 | 
						|
 | 
						|
    Unused << SendInitJSActorInfos(contentInfos, windowInfos);
 | 
						|
  }
 | 
						|
 | 
						|
  // Begin subscribing to any BrowsingContextGroups which were hosted by this
 | 
						|
  // process before it finished launching.
 | 
						|
  for (const auto& group : mGroups) {
 | 
						|
    group->Subscribe(this);
 | 
						|
  }
 | 
						|
 | 
						|
  MaybeEnableRemoteInputEventQueue();
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::IsAlive() const {
 | 
						|
  return mLifecycleState == LifecycleState::ALIVE ||
 | 
						|
         mLifecycleState == LifecycleState::INITIALIZED;
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::IsInitialized() const {
 | 
						|
  return mLifecycleState == LifecycleState::INITIALIZED;
 | 
						|
}
 | 
						|
 | 
						|
int32_t ContentParent::Pid() const {
 | 
						|
  if (!mSubprocess) {
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
  auto pid = mSubprocess->GetChildProcessId();
 | 
						|
  if (pid == 0) {
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
  return ReleaseAssertedCast<int32_t>(pid);
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::OnCompositorUnexpectedShutdown() {
 | 
						|
  GPUProcessManager* gpm = GPUProcessManager::Get();
 | 
						|
 | 
						|
  Endpoint<PCompositorManagerChild> compositor;
 | 
						|
  Endpoint<PImageBridgeChild> imageBridge;
 | 
						|
  Endpoint<PVRManagerChild> vrBridge;
 | 
						|
  Endpoint<PRemoteDecoderManagerChild> videoManager;
 | 
						|
  AutoTArray<uint32_t, 3> namespaces;
 | 
						|
 | 
						|
  if (!gpm->CreateContentBridges(OtherPid(), &compositor, &imageBridge,
 | 
						|
                                 &vrBridge, &videoManager, mChildID,
 | 
						|
                                 &namespaces)) {
 | 
						|
    MOZ_ASSERT(AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Unused << SendReinitRendering(std::move(compositor), std::move(imageBridge),
 | 
						|
                                std::move(vrBridge), std::move(videoManager),
 | 
						|
                                namespaces);
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::OnCompositorDeviceReset() {
 | 
						|
  Unused << SendReinitRenderingForDeviceReset();
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::MaybeEnableRemoteInputEventQueue() {
 | 
						|
  MOZ_ASSERT(!mIsRemoteInputEventQueueEnabled);
 | 
						|
  if (!IsInputEventQueueSupported()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  mIsRemoteInputEventQueueEnabled = true;
 | 
						|
  Unused << SendSetInputEventQueueEnabled();
 | 
						|
  SetInputPriorityEventEnabled(true);
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::SetInputPriorityEventEnabled(bool aEnabled) {
 | 
						|
  if (!IsInputEventQueueSupported() || !mIsRemoteInputEventQueueEnabled ||
 | 
						|
      mIsInputPriorityEventEnabled == aEnabled) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  mIsInputPriorityEventEnabled = aEnabled;
 | 
						|
  // Send IPC messages to flush the pending events in the input event queue and
 | 
						|
  // the normal event queue. See PContent.ipdl for more details.
 | 
						|
  Unused << SendSuspendInputEventQueue();
 | 
						|
  Unused << SendFlushInputEventQueue();
 | 
						|
  Unused << SendResumeInputEventQueue();
 | 
						|
}
 | 
						|
 | 
						|
/*static*/
 | 
						|
bool ContentParent::IsInputEventQueueSupported() {
 | 
						|
  static bool sSupported = false;
 | 
						|
  static bool sInitialized = false;
 | 
						|
  if (!sInitialized) {
 | 
						|
    MOZ_ASSERT(Preferences::IsServiceAvailable());
 | 
						|
    sSupported = Preferences::GetBool("input_event_queue.supported", false);
 | 
						|
    sInitialized = true;
 | 
						|
  }
 | 
						|
  return sSupported;
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::OnVarChanged(const GfxVarUpdate& aVar) {
 | 
						|
  if (!CanSend()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  Unused << SendVarUpdate(aVar);
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSetClipboard(
 | 
						|
    const IPCTransferable& aTransferable, const int32_t& aWhichClipboard,
 | 
						|
    const MaybeDiscarded<WindowContext>& aRequestingWindowContext) {
 | 
						|
  // aRequestingPrincipal is allowed to be nullptr here.
 | 
						|
 | 
						|
  if (!ValidatePrincipal(aTransferable.dataPrincipal(),
 | 
						|
                         {ValidatePrincipalOptions::AllowNullPtr,
 | 
						|
                          ValidatePrincipalOptions::AllowExpanded,
 | 
						|
                          ValidatePrincipalOptions::AllowSystem})) {
 | 
						|
    LogAndAssertFailedPrincipalValidationInfo(aTransferable.dataPrincipal(),
 | 
						|
                                              __func__);
 | 
						|
  }
 | 
						|
 | 
						|
  nsresult rv;
 | 
						|
  nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
 | 
						|
  NS_ENSURE_SUCCESS(rv, IPC_OK());
 | 
						|
 | 
						|
  nsCOMPtr<nsITransferable> trans =
 | 
						|
      do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
 | 
						|
  NS_ENSURE_SUCCESS(rv, IPC_OK());
 | 
						|
  trans->Init(nullptr);
 | 
						|
 | 
						|
  rv = nsContentUtils::IPCTransferableToTransferable(
 | 
						|
      aTransferable, true /* aAddDataFlavor */, trans,
 | 
						|
      true /* aFilterUnknownFlavors */);
 | 
						|
  NS_ENSURE_SUCCESS(rv, IPC_OK());
 | 
						|
 | 
						|
  // OK if this is null
 | 
						|
  RefPtr<WindowGlobalParent> window;
 | 
						|
  if (!aRequestingWindowContext.IsDiscarded()) {
 | 
						|
    window = aRequestingWindowContext.get_canonical();
 | 
						|
  }
 | 
						|
  clipboard->SetData(trans, nullptr, aWhichClipboard, window);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
/* static */ Result<nsCOMPtr<nsITransferable>, nsresult>
 | 
						|
ContentParent::CreateClipboardTransferable(const nsTArray<nsCString>& aTypes) {
 | 
						|
  nsresult rv;
 | 
						|
  nsCOMPtr<nsITransferable> trans =
 | 
						|
      do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    return Err(rv);
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_TRY(trans->Init(nullptr));
 | 
						|
  // The private flag is only used to prevent the data from being cached to the
 | 
						|
  // disk. The flag is not exported to the IPCDataTransfer object.
 | 
						|
  // The flag is set because we are not sure whether the clipboard data is used
 | 
						|
  // in a private browsing context. The transferable is only used in this scope,
 | 
						|
  // so the cache would not reduce memory consumption anyway.
 | 
						|
  trans->SetIsPrivateData(true);
 | 
						|
  // Fill out flavors for transferable
 | 
						|
  for (uint32_t t = 0; t < aTypes.Length(); t++) {
 | 
						|
    MOZ_TRY(trans->AddDataFlavor(aTypes[t].get()));
 | 
						|
  }
 | 
						|
 | 
						|
  return std::move(trans);
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvGetClipboard(
 | 
						|
    nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
 | 
						|
    const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
 | 
						|
    IPCTransferableDataOrError* aTransferableDataOrError) {
 | 
						|
  nsresult rv;
 | 
						|
  // We expect content processes to always pass a non-null window so Content
 | 
						|
  // Analysis can analyze it. (if Content Analysis is active)
 | 
						|
  // There may be some cases when a window is closing, etc., in
 | 
						|
  // which case returning no clipboard content should not be a problem.
 | 
						|
  if (aRequestingWindowContext.IsDiscarded()) {
 | 
						|
    NS_WARNING(
 | 
						|
        "discarded window passed to RecvGetClipboard(); returning no clipboard "
 | 
						|
        "content");
 | 
						|
    *aTransferableDataOrError = NS_ERROR_FAILURE;
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  if (aRequestingWindowContext.IsNull()) {
 | 
						|
    return IPC_FAIL(this, "passed null window to RecvGetClipboard()");
 | 
						|
  }
 | 
						|
  RefPtr<WindowGlobalParent> window = aRequestingWindowContext.get_canonical();
 | 
						|
  // Retrieve clipboard
 | 
						|
  nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    *aTransferableDataOrError = rv;
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  // Create transferable
 | 
						|
  auto result = CreateClipboardTransferable(aTypes);
 | 
						|
  if (result.isErr()) {
 | 
						|
    *aTransferableDataOrError = result.unwrapErr();
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  // Get data from clipboard
 | 
						|
  nsCOMPtr<nsITransferable> trans = result.unwrap();
 | 
						|
  rv = clipboard->GetData(trans, aWhichClipboard, window);
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    *aTransferableDataOrError = rv;
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  IPCTransferableData transferableData;
 | 
						|
  nsContentUtils::TransferableToIPCTransferableData(
 | 
						|
      trans, &transferableData, true /* aInSyncMessage */, this);
 | 
						|
  *aTransferableDataOrError = std::move(transferableData);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvEmptyClipboard(
 | 
						|
    const int32_t& aWhichClipboard) {
 | 
						|
  nsresult rv;
 | 
						|
  nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
 | 
						|
  NS_ENSURE_SUCCESS(rv, IPC_OK());
 | 
						|
 | 
						|
  clipboard->EmptyClipboard(aWhichClipboard);
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvClipboardHasType(
 | 
						|
    nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
 | 
						|
    bool* aHasType) {
 | 
						|
  nsresult rv;
 | 
						|
  nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
 | 
						|
  NS_ENSURE_SUCCESS(rv, IPC_OK());
 | 
						|
 | 
						|
  clipboard->HasDataMatchingFlavors(aTypes, aWhichClipboard, aHasType);
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
static Result<ClipboardReadRequest, nsresult> CreateClipboardReadRequest(
 | 
						|
    ContentParent& aContentParent,
 | 
						|
    nsIAsyncGetClipboardData& aAsyncGetClipboardData) {
 | 
						|
  nsTArray<nsCString> flavors;
 | 
						|
  nsresult rv = aAsyncGetClipboardData.GetFlavorList(flavors);
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    return Err(rv);
 | 
						|
  }
 | 
						|
 | 
						|
  auto requestParent = MakeNotNull<RefPtr<ClipboardReadRequestParent>>(
 | 
						|
      &aContentParent, &aAsyncGetClipboardData);
 | 
						|
 | 
						|
  // Open a remote endpoint for our PClipboardReadRequest actor.
 | 
						|
  ManagedEndpoint<PClipboardReadRequestChild> childEndpoint =
 | 
						|
      aContentParent.OpenPClipboardReadRequestEndpoint(requestParent);
 | 
						|
  if (NS_WARN_IF(!childEndpoint.IsValid())) {
 | 
						|
    return Err(NS_ERROR_FAILURE);
 | 
						|
  }
 | 
						|
 | 
						|
  return ClipboardReadRequest(std::move(childEndpoint), std::move(flavors));
 | 
						|
}
 | 
						|
 | 
						|
class ClipboardGetCallback final : public nsIAsyncClipboardGetCallback {
 | 
						|
 public:
 | 
						|
  ClipboardGetCallback(ContentParent* aContentParent,
 | 
						|
                       ContentParent::GetClipboardAsyncResolver&& aResolver)
 | 
						|
      : mContentParent(aContentParent), mResolver(std::move(aResolver)) {}
 | 
						|
 | 
						|
  // This object will never be held by a cycle-collected object, so it doesn't
 | 
						|
  // need to be cycle-collected despite holding alive cycle-collected objects.
 | 
						|
  NS_DECL_ISUPPORTS
 | 
						|
 | 
						|
  // nsIAsyncClipboardGetCallback
 | 
						|
  NS_IMETHOD OnSuccess(
 | 
						|
      nsIAsyncGetClipboardData* aAsyncGetClipboardData) override {
 | 
						|
    MOZ_ASSERT(mContentParent);
 | 
						|
    MOZ_ASSERT(aAsyncGetClipboardData);
 | 
						|
 | 
						|
    auto result =
 | 
						|
        CreateClipboardReadRequest(*mContentParent, *aAsyncGetClipboardData);
 | 
						|
    if (result.isErr()) {
 | 
						|
      return OnError(result.unwrapErr());
 | 
						|
    }
 | 
						|
 | 
						|
    mResolver(result.unwrap());
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
  NS_IMETHOD OnError(nsresult aResult) override {
 | 
						|
    mResolver(aResult);
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
 protected:
 | 
						|
  ~ClipboardGetCallback() = default;
 | 
						|
 | 
						|
  RefPtr<ContentParent> mContentParent;
 | 
						|
  ContentParent::GetClipboardAsyncResolver mResolver;
 | 
						|
};
 | 
						|
 | 
						|
NS_IMPL_ISUPPORTS(ClipboardGetCallback, nsIAsyncClipboardGetCallback)
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvGetClipboardAsync(
 | 
						|
    nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
 | 
						|
    const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
 | 
						|
    mozilla::NotNull<nsIPrincipal*> aRequestingPrincipal,
 | 
						|
    GetClipboardAsyncResolver&& aResolver) {
 | 
						|
  if (!ValidatePrincipal(aRequestingPrincipal,
 | 
						|
                         {ValidatePrincipalOptions::AllowSystem,
 | 
						|
                          ValidatePrincipalOptions::AllowExpanded})) {
 | 
						|
    LogAndAssertFailedPrincipalValidationInfo(aRequestingPrincipal, __func__);
 | 
						|
  }
 | 
						|
 | 
						|
  // If the requesting context has been discarded, cancel the paste.
 | 
						|
  if (aRequestingWindowContext.IsDiscarded()) {
 | 
						|
    aResolver(NS_ERROR_NOT_AVAILABLE);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<WindowGlobalParent> requestingWindow =
 | 
						|
      aRequestingWindowContext.get_canonical();
 | 
						|
  if (requestingWindow && requestingWindow->GetContentParent() != this) {
 | 
						|
    return IPC_FAIL(
 | 
						|
        this, "attempt to paste into WindowContext loaded in another process");
 | 
						|
  }
 | 
						|
 | 
						|
  nsresult rv;
 | 
						|
  // Retrieve clipboard
 | 
						|
  nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    aResolver(rv);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  auto callback = MakeRefPtr<ClipboardGetCallback>(this, std::move(aResolver));
 | 
						|
  rv = clipboard->AsyncGetData(aTypes, aWhichClipboard, requestingWindow,
 | 
						|
                               aRequestingPrincipal, callback);
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    callback->OnError(rv);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvGetClipboardDataSnapshotSync(
 | 
						|
    nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
 | 
						|
    const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
 | 
						|
    ClipboardReadRequestOrError* aRequestOrError) {
 | 
						|
  // If the requesting context has been discarded, cancel the paste.
 | 
						|
  if (aRequestingWindowContext.IsDiscarded()) {
 | 
						|
    *aRequestOrError = NS_ERROR_FAILURE;
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<WindowGlobalParent> requestingWindow =
 | 
						|
      aRequestingWindowContext.get_canonical();
 | 
						|
  if (requestingWindow && requestingWindow->GetContentParent() != this) {
 | 
						|
    return IPC_FAIL(
 | 
						|
        this, "attempt to paste into WindowContext loaded in another process");
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID));
 | 
						|
  if (!clipboard) {
 | 
						|
    *aRequestOrError = NS_ERROR_FAILURE;
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsIAsyncGetClipboardData> asyncGetClipboardData;
 | 
						|
  nsresult rv =
 | 
						|
      clipboard->GetDataSnapshotSync(aTypes, aWhichClipboard, requestingWindow,
 | 
						|
                                     getter_AddRefs(asyncGetClipboardData));
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    *aRequestOrError = rv;
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  auto result = CreateClipboardReadRequest(*this, *asyncGetClipboardData);
 | 
						|
  if (result.isErr()) {
 | 
						|
    *aRequestOrError = result.unwrapErr();
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  *aRequestOrError = result.unwrap();
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
already_AddRefed<PClipboardWriteRequestParent>
 | 
						|
ContentParent::AllocPClipboardWriteRequestParent(
 | 
						|
    const int32_t& aClipboardType,
 | 
						|
    const MaybeDiscarded<WindowContext>& aSettingWindowContext) {
 | 
						|
  WindowContext* settingWindowContext = nullptr;
 | 
						|
  if (!aSettingWindowContext.IsDiscarded()) {
 | 
						|
    settingWindowContext = aSettingWindowContext.get();
 | 
						|
  }
 | 
						|
  RefPtr<ClipboardWriteRequestParent> request =
 | 
						|
      MakeAndAddRef<ClipboardWriteRequestParent>(this);
 | 
						|
  request->Init(aClipboardType, settingWindowContext);
 | 
						|
  return request.forget();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvGetIconForExtension(
 | 
						|
    const nsACString& aFileExt, const uint32_t& aIconSize,
 | 
						|
    nsTArray<uint8_t>* bits) {
 | 
						|
#ifdef MOZ_WIDGET_ANDROID
 | 
						|
  NS_ASSERTION(AndroidBridge::Bridge() != nullptr,
 | 
						|
               "AndroidBridge is not available");
 | 
						|
  if (AndroidBridge::Bridge() == nullptr) {
 | 
						|
    // Do not fail - just no icon will be shown
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  bits->AppendElements(aIconSize * aIconSize * 4);
 | 
						|
 | 
						|
  AndroidBridge::Bridge()->GetIconForExtension(aFileExt, aIconSize,
 | 
						|
                                               bits->Elements());
 | 
						|
#endif
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvFirstIdle() {
 | 
						|
  // When the ContentChild goes idle, it sends us a FirstIdle message
 | 
						|
  // which we use as a good time to signal the PreallocatedProcessManager
 | 
						|
  // that it can start allocating processes from now on.
 | 
						|
  if (mIsAPreallocBlocker) {
 | 
						|
    MOZ_LOG(
 | 
						|
        ContentParent::GetLog(), LogLevel::Verbose,
 | 
						|
        ("RecvFirstIdle %p: Removing Blocker for %s", this, mRemoteType.get()));
 | 
						|
    PreallocatedProcessManager::RemoveBlocker(mRemoteType, this);
 | 
						|
    mIsAPreallocBlocker = false;
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
already_AddRefed<nsDocShellLoadState> ContentParent::TakePendingLoadStateForId(
 | 
						|
    uint64_t aLoadIdentifier) {
 | 
						|
  return mPendingLoadStates.Extract(aLoadIdentifier).valueOr(nullptr).forget();
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::StorePendingLoadState(nsDocShellLoadState* aLoadState) {
 | 
						|
  MOZ_DIAGNOSTIC_ASSERT(
 | 
						|
      !mPendingLoadStates.Contains(aLoadState->GetLoadIdentifier()),
 | 
						|
      "The same nsDocShellLoadState was sent to the same content process "
 | 
						|
      "twice? This will mess with cross-process tracking of loads");
 | 
						|
  mPendingLoadStates.InsertOrUpdate(aLoadState->GetLoadIdentifier(),
 | 
						|
                                    aLoadState);
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvCleanupPendingLoadState(
 | 
						|
    uint64_t aLoadIdentifier) {
 | 
						|
  mPendingLoadStates.Remove(aLoadIdentifier);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
// We want ContentParent to show up in CC logs for debugging purposes, but we
 | 
						|
// don't actually cycle collect it.
 | 
						|
NS_IMPL_CYCLE_COLLECTION_0(ContentParent)
 | 
						|
 | 
						|
NS_IMPL_CYCLE_COLLECTING_ADDREF(ContentParent)
 | 
						|
NS_IMPL_CYCLE_COLLECTING_RELEASE(ContentParent)
 | 
						|
 | 
						|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ContentParent)
 | 
						|
  NS_INTERFACE_MAP_ENTRY_CONCRETE(ContentParent)
 | 
						|
  NS_INTERFACE_MAP_ENTRY(nsIDOMProcessParent)
 | 
						|
  NS_INTERFACE_MAP_ENTRY(nsIObserver)
 | 
						|
  NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionCallback)
 | 
						|
  NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionErrorCallback)
 | 
						|
  NS_INTERFACE_MAP_ENTRY(nsIAsyncShutdownBlocker)
 | 
						|
  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
 | 
						|
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMProcessParent)
 | 
						|
NS_INTERFACE_MAP_END
 | 
						|
 | 
						|
class RequestContentJSInterruptRunnable final : public Runnable {
 | 
						|
 public:
 | 
						|
  explicit RequestContentJSInterruptRunnable(PProcessHangMonitorParent* aActor)
 | 
						|
      : Runnable("dom::RequestContentJSInterruptRunnable"),
 | 
						|
        mHangMonitorActor(aActor) {}
 | 
						|
 | 
						|
  NS_IMETHOD Run() override {
 | 
						|
    MOZ_ASSERT(mHangMonitorActor);
 | 
						|
    Unused << mHangMonitorActor->SendRequestContentJSInterrupt();
 | 
						|
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  // The end-of-life of ContentParent::mHangMonitorActor is bound to
 | 
						|
  // ContentParent::ActorDestroy and then HangMonitorParent::Shutdown
 | 
						|
  // dispatches a shutdown runnable to this queue and waits for it to be
 | 
						|
  // executed. So the runnable needs not to care about keeping it alive,
 | 
						|
  // as it is surely dispatched earlier than the
 | 
						|
  // HangMonitorParent::ShutdownOnThread.
 | 
						|
  RefPtr<PProcessHangMonitorParent> mHangMonitorActor;
 | 
						|
};
 | 
						|
 | 
						|
void ContentParent::SignalImpendingShutdownToContentJS() {
 | 
						|
  if (!mIsSignaledImpendingShutdown &&
 | 
						|
      !AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
 | 
						|
    MaybeLogBlockShutdownDiagnostics(
 | 
						|
        this, "BlockShutdown: NotifyImpendingShutdown.", __FILE__, __LINE__);
 | 
						|
    NotifyImpendingShutdown();
 | 
						|
    mIsSignaledImpendingShutdown = true;
 | 
						|
    if (mHangMonitorActor &&
 | 
						|
        StaticPrefs::dom_abort_script_on_child_shutdown()) {
 | 
						|
      MaybeLogBlockShutdownDiagnostics(
 | 
						|
          this, "BlockShutdown: RequestContentJSInterrupt.", __FILE__,
 | 
						|
          __LINE__);
 | 
						|
      RefPtr<RequestContentJSInterruptRunnable> r =
 | 
						|
          new RequestContentJSInterruptRunnable(mHangMonitorActor);
 | 
						|
      ProcessHangMonitor::Get()->Dispatch(r.forget());
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Async shutdown blocker
 | 
						|
NS_IMETHODIMP
 | 
						|
ContentParent::BlockShutdown(nsIAsyncShutdownClient* aClient) {
 | 
						|
  if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
 | 
						|
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | 
						|
    mBlockShutdownCalled = true;
 | 
						|
#endif
 | 
						|
    // Our real shutdown has not yet started. Just notify the impending
 | 
						|
    // shutdown and eventually cancel content JS.
 | 
						|
    SignalImpendingShutdownToContentJS();
 | 
						|
    // This will make our process unusable for normal content, so we need to
 | 
						|
    // ensure we won't get re-used by GetUsedBrowserProcess as we have not yet
 | 
						|
    // done MarkAsDead.
 | 
						|
    PreallocatedProcessManager::Erase(this);
 | 
						|
    StopRecyclingE10SOnly(false);
 | 
						|
 | 
						|
    if (sQuitApplicationGrantedClient) {
 | 
						|
      Unused << sQuitApplicationGrantedClient->RemoveBlocker(this);
 | 
						|
    }
 | 
						|
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | 
						|
    mBlockShutdownCalled = false;
 | 
						|
#endif
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | 
						|
  // We register two final shutdown blockers and both would call us, but if
 | 
						|
  // things go well we will unregister both as (delayed) reaction to the first
 | 
						|
  // call we get and thus never receive a second call. Thus we believe that we
 | 
						|
  // will get called only once except for quit-application-granted, which is
 | 
						|
  // handled above.
 | 
						|
  MOZ_ASSERT(!mBlockShutdownCalled);
 | 
						|
  mBlockShutdownCalled = true;
 | 
						|
#endif
 | 
						|
 | 
						|
  if (CanSend()) {
 | 
						|
    MaybeLogBlockShutdownDiagnostics(this, "BlockShutdown: CanSend.", __FILE__,
 | 
						|
                                     __LINE__);
 | 
						|
 | 
						|
    // Make sure that our process will get scheduled.
 | 
						|
    ProcessPriorityManager::SetProcessPriority(this,
 | 
						|
                                               PROCESS_PRIORITY_FOREGROUND);
 | 
						|
    // The normal shutdown sequence is to send a shutdown message
 | 
						|
    // to the child and then just wait for ActorDestroy which will
 | 
						|
    // cleanup everything and remove our blockers.
 | 
						|
    if (!ShutDownProcess(SEND_SHUTDOWN_MESSAGE)) {
 | 
						|
      KillHard("Failed to send Shutdown message. Destroying the process...");
 | 
						|
      return NS_OK;
 | 
						|
    }
 | 
						|
  } else if (IsLaunching()) {
 | 
						|
    MaybeLogBlockShutdownDiagnostics(
 | 
						|
        this, "BlockShutdown: !CanSend && IsLaunching.", __FILE__, __LINE__);
 | 
						|
 | 
						|
    // If we get here while we are launching, we must wait for the child to
 | 
						|
    // be able to react on our commands. Mark this process as dead. This
 | 
						|
    // will make bail out LaunchSubprocessResolve and kick off the normal
 | 
						|
    // shutdown sequence.
 | 
						|
    MarkAsDead();
 | 
						|
  } else {
 | 
						|
    MOZ_ASSERT(IsDead());
 | 
						|
    if (!IsDead()) {
 | 
						|
      MaybeLogBlockShutdownDiagnostics(
 | 
						|
          this, "BlockShutdown: !!! !CanSend && !IsLaunching && !IsDead !!!",
 | 
						|
          __FILE__, __LINE__);
 | 
						|
    } else {
 | 
						|
      MaybeLogBlockShutdownDiagnostics(
 | 
						|
          this, "BlockShutdown: !CanSend && !IsLaunching && IsDead.", __FILE__,
 | 
						|
          __LINE__);
 | 
						|
    }
 | 
						|
    // Nothing left we can do. We must assume that we race with an ongoing
 | 
						|
    // process shutdown, such that we can expect our shutdown blockers to be
 | 
						|
    // removed normally.
 | 
						|
  }
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
ContentParent::GetName(nsAString& aName) {
 | 
						|
  aName.AssignLiteral("ContentParent:");
 | 
						|
  aName.AppendPrintf(" id=%p", this);
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
ContentParent::GetState(nsIPropertyBag** aResult) {
 | 
						|
  auto props = MakeRefPtr<nsHashPropertyBag>();
 | 
						|
  props->SetPropertyAsACString(u"remoteTypePrefix"_ns,
 | 
						|
                               RemoteTypePrefix(mRemoteType));
 | 
						|
  *aResult = props.forget().downcast<nsIWritablePropertyBag>().take();
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
static void InitShutdownClients() {
 | 
						|
  if (!sXPCOMShutdownClient) {
 | 
						|
    nsresult rv;
 | 
						|
    nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdownService();
 | 
						|
    if (!svc) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    nsCOMPtr<nsIAsyncShutdownClient> client;
 | 
						|
    // TODO: It seems as if getPhase from AsyncShutdown.sys.mjs does not check
 | 
						|
    // if we are beyond our phase already. See bug 1762840.
 | 
						|
    if (!AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMWillShutdown)) {
 | 
						|
      rv = svc->GetXpcomWillShutdown(getter_AddRefs(client));
 | 
						|
      if (NS_SUCCEEDED(rv)) {
 | 
						|
        sXPCOMShutdownClient = client.forget();
 | 
						|
        ClearOnShutdown(&sXPCOMShutdownClient);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
 | 
						|
      rv = svc->GetProfileBeforeChange(getter_AddRefs(client));
 | 
						|
      if (NS_SUCCEEDED(rv)) {
 | 
						|
        sProfileBeforeChangeClient = client.forget();
 | 
						|
        ClearOnShutdown(&sProfileBeforeChangeClient);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    // TODO: ShutdownPhase::AppShutdownConfirmed is not mapping to
 | 
						|
    // QuitApplicationGranted, see bug 1762840 comment 4.
 | 
						|
    if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
 | 
						|
      rv = svc->GetQuitApplicationGranted(getter_AddRefs(client));
 | 
						|
      if (NS_SUCCEEDED(rv)) {
 | 
						|
        sQuitApplicationGrantedClient = client.forget();
 | 
						|
        ClearOnShutdown(&sQuitApplicationGrantedClient);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::AddShutdownBlockers() {
 | 
						|
  InitShutdownClients();
 | 
						|
  MOZ_ASSERT(sXPCOMShutdownClient);
 | 
						|
  MOZ_ASSERT(sProfileBeforeChangeClient);
 | 
						|
 | 
						|
  if (sXPCOMShutdownClient) {
 | 
						|
    sXPCOMShutdownClient->AddBlocker(
 | 
						|
        this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
 | 
						|
  }
 | 
						|
  if (sProfileBeforeChangeClient) {
 | 
						|
    sProfileBeforeChangeClient->AddBlocker(
 | 
						|
        this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
 | 
						|
  }
 | 
						|
  if (sQuitApplicationGrantedClient) {
 | 
						|
    sQuitApplicationGrantedClient->AddBlocker(
 | 
						|
        this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::RemoveShutdownBlockers() {
 | 
						|
  MOZ_ASSERT(sXPCOMShutdownClient);
 | 
						|
  MOZ_ASSERT(sProfileBeforeChangeClient);
 | 
						|
 | 
						|
  MaybeLogBlockShutdownDiagnostics(this, "RemoveShutdownBlockers", __FILE__,
 | 
						|
                                   __LINE__);
 | 
						|
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | 
						|
  mBlockShutdownCalled = false;
 | 
						|
#endif
 | 
						|
 | 
						|
  if (sXPCOMShutdownClient) {
 | 
						|
    Unused << sXPCOMShutdownClient->RemoveBlocker(this);
 | 
						|
  }
 | 
						|
  if (sProfileBeforeChangeClient) {
 | 
						|
    Unused << sProfileBeforeChangeClient->RemoveBlocker(this);
 | 
						|
  }
 | 
						|
  if (sQuitApplicationGrantedClient) {
 | 
						|
    Unused << sQuitApplicationGrantedClient->RemoveBlocker(this);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
ContentParent::Observe(nsISupports* aSubject, const char* aTopic,
 | 
						|
                       const char16_t* aData) {
 | 
						|
  if (IsDead() || !mSubprocess) {
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!strcmp(aTopic, "nsPref:changed")) {
 | 
						|
    // We know prefs are ASCII here.
 | 
						|
    NS_LossyConvertUTF16toASCII strData(aData);
 | 
						|
 | 
						|
    Pref pref(strData, /* isLocked */ false,
 | 
						|
              /* isSanitized */ false, Nothing(), Nothing());
 | 
						|
 | 
						|
    Preferences::GetPreference(&pref, GeckoProcessType_Content,
 | 
						|
                               GetRemoteType());
 | 
						|
 | 
						|
    // This check is a bit of a hack.  We want to avoid sending excessive
 | 
						|
    // preference updates to subprocesses for performance reasons, but we
 | 
						|
    // currently don't have a great mechanism for doing so. (See Bug 1819714)
 | 
						|
    // We're going to hijack the sanitization mechanism to accomplish our goal
 | 
						|
    // but it imposes the following complications:
 | 
						|
    // 1) It doesn't avoid sending anything to other (non-web-content)
 | 
						|
    //    subprocesses so we're not getting any perf gains there
 | 
						|
    // 2) It confuses the subprocesses w.r.t. sanitization.  The point of
 | 
						|
    //    sending a preference update of a sanitized preference is so that
 | 
						|
    //    content process knows when it's asked to resolve a sanitized
 | 
						|
    //    preference, and it can send telemetry and/or crash.  With this
 | 
						|
    //    change, a sanitized pref that is created during the browser session
 | 
						|
    //    will not be sent to the content process, and therefore the content
 | 
						|
    //    process won't know it should telemetry/crash on access - it'll just
 | 
						|
    //    silently fail to resolve it.  After browser restart, the sanitized
 | 
						|
    //    pref will be populated into the content process via the shared pref
 | 
						|
    //    map and _then_ if it is accessed, the content process will crash.
 | 
						|
    //    We're seeing good telemetry/crash rates right now, so we're okay with
 | 
						|
    //    this limitation.
 | 
						|
    if (pref.isSanitized()) {
 | 
						|
      return NS_OK;
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsInitialized()) {
 | 
						|
      MOZ_ASSERT(mQueuedPrefs.IsEmpty());
 | 
						|
      if (!SendPreferenceUpdate(pref)) {
 | 
						|
        return NS_ERROR_NOT_AVAILABLE;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      MOZ_ASSERT(!IsDead());
 | 
						|
      mQueuedPrefs.AppendElement(pref);
 | 
						|
    }
 | 
						|
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!IsAlive()) {
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
  // listening for memory pressure event
 | 
						|
  if (!strcmp(aTopic, "memory-pressure")) {
 | 
						|
    Unused << SendFlushMemory(nsDependentString(aData));
 | 
						|
  } else if (!strcmp(aTopic, "application-background")) {
 | 
						|
    Unused << SendApplicationBackground();
 | 
						|
  } else if (!strcmp(aTopic, "application-foreground")) {
 | 
						|
    Unused << SendApplicationForeground();
 | 
						|
  } else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC)) {
 | 
						|
    NS_ConvertUTF16toUTF8 dataStr(aData);
 | 
						|
    const char* offline = dataStr.get();
 | 
						|
    if (!SendSetOffline(!strcmp(offline, "true"))) {
 | 
						|
      return NS_ERROR_NOT_AVAILABLE;
 | 
						|
    }
 | 
						|
  } else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC)) {
 | 
						|
    if (!SendSetConnectivity(u"true"_ns.Equals(aData))) {
 | 
						|
      return NS_ERROR_NOT_AVAILABLE;
 | 
						|
    }
 | 
						|
  } else if (!strcmp(aTopic, NS_IPC_CAPTIVE_PORTAL_SET_STATE)) {
 | 
						|
    nsCOMPtr<nsICaptivePortalService> cps = do_QueryInterface(aSubject);
 | 
						|
    MOZ_ASSERT(cps, "Should QI to a captive portal service");
 | 
						|
    if (!cps) {
 | 
						|
      return NS_ERROR_FAILURE;
 | 
						|
    }
 | 
						|
    int32_t state;
 | 
						|
    cps->GetState(&state);
 | 
						|
    if (!SendSetCaptivePortalState(state)) {
 | 
						|
      return NS_ERROR_NOT_AVAILABLE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  // listening for alert notifications
 | 
						|
  else if (!strcmp(aTopic, "alertfinished") ||
 | 
						|
           !strcmp(aTopic, "alertclickcallback") ||
 | 
						|
           !strcmp(aTopic, "alertshow") ||
 | 
						|
           !strcmp(aTopic, "alertdisablecallback") ||
 | 
						|
           !strcmp(aTopic, "alertsettingscallback")) {
 | 
						|
    if (!SendNotifyAlertsObserver(nsDependentCString(aTopic),
 | 
						|
                                  nsDependentString(aData))) {
 | 
						|
      return NS_ERROR_NOT_AVAILABLE;
 | 
						|
    }
 | 
						|
  } else if (!strcmp(aTopic, "child-gc-request")) {
 | 
						|
    Unused << SendGarbageCollect();
 | 
						|
  } else if (!strcmp(aTopic, "child-cc-request")) {
 | 
						|
    Unused << SendCycleCollect();
 | 
						|
  } else if (!strcmp(aTopic, "child-mmu-request")) {
 | 
						|
    Unused << SendMinimizeMemoryUsage();
 | 
						|
  } else if (!strcmp(aTopic, "child-ghost-request")) {
 | 
						|
    Unused << SendUnlinkGhosts();
 | 
						|
  } else if (!strcmp(aTopic, "last-pb-context-exited")) {
 | 
						|
    Unused << SendLastPrivateDocShellDestroyed();
 | 
						|
  }
 | 
						|
#ifdef ACCESSIBILITY
 | 
						|
  else if (aData && !strcmp(aTopic, "a11y-init-or-shutdown")) {
 | 
						|
    if (*aData == '1') {
 | 
						|
      // Make sure accessibility is running in content process when
 | 
						|
      // accessibility gets initiated in chrome process.
 | 
						|
      Unused << SendActivateA11y();
 | 
						|
    } else {
 | 
						|
      // If possible, shut down accessibility in content process when
 | 
						|
      // accessibility gets shutdown in chrome process.
 | 
						|
      Unused << SendShutdownA11y();
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif
 | 
						|
  else if (!strcmp(aTopic, "cacheservice:empty-cache")) {
 | 
						|
    Unused << SendNotifyEmptyHTTPCache();
 | 
						|
  } else if (!strcmp(aTopic, "intl:app-locales-changed")) {
 | 
						|
    nsTArray<nsCString> appLocales;
 | 
						|
    LocaleService::GetInstance()->GetAppLocalesAsBCP47(appLocales);
 | 
						|
    Unused << SendUpdateAppLocales(appLocales);
 | 
						|
  } else if (!strcmp(aTopic, "intl:requested-locales-changed")) {
 | 
						|
    nsTArray<nsCString> requestedLocales;
 | 
						|
    LocaleService::GetInstance()->GetRequestedLocales(requestedLocales);
 | 
						|
    Unused << SendUpdateRequestedLocales(requestedLocales);
 | 
						|
  } else if (!strcmp(aTopic, "cookie-changed") ||
 | 
						|
             !strcmp(aTopic, "private-cookie-changed")) {
 | 
						|
    MOZ_ASSERT(aSubject, "cookie changed notification must have subject.");
 | 
						|
    nsCOMPtr<nsICookieNotification> notification = do_QueryInterface(aSubject);
 | 
						|
    MOZ_ASSERT(notification,
 | 
						|
               "cookie changed notification must have nsICookieNotification.");
 | 
						|
    nsICookieNotification::Action action = notification->GetAction();
 | 
						|
 | 
						|
    PNeckoParent* neckoParent = LoneManagedOrNullAsserts(ManagedPNeckoParent());
 | 
						|
    if (!neckoParent) {
 | 
						|
      return NS_OK;
 | 
						|
    }
 | 
						|
    PCookieServiceParent* csParent =
 | 
						|
        LoneManagedOrNullAsserts(neckoParent->ManagedPCookieServiceParent());
 | 
						|
    if (!csParent) {
 | 
						|
      return NS_OK;
 | 
						|
    }
 | 
						|
    auto* cs = static_cast<CookieServiceParent*>(csParent);
 | 
						|
    if (action == nsICookieNotification::COOKIES_BATCH_DELETED) {
 | 
						|
      nsCOMPtr<nsIArray> cookieList;
 | 
						|
      DebugOnly<nsresult> rv =
 | 
						|
          notification->GetBatchDeletedCookies(getter_AddRefs(cookieList));
 | 
						|
      NS_ASSERTION(NS_SUCCEEDED(rv) && cookieList, "couldn't get cookie list");
 | 
						|
      cs->RemoveBatchDeletedCookies(cookieList);
 | 
						|
      return NS_OK;
 | 
						|
    }
 | 
						|
 | 
						|
    if (action == nsICookieNotification::ALL_COOKIES_CLEARED) {
 | 
						|
      cs->RemoveAll();
 | 
						|
      return NS_OK;
 | 
						|
    }
 | 
						|
 | 
						|
    // Do not push these cookie updates to the same process they originated
 | 
						|
    // from.
 | 
						|
    if (cs->ProcessingCookie()) {
 | 
						|
      return NS_OK;
 | 
						|
    }
 | 
						|
 | 
						|
    nsCOMPtr<nsICookie> xpcCookie;
 | 
						|
    DebugOnly<nsresult> rv = notification->GetCookie(getter_AddRefs(xpcCookie));
 | 
						|
    NS_ASSERTION(NS_SUCCEEDED(rv) && xpcCookie, "couldn't get cookie");
 | 
						|
 | 
						|
    // only broadcast the cookie change to content processes that need it
 | 
						|
    const Cookie& cookie = xpcCookie->AsCookie();
 | 
						|
 | 
						|
    // do not send cookie if content process does not have similar cookie
 | 
						|
    if (!cs->ContentProcessHasCookie(cookie)) {
 | 
						|
      return NS_OK;
 | 
						|
    }
 | 
						|
 | 
						|
    if (action == nsICookieNotification::COOKIE_DELETED) {
 | 
						|
      cs->RemoveCookie(cookie);
 | 
						|
    } else if (action == nsICookieNotification::COOKIE_ADDED ||
 | 
						|
               action == nsICookieNotification::COOKIE_CHANGED) {
 | 
						|
      cs->AddCookie(cookie);
 | 
						|
    }
 | 
						|
  } else if (!strcmp(aTopic, NS_NETWORK_LINK_TYPE_TOPIC)) {
 | 
						|
    UpdateNetworkLinkType();
 | 
						|
  } else if (!strcmp(aTopic, "network:socket-process-crashed")) {
 | 
						|
    Unused << SendSocketProcessCrashed();
 | 
						|
  } else if (!strcmp(aTopic, DEFAULT_TIMEZONE_CHANGED_OBSERVER_TOPIC)) {
 | 
						|
    Unused << SendSystemTimezoneChanged();
 | 
						|
  } else if (!strcmp(aTopic, NS_NETWORK_TRR_MODE_CHANGED_TOPIC)) {
 | 
						|
    nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
 | 
						|
    nsIDNSService::ResolverMode mode;
 | 
						|
    dns->GetCurrentTrrMode(&mode);
 | 
						|
    Unused << SendSetTRRMode(mode, static_cast<nsIDNSService::ResolverMode>(
 | 
						|
                                       StaticPrefs::network_trr_mode()));
 | 
						|
  }
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::UpdateNetworkLinkType() {
 | 
						|
  nsresult rv;
 | 
						|
  nsCOMPtr<nsINetworkLinkService> nls =
 | 
						|
      do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv);
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  uint32_t linkType = nsINetworkLinkService::LINK_TYPE_UNKNOWN;
 | 
						|
  rv = nls->GetLinkType(&linkType);
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Unused << SendNetworkLinkTypeChange(linkType);
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
ContentParent::GetInterface(const nsIID& aIID, void** aResult) {
 | 
						|
  NS_ENSURE_ARG_POINTER(aResult);
 | 
						|
 | 
						|
  if (aIID.Equals(NS_GET_IID(nsIMessageSender))) {
 | 
						|
    nsCOMPtr<nsIMessageSender> mm = GetMessageManager();
 | 
						|
    mm.forget(aResult);
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
  return NS_NOINTERFACE;
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvInitBackground(
 | 
						|
    Endpoint<PBackgroundStarterParent>&& aEndpoint) {
 | 
						|
  if (!BackgroundParent::AllocStarter(this, std::move(aEndpoint))) {
 | 
						|
    NS_WARNING("BackgroundParent::Alloc failed");
 | 
						|
  }
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::CanOpenBrowser(const IPCTabContext& aContext) {
 | 
						|
  // (PopupIPCTabContext lets the child process prove that it has access to
 | 
						|
  // the app it's trying to open.)
 | 
						|
  // On e10s we also allow UnsafeTabContext to allow service workers to open
 | 
						|
  // windows. This is enforced in MaybeInvalidTabContext.
 | 
						|
  if (aContext.type() != IPCTabContext::TPopupIPCTabContext) {
 | 
						|
    MOZ_CRASH_UNLESS_FUZZING(
 | 
						|
        "Unexpected IPCTabContext type.  Aborting AllocPBrowserParent.");
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
 | 
						|
    const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext();
 | 
						|
 | 
						|
    auto* opener = BrowserParent::GetFrom(popupContext.opener().AsParent());
 | 
						|
    if (!opener) {
 | 
						|
      MOZ_CRASH_UNLESS_FUZZING(
 | 
						|
          "Got null opener from child; aborting AllocPBrowserParent.");
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  MaybeInvalidTabContext tc(aContext);
 | 
						|
  if (!tc.IsValid()) {
 | 
						|
    NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext.  (%s)  "
 | 
						|
                             "Aborting AllocPBrowserParent.",
 | 
						|
                             tc.GetInvalidReason())
 | 
						|
                 .get());
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
static bool CloneIsLegal(ContentParent* aCp, CanonicalBrowsingContext& aSource,
 | 
						|
                         CanonicalBrowsingContext& aTarget) {
 | 
						|
  // Source and target must be in the same BCG
 | 
						|
  if (NS_WARN_IF(aSource.Group() != aTarget.Group())) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  // The source and target must be in different toplevel <browser>s
 | 
						|
  if (NS_WARN_IF(aSource.Top() == aTarget.Top())) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // Neither source nor target must be toplevel.
 | 
						|
  if (NS_WARN_IF(aSource.IsTop()) || NS_WARN_IF(aTarget.IsTop())) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // Both should be embedded by the same process.
 | 
						|
  auto* sourceEmbedder = aSource.GetParentWindowContext();
 | 
						|
  if (NS_WARN_IF(!sourceEmbedder) ||
 | 
						|
      NS_WARN_IF(sourceEmbedder->GetContentParent() != aCp)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  auto* targetEmbedder = aTarget.GetParentWindowContext();
 | 
						|
  if (NS_WARN_IF(!targetEmbedder) ||
 | 
						|
      NS_WARN_IF(targetEmbedder->GetContentParent() != aCp)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // All seems sane.
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvCloneDocumentTreeInto(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aSource,
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aTarget, PrintData&& aPrintData) {
 | 
						|
  if (aSource.IsNullOrDiscarded() || aTarget.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
 | 
						|
    // All existing processes have potentially been slated for removal already,
 | 
						|
    // such that any subsequent call to GetNewOrUsedLaunchingBrowserProcess
 | 
						|
    // (normally supposed to find an existing process here) will try to create
 | 
						|
    // a new process (but fail) that nobody would ever really use. Let's avoid
 | 
						|
    // this together with the expensive CloneDocumentTreeInto operation.
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  auto* source = aSource.get_canonical();
 | 
						|
  auto* target = aTarget.get_canonical();
 | 
						|
 | 
						|
  if (!CloneIsLegal(this, *source, *target)) {
 | 
						|
    return IPC_FAIL(this, "Illegal subframe clone");
 | 
						|
  }
 | 
						|
 | 
						|
  ContentParent* cp = source->GetContentParent();
 | 
						|
  if (NS_WARN_IF(!cp)) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  if (NS_WARN_IF(cp->GetRemoteType() == GetRemoteType())) {
 | 
						|
    // Wanted to switch to a target browsing context that's already local again.
 | 
						|
    // See bug 1676996 for how this can happen.
 | 
						|
    //
 | 
						|
    // Dropping the switch on the floor seems fine for this case, though we
 | 
						|
    // could also try to clone the local document.
 | 
						|
    //
 | 
						|
    // If the remote type matches & it's in the same group (which was confirmed
 | 
						|
    // by CloneIsLegal), it must be the exact same process.
 | 
						|
    MOZ_DIAGNOSTIC_ASSERT(cp == this);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  target->CloneDocumentTreeInto(source, cp->GetRemoteType(),
 | 
						|
                                std::move(aPrintData));
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvUpdateRemotePrintSettings(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aTarget, PrintData&& aPrintData) {
 | 
						|
  if (aTarget.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  auto* target = aTarget.get_canonical();
 | 
						|
  auto* bp = target->GetBrowserParent();
 | 
						|
  if (NS_WARN_IF(!bp)) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  Unused << bp->SendUpdateRemotePrintSettings(aPrintData);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvConstructPopupBrowser(
 | 
						|
    ManagedEndpoint<PBrowserParent>&& aBrowserEp,
 | 
						|
    ManagedEndpoint<PWindowGlobalParent>&& aWindowEp, const TabId& aTabId,
 | 
						|
    const IPCTabContext& aContext, const WindowGlobalInit& aInitialWindowInit,
 | 
						|
    const uint32_t& aChromeFlags) {
 | 
						|
  MOZ_ASSERT(XRE_IsParentProcess());
 | 
						|
 | 
						|
  if (!CanOpenBrowser(aContext)) {
 | 
						|
    return IPC_FAIL(this, "CanOpenBrowser Failed");
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<CanonicalBrowsingContext> browsingContext =
 | 
						|
      CanonicalBrowsingContext::Get(
 | 
						|
          aInitialWindowInit.context().mBrowsingContextId);
 | 
						|
  if (!browsingContext || browsingContext->IsDiscarded()) {
 | 
						|
    return IPC_FAIL(this, "Null or discarded initial BrowsingContext");
 | 
						|
  }
 | 
						|
  if (!aInitialWindowInit.principal()) {
 | 
						|
    return IPC_FAIL(this, "Cannot create without valid initial principal");
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ValidatePrincipal(aInitialWindowInit.principal())) {
 | 
						|
    LogAndAssertFailedPrincipalValidationInfo(aInitialWindowInit.principal(),
 | 
						|
                                              __func__);
 | 
						|
  }
 | 
						|
 | 
						|
  if (browsingContext->GetBrowserParent()) {
 | 
						|
    return IPC_FAIL(this, "BrowsingContext already has a BrowserParent");
 | 
						|
  }
 | 
						|
 | 
						|
  uint32_t chromeFlags = aChromeFlags;
 | 
						|
  TabId openerTabId(0);
 | 
						|
  ContentParentId openerCpId(0);
 | 
						|
  if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
 | 
						|
    // CanOpenBrowser has ensured that the IPCTabContext is of
 | 
						|
    // type PopupIPCTabContext, and that the opener BrowserParent is
 | 
						|
    // reachable.
 | 
						|
    const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext();
 | 
						|
    auto* opener = BrowserParent::GetFrom(popupContext.opener().AsParent());
 | 
						|
    openerTabId = opener->GetTabId();
 | 
						|
    openerCpId = opener->Manager()->ChildID();
 | 
						|
 | 
						|
    // We must ensure that the private browsing and remoteness flags
 | 
						|
    // match those of the opener.
 | 
						|
    nsCOMPtr<nsILoadContext> loadContext = opener->GetLoadContext();
 | 
						|
    if (!loadContext) {
 | 
						|
      return IPC_FAIL(this, "Missing Opener LoadContext");
 | 
						|
    }
 | 
						|
    if (loadContext->UsePrivateBrowsing()) {
 | 
						|
      chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
 | 
						|
    }
 | 
						|
    if (loadContext->UseRemoteSubframes()) {
 | 
						|
      chromeFlags |= nsIWebBrowserChrome::CHROME_FISSION_WINDOW;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // And because we're allocating a remote browser, of course the
 | 
						|
  // window is remote.
 | 
						|
  chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
 | 
						|
 | 
						|
  if (NS_WARN_IF(!browsingContext->IsOwnedByProcess(ChildID()))) {
 | 
						|
    return IPC_FAIL(this, "BrowsingContext Owned by Incorrect Process!");
 | 
						|
  }
 | 
						|
 | 
						|
  MaybeInvalidTabContext tc(aContext);
 | 
						|
  MOZ_ASSERT(tc.IsValid());
 | 
						|
 | 
						|
  RefPtr<WindowGlobalParent> initialWindow =
 | 
						|
      WindowGlobalParent::CreateDisconnected(aInitialWindowInit);
 | 
						|
  if (!initialWindow) {
 | 
						|
    return IPC_FAIL(this, "Failed to create WindowGlobalParent");
 | 
						|
  }
 | 
						|
 | 
						|
  auto parent = MakeRefPtr<BrowserParent>(this, aTabId, tc.GetTabContext(),
 | 
						|
                                          browsingContext, chromeFlags);
 | 
						|
 | 
						|
  // The creation of PBrowser was triggered from content process through
 | 
						|
  // window.open().
 | 
						|
  // We need to register remote frame with the child generated tab id.
 | 
						|
  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
 | 
						|
  if (!cpm || !cpm->RegisterRemoteFrame(parent)) {
 | 
						|
    return IPC_FAIL(this, "RegisterRemoteFrame Failed");
 | 
						|
  }
 | 
						|
 | 
						|
  // Bind the created BrowserParent to IPC to actually link the actor.
 | 
						|
  if (NS_WARN_IF(!BindPBrowserEndpoint(std::move(aBrowserEp), parent))) {
 | 
						|
    return IPC_FAIL(this, "BindPBrowserEndpoint failed");
 | 
						|
  }
 | 
						|
 | 
						|
  if (NS_WARN_IF(!parent->BindPWindowGlobalEndpoint(std::move(aWindowEp),
 | 
						|
                                                    initialWindow))) {
 | 
						|
    return IPC_FAIL(this, "BindPWindowGlobalEndpoint failed");
 | 
						|
  }
 | 
						|
 | 
						|
  browsingContext->SetCurrentBrowserParent(parent);
 | 
						|
 | 
						|
  initialWindow->Init();
 | 
						|
 | 
						|
  // When enabling input event prioritization, input events may preempt other
 | 
						|
  // normal priority IPC messages. To prevent the input events preempt
 | 
						|
  // PBrowserConstructor, we use an IPC 'RemoteIsReadyToHandleInputEvents' to
 | 
						|
  // notify parent that BrowserChild is created. In this case, PBrowser is
 | 
						|
  // initiated from content so that we can set BrowserParent as ready to handle
 | 
						|
  // input
 | 
						|
  parent->SetReadyToHandleInputEvents();
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::PRemoteSpellcheckEngineParent*
 | 
						|
ContentParent::AllocPRemoteSpellcheckEngineParent() {
 | 
						|
  mozilla::RemoteSpellcheckEngineParent* parent =
 | 
						|
      new mozilla::RemoteSpellcheckEngineParent();
 | 
						|
  return parent;
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::DeallocPRemoteSpellcheckEngineParent(
 | 
						|
    PRemoteSpellcheckEngineParent* parent) {
 | 
						|
  delete parent;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ContentParent::SendShutdownTimerCallback(nsITimer* aTimer,
 | 
						|
                                              void* aClosure) {
 | 
						|
  auto* self = static_cast<ContentParent*>(aClosure);
 | 
						|
  self->AsyncSendShutDownMessage();
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ContentParent::ForceKillTimerCallback(nsITimer* aTimer, void* aClosure) {
 | 
						|
  // We don't want to time out the content process during XPCShell tests. This
 | 
						|
  // is the easiest way to ensure that.
 | 
						|
  if (PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR")) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  auto* self = static_cast<ContentParent*>(aClosure);
 | 
						|
  self->KillHard("ShutDownKill");
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::GeneratePairedMinidump(const char* aReason) {
 | 
						|
  // We're about to kill the child process associated with this content.
 | 
						|
  // Something has gone wrong to get us here, so we generate a minidump
 | 
						|
  // of the parent and child for submission to the crash server unless we're
 | 
						|
  // already shutting down.
 | 
						|
  if (mCrashReporter &&
 | 
						|
      !AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed) &&
 | 
						|
      StaticPrefs::dom_ipc_tabs_createKillHardCrashReports_AtStartup()) {
 | 
						|
    // GeneratePairedMinidump creates two minidumps for us - the main
 | 
						|
    // one is for the content process we're about to kill, and the other
 | 
						|
    // one is for the main browser process. That second one is the extra
 | 
						|
    // minidump tagging along, so we have to tell the crash reporter that
 | 
						|
    // it exists and is being appended.
 | 
						|
    nsAutoCString additionalDumps("browser");
 | 
						|
    mCrashReporter->AddAnnotationNSCString(
 | 
						|
        CrashReporter::Annotation::additional_minidumps, additionalDumps);
 | 
						|
    nsDependentCString reason(aReason);
 | 
						|
    mCrashReporter->AddAnnotationNSCString(
 | 
						|
        CrashReporter::Annotation::ipc_channel_error, reason);
 | 
						|
 | 
						|
    // Generate the report and insert into the queue for submittal.
 | 
						|
    if (mCrashReporter->GenerateMinidumpAndPair(mSubprocess, "browser"_ns)) {
 | 
						|
      mCrashReporter->FinalizeCrashReport();
 | 
						|
      mCreatedPairedMinidumps = true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::HandleOrphanedMinidump(nsString* aDumpId) {
 | 
						|
  if (CrashReporter::FinalizeOrphanedMinidump(
 | 
						|
          OtherPid(), GeckoProcessType_Content, aDumpId)) {
 | 
						|
    CrashReporterHost::RecordCrash(GeckoProcessType_Content,
 | 
						|
                                   nsICrashService::CRASH_TYPE_CRASH, *aDumpId);
 | 
						|
  } else {
 | 
						|
    NS_WARNING(nsPrintfCString("content process pid = %" PRIPID
 | 
						|
                               " crashed without leaving a minidump behind",
 | 
						|
                               OtherPid())
 | 
						|
                   .get());
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// WARNING: aReason appears in telemetry, so any new value passed in requires
 | 
						|
// data review.
 | 
						|
void ContentParent::KillHard(const char* aReason) {
 | 
						|
  AUTO_PROFILER_LABEL("ContentParent::KillHard", OTHER);
 | 
						|
 | 
						|
  // On Windows, calling KillHard multiple times causes problems - the
 | 
						|
  // process handle becomes invalid on the first call, causing a second call
 | 
						|
  // to crash our process - more details in bug 890840.
 | 
						|
  if (mCalledKillHard) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  mCalledKillHard = true;
 | 
						|
  if (mSendShutdownTimer) {
 | 
						|
    mSendShutdownTimer->Cancel();
 | 
						|
    mSendShutdownTimer = nullptr;
 | 
						|
  }
 | 
						|
  if (mForceKillTimer) {
 | 
						|
    mForceKillTimer->Cancel();
 | 
						|
    mForceKillTimer = nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  RemoveShutdownBlockers();
 | 
						|
  nsCString reason = nsDependentCString(aReason);
 | 
						|
 | 
						|
  // If we find mIsNotifiedShutdownSuccess there is no reason to blame this
 | 
						|
  // content process, most probably our parent process is just slow in
 | 
						|
  // processing its own main thread queue.
 | 
						|
  if (!mIsNotifiedShutdownSuccess) {
 | 
						|
    GeneratePairedMinidump(aReason);
 | 
						|
  } else {
 | 
						|
    reason = nsDependentCString("KillHard after IsNotifiedShutdownSuccess.");
 | 
						|
  }
 | 
						|
  Telemetry::Accumulate(Telemetry::SUBPROCESS_KILL_HARD, reason, 1);
 | 
						|
 | 
						|
  ProcessHandle otherProcessHandle;
 | 
						|
  if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle)) {
 | 
						|
    NS_ERROR("Failed to open child process when attempting kill.");
 | 
						|
    if (CanSend()) {
 | 
						|
      GetIPCChannel()->InduceConnectionError();
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!KillProcess(otherProcessHandle, base::PROCESS_END_KILLED_BY_USER)) {
 | 
						|
    if (mCrashReporter) {
 | 
						|
      mCrashReporter->DeleteCrashReport();
 | 
						|
    }
 | 
						|
    NS_WARNING("failed to kill subprocess!");
 | 
						|
  }
 | 
						|
 | 
						|
  if (mSubprocess) {
 | 
						|
    MOZ_LOG(
 | 
						|
        ContentParent::GetLog(), LogLevel::Verbose,
 | 
						|
        ("KillHard Subprocess(%s): ContentParent %p mSubprocess %p handle "
 | 
						|
         "%" PRIuPTR,
 | 
						|
         aReason, this, mSubprocess,
 | 
						|
         mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
 | 
						|
    mSubprocess->SetAlreadyDead();
 | 
						|
  }
 | 
						|
 | 
						|
  // After we've killed the remote process, also ensure we induce a connection
 | 
						|
  // error in the IPC channel to immediately stop all IPC communication on this
 | 
						|
  // channel.
 | 
						|
  if (CanSend()) {
 | 
						|
    GetIPCChannel()->InduceConnectionError();
 | 
						|
  }
 | 
						|
 | 
						|
  // EnsureProcessTerminated has responsibilty for closing otherProcessHandle.
 | 
						|
  XRE_GetIOMessageLoop()->PostTask(
 | 
						|
      NewRunnableFunction("EnsureProcessTerminatedRunnable",
 | 
						|
                          &ProcessWatcher::EnsureProcessTerminated,
 | 
						|
                          otherProcessHandle, /*force=*/true));
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::FriendlyName(nsAString& aName, bool aAnonymize) {
 | 
						|
  aName.Truncate();
 | 
						|
  if (mIsForBrowser) {
 | 
						|
    aName.AssignLiteral("Browser");
 | 
						|
  } else if (aAnonymize) {
 | 
						|
    aName.AssignLiteral("<anonymized-name>");
 | 
						|
  } else {
 | 
						|
    aName.AssignLiteral("???");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvInitCrashReporter(
 | 
						|
    const NativeThreadId& aThreadId) {
 | 
						|
  mCrashReporter =
 | 
						|
      MakeUnique<CrashReporterHost>(GeckoProcessType_Content, aThreadId);
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
hal_sandbox::PHalParent* ContentParent::AllocPHalParent() {
 | 
						|
  return hal_sandbox::CreateHalParent();
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::DeallocPHalParent(hal_sandbox::PHalParent* aHal) {
 | 
						|
  delete aHal;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
devtools::PHeapSnapshotTempFileHelperParent*
 | 
						|
ContentParent::AllocPHeapSnapshotTempFileHelperParent() {
 | 
						|
  return devtools::HeapSnapshotTempFileHelperParent::Create();
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::DeallocPHeapSnapshotTempFileHelperParent(
 | 
						|
    devtools::PHeapSnapshotTempFileHelperParent* aHeapSnapshotHelper) {
 | 
						|
  delete aHeapSnapshotHelper;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::SendRequestMemoryReport(
 | 
						|
    const uint32_t& aGeneration, const bool& aAnonymize,
 | 
						|
    const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile) {
 | 
						|
  // This automatically cancels the previous request.
 | 
						|
  mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
 | 
						|
  // If we run the callback in response to a reply, then by definition |this|
 | 
						|
  // is still alive, so the ref pointer is redundant, but it seems easier
 | 
						|
  // to hold a strong reference than to worry about that.
 | 
						|
  RefPtr<ContentParent> self(this);
 | 
						|
  PContentParent::SendRequestMemoryReport(
 | 
						|
      aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile,
 | 
						|
      [&, self](const uint32_t& aGeneration2) {
 | 
						|
        if (self->mMemoryReportRequest) {
 | 
						|
          self->mMemoryReportRequest->Finish(aGeneration2);
 | 
						|
          self->mMemoryReportRequest = nullptr;
 | 
						|
        }
 | 
						|
      },
 | 
						|
      [&, self](mozilla::ipc::ResponseRejectReason) {
 | 
						|
        self->mMemoryReportRequest = nullptr;
 | 
						|
      });
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvAddMemoryReport(
 | 
						|
    const MemoryReport& aReport) {
 | 
						|
  if (mMemoryReportRequest) {
 | 
						|
    mMemoryReportRequest->RecvReport(aReport);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
PCycleCollectWithLogsParent* ContentParent::AllocPCycleCollectWithLogsParent(
 | 
						|
    const bool& aDumpAllTraces, const FileDescriptor& aGCLog,
 | 
						|
    const FileDescriptor& aCCLog) {
 | 
						|
  MOZ_CRASH("Don't call this; use ContentParent::CycleCollectWithLogs");
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::DeallocPCycleCollectWithLogsParent(
 | 
						|
    PCycleCollectWithLogsParent* aActor) {
 | 
						|
  delete aActor;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::CycleCollectWithLogs(
 | 
						|
    bool aDumpAllTraces, nsICycleCollectorLogSink* aSink,
 | 
						|
    nsIDumpGCAndCCLogsCallback* aCallback) {
 | 
						|
  return CycleCollectWithLogsParent::AllocAndSendConstructor(
 | 
						|
      this, aDumpAllTraces, aSink, aCallback);
 | 
						|
}
 | 
						|
 | 
						|
PScriptCacheParent* ContentParent::AllocPScriptCacheParent(
 | 
						|
    const FileDescOrError& cacheFile, const bool& wantCacheData) {
 | 
						|
  return new loader::ScriptCacheParent(wantCacheData);
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::DeallocPScriptCacheParent(PScriptCacheParent* cache) {
 | 
						|
  delete static_cast<loader::ScriptCacheParent*>(cache);
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
already_AddRefed<PNeckoParent> ContentParent::AllocPNeckoParent() {
 | 
						|
  RefPtr<NeckoParent> actor = new NeckoParent();
 | 
						|
  return actor.forget();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvInitStreamFilter(
 | 
						|
    const uint64_t& aChannelId, const nsAString& aAddonId,
 | 
						|
    InitStreamFilterResolver&& aResolver) {
 | 
						|
  extensions::StreamFilterParent::Create(this, aChannelId, aAddonId)
 | 
						|
      ->Then(
 | 
						|
          GetCurrentSerialEventTarget(), __func__,
 | 
						|
          [aResolver](mozilla::ipc::Endpoint<PStreamFilterChild>&& aEndpoint) {
 | 
						|
            aResolver(std::move(aEndpoint));
 | 
						|
          },
 | 
						|
          [aResolver](bool aDummy) {
 | 
						|
            aResolver(mozilla::ipc::Endpoint<PStreamFilterChild>());
 | 
						|
          });
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvAddSecurityState(
 | 
						|
    const MaybeDiscarded<WindowContext>& aContext, uint32_t aStateFlags) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  aContext.get()->AddSecurityState(aStateFlags);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
already_AddRefed<PExternalHelperAppParent>
 | 
						|
ContentParent::AllocPExternalHelperAppParent(
 | 
						|
    nsIURI* uri, const mozilla::net::LoadInfoArgs& aLoadInfoArgs,
 | 
						|
    const nsACString& aMimeContentType, const nsACString& aContentDisposition,
 | 
						|
    const uint32_t& aContentDispositionHint,
 | 
						|
    const nsAString& aContentDispositionFilename, const bool& aForceSave,
 | 
						|
    const int64_t& aContentLength, const bool& aWasFileChannel,
 | 
						|
    nsIURI* aReferrer, const MaybeDiscarded<BrowsingContext>& aContext) {
 | 
						|
  RefPtr<ExternalHelperAppParent> parent = new ExternalHelperAppParent(
 | 
						|
      uri, aContentLength, aWasFileChannel, aContentDisposition,
 | 
						|
      aContentDispositionHint, aContentDispositionFilename);
 | 
						|
  return parent.forget();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvPExternalHelperAppConstructor(
 | 
						|
    PExternalHelperAppParent* actor, nsIURI* uri,
 | 
						|
    const LoadInfoArgs& loadInfoArgs, const nsACString& aMimeContentType,
 | 
						|
    const nsACString& aContentDisposition,
 | 
						|
    const uint32_t& aContentDispositionHint,
 | 
						|
    const nsAString& aContentDispositionFilename, const bool& aForceSave,
 | 
						|
    const int64_t& aContentLength, const bool& aWasFileChannel,
 | 
						|
    nsIURI* aReferrer, const MaybeDiscarded<BrowsingContext>& aContext) {
 | 
						|
  BrowsingContext* context = aContext.IsDiscarded() ? nullptr : aContext.get();
 | 
						|
  if (!static_cast<ExternalHelperAppParent*>(actor)->Init(
 | 
						|
          loadInfoArgs, aMimeContentType, aForceSave, aReferrer, context)) {
 | 
						|
    return IPC_FAIL(this, "Init failed.");
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
already_AddRefed<PHandlerServiceParent>
 | 
						|
ContentParent::AllocPHandlerServiceParent() {
 | 
						|
  RefPtr<HandlerServiceParent> actor = new HandlerServiceParent();
 | 
						|
  return actor.forget();
 | 
						|
}
 | 
						|
 | 
						|
media::PMediaParent* ContentParent::AllocPMediaParent() {
 | 
						|
  return media::AllocPMediaParent();
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::DeallocPMediaParent(media::PMediaParent* aActor) {
 | 
						|
  return media::DeallocPMediaParent(aActor);
 | 
						|
}
 | 
						|
 | 
						|
PBenchmarkStorageParent* ContentParent::AllocPBenchmarkStorageParent() {
 | 
						|
  return new BenchmarkStorageParent;
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::DeallocPBenchmarkStorageParent(
 | 
						|
    PBenchmarkStorageParent* aActor) {
 | 
						|
  delete aActor;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef MOZ_WEBSPEECH
 | 
						|
already_AddRefed<PSpeechSynthesisParent>
 | 
						|
ContentParent::AllocPSpeechSynthesisParent() {
 | 
						|
  if (!StaticPrefs::media_webspeech_synth_enabled()) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
  RefPtr<SpeechSynthesisParent> actor = new SpeechSynthesisParent();
 | 
						|
  return actor.forget();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvPSpeechSynthesisConstructor(
 | 
						|
    PSpeechSynthesisParent* aActor) {
 | 
						|
  if (!static_cast<SpeechSynthesisParent*>(aActor)->SendInit()) {
 | 
						|
    return IPC_FAIL(this, "SpeechSynthesisParent::SendInit failed.");
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvStartVisitedQueries(
 | 
						|
    const nsTArray<RefPtr<nsIURI>>& aUris) {
 | 
						|
  nsCOMPtr<IHistory> history = components::History::Service();
 | 
						|
  if (!history) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  for (const auto& uri : aUris) {
 | 
						|
    if (NS_WARN_IF(!uri)) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    history->ScheduleVisitedQuery(uri, this);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSetURITitle(nsIURI* uri,
 | 
						|
                                                       const nsAString& title) {
 | 
						|
  if (!uri) {
 | 
						|
    return IPC_FAIL(this, "uri must not be null.");
 | 
						|
  }
 | 
						|
  nsCOMPtr<IHistory> history = components::History::Service();
 | 
						|
  if (history) {
 | 
						|
    history->SetURITitle(uri, title);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvIsSecureURI(
 | 
						|
    nsIURI* aURI, const OriginAttributes& aOriginAttributes,
 | 
						|
    bool* aIsSecureURI) {
 | 
						|
  nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID));
 | 
						|
  if (!sss) {
 | 
						|
    return IPC_FAIL(this, "Failed to get nsISiteSecurityService.");
 | 
						|
  }
 | 
						|
  if (!aURI) {
 | 
						|
    return IPC_FAIL(this, "aURI must not be null.");
 | 
						|
  }
 | 
						|
  nsresult rv = sss->IsSecureURI(aURI, aOriginAttributes, aIsSecureURI);
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    return IPC_FAIL(this, "IsSecureURI failed.");
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvAccumulateMixedContentHSTS(
 | 
						|
    nsIURI* aURI, const bool& aActive,
 | 
						|
    const OriginAttributes& aOriginAttributes) {
 | 
						|
  if (!aURI) {
 | 
						|
    return IPC_FAIL(this, "aURI must not be null.");
 | 
						|
  }
 | 
						|
  nsMixedContentBlocker::AccumulateMixedContentHSTS(aURI, aActive,
 | 
						|
                                                    aOriginAttributes);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvLoadURIExternal(
 | 
						|
    nsIURI* uri, nsIPrincipal* aTriggeringPrincipal,
 | 
						|
    nsIPrincipal* aRedirectPrincipal,
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext,
 | 
						|
    bool aWasExternallyTriggered, bool aHasValidUserGestureActivation,
 | 
						|
    bool aNewWindowTarget) {
 | 
						|
  if (aContext.IsDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsIExternalProtocolService> extProtService(
 | 
						|
      do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
 | 
						|
  if (!extProtService) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!uri) {
 | 
						|
    return IPC_FAIL(this, "uri must not be null.");
 | 
						|
  }
 | 
						|
 | 
						|
  BrowsingContext* bc = aContext.get();
 | 
						|
  extProtService->LoadURI(uri, aTriggeringPrincipal, aRedirectPrincipal, bc,
 | 
						|
                          aWasExternallyTriggered,
 | 
						|
                          aHasValidUserGestureActivation, aNewWindowTarget);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvExtProtocolChannelConnectParent(
 | 
						|
    const uint64_t& registrarId) {
 | 
						|
  nsresult rv;
 | 
						|
 | 
						|
  // First get the real channel created before redirect on the parent.
 | 
						|
  nsCOMPtr<nsIChannel> channel;
 | 
						|
  rv = NS_LinkRedirectChannels(registrarId, nullptr, getter_AddRefs(channel));
 | 
						|
  NS_ENSURE_SUCCESS(rv, IPC_OK());
 | 
						|
 | 
						|
  nsCOMPtr<nsIParentChannel> parent = do_QueryInterface(channel, &rv);
 | 
						|
  NS_ENSURE_SUCCESS(rv, IPC_OK());
 | 
						|
 | 
						|
  // The channel itself is its own (faked) parent, link it.
 | 
						|
  rv = NS_LinkRedirectChannels(registrarId, parent, getter_AddRefs(channel));
 | 
						|
  NS_ENSURE_SUCCESS(rv, IPC_OK());
 | 
						|
 | 
						|
  // Signal the parent channel that it's a redirect-to parent.  This will
 | 
						|
  // make AsyncOpen on it do nothing (what we want).
 | 
						|
  // Yes, this is a bit of a hack, but I don't think it's necessary to invent
 | 
						|
  // a new interface just to set this flag on the channel.
 | 
						|
  parent->SetParentListener(nullptr);
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvShowAlert(
 | 
						|
    nsIAlertNotification* aAlert) {
 | 
						|
  if (!aAlert) {
 | 
						|
    return IPC_FAIL(this, "aAlert must not be null.");
 | 
						|
  }
 | 
						|
  nsCOMPtr<nsIAlertsService> sysAlerts(components::Alerts::Service());
 | 
						|
  if (sysAlerts) {
 | 
						|
    sysAlerts->ShowAlert(aAlert, this);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvCloseAlert(const nsAString& aName,
 | 
						|
                                                      bool aContextClosed) {
 | 
						|
  nsCOMPtr<nsIAlertsService> sysAlerts(components::Alerts::Service());
 | 
						|
  if (sysAlerts) {
 | 
						|
    sysAlerts->CloseAlert(aName, aContextClosed);
 | 
						|
  }
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvDisableNotifications(
 | 
						|
    nsIPrincipal* aPrincipal) {
 | 
						|
  if (!aPrincipal) {
 | 
						|
    return IPC_FAIL(this, "No principal");
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ValidatePrincipal(aPrincipal)) {
 | 
						|
    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
 | 
						|
  }
 | 
						|
  Unused << Notification::RemovePermission(aPrincipal);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvOpenNotificationSettings(
 | 
						|
    nsIPrincipal* aPrincipal) {
 | 
						|
  if (!aPrincipal) {
 | 
						|
    return IPC_FAIL(this, "No principal");
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ValidatePrincipal(aPrincipal)) {
 | 
						|
    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
 | 
						|
  }
 | 
						|
  Unused << Notification::OpenSettings(aPrincipal);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvNotificationEvent(
 | 
						|
    const nsAString& aType, const NotificationEventData& aData) {
 | 
						|
  nsCOMPtr<nsIServiceWorkerManager> swm =
 | 
						|
      mozilla::components::ServiceWorkerManager::Service();
 | 
						|
  if (NS_WARN_IF(!swm)) {
 | 
						|
    // Probably shouldn't happen, but no need to crash the child process.
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  if (aType.EqualsLiteral("click")) {
 | 
						|
    nsresult rv = swm->SendNotificationClickEvent(
 | 
						|
        aData.originSuffix(), aData.scope(), aData.ID(), aData.title(),
 | 
						|
        aData.dir(), aData.lang(), aData.body(), aData.tag(), aData.icon(),
 | 
						|
        aData.data(), aData.behavior());
 | 
						|
    Unused << NS_WARN_IF(NS_FAILED(rv));
 | 
						|
  } else {
 | 
						|
    MOZ_ASSERT(aType.EqualsLiteral("close"));
 | 
						|
    nsresult rv = swm->SendNotificationCloseEvent(
 | 
						|
        aData.originSuffix(), aData.scope(), aData.ID(), aData.title(),
 | 
						|
        aData.dir(), aData.lang(), aData.body(), aData.tag(), aData.icon(),
 | 
						|
        aData.data(), aData.behavior());
 | 
						|
    Unused << NS_WARN_IF(NS_FAILED(rv));
 | 
						|
  }
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSyncMessage(
 | 
						|
    const nsAString& aMsg, const ClonedMessageData& aData,
 | 
						|
    nsTArray<StructuredCloneData>* aRetvals) {
 | 
						|
  AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("ContentParent::RecvSyncMessage",
 | 
						|
                                             OTHER, aMsg);
 | 
						|
  MMPrinter::Print("ContentParent::RecvSyncMessage", aMsg, aData);
 | 
						|
 | 
						|
  RefPtr<nsFrameMessageManager> ppm = mMessageManager;
 | 
						|
  if (ppm) {
 | 
						|
    ipc::StructuredCloneData data;
 | 
						|
    ipc::UnpackClonedMessageData(aData, data);
 | 
						|
 | 
						|
    ppm->ReceiveMessage(ppm, nullptr, aMsg, true, &data, aRetvals,
 | 
						|
                        IgnoreErrors());
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvAsyncMessage(
 | 
						|
    const nsAString& aMsg, const ClonedMessageData& aData) {
 | 
						|
  AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("ContentParent::RecvAsyncMessage",
 | 
						|
                                             OTHER, aMsg);
 | 
						|
  MMPrinter::Print("ContentParent::RecvAsyncMessage", aMsg, aData);
 | 
						|
 | 
						|
  RefPtr<nsFrameMessageManager> ppm = mMessageManager;
 | 
						|
  if (ppm) {
 | 
						|
    ipc::StructuredCloneData data;
 | 
						|
    ipc::UnpackClonedMessageData(aData, data);
 | 
						|
 | 
						|
    ppm->ReceiveMessage(ppm, nullptr, aMsg, false, &data, nullptr,
 | 
						|
                        IgnoreErrors());
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
MOZ_CAN_RUN_SCRIPT
 | 
						|
static int32_t AddGeolocationListener(
 | 
						|
    nsIDOMGeoPositionCallback* watcher,
 | 
						|
    nsIDOMGeoPositionErrorCallback* errorCallBack, bool highAccuracy) {
 | 
						|
  RefPtr<Geolocation> geo = Geolocation::NonWindowSingleton();
 | 
						|
 | 
						|
  UniquePtr<PositionOptions> options = MakeUnique<PositionOptions>();
 | 
						|
  options->mTimeout = 0;
 | 
						|
  options->mMaximumAge = 0;
 | 
						|
  options->mEnableHighAccuracy = highAccuracy;
 | 
						|
  return geo->WatchPosition(watcher, errorCallBack, std::move(options));
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvAddGeolocationListener(
 | 
						|
    const bool& aHighAccuracy) {
 | 
						|
  // To ensure no geolocation updates are skipped, we always force the
 | 
						|
  // creation of a new listener.
 | 
						|
  RecvRemoveGeolocationListener();
 | 
						|
  mGeolocationWatchID = AddGeolocationListener(this, this, aHighAccuracy);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvRemoveGeolocationListener() {
 | 
						|
  if (mGeolocationWatchID != -1) {
 | 
						|
    RefPtr<Geolocation> geo = Geolocation::NonWindowSingleton();
 | 
						|
    if (geo) {
 | 
						|
      geo->ClearWatch(mGeolocationWatchID);
 | 
						|
    }
 | 
						|
    mGeolocationWatchID = -1;
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSetGeolocationHigherAccuracy(
 | 
						|
    const bool& aEnable) {
 | 
						|
  // This should never be called without a listener already present,
 | 
						|
  // so this check allows us to forgo securing privileges.
 | 
						|
  if (mGeolocationWatchID != -1) {
 | 
						|
    RecvRemoveGeolocationListener();
 | 
						|
    mGeolocationWatchID = AddGeolocationListener(this, this, aEnable);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
ContentParent::HandleEvent(nsIDOMGeoPosition* postion) {
 | 
						|
  Unused << SendGeolocationUpdate(postion);
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
ContentParent::HandleEvent(GeolocationPositionError* positionError) {
 | 
						|
  Unused << SendGeolocationError(positionError->Code());
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvConsoleMessage(
 | 
						|
    const nsAString& aMessage) {
 | 
						|
  nsresult rv;
 | 
						|
  nsCOMPtr<nsIConsoleService> consoleService =
 | 
						|
      do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
 | 
						|
  if (NS_SUCCEEDED(rv)) {
 | 
						|
    RefPtr<nsConsoleMessage> msg(new nsConsoleMessage(aMessage));
 | 
						|
    msg->SetIsForwardedFromContentProcess(true);
 | 
						|
    consoleService->LogMessageWithMode(msg, nsIConsoleService::SuppressLog);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvReportFrameTimingData(
 | 
						|
    const LoadInfoArgs& loadInfoArgs, const nsAString& entryName,
 | 
						|
    const nsAString& initiatorType, UniquePtr<PerformanceTimingData>&& aData) {
 | 
						|
  if (!aData) {
 | 
						|
    return IPC_FAIL(this, "aData should not be null");
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<WindowGlobalParent> parent =
 | 
						|
      WindowGlobalParent::GetByInnerWindowId(loadInfoArgs.innerWindowID());
 | 
						|
  if (!parent || !parent->GetContentParent()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_ASSERT(parent->GetContentParent() != this,
 | 
						|
             "No need to bounce around if in the same process");
 | 
						|
 | 
						|
  Unused << parent->GetContentParent()->SendReportFrameTimingData(
 | 
						|
      loadInfoArgs, entryName, initiatorType, aData);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvScriptError(
 | 
						|
    const nsAString& aMessage, const nsAString& aSourceName,
 | 
						|
    const nsAString& aSourceLine, const uint32_t& aLineNumber,
 | 
						|
    const uint32_t& aColNumber, const uint32_t& aFlags,
 | 
						|
    const nsACString& aCategory, const bool& aIsFromPrivateWindow,
 | 
						|
    const uint64_t& aInnerWindowId, const bool& aIsFromChromeContext) {
 | 
						|
  return RecvScriptErrorInternal(aMessage, aSourceName, aSourceLine,
 | 
						|
                                 aLineNumber, aColNumber, aFlags, aCategory,
 | 
						|
                                 aIsFromPrivateWindow, aIsFromChromeContext);
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvScriptErrorWithStack(
 | 
						|
    const nsAString& aMessage, const nsAString& aSourceName,
 | 
						|
    const nsAString& aSourceLine, const uint32_t& aLineNumber,
 | 
						|
    const uint32_t& aColNumber, const uint32_t& aFlags,
 | 
						|
    const nsACString& aCategory, const bool& aIsFromPrivateWindow,
 | 
						|
    const bool& aIsFromChromeContext, const ClonedMessageData& aStack) {
 | 
						|
  return RecvScriptErrorInternal(
 | 
						|
      aMessage, aSourceName, aSourceLine, aLineNumber, aColNumber, aFlags,
 | 
						|
      aCategory, aIsFromPrivateWindow, aIsFromChromeContext, &aStack);
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvScriptErrorInternal(
 | 
						|
    const nsAString& aMessage, const nsAString& aSourceName,
 | 
						|
    const nsAString& aSourceLine, const uint32_t& aLineNumber,
 | 
						|
    const uint32_t& aColNumber, const uint32_t& aFlags,
 | 
						|
    const nsACString& aCategory, const bool& aIsFromPrivateWindow,
 | 
						|
    const bool& aIsFromChromeContext, const ClonedMessageData* aStack) {
 | 
						|
  nsresult rv;
 | 
						|
  nsCOMPtr<nsIConsoleService> consoleService =
 | 
						|
      do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsIScriptError> msg;
 | 
						|
 | 
						|
  if (aStack) {
 | 
						|
    StructuredCloneData data;
 | 
						|
    UnpackClonedMessageData(*aStack, data);
 | 
						|
 | 
						|
    AutoJSAPI jsapi;
 | 
						|
    if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) {
 | 
						|
      MOZ_CRASH();
 | 
						|
    }
 | 
						|
    JSContext* cx = jsapi.cx();
 | 
						|
 | 
						|
    JS::Rooted<JS::Value> stack(cx);
 | 
						|
    ErrorResult rv;
 | 
						|
    data.Read(cx, &stack, rv);
 | 
						|
    if (rv.Failed() || !stack.isObject()) {
 | 
						|
      rv.SuppressException();
 | 
						|
      return IPC_OK();
 | 
						|
    }
 | 
						|
 | 
						|
    JS::Rooted<JSObject*> stackObj(cx, &stack.toObject());
 | 
						|
    if (!JS::IsUnwrappedSavedFrame(stackObj)) {
 | 
						|
      return IPC_FAIL(this, "Unexpected object");
 | 
						|
    }
 | 
						|
 | 
						|
    JS::Rooted<JSObject*> stackGlobal(cx, JS::GetNonCCWObjectGlobal(stackObj));
 | 
						|
    msg = new nsScriptErrorWithStack(JS::NothingHandleValue, stackObj,
 | 
						|
                                     stackGlobal);
 | 
						|
  } else {
 | 
						|
    msg = new nsScriptError();
 | 
						|
  }
 | 
						|
 | 
						|
  rv = msg->Init(aMessage, aSourceName, aSourceLine, aLineNumber, aColNumber,
 | 
						|
                 aFlags, aCategory, aIsFromPrivateWindow, aIsFromChromeContext);
 | 
						|
  if (NS_FAILED(rv)) return IPC_OK();
 | 
						|
 | 
						|
  msg->SetIsForwardedFromContentProcess(true);
 | 
						|
 | 
						|
  consoleService->LogMessageWithMode(msg, nsIConsoleService::SuppressLog);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::DoLoadMessageManagerScript(const nsAString& aURL,
 | 
						|
                                               bool aRunInGlobalScope) {
 | 
						|
  MOZ_ASSERT(!aRunInGlobalScope);
 | 
						|
  return SendLoadProcessScript(aURL);
 | 
						|
}
 | 
						|
 | 
						|
nsresult ContentParent::DoSendAsyncMessage(const nsAString& aMessage,
 | 
						|
                                           StructuredCloneData& aData) {
 | 
						|
  ClonedMessageData data;
 | 
						|
  if (!BuildClonedMessageData(aData, data)) {
 | 
						|
    return NS_ERROR_DOM_DATA_CLONE_ERR;
 | 
						|
  }
 | 
						|
  if (!SendAsyncMessage(aMessage, data)) {
 | 
						|
    return NS_ERROR_UNEXPECTED;
 | 
						|
  }
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvCopyFavicon(
 | 
						|
    nsIURI* aOldURI, nsIURI* aNewURI, const bool& aInPrivateBrowsing) {
 | 
						|
  if (!aOldURI) {
 | 
						|
    return IPC_FAIL(this, "aOldURI should not be null");
 | 
						|
  }
 | 
						|
  if (!aNewURI) {
 | 
						|
    return IPC_FAIL(this, "aNewURI should not be null");
 | 
						|
  }
 | 
						|
 | 
						|
  nsDocShell::CopyFavicon(aOldURI, aNewURI, aInPrivateBrowsing);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvFindImageText(
 | 
						|
    IPCImage&& aImage, nsTArray<nsCString>&& aLanguages,
 | 
						|
    FindImageTextResolver&& aResolver) {
 | 
						|
  if (!TextRecognition::IsSupported() ||
 | 
						|
      !Preferences::GetBool("dom.text-recognition.enabled")) {
 | 
						|
    return IPC_FAIL(this, "Text recognition not available.");
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<DataSourceSurface> surf = nsContentUtils::IPCImageToSurface(aImage);
 | 
						|
  if (!surf) {
 | 
						|
    aResolver(TextRecognitionResultOrError("Failed to read image"_ns));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  TextRecognition::FindText(*surf, aLanguages)
 | 
						|
      ->Then(
 | 
						|
          GetCurrentSerialEventTarget(), __func__,
 | 
						|
          [resolver = std::move(aResolver)](
 | 
						|
              TextRecognition::NativePromise::ResolveOrRejectValue&& aValue) {
 | 
						|
            if (aValue.IsResolve()) {
 | 
						|
              resolver(TextRecognitionResultOrError(aValue.ResolveValue()));
 | 
						|
            } else {
 | 
						|
              resolver(TextRecognitionResultOrError(aValue.RejectValue()));
 | 
						|
            }
 | 
						|
          });
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::ShouldContinueFromReplyTimeout() {
 | 
						|
  RefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
 | 
						|
  return !monitor || !monitor->ShouldTimeOutCPOWs();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvAddIdleObserver(
 | 
						|
    const uint64_t& aObserverId, const uint32_t& aIdleTimeInS) {
 | 
						|
  nsresult rv;
 | 
						|
  nsCOMPtr<nsIUserIdleService> idleService =
 | 
						|
      do_GetService("@mozilla.org/widget/useridleservice;1", &rv);
 | 
						|
  NS_ENSURE_SUCCESS(rv, IPC_FAIL(this, "Failed to get UserIdleService."));
 | 
						|
 | 
						|
  RefPtr<ParentIdleListener> listener =
 | 
						|
      new ParentIdleListener(this, aObserverId, aIdleTimeInS);
 | 
						|
  rv = idleService->AddIdleObserver(listener, aIdleTimeInS);
 | 
						|
  NS_ENSURE_SUCCESS(rv, IPC_FAIL(this, "AddIdleObserver failed."));
 | 
						|
  mIdleListeners.AppendElement(listener);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvRemoveIdleObserver(
 | 
						|
    const uint64_t& aObserverId, const uint32_t& aIdleTimeInS) {
 | 
						|
  RefPtr<ParentIdleListener> listener;
 | 
						|
  for (int32_t i = mIdleListeners.Length() - 1; i >= 0; --i) {
 | 
						|
    listener = static_cast<ParentIdleListener*>(mIdleListeners[i].get());
 | 
						|
    if (listener->mObserver == aObserverId && listener->mTime == aIdleTimeInS) {
 | 
						|
      nsresult rv;
 | 
						|
      nsCOMPtr<nsIUserIdleService> idleService =
 | 
						|
          do_GetService("@mozilla.org/widget/useridleservice;1", &rv);
 | 
						|
      NS_ENSURE_SUCCESS(rv, IPC_FAIL(this, "Failed to get UserIdleService."));
 | 
						|
      idleService->RemoveIdleObserver(listener, aIdleTimeInS);
 | 
						|
      mIdleListeners.RemoveElementAt(i);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvBackUpXResources(
 | 
						|
    const FileDescriptor& aXSocketFd) {
 | 
						|
#ifndef MOZ_X11
 | 
						|
  MOZ_CRASH("This message only makes sense on X11 platforms");
 | 
						|
#else
 | 
						|
  MOZ_ASSERT(!mChildXSocketFdDup, "Already backed up X resources??");
 | 
						|
  if (aXSocketFd.IsValid()) {
 | 
						|
    mChildXSocketFdDup = aXSocketFd.ClonePlatformHandle();
 | 
						|
  }
 | 
						|
#endif
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
class AnonymousTemporaryFileRequestor final : public Runnable {
 | 
						|
 public:
 | 
						|
  AnonymousTemporaryFileRequestor(ContentParent* aCP, const uint64_t& aID)
 | 
						|
      : Runnable("dom::AnonymousTemporaryFileRequestor"),
 | 
						|
        mCP(aCP),
 | 
						|
        mID(aID),
 | 
						|
        mRv(NS_OK),
 | 
						|
        mPRFD(nullptr) {}
 | 
						|
 | 
						|
  NS_IMETHOD Run() override {
 | 
						|
    if (NS_IsMainThread()) {
 | 
						|
      FileDescOrError result;
 | 
						|
      if (NS_WARN_IF(NS_FAILED(mRv))) {
 | 
						|
        // Returning false will kill the child process; instead
 | 
						|
        // propagate the error and let the child handle it.
 | 
						|
        result = mRv;
 | 
						|
      } else {
 | 
						|
        result = FileDescriptor(FileDescriptor::PlatformHandleType(
 | 
						|
            PR_FileDesc2NativeHandle(mPRFD)));
 | 
						|
        // The FileDescriptor object owns a duplicate of the file handle; we
 | 
						|
        // must close the original (and clean up the NSPR descriptor).
 | 
						|
        PR_Close(mPRFD);
 | 
						|
      }
 | 
						|
      Unused << mCP->SendProvideAnonymousTemporaryFile(mID, result);
 | 
						|
      // It's important to release this reference while wr're on the main
 | 
						|
      // thread!
 | 
						|
      mCP = nullptr;
 | 
						|
    } else {
 | 
						|
      mRv = NS_OpenAnonymousTemporaryFile(&mPRFD);
 | 
						|
      NS_DispatchToMainThread(this);
 | 
						|
    }
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  RefPtr<ContentParent> mCP;
 | 
						|
  uint64_t mID;
 | 
						|
  nsresult mRv;
 | 
						|
  PRFileDesc* mPRFD;
 | 
						|
};
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvRequestAnonymousTemporaryFile(
 | 
						|
    const uint64_t& aID) {
 | 
						|
  // Make sure to send a callback to the child if we bail out early.
 | 
						|
  nsresult rv = NS_OK;
 | 
						|
  RefPtr<ContentParent> self(this);
 | 
						|
  auto autoNotifyChildOnError = MakeScopeExit([&, self]() {
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      FileDescOrError result(rv);
 | 
						|
      Unused << self->SendProvideAnonymousTemporaryFile(aID, result);
 | 
						|
    }
 | 
						|
  });
 | 
						|
 | 
						|
  // We use a helper runnable to open the anonymous temporary file on the IO
 | 
						|
  // thread.  The same runnable will call us back on the main thread when the
 | 
						|
  // file has been opened.
 | 
						|
  nsCOMPtr<nsIEventTarget> target =
 | 
						|
      do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
 | 
						|
  if (!target) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  rv = target->Dispatch(new AnonymousTemporaryFileRequestor(this, aID),
 | 
						|
                        NS_DISPATCH_NORMAL);
 | 
						|
  if (NS_WARN_IF(NS_FAILED(rv))) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  rv = NS_OK;
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvCreateAudioIPCConnection(
 | 
						|
    CreateAudioIPCConnectionResolver&& aResolver) {
 | 
						|
  FileDescriptor fd = CubebUtils::CreateAudioIPCConnection();
 | 
						|
  FileDescOrError result;
 | 
						|
  if (fd.IsValid()) {
 | 
						|
    result = fd;
 | 
						|
  } else {
 | 
						|
    result = NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
  aResolver(result);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
already_AddRefed<extensions::PExtensionsParent>
 | 
						|
ContentParent::AllocPExtensionsParent() {
 | 
						|
  return MakeAndAddRef<extensions::ExtensionsParent>();
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::NotifyUpdatedDictionaries() {
 | 
						|
  RefPtr<mozSpellChecker> spellChecker(mozSpellChecker::Create());
 | 
						|
  MOZ_ASSERT(spellChecker, "No spell checker?");
 | 
						|
 | 
						|
  nsTArray<nsCString> dictionaries;
 | 
						|
  spellChecker->GetDictionaryList(&dictionaries);
 | 
						|
 | 
						|
  for (auto* cp : AllProcesses(eLive)) {
 | 
						|
    Unused << cp->SendUpdateDictionaryList(dictionaries);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::NotifyUpdatedFonts(bool aFullRebuild) {
 | 
						|
  if (gfxPlatformFontList::PlatformFontList()->SharedFontList()) {
 | 
						|
    for (auto* cp : AllProcesses(eLive)) {
 | 
						|
      Unused << cp->SendRebuildFontList(aFullRebuild);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  SystemFontList fontList;
 | 
						|
  gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList);
 | 
						|
 | 
						|
  for (auto* cp : AllProcesses(eLive)) {
 | 
						|
    Unused << cp->SendUpdateFontList(fontList);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
#ifdef MOZ_WEBRTC
 | 
						|
PWebrtcGlobalParent* ContentParent::AllocPWebrtcGlobalParent() {
 | 
						|
  return WebrtcGlobalParent::Alloc();
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::DeallocPWebrtcGlobalParent(PWebrtcGlobalParent* aActor) {
 | 
						|
  WebrtcGlobalParent::Dealloc(static_cast<WebrtcGlobalParent*>(aActor));
 | 
						|
  return true;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
PContentPermissionRequestParent*
 | 
						|
ContentParent::AllocPContentPermissionRequestParent(
 | 
						|
    const nsTArray<PermissionRequest>& aRequests, nsIPrincipal* aPrincipal,
 | 
						|
    nsIPrincipal* aTopLevelPrincipal, const bool& aIsHandlingUserInput,
 | 
						|
    const bool& aMaybeUnsafePermissionDelegate, const TabId& aTabId) {
 | 
						|
  RefPtr<BrowserParent> tp;
 | 
						|
  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
 | 
						|
  if (cpm) {
 | 
						|
    tp =
 | 
						|
        cpm->GetTopLevelBrowserParentByProcessAndTabId(this->ChildID(), aTabId);
 | 
						|
  }
 | 
						|
  if (!tp) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  nsIPrincipal* topPrincipal = aTopLevelPrincipal;
 | 
						|
  if (!topPrincipal) {
 | 
						|
    nsCOMPtr<nsIPrincipal> principal = tp->GetContentPrincipal();
 | 
						|
    topPrincipal = principal;
 | 
						|
  }
 | 
						|
  return nsContentPermissionUtils::CreateContentPermissionRequestParent(
 | 
						|
      aRequests, tp->GetOwnerElement(), aPrincipal, topPrincipal,
 | 
						|
      aIsHandlingUserInput, aMaybeUnsafePermissionDelegate, aTabId);
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::DeallocPContentPermissionRequestParent(
 | 
						|
    PContentPermissionRequestParent* actor) {
 | 
						|
  nsContentPermissionUtils::NotifyRemoveContentPermissionRequestParent(actor);
 | 
						|
  delete actor;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
already_AddRefed<PWebBrowserPersistDocumentParent>
 | 
						|
ContentParent::AllocPWebBrowserPersistDocumentParent(
 | 
						|
    PBrowserParent* aBrowser, const MaybeDiscarded<BrowsingContext>& aContext) {
 | 
						|
  return MakeAndAddRef<WebBrowserPersistDocumentParent>();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::CommonCreateWindow(
 | 
						|
    PBrowserParent* aThisTab, BrowsingContext& aParent, bool aSetOpener,
 | 
						|
    const uint32_t& aChromeFlags, const bool& aCalledFromJS,
 | 
						|
    const bool& aForPrinting, const bool& aForWindowDotPrint,
 | 
						|
    const bool& aIsTopLevelCreatedByWebContent, nsIURI* aURIToLoad,
 | 
						|
    const nsACString& aFeatures, const UserActivation::Modifiers& aModifiers,
 | 
						|
    BrowserParent* aNextRemoteBrowser, const nsAString& aName,
 | 
						|
    nsresult& aResult, nsCOMPtr<nsIRemoteTab>& aNewRemoteTab,
 | 
						|
    bool* aWindowIsNew, int32_t& aOpenLocation,
 | 
						|
    nsIPrincipal* aTriggeringPrincipal, nsIReferrerInfo* aReferrerInfo,
 | 
						|
    bool aLoadURI, nsIContentSecurityPolicy* aCsp,
 | 
						|
    const OriginAttributes& aOriginAttributes) {
 | 
						|
  // The content process should never be in charge of computing whether or
 | 
						|
  // not a window should be private - the parent will do that.
 | 
						|
  const uint32_t badFlags = nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW |
 | 
						|
                            nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW |
 | 
						|
                            nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME;
 | 
						|
  if (!!(aChromeFlags & badFlags)) {
 | 
						|
    return IPC_FAIL(this, "Forbidden aChromeFlags passed");
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<nsOpenWindowInfo> openInfo = new nsOpenWindowInfo();
 | 
						|
  openInfo->mForceNoOpener = !aSetOpener;
 | 
						|
  openInfo->mParent = &aParent;
 | 
						|
  openInfo->mIsRemote = true;
 | 
						|
  openInfo->mIsForPrinting = aForPrinting;
 | 
						|
  openInfo->mIsForWindowDotPrint = aForWindowDotPrint;
 | 
						|
  openInfo->mNextRemoteBrowser = aNextRemoteBrowser;
 | 
						|
  openInfo->mOriginAttributes = aOriginAttributes;
 | 
						|
  openInfo->mIsTopLevelCreatedByWebContent = aIsTopLevelCreatedByWebContent;
 | 
						|
 | 
						|
  MOZ_ASSERT_IF(aForWindowDotPrint, aForPrinting);
 | 
						|
 | 
						|
  RefPtr<BrowserParent> topParent = BrowserParent::GetFrom(aThisTab);
 | 
						|
  while (topParent && topParent->GetBrowserBridgeParent()) {
 | 
						|
    topParent = topParent->GetBrowserBridgeParent()->Manager();
 | 
						|
  }
 | 
						|
  RefPtr<BrowserHost> thisBrowserHost =
 | 
						|
      topParent ? topParent->GetBrowserHost() : nullptr;
 | 
						|
  MOZ_ASSERT_IF(topParent, thisBrowserHost);
 | 
						|
  RefPtr<BrowsingContext> topBC =
 | 
						|
      topParent ? topParent->GetBrowsingContext() : nullptr;
 | 
						|
  MOZ_ASSERT_IF(topParent, topBC);
 | 
						|
 | 
						|
  // The content process should have set its remote and fission flags correctly.
 | 
						|
  if (topBC) {
 | 
						|
    if ((!!(aChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) !=
 | 
						|
         topBC->UseRemoteTabs()) ||
 | 
						|
        (!!(aChromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW) !=
 | 
						|
         topBC->UseRemoteSubframes())) {
 | 
						|
      return IPC_FAIL(this, "Unexpected aChromeFlags passed");
 | 
						|
    }
 | 
						|
 | 
						|
    if (!aOriginAttributes.EqualsIgnoringFPD(topBC->OriginAttributesRef())) {
 | 
						|
      return IPC_FAIL(this, "Passed-in OriginAttributes does not match opener");
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsIContent> frame;
 | 
						|
  if (topParent) {
 | 
						|
    frame = topParent->GetOwnerElement();
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsPIDOMWindowOuter> outerWin;
 | 
						|
  if (frame) {
 | 
						|
    outerWin = frame->OwnerDoc()->GetWindow();
 | 
						|
 | 
						|
    // If our chrome window is in the process of closing, don't try to open a
 | 
						|
    // new tab in it.
 | 
						|
    if (outerWin && outerWin->Closed()) {
 | 
						|
      outerWin = nullptr;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
 | 
						|
  if (topParent) {
 | 
						|
    browserDOMWin = topParent->GetBrowserDOMWindow();
 | 
						|
  }
 | 
						|
 | 
						|
  // If we haven't found a chrome window to open in, just use the most recently
 | 
						|
  // opened one.
 | 
						|
  if (!outerWin) {
 | 
						|
    outerWin = nsContentUtils::GetMostRecentNonPBWindow();
 | 
						|
    if (NS_WARN_IF(!outerWin)) {
 | 
						|
      aResult = NS_ERROR_FAILURE;
 | 
						|
      return IPC_OK();
 | 
						|
    }
 | 
						|
 | 
						|
    if (nsGlobalWindowOuter::Cast(outerWin)->IsChromeWindow()) {
 | 
						|
      browserDOMWin =
 | 
						|
          nsGlobalWindowOuter::Cast(outerWin)->GetBrowserDOMWindow();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  aOpenLocation = nsWindowWatcher::GetWindowOpenLocation(
 | 
						|
      outerWin, aChromeFlags, aModifiers, aCalledFromJS, aForPrinting);
 | 
						|
 | 
						|
  MOZ_ASSERT(aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
 | 
						|
             aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB_BACKGROUND ||
 | 
						|
             aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWWINDOW ||
 | 
						|
             aOpenLocation == nsIBrowserDOMWindow::OPEN_PRINT_BROWSER);
 | 
						|
 | 
						|
  if (NS_WARN_IF(!browserDOMWin)) {
 | 
						|
    // Opening in the same window or headless requires an nsIBrowserDOMWindow.
 | 
						|
    aOpenLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
 | 
						|
  }
 | 
						|
 | 
						|
  if (aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
 | 
						|
      aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB_BACKGROUND ||
 | 
						|
      aOpenLocation == nsIBrowserDOMWindow::OPEN_PRINT_BROWSER) {
 | 
						|
    RefPtr<Element> openerElement = do_QueryObject(frame);
 | 
						|
 | 
						|
    nsCOMPtr<nsIOpenURIInFrameParams> params =
 | 
						|
        new nsOpenURIInFrameParams(openInfo, openerElement);
 | 
						|
    params->SetReferrerInfo(aReferrerInfo);
 | 
						|
    MOZ_ASSERT(aTriggeringPrincipal, "need a valid triggeringPrincipal");
 | 
						|
    params->SetTriggeringPrincipal(aTriggeringPrincipal);
 | 
						|
    params->SetCsp(aCsp);
 | 
						|
 | 
						|
    RefPtr<Element> el;
 | 
						|
 | 
						|
    if (aLoadURI) {
 | 
						|
      aResult = browserDOMWin->OpenURIInFrame(aURIToLoad, params, aOpenLocation,
 | 
						|
                                              nsIBrowserDOMWindow::OPEN_NEW,
 | 
						|
                                              aName, getter_AddRefs(el));
 | 
						|
    } else {
 | 
						|
      aResult = browserDOMWin->CreateContentWindowInFrame(
 | 
						|
          aURIToLoad, params, aOpenLocation, nsIBrowserDOMWindow::OPEN_NEW,
 | 
						|
          aName, getter_AddRefs(el));
 | 
						|
    }
 | 
						|
    RefPtr<nsFrameLoaderOwner> frameLoaderOwner = do_QueryObject(el);
 | 
						|
    if (NS_SUCCEEDED(aResult) && frameLoaderOwner) {
 | 
						|
      RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
 | 
						|
      if (frameLoader) {
 | 
						|
        aNewRemoteTab = frameLoader->GetRemoteTab();
 | 
						|
        // At this point, it's possible the inserted frameloader hasn't gone
 | 
						|
        // through layout yet. To ensure that the dimensions that we send down
 | 
						|
        // when telling the frameloader to display will be correct (instead of
 | 
						|
        // falling back to a 10x10 default), we force layout if necessary to get
 | 
						|
        // the most up-to-date dimensions. See bug 1358712 for details.
 | 
						|
        frameLoader->ForceLayoutIfNecessary();
 | 
						|
      }
 | 
						|
    } else if (NS_SUCCEEDED(aResult) && !frameLoaderOwner) {
 | 
						|
      // Fall through to the normal window opening code path when there is no
 | 
						|
      // window which we can open a new tab in.
 | 
						|
      aOpenLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
 | 
						|
    } else {
 | 
						|
      *aWindowIsNew = false;
 | 
						|
    }
 | 
						|
 | 
						|
    // If we didn't retarget our window open into a new window, we should return
 | 
						|
    // now.
 | 
						|
    if (aOpenLocation != nsIBrowserDOMWindow::OPEN_NEWWINDOW) {
 | 
						|
      return IPC_OK();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsPIWindowWatcher> pwwatch =
 | 
						|
      do_GetService(NS_WINDOWWATCHER_CONTRACTID, &aResult);
 | 
						|
  if (NS_WARN_IF(NS_FAILED(aResult))) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  WindowFeatures features;
 | 
						|
  features.Tokenize(aFeatures);
 | 
						|
 | 
						|
  aResult = pwwatch->OpenWindowWithRemoteTab(
 | 
						|
      thisBrowserHost, features, aModifiers, aCalledFromJS, aParent.FullZoom(),
 | 
						|
      openInfo, getter_AddRefs(aNewRemoteTab));
 | 
						|
  if (NS_WARN_IF(NS_FAILED(aResult))) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_ASSERT(aNewRemoteTab);
 | 
						|
  RefPtr<BrowserHost> newBrowserHost = BrowserHost::GetFrom(aNewRemoteTab);
 | 
						|
  RefPtr<BrowserParent> newBrowserParent = newBrowserHost->GetActor();
 | 
						|
 | 
						|
  // At this point, it's possible the inserted frameloader hasn't gone through
 | 
						|
  // layout yet. To ensure that the dimensions that we send down when telling
 | 
						|
  // the frameloader to display will be correct (instead of falling back to a
 | 
						|
  // 10x10 default), we force layout if necessary to get the most up-to-date
 | 
						|
  // dimensions. See bug 1358712 for details.
 | 
						|
  nsCOMPtr<Element> frameElement = newBrowserHost->GetOwnerElement();
 | 
						|
  MOZ_ASSERT(frameElement);
 | 
						|
  if (nsWindowWatcher::HaveSpecifiedSize(features)) {
 | 
						|
    // We want to flush the layout anyway because of the resize to the specified
 | 
						|
    // size. (Bug 1793605).
 | 
						|
    RefPtr<Document> chromeDoc = frameElement->OwnerDoc();
 | 
						|
    MOZ_ASSERT(chromeDoc);
 | 
						|
    chromeDoc->FlushPendingNotifications(FlushType::Layout);
 | 
						|
  } else {
 | 
						|
    RefPtr<nsFrameLoaderOwner> frameLoaderOwner = do_QueryObject(frameElement);
 | 
						|
    MOZ_ASSERT(frameLoaderOwner);
 | 
						|
    RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
 | 
						|
    MOZ_ASSERT(frameLoader);
 | 
						|
    frameLoader->ForceLayoutIfNecessary();
 | 
						|
  }
 | 
						|
 | 
						|
  // If we were passed a name for the window which would override the default,
 | 
						|
  // we should send it down to the new tab.
 | 
						|
  if (nsContentUtils::IsOverridingWindowName(aName)) {
 | 
						|
    MOZ_ALWAYS_SUCCEEDS(newBrowserHost->GetBrowsingContext()->SetName(aName));
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_ASSERT(newBrowserHost->GetBrowsingContext()->OriginAttributesRef() ==
 | 
						|
             aOriginAttributes);
 | 
						|
 | 
						|
  if (aURIToLoad && aLoadURI) {
 | 
						|
    nsCOMPtr<mozIDOMWindowProxy> openerWindow;
 | 
						|
    if (aSetOpener && topParent) {
 | 
						|
      openerWindow = topParent->GetParentWindowOuter();
 | 
						|
    }
 | 
						|
    nsCOMPtr<nsIBrowserDOMWindow> newBrowserDOMWin =
 | 
						|
        newBrowserParent->GetBrowserDOMWindow();
 | 
						|
    if (NS_WARN_IF(!newBrowserDOMWin)) {
 | 
						|
      aResult = NS_ERROR_ABORT;
 | 
						|
      return IPC_OK();
 | 
						|
    }
 | 
						|
    RefPtr<BrowsingContext> bc;
 | 
						|
    aResult = newBrowserDOMWin->OpenURI(
 | 
						|
        aURIToLoad, openInfo, nsIBrowserDOMWindow::OPEN_CURRENTWINDOW,
 | 
						|
        nsIBrowserDOMWindow::OPEN_NEW, aTriggeringPrincipal, aCsp,
 | 
						|
        getter_AddRefs(bc));
 | 
						|
  }
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvCreateWindow(
 | 
						|
    PBrowserParent* aThisTab, const MaybeDiscarded<BrowsingContext>& aParent,
 | 
						|
    PBrowserParent* aNewTab, const uint32_t& aChromeFlags,
 | 
						|
    const bool& aCalledFromJS, const bool& aForPrinting,
 | 
						|
    const bool& aForWindowDotPrint, const bool& aIsTopLevelCreatedByWebContent,
 | 
						|
    nsIURI* aURIToLoad, const nsACString& aFeatures,
 | 
						|
    const UserActivation::Modifiers& aModifiers,
 | 
						|
    nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp,
 | 
						|
    nsIReferrerInfo* aReferrerInfo, const OriginAttributes& aOriginAttributes,
 | 
						|
    CreateWindowResolver&& aResolve) {
 | 
						|
  if (!aTriggeringPrincipal) {
 | 
						|
    return IPC_FAIL(this, "No principal");
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ValidatePrincipal(aTriggeringPrincipal)) {
 | 
						|
    LogAndAssertFailedPrincipalValidationInfo(aTriggeringPrincipal, __func__);
 | 
						|
  }
 | 
						|
 | 
						|
  nsresult rv = NS_OK;
 | 
						|
  CreatedWindowInfo cwi;
 | 
						|
 | 
						|
  // We always expect to open a new window here. If we don't, it's an error.
 | 
						|
  cwi.windowOpened() = true;
 | 
						|
  cwi.maxTouchPoints() = 0;
 | 
						|
 | 
						|
  // Make sure to resolve the resolver when this function exits, even if we
 | 
						|
  // failed to generate a valid response.
 | 
						|
  auto resolveOnExit = MakeScopeExit([&] {
 | 
						|
    // Copy over the nsresult, and then resolve.
 | 
						|
    cwi.rv() = rv;
 | 
						|
    aResolve(cwi);
 | 
						|
  });
 | 
						|
 | 
						|
  RefPtr<BrowserParent> thisTab = BrowserParent::GetFrom(aThisTab);
 | 
						|
  RefPtr<BrowserParent> newTab = BrowserParent::GetFrom(aNewTab);
 | 
						|
  MOZ_ASSERT(newTab);
 | 
						|
 | 
						|
  auto destroyNewTabOnError = MakeScopeExit([&] {
 | 
						|
    // We always expect to open a new window here. If we don't, it's an error.
 | 
						|
    if (!cwi.windowOpened() || NS_FAILED(rv)) {
 | 
						|
      if (newTab) {
 | 
						|
        newTab->Destroy();
 | 
						|
      }
 | 
						|
    }
 | 
						|
  });
 | 
						|
 | 
						|
  // Don't continue to try to create a new window if we've been fully discarded.
 | 
						|
  RefPtr<BrowsingContext> parent = aParent.GetMaybeDiscarded();
 | 
						|
  if (NS_WARN_IF(!parent)) {
 | 
						|
    rv = NS_ERROR_FAILURE;
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  // Validate that our new BrowsingContext looks as we would expect it.
 | 
						|
  RefPtr<BrowsingContext> newBC = newTab->GetBrowsingContext();
 | 
						|
  if (!newBC) {
 | 
						|
    return IPC_FAIL(this, "Missing BrowsingContext for new tab");
 | 
						|
  }
 | 
						|
 | 
						|
  uint64_t newBCOpenerId = newBC->GetOpenerId();
 | 
						|
  if (newBCOpenerId != 0 && parent->Id() != newBCOpenerId) {
 | 
						|
    return IPC_FAIL(this, "Invalid opener BrowsingContext for new tab");
 | 
						|
  }
 | 
						|
  if (newBC->GetParent() != nullptr) {
 | 
						|
    return IPC_FAIL(this,
 | 
						|
                    "Unexpected non-toplevel BrowsingContext for new tab");
 | 
						|
  }
 | 
						|
  if (!!(aChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) !=
 | 
						|
          newBC->UseRemoteTabs() ||
 | 
						|
      !!(aChromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW) !=
 | 
						|
          newBC->UseRemoteSubframes()) {
 | 
						|
    return IPC_FAIL(this, "Unexpected aChromeFlags passed");
 | 
						|
  }
 | 
						|
  if (!aOriginAttributes.EqualsIgnoringFPD(newBC->OriginAttributesRef())) {
 | 
						|
    return IPC_FAIL(this, "Opened tab has mismatched OriginAttributes");
 | 
						|
  }
 | 
						|
 | 
						|
  if (thisTab && BrowserParent::GetFrom(thisTab)->GetBrowsingContext()) {
 | 
						|
    BrowsingContext* thisTabBC = thisTab->GetBrowsingContext();
 | 
						|
    if (thisTabBC->UseRemoteTabs() != newBC->UseRemoteTabs() ||
 | 
						|
        thisTabBC->UseRemoteSubframes() != newBC->UseRemoteSubframes() ||
 | 
						|
        thisTabBC->UsePrivateBrowsing() != newBC->UsePrivateBrowsing()) {
 | 
						|
      return IPC_FAIL(this, "New BrowsingContext has mismatched LoadContext");
 | 
						|
    }
 | 
						|
  }
 | 
						|
  BrowserParent::AutoUseNewTab aunt(newTab);
 | 
						|
 | 
						|
  nsCOMPtr<nsIRemoteTab> newRemoteTab;
 | 
						|
  int32_t openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
 | 
						|
  mozilla::ipc::IPCResult ipcResult = CommonCreateWindow(
 | 
						|
      aThisTab, *parent, newBCOpenerId != 0, aChromeFlags, aCalledFromJS,
 | 
						|
      aForPrinting, aForWindowDotPrint, aIsTopLevelCreatedByWebContent,
 | 
						|
      aURIToLoad, aFeatures, aModifiers, newTab, VoidString(), rv, newRemoteTab,
 | 
						|
      &cwi.windowOpened(), openLocation, aTriggeringPrincipal, aReferrerInfo,
 | 
						|
      /* aLoadUri = */ false, aCsp, aOriginAttributes);
 | 
						|
  if (!ipcResult) {
 | 
						|
    return ipcResult;
 | 
						|
  }
 | 
						|
 | 
						|
  if (NS_WARN_IF(NS_FAILED(rv)) || !newRemoteTab) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_ASSERT(BrowserHost::GetFrom(newRemoteTab.get()) ==
 | 
						|
             newTab->GetBrowserHost());
 | 
						|
 | 
						|
  // This used to happen in the child - there may now be a better place to
 | 
						|
  // do this work.
 | 
						|
  MOZ_ALWAYS_SUCCEEDS(newBC->SetHasSiblings(
 | 
						|
      openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
 | 
						|
      openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB_BACKGROUND));
 | 
						|
 | 
						|
  newTab->SwapFrameScriptsFrom(cwi.frameScripts());
 | 
						|
  newTab->MaybeShowFrame();
 | 
						|
 | 
						|
  nsCOMPtr<nsIWidget> widget = newTab->GetWidget();
 | 
						|
  if (widget) {
 | 
						|
    cwi.dimensions() = newTab->GetDimensionInfo();
 | 
						|
  }
 | 
						|
 | 
						|
  cwi.maxTouchPoints() = newTab->GetMaxTouchPoints();
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvCreateWindowInDifferentProcess(
 | 
						|
    PBrowserParent* aThisTab, const MaybeDiscarded<BrowsingContext>& aParent,
 | 
						|
    const uint32_t& aChromeFlags, const bool& aCalledFromJS,
 | 
						|
    const bool& aIsTopLevelCreatedByWebContent, nsIURI* aURIToLoad,
 | 
						|
    const nsACString& aFeatures, const UserActivation::Modifiers& aModifiers,
 | 
						|
    const nsAString& aName, nsIPrincipal* aTriggeringPrincipal,
 | 
						|
    nsIContentSecurityPolicy* aCsp, nsIReferrerInfo* aReferrerInfo,
 | 
						|
    const OriginAttributes& aOriginAttributes) {
 | 
						|
  MOZ_DIAGNOSTIC_ASSERT(!nsContentUtils::IsSpecialName(aName));
 | 
						|
 | 
						|
  // Don't continue to try to create a new window if we've been fully discarded.
 | 
						|
  RefPtr<BrowsingContext> parent = aParent.GetMaybeDiscarded();
 | 
						|
  if (NS_WARN_IF(!parent)) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsIRemoteTab> newRemoteTab;
 | 
						|
  bool windowIsNew;
 | 
						|
  int32_t openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
 | 
						|
 | 
						|
  // If we have enough data, check the schemes of the loader and loadee
 | 
						|
  // to make sure they make sense.
 | 
						|
  if (aURIToLoad && aURIToLoad->SchemeIs("file") &&
 | 
						|
      GetRemoteType() != FILE_REMOTE_TYPE &&
 | 
						|
      Preferences::GetBool("browser.tabs.remote.enforceRemoteTypeRestrictions",
 | 
						|
                           false)) {
 | 
						|
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 | 
						|
#  ifdef DEBUG
 | 
						|
    nsAutoCString uriToLoadStr;
 | 
						|
    nsAutoCString triggeringUriStr;
 | 
						|
    aURIToLoad->GetAsciiSpec(uriToLoadStr);
 | 
						|
    aTriggeringPrincipal->GetAsciiSpec(triggeringUriStr);
 | 
						|
 | 
						|
    NS_WARNING(nsPrintfCString(
 | 
						|
                   "RecvCreateWindowInDifferentProcess blocked loading file "
 | 
						|
                   "scheme from non-file remotetype: %s tried to load %s",
 | 
						|
                   triggeringUriStr.get(), uriToLoadStr.get())
 | 
						|
                   .get());
 | 
						|
#  endif
 | 
						|
    MOZ_CRASH(
 | 
						|
        "RecvCreateWindowInDifferentProcess blocked loading improper scheme");
 | 
						|
#endif
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  nsresult rv;
 | 
						|
  mozilla::ipc::IPCResult ipcResult = CommonCreateWindow(
 | 
						|
      aThisTab, *parent, /* aSetOpener = */ false, aChromeFlags, aCalledFromJS,
 | 
						|
      /* aForPrinting = */ false,
 | 
						|
      /* aForWindowDotPrint = */ false, aIsTopLevelCreatedByWebContent,
 | 
						|
      aURIToLoad, aFeatures, aModifiers,
 | 
						|
      /* aNextRemoteBrowser = */ nullptr, aName, rv, newRemoteTab, &windowIsNew,
 | 
						|
      openLocation, aTriggeringPrincipal, aReferrerInfo,
 | 
						|
      /* aLoadUri = */ true, aCsp, aOriginAttributes);
 | 
						|
  if (!ipcResult) {
 | 
						|
    return ipcResult;
 | 
						|
  }
 | 
						|
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    NS_WARNING("Call to CommonCreateWindow failed.");
 | 
						|
  }
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvShutdownProfile(
 | 
						|
    const nsACString& aProfile) {
 | 
						|
  profiler_received_exit_profile(aProfile);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvShutdownPerfStats(
 | 
						|
    const nsACString& aPerfStats) {
 | 
						|
  PerfStats::StorePerfStats(this, aPerfStats);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvGetFontListShmBlock(
 | 
						|
    const uint32_t& aGeneration, const uint32_t& aIndex,
 | 
						|
    base::SharedMemoryHandle* aOut) {
 | 
						|
  auto* fontList = gfxPlatformFontList::PlatformFontList();
 | 
						|
  MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
 | 
						|
  fontList->ShareFontListShmBlockToProcess(aGeneration, aIndex, Pid(), aOut);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvInitializeFamily(
 | 
						|
    const uint32_t& aGeneration, const uint32_t& aFamilyIndex,
 | 
						|
    const bool& aLoadCmaps) {
 | 
						|
  auto* fontList = gfxPlatformFontList::PlatformFontList();
 | 
						|
  MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
 | 
						|
  fontList->InitializeFamily(aGeneration, aFamilyIndex, aLoadCmaps);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSetCharacterMap(
 | 
						|
    const uint32_t& aGeneration, const uint32_t& aFamilyIndex,
 | 
						|
    const bool& aAlias, const uint32_t& aFaceIndex,
 | 
						|
    const gfxSparseBitSet& aMap) {
 | 
						|
  auto* fontList = gfxPlatformFontList::PlatformFontList();
 | 
						|
  MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
 | 
						|
  fontList->SetCharacterMap(aGeneration, aFamilyIndex, aAlias, aFaceIndex,
 | 
						|
                            aMap);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvInitOtherFamilyNames(
 | 
						|
    const uint32_t& aGeneration, const bool& aDefer, bool* aLoaded) {
 | 
						|
  auto* fontList = gfxPlatformFontList::PlatformFontList();
 | 
						|
  MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
 | 
						|
  *aLoaded = fontList->InitOtherFamilyNames(aGeneration, aDefer);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSetupFamilyCharMap(
 | 
						|
    const uint32_t& aGeneration, const uint32_t& aIndex, const bool& aAlias) {
 | 
						|
  auto* fontList = gfxPlatformFontList::PlatformFontList();
 | 
						|
  MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
 | 
						|
  fontList->SetupFamilyCharMap(aGeneration, aIndex, aAlias);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvStartCmapLoading(
 | 
						|
    const uint32_t& aGeneration, const uint32_t& aStartIndex) {
 | 
						|
  auto* fontList = gfxPlatformFontList::PlatformFontList();
 | 
						|
  MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
 | 
						|
  fontList->StartCmapLoading(aGeneration, aStartIndex);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvGetHyphDict(
 | 
						|
    nsIURI* aURI, base::SharedMemoryHandle* aOutHandle, uint32_t* aOutSize) {
 | 
						|
  if (!aURI) {
 | 
						|
    return IPC_FAIL(this, "aURI must not be null.");
 | 
						|
  }
 | 
						|
  nsHyphenationManager::Instance()->ShareHyphDictToProcess(
 | 
						|
      aURI, Pid(), aOutHandle, aOutSize);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvGraphicsError(
 | 
						|
    const nsACString& aError) {
 | 
						|
  if (gfx::LogForwarder* lf = gfx::Factory::GetLogForwarder()) {
 | 
						|
    std::stringstream message;
 | 
						|
    message << "CP+" << aError;
 | 
						|
    lf->UpdateStringsVector(message.str());
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvBeginDriverCrashGuard(
 | 
						|
    const uint32_t& aGuardType, bool* aOutCrashed) {
 | 
						|
  // Only one driver crash guard should be active at a time, per-process.
 | 
						|
  MOZ_ASSERT(!mDriverCrashGuard);
 | 
						|
 | 
						|
  UniquePtr<gfx::DriverCrashGuard> guard;
 | 
						|
  switch (gfx::CrashGuardType(aGuardType)) {
 | 
						|
    case gfx::CrashGuardType::D3D11Layers:
 | 
						|
      guard = MakeUnique<gfx::D3D11LayersCrashGuard>(this);
 | 
						|
      break;
 | 
						|
    case gfx::CrashGuardType::GLContext:
 | 
						|
      guard = MakeUnique<gfx::GLContextCrashGuard>(this);
 | 
						|
      break;
 | 
						|
    case gfx::CrashGuardType::WMFVPXVideo:
 | 
						|
      guard = MakeUnique<gfx::WMFVPXVideoCrashGuard>(this);
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      return IPC_FAIL(this, "unknown crash guard type");
 | 
						|
  }
 | 
						|
 | 
						|
  if (guard->Crashed()) {
 | 
						|
    *aOutCrashed = true;
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  *aOutCrashed = false;
 | 
						|
  mDriverCrashGuard = std::move(guard);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvEndDriverCrashGuard(
 | 
						|
    const uint32_t& aGuardType) {
 | 
						|
  mDriverCrashGuard = nullptr;
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvNotifyBenchmarkResult(
 | 
						|
    const nsAString& aCodecName, const uint32_t& aDecodeFPS)
 | 
						|
 | 
						|
{
 | 
						|
  if (aCodecName.EqualsLiteral("VP9")) {
 | 
						|
    Preferences::SetUint(VP9Benchmark::sBenchmarkFpsPref, aDecodeFPS);
 | 
						|
    Preferences::SetUint(VP9Benchmark::sBenchmarkFpsVersionCheck,
 | 
						|
                         VP9Benchmark::sBenchmarkVersionID);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvNotifyPushObservers(
 | 
						|
    const nsACString& aScope, nsIPrincipal* aPrincipal,
 | 
						|
    const nsAString& aMessageId) {
 | 
						|
  if (!aPrincipal) {
 | 
						|
    return IPC_FAIL(this, "No principal");
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ValidatePrincipal(aPrincipal)) {
 | 
						|
    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
 | 
						|
  }
 | 
						|
  PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId, Nothing());
 | 
						|
  Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvNotifyPushObserversWithData(
 | 
						|
    const nsACString& aScope, nsIPrincipal* aPrincipal,
 | 
						|
    const nsAString& aMessageId, nsTArray<uint8_t>&& aData) {
 | 
						|
  if (!aPrincipal) {
 | 
						|
    return IPC_FAIL(this, "No principal");
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ValidatePrincipal(aPrincipal)) {
 | 
						|
    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
 | 
						|
  }
 | 
						|
  PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId,
 | 
						|
                                   Some(std::move(aData)));
 | 
						|
  Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult
 | 
						|
ContentParent::RecvNotifyPushSubscriptionChangeObservers(
 | 
						|
    const nsACString& aScope, nsIPrincipal* aPrincipal) {
 | 
						|
  if (!aPrincipal) {
 | 
						|
    return IPC_FAIL(this, "No principal");
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ValidatePrincipal(aPrincipal)) {
 | 
						|
    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
 | 
						|
  }
 | 
						|
  PushSubscriptionChangeDispatcher dispatcher(aScope, aPrincipal);
 | 
						|
  Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvPushError(const nsACString& aScope,
 | 
						|
                                                     nsIPrincipal* aPrincipal,
 | 
						|
                                                     const nsAString& aMessage,
 | 
						|
                                                     const uint32_t& aFlags) {
 | 
						|
  if (!aPrincipal) {
 | 
						|
    return IPC_FAIL(this, "No principal");
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ValidatePrincipal(aPrincipal)) {
 | 
						|
    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
 | 
						|
  }
 | 
						|
  PushErrorDispatcher dispatcher(aScope, aPrincipal, aMessage, aFlags);
 | 
						|
  Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult
 | 
						|
ContentParent::RecvNotifyPushSubscriptionModifiedObservers(
 | 
						|
    const nsACString& aScope, nsIPrincipal* aPrincipal) {
 | 
						|
  if (!aPrincipal) {
 | 
						|
    return IPC_FAIL(this, "No principal");
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ValidatePrincipal(aPrincipal)) {
 | 
						|
    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
 | 
						|
  }
 | 
						|
  PushSubscriptionModifiedDispatcher dispatcher(aScope, aPrincipal);
 | 
						|
  Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers()));
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ContentParent::BroadcastBlobURLRegistration(const nsACString& aURI,
 | 
						|
                                                 BlobImpl* aBlobImpl,
 | 
						|
                                                 nsIPrincipal* aPrincipal,
 | 
						|
                                                 const nsCString& aPartitionKey,
 | 
						|
                                                 ContentParent* aIgnoreThisCP) {
 | 
						|
  uint64_t originHash = ComputeLoadedOriginHash(aPrincipal);
 | 
						|
 | 
						|
  bool toBeSent =
 | 
						|
      BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal);
 | 
						|
 | 
						|
  nsCString uri(aURI);
 | 
						|
 | 
						|
  for (auto* cp : AllProcesses(eLive)) {
 | 
						|
    if (cp != aIgnoreThisCP) {
 | 
						|
      if (!toBeSent && !cp->mLoadedOriginHashes.Contains(originHash)) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      nsresult rv = cp->TransmitPermissionsForPrincipal(aPrincipal);
 | 
						|
      if (NS_WARN_IF(NS_FAILED(rv))) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      IPCBlob ipcBlob;
 | 
						|
      rv = IPCBlobUtils::Serialize(aBlobImpl, ipcBlob);
 | 
						|
      if (NS_WARN_IF(NS_FAILED(rv))) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      Unused << cp->SendBlobURLRegistration(uri, ipcBlob, aPrincipal,
 | 
						|
                                            aPartitionKey);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void ContentParent::BroadcastBlobURLUnregistration(
 | 
						|
    const nsACString& aURI, nsIPrincipal* aPrincipal,
 | 
						|
    ContentParent* aIgnoreThisCP) {
 | 
						|
  uint64_t originHash = ComputeLoadedOriginHash(aPrincipal);
 | 
						|
 | 
						|
  bool toBeSent =
 | 
						|
      BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal);
 | 
						|
 | 
						|
  nsCString uri(aURI);
 | 
						|
 | 
						|
  for (auto* cp : AllProcesses(eLive)) {
 | 
						|
    if (cp != aIgnoreThisCP &&
 | 
						|
        (toBeSent || cp->mLoadedOriginHashes.Contains(originHash))) {
 | 
						|
      Unused << cp->SendBlobURLUnregistration(uri);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvStoreAndBroadcastBlobURLRegistration(
 | 
						|
    const nsACString& aURI, const IPCBlob& aBlob, nsIPrincipal* aPrincipal,
 | 
						|
    const nsCString& aPartitionKey) {
 | 
						|
  if (!aPrincipal) {
 | 
						|
    return IPC_FAIL(this, "No principal");
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ValidatePrincipal(aPrincipal, {ValidatePrincipalOptions::AllowSystem})) {
 | 
						|
    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
 | 
						|
  }
 | 
						|
  RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(aBlob);
 | 
						|
  if (NS_WARN_IF(!blobImpl)) {
 | 
						|
    return IPC_FAIL(this, "Blob deserialization failed.");
 | 
						|
  }
 | 
						|
 | 
						|
  BlobURLProtocolHandler::AddDataEntry(aURI, aPrincipal, aPartitionKey,
 | 
						|
                                       blobImpl);
 | 
						|
  BroadcastBlobURLRegistration(aURI, blobImpl, aPrincipal, aPartitionKey, this);
 | 
						|
 | 
						|
  // We want to store this blobURL, so we can unregister it if the child
 | 
						|
  // crashes.
 | 
						|
  mBlobURLs.AppendElement(aURI);
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult
 | 
						|
ContentParent::RecvUnstoreAndBroadcastBlobURLUnregistration(
 | 
						|
    const nsACString& aURI, nsIPrincipal* aPrincipal) {
 | 
						|
  if (!aPrincipal) {
 | 
						|
    return IPC_FAIL(this, "No principal");
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ValidatePrincipal(aPrincipal, {ValidatePrincipalOptions::AllowSystem})) {
 | 
						|
    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
 | 
						|
  }
 | 
						|
  BlobURLProtocolHandler::RemoveDataEntry(aURI, false /* Don't broadcast */);
 | 
						|
  BroadcastBlobURLUnregistration(aURI, aPrincipal, this);
 | 
						|
  mBlobURLs.RemoveElement(aURI);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvGetFilesRequest(
 | 
						|
    const nsID& aID, const nsAString& aDirectoryPath,
 | 
						|
    const bool& aRecursiveFlag) {
 | 
						|
  MOZ_ASSERT(!mGetFilesPendingRequests.GetWeak(aID));
 | 
						|
 | 
						|
  if (!mozilla::Preferences::GetBool("dom.filesystem.pathcheck.disabled",
 | 
						|
                                     false)) {
 | 
						|
    RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get();
 | 
						|
    if (!fss) {
 | 
						|
      return IPC_FAIL(this, "Failed to get FileSystemSecurity.");
 | 
						|
    }
 | 
						|
 | 
						|
    if (!fss->ContentProcessHasAccessTo(ChildID(), aDirectoryPath)) {
 | 
						|
      return IPC_FAIL(this, "ContentProcessHasAccessTo failed.");
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  ErrorResult rv;
 | 
						|
  RefPtr<GetFilesHelper> helper = GetFilesHelperParent::Create(
 | 
						|
      aID, aDirectoryPath, aRecursiveFlag, this, rv);
 | 
						|
 | 
						|
  if (NS_WARN_IF(rv.Failed())) {
 | 
						|
    if (!SendGetFilesResponse(aID,
 | 
						|
                              GetFilesResponseFailure(rv.StealNSResult()))) {
 | 
						|
      return IPC_FAIL(this, "SendGetFilesResponse failed.");
 | 
						|
    }
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  mGetFilesPendingRequests.InsertOrUpdate(aID, std::move(helper));
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvDeleteGetFilesRequest(
 | 
						|
    const nsID& aID) {
 | 
						|
  mGetFilesPendingRequests.Remove(aID);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::SendGetFilesResponseAndForget(
 | 
						|
    const nsID& aID, const GetFilesResponseResult& aResult) {
 | 
						|
  if (mGetFilesPendingRequests.Remove(aID)) {
 | 
						|
    Unused << SendGetFilesResponse(aID, aResult);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::PaintTabWhileInterruptingJS(BrowserParent* aBrowserParent) {
 | 
						|
  if (!mHangMonitorActor) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  ProcessHangMonitor::PaintWhileInterruptingJS(mHangMonitorActor,
 | 
						|
                                               aBrowserParent);
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::UnloadLayersWhileInterruptingJS(
 | 
						|
    BrowserParent* aBrowserParent) {
 | 
						|
  if (!mHangMonitorActor) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  ProcessHangMonitor::UnloadLayersWhileInterruptingJS(mHangMonitorActor,
 | 
						|
                                                      aBrowserParent);
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::CancelContentJSExecutionIfRunning(
 | 
						|
    BrowserParent* aBrowserParent, nsIRemoteTab::NavigationType aNavigationType,
 | 
						|
    const CancelContentJSOptions& aCancelContentJSOptions) {
 | 
						|
  if (!mHangMonitorActor) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  ProcessHangMonitor::CancelContentJSExecutionIfRunning(
 | 
						|
      mHangMonitorActor, aBrowserParent, aNavigationType,
 | 
						|
      aCancelContentJSOptions);
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::SetMainThreadQoSPriority(
 | 
						|
    nsIThread::QoSPriority aQoSPriority) {
 | 
						|
  if (!mHangMonitorActor) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  ProcessHangMonitor::SetMainThreadQoSPriority(mHangMonitorActor, aQoSPriority);
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::UpdateCookieStatus(nsIChannel* aChannel) {
 | 
						|
  PNeckoParent* neckoParent = LoneManagedOrNullAsserts(ManagedPNeckoParent());
 | 
						|
  PCookieServiceParent* csParent =
 | 
						|
      LoneManagedOrNullAsserts(neckoParent->ManagedPCookieServiceParent());
 | 
						|
  if (csParent) {
 | 
						|
    auto* cs = static_cast<CookieServiceParent*>(csParent);
 | 
						|
    cs->TrackCookieLoad(aChannel);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
nsresult ContentParent::AboutToLoadHttpDocumentForChild(
 | 
						|
    nsIChannel* aChannel, bool* aShouldWaitForPermissionCookieUpdate) {
 | 
						|
  MOZ_ASSERT(aChannel);
 | 
						|
 | 
						|
  if (aShouldWaitForPermissionCookieUpdate) {
 | 
						|
    *aShouldWaitForPermissionCookieUpdate = false;
 | 
						|
  }
 | 
						|
 | 
						|
  nsresult rv;
 | 
						|
  bool isDocument = aChannel->IsDocument();
 | 
						|
  if (!isDocument) {
 | 
						|
    // We may be looking at a nsIHttpChannel which has isMainDocumentChannel set
 | 
						|
    // (e.g. the internal http channel for a view-source: load.).
 | 
						|
    nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
 | 
						|
    if (httpChannel) {
 | 
						|
      rv = httpChannel->GetIsMainDocumentChannel(&isDocument);
 | 
						|
      NS_ENSURE_SUCCESS(rv, rv);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (!isDocument) {
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
  // Get the principal for the channel result, so that we can get the permission
 | 
						|
  // key for the document which will be created from this response.
 | 
						|
  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
 | 
						|
  if (NS_WARN_IF(!ssm)) {
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsIPrincipal> principal;
 | 
						|
  nsCOMPtr<nsIPrincipal> partitionedPrincipal;
 | 
						|
  rv = ssm->GetChannelResultPrincipals(aChannel, getter_AddRefs(principal),
 | 
						|
                                       getter_AddRefs(partitionedPrincipal));
 | 
						|
  NS_ENSURE_SUCCESS(rv, rv);
 | 
						|
 | 
						|
  // Let the caller know we're going to send main thread IPC for updating
 | 
						|
  // permisssions/cookies.
 | 
						|
  if (aShouldWaitForPermissionCookieUpdate) {
 | 
						|
    *aShouldWaitForPermissionCookieUpdate = true;
 | 
						|
  }
 | 
						|
 | 
						|
  TransmitBlobURLsForPrincipal(principal);
 | 
						|
 | 
						|
  // Tranmit permissions for both regular and partitioned principal so that the
 | 
						|
  // content process can get permissions for the partitioned principal. For
 | 
						|
  // example, the desk-notification permission for a partitioned service worker.
 | 
						|
  rv = TransmitPermissionsForPrincipal(principal);
 | 
						|
  NS_ENSURE_SUCCESS(rv, rv);
 | 
						|
 | 
						|
  rv = TransmitPermissionsForPrincipal(partitionedPrincipal);
 | 
						|
  NS_ENSURE_SUCCESS(rv, rv);
 | 
						|
 | 
						|
  nsLoadFlags newLoadFlags;
 | 
						|
  aChannel->GetLoadFlags(&newLoadFlags);
 | 
						|
  if (newLoadFlags & nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE) {
 | 
						|
    UpdateCookieStatus(aChannel);
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
 | 
						|
  RefPtr<BrowsingContext> browsingContext;
 | 
						|
  rv = loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext));
 | 
						|
  NS_ENSURE_SUCCESS(rv, rv);
 | 
						|
 | 
						|
  if (!NextGenLocalStorageEnabled()) {
 | 
						|
    return NS_OK;
 | 
						|
  }
 | 
						|
 | 
						|
  if (principal->GetIsContentPrincipal()) {
 | 
						|
    nsCOMPtr<nsILocalStorageManager> lsm =
 | 
						|
        do_GetService("@mozilla.org/dom/localStorage-manager;1");
 | 
						|
    if (NS_WARN_IF(!lsm)) {
 | 
						|
      return NS_ERROR_FAILURE;
 | 
						|
    }
 | 
						|
 | 
						|
    nsCOMPtr<nsIPrincipal> storagePrincipal;
 | 
						|
    rv = ssm->GetChannelResultStoragePrincipal(
 | 
						|
        aChannel, getter_AddRefs(storagePrincipal));
 | 
						|
    NS_ENSURE_SUCCESS(rv, rv);
 | 
						|
 | 
						|
    RefPtr<Promise> dummy;
 | 
						|
    rv = lsm->Preload(storagePrincipal, nullptr, getter_AddRefs(dummy));
 | 
						|
    if (NS_FAILED(rv)) {
 | 
						|
      NS_WARNING("Failed to preload local storage!");
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
nsresult ContentParent::TransmitPermissionsForPrincipal(
 | 
						|
    nsIPrincipal* aPrincipal) {
 | 
						|
  // Create the key, and send it down to the content process.
 | 
						|
  nsTArray<std::pair<nsCString, nsCString>> pairs =
 | 
						|
      PermissionManager::GetAllKeysForPrincipal(aPrincipal);
 | 
						|
  MOZ_ASSERT(pairs.Length() >= 1);
 | 
						|
  for (auto& pair : pairs) {
 | 
						|
    EnsurePermissionsByKey(pair.first, pair.second);
 | 
						|
  }
 | 
						|
 | 
						|
  // We need to add the Site to the secondary keys of interest here.
 | 
						|
  // This allows site-scoped permission updates to propogate when the
 | 
						|
  // port is non-standard.
 | 
						|
  nsAutoCString siteKey;
 | 
						|
  nsresult rv =
 | 
						|
      PermissionManager::GetKeyForPrincipal(aPrincipal, false, true, siteKey);
 | 
						|
  if (NS_SUCCEEDED(rv) && !siteKey.IsEmpty()) {
 | 
						|
    mActiveSecondaryPermissionKeys.EnsureInserted(siteKey);
 | 
						|
  }
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::TransmitBlobURLsForPrincipal(nsIPrincipal* aPrincipal) {
 | 
						|
  // If we're already broadcasting BlobURLs with this principal, we don't need
 | 
						|
  // to send them here.
 | 
						|
  if (BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // We shouldn't have any Blob URLs with expanded principals, so transmit URLs
 | 
						|
  // for each principal in the AllowList instead.
 | 
						|
  if (nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(aPrincipal)) {
 | 
						|
    for (const auto& prin : ep->AllowList()) {
 | 
						|
      TransmitBlobURLsForPrincipal(prin);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  uint64_t originHash = ComputeLoadedOriginHash(aPrincipal);
 | 
						|
 | 
						|
  if (!mLoadedOriginHashes.Contains(originHash)) {
 | 
						|
    mLoadedOriginHashes.AppendElement(originHash);
 | 
						|
 | 
						|
    nsTArray<BlobURLRegistrationData> registrations;
 | 
						|
    BlobURLProtocolHandler::ForEachBlobURL(
 | 
						|
        [&](BlobImpl* aBlobImpl, nsIPrincipal* aBlobPrincipal,
 | 
						|
            const nsCString& aPartitionKey, const nsACString& aURI,
 | 
						|
            bool aRevoked) {
 | 
						|
          // This check uses `ComputeLoadedOriginHash` to compare, rather than
 | 
						|
          // doing the more accurate `Equals` check, as it needs to match the
 | 
						|
          // behaviour of the logic to broadcast new registrations.
 | 
						|
          if (originHash != ComputeLoadedOriginHash(aBlobPrincipal)) {
 | 
						|
            return true;
 | 
						|
          }
 | 
						|
 | 
						|
          IPCBlob ipcBlob;
 | 
						|
          nsresult rv = IPCBlobUtils::Serialize(aBlobImpl, ipcBlob);
 | 
						|
          if (NS_WARN_IF(NS_FAILED(rv))) {
 | 
						|
            return false;
 | 
						|
          }
 | 
						|
 | 
						|
          registrations.AppendElement(
 | 
						|
              BlobURLRegistrationData(nsCString(aURI), ipcBlob, aPrincipal,
 | 
						|
                                      nsCString(aPartitionKey), aRevoked));
 | 
						|
 | 
						|
          rv = TransmitPermissionsForPrincipal(aBlobPrincipal);
 | 
						|
          Unused << NS_WARN_IF(NS_FAILED(rv));
 | 
						|
          return true;
 | 
						|
        });
 | 
						|
 | 
						|
    if (!registrations.IsEmpty()) {
 | 
						|
      Unused << SendInitBlobURLs(registrations);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::TransmitBlobDataIfBlobURL(nsIURI* aURI) {
 | 
						|
  MOZ_ASSERT(aURI);
 | 
						|
 | 
						|
  nsCOMPtr<nsIPrincipal> principal;
 | 
						|
  if (BlobURLProtocolHandler::GetBlobURLPrincipal(aURI,
 | 
						|
                                                  getter_AddRefs(principal))) {
 | 
						|
    TransmitBlobURLsForPrincipal(principal);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::EnsurePermissionsByKey(const nsACString& aKey,
 | 
						|
                                           const nsACString& aOrigin) {
 | 
						|
  // NOTE: Make sure to initialize the permission manager before updating the
 | 
						|
  // mActivePermissionKeys list. If the permission manager is being initialized
 | 
						|
  // by this call to GetPermissionManager, and we've added the key to
 | 
						|
  // mActivePermissionKeys, then the permission manager will send down a
 | 
						|
  // SendAddPermission before receiving the SendSetPermissionsWithKey message.
 | 
						|
  RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
 | 
						|
  if (!permManager) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!mActivePermissionKeys.EnsureInserted(aKey)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  nsTArray<IPC::Permission> perms;
 | 
						|
  if (permManager->GetPermissionsFromOriginOrKey(aOrigin, aKey, perms)) {
 | 
						|
    Unused << SendSetPermissionsWithKey(aKey, perms);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::NeedsPermissionsUpdate(
 | 
						|
    const nsACString& aPermissionKey) const {
 | 
						|
  return mActivePermissionKeys.Contains(aPermissionKey);
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::NeedsSecondaryKeyPermissionsUpdate(
 | 
						|
    const nsACString& aPermissionKey) const {
 | 
						|
  return mActiveSecondaryPermissionKeys.Contains(aPermissionKey);
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvAccumulateChildHistograms(
 | 
						|
    nsTArray<HistogramAccumulation>&& aAccumulations) {
 | 
						|
  TelemetryIPC::AccumulateChildHistograms(GetTelemetryProcessID(mRemoteType),
 | 
						|
                                          aAccumulations);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvAccumulateChildKeyedHistograms(
 | 
						|
    nsTArray<KeyedHistogramAccumulation>&& aAccumulations) {
 | 
						|
  TelemetryIPC::AccumulateChildKeyedHistograms(
 | 
						|
      GetTelemetryProcessID(mRemoteType), aAccumulations);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvUpdateChildScalars(
 | 
						|
    nsTArray<ScalarAction>&& aScalarActions) {
 | 
						|
  TelemetryIPC::UpdateChildScalars(GetTelemetryProcessID(mRemoteType),
 | 
						|
                                   aScalarActions);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvUpdateChildKeyedScalars(
 | 
						|
    nsTArray<KeyedScalarAction>&& aScalarActions) {
 | 
						|
  TelemetryIPC::UpdateChildKeyedScalars(GetTelemetryProcessID(mRemoteType),
 | 
						|
                                        aScalarActions);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvRecordChildEvents(
 | 
						|
    nsTArray<mozilla::Telemetry::ChildEventData>&& aEvents) {
 | 
						|
  TelemetryIPC::RecordChildEvents(GetTelemetryProcessID(mRemoteType), aEvents);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvRecordDiscardedData(
 | 
						|
    const mozilla::Telemetry::DiscardedData& aDiscardedData) {
 | 
						|
  TelemetryIPC::RecordDiscardedData(GetTelemetryProcessID(mRemoteType),
 | 
						|
                                    aDiscardedData);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
static bool WebdriverRunning() {
 | 
						|
#ifdef ENABLE_WEBDRIVER
 | 
						|
  nsCOMPtr<nsIMarionette> marionette = do_GetService(NS_MARIONETTE_CONTRACTID);
 | 
						|
  if (marionette) {
 | 
						|
    bool marionetteRunning = false;
 | 
						|
    marionette->GetRunning(&marionetteRunning);
 | 
						|
    if (marionetteRunning) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsIRemoteAgent> agent = do_GetService(NS_REMOTEAGENT_CONTRACTID);
 | 
						|
  if (agent) {
 | 
						|
    bool remoteAgentRunning = false;
 | 
						|
    agent->GetRunning(&remoteAgentRunning);
 | 
						|
    if (remoteAgentRunning) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvRecordPageLoadEvent(
 | 
						|
    mozilla::glean::perf::PageLoadExtra&& aPageLoadEventExtra) {
 | 
						|
  // Check whether a webdriver is running.
 | 
						|
  aPageLoadEventExtra.usingWebdriver = mozilla::Some(WebdriverRunning());
 | 
						|
  mozilla::glean::perf::page_load.Record(mozilla::Some(aPageLoadEventExtra));
 | 
						|
 | 
						|
  // Send the PageLoadPing after every 30 page loads, or on startup.
 | 
						|
  if (++sPageLoadEventCounter >= 30) {
 | 
						|
    NS_SUCCEEDED(NS_DispatchToMainThreadQueue(
 | 
						|
        NS_NewRunnableFunction(
 | 
						|
            "PageLoadPingIdleTask",
 | 
						|
            [] { mozilla::glean_pings::Pageload.Submit("threshold"_ns); }),
 | 
						|
        EventQueuePriority::Idle));
 | 
						|
    sPageLoadEventCounter = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
//////////////////////////////////////////////////////////////////
 | 
						|
// PURLClassifierParent
 | 
						|
 | 
						|
PURLClassifierParent* ContentParent::AllocPURLClassifierParent(
 | 
						|
    nsIPrincipal* aPrincipal, bool* aSuccess) {
 | 
						|
  MOZ_ASSERT(NS_IsMainThread());
 | 
						|
 | 
						|
  *aSuccess = true;
 | 
						|
  RefPtr<URLClassifierParent> actor = new URLClassifierParent();
 | 
						|
  return actor.forget().take();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvPURLClassifierConstructor(
 | 
						|
    PURLClassifierParent* aActor, nsIPrincipal* aPrincipal, bool* aSuccess) {
 | 
						|
  MOZ_ASSERT(NS_IsMainThread());
 | 
						|
  MOZ_ASSERT(aActor);
 | 
						|
  *aSuccess = false;
 | 
						|
 | 
						|
  auto* actor = static_cast<URLClassifierParent*>(aActor);
 | 
						|
  nsCOMPtr<nsIPrincipal> principal(aPrincipal);
 | 
						|
  if (!principal) {
 | 
						|
    actor->ClassificationFailed();
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  if (!ValidatePrincipal(aPrincipal)) {
 | 
						|
    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
 | 
						|
  }
 | 
						|
  return actor->StartClassify(principal, aSuccess);
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::DeallocPURLClassifierParent(PURLClassifierParent* aActor) {
 | 
						|
  MOZ_ASSERT(NS_IsMainThread());
 | 
						|
  MOZ_ASSERT(aActor);
 | 
						|
 | 
						|
  RefPtr<URLClassifierParent> actor =
 | 
						|
      dont_AddRef(static_cast<URLClassifierParent*>(aActor));
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
//////////////////////////////////////////////////////////////////
 | 
						|
// PURLClassifierLocalParent
 | 
						|
 | 
						|
PURLClassifierLocalParent* ContentParent::AllocPURLClassifierLocalParent(
 | 
						|
    nsIURI* aURI, const nsTArray<IPCURLClassifierFeature>& aFeatures) {
 | 
						|
  MOZ_ASSERT(NS_IsMainThread());
 | 
						|
 | 
						|
  RefPtr<URLClassifierLocalParent> actor = new URLClassifierLocalParent();
 | 
						|
  return actor.forget().take();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvPURLClassifierLocalConstructor(
 | 
						|
    PURLClassifierLocalParent* aActor, nsIURI* aURI,
 | 
						|
    nsTArray<IPCURLClassifierFeature>&& aFeatures) {
 | 
						|
  MOZ_ASSERT(NS_IsMainThread());
 | 
						|
  MOZ_ASSERT(aActor);
 | 
						|
 | 
						|
  nsTArray<IPCURLClassifierFeature> features = std::move(aFeatures);
 | 
						|
 | 
						|
  if (!aURI) {
 | 
						|
    return IPC_FAIL(this, "aURI should not be null");
 | 
						|
  }
 | 
						|
 | 
						|
  auto* actor = static_cast<URLClassifierLocalParent*>(aActor);
 | 
						|
  return actor->StartClassify(aURI, features);
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::DeallocPURLClassifierLocalParent(
 | 
						|
    PURLClassifierLocalParent* aActor) {
 | 
						|
  MOZ_ASSERT(NS_IsMainThread());
 | 
						|
  MOZ_ASSERT(aActor);
 | 
						|
 | 
						|
  RefPtr<URLClassifierLocalParent> actor =
 | 
						|
      dont_AddRef(static_cast<URLClassifierLocalParent*>(aActor));
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
PSessionStorageObserverParent*
 | 
						|
ContentParent::AllocPSessionStorageObserverParent() {
 | 
						|
  MOZ_ASSERT(NS_IsMainThread());
 | 
						|
 | 
						|
  return mozilla::dom::AllocPSessionStorageObserverParent();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvPSessionStorageObserverConstructor(
 | 
						|
    PSessionStorageObserverParent* aActor) {
 | 
						|
  MOZ_ASSERT(NS_IsMainThread());
 | 
						|
  MOZ_ASSERT(aActor);
 | 
						|
 | 
						|
  if (!mozilla::dom::RecvPSessionStorageObserverConstructor(aActor)) {
 | 
						|
    return IPC_FAIL(this, "RecvPSessionStorageObserverConstructor failed.");
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::DeallocPSessionStorageObserverParent(
 | 
						|
    PSessionStorageObserverParent* aActor) {
 | 
						|
  MOZ_ASSERT(NS_IsMainThread());
 | 
						|
  MOZ_ASSERT(aActor);
 | 
						|
 | 
						|
  return mozilla::dom::DeallocPSessionStorageObserverParent(aActor);
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvBHRThreadHang(
 | 
						|
    const HangDetails& aHangDetails) {
 | 
						|
  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
 | 
						|
  if (obs) {
 | 
						|
    // Copy the HangDetails recieved over the network into a nsIHangDetails, and
 | 
						|
    // then fire our own observer notification.
 | 
						|
    // XXX: We should be able to avoid this potentially expensive copy here by
 | 
						|
    // moving our deserialized argument.
 | 
						|
    nsCOMPtr<nsIHangDetails> hangDetails =
 | 
						|
        new nsHangDetails(HangDetails(aHangDetails), PersistedToDisk::No);
 | 
						|
    obs->NotifyObservers(hangDetails, "bhr-thread-hang", nullptr);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvAddCertException(
 | 
						|
    nsIX509Cert* aCert, const nsACString& aHostName, int32_t aPort,
 | 
						|
    const OriginAttributes& aOriginAttributes, bool aIsTemporary,
 | 
						|
    AddCertExceptionResolver&& aResolver) {
 | 
						|
  nsCOMPtr<nsICertOverrideService> overrideService =
 | 
						|
      do_GetService(NS_CERTOVERRIDE_CONTRACTID);
 | 
						|
  if (!overrideService) {
 | 
						|
    aResolver(NS_ERROR_FAILURE);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  nsresult rv = overrideService->RememberValidityOverride(
 | 
						|
      aHostName, aPort, aOriginAttributes, aCert, aIsTemporary);
 | 
						|
  aResolver(rv);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult
 | 
						|
ContentParent::RecvAutomaticStorageAccessPermissionCanBeGranted(
 | 
						|
    nsIPrincipal* aPrincipal,
 | 
						|
    AutomaticStorageAccessPermissionCanBeGrantedResolver&& aResolver) {
 | 
						|
  if (!aPrincipal) {
 | 
						|
    return IPC_FAIL(this, "No principal");
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ValidatePrincipal(aPrincipal)) {
 | 
						|
    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
 | 
						|
  }
 | 
						|
  aResolver(Document::AutomaticStorageAccessPermissionCanBeGranted(aPrincipal));
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult
 | 
						|
ContentParent::RecvStorageAccessPermissionGrantedForOrigin(
 | 
						|
    uint64_t aTopLevelWindowId,
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aParentContext,
 | 
						|
    nsIPrincipal* aTrackingPrincipal, const nsACString& aTrackingOrigin,
 | 
						|
    const int& aAllowMode,
 | 
						|
    const Maybe<ContentBlockingNotifier::StorageAccessPermissionGrantedReason>&
 | 
						|
        aReason,
 | 
						|
    const bool& aFrameOnly,
 | 
						|
    StorageAccessPermissionGrantedForOriginResolver&& aResolver) {
 | 
						|
  if (aParentContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!aTrackingPrincipal) {
 | 
						|
    return IPC_FAIL(this, "No principal");
 | 
						|
  }
 | 
						|
 | 
						|
  // We only report here if we cannot report the console directly in the content
 | 
						|
  // process. In that case, the `aReason` would be given a value. Otherwise, it
 | 
						|
  // will be nothing.
 | 
						|
  if (aReason) {
 | 
						|
    ContentBlockingNotifier::ReportUnblockingToConsole(
 | 
						|
        aParentContext.get_canonical(), NS_ConvertUTF8toUTF16(aTrackingOrigin),
 | 
						|
        aReason.value());
 | 
						|
  }
 | 
						|
 | 
						|
  StorageAccessAPIHelper::SaveAccessForOriginOnParentProcess(
 | 
						|
      aTopLevelWindowId, aParentContext.get_canonical(), aTrackingPrincipal,
 | 
						|
      aAllowMode, aFrameOnly)
 | 
						|
      ->Then(GetCurrentSerialEventTarget(), __func__,
 | 
						|
             [aResolver = std::move(aResolver)](
 | 
						|
                 StorageAccessAPIHelper::ParentAccessGrantPromise::
 | 
						|
                     ResolveOrRejectValue&& aValue) {
 | 
						|
               bool success =
 | 
						|
                   aValue.IsResolve() && NS_SUCCEEDED(aValue.ResolveValue());
 | 
						|
               aResolver(success);
 | 
						|
             });
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvCompleteAllowAccessFor(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aParentContext,
 | 
						|
    uint64_t aTopLevelWindowId, nsIPrincipal* aTrackingPrincipal,
 | 
						|
    const nsACString& aTrackingOrigin, uint32_t aCookieBehavior,
 | 
						|
    const ContentBlockingNotifier::StorageAccessPermissionGrantedReason&
 | 
						|
        aReason,
 | 
						|
    CompleteAllowAccessForResolver&& aResolver) {
 | 
						|
  if (aParentContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  StorageAccessAPIHelper::CompleteAllowAccessForOnParentProcess(
 | 
						|
      aParentContext.get_canonical(), aTopLevelWindowId, aTrackingPrincipal,
 | 
						|
      aTrackingOrigin, aCookieBehavior, aReason, nullptr)
 | 
						|
      ->Then(GetCurrentSerialEventTarget(), __func__,
 | 
						|
             [aResolver = std::move(aResolver)](
 | 
						|
                 StorageAccessAPIHelper::StorageAccessPermissionGrantPromise::
 | 
						|
                     ResolveOrRejectValue&& aValue) {
 | 
						|
               Maybe<StorageAccessPromptChoices> choice;
 | 
						|
               if (aValue.IsResolve()) {
 | 
						|
                 choice.emplace(static_cast<StorageAccessPromptChoices>(
 | 
						|
                     aValue.ResolveValue()));
 | 
						|
               }
 | 
						|
               aResolver(choice);
 | 
						|
             });
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSetAllowStorageAccessRequestFlag(
 | 
						|
    nsIPrincipal* aEmbeddedPrincipal, nsIURI* aEmbeddingOrigin,
 | 
						|
    SetAllowStorageAccessRequestFlagResolver&& aResolver) {
 | 
						|
  MOZ_ASSERT(aEmbeddedPrincipal);
 | 
						|
  MOZ_ASSERT(aEmbeddingOrigin);
 | 
						|
 | 
						|
  if (!aEmbeddedPrincipal || !aEmbeddingOrigin) {
 | 
						|
    aResolver(false);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  // Get the permission manager and build the key.
 | 
						|
  RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
 | 
						|
  if (!permManager) {
 | 
						|
    aResolver(false);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  nsCOMPtr<nsIURI> embeddedURI = aEmbeddedPrincipal->GetURI();
 | 
						|
  nsCString permissionKey;
 | 
						|
  bool success = AntiTrackingUtils::CreateStorageRequestPermissionKey(
 | 
						|
      embeddedURI, permissionKey);
 | 
						|
  if (!success) {
 | 
						|
    aResolver(false);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  // Set the permission to ALLOW for a prefence specified amount of seconds.
 | 
						|
  // Time units are inconsistent, be careful
 | 
						|
  int64_t when = (PR_Now() / PR_USEC_PER_MSEC) +
 | 
						|
                 StaticPrefs::dom_storage_access_forward_declared_lifetime() *
 | 
						|
                     PR_MSEC_PER_SEC;
 | 
						|
  nsCOMPtr<nsIPrincipal> principal = BasePrincipal::CreateContentPrincipal(
 | 
						|
      aEmbeddingOrigin, aEmbeddedPrincipal->OriginAttributesRef());
 | 
						|
  nsresult rv = permManager->AddFromPrincipal(
 | 
						|
      principal, permissionKey, nsIPermissionManager::ALLOW_ACTION,
 | 
						|
      nsIPermissionManager::EXPIRE_TIME, when);
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    aResolver(false);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  // Resolve with success if we set the permission.
 | 
						|
  aResolver(true);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvTestAllowStorageAccessRequestFlag(
 | 
						|
    nsIPrincipal* aEmbeddingPrincipal, nsIURI* aEmbeddedOrigin,
 | 
						|
    TestAllowStorageAccessRequestFlagResolver&& aResolver) {
 | 
						|
  MOZ_ASSERT(aEmbeddingPrincipal);
 | 
						|
  MOZ_ASSERT(aEmbeddedOrigin);
 | 
						|
 | 
						|
  // Get the permission manager and build the key.
 | 
						|
  RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
 | 
						|
  if (!permManager) {
 | 
						|
    aResolver(false);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  nsCString requestPermissionKey;
 | 
						|
  bool success = AntiTrackingUtils::CreateStorageRequestPermissionKey(
 | 
						|
      aEmbeddedOrigin, requestPermissionKey);
 | 
						|
  if (!success) {
 | 
						|
    aResolver(false);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  // Get the permission and resolve false if it is not set to ALLOW.
 | 
						|
  uint32_t access = nsIPermissionManager::UNKNOWN_ACTION;
 | 
						|
  nsresult rv = permManager->TestPermissionFromPrincipal(
 | 
						|
      aEmbeddingPrincipal, requestPermissionKey, &access);
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    aResolver(false);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  if (access != nsIPermissionManager::ALLOW_ACTION) {
 | 
						|
    aResolver(false);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  // Remove the permission, failing if the permission manager fails
 | 
						|
  rv = permManager->RemoveFromPrincipal(aEmbeddingPrincipal,
 | 
						|
                                        requestPermissionKey);
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    aResolver(false);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  // At this point, signal to our caller that the permission was set
 | 
						|
  aResolver(true);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvStoreUserInteractionAsPermission(
 | 
						|
    nsIPrincipal* aPrincipal) {
 | 
						|
  if (!aPrincipal) {
 | 
						|
    return IPC_FAIL(this, "No principal");
 | 
						|
  }
 | 
						|
 | 
						|
  if (!ValidatePrincipal(aPrincipal)) {
 | 
						|
    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
 | 
						|
  }
 | 
						|
  ContentBlockingUserInteraction::Observe(aPrincipal);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvTestCookiePermissionDecided(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, nsIPrincipal* aPrincipal,
 | 
						|
    const TestCookiePermissionDecidedResolver&& aResolver) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!aPrincipal) {
 | 
						|
    return IPC_FAIL(this, "No principal");
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<WindowGlobalParent> wgp =
 | 
						|
      aContext.get_canonical()->GetCurrentWindowGlobal();
 | 
						|
  nsCOMPtr<nsICookieJarSettings> cjs = wgp->CookieJarSettings();
 | 
						|
 | 
						|
  Maybe<bool> result =
 | 
						|
      StorageAccessAPIHelper::CheckCookiesPermittedDecidesStorageAccessAPI(
 | 
						|
          cjs, aPrincipal);
 | 
						|
  aResolver(result);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvTestStorageAccessPermission(
 | 
						|
    nsIPrincipal* aEmbeddingPrincipal, const nsCString& aEmbeddedOrigin,
 | 
						|
    const TestStorageAccessPermissionResolver&& aResolver) {
 | 
						|
  // Get the permission manager and build the key.
 | 
						|
  RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
 | 
						|
  if (!permManager) {
 | 
						|
    aResolver(Nothing());
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  nsCString requestPermissionKey;
 | 
						|
  AntiTrackingUtils::CreateStoragePermissionKey(aEmbeddedOrigin,
 | 
						|
                                                requestPermissionKey);
 | 
						|
 | 
						|
  // Test the permission
 | 
						|
  uint32_t access = nsIPermissionManager::UNKNOWN_ACTION;
 | 
						|
  nsresult rv = permManager->TestPermissionFromPrincipal(
 | 
						|
      aEmbeddingPrincipal, requestPermissionKey, &access);
 | 
						|
  if (NS_FAILED(rv)) {
 | 
						|
    aResolver(Nothing());
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  if (access == nsIPermissionManager::ALLOW_ACTION) {
 | 
						|
    aResolver(Some(true));
 | 
						|
  } else if (access == nsIPermissionManager::DENY_ACTION) {
 | 
						|
    aResolver(Some(false));
 | 
						|
  } else {
 | 
						|
    aResolver(Nothing());
 | 
						|
  }
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaPlaybackChanged(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext,
 | 
						|
    MediaPlaybackState aState) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  if (RefPtr<IMediaInfoUpdater> updater =
 | 
						|
          aContext.get_canonical()->GetMediaController()) {
 | 
						|
    updater->NotifyMediaPlaybackChanged(aContext.ContextId(), aState);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaAudibleChanged(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, MediaAudibleState aState) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  if (RefPtr<IMediaInfoUpdater> updater =
 | 
						|
          aContext.get_canonical()->GetMediaController()) {
 | 
						|
    updater->NotifyMediaAudibleChanged(aContext.ContextId(), aState);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvNotifyPictureInPictureModeChanged(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, bool aEnabled) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  if (RefPtr<MediaController> controller =
 | 
						|
          aContext.get_canonical()->GetMediaController()) {
 | 
						|
    controller->SetIsInPictureInPictureMode(aContext.ContextId(), aEnabled);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvAbortOtherOrientationPendingPromises(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  CanonicalBrowsingContext* context = aContext.get_canonical();
 | 
						|
 | 
						|
  context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
 | 
						|
    Unused << aParent->SendAbortOrientationPendingPromises(context);
 | 
						|
  });
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaSessionUpdated(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, bool aIsCreated) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<IMediaInfoUpdater> updater =
 | 
						|
      aContext.get_canonical()->GetMediaController();
 | 
						|
  if (!updater) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  if (aIsCreated) {
 | 
						|
    updater->NotifySessionCreated(aContext->Id());
 | 
						|
  } else {
 | 
						|
    updater->NotifySessionDestroyed(aContext->Id());
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvNotifyUpdateMediaMetadata(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext,
 | 
						|
    const Maybe<MediaMetadataBase>& aMetadata) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  if (RefPtr<IMediaInfoUpdater> updater =
 | 
						|
          aContext.get_canonical()->GetMediaController()) {
 | 
						|
    updater->UpdateMetadata(aContext.ContextId(), aMetadata);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult
 | 
						|
ContentParent::RecvNotifyMediaSessionPlaybackStateChanged(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext,
 | 
						|
    MediaSessionPlaybackState aPlaybackState) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  if (RefPtr<IMediaInfoUpdater> updater =
 | 
						|
          aContext.get_canonical()->GetMediaController()) {
 | 
						|
    updater->SetDeclaredPlaybackState(aContext.ContextId(), aPlaybackState);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult
 | 
						|
ContentParent::RecvNotifyMediaSessionSupportedActionChanged(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, MediaSessionAction aAction,
 | 
						|
    bool aEnabled) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  RefPtr<IMediaInfoUpdater> updater =
 | 
						|
      aContext.get_canonical()->GetMediaController();
 | 
						|
  if (!updater) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  if (aEnabled) {
 | 
						|
    updater->EnableAction(aContext.ContextId(), aAction);
 | 
						|
  } else {
 | 
						|
    updater->DisableAction(aContext.ContextId(), aAction);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaFullScreenState(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, bool aIsInFullScreen) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  if (RefPtr<IMediaInfoUpdater> updater =
 | 
						|
          aContext.get_canonical()->GetMediaController()) {
 | 
						|
    updater->NotifyMediaFullScreenState(aContext.ContextId(), aIsInFullScreen);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvNotifyPositionStateChanged(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext,
 | 
						|
    const Maybe<PositionState>& aState) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  if (RefPtr<IMediaInfoUpdater> updater =
 | 
						|
          aContext.get_canonical()->GetMediaController()) {
 | 
						|
    updater->UpdatePositionState(aContext.ContextId(), aState);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvNotifyGuessedPositionStateChanged(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, const nsID& aMediaId,
 | 
						|
    const Maybe<PositionState>& aState) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  if (RefPtr<IMediaInfoUpdater> updater =
 | 
						|
          aContext.get_canonical()->GetMediaController()) {
 | 
						|
    updater->UpdateGuessedPositionState(aContext.ContextId(), aMediaId, aState);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvAddOrRemovePageAwakeRequest(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext,
 | 
						|
    const bool& aShouldAddCount) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  if (aShouldAddCount) {
 | 
						|
    aContext.get_canonical()->AddPageAwakeRequest();
 | 
						|
  } else {
 | 
						|
    aContext.get_canonical()->RemovePageAwakeRequest();
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
#if defined(XP_WIN)
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvGetModulesTrust(
 | 
						|
    ModulePaths&& aModPaths, bool aRunAtNormalPriority,
 | 
						|
    GetModulesTrustResolver&& aResolver) {
 | 
						|
  RefPtr<DllServices> dllSvc(DllServices::Get());
 | 
						|
  dllSvc->GetModulesTrust(std::move(aModPaths), aRunAtNormalPriority)
 | 
						|
      ->Then(
 | 
						|
          GetMainThreadSerialEventTarget(), __func__,
 | 
						|
          [aResolver](ModulesMapResult&& aResult) {
 | 
						|
            aResolver(Some(ModulesMapResult(std::move(aResult))));
 | 
						|
          },
 | 
						|
          [aResolver](nsresult aRv) { aResolver(Nothing()); });
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
#endif  // defined(XP_WIN)
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvCreateBrowsingContext(
 | 
						|
    uint64_t aGroupId, BrowsingContext::IPCInitializer&& aInit) {
 | 
						|
  RefPtr<WindowGlobalParent> parent;
 | 
						|
  if (aInit.mParentId != 0) {
 | 
						|
    parent = WindowGlobalParent::GetByInnerWindowId(aInit.mParentId);
 | 
						|
    if (!parent) {
 | 
						|
      return IPC_FAIL(this, "Parent doesn't exist in parent process");
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (parent && parent->GetContentParent() != this) {
 | 
						|
    // We're trying attach a child BrowsingContext to a parent
 | 
						|
    // WindowContext in another process. This is illegal since the
 | 
						|
    // only thing that could create that child BrowsingContext is the parent
 | 
						|
    // window's process.
 | 
						|
    return IPC_FAIL(this,
 | 
						|
                    "Must create BrowsingContext from the parent's process");
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<BrowsingContext> opener;
 | 
						|
  if (aInit.GetOpenerId() != 0) {
 | 
						|
    opener = BrowsingContext::Get(aInit.GetOpenerId());
 | 
						|
    if (!opener) {
 | 
						|
      return IPC_FAIL(this, "Opener doesn't exist in parent process");
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<BrowsingContext> child = BrowsingContext::Get(aInit.mId);
 | 
						|
  if (child) {
 | 
						|
    // This is highly suspicious. BrowsingContexts should only be created once,
 | 
						|
    // so finding one indicates that someone is doing something they shouldn't.
 | 
						|
    return IPC_FAIL(this, "A BrowsingContext with this ID already exists");
 | 
						|
  }
 | 
						|
 | 
						|
  // Ensure that the passed-in BrowsingContextGroup is valid.
 | 
						|
  RefPtr<BrowsingContextGroup> group =
 | 
						|
      BrowsingContextGroup::GetOrCreate(aGroupId);
 | 
						|
  if (parent) {
 | 
						|
    if (parent->Group()->Id() != aGroupId) {
 | 
						|
      return IPC_FAIL(this, "Parent has different group ID");
 | 
						|
    }
 | 
						|
    if (parent->IsDiscarded()) {
 | 
						|
      return IPC_FAIL(this, "Parent is discarded");
 | 
						|
    }
 | 
						|
    if (parent->Group() != group) {
 | 
						|
      return IPC_FAIL(this, "Parent has different group object");
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (opener && opener->Group() != group) {
 | 
						|
    if (opener->Group()->Id() != aGroupId) {
 | 
						|
      return IPC_FAIL(this, "Opener has different group ID");
 | 
						|
    }
 | 
						|
    return IPC_FAIL(this, "Opener has different group object");
 | 
						|
  }
 | 
						|
  if (!parent && !opener && !group->Toplevels().IsEmpty()) {
 | 
						|
    return IPC_FAIL(this, "Unrelated context from child in stale group");
 | 
						|
  }
 | 
						|
 | 
						|
  return BrowsingContext::CreateFromIPC(std::move(aInit), group, this);
 | 
						|
}
 | 
						|
 | 
						|
bool ContentParent::CheckBrowsingContextEmbedder(CanonicalBrowsingContext* aBC,
 | 
						|
                                                 const char* aOperation) const {
 | 
						|
  if (!aBC->IsEmbeddedInProcess(ChildID())) {
 | 
						|
    MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
 | 
						|
            ("ParentIPC: Trying to %s out of process context 0x%08" PRIx64,
 | 
						|
             aOperation, aBC->Id()));
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvDiscardBrowsingContext(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, bool aDoDiscard,
 | 
						|
    DiscardBrowsingContextResolver&& aResolve) {
 | 
						|
  if (CanonicalBrowsingContext* context =
 | 
						|
          CanonicalBrowsingContext::Cast(aContext.GetMaybeDiscarded())) {
 | 
						|
    if (aDoDiscard && !context->IsDiscarded()) {
 | 
						|
      if (!CheckBrowsingContextEmbedder(context, "discard")) {
 | 
						|
        return IPC_FAIL(this, "Illegal Discard attempt");
 | 
						|
      }
 | 
						|
 | 
						|
      context->Detach(/* aFromIPC */ true);
 | 
						|
    }
 | 
						|
    context->AddFinalDiscardListener(aResolve);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  // Resolve the promise, as we've received and handled the message. This will
 | 
						|
  // allow the content process to fully-discard references to this BC.
 | 
						|
  aResolve(true);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::UnregisterRemoveWorkerActor() {
 | 
						|
  MOZ_ASSERT(NS_IsMainThread());
 | 
						|
 | 
						|
  {
 | 
						|
    RecursiveMutexAutoLock lock(mThreadsafeHandle->mMutex);
 | 
						|
    if (--mThreadsafeHandle->mRemoteWorkerActorCount) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
 | 
						|
          ("UnregisterRemoveWorkerActor %p", this));
 | 
						|
  MaybeBeginShutDown();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvWindowClose(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, bool aTrustedCaller) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    MOZ_LOG(
 | 
						|
        BrowsingContext::GetLog(), LogLevel::Debug,
 | 
						|
        ("ParentIPC: Trying to send a message to dead or detached context"));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  CanonicalBrowsingContext* context = aContext.get_canonical();
 | 
						|
 | 
						|
  // FIXME Need to check that the sending process has access to the unit of
 | 
						|
  // related
 | 
						|
  //       browsing contexts of bc.
 | 
						|
 | 
						|
  if (ContentParent* cp = context->GetContentParent()) {
 | 
						|
    Unused << cp->SendWindowClose(context, aTrustedCaller);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvWindowFocus(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType,
 | 
						|
    uint64_t aActionId) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    MOZ_LOG(
 | 
						|
        BrowsingContext::GetLog(), LogLevel::Debug,
 | 
						|
        ("ParentIPC: Trying to send a message to dead or detached context"));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  LOGFOCUS(("ContentParent::RecvWindowFocus actionid: %" PRIu64, aActionId));
 | 
						|
  CanonicalBrowsingContext* context = aContext.get_canonical();
 | 
						|
 | 
						|
  if (ContentParent* cp = context->GetContentParent()) {
 | 
						|
    Unused << cp->SendWindowFocus(context, aCallerType, aActionId);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvWindowBlur(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    MOZ_LOG(
 | 
						|
        BrowsingContext::GetLog(), LogLevel::Debug,
 | 
						|
        ("ParentIPC: Trying to send a message to dead or detached context"));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  CanonicalBrowsingContext* context = aContext.get_canonical();
 | 
						|
 | 
						|
  if (ContentParent* cp = context->GetContentParent()) {
 | 
						|
    Unused << cp->SendWindowBlur(context, aCallerType);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvRaiseWindow(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType,
 | 
						|
    uint64_t aActionId) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    MOZ_LOG(
 | 
						|
        BrowsingContext::GetLog(), LogLevel::Debug,
 | 
						|
        ("ParentIPC: Trying to send a message to dead or detached context"));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  LOGFOCUS(("ContentParent::RecvRaiseWindow actionid: %" PRIu64, aActionId));
 | 
						|
 | 
						|
  CanonicalBrowsingContext* context = aContext.get_canonical();
 | 
						|
 | 
						|
  if (ContentParent* cp = context->GetContentParent()) {
 | 
						|
    Unused << cp->SendRaiseWindow(context, aCallerType, aActionId);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvAdjustWindowFocus(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, bool aIsVisible,
 | 
						|
    uint64_t aActionId, bool aShouldClearFocus,
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aAncestorBrowsingContextToFocus) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    MOZ_LOG(
 | 
						|
        BrowsingContext::GetLog(), LogLevel::Debug,
 | 
						|
        ("ParentIPC: Trying to send a message to dead or detached context"));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  LOGFOCUS(
 | 
						|
      ("ContentParent::RecvAdjustWindowFocus isVisible %d actionid: %" PRIu64,
 | 
						|
       aIsVisible, aActionId));
 | 
						|
 | 
						|
  nsTHashMap<nsPtrHashKey<ContentParent>, bool> processes(2);
 | 
						|
  processes.InsertOrUpdate(this, true);
 | 
						|
 | 
						|
  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
 | 
						|
  if (cpm) {
 | 
						|
    CanonicalBrowsingContext* context = aContext.get_canonical();
 | 
						|
    while (context) {
 | 
						|
      BrowsingContext* parent = context->GetParent();
 | 
						|
      if (!parent) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      CanonicalBrowsingContext* canonicalParent = parent->Canonical();
 | 
						|
      ContentParent* cp = cpm->GetContentProcessById(
 | 
						|
          ContentParentId(canonicalParent->OwnerProcessId()));
 | 
						|
      if (cp && !processes.Get(cp)) {
 | 
						|
        Unused << cp->SendAdjustWindowFocus(context, aIsVisible, aActionId,
 | 
						|
                                            aShouldClearFocus,
 | 
						|
                                            aAncestorBrowsingContextToFocus);
 | 
						|
        processes.InsertOrUpdate(cp, true);
 | 
						|
      }
 | 
						|
      context = canonicalParent;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvClearFocus(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    MOZ_LOG(
 | 
						|
        BrowsingContext::GetLog(), LogLevel::Debug,
 | 
						|
        ("ParentIPC: Trying to send a message to dead or detached context"));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  CanonicalBrowsingContext* context = aContext.get_canonical();
 | 
						|
 | 
						|
  if (ContentParent* cp = context->GetContentParent()) {
 | 
						|
    Unused << cp->SendClearFocus(context);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSetFocusedBrowsingContext(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    MOZ_LOG(
 | 
						|
        BrowsingContext::GetLog(), LogLevel::Debug,
 | 
						|
        ("ParentIPC: Trying to send a message to dead or detached context"));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  LOGFOCUS(("ContentParent::RecvSetFocusedBrowsingContext actionid: %" PRIu64,
 | 
						|
            aActionId));
 | 
						|
  CanonicalBrowsingContext* context = aContext.get_canonical();
 | 
						|
 | 
						|
  nsFocusManager* fm = nsFocusManager::GetFocusManager();
 | 
						|
  if (!fm) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!fm->SetFocusedBrowsingContextInChrome(context, aActionId)) {
 | 
						|
    LOGFOCUS((
 | 
						|
        "Ignoring out-of-sequence attempt [%p] to set focused browsing context "
 | 
						|
        "in parent.",
 | 
						|
        context));
 | 
						|
    Unused << SendReviseFocusedBrowsingContext(
 | 
						|
        aActionId, fm->GetFocusedBrowsingContextInChrome(),
 | 
						|
        fm->GetActionIdForFocusedBrowsingContextInChrome());
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  BrowserParent::UpdateFocusFromBrowsingContext();
 | 
						|
 | 
						|
  context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
 | 
						|
    Unused << aParent->SendSetFocusedBrowsingContext(context, aActionId);
 | 
						|
  });
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSetActiveBrowsingContext(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    MOZ_LOG(
 | 
						|
        BrowsingContext::GetLog(), LogLevel::Debug,
 | 
						|
        ("ParentIPC: Trying to send a message to dead or detached context"));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  LOGFOCUS(("ContentParent::RecvSetActiveBrowsingContext actionid: %" PRIu64,
 | 
						|
            aActionId));
 | 
						|
  CanonicalBrowsingContext* context = aContext.get_canonical();
 | 
						|
 | 
						|
  nsFocusManager* fm = nsFocusManager::GetFocusManager();
 | 
						|
  if (!fm) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!fm->SetActiveBrowsingContextInChrome(context, aActionId)) {
 | 
						|
    LOGFOCUS(
 | 
						|
        ("Ignoring out-of-sequence attempt [%p] to set active browsing context "
 | 
						|
         "in parent.",
 | 
						|
         context));
 | 
						|
    Unused << SendReviseActiveBrowsingContext(
 | 
						|
        aActionId, fm->GetActiveBrowsingContextInChrome(),
 | 
						|
        fm->GetActionIdForActiveBrowsingContextInChrome());
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
 | 
						|
    Unused << aParent->SendSetActiveBrowsingContext(context, aActionId);
 | 
						|
  });
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvUnsetActiveBrowsingContext(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    MOZ_LOG(
 | 
						|
        BrowsingContext::GetLog(), LogLevel::Debug,
 | 
						|
        ("ParentIPC: Trying to send a message to dead or detached context"));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  LOGFOCUS(("ContentParent::RecvUnsetActiveBrowsingContext actionid: %" PRIu64,
 | 
						|
            aActionId));
 | 
						|
  CanonicalBrowsingContext* context = aContext.get_canonical();
 | 
						|
 | 
						|
  nsFocusManager* fm = nsFocusManager::GetFocusManager();
 | 
						|
  if (!fm) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!fm->SetActiveBrowsingContextInChrome(nullptr, aActionId)) {
 | 
						|
    LOGFOCUS(
 | 
						|
        ("Ignoring out-of-sequence attempt to unset active browsing context in "
 | 
						|
         "parent [%p].",
 | 
						|
         context));
 | 
						|
    Unused << SendReviseActiveBrowsingContext(
 | 
						|
        aActionId, fm->GetActiveBrowsingContextInChrome(),
 | 
						|
        fm->GetActionIdForActiveBrowsingContextInChrome());
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
 | 
						|
    Unused << aParent->SendUnsetActiveBrowsingContext(context, aActionId);
 | 
						|
  });
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSetFocusedElement(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, bool aNeedsFocus) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    MOZ_LOG(
 | 
						|
        BrowsingContext::GetLog(), LogLevel::Debug,
 | 
						|
        ("ParentIPC: Trying to send a message to dead or detached context"));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  LOGFOCUS(("ContentParent::RecvSetFocusedElement"));
 | 
						|
  CanonicalBrowsingContext* context = aContext.get_canonical();
 | 
						|
 | 
						|
  if (ContentParent* cp = context->GetContentParent()) {
 | 
						|
    Unused << cp->SendSetFocusedElement(context, aNeedsFocus);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvFinalizeFocusOuter(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, bool aCanFocus,
 | 
						|
    CallerType aCallerType) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    MOZ_LOG(
 | 
						|
        BrowsingContext::GetLog(), LogLevel::Debug,
 | 
						|
        ("ParentIPC: Trying to send a message to dead or detached context"));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  LOGFOCUS(("ContentParent::RecvFinalizeFocusOuter"));
 | 
						|
  CanonicalBrowsingContext* context = aContext.get_canonical();
 | 
						|
  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
 | 
						|
  if (cpm) {
 | 
						|
    ContentParent* cp = cpm->GetContentProcessById(
 | 
						|
        ContentParentId(context->EmbedderProcessId()));
 | 
						|
    if (cp) {
 | 
						|
      Unused << cp->SendFinalizeFocusOuter(context, aCanFocus, aCallerType);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvInsertNewFocusActionId(
 | 
						|
    uint64_t aActionId) {
 | 
						|
  LOGFOCUS(("ContentParent::RecvInsertNewFocusActionId actionid: %" PRIu64,
 | 
						|
            aActionId));
 | 
						|
  nsFocusManager* fm = nsFocusManager::GetFocusManager();
 | 
						|
  if (fm) {
 | 
						|
    fm->InsertNewFocusActionId(aActionId);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvBlurToParent(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aFocusedBrowsingContext,
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aBrowsingContextToClear,
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aAncestorBrowsingContextToFocus,
 | 
						|
    bool aIsLeavingDocument, bool aAdjustWidget,
 | 
						|
    bool aBrowsingContextToClearHandled,
 | 
						|
    bool aAncestorBrowsingContextToFocusHandled, uint64_t aActionId) {
 | 
						|
  if (aFocusedBrowsingContext.IsNullOrDiscarded()) {
 | 
						|
    MOZ_LOG(
 | 
						|
        BrowsingContext::GetLog(), LogLevel::Debug,
 | 
						|
        ("ParentIPC: Trying to send a message to dead or detached context"));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  LOGFOCUS(
 | 
						|
      ("ContentParent::RecvBlurToParent isLeavingDocument %d adjustWidget %d "
 | 
						|
       "browsingContextToClearHandled %d ancestorBrowsingContextToFocusHandled "
 | 
						|
       "%d actionid: %" PRIu64,
 | 
						|
       aIsLeavingDocument, aAdjustWidget, aBrowsingContextToClearHandled,
 | 
						|
       aAncestorBrowsingContextToFocusHandled, aActionId));
 | 
						|
 | 
						|
  CanonicalBrowsingContext* focusedBrowsingContext =
 | 
						|
      aFocusedBrowsingContext.get_canonical();
 | 
						|
 | 
						|
  // If aBrowsingContextToClear and aAncestorBrowsingContextToFocusHandled
 | 
						|
  // didn't get handled in the process that sent this IPC message and they
 | 
						|
  // aren't in the same process as aFocusedBrowsingContext, we need to split
 | 
						|
  // off their handling here and use SendSetFocusedElement to send them
 | 
						|
  // elsewhere than the blurring itself.
 | 
						|
 | 
						|
  bool ancestorDifferent =
 | 
						|
      (!aAncestorBrowsingContextToFocusHandled &&
 | 
						|
       !aAncestorBrowsingContextToFocus.IsNullOrDiscarded() &&
 | 
						|
       (focusedBrowsingContext->OwnerProcessId() !=
 | 
						|
        aAncestorBrowsingContextToFocus.get_canonical()->OwnerProcessId()));
 | 
						|
  if (!aBrowsingContextToClearHandled &&
 | 
						|
      !aBrowsingContextToClear.IsNullOrDiscarded() &&
 | 
						|
      (focusedBrowsingContext->OwnerProcessId() !=
 | 
						|
       aBrowsingContextToClear.get_canonical()->OwnerProcessId())) {
 | 
						|
    MOZ_RELEASE_ASSERT(!ancestorDifferent,
 | 
						|
                       "This combination is not supposed to happen.");
 | 
						|
    if (ContentParent* cp =
 | 
						|
            aBrowsingContextToClear.get_canonical()->GetContentParent()) {
 | 
						|
      Unused << cp->SendSetFocusedElement(aBrowsingContextToClear, false);
 | 
						|
    }
 | 
						|
  } else if (ancestorDifferent) {
 | 
						|
    if (ContentParent* cp = aAncestorBrowsingContextToFocus.get_canonical()
 | 
						|
                                ->GetContentParent()) {
 | 
						|
      Unused << cp->SendSetFocusedElement(aAncestorBrowsingContextToFocus,
 | 
						|
                                          true);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (ContentParent* cp = focusedBrowsingContext->GetContentParent()) {
 | 
						|
    Unused << cp->SendBlurToChild(aFocusedBrowsingContext,
 | 
						|
                                  aBrowsingContextToClear,
 | 
						|
                                  aAncestorBrowsingContextToFocus,
 | 
						|
                                  aIsLeavingDocument, aAdjustWidget, aActionId);
 | 
						|
  }
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvMaybeExitFullscreen(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    MOZ_LOG(
 | 
						|
        BrowsingContext::GetLog(), LogLevel::Debug,
 | 
						|
        ("ParentIPC: Trying to send a message to dead or detached context"));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  CanonicalBrowsingContext* context = aContext.get_canonical();
 | 
						|
 | 
						|
  if (ContentParent* cp = context->GetContentParent()) {
 | 
						|
    Unused << cp->SendMaybeExitFullscreen(context);
 | 
						|
  }
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvWindowPostMessage(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext,
 | 
						|
    const ClonedOrErrorMessageData& aMessage, const PostMessageData& aData) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    MOZ_LOG(
 | 
						|
        BrowsingContext::GetLog(), LogLevel::Debug,
 | 
						|
        ("ParentIPC: Trying to send a message to dead or detached context"));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  CanonicalBrowsingContext* context = aContext.get_canonical();
 | 
						|
 | 
						|
  if (aData.source().IsDiscarded()) {
 | 
						|
    MOZ_LOG(
 | 
						|
        BrowsingContext::GetLog(), LogLevel::Debug,
 | 
						|
        ("ParentIPC: Trying to send a message from dead or detached context"));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<ContentParent> cp = context->GetContentParent();
 | 
						|
  if (!cp) {
 | 
						|
    MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
 | 
						|
            ("ParentIPC: Trying to send PostMessage to dead content process"));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  ClonedOrErrorMessageData message;
 | 
						|
  StructuredCloneData messageFromChild;
 | 
						|
  if (aMessage.type() == ClonedOrErrorMessageData::TClonedMessageData) {
 | 
						|
    UnpackClonedMessageData(aMessage, messageFromChild);
 | 
						|
 | 
						|
    ClonedMessageData clonedMessageData;
 | 
						|
    if (BuildClonedMessageData(messageFromChild, clonedMessageData)) {
 | 
						|
      message = std::move(clonedMessageData);
 | 
						|
    } else {
 | 
						|
      // FIXME Logging?
 | 
						|
      message = ErrorMessageData();
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    MOZ_ASSERT(aMessage.type() == ClonedOrErrorMessageData::TErrorMessageData);
 | 
						|
    message = ErrorMessageData();
 | 
						|
  }
 | 
						|
 | 
						|
  Unused << cp->SendWindowPostMessage(context, message, aData);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::AddBrowsingContextGroup(BrowsingContextGroup* aGroup) {
 | 
						|
  MOZ_DIAGNOSTIC_ASSERT(aGroup);
 | 
						|
  // Ensure that the group has been inserted, and if we're not launching
 | 
						|
  // anymore, also begin subscribing. Launching processes will be subscribed if
 | 
						|
  // they finish launching in `LaunchSubprocessResolve`.
 | 
						|
  if (mGroups.EnsureInserted(aGroup) && !IsLaunching()) {
 | 
						|
    aGroup->Subscribe(this);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ContentParent::RemoveBrowsingContextGroup(BrowsingContextGroup* aGroup) {
 | 
						|
  MOZ_DIAGNOSTIC_ASSERT(aGroup);
 | 
						|
  // Remove the group from our list. This is called from the
 | 
						|
  // BrowsingContextGroup when unsubscribing, so we don't need to do it here.
 | 
						|
  if (mGroups.EnsureRemoved(aGroup) && CanSend()) {
 | 
						|
    // If we're removing the entry for the first time, tell the content process
 | 
						|
    // to clean up the group.
 | 
						|
    Unused << SendDestroyBrowsingContextGroup(aGroup->Id());
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvCommitBrowsingContextTransaction(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext,
 | 
						|
    BrowsingContext::BaseTransaction&& aTransaction, uint64_t aEpoch) {
 | 
						|
  // Record the new BrowsingContextFieldEpoch associated with this transaction.
 | 
						|
  // This should be done unconditionally, so that we're always in-sync.
 | 
						|
  //
 | 
						|
  // The order the parent process receives transactions is considered the
 | 
						|
  // "canonical" ordering, so we don't need to worry about doing any
 | 
						|
  // epoch-related validation.
 | 
						|
  MOZ_ASSERT(aEpoch == mBrowsingContextFieldEpoch + 1,
 | 
						|
             "Child process skipped an epoch?");
 | 
						|
  mBrowsingContextFieldEpoch = aEpoch;
 | 
						|
 | 
						|
  return aTransaction.CommitFromIPC(aContext, this);
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvBlobURLDataRequest(
 | 
						|
    const nsACString& aBlobURL, nsIPrincipal* aTriggeringPrincipal,
 | 
						|
    nsIPrincipal* aLoadingPrincipal, const OriginAttributes& aOriginAttributes,
 | 
						|
    uint64_t aInnerWindowId, const nsCString& aPartitionKey,
 | 
						|
    BlobURLDataRequestResolver&& aResolver) {
 | 
						|
  RefPtr<BlobImpl> blobImpl;
 | 
						|
 | 
						|
  // Since revoked blobs are also retrieved, it is possible that the blob no
 | 
						|
  // longer exists (due to the 5 second timeout) when execution reaches here
 | 
						|
  if (!BlobURLProtocolHandler::GetDataEntry(
 | 
						|
          aBlobURL, getter_AddRefs(blobImpl), aLoadingPrincipal,
 | 
						|
          aTriggeringPrincipal, aOriginAttributes, aInnerWindowId,
 | 
						|
          aPartitionKey, true /* AlsoIfRevoked */)) {
 | 
						|
    aResolver(NS_ERROR_DOM_BAD_URI);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  IPCBlob ipcBlob;
 | 
						|
  nsresult rv = IPCBlobUtils::Serialize(blobImpl, ipcBlob);
 | 
						|
 | 
						|
  if (NS_WARN_IF(NS_FAILED(rv))) {
 | 
						|
    aResolver(rv);
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  aResolver(ipcBlob);
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvReportServiceWorkerShutdownProgress(
 | 
						|
    uint32_t aShutdownStateId, ServiceWorkerShutdownState::Progress aProgress) {
 | 
						|
  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
 | 
						|
  MOZ_RELEASE_ASSERT(swm, "ServiceWorkers should shutdown before SWM.");
 | 
						|
 | 
						|
  swm->ReportServiceWorkerShutdownProgress(aShutdownStateId, aProgress);
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvNotifyOnHistoryReload(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, const bool& aForceReload,
 | 
						|
    NotifyOnHistoryReloadResolver&& aResolver) {
 | 
						|
  bool canReload = false;
 | 
						|
  Maybe<NotNull<RefPtr<nsDocShellLoadState>>> loadState;
 | 
						|
  Maybe<bool> reloadActiveEntry;
 | 
						|
  if (!aContext.IsNullOrDiscarded()) {
 | 
						|
    aContext.get_canonical()->NotifyOnHistoryReload(
 | 
						|
        aForceReload, canReload, loadState, reloadActiveEntry);
 | 
						|
  }
 | 
						|
  aResolver(
 | 
						|
      std::tuple<const bool&,
 | 
						|
                 const Maybe<NotNull<RefPtr<nsDocShellLoadState>>>&,
 | 
						|
                 const Maybe<bool>&>(canReload, loadState, reloadActiveEntry));
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvHistoryCommit(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, const uint64_t& aLoadID,
 | 
						|
    const nsID& aChangeID, const uint32_t& aLoadType, const bool& aPersist,
 | 
						|
    const bool& aCloneEntryChildren, const bool& aChannelExpired,
 | 
						|
    const uint32_t& aCacheKey) {
 | 
						|
  if (!aContext.IsDiscarded()) {
 | 
						|
    CanonicalBrowsingContext* canonical = aContext.get_canonical();
 | 
						|
    if (!canonical) {
 | 
						|
      return IPC_FAIL(
 | 
						|
          this, "Could not get canonical. aContext.get_canonical() fails.");
 | 
						|
    }
 | 
						|
    canonical->SessionHistoryCommit(aLoadID, aChangeID, aLoadType, aPersist,
 | 
						|
                                    aCloneEntryChildren, aChannelExpired,
 | 
						|
                                    aCacheKey);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvHistoryGo(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, int32_t aOffset,
 | 
						|
    uint64_t aHistoryEpoch, bool aRequireUserInteraction, bool aUserActivation,
 | 
						|
    HistoryGoResolver&& aResolveRequestedIndex) {
 | 
						|
  if (!aContext.IsNullOrDiscarded()) {
 | 
						|
    RefPtr<CanonicalBrowsingContext> canonical = aContext.get_canonical();
 | 
						|
    aResolveRequestedIndex(
 | 
						|
        canonical->HistoryGo(aOffset, aHistoryEpoch, aRequireUserInteraction,
 | 
						|
                             aUserActivation, Some(ChildID())));
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSynchronizeLayoutHistoryState(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext,
 | 
						|
    nsILayoutHistoryState* aState) {
 | 
						|
  if (aContext.IsNull()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  BrowsingContext* bc = aContext.GetMaybeDiscarded();
 | 
						|
  if (!bc) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
  SessionHistoryEntry* entry = bc->Canonical()->GetActiveSessionHistoryEntry();
 | 
						|
  if (entry) {
 | 
						|
    entry->SetLayoutHistoryState(aState);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryTitle(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, const nsAString& aTitle) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  SessionHistoryEntry* entry =
 | 
						|
      aContext.get_canonical()->GetActiveSessionHistoryEntry();
 | 
						|
  if (entry) {
 | 
						|
    entry->SetTitle(aTitle);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult
 | 
						|
ContentParent::RecvSessionHistoryEntryScrollRestorationIsManual(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, const bool& aIsManual) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  SessionHistoryEntry* entry =
 | 
						|
      aContext.get_canonical()->GetActiveSessionHistoryEntry();
 | 
						|
  if (entry) {
 | 
						|
    entry->SetScrollRestorationIsManual(aIsManual);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryScrollPosition(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, const int32_t& aX,
 | 
						|
    const int32_t& aY) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  SessionHistoryEntry* entry =
 | 
						|
      aContext.get_canonical()->GetActiveSessionHistoryEntry();
 | 
						|
  if (entry) {
 | 
						|
    entry->SetScrollPosition(aX, aY);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult
 | 
						|
ContentParent::RecvSessionHistoryEntryStoreWindowNameInContiguousEntries(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, const nsAString& aName) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  // Per https://html.spec.whatwg.org/#history-traversal 4.2.1, we need to set
 | 
						|
  // the name to all contiguous entries. This has to be called before
 | 
						|
  // CanonicalBrowsingContext::SessionHistoryCommit(), so the active entry is
 | 
						|
  // still the old entry that we want to set.
 | 
						|
 | 
						|
  SessionHistoryEntry* entry =
 | 
						|
      aContext.get_canonical()->GetActiveSessionHistoryEntry();
 | 
						|
 | 
						|
  if (entry) {
 | 
						|
    nsSHistory::WalkContiguousEntries(
 | 
						|
        entry, [&](nsISHEntry* aEntry) { aEntry->SetName(aName); });
 | 
						|
  }
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryCacheKey(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext,
 | 
						|
    const uint32_t& aCacheKey) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  SessionHistoryEntry* entry =
 | 
						|
      aContext.get_canonical()->GetActiveSessionHistoryEntry();
 | 
						|
  if (entry) {
 | 
						|
    entry->SetCacheKey(aCacheKey);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryWireframe(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext,
 | 
						|
    const Wireframe& aWireframe) {
 | 
						|
  if (aContext.IsNull()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  BrowsingContext* bc = aContext.GetMaybeDiscarded();
 | 
						|
  if (!bc) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  SessionHistoryEntry* entry = bc->Canonical()->GetActiveSessionHistoryEntry();
 | 
						|
  if (entry) {
 | 
						|
    entry->SetWireframe(Some(aWireframe));
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult
 | 
						|
ContentParent::RecvGetLoadingSessionHistoryInfoFromParent(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext,
 | 
						|
    GetLoadingSessionHistoryInfoFromParentResolver&& aResolver) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  Maybe<LoadingSessionHistoryInfo> info;
 | 
						|
  aContext.get_canonical()->GetLoadingSessionHistoryInfoFromParent(info);
 | 
						|
  aResolver(info);
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvRemoveFromBFCache(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext) {
 | 
						|
  if (aContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsFrameLoaderOwner> owner =
 | 
						|
      do_QueryInterface(aContext.get_canonical()->GetEmbedderElement());
 | 
						|
  if (!owner) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<nsFrameLoader> frameLoader = owner->GetFrameLoader();
 | 
						|
  if (!frameLoader || !frameLoader->GetMaybePendingBrowsingContext()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsISHistory> shistory = frameLoader->GetMaybePendingBrowsingContext()
 | 
						|
                                       ->Canonical()
 | 
						|
                                       ->GetSessionHistory();
 | 
						|
  if (!shistory) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  uint32_t count = shistory->GetCount();
 | 
						|
  for (uint32_t i = 0; i < count; ++i) {
 | 
						|
    nsCOMPtr<nsISHEntry> entry;
 | 
						|
    shistory->GetEntryAtIndex(i, getter_AddRefs(entry));
 | 
						|
    nsCOMPtr<SessionHistoryEntry> she = do_QueryInterface(entry);
 | 
						|
    if (she) {
 | 
						|
      if (RefPtr<nsFrameLoader> frameLoader = she->GetFrameLoader()) {
 | 
						|
        if (frameLoader->GetMaybePendingBrowsingContext() == aContext.get()) {
 | 
						|
          she->SetFrameLoader(nullptr);
 | 
						|
          frameLoader->Destroy();
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSetActiveSessionHistoryEntry(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext,
 | 
						|
    const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo&& aInfo,
 | 
						|
    uint32_t aLoadType, uint32_t aUpdatedCacheKey, const nsID& aChangeID) {
 | 
						|
  if (!aContext.IsNullOrDiscarded()) {
 | 
						|
    aContext.get_canonical()->SetActiveSessionHistoryEntry(
 | 
						|
        aPreviousScrollPos, &aInfo, aLoadType, aUpdatedCacheKey, aChangeID);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvReplaceActiveSessionHistoryEntry(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext,
 | 
						|
    SessionHistoryInfo&& aInfo) {
 | 
						|
  if (!aContext.IsNullOrDiscarded()) {
 | 
						|
    aContext.get_canonical()->ReplaceActiveSessionHistoryEntry(&aInfo);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult
 | 
						|
ContentParent::RecvRemoveDynEntriesFromActiveSessionHistoryEntry(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext) {
 | 
						|
  if (!aContext.IsNullOrDiscarded()) {
 | 
						|
    aContext.get_canonical()->RemoveDynEntriesFromActiveSessionHistoryEntry();
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvRemoveFromSessionHistory(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext, const nsID& aChangeID) {
 | 
						|
  if (!aContext.IsNullOrDiscarded()) {
 | 
						|
    aContext.get_canonical()->RemoveFromSessionHistory(aChangeID);
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvHistoryReload(
 | 
						|
    const MaybeDiscarded<BrowsingContext>& aContext,
 | 
						|
    const uint32_t aReloadFlags) {
 | 
						|
  if (!aContext.IsNullOrDiscarded()) {
 | 
						|
    nsCOMPtr<nsISHistory> shistory =
 | 
						|
        aContext.get_canonical()->GetSessionHistory();
 | 
						|
    if (shistory) {
 | 
						|
      shistory->Reload(aReloadFlags);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvCommitWindowContextTransaction(
 | 
						|
    const MaybeDiscarded<WindowContext>& aContext,
 | 
						|
    WindowContext::BaseTransaction&& aTransaction, uint64_t aEpoch) {
 | 
						|
  // Record the new BrowsingContextFieldEpoch associated with this transaction.
 | 
						|
  // This should be done unconditionally, so that we're always in-sync.
 | 
						|
  //
 | 
						|
  // The order the parent process receives transactions is considered the
 | 
						|
  // "canonical" ordering, so we don't need to worry about doing any
 | 
						|
  // epoch-related validation.
 | 
						|
  MOZ_ASSERT(aEpoch == mBrowsingContextFieldEpoch + 1,
 | 
						|
             "Child process skipped an epoch?");
 | 
						|
  mBrowsingContextFieldEpoch = aEpoch;
 | 
						|
 | 
						|
  return aTransaction.CommitFromIPC(aContext, this);
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP ContentParent::GetChildID(uint64_t* aOut) {
 | 
						|
  *aOut = this->ChildID();
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP ContentParent::GetOsPid(int32_t* aOut) {
 | 
						|
  *aOut = Pid();
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP ContentParent::GetRemoteType(nsACString& aRemoteType) {
 | 
						|
  aRemoteType = GetRemoteType();
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
IPCResult ContentParent::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);
 | 
						|
  }
 | 
						|
  MMPrinter::Print("ContentParent::RecvRawMessage", aMeta.actorName(),
 | 
						|
                   aMeta.messageName(), aData);
 | 
						|
  ReceiveRawMessage(aMeta, std::move(data), std::move(stack));
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP ContentParent::GetActor(const nsACString& aName, JSContext* aCx,
 | 
						|
                                      JSProcessActorParent** retval) {
 | 
						|
  ErrorResult error;
 | 
						|
  RefPtr<JSProcessActorParent> actor =
 | 
						|
      JSActorManager::GetActor(aCx, aName, error)
 | 
						|
          .downcast<JSProcessActorParent>();
 | 
						|
  if (error.MaybeSetPendingException(aCx)) {
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
  actor.forget(retval);
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP ContentParent::GetExistingActor(const nsACString& aName,
 | 
						|
                                              JSProcessActorParent** retval) {
 | 
						|
  RefPtr<JSProcessActorParent> actor =
 | 
						|
      JSActorManager::GetExistingActor(aName).downcast<JSProcessActorParent>();
 | 
						|
  actor.forget(retval);
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
already_AddRefed<JSActor> ContentParent::InitJSActor(
 | 
						|
    JS::Handle<JSObject*> aMaybeActor, const nsACString& aName,
 | 
						|
    ErrorResult& aRv) {
 | 
						|
  RefPtr<JSProcessActorParent> actor;
 | 
						|
  if (aMaybeActor.get()) {
 | 
						|
    aRv = UNWRAP_OBJECT(JSProcessActorParent, aMaybeActor.get(), actor);
 | 
						|
    if (aRv.Failed()) {
 | 
						|
      return nullptr;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    actor = new JSProcessActorParent();
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_RELEASE_ASSERT(!actor->Manager(),
 | 
						|
                     "mManager was already initialized once!");
 | 
						|
  actor->Init(aName, this);
 | 
						|
  return actor.forget();
 | 
						|
}
 | 
						|
 | 
						|
IPCResult ContentParent::RecvFOGData(ByteBuf&& buf) {
 | 
						|
  glean::FOGData(std::move(buf));
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::ipc::IPCResult ContentParent::RecvSetContainerFeaturePolicy(
 | 
						|
    const MaybeDiscardedBrowsingContext& aContainerContext,
 | 
						|
    MaybeFeaturePolicyInfo&& aContainerFeaturePolicyInfo) {
 | 
						|
  if (aContainerContext.IsNullOrDiscarded()) {
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
  auto* context = aContainerContext.get_canonical();
 | 
						|
  context->SetContainerFeaturePolicy(std::move(aContainerFeaturePolicyInfo));
 | 
						|
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP ContentParent::GetCanSend(bool* aCanSend) {
 | 
						|
  *aCanSend = CanSend();
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
ContentParent* ContentParent::AsContentParent() { return this; }
 | 
						|
 | 
						|
JSActorManager* ContentParent::AsJSActorManager() { return this; }
 | 
						|
 | 
						|
IPCResult ContentParent::RecvGetSystemIcon(nsIURI* aURI,
 | 
						|
                                           GetSystemIconResolver&& aResolver) {
 | 
						|
  using ResolverArgs = std::tuple<const nsresult&, mozilla::Maybe<ByteBuf>&&>;
 | 
						|
 | 
						|
  if (!aURI) {
 | 
						|
    Maybe<ByteBuf> bytebuf = Nothing();
 | 
						|
    aResolver(ResolverArgs(NS_ERROR_NULL_POINTER, std::move(bytebuf)));
 | 
						|
    return IPC_OK();
 | 
						|
  }
 | 
						|
 | 
						|
#if defined(MOZ_WIDGET_GTK)
 | 
						|
  Maybe<ByteBuf> bytebuf = Some(ByteBuf{});
 | 
						|
  nsresult rv = nsIconChannel::GetIcon(aURI, bytebuf.ptr());
 | 
						|
  if (NS_WARN_IF(NS_FAILED(rv))) {
 | 
						|
    bytebuf = Nothing();
 | 
						|
  }
 | 
						|
  aResolver(ResolverArgs(rv, std::move(bytebuf)));
 | 
						|
  return IPC_OK();
 | 
						|
#elif defined(XP_WIN)
 | 
						|
  nsIconChannel::GetIconAsync(aURI)->Then(
 | 
						|
      GetCurrentSerialEventTarget(), __func__,
 | 
						|
      [aResolver](ByteBuf&& aByteBuf) {
 | 
						|
        Maybe<ByteBuf> bytebuf = Some(std::move(aByteBuf));
 | 
						|
        aResolver(ResolverArgs(NS_OK, std::move(bytebuf)));
 | 
						|
      },
 | 
						|
      [aResolver](nsresult aErr) {
 | 
						|
        Maybe<ByteBuf> bytebuf = Nothing();
 | 
						|
        aResolver(ResolverArgs(aErr, std::move(bytebuf)));
 | 
						|
      });
 | 
						|
  return IPC_OK();
 | 
						|
#else
 | 
						|
  MOZ_CRASH(
 | 
						|
      "This message is currently implemented only on GTK and Windows "
 | 
						|
      "platforms");
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
#ifdef FUZZING_SNAPSHOT
 | 
						|
IPCResult ContentParent::RecvSignalFuzzingReady() {
 | 
						|
  // No action needed here, we already observe this message directly
 | 
						|
  // on the channel and act accordingly.
 | 
						|
  return IPC_OK();
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
nsCString ThreadsafeContentParentHandle::GetRemoteType() {
 | 
						|
  RecursiveMutexAutoLock lock(mMutex);
 | 
						|
  return mRemoteType;
 | 
						|
}
 | 
						|
 | 
						|
bool ThreadsafeContentParentHandle::MaybeRegisterRemoteWorkerActor(
 | 
						|
    MoveOnlyFunction<bool(uint32_t, bool)> aCallback) {
 | 
						|
  RecursiveMutexAutoLock lock(mMutex);
 | 
						|
  if (aCallback(mRemoteWorkerActorCount, mShutdownStarted)) {
 | 
						|
    // TODO: I'd wish we could assert here that our ContentParent is alive.
 | 
						|
    ++mRemoteWorkerActorCount;
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace dom
 | 
						|
}  // namespace mozilla
 | 
						|
 | 
						|
NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
ParentIdleListener::Observe(nsISupports*, const char* aTopic,
 | 
						|
                            const char16_t* aData) {
 | 
						|
  mozilla::Unused << mParent->SendNotifyIdleObserver(
 | 
						|
      mObserver, nsDependentCString(aTopic), nsDependentString(aData));
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
#undef LOGPDM
 |