Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/dom/ipc/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 273 kB image not shown  

Quelle  ContentParent.cpp   Sprache: 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 "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/RDDProcessManager.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/glean/DomMetrics.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/GeolocationSystem.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/NotificationUtils.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/RemoteWorkerServiceParent.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/SharedMemory.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/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 "nsIAppShell.h"
#include "nsIAppWindow.h"
#include "nsIAsyncInputStream.h"
#include "nsIBidiKeyboard.h"
#include "nsICaptivePortalService.h"
#include "nsICertOverrideService.h"
#include "nsIClipboard.h"
#include "nsIContentAnalysis.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");

MOZ_RUNINIT 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;
}

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;
#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

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*/ UniqueContentParentKeepAlive ContentParent::MakePreallocProcess() {
  RefPtr<ContentParent> process = new ContentParent(PREALLOC_REMOTE_TYPE);
  if (NS_WARN_IF(!process->BeginSubprocessLaunch(PROCESS_PRIORITY_PREALLOC))) {
    process->LaunchSubprocessReject();
    return nullptr;
  }
  return process->AddKeepAlive(/* aBrowserId */ 0);
}

/*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) {
    cp->MaybeBeginShutDown(/* aImmediate */ true,
                           /* aIgnoreKeepAlivePref */ true);
    if (cp->IsDead()) {
      // Make sure that this process is no longer accessible from JS by its
      // message manager.
      cp->ShutDownMessageManager();
    }
  }
}

/*static*/
already_AddRefed<ContentParent> ContentParent::MinTabSelect(
    const nsTArray<ContentParent*>& aContentParents, int32_t aMaxContentParents,
    uint64_t aBrowserId) {
  uint32_t maxSelectable =
      std::min(static_cast<uint32_t>(aContentParents.Length()),
               static_cast<uint32_t>(aMaxContentParents));
  uint32_t min = INT_MAX;
  RefPtr<ContentParent> candidate;

  for (uint32_t i = 0; i < maxSelectable; i++) {
    ContentParent* p = aContentParents[i];
    MOZ_DIAGNOSTIC_ASSERT(!p->IsDead());
    if (p->IsShuttingDown()) {
      continue;
    }

    // Check how many other tabs are already hosted by this process.  Ignore
    // keepalives without a BrowserId as well as keepalives corresponding to
    // `aBrowserId` when doing this calculation.
    ThreadsafeContentParentHandle* handle = p->ThreadsafeHandle();
    RecursiveMutexAutoLock lock(handle->mMutex);
    uint32_t keepAliveCount = handle->mKeepAlivesPerBrowserId.Count();
    if (handle->mKeepAlivesPerBrowserId.Contains(0)) {
      --keepAliveCount;
    }
    if (aBrowserId != 0 &&
        handle->mKeepAlivesPerBrowserId.Contains(aBrowserId)) {
      --keepAliveCount;
    }

    if (keepAliveCount < min) {
      candidate = p;
      min = keepAliveCount;
    }
  }

  // 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*/
UniqueContentParentKeepAlive ContentParent::GetUsedBrowserProcess(
    const nsACString& aRemoteType, nsTArray<ContentParent*>& aContentParents,
    uint32_t aMaxContentParents, bool aPreferUsed, ProcessPriority aPriority,
    uint64_t aBrowserId) {
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
  AutoRestore ar(sInProcessSelector);
  sInProcessSelector = true;
#endif

  uint32_t numberOfParents = aContentParents.Length();
  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;
  }

  // Use MinTabSelect to choose a content process unless content process re-use
  // has been disabled.
  RefPtr<ContentParent> selected;
  if (!StaticPrefs::dom_ipc_disableContentProcessReuse() &&
      (selected =
           MinTabSelect(aContentParents, aMaxContentParents, aBrowserId))) {
    if (profiler_thread_is_being_profiled_for_markers()) {
      nsPrintfCString marker("Reused process %u",
                             (unsigned int)selected->ChildID());
      PROFILER_MARKER_TEXT("Process", DOM, {}, marker);
    }
    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
            ("GetUsedProcess: Reused process %p (%d) for %s", selected.get(),
             (unsigned int)selected->ChildID(),
             PromiseFlatCString(aRemoteType).get()));
    selected->AssertAlive();
    return selected->AddKeepAlive(aBrowserId);
  }

  // Try to take a preallocated process except for certain remote types.
  // Note: this process may not have finished launching yet
  UniqueContentParentKeepAlive 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);
    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);

      preallocated->StartRemoteWorkerService();

      nsCOMPtr<nsIObserverService> obs =
          mozilla::services::GetObserverService();
      if (obs) {
        nsAutoString cpId;
        cpId.AppendInt(static_cast<uint64_t>(preallocated->ChildID()));
        obs->NotifyObservers(static_cast<nsIObserver*>(preallocated.get()),
                             "process-type-set", cpId.get());
        preallocated->AssertAlive();
      }
    }
    // NOTE: Make sure to return a keepalive for the requested aBrowserId. The
    // keepalive used by the preallocated process manager will be released upon
    // returning.
    return preallocated->AddKeepAlive(aBrowserId);
  }

  return nullptr;
}

/*static*/
UniqueContentParentKeepAlive ContentParent::GetNewOrUsedLaunchingBrowserProcess(
    const nsACString& aRemoteType, BrowsingContextGroup* aGroup,
    ProcessPriority aPriority, bool aPreferUsed, uint64_t aBrowserId) {
  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.
  UniqueContentParentKeepAlive contentParent;
  if (aGroup) {
    if (RefPtr<ContentParent> candidate = aGroup->GetHostProcess(aRemoteType)) {
      MOZ_DIAGNOSTIC_ASSERT(!candidate->IsShuttingDown());
      MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
              ("GetNewOrUsedProcess: Existing host process %p (launching %d)",
               candidate.get(), candidate->IsLaunching()));
      contentParent = candidate->TryAddKeepAlive(aBrowserId);
    }
  }

  nsTArray<ContentParent*>& contentParents = GetOrCreatePool(aRemoteType);

  if (!contentParent) {
    // No host process. Let's try to re-use an existing process.
    uint32_t maxContentParents = GetMaxProcessCount(aRemoteType);

    contentParent =
        GetUsedBrowserProcess(aRemoteType, contentParents, maxContentParents,
                              aPreferUsed, aPriority, aBrowserId);
    MOZ_DIAGNOSTIC_ASSERT_IF(contentParent, !contentParent->IsShuttingDown());
  }

  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()));

    RefPtr<ContentParent> newCp = new ContentParent(aRemoteType);
    if (NS_WARN_IF(!newCp->BeginSubprocessLaunch(aPriority))) {
      // Launch aborted because of shutdown. Bailout.
      newCp->LaunchSubprocessReject();
      return nullptr;
    }
    contentParent = newCp->AddKeepAlive(aBrowserId);

    // 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.get());

    // 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();
  if (aGroup) {
    aGroup->EnsureHostProcess(contentParent.get());
  }
  return contentParent;
}

/*static*/
RefPtr<ContentParent::LaunchPromise>
ContentParent::GetNewOrUsedBrowserProcessAsync(const nsACString& aRemoteType,
                                               BrowsingContextGroup* aGroup,
                                               ProcessPriority aPriority,
                                               bool aPreferUsed,
                                               uint64_t aBrowserId) {
  // Obtain a `ContentParent` launched asynchronously.
  UniqueContentParentKeepAlive contentParent =
      GetNewOrUsedLaunchingBrowserProcess(aRemoteType, aGroup, aPriority,
                                          aPreferUsed, aBrowserId);
  if (!contentParent) {
    // In case of launch error, stop here.
    return LaunchPromise::CreateAndReject(NS_ERROR_ILLEGAL_DURING_SHUTDOWN,
                                          __func__);
  }
  return contentParent->WaitForLaunchAsync(aPriority, aBrowserId);
}

/*static*/
UniqueContentParentKeepAlive ContentParent::GetNewOrUsedBrowserProcess(
    const nsACString& aRemoteType, BrowsingContextGroup* aGroup,
    ProcessPriority aPriority, bool aPreferUsed, uint64_t aBrowserId) {
  UniqueContentParentKeepAlive contentParent =
      GetNewOrUsedLaunchingBrowserProcess(aRemoteType, aGroup, aPriority,
                                          aPreferUsed, aBrowserId);
  if (!contentParent || !contentParent->WaitForLaunchSync(aPriority)) {
    // In case of launch error, stop here.
    return nullptr;
  }
  return contentParent;
}

RefPtr<ContentParent::LaunchPromise> ContentParent::WaitForLaunchAsync(
    ProcessPriority aPriority, uint64_t aBrowserId) {
  MOZ_DIAGNOSTIC_ASSERT(!IsDead());
  UniqueContentParentKeepAlive self = AddKeepAlive(aBrowserId);

  if (!IsLaunching()) {
    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
            ("WaitForLaunchAsync: launched"));
    return LaunchPromise::CreateAndResolve(std::move(self), __func__);
  }

  // We've started an async content process launch.
  glean::dom_contentprocess::launch_is_sync
      .EnumGet(glean::dom_contentprocess::LaunchIsSyncLabel::eFalse)
      .Add();

  // 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 = std::move(self), aPriority](
          const ProcessHandlePromise::ResolveOrRejectValue& aValue) mutable {
        if (aValue.IsResolve() &&
            self->LaunchSubprocessResolve(/* aIsSync = */ false, aPriority)) {
          MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
                  ("WaitForLaunchAsync: async, now launched"));
          self->mActivateTS = TimeStamp::Now();
          return LaunchPromise::CreateAndResolve(std::move(self), __func__);
        }

        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.
  glean::dom_contentprocess::launch_is_sync
      .EnumGet(glean::dom_contentprocess::LaunchIsSyncLabel::eTrue)
      .Add();

  // 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(EndpointProcInfo::Current(),
                                    OtherEndpointProcInfo(), &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>& aLookbackDays,
    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, aLookbackDays.valueOr(0),
      aImpressionType ? GetEnumString(*aImpressionType) : EmptyCString(), aAds,
      aSourceHosts);
  return IPC_OK();
}

/*static*/
void ContentParent::LogAndAssertFailedPrincipalValidationInfo(
    nsIPrincipal* aPrincipal, const char* aMethod) {
  // Send Telemetry
  nsAutoCString principalScheme, principalType, spec;
  mozilla::glean::security::FissionPrincipalsExtra extra = {};

  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.scheme = Some(principalScheme);
  } else {
    principalType.AssignLiteral("Unknown");
  }
  extra.principaltype = Some(principalType);
  extra.value = Some(aMethod);

  // Do not send telemetry when chrome-debugging is enabled
  bool isChromeDebuggingEnabled =
      Preferences::GetBool("devtools.chrome.enabled"false);
  if (!isChromeDebuggingEnabled) {
    glean::security::fission_principals.Record(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);
  }

  // Hold a KeepAlive on our ContentParent throughout this function. Once the
  // `BrowserParent` has been created, it can be cleared, as that BrowserParent
  // will establish its own KeepAlive.
  UniqueContentParentKeepAlive constructorSender;
  MOZ_RELEASE_ASSERT(XRE_IsParentProcess(),
                     "Cannot allocate BrowserParent in content process");
  if (aOpenerContentParent && !aOpenerContentParent->IsShuttingDown()) {
    constructorSender =
        aOpenerContentParent->AddKeepAlive(aBrowsingContext->BrowserId());
  } else {
    constructorSender = GetNewOrUsedBrowserProcess(
        remoteType, aBrowsingContext->Group(), PROCESS_PRIORITY_FOREGROUND,
        /* aPreferUsed */ false,
        /* aBrowserId */ aBrowsingContext->BrowserId());
    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.get());

  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.get(), 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) {
  for (auto* cp : AllProcesses(eLive)) {
    AutoTArray<StringBundleDescriptor, 1> array;
    array.AppendElement(StringBundleDescriptor(
        aBundle.bundleURL(), SharedMemory::CloneHandle(aBundle.mapHandle()),
        aBundle.mapSize()));
    Unused << cp->SendRegisterStringBundles(std::move(array));
  }
}

void ContentParent::BroadcastShmBlockAdded(uint32_t aGeneration,
                                           uint32_t aIndex) {
  auto* pfl = gfxPlatformFontList::PlatformFontList();
  for (auto* cp : AllProcesses(eLive)) {
    SharedMemory::Handle handle =
        pfl->ShareShmBlockToProcess(aIndex, cp->Pid());
    if (handle == 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 = std::size(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(nsAccessibilityService::GetActiveCacheDomains());
  }
#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());

  // sending only the remote settings schemes to the content process
  nsCOMPtr<nsIIOService> io(do_GetIOService());
  MOZ_ASSERT(io, "No IO service for SimpleURI scheme broadcast to content");
  nsTArray<nsCString> remoteSchemes;
  MOZ_ALWAYS_SUCCEEDS(io->GetSimpleURIUnknownRemoteSchemes(remoteSchemes));
  Unused << SendSimpleURIUnknownRemoteSchemes(std::move(remoteSchemes));
}

void ContentParent::AsyncSendShutDownMessage() {
  MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
          ("AsyncSendShutDownMessage %p"this));
  MOZ_ASSERT(NS_IsMainThread());

  // 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(!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(!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);
  }

  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);

#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);

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=92 H=95 G=93

¤ Dauer der Verarbeitung: 0.26 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.