tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ContentParent.cpp (285929B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "ContentParent.h"
      8 
      9 #include <map>
     10 #include <utility>
     11 
     12 #include "BrowserParent.h"
     13 #include "ContentProcessManager.h"
     14 #include "GMPServiceParent.h"
     15 #include "GeckoProfiler.h"
     16 #include "Geolocation.h"
     17 #include "GfxInfoBase.h"
     18 #include "HandlerServiceParent.h"
     19 #include "IHistory.h"
     20 #include "MMPrinter.h"
     21 #include "PreallocatedProcessManager.h"
     22 #include "ProcessPriorityManager.h"
     23 #include "ProfilerParent.h"
     24 #include "SandboxHal.h"
     25 #include "SourceSurfaceRawData.h"
     26 #include "base/basictypes.h"
     27 #include "chrome/common/process_watcher.h"
     28 #include "gfxPlatform.h"
     29 #include "gfxPlatformFontList.h"
     30 #include "mozilla/AntiTrackingUtils.h"
     31 #include "mozilla/AppShutdown.h"
     32 #include "mozilla/AutoRestore.h"
     33 #include "mozilla/BasePrincipal.h"
     34 #include "mozilla/Casting.h"
     35 #include "mozilla/ClearOnShutdown.h"
     36 #include "mozilla/ClipboardContentAnalysisParent.h"
     37 #include "mozilla/ClipboardReadRequestParent.h"
     38 #include "mozilla/ClipboardWriteRequestParent.h"
     39 #include "mozilla/CmdLineAndEnvUtils.h"
     40 #include "mozilla/Components.h"
     41 #include "mozilla/ContentBlockingUserInteraction.h"
     42 #include "mozilla/DebugOnly.h"
     43 #include "mozilla/FOGIPC.h"
     44 #include "mozilla/GeckoArgs.h"
     45 #include "mozilla/GeckoTrace.h"
     46 #include "mozilla/GlobalStyleSheetCache.h"
     47 #include "mozilla/HangDetails.h"
     48 #include "mozilla/LookAndFeel.h"
     49 #include "mozilla/Maybe.h"
     50 #include "mozilla/NullPrincipal.h"
     51 #include "mozilla/PageloadEvent.h"
     52 #include "mozilla/Preferences.h"
     53 #include "mozilla/PresShell.h"
     54 #include "mozilla/ProcessHangMonitor.h"
     55 #include "mozilla/ProcessHangMonitorIPC.h"
     56 #include "mozilla/ProfilerLabels.h"
     57 #include "mozilla/ProfilerMarkers.h"
     58 #include "mozilla/RDDProcessManager.h"
     59 #include "mozilla/RecursiveMutex.h"
     60 #include "mozilla/RemoteLazyInputStreamParent.h"
     61 #include "mozilla/Result.h"
     62 #include "mozilla/ScopeExit.h"
     63 #include "mozilla/ScriptPreloader.h"
     64 #include "mozilla/Services.h"
     65 #include "mozilla/Sprintf.h"
     66 #include "mozilla/StaticPrefs_dom.h"
     67 #include "mozilla/StaticPrefs_fission.h"
     68 #include "mozilla/StaticPrefs_media.h"
     69 #include "mozilla/StaticPrefs_network.h"
     70 #include "mozilla/StaticPrefs_threads.h"
     71 #include "mozilla/StaticPrefs_widget.h"
     72 #include "mozilla/StorageAccessAPIHelper.h"
     73 #include "mozilla/StyleSheet.h"
     74 #include "mozilla/StyleSheetInlines.h"
     75 #include "mozilla/TaskController.h"
     76 #include "mozilla/Telemetry.h"
     77 #include "mozilla/TelemetryComms.h"
     78 #include "mozilla/TelemetryIPC.h"
     79 #include "mozilla/WebBrowserPersistDocumentParent.h"
     80 #include "mozilla/XREAppData.h"
     81 #include "mozilla/devtools/HeapSnapshotTempFileHelperParent.h"
     82 #include "mozilla/dom/BlobURLProtocolHandler.h"
     83 #include "mozilla/dom/BrowserHost.h"
     84 #include "mozilla/dom/BrowsingContext.h"
     85 #include "mozilla/dom/BrowsingContextGroup.h"
     86 #include "mozilla/dom/CancelContentJSOptionsBinding.h"
     87 #include "mozilla/dom/CanonicalBrowsingContext.h"
     88 #include "mozilla/dom/ClientManager.h"
     89 #include "mozilla/dom/ContentChild.h"
     90 #include "mozilla/dom/DataTransfer.h"
     91 #include "mozilla/dom/Document.h"
     92 #include "mozilla/dom/Element.h"
     93 #include "mozilla/dom/ExternalHelperAppParent.h"
     94 #include "mozilla/dom/File.h"
     95 #include "mozilla/dom/FileSystemSecurity.h"
     96 #include "mozilla/dom/GeolocationBinding.h"
     97 #include "mozilla/dom/GeolocationPositionError.h"
     98 #include "mozilla/dom/GeolocationSystem.h"
     99 #include "mozilla/dom/GetFilesHelper.h"
    100 #include "mozilla/dom/IPCBlobUtils.h"
    101 #include "mozilla/dom/JSActorService.h"
    102 #include "mozilla/dom/JSProcessActorBinding.h"
    103 #include "mozilla/dom/LocalStorageCommon.h"
    104 #include "mozilla/dom/MediaController.h"
    105 #include "mozilla/dom/MediaStatusManager.h"
    106 #include "mozilla/dom/MemoryReportRequest.h"
    107 #include "mozilla/dom/PContentPermissionRequestParent.h"
    108 #include "mozilla/dom/PCycleCollectWithLogsParent.h"
    109 #include "mozilla/dom/ParentProcessMessageManager.h"
    110 #include "mozilla/dom/Permissions.h"
    111 #include "mozilla/dom/ProcessMessageManager.h"
    112 #include "mozilla/dom/PushNotifier.h"
    113 #include "mozilla/dom/RemoteWorkerDebuggerManagerParent.h"
    114 #include "mozilla/dom/RemoteWorkerServiceParent.h"
    115 #include "mozilla/dom/ServiceWorkerManager.h"
    116 #include "mozilla/dom/ServiceWorkerRegistrar.h"
    117 #include "mozilla/dom/ServiceWorkerUtils.h"
    118 #include "mozilla/dom/SessionHistoryEntry.h"
    119 #include "mozilla/dom/SessionStorageManager.h"
    120 #include "mozilla/dom/StorageIPC.h"
    121 #include "mozilla/dom/URLClassifierParent.h"
    122 #include "mozilla/dom/UserActivation.h"
    123 #include "mozilla/dom/WindowGlobalParent.h"
    124 #include "mozilla/dom/ipc/SharedMap.h"
    125 #include "mozilla/dom/ipc/StructuredCloneData.h"
    126 #include "mozilla/dom/notification/NotificationUtils.h"
    127 #include "mozilla/dom/nsMixedContentBlocker.h"
    128 #include "mozilla/dom/power/PowerManagerService.h"
    129 #include "mozilla/dom/quota/QuotaManagerService.h"
    130 #include "mozilla/extensions/ExtensionsParent.h"
    131 #include "mozilla/extensions/StreamFilterParent.h"
    132 #include "mozilla/gfx/GPUProcessManager.h"
    133 #include "mozilla/gfx/gfxVars.h"
    134 #include "mozilla/glean/DomMetrics.h"
    135 #include "mozilla/glean/GleanPings.h"
    136 #include "mozilla/glean/IpcMetrics.h"
    137 #include "mozilla/hal_sandbox/PHalParent.h"
    138 #include "mozilla/intl/L10nRegistry.h"
    139 #include "mozilla/intl/LocaleService.h"
    140 #include "mozilla/intl/OSPreferences.h"
    141 #include "mozilla/ipc/BackgroundChild.h"
    142 #include "mozilla/ipc/BackgroundParent.h"
    143 #include "mozilla/ipc/ByteBuf.h"
    144 #include "mozilla/ipc/CrashReporterHost.h"
    145 #include "mozilla/ipc/Endpoint.h"
    146 #include "mozilla/ipc/FileDescriptorUtils.h"
    147 #include "mozilla/ipc/IPCStreamUtils.h"
    148 #include "mozilla/ipc/ProcessUtils.h"
    149 #include "mozilla/ipc/SharedMemoryHandle.h"
    150 #include "mozilla/ipc/TestShellParent.h"
    151 #include "mozilla/ipc/URIUtils.h"
    152 #include "mozilla/layers/CompositorThread.h"
    153 #include "mozilla/layers/ImageBridgeParent.h"
    154 #include "mozilla/layers/LayerTreeOwnerTracker.h"
    155 #include "mozilla/layers/PAPZParent.h"
    156 #include "mozilla/loader/ScriptCacheActors.h"
    157 #include "mozilla/media/MediaParent.h"
    158 #include "mozilla/mozSpellChecker.h"
    159 #include "mozilla/net/CookieKey.h"
    160 #include "mozilla/net/CookieServiceParent.h"
    161 #include "mozilla/net/NeckoMessageUtils.h"
    162 #include "mozilla/net/NeckoParent.h"
    163 #include "mozilla/net/PCookieServiceParent.h"
    164 #include "mozilla/net/TRRService.h"
    165 #include "mozilla/net/UrlClassifierFeatureFactory.h"
    166 #include "mozilla/widget/RemoteLookAndFeel.h"
    167 #include "mozilla/widget/ScreenManager.h"
    168 #include "mozilla/widget/TextRecognition.h"
    169 #include "nsAnonymousTemporaryFile.h"
    170 #include "nsAppRunner.h"
    171 #include "nsCExternalHandlerService.h"
    172 #include "nsCOMPtr.h"
    173 #include "nsCRT.h"
    174 #include "nsChromeRegistryChrome.h"
    175 #include "nsComponentManagerUtils.h"
    176 #include "nsConsoleMessage.h"
    177 #include "nsConsoleService.h"
    178 #include "nsContentPermissionHelper.h"
    179 #include "nsContentUtils.h"
    180 #include "nsDNSService2.h"
    181 #include "nsDebugImpl.h"
    182 #include "nsDirectoryServiceDefs.h"
    183 #include "nsDocShell.h"
    184 #include "nsEmbedCID.h"
    185 #include "nsFocusManager.h"
    186 #include "nsFrameLoader.h"
    187 #include "nsFrameMessageManager.h"
    188 #include "nsGlobalWindowOuter.h"
    189 #include "nsHashPropertyBag.h"
    190 #include "nsHyphenationManager.h"
    191 #include "nsIAppShell.h"
    192 #include "nsIAppWindow.h"
    193 #include "nsIAsyncInputStream.h"
    194 #include "nsIBidiKeyboard.h"
    195 #include "nsIBrowserDOMWindow.h"
    196 #include "nsICaptivePortalService.h"
    197 #include "nsICertOverrideService.h"
    198 #include "nsIClipboard.h"
    199 #include "nsIContentAnalysis.h"
    200 #include "nsIContentSecurityPolicy.h"
    201 #include "nsICookie.h"
    202 #include "nsICookieNotification.h"
    203 #include "nsICrashService.h"
    204 #include "nsICycleCollectorListener.h"
    205 #include "nsIDocShell.h"
    206 #include "nsIDocShellTreeOwner.h"
    207 #include "nsIDragService.h"
    208 #include "nsIExternalProtocolService.h"
    209 #include "nsIGfxInfo.h"
    210 #include "nsIInterfaceRequestorUtils.h"
    211 #include "nsILocalStorageManager.h"
    212 #include "nsIMemoryInfoDumper.h"
    213 #include "nsIMemoryReporter.h"
    214 #include "nsINetworkLinkService.h"
    215 #include "nsIObserverService.h"
    216 #include "nsIParentChannel.h"
    217 #include "nsIPrivateAttributionService.h"
    218 #include "nsIScriptError.h"
    219 #include "nsIScriptSecurityManager.h"
    220 #include "nsIServiceWorkerManager.h"
    221 #include "nsISiteSecurityService.h"
    222 #include "nsIStringBundle.h"
    223 #include "nsITimer.h"
    224 #include "nsIURL.h"
    225 #include "nsIUserIdleService.h"
    226 #include "nsIWebBrowserChrome.h"
    227 #include "nsIX509Cert.h"
    228 #include "nsIXULRuntime.h"
    229 #include "nsPIDNSService.h"
    230 #if defined(MOZ_WIDGET_GTK) || defined(XP_WIN)
    231 #  include "nsIconChannel.h"
    232 #endif
    233 #include "XPCSelfHostedShmem.h"
    234 #include "nsFrameLoaderOwner.h"
    235 #include "nsMemoryInfoDumper.h"
    236 #include "nsMemoryReporterManager.h"
    237 #include "nsOpenURIInFrameParams.h"
    238 #include "nsOpenWindowInfo.h"
    239 #include "nsPIWindowWatcher.h"
    240 #include "nsQueryObject.h"
    241 #include "nsReadableUtils.h"
    242 #include "nsSHistory.h"
    243 #include "nsScriptError.h"
    244 #include "nsServiceManagerUtils.h"
    245 #include "nsStreamUtils.h"
    246 #include "nsStyleSheetService.h"
    247 #include "nsThread.h"
    248 #include "nsThreadUtils.h"
    249 #include "nsWidgetsCID.h"
    250 #include "nsWindowWatcher.h"
    251 #include "prenv.h"
    252 #include "prio.h"
    253 #include "private/pprio.h"
    254 #include "xpcpublic.h"
    255 
    256 #ifdef MOZ_WEBRTC
    257 #  include "jsapi/WebrtcGlobalParent.h"
    258 #endif
    259 
    260 #if defined(XP_MACOSX)
    261 #  include "mozilla/AvailableMemoryWatcher.h"
    262 #  include "nsMacUtilsImpl.h"
    263 #endif
    264 
    265 #if defined(ANDROID) || defined(LINUX)
    266 #  include "nsSystemInfo.h"
    267 #endif
    268 
    269 #if defined(XP_LINUX)
    270 #  include "mozilla/Hal.h"
    271 #endif
    272 
    273 #ifdef ANDROID
    274 #  include "gfxAndroidPlatform.h"
    275 #endif
    276 
    277 #include "mozilla/PermissionManager.h"
    278 
    279 #ifdef MOZ_WIDGET_ANDROID
    280 #  include "AndroidBridge.h"
    281 #  include "mozilla/java/GeckoProcessManagerWrappers.h"
    282 #  include "mozilla/java/GeckoProcessTypeWrappers.h"
    283 #endif
    284 
    285 #ifdef MOZ_WIDGET_GTK
    286 #  include <gdk/gdk.h>
    287 
    288 #  include "mozilla/WidgetUtilsGtk.h"
    289 #endif
    290 
    291 #include "Crypto.h"
    292 #include "mozilla/RemoteSpellCheckEngineParent.h"
    293 
    294 #ifdef MOZ_WEBSPEECH
    295 #  include "mozilla/dom/SpeechSynthesisParent.h"
    296 #endif
    297 
    298 #if defined(MOZ_SANDBOX)
    299 #  include "mozilla/SandboxSettings.h"
    300 #  if defined(XP_LINUX)
    301 #    include "mozilla/SandboxBroker.h"
    302 #    include "mozilla/SandboxBrokerPolicyFactory.h"
    303 #    include "mozilla/SandboxInfo.h"
    304 #  endif
    305 #  if defined(XP_MACOSX)
    306 #    include "mozilla/Sandbox.h"
    307 #  endif
    308 #endif
    309 
    310 #ifdef XP_WIN
    311 #  include "mozilla/WinDllServices.h"
    312 #endif
    313 
    314 #ifdef MOZ_CODE_COVERAGE
    315 #  include "mozilla/CodeCoverageHandler.h"
    316 #endif
    317 
    318 #ifdef FUZZING_SNAPSHOT
    319 #  include "mozilla/fuzzing/IPCFuzzController.h"
    320 #endif
    321 
    322 #ifdef ENABLE_WEBDRIVER
    323 #  include "nsIMarionette.h"
    324 #  include "nsIRemoteAgent.h"
    325 #endif
    326 
    327 #include "mozilla/RemoteDecodeUtils.h"
    328 #include "nsIToolkitProfile.h"
    329 #include "nsIToolkitProfileService.h"
    330 
    331 #ifdef MOZ_WMF_CDM
    332 #  include "mozilla/EMEUtils.h"
    333 #  include "nsIWindowsMediaFoundationCDMOriginsListService.h"
    334 
    335 namespace mozilla {
    336 class OriginsListLoadCallback final : public nsIOriginsListLoadCallback {
    337 public:
    338  explicit OriginsListLoadCallback(ContentParent* aContentParent)
    339      : mContentParent(aContentParent) {
    340    MOZ_ASSERT(mContentParent);
    341  }
    342 
    343  NS_DECL_ISUPPORTS
    344 
    345  // nsIOriginsListLoadCallback
    346  NS_IMETHODIMP OnOriginsListLoaded(nsIArray* aEntries) {
    347    if (NS_WARN_IF(!mContentParent)) {
    348      return NS_ERROR_FAILURE;
    349    }
    350 
    351    uint32_t length = 0;
    352    nsresult rv = aEntries->GetLength(&length);
    353    if (NS_FAILED(rv)) {
    354      return rv;
    355    }
    356 
    357    nsTArray<dom::IPCOriginStatusEntry> ipcEntries;
    358    for (uint32_t i = 0; i < length; ++i) {
    359      nsCOMPtr<nsIOriginStatusEntry> entry;
    360      aEntries->QueryElementAt(i, NS_GET_IID(nsIOriginStatusEntry),
    361                               getter_AddRefs(entry));
    362      if (!entry) {
    363        NS_WARNING("OriginsListLoadCallback, skip bad entry?");
    364        continue;
    365      }
    366      nsAutoCString origin;
    367      int32_t status = 0;
    368      entry->GetOrigin(origin);
    369      entry->GetStatus(&status);
    370      dom::IPCOriginStatusEntry ipcEntry(origin, status);
    371      ipcEntries.AppendElement(ipcEntry);
    372    }
    373    (void)mContentParent->SendUpdateMFCDMOriginEntries(ipcEntries);
    374    return NS_OK;
    375  }
    376 
    377 private:
    378  ~OriginsListLoadCallback() = default;
    379 
    380  RefPtr<ContentParent> mContentParent;
    381 };
    382 NS_IMPL_ISUPPORTS(OriginsListLoadCallback, nsIOriginsListLoadCallback)
    383 }  // namespace mozilla
    384 #endif
    385 
    386 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
    387 
    388 using base::KillProcess;
    389 
    390 using namespace CrashReporter;
    391 using namespace mozilla::dom::power;
    392 using namespace mozilla::media;
    393 using namespace mozilla::embedding;
    394 using namespace mozilla::gfx;
    395 using namespace mozilla::gmp;
    396 using namespace mozilla::hal;
    397 using namespace mozilla::ipc;
    398 using namespace mozilla::intl;
    399 using namespace mozilla::layers;
    400 using namespace mozilla::layout;
    401 using namespace mozilla::net;
    402 using namespace mozilla::psm;
    403 using namespace mozilla::widget;
    404 using namespace mozilla::Telemetry;
    405 using mozilla::loader::PScriptCacheParent;
    406 using mozilla::Telemetry::ProcessID;
    407 
    408 extern mozilla::LazyLogModule gFocusLog;
    409 
    410 #define LOGFOCUS(args) MOZ_LOG(gFocusLog, mozilla::LogLevel::Debug, args)
    411 
    412 extern mozilla::LazyLogModule sPDMLog;
    413 #define LOGPDM(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
    414 
    415 namespace mozilla {
    416 namespace CubebUtils {
    417 extern FileDescriptor CreateAudioIPCConnection();
    418 }
    419 
    420 namespace dom {
    421 
    422 LazyLogModule gProcessLog("Process");
    423 
    424 MOZ_RUNINIT static std::map<RemoteMediaIn, media::MediaCodecsSupported>
    425    sCodecsSupported;
    426 
    427 /* static */
    428 uint32_t ContentParent::sMaxContentProcesses = 0;
    429 
    430 /* static */
    431 LogModule* ContentParent::GetLog() { return gProcessLog; }
    432 
    433 #define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
    434 #define NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC "ipc:network:set-connectivity"
    435 
    436 // IPC receiver for remote GC/CC logging.
    437 class CycleCollectWithLogsParent final : public PCycleCollectWithLogsParent {
    438 public:
    439  MOZ_COUNTED_DTOR(CycleCollectWithLogsParent)
    440 
    441  static bool AllocAndSendConstructor(ContentParent* aManager,
    442                                      bool aDumpAllTraces,
    443                                      nsICycleCollectorLogSink* aSink,
    444                                      nsIDumpGCAndCCLogsCallback* aCallback) {
    445    CycleCollectWithLogsParent* actor;
    446    FILE* gcLog;
    447    FILE* ccLog;
    448    nsresult rv;
    449 
    450    actor = new CycleCollectWithLogsParent(aSink, aCallback);
    451    rv = actor->mSink->Open(&gcLog, &ccLog);
    452    if (NS_WARN_IF(NS_FAILED(rv))) {
    453      delete actor;
    454      return false;
    455    }
    456 
    457    return aManager->SendPCycleCollectWithLogsConstructor(
    458        actor, aDumpAllTraces, FILEToFileDescriptor(gcLog),
    459        FILEToFileDescriptor(ccLog));
    460  }
    461 
    462 private:
    463  virtual mozilla::ipc::IPCResult RecvCloseGCLog() override {
    464    (void)mSink->CloseGCLog();
    465    return IPC_OK();
    466  }
    467 
    468  virtual mozilla::ipc::IPCResult RecvCloseCCLog() override {
    469    (void)mSink->CloseCCLog();
    470    return IPC_OK();
    471  }
    472 
    473  virtual mozilla::ipc::IPCResult Recv__delete__() override {
    474    // Report completion to mCallback only on successful
    475    // completion of the protocol.
    476    nsCOMPtr<nsIFile> gcLog, ccLog;
    477    mSink->GetGcLog(getter_AddRefs(gcLog));
    478    mSink->GetCcLog(getter_AddRefs(ccLog));
    479    (void)mCallback->OnDump(gcLog, ccLog, /* parent = */ false);
    480    return IPC_OK();
    481  }
    482 
    483  virtual void ActorDestroy(ActorDestroyReason aReason) override {
    484    // If the actor is unexpectedly destroyed, we deliberately
    485    // don't call Close[GC]CLog on the sink, because the logs may
    486    // be incomplete.  See also the nsCycleCollectorLogSinkToFile
    487    // implementaiton of those methods, and its destructor.
    488  }
    489 
    490  CycleCollectWithLogsParent(nsICycleCollectorLogSink* aSink,
    491                             nsIDumpGCAndCCLogsCallback* aCallback)
    492      : mSink(aSink), mCallback(aCallback) {
    493    MOZ_COUNT_CTOR(CycleCollectWithLogsParent);
    494  }
    495 
    496  nsCOMPtr<nsICycleCollectorLogSink> mSink;
    497  nsCOMPtr<nsIDumpGCAndCCLogsCallback> mCallback;
    498 };
    499 
    500 // A memory reporter for ContentParent objects themselves.
    501 class ContentParentsMemoryReporter final : public nsIMemoryReporter {
    502  ~ContentParentsMemoryReporter() = default;
    503 
    504 public:
    505  NS_DECL_ISUPPORTS
    506  NS_DECL_NSIMEMORYREPORTER
    507 };
    508 
    509 NS_IMPL_ISUPPORTS(ContentParentsMemoryReporter, nsIMemoryReporter)
    510 
    511 NS_IMETHODIMP
    512 ContentParentsMemoryReporter::CollectReports(
    513    nsIHandleReportCallback* aHandleReport, nsISupports* aData,
    514    bool aAnonymize) {
    515  AutoTArray<ContentParent*, 16> cps;
    516  ContentParent::GetAllEvenIfDead(cps);
    517 
    518  for (uint32_t i = 0; i < cps.Length(); i++) {
    519    ContentParent* cp = cps[i];
    520    MessageChannel* channel = cp->GetIPCChannel();
    521 
    522    nsString friendlyName;
    523    cp->FriendlyName(friendlyName, aAnonymize);
    524 
    525    cp->AddRef();
    526    nsrefcnt refcnt = cp->Release();
    527 
    528    const char* channelStr = "no channel";
    529    uint32_t numQueuedMessages = 0;
    530    if (channel) {
    531      if (channel->IsClosed()) {
    532        channelStr = "closed channel";
    533      } else {
    534        channelStr = "open channel";
    535      }
    536      numQueuedMessages =
    537          0;  // XXX was channel->Unsound_NumQueuedMessages(); Bug 1754876
    538    }
    539 
    540    nsPrintfCString path(
    541        "queued-ipc-messages/content-parent"
    542        "(%s, pid=%d, %s, 0x%p, refcnt=%" PRIuPTR ")",
    543        NS_ConvertUTF16toUTF8(friendlyName).get(), cp->Pid(), channelStr,
    544        static_cast<nsIObserver*>(cp), refcnt);
    545 
    546    constexpr auto desc =
    547        "The number of unset IPC messages held in this ContentParent's "
    548        "channel.  A large value here might indicate that we're leaking "
    549        "messages.  Similarly, a ContentParent object for a process that's no "
    550        "longer running could indicate that we're leaking ContentParents."_ns;
    551 
    552    aHandleReport->Callback(/* process */ ""_ns, path, KIND_OTHER, UNITS_COUNT,
    553                            numQueuedMessages, desc, aData);
    554  }
    555 
    556  return NS_OK;
    557 }
    558 
    559 // A hashtable (by type) of processes/ContentParents.  This includes
    560 // processes that are in the Preallocator cache (which would be type
    561 // 'prealloc'), and recycled processes ('web' and in the future
    562 // eTLD+1-locked) processes).
    563 nsClassHashtable<nsCStringHashKey, nsTArray<ContentParent*>>*
    564    ContentParent::sBrowserContentParents;
    565 
    566 namespace {
    567 
    568 uint64_t ComputeLoadedOriginHash(nsIPrincipal* aPrincipal) {
    569  uint32_t originNoSuffix =
    570      BasePrincipal::Cast(aPrincipal)->GetOriginNoSuffixHash();
    571  uint32_t originSuffix =
    572      BasePrincipal::Cast(aPrincipal)->GetOriginSuffixHash();
    573 
    574  return ((uint64_t)originNoSuffix) << 32 | originSuffix;
    575 }
    576 
    577 ProcessID GetTelemetryProcessID(const nsACString& remoteType) {
    578  // OOP WebExtensions run in a content process.
    579  // For Telemetry though we want to break out collected data from the
    580  // WebExtensions process into a separate bucket, to make sure we can analyze
    581  // it separately and avoid skewing normal content process metrics.
    582  return remoteType == EXTENSION_REMOTE_TYPE ? ProcessID::Extension
    583                                             : ProcessID::Content;
    584 }
    585 
    586 }  // anonymous namespace
    587 
    588 StaticAutoPtr<LinkedList<ContentParent>> ContentParent::sContentParents;
    589 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
    590 StaticAutoPtr<SandboxBrokerPolicyFactory>
    591    ContentParent::sSandboxBrokerPolicyFactory;
    592 #endif
    593 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
    594 StaticAutoPtr<std::vector<std::string>> ContentParent::sMacSandboxParams;
    595 #endif
    596 
    597 // Set to true when the first content process gets created.
    598 static bool sCreatedFirstContentProcess = false;
    599 
    600 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    601 // True when we're running the process selection code, and do not expect to
    602 // enter code paths where processes may die.
    603 static bool sInProcessSelector = false;
    604 #endif
    605 
    606 static const char* sObserverTopics[] = {
    607    NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
    608    NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
    609    NS_IPC_CAPTIVE_PORTAL_SET_STATE,
    610    "application-background",
    611    "application-foreground",
    612    "memory-pressure",
    613    "child-gc-request",
    614    "child-cc-request",
    615    "child-mmu-request",
    616    "child-ghost-request",
    617    "last-pb-context-exited",
    618    "file-watcher-update",
    619 #ifdef ACCESSIBILITY
    620    "a11y-init-or-shutdown",
    621 #endif
    622    "cacheservice:empty-cache",
    623    "intl:app-locales-changed",
    624    "intl:requested-locales-changed",
    625    "cookie-changed",
    626    "private-cookie-changed",
    627    NS_NETWORK_LINK_TYPE_TOPIC,
    628    NS_NETWORK_TRR_MODE_CHANGED_TOPIC,
    629    "network:socket-process-crashed",
    630    DEFAULT_TIMEZONE_CHANGED_OBSERVER_TOPIC,
    631 };
    632 
    633 void ContentParent_NotifyUpdatedDictionaries() {
    634  ContentParent::NotifyUpdatedDictionaries();
    635 }
    636 
    637 // PreallocateProcess is called by the PreallocatedProcessManager.
    638 // ContentParent then takes this process back within GetNewOrUsedBrowserProcess.
    639 /*static*/ UniqueContentParentKeepAlive ContentParent::MakePreallocProcess() {
    640  RefPtr<ContentParent> process = new ContentParent(PREALLOC_REMOTE_TYPE);
    641  if (NS_WARN_IF(!process->BeginSubprocessLaunch(PROCESS_PRIORITY_PREALLOC))) {
    642    process->LaunchSubprocessReject();
    643    return nullptr;
    644  }
    645  return process->AddKeepAlive(/* aBrowserId */ 0);
    646 }
    647 
    648 /*static*/
    649 void ContentParent::StartUp() {
    650  // FIXME Bug 1023701 - Stop using ContentParent static methods in
    651  // child process
    652  if (!XRE_IsParentProcess()) {
    653    return;
    654  }
    655 
    656  // From this point on, NS_WARNING, NS_ASSERTION, etc. should print out the
    657  // PID along with the warning.
    658  nsDebugImpl::SetMultiprocessMode("Parent");
    659 
    660  // Note: This reporter measures all ContentParents.
    661  RegisterStrongMemoryReporter(new ContentParentsMemoryReporter());
    662 
    663  BackgroundChild::Startup();
    664  ClientManager::Startup();
    665 
    666  Preferences::RegisterCallbackAndCall(&OnFissionBlocklistPrefChange,
    667                                       kFissionEnforceBlockList);
    668  Preferences::RegisterCallbackAndCall(&OnFissionBlocklistPrefChange,
    669                                       kFissionOmitBlockListValues);
    670 
    671 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
    672  sSandboxBrokerPolicyFactory = new SandboxBrokerPolicyFactory();
    673 #endif
    674 
    675 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
    676  sMacSandboxParams = new std::vector<std::string>();
    677 #endif
    678 }
    679 
    680 /*static*/
    681 void ContentParent::ShutDown() {
    682  // For the most, we rely on normal process shutdown and
    683  // ClearOnShutdown() to clean up our state.
    684 
    685 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
    686  sSandboxBrokerPolicyFactory = nullptr;
    687 #endif
    688 
    689 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
    690  sMacSandboxParams = nullptr;
    691 #endif
    692 }
    693 
    694 /*static*/
    695 uint32_t ContentParent::GetPoolSize(const nsACString& aContentProcessType) {
    696  if (!sBrowserContentParents) {
    697    return 0;
    698  }
    699 
    700  nsTArray<ContentParent*>* parents =
    701      sBrowserContentParents->Get(aContentProcessType);
    702 
    703  return parents ? parents->Length() : 0;
    704 }
    705 
    706 /*static*/ nsTArray<ContentParent*>& ContentParent::GetOrCreatePool(
    707    const nsACString& aContentProcessType) {
    708  if (!sBrowserContentParents) {
    709    sBrowserContentParents =
    710        new nsClassHashtable<nsCStringHashKey, nsTArray<ContentParent*>>;
    711  }
    712 
    713  return *sBrowserContentParents->GetOrInsertNew(aContentProcessType);
    714 }
    715 
    716 nsDependentCSubstring RemoteTypePrefix(const nsACString& aContentProcessType) {
    717  // The suffix after a `=` in a remoteType is dynamic, and used to control the
    718  // process pool to use.
    719  int32_t equalIdx = aContentProcessType.FindChar(L'=');
    720  if (equalIdx == kNotFound) {
    721    equalIdx = aContentProcessType.Length();
    722  }
    723  return StringHead(aContentProcessType, equalIdx);
    724 }
    725 
    726 bool IsWebRemoteType(const nsACString& aContentProcessType) {
    727  // Note: matches webIsolated, web, and webCOOP+COEP types.
    728  return StringBeginsWith(aContentProcessType, DEFAULT_REMOTE_TYPE);
    729 }
    730 
    731 bool IsWebCoopCoepRemoteType(const nsACString& aContentProcessType) {
    732  return StringBeginsWith(aContentProcessType,
    733                          WITH_COOP_COEP_REMOTE_TYPE_PREFIX);
    734 }
    735 
    736 bool IsExtensionRemoteType(const nsACString& aContentProcessType) {
    737  return aContentProcessType == EXTENSION_REMOTE_TYPE;
    738 }
    739 
    740 /*static*/
    741 uint32_t ContentParent::GetMaxProcessCount(
    742    const nsACString& aContentProcessType) {
    743  // Max process count is based only on the prefix.
    744  const nsDependentCSubstring processTypePrefix =
    745      RemoteTypePrefix(aContentProcessType);
    746 
    747  // Check for the default remote type of "web", as it uses different prefs.
    748  if (processTypePrefix == DEFAULT_REMOTE_TYPE) {
    749    return GetMaxWebProcessCount();
    750  }
    751 
    752  // Read the pref controling this remote type. `dom.ipc.processCount` is not
    753  // used as a fallback, as it is intended to control the number of "web"
    754  // content processes, checked in `mozilla::GetMaxWebProcessCount()`.
    755  nsAutoCString processCountPref("dom.ipc.processCount.");
    756  processCountPref.Append(processTypePrefix);
    757 
    758  int32_t maxContentParents = Preferences::GetInt(processCountPref.get(), 1);
    759  if (maxContentParents < 1) {
    760    maxContentParents = 1;
    761  }
    762 
    763  return static_cast<uint32_t>(maxContentParents);
    764 }
    765 
    766 /*static*/
    767 bool ContentParent::IsMaxProcessCountReached(
    768    const nsACString& aContentProcessType) {
    769  return GetPoolSize(aContentProcessType) >=
    770         GetMaxProcessCount(aContentProcessType);
    771 }
    772 
    773 // Really more ReleaseUnneededProcesses()
    774 /*static*/
    775 void ContentParent::ReleaseCachedProcesses() {
    776  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
    777          ("ReleaseCachedProcesses:"));
    778  if (!sBrowserContentParents) {
    779    return;
    780  }
    781 
    782 #ifdef DEBUG
    783  for (const auto& cps : *sBrowserContentParents) {
    784    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
    785            ("%s: %zu processes", PromiseFlatCString(cps.GetKey()).get(),
    786             cps.GetData()->Length()));
    787  }
    788 #endif
    789 
    790  // First let's collect all processes and keep a grip.
    791  AutoTArray<RefPtr<ContentParent>, 32> fixArray;
    792  for (const auto& contentParents : sBrowserContentParents->Values()) {
    793    for (auto* cp : *contentParents) {
    794      fixArray.AppendElement(cp);
    795    }
    796  }
    797 
    798  for (const auto& cp : fixArray) {
    799    cp->MaybeBeginShutDown(/* aImmediate */ true,
    800                           /* aIgnoreKeepAlivePref */ true);
    801    if (cp->IsDead()) {
    802      // Make sure that this process is no longer accessible from JS by its
    803      // message manager.
    804      cp->ShutDownMessageManager();
    805    }
    806  }
    807 }
    808 
    809 /*static*/
    810 already_AddRefed<ContentParent> ContentParent::MinTabSelect(
    811    const nsTArray<ContentParent*>& aContentParents, int32_t aMaxContentParents,
    812    uint64_t aBrowserId) {
    813  uint32_t maxSelectable =
    814      std::min(static_cast<uint32_t>(aContentParents.Length()),
    815               static_cast<uint32_t>(aMaxContentParents));
    816  uint32_t min = INT_MAX;
    817  RefPtr<ContentParent> candidate;
    818 
    819  for (uint32_t i = 0; i < maxSelectable; i++) {
    820    ContentParent* p = aContentParents[i];
    821    MOZ_DIAGNOSTIC_ASSERT(!p->IsDead());
    822    if (p->IsShuttingDown()) {
    823      continue;
    824    }
    825 
    826    // Check how many other tabs are already hosted by this process.  Ignore
    827    // keepalives without a BrowserId as well as keepalives corresponding to
    828    // `aBrowserId` when doing this calculation.
    829    ThreadsafeContentParentHandle* handle = p->ThreadsafeHandle();
    830    RecursiveMutexAutoLock lock(handle->mMutex);
    831    uint32_t keepAliveCount = handle->mKeepAlivesPerBrowserId.Count();
    832    if (handle->mKeepAlivesPerBrowserId.Contains(0)) {
    833      --keepAliveCount;
    834    }
    835    if (aBrowserId != 0 &&
    836        handle->mKeepAlivesPerBrowserId.Contains(aBrowserId)) {
    837      --keepAliveCount;
    838    }
    839 
    840    if (keepAliveCount < min) {
    841      candidate = p;
    842      min = keepAliveCount;
    843    }
    844  }
    845 
    846  // If all current processes have at least one tab and we have not yet reached
    847  // the maximum, use a new process.
    848  if (min > 0 &&
    849      aContentParents.Length() < static_cast<uint32_t>(aMaxContentParents)) {
    850    return nullptr;
    851  }
    852 
    853  // Otherwise we return candidate.
    854  return candidate.forget();
    855 }
    856 
    857 /* static */
    858 already_AddRefed<nsIPrincipal>
    859 ContentParent::CreateRemoteTypeIsolationPrincipal(
    860    const nsACString& aRemoteType) {
    861  if ((RemoteTypePrefix(aRemoteType) != FISSION_WEB_REMOTE_TYPE) &&
    862      !StringBeginsWith(aRemoteType, WITH_COOP_COEP_REMOTE_TYPE_PREFIX)) {
    863    return nullptr;
    864  }
    865 
    866  int32_t offset = aRemoteType.FindChar('=') + 1;
    867  MOZ_ASSERT(offset > 1, "can not extract origin from that remote type");
    868  nsAutoCString origin(
    869      Substring(aRemoteType, offset, aRemoteType.Length() - offset));
    870 
    871  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
    872  nsCOMPtr<nsIPrincipal> principal;
    873  ssm->CreateContentPrincipalFromOrigin(origin, getter_AddRefs(principal));
    874  return principal.forget();
    875 }
    876 
    877 /*static*/
    878 UniqueContentParentKeepAlive ContentParent::GetUsedBrowserProcess(
    879    const nsACString& aRemoteType, nsTArray<ContentParent*>& aContentParents,
    880    uint32_t aMaxContentParents, bool aPreferUsed, ProcessPriority aPriority,
    881    uint64_t aBrowserId) {
    882 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
    883  AutoRestore ar(sInProcessSelector);
    884  sInProcessSelector = true;
    885 #endif
    886 
    887  uint32_t numberOfParents = aContentParents.Length();
    888  if (aPreferUsed && numberOfParents) {
    889    // If we prefer re-using existing content processes, we don't want to create
    890    // a new process, and instead re-use an existing one, so pretend the process
    891    // limit is at the current number of processes.
    892    aMaxContentParents = numberOfParents;
    893  }
    894 
    895  // Use MinTabSelect to choose a content process unless content process re-use
    896  // has been disabled.
    897  RefPtr<ContentParent> selected;
    898  if (!StaticPrefs::dom_ipc_disableContentProcessReuse() &&
    899      (selected =
    900           MinTabSelect(aContentParents, aMaxContentParents, aBrowserId))) {
    901    if (profiler_thread_is_being_profiled_for_markers()) {
    902      nsPrintfCString marker("Reused process %u",
    903                             (unsigned int)selected->ChildID());
    904      PROFILER_MARKER_TEXT("Process", DOM, {}, marker);
    905    }
    906    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
    907            ("GetUsedProcess: Reused process id=%p childID=%" PRIu64 " for %s",
    908             selected.get(), (uint64_t)selected->ChildID(),
    909             PromiseFlatCString(aRemoteType).get()));
    910    selected->AssertAlive();
    911    return selected->AddKeepAlive(aBrowserId);
    912  }
    913 
    914  // Try to take a preallocated process except for certain remote types.
    915  // Note: this process may not have finished launching yet
    916  UniqueContentParentKeepAlive preallocated;
    917  if (aRemoteType != FILE_REMOTE_TYPE &&
    918      aRemoteType != PRIVILEGEDABOUT_REMOTE_TYPE &&
    919      aRemoteType != EXTENSION_REMOTE_TYPE &&  // Bug 1638119
    920      (preallocated = PreallocatedProcessManager::Take(aRemoteType))) {
    921    MOZ_DIAGNOSTIC_ASSERT(preallocated->GetRemoteType() ==
    922                          PREALLOC_REMOTE_TYPE);
    923    preallocated->AssertAlive();
    924 
    925    if (profiler_thread_is_being_profiled_for_markers()) {
    926      nsPrintfCString marker(
    927          "Assigned preallocated process %u%s",
    928          (unsigned int)preallocated->ChildID(),
    929          preallocated->IsLaunching() ? " (still launching)" : "");
    930      PROFILER_MARKER_TEXT("Process", DOM, {}, marker);
    931    }
    932    MOZ_LOG(
    933        ContentParent::GetLog(), LogLevel::Debug,
    934        ("Adopted preallocated process id=%p childID=%" PRIu64 " for type %s%s",
    935         preallocated.get(), (uint64_t)preallocated->ChildID(),
    936         PromiseFlatCString(aRemoteType).get(),
    937         preallocated->IsLaunching() ? " (still launching)" : ""));
    938 
    939    // This ensures that the preallocator won't shut down the process once
    940    // it finishes starting
    941    preallocated->mRemoteType.Assign(aRemoteType);
    942    {
    943      RecursiveMutexAutoLock lock(preallocated->mThreadsafeHandle->mMutex);
    944      preallocated->mThreadsafeHandle->mRemoteType = preallocated->mRemoteType;
    945    }
    946    preallocated->mRemoteTypeIsolationPrincipal =
    947        CreateRemoteTypeIsolationPrincipal(aRemoteType);
    948    preallocated->AddToPool(aContentParents);
    949 
    950    // rare, but will happen
    951    if (!preallocated->IsLaunching()) {
    952      // Specialize this process for the appropriate remote type, and activate
    953      // it.
    954 
    955      (void)preallocated->SendRemoteType(preallocated->mRemoteType,
    956                                         preallocated->mProfile);
    957 
    958      preallocated->StartRemoteWorkerService();
    959 
    960      nsCOMPtr<nsIObserverService> obs =
    961          mozilla::services::GetObserverService();
    962      if (obs) {
    963        nsAutoString cpId;
    964        cpId.AppendInt(static_cast<uint64_t>(preallocated->ChildID()));
    965        obs->NotifyObservers(static_cast<nsIObserver*>(preallocated.get()),
    966                             "process-type-set", cpId.get());
    967        preallocated->AssertAlive();
    968      }
    969    }
    970    // NOTE: Make sure to return a keepalive for the requested aBrowserId. The
    971    // keepalive used by the preallocated process manager will be released upon
    972    // returning.
    973    return preallocated->AddKeepAlive(aBrowserId);
    974  }
    975 
    976  return nullptr;
    977 }
    978 
    979 /*static*/
    980 UniqueContentParentKeepAlive ContentParent::GetNewOrUsedLaunchingBrowserProcess(
    981    const nsACString& aRemoteType, BrowsingContextGroup* aGroup,
    982    ProcessPriority aPriority, bool aPreferUsed, uint64_t aBrowserId) {
    983  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
    984          ("GetNewOrUsedProcess for type %s",
    985           PromiseFlatCString(aRemoteType).get()));
    986 
    987  if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
    988    return nullptr;
    989  }
    990 
    991  // If we have an existing host process attached to this BrowsingContextGroup,
    992  // always return it, as we can never have multiple host processes within a
    993  // single BrowsingContextGroup.
    994  UniqueContentParentKeepAlive contentParent;
    995  if (aGroup) {
    996    if (RefPtr<ContentParent> candidate = aGroup->GetHostProcess(aRemoteType)) {
    997      MOZ_DIAGNOSTIC_ASSERT(!candidate->IsShuttingDown());
    998      MOZ_LOG(
    999          ContentParent::GetLog(), LogLevel::Debug,
   1000          ("GetNewOrUsedProcess: Existing host process id=%p childID=%" PRIu64
   1001           " (launching %d)",
   1002           candidate.get(), (uint64_t)candidate->ChildID(),
   1003           candidate->IsLaunching()));
   1004      contentParent = candidate->TryAddKeepAlive(aBrowserId);
   1005    }
   1006  }
   1007 
   1008  nsTArray<ContentParent*>& contentParents = GetOrCreatePool(aRemoteType);
   1009 
   1010  if (!contentParent) {
   1011    // No host process. Let's try to re-use an existing process.
   1012    uint32_t maxContentParents = GetMaxProcessCount(aRemoteType);
   1013 
   1014    contentParent =
   1015        GetUsedBrowserProcess(aRemoteType, contentParents, maxContentParents,
   1016                              aPreferUsed, aPriority, aBrowserId);
   1017    MOZ_DIAGNOSTIC_ASSERT_IF(contentParent, !contentParent->IsShuttingDown());
   1018  }
   1019 
   1020  if (!contentParent) {
   1021    // No reusable process. Let's create and launch one.
   1022    // The life cycle will be set to `LifecycleState::LAUNCHING`.
   1023    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
   1024            ("Launching new process immediately for type %s",
   1025             PromiseFlatCString(aRemoteType).get()));
   1026 
   1027    RefPtr<ContentParent> newCp = new ContentParent(aRemoteType);
   1028    if (NS_WARN_IF(!newCp->BeginSubprocessLaunch(aPriority))) {
   1029      // Launch aborted because of shutdown. Bailout.
   1030      newCp->LaunchSubprocessReject();
   1031      return nullptr;
   1032    }
   1033    contentParent = newCp->AddKeepAlive(aBrowserId);
   1034 
   1035    // Until the new process is ready let's not allow to start up any
   1036    // preallocated processes. The blocker will be removed once we receive
   1037    // the first idle message.
   1038    contentParent->mIsAPreallocBlocker = true;
   1039    PreallocatedProcessManager::AddBlocker(aRemoteType, contentParent.get());
   1040 
   1041    // Store this process for future reuse.
   1042    contentParent->AddToPool(contentParents);
   1043 
   1044    MOZ_LOG(
   1045        ContentParent::GetLog(), LogLevel::Debug,
   1046        ("GetNewOrUsedProcess: new immediate process id=%p childID=%" PRIu64,
   1047         contentParent.get(), (uint64_t)contentParent->ChildID()));
   1048  }
   1049  // else we have an existing or preallocated process (which may be
   1050  // still launching)
   1051 
   1052  contentParent->AssertAlive();
   1053  if (aGroup) {
   1054    aGroup->EnsureHostProcess(contentParent.get());
   1055  }
   1056  return contentParent;
   1057 }
   1058 
   1059 /*static*/
   1060 RefPtr<ContentParent::LaunchPromise>
   1061 ContentParent::GetNewOrUsedBrowserProcessAsync(const nsACString& aRemoteType,
   1062                                               BrowsingContextGroup* aGroup,
   1063                                               ProcessPriority aPriority,
   1064                                               bool aPreferUsed,
   1065                                               uint64_t aBrowserId) {
   1066  // Obtain a `ContentParent` launched asynchronously.
   1067  UniqueContentParentKeepAlive contentParent =
   1068      GetNewOrUsedLaunchingBrowserProcess(aRemoteType, aGroup, aPriority,
   1069                                          aPreferUsed, aBrowserId);
   1070  if (!contentParent) {
   1071    // In case of launch error, stop here.
   1072    return LaunchPromise::CreateAndReject(NS_ERROR_ILLEGAL_DURING_SHUTDOWN,
   1073                                          __func__);
   1074  }
   1075  return contentParent->WaitForLaunchAsync(aPriority, aBrowserId);
   1076 }
   1077 
   1078 /*static*/
   1079 UniqueContentParentKeepAlive ContentParent::GetNewOrUsedBrowserProcess(
   1080    const nsACString& aRemoteType, BrowsingContextGroup* aGroup,
   1081    ProcessPriority aPriority, bool aPreferUsed, uint64_t aBrowserId) {
   1082  UniqueContentParentKeepAlive contentParent =
   1083      GetNewOrUsedLaunchingBrowserProcess(aRemoteType, aGroup, aPriority,
   1084                                          aPreferUsed, aBrowserId);
   1085  if (!contentParent || !contentParent->WaitForLaunchSync(aPriority)) {
   1086    // In case of launch error, stop here.
   1087    return nullptr;
   1088  }
   1089  return contentParent;
   1090 }
   1091 
   1092 RefPtr<ContentParent::LaunchPromise> ContentParent::WaitForLaunchAsync(
   1093    ProcessPriority aPriority, uint64_t aBrowserId) {
   1094  MOZ_DIAGNOSTIC_ASSERT(!IsDead());
   1095  UniqueContentParentKeepAlive self = AddKeepAlive(aBrowserId);
   1096 
   1097  if (!IsLaunching()) {
   1098    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
   1099            ("WaitForLaunchAsync: launched"));
   1100    return LaunchPromise::CreateAndResolve(std::move(self), __func__);
   1101  }
   1102 
   1103  // We've started an async content process launch.
   1104  glean::dom_contentprocess::launch_is_sync
   1105      .EnumGet(glean::dom_contentprocess::LaunchIsSyncLabel::eFalse)
   1106      .Add();
   1107 
   1108  // We have located a process that hasn't finished initializing, then attempt
   1109  // to finish initializing. Both `LaunchSubprocessResolve` and
   1110  // `LaunchSubprocessReject` are safe to call multiple times if we race with
   1111  // other `WaitForLaunchAsync` callbacks.
   1112  return mSubprocess->WhenProcessHandleReady()->Then(
   1113      GetCurrentSerialEventTarget(), __func__,
   1114      [self = std::move(self), aPriority](
   1115          const ProcessHandlePromise::ResolveOrRejectValue& aValue) mutable {
   1116        if (aValue.IsResolve() &&
   1117            self->LaunchSubprocessResolve(/* aIsSync = */ false, aPriority)) {
   1118          MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
   1119                  ("WaitForLaunchAsync: async, now launched, process id=%p, "
   1120                   "childID=%" PRIu64,
   1121                   self.get(), (uint64_t)self->ChildID()));
   1122          return LaunchPromise::CreateAndResolve(std::move(self), __func__);
   1123        }
   1124 
   1125        MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
   1126                ("WaitForLaunchAsync: async, rejected"));
   1127        self->LaunchSubprocessReject();
   1128        return LaunchPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   1129      });
   1130 }
   1131 
   1132 bool ContentParent::WaitForLaunchSync(ProcessPriority aPriority) {
   1133  MOZ_DIAGNOSTIC_ASSERT(!IsDead());
   1134  if (!IsLaunching()) {
   1135    return true;
   1136  }
   1137 
   1138  // We've started a sync content process launch.
   1139  glean::dom_contentprocess::launch_is_sync
   1140      .EnumGet(glean::dom_contentprocess::LaunchIsSyncLabel::eTrue)
   1141      .Add();
   1142 
   1143  // We're a process which hasn't finished initializing. We may be racing
   1144  // against whoever launched it (and whoever else is already racing). Since
   1145  // we're sync, we win the race and finish the initialization.
   1146  bool launchSuccess = mSubprocess->WaitForProcessHandle();
   1147  if (launchSuccess &&
   1148      LaunchSubprocessResolve(/* aIsSync = */ true, aPriority)) {
   1149    return true;
   1150  }
   1151  // In case of failure.
   1152  LaunchSubprocessReject();
   1153  return false;
   1154 }
   1155 
   1156 static nsIDocShell* GetOpenerDocShellHelper(Element* aFrameElement) {
   1157  // Propagate the private-browsing status of the element's parent
   1158  // docshell to the remote docshell, via the chrome flags.
   1159  MOZ_ASSERT(aFrameElement);
   1160  nsPIDOMWindowOuter* win = aFrameElement->OwnerDoc()->GetWindow();
   1161  if (!win) {
   1162    NS_WARNING("Remote frame has no window");
   1163    return nullptr;
   1164  }
   1165  nsIDocShell* docShell = win->GetDocShell();
   1166  if (!docShell) {
   1167    NS_WARNING("Remote frame has no docshell");
   1168    return nullptr;
   1169  }
   1170 
   1171  return docShell;
   1172 }
   1173 
   1174 mozilla::ipc::IPCResult ContentParent::RecvCreateClipboardContentAnalysis(
   1175    Endpoint<PClipboardContentAnalysisParent>&& aParentEndpoint) {
   1176  if (mClipboardContentAnalysisCreated) {
   1177    return IPC_FAIL(this, "ClipboardContentAnalysisParent already created");
   1178  }
   1179  mClipboardContentAnalysisCreated = true;
   1180 
   1181  if (!mClipboardContentAnalysisThread) {
   1182    nsresult rv = NS_NewNamedThread(
   1183        "BkgrndClipboard", getter_AddRefs(mClipboardContentAnalysisThread));
   1184    if (NS_WARN_IF(NS_FAILED(rv))) {
   1185      return IPC_FAIL(this, "NS_NewNamedThread failed");
   1186    }
   1187  }
   1188 
   1189  // Bind the new endpoint to the backgroundClipboardContentAnalysis thread.
   1190  mClipboardContentAnalysisThread->Dispatch(
   1191      NS_NewRunnableFunction(
   1192          "Create ClipboardContentAnalysisParent",
   1193          [threadsafeHandle = RefPtr{ThreadsafeHandle()},
   1194           parentEndpoint = std::move(aParentEndpoint)]() mutable {
   1195            // Use a threadsafe handle here, so that it can
   1196            // be used to validate that the WindowContext comes from the
   1197            // correct content process.
   1198            RefPtr<ClipboardContentAnalysisParent> actor =
   1199                new ClipboardContentAnalysisParent(std::move(threadsafeHandle));
   1200            parentEndpoint.Bind(actor);
   1201          }),
   1202      NS_DISPATCH_NORMAL);
   1203  return IPC_OK();
   1204 }
   1205 
   1206 mozilla::ipc::IPCResult ContentParent::RecvCreateGMPService() {
   1207  Endpoint<PGMPServiceParent> parent;
   1208  Endpoint<PGMPServiceChild> child;
   1209 
   1210  if (mGMPCreated) {
   1211    return IPC_FAIL(this, "GMP Service already created");
   1212  }
   1213 
   1214  nsresult rv;
   1215  rv = PGMPService::CreateEndpoints(EndpointProcInfo::Current(),
   1216                                    OtherEndpointProcInfo(), &parent, &child);
   1217  if (NS_FAILED(rv)) {
   1218    return IPC_FAIL(this, "CreateEndpoints failed");
   1219  }
   1220 
   1221  if (!GMPServiceParent::Create(std::move(parent))) {
   1222    return IPC_FAIL(this, "GMPServiceParent::Create failed");
   1223  }
   1224 
   1225  if (!SendInitGMPService(std::move(child))) {
   1226    return IPC_FAIL(this, "SendInitGMPService failed");
   1227  }
   1228 
   1229  mGMPCreated = true;
   1230 
   1231  return IPC_OK();
   1232 }
   1233 
   1234 IPCResult ContentParent::RecvAttributionEvent(
   1235    const nsACString& aHost, PrivateAttributionImpressionType aType,
   1236    uint32_t aIndex, const nsAString& aAd, const nsACString& aTargetHost) {
   1237  nsCOMPtr<nsIPrivateAttributionService> pa =
   1238      components::PrivateAttribution::Service();
   1239  if (NS_WARN_IF(!pa)) {
   1240    return IPC_OK();
   1241  }
   1242  pa->OnAttributionEvent(aHost, GetEnumString(aType), aIndex, aAd, aTargetHost);
   1243  return IPC_OK();
   1244 }
   1245 
   1246 IPCResult ContentParent::RecvAttributionConversion(
   1247    const nsACString& aHost, const nsAString& aTask, uint32_t aHistogramSize,
   1248    const Maybe<uint32_t>& aLookbackDays,
   1249    const Maybe<PrivateAttributionImpressionType>& aImpressionType,
   1250    const nsTArray<nsString>& aAds, const nsTArray<nsCString>& aSourceHosts) {
   1251  nsCOMPtr<nsIPrivateAttributionService> pa =
   1252      components::PrivateAttribution::Service();
   1253  if (NS_WARN_IF(!pa)) {
   1254    return IPC_OK();
   1255  }
   1256  pa->OnAttributionConversion(
   1257      aHost, aTask, aHistogramSize, aLookbackDays.valueOr(0),
   1258      aImpressionType ? GetEnumString(*aImpressionType) : EmptyCString(), aAds,
   1259      aSourceHosts);
   1260  return IPC_OK();
   1261 }
   1262 
   1263 /*static*/
   1264 void ContentParent::LogAndAssertFailedPrincipalValidationInfo(
   1265    nsIPrincipal* aPrincipal, const char* aMethod) {
   1266  // Send Telemetry
   1267  nsAutoCString principalScheme, principalType, spec;
   1268  mozilla::glean::security::FissionPrincipalsExtra extra = {};
   1269 
   1270  if (!aPrincipal) {
   1271    principalType.AssignLiteral("NullPtr");
   1272  } else if (aPrincipal->IsSystemPrincipal()) {
   1273    principalType.AssignLiteral("SystemPrincipal");
   1274  } else if (aPrincipal->GetIsExpandedPrincipal()) {
   1275    principalType.AssignLiteral("ExpandedPrincipal");
   1276  } else if (aPrincipal->GetIsContentPrincipal()) {
   1277    principalType.AssignLiteral("ContentPrincipal");
   1278    aPrincipal->GetSpec(spec);
   1279    aPrincipal->GetScheme(principalScheme);
   1280 
   1281    extra.scheme = Some(principalScheme);
   1282  } else {
   1283    principalType.AssignLiteral("Unknown");
   1284  }
   1285  extra.principaltype = Some(principalType);
   1286  extra.value = Some(aMethod);
   1287 
   1288  // Do not send telemetry when chrome-debugging is enabled
   1289  bool isChromeDebuggingEnabled =
   1290      Preferences::GetBool("devtools.chrome.enabled", false);
   1291  if (!isChromeDebuggingEnabled) {
   1292    glean::security::fission_principals.Record(mozilla::Some(extra));
   1293  }
   1294 
   1295  // And log it
   1296  MOZ_LOG(
   1297      ContentParent::GetLog(), LogLevel::Error,
   1298      ("  Receiving unexpected Principal (%s) within %s",
   1299       aPrincipal && aPrincipal->GetIsContentPrincipal() ? spec.get()
   1300                                                         : principalType.get(),
   1301       aMethod));
   1302 
   1303 #ifdef DEBUG
   1304  // Not only log but also ensure we do not receive an unexpected
   1305  // principal when running in debug mode.
   1306  MOZ_ASSERT(false, "Receiving unexpected Principal");
   1307 #endif
   1308 }
   1309 
   1310 bool ContentParent::ValidatePrincipal(
   1311    nsIPrincipal* aPrincipal,
   1312    const EnumSet<ValidatePrincipalOptions>& aOptions) {
   1313  return ValidatePrincipalCouldPotentiallyBeLoadedBy(aPrincipal, mRemoteType,
   1314                                                     aOptions);
   1315 }
   1316 
   1317 /*static*/
   1318 already_AddRefed<RemoteBrowser> ContentParent::CreateBrowser(
   1319    const TabContext& aContext, Element* aFrameElement,
   1320    const nsACString& aRemoteType, BrowsingContext* aBrowsingContext,
   1321    ContentParent* aOpenerContentParent) {
   1322  AUTO_PROFILER_LABEL("ContentParent::CreateBrowser", OTHER);
   1323 
   1324  MOZ_DIAGNOSTIC_ASSERT(
   1325      !aBrowsingContext->Canonical()->GetBrowserParent(),
   1326      "BrowsingContext must not have BrowserParent, or have previous "
   1327      "BrowserParent cleared");
   1328 
   1329  // Don't bother creating new content browsers after entering shutdown. This
   1330  // could lead to starting a new content process, which may significantly delay
   1331  // shutdown, and the content is unlikely to be displayed.
   1332  if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
   1333    NS_WARNING("Ignoring remote browser creation request during shutdown");
   1334    return nullptr;
   1335  }
   1336 
   1337  nsAutoCString remoteType(aRemoteType);
   1338  if (remoteType.IsEmpty()) {
   1339    remoteType = DEFAULT_REMOTE_TYPE;
   1340  }
   1341 
   1342  TabId tabId(nsContentUtils::GenerateTabId());
   1343 
   1344  nsIDocShell* docShell = GetOpenerDocShellHelper(aFrameElement);
   1345  TabId openerTabId;
   1346  if (docShell) {
   1347    openerTabId = BrowserParent::GetTabIdFrom(docShell);
   1348  }
   1349 
   1350  // Hold a KeepAlive on our ContentParent throughout this function. Once the
   1351  // `BrowserParent` has been created, it can be cleared, as that BrowserParent
   1352  // will establish its own KeepAlive.
   1353  UniqueContentParentKeepAlive constructorSender;
   1354  MOZ_RELEASE_ASSERT(XRE_IsParentProcess(),
   1355                     "Cannot allocate BrowserParent in content process");
   1356  if (aOpenerContentParent && !aOpenerContentParent->IsShuttingDown()) {
   1357    constructorSender =
   1358        aOpenerContentParent->AddKeepAlive(aBrowsingContext->BrowserId());
   1359  } else {
   1360    constructorSender = GetNewOrUsedBrowserProcess(
   1361        remoteType, aBrowsingContext->Group(), PROCESS_PRIORITY_FOREGROUND,
   1362        /* aPreferUsed */ false,
   1363        /* aBrowserId */ aBrowsingContext->BrowserId());
   1364    if (!constructorSender) {
   1365      return nullptr;
   1366    }
   1367  }
   1368 
   1369  aBrowsingContext->SetEmbedderElement(aFrameElement);
   1370 
   1371  // Ensure that the process which we're using to launch is set as the host
   1372  // process for this BrowsingContextGroup.
   1373  aBrowsingContext->Group()->EnsureHostProcess(constructorSender.get());
   1374 
   1375  nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
   1376  docShell->GetTreeOwner(getter_AddRefs(treeOwner));
   1377  if (!treeOwner) {
   1378    return nullptr;
   1379  }
   1380 
   1381  nsCOMPtr<nsIWebBrowserChrome> wbc = do_GetInterface(treeOwner);
   1382  if (!wbc) {
   1383    return nullptr;
   1384  }
   1385  uint32_t chromeFlags = 0;
   1386  wbc->GetChromeFlags(&chromeFlags);
   1387 
   1388  nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
   1389  if (loadContext && loadContext->UsePrivateBrowsing()) {
   1390    chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
   1391  }
   1392  if (loadContext && loadContext->UseRemoteTabs()) {
   1393    chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
   1394  }
   1395  if (loadContext && loadContext->UseRemoteSubframes()) {
   1396    chromeFlags |= nsIWebBrowserChrome::CHROME_FISSION_WINDOW;
   1397  }
   1398 
   1399  if (tabId == 0) {
   1400    return nullptr;
   1401  }
   1402 
   1403  aBrowsingContext->Canonical()->SetOwnerProcessId(
   1404      constructorSender->ChildID());
   1405 
   1406  RefPtr<BrowserParent> browserParent =
   1407      new BrowserParent(constructorSender.get(), tabId, aContext,
   1408                        aBrowsingContext->Canonical(), chromeFlags);
   1409 
   1410  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
   1411  if (NS_WARN_IF(!cpm)) {
   1412    return nullptr;
   1413  }
   1414  cpm->RegisterRemoteFrame(browserParent);
   1415 
   1416  // Open a remote endpoint for our PBrowser actor.
   1417  ManagedEndpoint<PBrowserChild> childEp =
   1418      constructorSender->OpenPBrowserEndpoint(browserParent);
   1419  if (NS_WARN_IF(!childEp.IsValid())) {
   1420    return nullptr;
   1421  }
   1422 
   1423  nsCOMPtr<nsIPrincipal> initialPrincipal =
   1424      NullPrincipal::Create(aBrowsingContext->OriginAttributesRef());
   1425  WindowGlobalInit windowInit = WindowGlobalActor::AboutBlankInitializer(
   1426      aBrowsingContext, initialPrincipal);
   1427 
   1428  RefPtr<WindowGlobalParent> windowParent =
   1429      WindowGlobalParent::CreateDisconnected(windowInit);
   1430  if (NS_WARN_IF(!windowParent)) {
   1431    return nullptr;
   1432  }
   1433 
   1434  // Open a remote endpoint for the initial PWindowGlobal actor.
   1435  ManagedEndpoint<PWindowGlobalChild> windowEp =
   1436      browserParent->OpenPWindowGlobalEndpoint(windowParent);
   1437  if (NS_WARN_IF(!windowEp.IsValid())) {
   1438    return nullptr;
   1439  }
   1440 
   1441  windowParent->Init();
   1442 
   1443  // Tell the content process to set up its PBrowserChild.
   1444  bool ok = constructorSender->SendConstructBrowser(
   1445      std::move(childEp), std::move(windowEp), tabId,
   1446      aContext.AsIPCTabContext(), windowInit, chromeFlags,
   1447      constructorSender->ChildID(), constructorSender->IsForBrowser(),
   1448      /* aIsTopLevel */ true);
   1449  if (NS_WARN_IF(!ok)) {
   1450    return nullptr;
   1451  }
   1452 
   1453  // Ensure that we're marked as the current BrowserParent on our
   1454  // CanonicalBrowsingContext.
   1455  aBrowsingContext->Canonical()->SetCurrentBrowserParent(browserParent);
   1456 
   1457  RefPtr<BrowserHost> browserHost = new BrowserHost(browserParent);
   1458  browserParent->SetOwnerElement(aFrameElement);
   1459  return browserHost.forget();
   1460 }
   1461 
   1462 void ContentParent::GetAll(nsTArray<ContentParent*>& aArray) {
   1463  aArray.Clear();
   1464 
   1465  for (auto* cp : AllProcesses(eLive)) {
   1466    aArray.AppendElement(cp);
   1467  }
   1468 }
   1469 
   1470 void ContentParent::GetAllEvenIfDead(nsTArray<ContentParent*>& aArray) {
   1471  aArray.Clear();
   1472 
   1473  for (auto* cp : AllProcesses(eAll)) {
   1474    aArray.AppendElement(cp);
   1475  }
   1476 }
   1477 
   1478 void ContentParent::BroadcastStringBundle(
   1479    const StringBundleDescriptor& aBundle) {
   1480  for (auto* cp : AllProcesses(eLive)) {
   1481    AutoTArray<StringBundleDescriptor, 1> array;
   1482    array.AppendElement(StringBundleDescriptor(aBundle.bundleURL(),
   1483                                               aBundle.mapHandle().Clone()));
   1484    (void)cp->SendRegisterStringBundles(std::move(array));
   1485  }
   1486 }
   1487 
   1488 void ContentParent::BroadcastShmBlockAdded(uint32_t aGeneration,
   1489                                           uint32_t aIndex) {
   1490  auto* pfl = gfxPlatformFontList::PlatformFontList();
   1491  for (auto* cp : AllProcesses(eLive)) {
   1492    ReadOnlySharedMemoryHandle handle =
   1493        pfl->ShareShmBlockToProcess(aIndex, cp->Pid());
   1494    if (!handle.IsValid()) {
   1495      // If something went wrong here, we just skip it; the child will need to
   1496      // request the block as needed, at some performance cost.
   1497      continue;
   1498    }
   1499    (void)cp->SendFontListShmBlockAdded(aGeneration, aIndex, std::move(handle));
   1500  }
   1501 }
   1502 
   1503 void ContentParent::BroadcastThemeUpdate(widget::ThemeChangeKind aKind) {
   1504  const FullLookAndFeel& lnf = *RemoteLookAndFeel::ExtractData();
   1505  for (auto* cp : AllProcesses(eLive)) {
   1506    (void)cp->SendThemeChanged(lnf, aKind);
   1507  }
   1508 }
   1509 
   1510 /*static */
   1511 void ContentParent::BroadcastMediaCodecsSupportedUpdate(
   1512    RemoteMediaIn aLocation, const media::MediaCodecsSupported& aSupported) {
   1513  // Update processes and print the support info from the given location.
   1514  sCodecsSupported[aLocation] = aSupported;
   1515  for (auto* cp : AllProcesses(eAll)) {
   1516    (void)cp->SendUpdateMediaCodecsSupported(aLocation, aSupported);
   1517  }
   1518  nsCString supportString;
   1519  media::MCSInfo::GetMediaCodecsSupportedString(supportString, aSupported);
   1520  LOGPDM("Broadcast support from '%s', support=%s",
   1521         RemoteMediaInToStr(aLocation), supportString.get());
   1522 
   1523  // Merge incoming support with existing support list from other locations
   1524  media::MCSInfo::AddSupport(aSupported);
   1525  auto fullSupport = media::MCSInfo::GetSupport();
   1526 
   1527  // Generate + save FULL support string for display in about:support
   1528  supportString.Truncate();
   1529  media::MCSInfo::GetMediaCodecsSupportedString(supportString, fullSupport);
   1530 
   1531  if (nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service()) {
   1532    gfxInfo->SetCodecSupportInfo(supportString);
   1533  }
   1534 }
   1535 
   1536 const nsACString& ContentParent::GetRemoteType() const { return mRemoteType; }
   1537 
   1538 static StaticRefPtr<nsIAsyncShutdownClient> sXPCOMShutdownClient;
   1539 static StaticRefPtr<nsIAsyncShutdownClient> sProfileBeforeChangeClient;
   1540 static StaticRefPtr<nsIAsyncShutdownClient> sAppShutdownConfirmedClient;
   1541 
   1542 void ContentParent::Init() {
   1543  MOZ_ASSERT(sXPCOMShutdownClient);
   1544 
   1545  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   1546  if (obs) {
   1547    size_t length = std::size(sObserverTopics);
   1548    for (size_t i = 0; i < length; ++i) {
   1549      obs->AddObserver(this, sObserverTopics[i], false);
   1550    }
   1551  }
   1552 
   1553  if (obs) {
   1554    nsAutoString cpId;
   1555    cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
   1556    obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-created",
   1557                         cpId.get());
   1558  }
   1559 
   1560 #ifdef ACCESSIBILITY
   1561  // If accessibility is running in chrome process then start it in content
   1562  // process.
   1563  if (GetAccService()) {
   1564    (void)SendActivateA11y(nsAccessibilityService::GetActiveCacheDomains());
   1565  }
   1566 #endif  // #ifdef ACCESSIBILITY
   1567 
   1568  (void)SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
   1569 
   1570  RefPtr<GeckoMediaPluginServiceParent> gmps(
   1571      GeckoMediaPluginServiceParent::GetSingleton());
   1572  if (gmps) {
   1573    gmps->UpdateContentProcessGMPCapabilities(this);
   1574  }
   1575 
   1576  // Flush any pref updates that happened during launch and weren't
   1577  // included in the blobs set up in BeginSubprocessLaunch.
   1578  for (const Pref& pref : mQueuedPrefs) {
   1579    (void)NS_WARN_IF(!SendPreferenceUpdate(pref));
   1580  }
   1581  mQueuedPrefs.Clear();
   1582 
   1583  (void)SendInitNextGenLocalStorageEnabled(NextGenLocalStorageEnabled());
   1584 
   1585  // sending only the remote settings schemes to the content process
   1586  nsCOMPtr<nsIIOService> io(do_GetIOService());
   1587  MOZ_ASSERT(io, "No IO service for SimpleURI scheme broadcast to content");
   1588  nsTArray<nsCString> remoteSchemes;
   1589  MOZ_ALWAYS_SUCCEEDS(io->GetSimpleURIUnknownRemoteSchemes(remoteSchemes));
   1590  (void)SendSimpleURIUnknownRemoteSchemes(std::move(remoteSchemes));
   1591 }
   1592 
   1593 void ContentParent::AsyncSendShutDownMessage() {
   1594  MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
   1595          ("AsyncSendShutDownMessage id=%p, childID=%" PRIu64, this,
   1596           (uint64_t)this->ChildID()));
   1597  MOZ_ASSERT(NS_IsMainThread());
   1598  MOZ_ASSERT(IsDead());
   1599  if (mShutdownPending || !CanSend()) {
   1600    // Don't bother dispatching a runnable if shutdown is already pending or the
   1601    // channel has already been disconnected, as it won't do anything.
   1602    // We could be very late in shutdown and unable to dispatch.
   1603    return;
   1604  }
   1605 
   1606  // In the case of normal shutdown, send a shutdown message to child to
   1607  // allow it to perform shutdown tasks.
   1608  GetCurrentSerialEventTarget()->Dispatch(NewRunnableMethod<ShutDownMethod>(
   1609      "dom::ContentParent::ShutDownProcess", this,
   1610      &ContentParent::ShutDownProcess, SEND_SHUTDOWN_MESSAGE));
   1611 }
   1612 
   1613 void MaybeLogBlockShutdownDiagnostics(ContentParent* aSelf, const char* aMsg,
   1614                                      const char* aFile, int32_t aLine) {
   1615 #if defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
   1616  if (aSelf->IsBlockingShutdown()) {
   1617    MOZ_LOG(
   1618        ContentParent::GetLog(), LogLevel::Info,
   1619        ("ContentParent: id=%p childID=%" PRIu64 " pid=%d - %s at %s(%d)",
   1620         aSelf, (uint64_t)aSelf->ChildID(), aSelf->Pid(), aMsg, aFile, aLine));
   1621  }
   1622 #else
   1623  (void)aSelf;
   1624  (void)aMsg;
   1625  (void)aFile;
   1626  (void)aLine;
   1627 #endif
   1628 }
   1629 
   1630 bool ContentParent::ShutDownProcess(ShutDownMethod aMethod) {
   1631  bool result = false;
   1632  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
   1633          ("ShutDownProcess: id=%p childID=%" PRIu64, this,
   1634           (uint64_t)this->ChildID()));
   1635  // NB: must MarkAsDead() here so that this isn't accidentally
   1636  // returned from Get*() while in the midst of shutdown.
   1637  MarkAsDead();
   1638 
   1639  // Shutting down by sending a shutdown message works differently than the
   1640  // other methods. We first call Shutdown() in the child. After the child is
   1641  // ready, it calls FinishShutdown() on us. Then we close the channel.
   1642  if (aMethod == SEND_SHUTDOWN_MESSAGE) {
   1643    if (!mShutdownPending) {
   1644      if (CanSend()) {
   1645        // Stop sending input events with input priority when shutting down.
   1646        SetInputPriorityEventEnabled(false);
   1647        // If we did not earlier, let's signal the shutdown to JS now.
   1648        SignalImpendingShutdownToContentJS();
   1649 
   1650        // Adjust the QoS priorities for shutdown, if they exist.
   1651        if (StaticPrefs::threads_use_low_power_enabled() &&
   1652            StaticPrefs::
   1653                threads_lower_mainthread_priority_in_background_enabled()) {
   1654          SetMainThreadQoSPriority(nsIThread::QOS_PRIORITY_NORMAL);
   1655        }
   1656 
   1657        // Send the shutdown message with normal priority.
   1658        if (SendShutdown()) {
   1659          MaybeLogBlockShutdownDiagnostics(
   1660              this, "ShutDownProcess: Sent shutdown message.", __FILE__,
   1661              __LINE__);
   1662          mShutdownPending = true;
   1663          // We start the kill timer only after we asked our process to
   1664          // shutdown.
   1665          StartForceKillTimer();
   1666          result = true;
   1667        } else {
   1668          MaybeLogBlockShutdownDiagnostics(
   1669              this, "ShutDownProcess: !!! Send shutdown message failed! !!!",
   1670              __FILE__, __LINE__);
   1671        }
   1672      } else {
   1673        MaybeLogBlockShutdownDiagnostics(
   1674            this, "ShutDownProcess: !!! !CanSend !!!", __FILE__, __LINE__);
   1675      }
   1676    } else {
   1677      MaybeLogBlockShutdownDiagnostics(
   1678          this, "ShutDownProcess: Shutdown already pending.", __FILE__,
   1679          __LINE__);
   1680 
   1681      result = true;
   1682    }
   1683    // If call was not successful, the channel must have been broken
   1684    // somehow, and we will clean up the error in ActorDestroy.
   1685    return result;
   1686  }
   1687 
   1688  using mozilla::dom::quota::QuotaManagerService;
   1689 
   1690  if (QuotaManagerService* qms = QuotaManagerService::GetOrCreate()) {
   1691    qms->AbortOperationsForProcess(mChildID);
   1692  }
   1693 
   1694  if (aMethod == CLOSE_CHANNEL) {
   1695    if (!mCalledClose) {
   1696      MaybeLogBlockShutdownDiagnostics(
   1697          this, "ShutDownProcess: Closing channel.", __FILE__, __LINE__);
   1698      // Close() can only be called once: It kicks off the destruction sequence.
   1699      mCalledClose = true;
   1700      Close();
   1701    }
   1702    result = true;
   1703  }
   1704 
   1705  // A ContentParent object might not get freed until after XPCOM shutdown has
   1706  // shut down the cycle collector.  But by then it's too late to release any
   1707  // CC'ed objects, so we need to null them out here, while we still can.  See
   1708  // bug 899761.
   1709  ShutDownMessageManager();
   1710  return result;
   1711 }
   1712 
   1713 mozilla::ipc::IPCResult ContentParent::RecvNotifyShutdownSuccess() {
   1714  if (!mShutdownPending) {
   1715    return IPC_FAIL(this, "RecvNotifyShutdownSuccess without mShutdownPending");
   1716  }
   1717 
   1718  mIsNotifiedShutdownSuccess = true;
   1719 
   1720  return IPC_OK();
   1721 }
   1722 
   1723 mozilla::ipc::IPCResult ContentParent::RecvFinishShutdown() {
   1724  if (!mShutdownPending) {
   1725    return IPC_FAIL(this, "RecvFinishShutdown without mShutdownPending");
   1726  }
   1727 
   1728  // At this point, we already called ShutDownProcess once with
   1729  // SEND_SHUTDOWN_MESSAGE. To actually close the channel, we call
   1730  // ShutDownProcess again with CLOSE_CHANNEL.
   1731  if (mCalledClose) {
   1732    MaybeLogBlockShutdownDiagnostics(
   1733        this, "RecvFinishShutdown: Channel already closed.", __FILE__,
   1734        __LINE__);
   1735  }
   1736 
   1737  ShutDownProcess(CLOSE_CHANNEL);
   1738  return IPC_OK();
   1739 }
   1740 
   1741 void ContentParent::ShutDownMessageManager() {
   1742  if (!mMessageManager) {
   1743    return;
   1744  }
   1745 
   1746  mMessageManager->SetOsPid(-1);
   1747  mMessageManager->Disconnect();
   1748  mMessageManager = nullptr;
   1749 }
   1750 
   1751 void ContentParent::AddToPool(nsTArray<ContentParent*>& aPool) {
   1752  MOZ_DIAGNOSTIC_ASSERT(!mIsInPool);
   1753  AssertAlive();
   1754  MOZ_DIAGNOSTIC_ASSERT(!mCalledKillHard);
   1755  aPool.AppendElement(this);
   1756  mIsInPool = true;
   1757 }
   1758 
   1759 void ContentParent::RemoveFromPool(nsTArray<ContentParent*>& aPool) {
   1760  MOZ_DIAGNOSTIC_ASSERT(mIsInPool);
   1761  aPool.RemoveElement(this);
   1762  mIsInPool = false;
   1763 }
   1764 
   1765 void ContentParent::AssertNotInPool() {
   1766  MOZ_RELEASE_ASSERT(!mIsInPool);
   1767 
   1768  MOZ_RELEASE_ASSERT(!sBrowserContentParents ||
   1769                     !sBrowserContentParents->Contains(mRemoteType) ||
   1770                     !sBrowserContentParents->Get(mRemoteType)->Contains(this));
   1771 
   1772  for (const auto& group : mGroups) {
   1773    MOZ_RELEASE_ASSERT(group->GetHostProcess(mRemoteType) != this,
   1774                       "still a host process for one of our groups?");
   1775  }
   1776 }
   1777 
   1778 void ContentParent::AssertAlive() {
   1779  MOZ_DIAGNOSTIC_ASSERT(!mIsSignaledImpendingShutdown);
   1780  MOZ_DIAGNOSTIC_ASSERT(!IsDead());
   1781 }
   1782 
   1783 void ContentParent::RemoveFromList() {
   1784  if (!mIsInPool) {
   1785 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   1786    AssertNotInPool();
   1787 #endif
   1788    return;
   1789  }
   1790 
   1791  // Ensure that this BrowsingContextGroup is no longer used to host new
   1792  // documents from any associated BrowsingContextGroups. It may become a host
   1793  // again in the future, if it is restored to the pool.
   1794  for (const auto& group : mGroups) {
   1795    group->RemoveHostProcess(this);
   1796  }
   1797 
   1798  if (sBrowserContentParents) {
   1799    if (auto entry = sBrowserContentParents->Lookup(mRemoteType)) {
   1800      const auto& contentParents = entry.Data();
   1801      RemoveFromPool(*contentParents);
   1802      if (contentParents->IsEmpty()) {
   1803        entry.Remove();
   1804      }
   1805    }
   1806    if (sBrowserContentParents->IsEmpty()) {
   1807      delete sBrowserContentParents;
   1808      sBrowserContentParents = nullptr;
   1809    }
   1810  }
   1811 }
   1812 
   1813 void ContentParent::MarkAsDead() {
   1814  MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
   1815          ("Marking ContentProcess id=%p childID=%" PRIu64 " as dead", this,
   1816           (uint64_t)this->ChildID()));
   1817  MOZ_DIAGNOSTIC_ASSERT(!sInProcessSelector);
   1818  RemoveFromList();
   1819 
   1820  // Flag shutdown has started for us to our threadsafe handle.
   1821  {
   1822    // Depending on how we get here, the lock might or might not be set.
   1823    RecursiveMutexAutoLock lock(mThreadsafeHandle->mMutex);
   1824 
   1825    mThreadsafeHandle->mShutdownStarted = true;
   1826  }
   1827 
   1828  // Prevent this process from being re-used.
   1829  PreallocatedProcessManager::Erase(this);
   1830 
   1831 #if defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_PROFILE_GENERATE)
   1832  if (IsAlive()) {
   1833    // We're intentionally killing the content process at this point to ensure
   1834    // that we never have a "dead" content process sitting around and occupying
   1835    // an Android Service.
   1836    //
   1837    // The exception is in MOZ_PROFILE_GENERATE builds where we must allow the
   1838    // process to shutdown cleanly so that profile data can be dumped. This is
   1839    // okay as we will not reach our process limit during the profile run.
   1840    nsCOMPtr<nsIEventTarget> launcherThread(GetIPCLauncher());
   1841    MOZ_ASSERT(launcherThread);
   1842 
   1843    auto procType = java::GeckoProcessType::CONTENT();
   1844    auto selector =
   1845        java::GeckoProcessManager::Selector::New(procType, OtherPid());
   1846 
   1847    launcherThread->Dispatch(NS_NewRunnableFunction(
   1848        "ContentParent::MarkAsDead",
   1849        [selector =
   1850             java::GeckoProcessManager::Selector::GlobalRef(selector)]() {
   1851          java::GeckoProcessManager::ShutdownProcess(selector);
   1852        }));
   1853  }
   1854 #endif
   1855 
   1856  mLifecycleState = LifecycleState::DEAD;
   1857 }
   1858 
   1859 void ContentParent::ProcessingError(Result aCode, const char* aReason) {
   1860  if (MsgDropped == aCode) {
   1861    return;
   1862  }
   1863  // Other errors are big deals.
   1864 #ifndef FUZZING
   1865  KillHard(aReason);
   1866 #endif
   1867  if (CanSend()) {
   1868    GetIPCChannel()->InduceConnectionError();
   1869  }
   1870 }
   1871 
   1872 void ContentParent::ActorDestroy(ActorDestroyReason why) {
   1873 #ifdef FUZZING_SNAPSHOT
   1874  MOZ_FUZZING_IPC_DROP_PEER("ContentParent::ActorDestroy");
   1875 #endif
   1876 
   1877  if (mSendShutdownTimer) {
   1878    mSendShutdownTimer->Cancel();
   1879    mSendShutdownTimer = nullptr;
   1880  }
   1881  if (mForceKillTimer) {
   1882    mForceKillTimer->Cancel();
   1883    mForceKillTimer = nullptr;
   1884  }
   1885 
   1886  // Signal shutdown completion regardless of error state, so we can
   1887  // finish waiting in the xpcom-shutdown/profile-before-change observer.
   1888  RemoveShutdownBlockers();
   1889 
   1890  if (mHangMonitorActor) {
   1891    ProcessHangMonitor::RemoveProcess(mHangMonitorActor);
   1892    mHangMonitorActor = nullptr;
   1893  }
   1894 
   1895  RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get();
   1896  if (fss) {
   1897    fss->Forget(ChildID());
   1898  }
   1899 
   1900  if (why == NormalShutdown && !mCalledClose) {
   1901    // If we shut down normally but haven't called Close, assume somebody
   1902    // else called Close on us. In that case, we still need to call
   1903    // ShutDownProcess below to perform other necessary clean up.
   1904    mCalledClose = true;
   1905  }
   1906 
   1907  // Make sure we always clean up.
   1908  ShutDownProcess(CLOSE_CHANNEL);
   1909 
   1910  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   1911  if (obs) {
   1912    size_t length = std::size(sObserverTopics);
   1913    for (size_t i = 0; i < length; ++i) {
   1914      obs->RemoveObserver(static_cast<nsIObserver*>(this), sObserverTopics[i]);
   1915    }
   1916  }
   1917 
   1918  // remove the global remote preferences observers
   1919  Preferences::RemoveObserver(this, "");
   1920  gfxVars::RemoveReceiver(this);
   1921 
   1922  if (GPUProcessManager* gpu = GPUProcessManager::Get()) {
   1923    // Note: the manager could have shutdown already.
   1924    gpu->RemoveListener(this);
   1925  }
   1926 
   1927  RecvRemoveGeolocationListener();
   1928 
   1929 #ifdef MOZ_WMF_CDM
   1930  if (mOriginsListCallback) {
   1931    nsCOMPtr<nsIWindowsMediaFoundationCDMOriginsListService> rsService =
   1932        do_GetService("@mozilla.org/media/wmfcdm-origins-list;1");
   1933    if (rsService) {
   1934      rsService->RemoveCallback(mOriginsListCallback);
   1935    }
   1936    mOriginsListCallback = nullptr;
   1937  }
   1938 #endif
   1939 
   1940  // Destroy our JSProcessActors, and reject any pending queries.
   1941  JSActorDidDestroy();
   1942 
   1943  if (obs) {
   1944    RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
   1945 
   1946    props->SetPropertyAsUint64(u"childID"_ns, mChildID);
   1947 
   1948    if (AbnormalShutdown == why) {
   1949      glean::subprocess::abnormal_abort.Get("content"_ns).Add(1);
   1950 
   1951      props->SetPropertyAsBool(u"abnormal"_ns, true);
   1952 
   1953      nsAutoString dumpID;
   1954      nsAutoCString processType;
   1955      // There's a window in which child processes can crash
   1956      // after IPC is established, but before a crash reporter
   1957      // is created.
   1958      if (mCrashReporter) {
   1959        // if mCreatedPairedMinidumps is true, we've already generated
   1960        // parent/child dumps for desktop crashes.
   1961        if (!mCreatedPairedMinidumps) {
   1962 #if defined(XP_MACOSX)
   1963          RefPtr<nsAvailableMemoryWatcherBase> memWatcher;
   1964          memWatcher = nsAvailableMemoryWatcherBase::GetSingleton();
   1965          memWatcher->AddChildAnnotations(mCrashReporter);
   1966 #endif
   1967 
   1968          mCrashReporter->GenerateCrashReport();
   1969        }
   1970 
   1971        if (mCrashReporter->HasMinidump()) {
   1972          dumpID = mCrashReporter->MinidumpID();
   1973        }
   1974        processType = mCrashReporter->ProcessType();
   1975      } else {
   1976        HandleOrphanedMinidump(&dumpID);
   1977        processType = XRE_GeckoProcessTypeToString(GeckoProcessType_Content);
   1978      }
   1979 
   1980      if (!dumpID.IsEmpty()) {
   1981        props->SetPropertyAsAString(u"dumpID"_ns, dumpID);
   1982      }
   1983      if (!processType.IsEmpty()) {
   1984        props->SetPropertyAsACString(u"processType"_ns, processType);
   1985      }
   1986    }
   1987    nsAutoString cpId;
   1988    cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
   1989    obs->NotifyObservers((nsIPropertyBag2*)props, "ipc:content-shutdown",
   1990                         cpId.get());
   1991  }
   1992 
   1993  // Remove any and all idle listeners.
   1994  if (mIdleListeners.Length() > 0) {
   1995    nsCOMPtr<nsIUserIdleService> idleService =
   1996        do_GetService("@mozilla.org/widget/useridleservice;1");
   1997    if (idleService) {
   1998      RefPtr<ParentIdleListener> listener;
   1999      for (const auto& lentry : mIdleListeners) {
   2000        listener = static_cast<ParentIdleListener*>(lentry.get());
   2001        idleService->RemoveIdleObserver(listener, listener->mTime);
   2002      }
   2003    }
   2004    mIdleListeners.Clear();
   2005  }
   2006 
   2007  MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
   2008          ("destroying Subprocess in ActorDestroy: ContentParent id=%p "
   2009           "mSubprocess id=%p handle %" PRIuPTR,
   2010           this, mSubprocess,
   2011           mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
   2012  // FIXME (bug 1520997): does this really need an additional dispatch?
   2013  if (GetCurrentSerialEventTarget()) {
   2014    GetCurrentSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
   2015        "DelayedDeleteSubprocessRunnable", [subprocess = mSubprocess] {
   2016          MOZ_LOG(
   2017              ContentParent::GetLog(), LogLevel::Debug,
   2018              ("destroyed Subprocess in ActorDestroy: Subprocess id=%p handle "
   2019               "%" PRIuPTR,
   2020               subprocess,
   2021               subprocess ? (uintptr_t)subprocess->GetChildProcessHandle()
   2022                          : -1));
   2023          subprocess->Destroy();
   2024        }));
   2025  }
   2026  mSubprocess = nullptr;
   2027 
   2028  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
   2029  if (cpm) {
   2030    cpm->RemoveContentProcess(this->ChildID());
   2031  }
   2032 
   2033  if (mDriverCrashGuard) {
   2034    mDriverCrashGuard->NotifyCrashed();
   2035  }
   2036 
   2037  // Unregister all the BlobURLs registered by the ContentChild.
   2038  BlobURLProtocolHandler::RemoveDataEntriesPerContentParent(ChildID());
   2039 
   2040 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   2041  AssertNotInPool();
   2042 #endif
   2043 
   2044  // As this process is going away, ensure that every BrowsingContext hosted by
   2045  // it has been detached, and every BrowsingContextGroup has been fully
   2046  // unsubscribed.
   2047  BrowsingContext::DiscardFromContentParent(this);
   2048 
   2049  const nsTHashSet<RefPtr<BrowsingContextGroup>> groups = std::move(mGroups);
   2050  for (const auto& group : groups) {
   2051    group->Unsubscribe(this);
   2052  }
   2053  MOZ_DIAGNOSTIC_ASSERT(mGroups.IsEmpty());
   2054 
   2055  mPendingLoadStates.Clear();
   2056 }
   2057 
   2058 UniqueContentParentKeepAlive ContentParent::TryAddKeepAlive(
   2059    uint64_t aBrowserId) {
   2060  UniqueContentParentKeepAlive keepAlive =
   2061      UniqueContentParentKeepAliveFromThreadsafe(
   2062          mThreadsafeHandle->TryAddKeepAlive(aBrowserId));
   2063  // If we successfully added a KeepAlive, we can cancel any pending
   2064  // MaybeBeginShutDown call (as it will no longer begin process shutdown due to
   2065  // outstanding KeepAlives).
   2066  // This is just an optimization and the MaybeBeginShutDown call will be a
   2067  // no-op if it is called with the KeepAlive held.
   2068  if (keepAlive && mMaybeBeginShutdownRunner) {
   2069    mMaybeBeginShutdownRunner->Cancel();
   2070    mMaybeBeginShutdownRunner = nullptr;
   2071  }
   2072  return keepAlive;
   2073 }
   2074 
   2075 UniqueContentParentKeepAlive ContentParent::AddKeepAlive(uint64_t aBrowserId) {
   2076  UniqueContentParentKeepAlive keepAlive = TryAddKeepAlive(aBrowserId);
   2077  MOZ_DIAGNOSTIC_ASSERT(keepAlive, "ContentParent is already dead");
   2078  return keepAlive;
   2079 }
   2080 
   2081 void ContentParent::RemoveKeepAlive(uint64_t aBrowserId) {
   2082  AssertIsOnMainThread();
   2083 
   2084  {
   2085    RecursiveMutexAutoLock lock(mThreadsafeHandle->mMutex);
   2086    auto entry = mThreadsafeHandle->mKeepAlivesPerBrowserId.Lookup(aBrowserId);
   2087    MOZ_RELEASE_ASSERT(entry, "No KeepAlive for this BrowserId");
   2088    if (!--entry.Data()) {
   2089      entry.Remove();
   2090    }
   2091  }
   2092 
   2093  MaybeBeginShutDown();
   2094 }
   2095 
   2096 void ContentParent::MaybeBeginShutDown(bool aImmediate,
   2097                                       bool aIgnoreKeepAlivePref) {
   2098  AssertIsOnMainThread();
   2099  MOZ_ASSERT(!aIgnoreKeepAlivePref || aImmediate,
   2100             "aIgnoreKeepAlivePref requires aImmediate");
   2101 
   2102  // Don't bother waiting, even if `aImmediate` is not true, if the process
   2103  // can no longer be re-used (e.g. because it is dead, or we're in shutdown).
   2104  bool immediate =
   2105      aImmediate || IsDead() ||
   2106      AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed) ||
   2107      StaticPrefs::dom_ipc_processReuse_unusedGraceMs() == 0;
   2108 
   2109  // Clean up any scheduled idle task unless we schedule a new one.
   2110  auto cancelIdleTask = MakeScopeExit([&] {
   2111    if (mMaybeBeginShutdownRunner) {
   2112      mMaybeBeginShutdownRunner->Cancel();
   2113      mMaybeBeginShutdownRunner = nullptr;
   2114    }
   2115  });
   2116 
   2117  {
   2118    RecursiveMutexAutoLock lock(mThreadsafeHandle->mMutex);
   2119    // If we still have keepalives or are still launching, we're not shutting
   2120    // down. Return.
   2121    if (IsLaunching() ||
   2122        !mThreadsafeHandle->mKeepAlivesPerBrowserId.IsEmpty()) {
   2123      return;
   2124    }
   2125 
   2126    // If we're not in main process shutdown, we might want to keep some content
   2127    // processes alive for performance reasons (e.g. test runs and privileged
   2128    // content process for some about: pages). We don't want to alter behavior
   2129    // if the pref is not set, so default to 0.
   2130    if (!aIgnoreKeepAlivePref && mIsInPool && !mRemoteType.Contains('=') &&
   2131        !AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
   2132      auto* contentParents = sBrowserContentParents->Get(mRemoteType);
   2133      MOZ_RELEASE_ASSERT(
   2134          contentParents,
   2135          "mIsInPool, yet no entry for mRemoteType in sBrowserContentParents?");
   2136 
   2137      nsAutoCString keepAlivePref("dom.ipc.keepProcessesAlive.");
   2138      keepAlivePref.Append(mRemoteType);
   2139 
   2140      int32_t processesToKeepAlive = 0;
   2141      if (NS_SUCCEEDED(Preferences::GetInt(keepAlivePref.get(),
   2142                                           &processesToKeepAlive)) &&
   2143          contentParents->Length() <=
   2144              static_cast<size_t>(processesToKeepAlive)) {
   2145        // We're keeping this process alive even though there are no keepalives
   2146        // for it due to the keepalive pref.
   2147        return;
   2148      }
   2149    }
   2150 
   2151    if (immediate) {
   2152      // We're not keeping this process alive, begin shutdown.
   2153      mThreadsafeHandle->mShutdownStarted = true;
   2154    }
   2155  }
   2156 
   2157  // If we're not beginning shutdown immediately, make sure an idle task runner
   2158  // is scheduled to call us back. This delay is intended to avoid unnecessary
   2159  // process churn when a process becomes momentarily unused (which can happen
   2160  // frequently when running tests).
   2161  if (!immediate) {
   2162    // We want an idle task to call us back, don't cancel it.
   2163    cancelIdleTask.release();
   2164 
   2165    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
   2166            ("MaybeBeginShutDown(%d) would begin shutdown, %s", OtherChildID(),
   2167             mMaybeBeginShutdownRunner ? "already delayed" : "delaying"));
   2168 
   2169    if (!mMaybeBeginShutdownRunner) {
   2170      TimeDuration startDelay = TimeDuration::FromMilliseconds(
   2171          StaticPrefs::dom_ipc_processReuse_unusedGraceMs());
   2172      TimeDuration maxDelay = startDelay + TimeDuration::FromSeconds(1);
   2173      mMaybeBeginShutdownRunner = IdleTaskRunner::Create(
   2174          [self = RefPtr{this}](TimeStamp) -> bool {
   2175            MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
   2176                    ("MaybeBeginShutDown(%d) resuming after delay",
   2177                     self->OtherChildID()));
   2178            self->MaybeBeginShutDown(/* aImmediate */ true);
   2179            return true;
   2180          },
   2181          "ContentParent::IdleMaybeBeginShutdown"_ns, startDelay, maxDelay,
   2182          /* aMinimumUsefulBudget */ TimeDuration::FromMilliseconds(3),
   2183          /* aRepeating */ false, [] { return false; });
   2184    }
   2185    return;
   2186  }
   2187 
   2188  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
   2189          ("MaybeBeginShutDown(%d) shutdown starting (%u bps)", OtherChildID(),
   2190           ManagedPBrowserParent().Count()));
   2191 
   2192  MarkAsDead();
   2193  SignalImpendingShutdownToContentJS();
   2194 
   2195  if (ManagedPBrowserParent().Count() > 0) {
   2196    // We still have PBrowser instances which have not been shut down.
   2197    // Wait for them to be destroyed before we follow-through and shut down this
   2198    // process, but start a shutdown timer to kill them if this takes too long.
   2199    StartSendShutdownTimer();
   2200  } else {
   2201    // All tabs are dead, we can fully begin shutting down.
   2202    AsyncSendShutDownMessage();
   2203  }
   2204 }
   2205 
   2206 void ContentParent::StartSendShutdownTimer() {
   2207  if (mSendShutdownTimer || !CanSend()) {
   2208    return;
   2209  }
   2210 
   2211  uint32_t timeoutSecs = StaticPrefs::dom_ipc_tabs_shutdownTimeoutSecs();
   2212  if (timeoutSecs > 0) {
   2213    NS_NewTimerWithFuncCallback(
   2214        getter_AddRefs(mSendShutdownTimer),
   2215        ContentParent::SendShutdownTimerCallback, this, timeoutSecs * 1000,
   2216        nsITimer::TYPE_ONE_SHOT,
   2217        "dom::ContentParent::StartSendShutdownTimer"_ns);
   2218    MOZ_ASSERT(mSendShutdownTimer);
   2219  }
   2220 }
   2221 
   2222 void ContentParent::StartForceKillTimer() {
   2223  if (mForceKillTimer || !CanSend()) {
   2224    return;
   2225  }
   2226 
   2227  uint32_t timeoutSecs = StaticPrefs::dom_ipc_tabs_shutdownTimeoutSecs();
   2228  if (timeoutSecs > 0) {
   2229    NS_NewTimerWithFuncCallback(getter_AddRefs(mForceKillTimer),
   2230                                ContentParent::ForceKillTimerCallback, this,
   2231                                timeoutSecs * 1000, nsITimer::TYPE_ONE_SHOT,
   2232                                "dom::ContentParent::StartForceKillTimer"_ns);
   2233    MOZ_ASSERT(mForceKillTimer);
   2234  }
   2235 }
   2236 
   2237 TestShellParent* ContentParent::CreateTestShell() {
   2238  RefPtr<TestShellParent> actor = new TestShellParent();
   2239  if (!SendPTestShellConstructor(actor)) {
   2240    return nullptr;
   2241  }
   2242  return actor;
   2243 }
   2244 
   2245 bool ContentParent::DestroyTestShell(TestShellParent* aTestShell) {
   2246  return PTestShellParent::Send__delete__(aTestShell);
   2247 }
   2248 
   2249 TestShellParent* ContentParent::GetTestShellSingleton() {
   2250  PTestShellParent* p = LoneManagedOrNullAsserts(ManagedPTestShellParent());
   2251  return static_cast<TestShellParent*>(p);
   2252 }
   2253 
   2254 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
   2255 // Append the sandbox command line parameters that are not static. i.e.,
   2256 // parameters that can be different for different child processes.
   2257 void ContentParent::AppendDynamicSandboxParams(
   2258    std::vector<std::string>& aArgs) {
   2259  // For file content processes
   2260  if (GetRemoteType() == FILE_REMOTE_TYPE) {
   2261    MacSandboxInfo::AppendFileAccessParam(aArgs, true);
   2262  }
   2263 }
   2264 
   2265 // Generate the static sandbox command line parameters and store
   2266 // them in the provided params vector to be used each time a new
   2267 // content process is launched.
   2268 static void CacheSandboxParams(std::vector<std::string>& aCachedParams) {
   2269  // This must only be called once and we should
   2270  // be starting with an empty list of parameters.
   2271  MOZ_ASSERT(aCachedParams.empty());
   2272 
   2273  MacSandboxInfo info;
   2274  info.type = MacSandboxType_Content;
   2275  info.level = GetEffectiveContentSandboxLevel();
   2276 
   2277  // Sandbox logging
   2278  if (Preferences::GetBool("security.sandbox.logging.enabled") ||
   2279      PR_GetEnv("MOZ_SANDBOX_LOGGING")) {
   2280    info.shouldLog = true;
   2281  }
   2282 
   2283  // Audio access
   2284  if (!StaticPrefs::media_cubeb_sandbox()) {
   2285    info.hasAudio = true;
   2286  }
   2287 
   2288  // Window server access. If the disconnect-windowserver pref is not
   2289  // "true" or out-of-process WebGL is not enabled, allow window server
   2290  // access in the sandbox policy.
   2291  if (!Preferences::GetBool(
   2292          "security.sandbox.content.mac.disconnect-windowserver") ||
   2293      !Preferences::GetBool("webgl.out-of-process")) {
   2294    info.hasWindowServer = true;
   2295  }
   2296 
   2297  // .app path (normalized)
   2298  nsAutoCString appPath;
   2299  if (!nsMacUtilsImpl::GetAppPath(appPath)) {
   2300    MOZ_CRASH("Failed to get app dir paths");
   2301  }
   2302  info.appPath = appPath.get();
   2303 
   2304  // TESTING_READ_PATH1
   2305  nsAutoCString testingReadPath1;
   2306  Preferences::GetCString("security.sandbox.content.mac.testing_read_path1",
   2307                          testingReadPath1);
   2308  if (!testingReadPath1.IsEmpty()) {
   2309    info.testingReadPath1 = testingReadPath1.get();
   2310  }
   2311 
   2312  // TESTING_READ_PATH2
   2313  nsAutoCString testingReadPath2;
   2314  Preferences::GetCString("security.sandbox.content.mac.testing_read_path2",
   2315                          testingReadPath2);
   2316  if (!testingReadPath2.IsEmpty()) {
   2317    info.testingReadPath2 = testingReadPath2.get();
   2318  }
   2319 
   2320  // TESTING_READ_PATH3, TESTING_READ_PATH4. In non-packaged builds,
   2321  // these are used to whitelist the repo dir and object dir respectively.
   2322  nsresult rv;
   2323  if (!mozilla::IsPackagedBuild()) {
   2324    // Repo dir
   2325    nsCOMPtr<nsIFile> repoDir;
   2326    rv = nsMacUtilsImpl::GetRepoDir(getter_AddRefs(repoDir));
   2327    if (NS_FAILED(rv)) {
   2328      MOZ_CRASH("Failed to get path to repo dir");
   2329    }
   2330    nsCString repoDirPath;
   2331    (void)repoDir->GetNativePath(repoDirPath);
   2332    info.testingReadPath3 = repoDirPath.get();
   2333 
   2334    // Object dir
   2335    nsCOMPtr<nsIFile> objDir;
   2336    rv = nsMacUtilsImpl::GetObjDir(getter_AddRefs(objDir));
   2337    if (NS_FAILED(rv)) {
   2338      MOZ_CRASH("Failed to get path to build object dir");
   2339    }
   2340    nsCString objDirPath;
   2341    (void)objDir->GetNativePath(objDirPath);
   2342    info.testingReadPath4 = objDirPath.get();
   2343  }
   2344 
   2345  // DEBUG_WRITE_DIR
   2346 #  ifdef DEBUG
   2347  // For bloat/leak logging or when a content process dies intentionally
   2348  // (|NoteIntentionalCrash|) for tests, it wants to log that it did this.
   2349  // Allow writing to this location.
   2350  nsAutoCString bloatLogDirPath;
   2351  if (NS_SUCCEEDED(nsMacUtilsImpl::GetBloatLogDir(bloatLogDirPath))) {
   2352    info.debugWriteDir = bloatLogDirPath.get();
   2353  }
   2354 #  endif  // DEBUG
   2355 
   2356  info.AppendAsParams(aCachedParams);
   2357 }
   2358 
   2359 // Append sandboxing command line parameters.
   2360 void ContentParent::AppendSandboxParams(std::vector<std::string>& aArgs) {
   2361  MOZ_ASSERT(sMacSandboxParams != nullptr);
   2362 
   2363  // An empty sMacSandboxParams indicates this is the
   2364  // first invocation and we don't have cached params yet.
   2365  if (sMacSandboxParams->empty()) {
   2366    CacheSandboxParams(*sMacSandboxParams);
   2367    MOZ_ASSERT(!sMacSandboxParams->empty());
   2368  }
   2369 
   2370  // Append cached arguments.
   2371  aArgs.insert(aArgs.end(), sMacSandboxParams->begin(),
   2372               sMacSandboxParams->end());
   2373 
   2374  // Append remaining arguments.
   2375  AppendDynamicSandboxParams(aArgs);
   2376 }
   2377 #endif  // XP_MACOSX && MOZ_SANDBOX
   2378 
   2379 bool ContentParent::BeginSubprocessLaunch(ProcessPriority aPriority) {
   2380  AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess", OTHER);
   2381 
   2382  // Ensure we will not rush through our shutdown phases while launching.
   2383  // LaunchSubprocessReject will remove them in case of failure,
   2384  // otherwise ActorDestroy will take care.
   2385  AddShutdownBlockers();
   2386 
   2387  if (!ContentProcessManager::GetSingleton()) {
   2388    MOZ_ASSERT(false, "Unable to acquire ContentProcessManager singleton!");
   2389    return false;
   2390  }
   2391 
   2392  geckoargs::ChildProcessArgs extraArgs;
   2393  geckoargs::sIsForBrowser.Put(IsForBrowser(), extraArgs);
   2394  geckoargs::sNotForBrowser.Put(!IsForBrowser(), extraArgs);
   2395 
   2396  // Prefs information is passed via anonymous shared memory to avoid bloating
   2397  // the command line.
   2398 
   2399  // Instantiate the pref serializer. It will be cleaned up in
   2400  // `LaunchSubprocessReject`/`LaunchSubprocessResolve`.
   2401  mPrefSerializer = MakeUnique<mozilla::ipc::SharedPreferenceSerializer>();
   2402  if (!mPrefSerializer->SerializeToSharedMemory(GeckoProcessType_Content,
   2403                                                GetRemoteType())) {
   2404    NS_WARNING("SharedPreferenceSerializer::SerializeToSharedMemory failed");
   2405    MarkAsDead();
   2406    return false;
   2407  }
   2408  mPrefSerializer->AddSharedPrefCmdLineArgs(*mSubprocess, extraArgs);
   2409 
   2410  // The JS engine does some computation during the initialization which can be
   2411  // shared across processes. We add command line arguments to pass a file
   2412  // handle and its content length, to minimize the startup time of content
   2413  // processes.
   2414  if (xpc::SelfHostedShmem::SelfHostedUseSharedMemory()) {
   2415    ::mozilla::ipc::ExportSharedJSInit(*mSubprocess, extraArgs);
   2416  }
   2417 
   2418  // Register ContentParent as an observer for changes to any pref
   2419  // whose prefix matches the empty string, i.e. all of them.  The
   2420  // observation starts here in order to capture pref updates that
   2421  // happen during async launch.
   2422  Preferences::AddStrongObserver(this, "");
   2423 
   2424  geckoargs::sSafeMode.Put(gSafeMode, extraArgs);
   2425 
   2426 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
   2427  if (IsContentSandboxEnabled()) {
   2428    AppendSandboxParams(extraArgs.mArgs);
   2429    mSubprocess->DisableOSActivityMode();
   2430  }
   2431 #endif
   2432 
   2433  nsCString parentBuildID(mozilla::PlatformBuildID());
   2434  geckoargs::sParentBuildID.Put(parentBuildID.get(), extraArgs);
   2435 
   2436 #ifdef MOZ_WIDGET_GTK
   2437  // This is X11-only pending a solution for WebGL in Wayland mode.
   2438  if (StaticPrefs::dom_ipc_avoid_gtk() && widget::GdkIsX11Display()) {
   2439    mSubprocess->SetEnv("MOZ_HEADLESS", "1");
   2440  }
   2441 #endif
   2442 
   2443  mLaunchYieldTS = TimeStamp::Now();
   2444  return mSubprocess->AsyncLaunch(std::move(extraArgs));
   2445 }
   2446 
   2447 void ContentParent::LaunchSubprocessReject() {
   2448  NS_WARNING("failed to launch child in the parent");
   2449  MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
   2450          ("failed to launch child in the parent"));
   2451  // Now that communication with the child is complete, we can cleanup
   2452  // the preference serializer.
   2453  mPrefSerializer = nullptr;
   2454  if (mIsAPreallocBlocker) {
   2455    PreallocatedProcessManager::RemoveBlocker(mRemoteType, this);
   2456    mIsAPreallocBlocker = false;
   2457  }
   2458  MarkAsDead();
   2459  RemoveShutdownBlockers();
   2460 }
   2461 
   2462 bool ContentParent::LaunchSubprocessResolve(bool aIsSync,
   2463                                            ProcessPriority aPriority) {
   2464  AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess::resolve", OTHER);
   2465 
   2466  if (mLaunchResolved) {
   2467    // We've already been called, return.
   2468    MOZ_ASSERT(sCreatedFirstContentProcess);
   2469    MOZ_ASSERT(!mPrefSerializer);
   2470    MOZ_ASSERT(mLifecycleState != LifecycleState::LAUNCHING);
   2471    return mLaunchResolvedOk;
   2472  }
   2473  mLaunchResolved = true;
   2474 
   2475  // Now that communication with the child is complete, we can cleanup
   2476  // the preference serializer.
   2477  mPrefSerializer = nullptr;
   2478 
   2479  const auto launchResumeTS = TimeStamp::Now();
   2480  if (profiler_thread_is_being_profiled_for_markers()) {
   2481    nsPrintfCString marker("Process start%s for %u",
   2482                           mIsAPreallocBlocker ? " (immediate)" : "",
   2483                           (unsigned int)ChildID());
   2484    PROFILER_MARKER_TEXT(
   2485        mIsAPreallocBlocker ? ProfilerString8View("Process Immediate Launch")
   2486                            : ProfilerString8View("Process Launch"),
   2487        DOM, MarkerTiming::Interval(mLaunchTS, launchResumeTS), marker);
   2488  }
   2489 
   2490  if (!sCreatedFirstContentProcess) {
   2491    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   2492    obs->NotifyObservers(nullptr, "ipc:first-content-process-created", nullptr);
   2493    sCreatedFirstContentProcess = true;
   2494  }
   2495 
   2496  mSubprocess->TakeInitialEndpoint().Bind(this);
   2497 
   2498  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
   2499  if (!cpm) {
   2500    NS_WARNING("immediately shutting-down caused by our shutdown");
   2501    ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
   2502    return false;
   2503  }
   2504  cpm->AddContentProcess(this);
   2505 
   2506 #ifdef MOZ_CODE_COVERAGE
   2507  (void)SendShareCodeCoverageMutex(
   2508      CodeCoverageHandler::Get()->GetMutexHandle());
   2509 #endif
   2510 
   2511  // We must be in the LAUNCHING state still. If we've somehow already been
   2512  // marked as DEAD, fail the process launch, and immediately begin tearing down
   2513  // the content process.
   2514  if (IsDead()) {
   2515    NS_WARNING("immediately shutting-down already-dead process");
   2516    ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
   2517    return false;
   2518  }
   2519  MOZ_ASSERT(mLifecycleState == LifecycleState::LAUNCHING);
   2520  mLifecycleState = LifecycleState::ALIVE;
   2521 
   2522  if (!InitInternal(aPriority)) {
   2523    NS_WARNING("failed to initialize child in the parent");
   2524    // We've already called Open() by this point, so we need to close the
   2525    // channel to avoid leaking the process.
   2526    ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
   2527    return false;
   2528  }
   2529 
   2530  mHangMonitorActor = ProcessHangMonitor::AddProcess(this);
   2531 
   2532  // Set a reply timeout for CPOWs.
   2533  SetReplyTimeoutMs(StaticPrefs::dom_ipc_cpow_timeout());
   2534 
   2535  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   2536  if (obs) {
   2537    nsAutoString cpId;
   2538    cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
   2539    obs->NotifyObservers(static_cast<nsIObserver*>(this),
   2540                         "ipc:content-initializing", cpId.get());
   2541  }
   2542 
   2543  Init();
   2544 
   2545  mLifecycleState = LifecycleState::INITIALIZED;
   2546 
   2547  if (aIsSync) {
   2548    glean::dom_contentprocess::sync_launch.AccumulateRawDuration(
   2549        TimeStamp::Now() - mLaunchTS);
   2550  } else {
   2551    glean::dom_contentprocess::launch_total.AccumulateRawDuration(
   2552        TimeStamp::Now() - mLaunchTS);
   2553 
   2554    glean::dom_contentprocess::launch_mainthread.AccumulateRawDuration(
   2555        (mLaunchYieldTS - mLaunchTS) + (TimeStamp::Now() - launchResumeTS));
   2556  }
   2557 
   2558  mLaunchResolvedOk = true;
   2559  return true;
   2560 }
   2561 
   2562 static bool IsFileContent(const nsACString& aRemoteType) {
   2563  return aRemoteType == FILE_REMOTE_TYPE;
   2564 }
   2565 
   2566 ContentParent::ContentParent(const nsACString& aRemoteType)
   2567    : mSubprocess(new GeckoChildProcessHost(GeckoProcessType_Content,
   2568                                            IsFileContent(aRemoteType))),
   2569      mLaunchTS(TimeStamp::Now()),
   2570      mLaunchYieldTS(mLaunchTS),
   2571      mIsAPreallocBlocker(false),
   2572      mRemoteType(aRemoteType),
   2573      mChildID(mSubprocess->GetChildID()),
   2574      mGeolocationWatchID(-1),
   2575      mThreadsafeHandle(
   2576          new ThreadsafeContentParentHandle(this, mChildID, mRemoteType)),
   2577      mLifecycleState(LifecycleState::LAUNCHING),
   2578      mIsForBrowser(!mRemoteType.IsEmpty()),
   2579      mCalledClose(false),
   2580      mCalledKillHard(false),
   2581      mCreatedPairedMinidumps(false),
   2582      mShutdownPending(false),
   2583      mLaunchResolved(false),
   2584      mLaunchResolvedOk(false),
   2585      mIsRemoteInputEventQueueEnabled(false),
   2586      mIsInputPriorityEventEnabled(false),
   2587      mIsInPool(false),
   2588      mGMPCreated(false),
   2589      mClipboardContentAnalysisCreated(false),
   2590 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   2591      mBlockShutdownCalled(false),
   2592 #endif
   2593      mHangMonitorActor(nullptr) {
   2594  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   2595 
   2596  mRemoteTypeIsolationPrincipal =
   2597      CreateRemoteTypeIsolationPrincipal(aRemoteType);
   2598 
   2599  // Insert ourselves into the global linked list of ContentParent objects.
   2600  if (!sContentParents) {
   2601    sContentParents = new LinkedList<ContentParent>();
   2602  }
   2603  sContentParents->insertBack(this);
   2604 
   2605  mMessageManager = nsFrameMessageManager::NewProcessMessageManager(true);
   2606 
   2607 #if defined(XP_WIN)
   2608  // Request Windows message deferral behavior on our side of the PContent
   2609  // channel. Generally only applies to the situation where we get caught in
   2610  // a deadlock with the plugin process when sending CPOWs.
   2611  GetIPCChannel()->SetChannelFlags(
   2612      MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
   2613 #endif
   2614 
   2615  MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
   2616          ("CreateSubprocess: ContentParent id=%p mSubprocess id=%p childID=%d",
   2617           this, mSubprocess, mSubprocess->GetChildID()));
   2618 }
   2619 
   2620 ContentParent::~ContentParent() {
   2621  if (mSendShutdownTimer) {
   2622    mSendShutdownTimer->Cancel();
   2623  }
   2624  if (mForceKillTimer) {
   2625    mForceKillTimer->Cancel();
   2626  }
   2627 
   2628  AssertIsOnMainThread();
   2629 
   2630  // Clear the weak reference from the threadsafe handle back to this actor.
   2631  mThreadsafeHandle->mWeakActor = nullptr;
   2632 
   2633  if (mIsAPreallocBlocker) {
   2634    MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
   2635            ("Removing blocker on ContentProcess id=%p childID=%" PRIu64
   2636             " destruction",
   2637             this, (uint64_t)this->ChildID()));
   2638    PreallocatedProcessManager::RemoveBlocker(mRemoteType, this);
   2639    mIsAPreallocBlocker = false;
   2640  }
   2641 
   2642  // We should be removed from all these lists in ActorDestroy.
   2643  AssertNotInPool();
   2644 
   2645  // Normally mSubprocess is destroyed in ActorDestroy, but that won't
   2646  // happen if the process wasn't launched or if it failed to launch.
   2647  if (mSubprocess) {
   2648    MOZ_LOG(
   2649        ContentParent::GetLog(), LogLevel::Verbose,
   2650        ("DestroySubprocess: ContentParent id=%p childID=%" PRIu64
   2651         " mSubprocess id=%p handle "
   2652         "%" PRIuPTR,
   2653         this, (uint64_t)this->ChildID(), mSubprocess,
   2654         mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
   2655    mSubprocess->Destroy();
   2656  }
   2657 }
   2658 
   2659 bool ContentParent::InitInternal(ProcessPriority aInitialPriority) {
   2660  // We can't access the locale service after shutdown has started. Since we
   2661  // can't init the process without it, and since we're going to be canceling
   2662  // whatever load attempt that initiated this process creation anyway, just
   2663  // bail out now if shutdown has already started.
   2664  if (PastShutdownPhase(ShutdownPhase::XPCOMShutdown)) {
   2665    return false;
   2666  }
   2667 
   2668  XPCOMInitData xpcomInit;
   2669 
   2670  MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
   2671          ("ContentParent::InitInternal: id=%p, childID=%" PRIu64, (void*)this,
   2672           (uint64_t)this->ChildID()));
   2673  nsCOMPtr<nsIIOService> io(do_GetIOService());
   2674  MOZ_ASSERT(io, "No IO service?");
   2675  DebugOnly<nsresult> rv = io->GetOffline(&xpcomInit.isOffline());
   2676  MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting offline?");
   2677 
   2678  rv = io->GetConnectivity(&xpcomInit.isConnected());
   2679  MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting connectivity?");
   2680 
   2681  xpcomInit.captivePortalState() = nsICaptivePortalService::UNKNOWN;
   2682  nsCOMPtr<nsICaptivePortalService> cps =
   2683      do_GetService(NS_CAPTIVEPORTAL_CONTRACTID);
   2684  if (cps) {
   2685    cps->GetState(&xpcomInit.captivePortalState());
   2686  }
   2687 
   2688  if (StaticPrefs::fission_processProfileName()) {
   2689    nsCOMPtr<nsIToolkitProfileService> profileSvc =
   2690        do_GetService(NS_PROFILESERVICE_CONTRACTID);
   2691    if (profileSvc) {
   2692      nsCOMPtr<nsIToolkitProfile> currentProfile;
   2693      nsresult rv =
   2694          profileSvc->GetCurrentProfile(getter_AddRefs(currentProfile));
   2695      if (NS_SUCCEEDED(rv) && currentProfile) {
   2696        currentProfile->GetName(mProfile);
   2697      }
   2698    }
   2699  }
   2700 
   2701  nsIBidiKeyboard* bidi = nsContentUtils::GetBidiKeyboard();
   2702 
   2703  xpcomInit.isLangRTL() = false;
   2704  xpcomInit.haveBidiKeyboards() = false;
   2705  if (bidi) {
   2706    bidi->IsLangRTL(&xpcomInit.isLangRTL());
   2707    bidi->GetHaveBidiKeyboards(&xpcomInit.haveBidiKeyboards());
   2708  }
   2709 
   2710  RefPtr<mozSpellChecker> spellChecker(mozSpellChecker::Create());
   2711  MOZ_ASSERT(spellChecker, "No spell checker?");
   2712 
   2713  spellChecker->GetDictionaryList(&xpcomInit.dictionaries());
   2714 
   2715  OSPreferences::GetInstance()->GetSystemLocales(xpcomInit.sysLocales());
   2716 
   2717  LocaleService::GetInstance()->GetAppLocalesAsBCP47(xpcomInit.appLocales());
   2718  LocaleService::GetInstance()->GetRequestedLocales(
   2719      xpcomInit.requestedLocales());
   2720 
   2721  L10nRegistry::GetParentProcessFileSourceDescriptors(
   2722      xpcomInit.l10nFileSources());
   2723 
   2724  nsCOMPtr<nsIClipboard> clipboard(
   2725      do_GetService("@mozilla.org/widget/clipboard;1"));
   2726  MOZ_ASSERT(clipboard, "No clipboard?");
   2727  MOZ_ASSERT(
   2728      clipboard->IsClipboardTypeSupported(nsIClipboard::kGlobalClipboard),
   2729      "We should always support the global clipboard.");
   2730 
   2731  xpcomInit.clipboardCaps().supportsSelectionClipboard() =
   2732      clipboard->IsClipboardTypeSupported(nsIClipboard::kSelectionClipboard);
   2733 
   2734  xpcomInit.clipboardCaps().supportsFindClipboard() =
   2735      clipboard->IsClipboardTypeSupported(nsIClipboard::kFindClipboard);
   2736 
   2737  xpcomInit.clipboardCaps().supportsSelectionCache() =
   2738      clipboard->IsClipboardTypeSupported(nsIClipboard::kSelectionCache);
   2739 
   2740  // Let's copy the domain policy from the parent to the child (if it's active).
   2741  auto initialData = MakeUnique<StructuredCloneData>();
   2742  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   2743  if (ssm) {
   2744    ssm->CloneDomainPolicy(&xpcomInit.domainPolicy());
   2745 
   2746    if (ParentProcessMessageManager* mm =
   2747            nsFrameMessageManager::sParentProcessManager) {
   2748      AutoJSAPI jsapi;
   2749      if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) {
   2750        MOZ_CRASH();
   2751      }
   2752      JS::Rooted<JS::Value> init(jsapi.cx());
   2753      // We'll crash on failure, so use a IgnoredErrorResult (which also
   2754      // auto-suppresses exceptions).
   2755      IgnoredErrorResult rv;
   2756      mm->GetInitialProcessData(jsapi.cx(), &init, rv);
   2757      if (NS_WARN_IF(rv.Failed())) {
   2758        MOZ_CRASH();
   2759      }
   2760 
   2761      initialData->Write(jsapi.cx(), init, rv);
   2762      if (NS_WARN_IF(rv.Failed())) {
   2763        MOZ_CRASH();
   2764      }
   2765    }
   2766  }
   2767  // This is only implemented (returns a non-empty list) by MacOSX and Linux
   2768  // at present.
   2769  SystemFontList fontList;
   2770  gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList);
   2771 
   2772  const FullLookAndFeel& lnf = *RemoteLookAndFeel::ExtractData();
   2773 
   2774  // If the shared fontlist is in use, collect its shmem block handles to pass
   2775  // to the child.
   2776  nsTArray<ReadOnlySharedMemoryHandle> sharedFontListBlocks;
   2777  gfxPlatformFontList::PlatformFontList()->ShareFontListToProcess(
   2778      &sharedFontListBlocks, OtherPid());
   2779 
   2780  // Content processes have no permission to access profile directory, so we
   2781  // send the file URL instead.
   2782  auto* sheetCache = GlobalStyleSheetCache::Singleton();
   2783  if (StyleSheet* ucs = sheetCache->GetUserContentSheet()) {
   2784    xpcomInit.userContentSheetURL() = ucs->GetOriginalURI();
   2785  } else {
   2786    xpcomInit.userContentSheetURL() = nullptr;
   2787  }
   2788 
   2789  // 1. Ensure the GPU process is ready, as we know we are not yet in shutdown.
   2790  GPUProcessManager* gpm = GPUProcessManager::Get();
   2791  nsresult gpuReadyRv = gpm->EnsureGPUReady();
   2792  // 2. Build ContentDeviceData first, as it may affect some gfxVars.
   2793  gfxPlatform::GetPlatform()->BuildContentDeviceData(
   2794      &xpcomInit.contentDeviceData());
   2795  // 3. Gather non-default gfxVars.
   2796  xpcomInit.gfxNonDefaultVarUpdates() = gfxVars::FetchNonDefaultVars();
   2797  // 4. Start listening for gfxVars updates, to notify content process later on.
   2798  gfxVars::AddReceiver(this);
   2799 
   2800  nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
   2801  if (gfxInfo) {
   2802    GfxInfoBase* gfxInfoRaw = static_cast<GfxInfoBase*>(gfxInfo.get());
   2803    xpcomInit.gfxFeatureStatus() = gfxInfoRaw->GetAllFeatures();
   2804  }
   2805 
   2806  // Send the dynamic scalar definitions to the new process.
   2807  TelemetryIPC::GetDynamicScalarDefinitions(xpcomInit.dynamicScalarDefs());
   2808 
   2809  for (auto const& [location, supported] : sCodecsSupported) {
   2810    (void)SendUpdateMediaCodecsSupported(location, supported);
   2811  }
   2812 
   2813  // Must send screen info before send initialData
   2814  ScreenManager& screenManager = ScreenManager::GetSingleton();
   2815  screenManager.CopyScreensToRemote(this);
   2816 
   2817  // Send the UA sheet shared memory buffer and the address it is mapped at.
   2818  Maybe<ReadOnlySharedMemoryHandle> sharedUASheetHandle;
   2819  uintptr_t sharedUASheetAddress = sheetCache->GetSharedMemoryAddress();
   2820 
   2821  if (ReadOnlySharedMemoryHandle handle = sheetCache->CloneHandle()) {
   2822    sharedUASheetHandle.emplace(std::move(handle));
   2823  } else {
   2824    sharedUASheetAddress = 0;
   2825  }
   2826 
   2827  bool isReadyForBackgroundProcessing = false;
   2828 #if defined(XP_WIN)
   2829  RefPtr<DllServices> dllSvc(DllServices::Get());
   2830  isReadyForBackgroundProcessing = dllSvc->IsReadyForBackgroundProcessing();
   2831 #endif
   2832 
   2833  xpcomInit.perfStatsMask() = PerfStats::GetCollectionMask();
   2834 
   2835  nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
   2836  dns->GetTrrDomain(xpcomInit.trrDomain());
   2837 
   2838  nsIDNSService::ResolverMode mode;
   2839  dns->GetCurrentTrrMode(&mode);
   2840  xpcomInit.trrMode() = mode;
   2841  xpcomInit.trrModeFromPref() =
   2842      static_cast<nsIDNSService::ResolverMode>(StaticPrefs::network_trr_mode());
   2843 
   2844  (void)SendSetXPCOMProcessAttributes(
   2845      xpcomInit, initialData, lnf, fontList, std::move(sharedUASheetHandle),
   2846      sharedUASheetAddress, std::move(sharedFontListBlocks),
   2847      isReadyForBackgroundProcessing);
   2848 
   2849  ipc::WritableSharedMap* sharedData =
   2850      nsFrameMessageManager::sParentProcessManager->SharedData();
   2851  sharedData->Flush();
   2852  sharedData->SendTo(this);
   2853 
   2854  nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
   2855  nsChromeRegistryChrome* chromeRegistry =
   2856      static_cast<nsChromeRegistryChrome*>(registrySvc.get());
   2857  chromeRegistry->SendRegisteredChrome(this);
   2858 
   2859  nsCOMPtr<nsIStringBundleService> stringBundleService =
   2860      components::StringBundle::Service();
   2861  stringBundleService->SendContentBundles(this);
   2862 
   2863  if (gAppData) {
   2864    nsCString version(gAppData->version);
   2865    nsCString buildID(gAppData->buildID);
   2866    nsCString name(gAppData->name);
   2867    nsCString UAName(gAppData->UAName);
   2868    nsCString ID(gAppData->ID);
   2869    nsCString vendor(gAppData->vendor);
   2870    nsCString sourceURL(gAppData->sourceURL);
   2871    nsCString updateURL(gAppData->updateURL);
   2872 
   2873    // Sending all information to content process.
   2874    (void)SendAppInfo(version, buildID, name, UAName, ID, vendor, sourceURL,
   2875                      updateURL);
   2876  }
   2877 
   2878  // Send the child its remote type. On Mac, this needs to be sent prior
   2879  // to the message we send to enable the Sandbox (SendStartProcessSandbox)
   2880  // because different remote types require different sandbox privileges.
   2881 
   2882  (void)SendRemoteType(mRemoteType, mProfile);
   2883 
   2884  if (mRemoteType != PREALLOC_REMOTE_TYPE) {
   2885    StartRemoteWorkerService();
   2886  }
   2887 
   2888  ScriptPreloader::InitContentChild(*this);
   2889 
   2890  // Initialize the message manager (and load delayed scripts) now that we
   2891  // have established communications with the child.
   2892  mMessageManager->InitWithCallback(this);
   2893  mMessageManager->SetOsPid(Pid());
   2894 
   2895  // Set the subprocess's priority.  We do this early on because we're likely
   2896  // /lowering/ the process's CPU and memory priority, which it has inherited
   2897  // from this process.
   2898  //
   2899  // This call can cause us to send IPC messages to the child process, so it
   2900  // must come after the Open() call above.
   2901  ProcessPriorityManager::SetProcessPriority(this, aInitialPriority);
   2902 
   2903  // NB: internally, this will send an IPC message to the child
   2904  // process to get it to create the CompositorBridgeChild.  This
   2905  // message goes through the regular IPC queue for this
   2906  // channel, so delivery will happen-before any other messages
   2907  // we send.  The CompositorBridgeChild must be created before any
   2908  // PBrowsers are created, because they rely on the Compositor
   2909  // already being around.  (Creation is async, so can't happen
   2910  // on demand.)
   2911  Endpoint<PCompositorManagerChild> compositor;
   2912  Endpoint<PImageBridgeChild> imageBridge;
   2913  Endpoint<PVRManagerChild> vrBridge;
   2914  Endpoint<PRemoteMediaManagerChild> videoManager;
   2915  AutoTArray<uint32_t, 3> namespaces;
   2916 
   2917  if (NS_SUCCEEDED(gpuReadyRv) &&
   2918      gpm->CreateContentBridges(OtherEndpointProcInfo(), &compositor,
   2919                                &imageBridge, &vrBridge, &videoManager,
   2920                                mChildID, &namespaces)) {
   2921    (void)SendInitRendering(std::move(compositor), std::move(imageBridge),
   2922                            std::move(vrBridge), std::move(videoManager),
   2923                            namespaces);
   2924  } else {
   2925    // This can fail if we've already started shutting down the compositor
   2926    // thread. See Bug 1562763 comment 8. On Android this can fail we are are
   2927    // put in the background, making it unlikely the content process will remain
   2928    // alive for much longer, but if it does, we will do the necessary
   2929    // operations for InitRendering in ReinitRendering when the GPU process is
   2930    // available.
   2931    if (gpuReadyRv == NS_ERROR_ILLEGAL_DURING_SHUTDOWN) {
   2932      return false;
   2933    }
   2934  }
   2935 
   2936  gpm->AddListener(this);
   2937 
   2938  if (StaticPrefs::media_rdd_process_enabled()) {
   2939    // Ensure the RDD process has been started.
   2940    RDDProcessManager* rdd = RDDProcessManager::Get();
   2941    rdd->LaunchRDDProcess();
   2942  }
   2943 
   2944  nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
   2945  if (sheetService) {
   2946    // This looks like a lot of work, but in a normal browser session we just
   2947    // send two loads.
   2948    //
   2949    // The URIs of the Gecko and Servo sheets should be the same, so it
   2950    // shouldn't matter which we look at.
   2951 
   2952    for (StyleSheet* sheet : *sheetService->AgentStyleSheets()) {
   2953      (void)SendLoadAndRegisterSheet(sheet->GetOriginalURI(),
   2954                                     nsIStyleSheetService::AGENT_SHEET);
   2955    }
   2956 
   2957    for (StyleSheet* sheet : *sheetService->UserStyleSheets()) {
   2958      (void)SendLoadAndRegisterSheet(sheet->GetOriginalURI(),
   2959                                     nsIStyleSheetService::USER_SHEET);
   2960    }
   2961 
   2962    for (StyleSheet* sheet : *sheetService->AuthorStyleSheets()) {
   2963      (void)SendLoadAndRegisterSheet(sheet->GetOriginalURI(),
   2964                                     nsIStyleSheetService::AUTHOR_SHEET);
   2965    }
   2966  }
   2967 
   2968 #ifdef MOZ_WMF_CDM
   2969  if (!mOriginsListCallback && IsMediaFoundationCDMPlaybackEnabled()) {
   2970    mOriginsListCallback = new OriginsListLoadCallback(this);
   2971    nsCOMPtr<nsIWindowsMediaFoundationCDMOriginsListService> rsService =
   2972        do_GetService("@mozilla.org/media/wmfcdm-origins-list;1");
   2973    if (rsService) {
   2974      rsService->SetCallback(mOriginsListCallback);
   2975    }
   2976  }
   2977 #endif
   2978 
   2979 #ifdef MOZ_SANDBOX
   2980  bool shouldSandbox = true;
   2981  Maybe<FileDescriptor> brokerFd;
   2982  // XXX: Checking the pref here makes it possible to enable/disable sandboxing
   2983  // during an active session. Currently the pref is only used for testing
   2984  // purpose. If the decision is made to permanently rely on the pref, this
   2985  // should be changed so that it is required to restart firefox for the change
   2986  // of value to take effect. Always send SetProcessSandbox message on macOS.
   2987 #  if !defined(XP_MACOSX)
   2988  shouldSandbox = IsContentSandboxEnabled();
   2989 #  endif
   2990 
   2991 #  ifdef XP_LINUX
   2992  if (shouldSandbox) {
   2993    MOZ_ASSERT(!mSandboxBroker);
   2994    bool isFileProcess = mRemoteType == FILE_REMOTE_TYPE;
   2995    UniquePtr<SandboxBroker::Policy> policy =
   2996        sSandboxBrokerPolicyFactory->GetContentPolicy(Pid(), isFileProcess);
   2997    if (policy) {
   2998      brokerFd = Some(FileDescriptor());
   2999      mSandboxBroker =
   3000          SandboxBroker::Create(std::move(policy), Pid(), brokerFd.ref());
   3001      if (!mSandboxBroker) {
   3002        KillHard("SandboxBroker::Create failed");
   3003        return false;
   3004      }
   3005      MOZ_ASSERT(brokerFd.ref().IsValid());
   3006    }
   3007  }
   3008 #  endif
   3009  if (shouldSandbox && !SendSetProcessSandbox(brokerFd)) {
   3010    KillHard("SandboxInitFailed");
   3011  }
   3012 #endif
   3013 
   3014  // Ensure that the default set of permissions are avaliable in the content
   3015  // process before we try to load any URIs in it.
   3016  //
   3017  // NOTE: All default permissions has to be transmitted to the child process
   3018  // before the blob urls in the for loop below (See Bug 1738713 comment 12).
   3019  EnsurePermissionsByKey(""_ns, ""_ns);
   3020 
   3021  {
   3022    nsTArray<BlobURLRegistrationData> registrations;
   3023    BlobURLProtocolHandler::ForEachBlobURL([&](BlobImpl* aBlobImpl,
   3024                                               nsIPrincipal* aPrincipal,
   3025                                               const nsCString& aPartitionKey,
   3026                                               const nsACString& aURI,
   3027                                               bool aRevoked) {
   3028      // We send all moz-extension Blob URL's to all content processes
   3029      // because content scripts mean that a moz-extension can live in any
   3030      // process. Same thing for system principal Blob URLs. Content Blob
   3031      // URL's are sent for content principals on-demand by
   3032      // AboutToLoadHttpDocumentForChild and RemoteWorkerManager.
   3033      if (!BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal)) {
   3034        return true;
   3035      }
   3036 
   3037      IPCBlob ipcBlob;
   3038      nsresult rv = IPCBlobUtils::Serialize(aBlobImpl, ipcBlob);
   3039      if (NS_WARN_IF(NS_FAILED(rv))) {
   3040        return false;
   3041      }
   3042 
   3043      registrations.AppendElement(BlobURLRegistrationData(
   3044          nsCString(aURI), ipcBlob, WrapNotNull(aPrincipal),
   3045          nsCString(aPartitionKey), aRevoked));
   3046 
   3047      rv = TransmitPermissionsForPrincipal(aPrincipal);
   3048      (void)NS_WARN_IF(NS_FAILED(rv));
   3049      return true;
   3050    });
   3051 
   3052    if (!registrations.IsEmpty()) {
   3053      (void)SendInitBlobURLs(registrations);
   3054    }
   3055  }
   3056 
   3057  // Send down { Parent, Window }ActorOptions at startup to content process.
   3058  RefPtr<JSActorService> actorSvc = JSActorService::GetSingleton();
   3059  if (actorSvc) {
   3060    nsTArray<JSProcessActorInfo> contentInfos;
   3061    actorSvc->GetJSProcessActorInfos(contentInfos);
   3062 
   3063    nsTArray<JSWindowActorInfo> windowInfos;
   3064    actorSvc->GetJSWindowActorInfos(windowInfos);
   3065 
   3066    (void)SendInitJSActorInfos(contentInfos, windowInfos);
   3067  }
   3068 
   3069  // Begin subscribing to any BrowsingContextGroups which were hosted by this
   3070  // process before it finished launching.
   3071  for (const auto& group : mGroups) {
   3072    group->Subscribe(this);
   3073  }
   3074 
   3075  MaybeEnableRemoteInputEventQueue();
   3076 
   3077  return true;
   3078 }
   3079 
   3080 bool ContentParent::IsAlive() const {
   3081  return mLifecycleState == LifecycleState::ALIVE ||
   3082         mLifecycleState == LifecycleState::INITIALIZED;
   3083 }
   3084 
   3085 bool ContentParent::IsInitialized() const {
   3086  return mLifecycleState == LifecycleState::INITIALIZED;
   3087 }
   3088 
   3089 int32_t ContentParent::Pid() const {
   3090  if (!mSubprocess) {
   3091    return -1;
   3092  }
   3093  auto pid = mSubprocess->GetChildProcessId();
   3094  if (pid == 0) {
   3095    return -1;
   3096  }
   3097  return ReleaseAssertedCast<int32_t>(pid);
   3098 }
   3099 
   3100 void ContentParent::OnCompositorUnexpectedShutdown() {
   3101  GPUProcessManager* gpm = GPUProcessManager::Get();
   3102 
   3103  Endpoint<PCompositorManagerChild> compositor;
   3104  Endpoint<PImageBridgeChild> imageBridge;
   3105  Endpoint<PVRManagerChild> vrBridge;
   3106  Endpoint<PRemoteMediaManagerChild> videoManager;
   3107  AutoTArray<uint32_t, 3> namespaces;
   3108 
   3109  if (!gpm->CreateContentBridges(OtherEndpointProcInfo(), &compositor,
   3110                                 &imageBridge, &vrBridge, &videoManager,
   3111                                 mChildID, &namespaces)) {
   3112    return;
   3113  }
   3114 
   3115  (void)SendReinitRendering(std::move(compositor), std::move(imageBridge),
   3116                            std::move(vrBridge), std::move(videoManager),
   3117                            namespaces);
   3118 }
   3119 
   3120 void ContentParent::OnCompositorDeviceReset() {
   3121  (void)SendReinitRenderingForDeviceReset();
   3122 }
   3123 
   3124 void ContentParent::MaybeEnableRemoteInputEventQueue() {
   3125  MOZ_ASSERT(!mIsRemoteInputEventQueueEnabled);
   3126  mIsRemoteInputEventQueueEnabled = true;
   3127  (void)SendSetInputEventQueueEnabled();
   3128  SetInputPriorityEventEnabled(true);
   3129 }
   3130 
   3131 void ContentParent::SetInputPriorityEventEnabled(bool aEnabled) {
   3132  if (!mIsRemoteInputEventQueueEnabled ||
   3133      mIsInputPriorityEventEnabled == aEnabled) {
   3134    return;
   3135  }
   3136  mIsInputPriorityEventEnabled = aEnabled;
   3137  // Send IPC messages to flush the pending events in the input event queue and
   3138  // the normal event queue. See PContent.ipdl for more details.
   3139  (void)SendSuspendInputEventQueue();
   3140  (void)SendFlushInputEventQueue();
   3141  (void)SendResumeInputEventQueue();
   3142 }
   3143 
   3144 void ContentParent::OnVarChanged(const nsTArray<GfxVarUpdate>& aVar) {
   3145  if (!CanSend()) {
   3146    return;
   3147  }
   3148  (void)SendVarUpdate(aVar);
   3149 }
   3150 
   3151 mozilla::ipc::IPCResult ContentParent::RecvSetClipboard(
   3152    const IPCTransferable& aTransferable,
   3153    const nsIClipboard::ClipboardType& aWhichClipboard,
   3154    const MaybeDiscarded<WindowContext>& aRequestingWindowContext) {
   3155  // aRequestingPrincipal is allowed to be nullptr here.
   3156 
   3157  if (!ValidatePrincipal(aTransferable.dataPrincipal(),
   3158                         {ValidatePrincipalOptions::AllowNullPtr,
   3159                          ValidatePrincipalOptions::AllowExpanded,
   3160                          ValidatePrincipalOptions::AllowSystem})) {
   3161    LogAndAssertFailedPrincipalValidationInfo(aTransferable.dataPrincipal(),
   3162                                              __func__);
   3163  }
   3164 
   3165  nsresult rv;
   3166  nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
   3167  NS_ENSURE_SUCCESS(rv, IPC_OK());
   3168 
   3169  nsCOMPtr<nsITransferable> trans =
   3170      do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
   3171  NS_ENSURE_SUCCESS(rv, IPC_OK());
   3172  trans->Init(nullptr);
   3173 
   3174  rv = nsContentUtils::IPCTransferableToTransferable(
   3175      aTransferable, true /* aAddDataFlavor */, trans,
   3176      true /* aFilterUnknownFlavors */);
   3177  NS_ENSURE_SUCCESS(rv, IPC_OK());
   3178 
   3179  // OK if this is null
   3180  RefPtr<WindowGlobalParent> window;
   3181  if (!aRequestingWindowContext.IsDiscarded()) {
   3182    window = aRequestingWindowContext.get_canonical();
   3183  }
   3184  clipboard->SetData(trans, nullptr, aWhichClipboard, window);
   3185  return IPC_OK();
   3186 }
   3187 
   3188 /* static */ Result<nsCOMPtr<nsITransferable>, nsresult>
   3189 ContentParent::CreateClipboardTransferable(const nsTArray<nsCString>& aTypes) {
   3190  nsresult rv;
   3191  nsCOMPtr<nsITransferable> trans =
   3192      do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
   3193  if (NS_FAILED(rv)) {
   3194    return Err(rv);
   3195  }
   3196 
   3197  MOZ_TRY(trans->Init(nullptr));
   3198  // The private flag is only used to prevent the data from being cached to the
   3199  // disk. The flag is not exported to the IPCDataTransfer object.
   3200  // The flag is set because we are not sure whether the clipboard data is used
   3201  // in a private browsing context. The transferable is only used in this scope,
   3202  // so the cache would not reduce memory consumption anyway.
   3203  trans->SetIsPrivateData(true);
   3204  // Fill out flavors for transferable
   3205  for (uint32_t t = 0; t < aTypes.Length(); t++) {
   3206    MOZ_TRY(trans->AddDataFlavor(aTypes[t].get()));
   3207  }
   3208 
   3209  return std::move(trans);
   3210 }
   3211 
   3212 mozilla::ipc::IPCResult ContentParent::RecvGetClipboard(
   3213    nsTArray<nsCString>&& aTypes,
   3214    const nsIClipboard::ClipboardType& aWhichClipboard,
   3215    const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
   3216    IPCTransferableDataOrError* aTransferableDataOrError) {
   3217  nsresult rv;
   3218  // We expect content processes to always pass a non-null window so Content
   3219  // Analysis can analyze it. (if Content Analysis is active)
   3220  // There may be some cases when a window is closing, etc., in
   3221  // which case returning no clipboard content should not be a problem.
   3222  if (aRequestingWindowContext.IsDiscarded()) {
   3223    NS_WARNING(
   3224        "discarded window passed to RecvGetClipboard(); returning no clipboard "
   3225        "content");
   3226    *aTransferableDataOrError = NS_ERROR_FAILURE;
   3227    return IPC_OK();
   3228  }
   3229  if (aRequestingWindowContext.IsNull()) {
   3230    return IPC_FAIL(this, "passed null window to RecvGetClipboard()");
   3231  }
   3232  RefPtr<WindowGlobalParent> window = aRequestingWindowContext.get_canonical();
   3233  // Retrieve clipboard
   3234  nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
   3235  if (NS_FAILED(rv)) {
   3236    *aTransferableDataOrError = rv;
   3237    return IPC_OK();
   3238  }
   3239 
   3240  // Create transferable
   3241  auto result = CreateClipboardTransferable(aTypes);
   3242  if (result.isErr()) {
   3243    *aTransferableDataOrError = result.unwrapErr();
   3244    return IPC_OK();
   3245  }
   3246 
   3247  // Get data from clipboard
   3248  nsCOMPtr<nsITransferable> trans = result.unwrap();
   3249  rv = clipboard->GetData(trans, aWhichClipboard, window);
   3250  if (NS_FAILED(rv)) {
   3251    *aTransferableDataOrError = rv;
   3252    return IPC_OK();
   3253  }
   3254 
   3255  IPCTransferableData transferableData;
   3256  nsContentUtils::TransferableToIPCTransferableData(
   3257      trans, &transferableData, true /* aInSyncMessage */, this);
   3258  *aTransferableDataOrError = std::move(transferableData);
   3259  return IPC_OK();
   3260 }
   3261 
   3262 mozilla::ipc::IPCResult ContentParent::RecvEmptyClipboard(
   3263    const nsIClipboard::ClipboardType& aWhichClipboard) {
   3264  nsresult rv;
   3265  nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
   3266  NS_ENSURE_SUCCESS(rv, IPC_OK());
   3267 
   3268  clipboard->EmptyClipboard(aWhichClipboard);
   3269 
   3270  return IPC_OK();
   3271 }
   3272 
   3273 mozilla::ipc::IPCResult ContentParent::RecvClipboardHasType(
   3274    nsTArray<nsCString>&& aTypes,
   3275    const nsIClipboard::ClipboardType& aWhichClipboard, bool* aHasType) {
   3276  nsresult rv;
   3277  nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
   3278  NS_ENSURE_SUCCESS(rv, IPC_OK());
   3279 
   3280  clipboard->HasDataMatchingFlavors(aTypes, aWhichClipboard, aHasType);
   3281 
   3282  return IPC_OK();
   3283 }
   3284 
   3285 namespace {
   3286 static Result<ClipboardReadRequest, nsresult> CreateClipboardReadRequest(
   3287    ContentParent& aContentParent,
   3288    nsIClipboardDataSnapshot& aClipboardDataSnapshot) {
   3289  nsTArray<nsCString> flavors;
   3290  nsresult rv = aClipboardDataSnapshot.GetFlavorList(flavors);
   3291  if (NS_FAILED(rv)) {
   3292    return Err(rv);
   3293  }
   3294 
   3295  auto requestParent = MakeNotNull<RefPtr<ClipboardReadRequestParent>>(
   3296      &aContentParent, &aClipboardDataSnapshot);
   3297 
   3298  // Open a remote endpoint for our PClipboardReadRequest actor.
   3299  ManagedEndpoint<PClipboardReadRequestChild> childEndpoint =
   3300      aContentParent.OpenPClipboardReadRequestEndpoint(requestParent);
   3301  if (NS_WARN_IF(!childEndpoint.IsValid())) {
   3302    return Err(NS_ERROR_FAILURE);
   3303  }
   3304 
   3305  return ClipboardReadRequest(std::move(childEndpoint), std::move(flavors));
   3306 }
   3307 
   3308 class ClipboardGetCallback final : public nsIClipboardGetDataSnapshotCallback {
   3309 public:
   3310  ClipboardGetCallback(
   3311      ContentParent* aContentParent,
   3312      ContentParent::GetClipboardDataSnapshotResolver&& aResolver)
   3313      : mContentParent(aContentParent), mResolver(std::move(aResolver)) {}
   3314 
   3315  // This object will never be held by a cycle-collected object, so it doesn't
   3316  // need to be cycle-collected despite holding alive cycle-collected objects.
   3317  NS_DECL_ISUPPORTS
   3318 
   3319  // nsIClipboardGetDataSnapshotCallback
   3320  NS_IMETHOD OnSuccess(
   3321      nsIClipboardDataSnapshot* aClipboardDataSnapshot) override {
   3322    MOZ_ASSERT(mContentParent);
   3323    MOZ_ASSERT(aClipboardDataSnapshot);
   3324 
   3325    auto result =
   3326        CreateClipboardReadRequest(*mContentParent, *aClipboardDataSnapshot);
   3327    if (result.isErr()) {
   3328      return OnError(result.unwrapErr());
   3329    }
   3330 
   3331    mResolver(result.unwrap());
   3332    return NS_OK;
   3333  }
   3334 
   3335  NS_IMETHOD OnError(nsresult aResult) override {
   3336    mResolver(aResult);
   3337    return NS_OK;
   3338  }
   3339 
   3340 protected:
   3341  ~ClipboardGetCallback() = default;
   3342 
   3343  RefPtr<ContentParent> mContentParent;
   3344  ContentParent::GetClipboardDataSnapshotResolver mResolver;
   3345 };
   3346 
   3347 NS_IMPL_ISUPPORTS(ClipboardGetCallback, nsIClipboardGetDataSnapshotCallback)
   3348 
   3349 }  // namespace
   3350 
   3351 mozilla::ipc::IPCResult ContentParent::RecvGetClipboardDataSnapshot(
   3352    nsTArray<nsCString>&& aTypes,
   3353    const nsIClipboard::ClipboardType& aWhichClipboard,
   3354    const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
   3355    mozilla::NotNull<nsIPrincipal*> aRequestingPrincipal,
   3356    GetClipboardDataSnapshotResolver&& aResolver) {
   3357  if (!ValidatePrincipal(aRequestingPrincipal,
   3358                         {ValidatePrincipalOptions::AllowSystem,
   3359                          ValidatePrincipalOptions::AllowExpanded})) {
   3360    LogAndAssertFailedPrincipalValidationInfo(aRequestingPrincipal, __func__);
   3361  }
   3362 
   3363  // If the requesting context has been discarded, cancel the paste.
   3364  if (aRequestingWindowContext.IsDiscarded()) {
   3365    aResolver(NS_ERROR_NOT_AVAILABLE);
   3366    return IPC_OK();
   3367  }
   3368 
   3369  RefPtr<WindowGlobalParent> requestingWindow =
   3370      aRequestingWindowContext.get_canonical();
   3371  if (requestingWindow && requestingWindow->GetContentParent() != this) {
   3372    return IPC_FAIL(
   3373        this, "attempt to paste into WindowContext loaded in another process");
   3374  }
   3375 
   3376  nsresult rv;
   3377  // Retrieve clipboard
   3378  nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
   3379  if (NS_FAILED(rv)) {
   3380    aResolver(rv);
   3381    return IPC_OK();
   3382  }
   3383 
   3384  auto callback = MakeRefPtr<ClipboardGetCallback>(this, std::move(aResolver));
   3385  rv = clipboard->GetDataSnapshot(aTypes, aWhichClipboard, requestingWindow,
   3386                                  aRequestingPrincipal, callback);
   3387  if (NS_FAILED(rv)) {
   3388    callback->OnError(rv);
   3389    return IPC_OK();
   3390  }
   3391 
   3392  return IPC_OK();
   3393 }
   3394 
   3395 mozilla::ipc::IPCResult ContentParent::RecvGetClipboardDataSnapshotSync(
   3396    nsTArray<nsCString>&& aTypes,
   3397    const nsIClipboard::ClipboardType& aWhichClipboard,
   3398    const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
   3399    ClipboardReadRequestOrError* aRequestOrError) {
   3400  // If the requesting context has been discarded, cancel the paste.
   3401  if (aRequestingWindowContext.IsDiscarded()) {
   3402    *aRequestOrError = NS_ERROR_FAILURE;
   3403    return IPC_OK();
   3404  }
   3405 
   3406  RefPtr<WindowGlobalParent> requestingWindow =
   3407      aRequestingWindowContext.get_canonical();
   3408  if (requestingWindow && requestingWindow->GetContentParent() != this) {
   3409    return IPC_FAIL(
   3410        this, "attempt to paste into WindowContext loaded in another process");
   3411  }
   3412 
   3413  nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID));
   3414  if (!clipboard) {
   3415    *aRequestOrError = NS_ERROR_FAILURE;
   3416    return IPC_OK();
   3417  }
   3418 
   3419  nsCOMPtr<nsIClipboardDataSnapshot> clipboardDataSnapshot;
   3420  nsresult rv =
   3421      clipboard->GetDataSnapshotSync(aTypes, aWhichClipboard, requestingWindow,
   3422                                     getter_AddRefs(clipboardDataSnapshot));
   3423  if (NS_FAILED(rv)) {
   3424    *aRequestOrError = rv;
   3425    return IPC_OK();
   3426  }
   3427 
   3428  auto result = CreateClipboardReadRequest(*this, *clipboardDataSnapshot);
   3429  if (result.isErr()) {
   3430    *aRequestOrError = result.unwrapErr();
   3431    return IPC_OK();
   3432  }
   3433 
   3434  *aRequestOrError = result.unwrap();
   3435  return IPC_OK();
   3436 }
   3437 
   3438 already_AddRefed<PClipboardWriteRequestParent>
   3439 ContentParent::AllocPClipboardWriteRequestParent(
   3440    const nsIClipboard::ClipboardType& aClipboardType,
   3441    const MaybeDiscarded<WindowContext>& aSettingWindowContext) {
   3442  WindowContext* settingWindowContext = nullptr;
   3443  if (!aSettingWindowContext.IsDiscarded()) {
   3444    settingWindowContext = aSettingWindowContext.get();
   3445  }
   3446  RefPtr<ClipboardWriteRequestParent> request =
   3447      MakeAndAddRef<ClipboardWriteRequestParent>(this);
   3448  request->Init(aClipboardType, settingWindowContext);
   3449  return request.forget();
   3450 }
   3451 
   3452 mozilla::ipc::IPCResult ContentParent::RecvGetIconForExtension(
   3453    const nsACString& aFileExt, const uint32_t& aIconSize,
   3454    nsTArray<uint8_t>* bits) {
   3455 #ifdef MOZ_WIDGET_ANDROID
   3456  NS_ASSERTION(AndroidBridge::Bridge() != nullptr,
   3457               "AndroidBridge is not available");
   3458  if (AndroidBridge::Bridge() == nullptr) {
   3459    // Do not fail - just no icon will be shown
   3460    return IPC_OK();
   3461  }
   3462 
   3463  bits->AppendElements(aIconSize * aIconSize * 4);
   3464 
   3465  AndroidBridge::Bridge()->GetIconForExtension(aFileExt, aIconSize,
   3466                                               bits->Elements());
   3467 #endif
   3468  return IPC_OK();
   3469 }
   3470 
   3471 mozilla::ipc::IPCResult ContentParent::RecvFirstIdle() {
   3472  // When the ContentChild goes idle, it sends us a FirstIdle message
   3473  // which we use as a good time to signal the PreallocatedProcessManager
   3474  // that it can start allocating processes from now on.
   3475  if (mIsAPreallocBlocker) {
   3476    MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
   3477            ("RecvFirstIdle id=%p childID=%" PRIu64 ": Removing Blocker for %s",
   3478             this, (uint64_t)this->ChildID(), mRemoteType.get()));
   3479    PreallocatedProcessManager::RemoveBlocker(mRemoteType, this);
   3480    mIsAPreallocBlocker = false;
   3481  }
   3482  return IPC_OK();
   3483 }
   3484 
   3485 already_AddRefed<nsDocShellLoadState> ContentParent::TakePendingLoadStateForId(
   3486    uint64_t aLoadIdentifier) {
   3487  return mPendingLoadStates.Extract(aLoadIdentifier).valueOr(nullptr).forget();
   3488 }
   3489 
   3490 void ContentParent::StorePendingLoadState(nsDocShellLoadState* aLoadState) {
   3491  MOZ_DIAGNOSTIC_ASSERT(
   3492      !mPendingLoadStates.Contains(aLoadState->GetLoadIdentifier()),
   3493      "The same nsDocShellLoadState was sent to the same content process "
   3494      "twice? This will mess with cross-process tracking of loads");
   3495  mPendingLoadStates.InsertOrUpdate(aLoadState->GetLoadIdentifier(),
   3496                                    aLoadState);
   3497 }
   3498 
   3499 mozilla::ipc::IPCResult ContentParent::RecvCleanupPendingLoadState(
   3500    uint64_t aLoadIdentifier) {
   3501  mPendingLoadStates.Remove(aLoadIdentifier);
   3502  return IPC_OK();
   3503 }
   3504 
   3505 // We want ContentParent to show up in CC logs for debugging purposes, but we
   3506 // don't actually cycle collect it.
   3507 NS_IMPL_CYCLE_COLLECTION_0(ContentParent)
   3508 
   3509 NS_IMPL_CYCLE_COLLECTING_ADDREF(ContentParent)
   3510 NS_IMPL_CYCLE_COLLECTING_RELEASE(ContentParent)
   3511 
   3512 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ContentParent)
   3513  NS_INTERFACE_MAP_ENTRY_CONCRETE(ContentParent)
   3514  NS_INTERFACE_MAP_ENTRY(nsIDOMProcessParent)
   3515  NS_INTERFACE_MAP_ENTRY(nsIObserver)
   3516  NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionCallback)
   3517  NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionErrorCallback)
   3518  NS_INTERFACE_MAP_ENTRY(nsIAsyncShutdownBlocker)
   3519  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   3520  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMProcessParent)
   3521 NS_INTERFACE_MAP_END
   3522 
   3523 class RequestContentJSInterruptRunnable final : public Runnable {
   3524 public:
   3525  explicit RequestContentJSInterruptRunnable(PProcessHangMonitorParent* aActor)
   3526      : Runnable("dom::RequestContentJSInterruptRunnable"),
   3527        mHangMonitorActor(aActor) {}
   3528 
   3529  NS_IMETHOD Run() override {
   3530    MOZ_ASSERT(mHangMonitorActor);
   3531    (void)mHangMonitorActor->SendRequestContentJSInterrupt();
   3532 
   3533    return NS_OK;
   3534  }
   3535 
   3536 private:
   3537  // The end-of-life of ContentParent::mHangMonitorActor is bound to
   3538  // ContentParent::ActorDestroy and then HangMonitorParent::Shutdown
   3539  // dispatches a shutdown runnable to this queue and waits for it to be
   3540  // executed. So the runnable needs not to care about keeping it alive,
   3541  // as it is surely dispatched earlier than the
   3542  // HangMonitorParent::ShutdownOnThread.
   3543  RefPtr<PProcessHangMonitorParent> mHangMonitorActor;
   3544 };
   3545 
   3546 void ContentParent::SignalImpendingShutdownToContentJS() {
   3547  if (!mIsSignaledImpendingShutdown &&
   3548      !AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
   3549    MaybeLogBlockShutdownDiagnostics(
   3550        this, "BlockShutdown: NotifyImpendingShutdown.", __FILE__, __LINE__);
   3551    NotifyImpendingShutdown();
   3552    mIsSignaledImpendingShutdown = true;
   3553    if (mHangMonitorActor &&
   3554        StaticPrefs::dom_abort_script_on_child_shutdown()) {
   3555      MaybeLogBlockShutdownDiagnostics(
   3556          this, "BlockShutdown: RequestContentJSInterrupt.", __FILE__,
   3557          __LINE__);
   3558      RefPtr<RequestContentJSInterruptRunnable> r =
   3559          new RequestContentJSInterruptRunnable(mHangMonitorActor);
   3560      ProcessHangMonitor::Get()->Dispatch(r.forget());
   3561    }
   3562  }
   3563 }
   3564 
   3565 // Async shutdown blocker
   3566 NS_IMETHODIMP
   3567 ContentParent::BlockShutdown(nsIAsyncShutdownClient* aClient) {
   3568  if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
   3569 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   3570    mBlockShutdownCalled = true;
   3571 #endif
   3572    // This will make our process unusable for normal content, so we need to
   3573    // ensure we won't get re-used by GetUsedBrowserProcess as we have not yet
   3574    // done MarkAsDead.
   3575    PreallocatedProcessManager::Erase(this);
   3576    {
   3577      RecursiveMutexAutoLock lock(mThreadsafeHandle->mMutex);
   3578      mThreadsafeHandle->mShutdownStarted = true;
   3579    }
   3580    // Our real shutdown has not yet started. Just notify the impending
   3581    // shutdown and eventually cancel content JS.
   3582    SignalImpendingShutdownToContentJS();
   3583 
   3584    if (sAppShutdownConfirmedClient) {
   3585      (void)sAppShutdownConfirmedClient->RemoveBlocker(this);
   3586    }
   3587 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   3588    mBlockShutdownCalled = false;
   3589 #endif
   3590    return NS_OK;
   3591  }
   3592 
   3593 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   3594  // We register two final shutdown blockers and both would call us, but if
   3595  // things go well we will unregister both as (delayed) reaction to the first
   3596  // call we get and thus never receive a second call. Thus we believe that we
   3597  // will get called only once except for quit-application-granted, which is
   3598  // handled above.
   3599  MOZ_ASSERT(!mBlockShutdownCalled);
   3600  mBlockShutdownCalled = true;
   3601 #endif
   3602 
   3603  if (CanSend()) {
   3604    MaybeLogBlockShutdownDiagnostics(this, "BlockShutdown: CanSend.", __FILE__,
   3605                                     __LINE__);
   3606 
   3607    // Make sure that our process will get scheduled.
   3608    ProcessPriorityManager::SetProcessPriority(this,
   3609                                               PROCESS_PRIORITY_FOREGROUND);
   3610    // The normal shutdown sequence is to send a shutdown message
   3611    // to the child and then just wait for ActorDestroy which will
   3612    // cleanup everything and remove our blockers.
   3613    if (!ShutDownProcess(SEND_SHUTDOWN_MESSAGE)) {
   3614      KillHard("Failed to send Shutdown message. Destroying the process...");
   3615      return NS_OK;
   3616    }
   3617  } else if (IsLaunching()) {
   3618    MaybeLogBlockShutdownDiagnostics(
   3619        this, "BlockShutdown: !CanSend && IsLaunching.", __FILE__, __LINE__);
   3620 
   3621    // If we get here while we are launching, we must wait for the child to
   3622    // be able to react on our commands. Mark this process as dead. This
   3623    // will make bail out LaunchSubprocessResolve and kick off the normal
   3624    // shutdown sequence.
   3625    MarkAsDead();
   3626  } else {
   3627    MOZ_ASSERT(IsDead());
   3628    if (!IsDead()) {
   3629      MaybeLogBlockShutdownDiagnostics(
   3630          this, "BlockShutdown: !!! !CanSend && !IsLaunching && !IsDead !!!",
   3631          __FILE__, __LINE__);
   3632    } else {
   3633      MaybeLogBlockShutdownDiagnostics(
   3634          this, "BlockShutdown: !CanSend && !IsLaunching && IsDead.", __FILE__,
   3635          __LINE__);
   3636    }
   3637    // Nothing left we can do. We must assume that we race with an ongoing
   3638    // process shutdown, such that we can expect our shutdown blockers to be
   3639    // removed normally.
   3640  }
   3641 
   3642  return NS_OK;
   3643 }
   3644 
   3645 NS_IMETHODIMP
   3646 ContentParent::GetName(nsAString& aName) {
   3647  aName.AssignLiteral("ContentParent:");
   3648  aName.AppendPrintf(" id=%p", this);
   3649  return NS_OK;
   3650 }
   3651 
   3652 NS_IMETHODIMP
   3653 ContentParent::GetState(nsIPropertyBag** aResult) {
   3654  auto props = MakeRefPtr<nsHashPropertyBag>();
   3655  props->SetPropertyAsACString(u"remoteTypePrefix"_ns,
   3656                               RemoteTypePrefix(mRemoteType));
   3657  *aResult = props.forget().downcast<nsIWritablePropertyBag>().take();
   3658  return NS_OK;
   3659 }
   3660 
   3661 static void InitShutdownClients() {
   3662  if (!sXPCOMShutdownClient) {
   3663    nsresult rv;
   3664    nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdownService();
   3665    if (!svc) {
   3666      return;
   3667    }
   3668 
   3669    nsCOMPtr<nsIAsyncShutdownClient> client;
   3670    // TODO: It seems as if getPhase from AsyncShutdown.sys.mjs does not check
   3671    // if we are beyond our phase already. See bug 1762840.
   3672    if (!AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMWillShutdown)) {
   3673      rv = svc->GetXpcomWillShutdown(getter_AddRefs(client));
   3674      if (NS_SUCCEEDED(rv)) {
   3675        sXPCOMShutdownClient = client.forget();
   3676        ClearOnShutdown(&sXPCOMShutdownClient);
   3677      }
   3678    }
   3679    if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
   3680      rv = svc->GetProfileBeforeChange(getter_AddRefs(client));
   3681      if (NS_SUCCEEDED(rv)) {
   3682        sProfileBeforeChangeClient = client.forget();
   3683        ClearOnShutdown(&sProfileBeforeChangeClient);
   3684      }
   3685    }
   3686    if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
   3687      rv = svc->GetAppShutdownConfirmed(getter_AddRefs(client));
   3688      if (NS_SUCCEEDED(rv)) {
   3689        sAppShutdownConfirmedClient = client.forget();
   3690        ClearOnShutdown(&sAppShutdownConfirmedClient);
   3691      }
   3692    }
   3693  }
   3694 }
   3695 
   3696 void ContentParent::AddShutdownBlockers() {
   3697  InitShutdownClients();
   3698  MOZ_ASSERT(sXPCOMShutdownClient);
   3699  MOZ_ASSERT(sProfileBeforeChangeClient);
   3700 
   3701  if (sXPCOMShutdownClient) {
   3702    sXPCOMShutdownClient->AddBlocker(
   3703        this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
   3704  }
   3705  if (sProfileBeforeChangeClient) {
   3706    sProfileBeforeChangeClient->AddBlocker(
   3707        this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
   3708  }
   3709  if (sAppShutdownConfirmedClient) {
   3710    sAppShutdownConfirmedClient->AddBlocker(
   3711        this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
   3712  }
   3713 }
   3714 
   3715 void ContentParent::RemoveShutdownBlockers() {
   3716  MOZ_ASSERT(sXPCOMShutdownClient);
   3717  MOZ_ASSERT(sProfileBeforeChangeClient);
   3718 
   3719  MaybeLogBlockShutdownDiagnostics(this, "RemoveShutdownBlockers", __FILE__,
   3720                                   __LINE__);
   3721 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   3722  mBlockShutdownCalled = false;
   3723 #endif
   3724 
   3725  if (sXPCOMShutdownClient) {
   3726    (void)sXPCOMShutdownClient->RemoveBlocker(this);
   3727  }
   3728  if (sProfileBeforeChangeClient) {
   3729    (void)sProfileBeforeChangeClient->RemoveBlocker(this);
   3730  }
   3731  if (sAppShutdownConfirmedClient) {
   3732    (void)sAppShutdownConfirmedClient->RemoveBlocker(this);
   3733  }
   3734 }
   3735 
   3736 NS_IMETHODIMP
   3737 ContentParent::Observe(nsISupports* aSubject, const char* aTopic,
   3738                       const char16_t* aData) {
   3739  if (IsDead() || !mSubprocess) {
   3740    return NS_OK;
   3741  }
   3742 
   3743  if (!strcmp(aTopic, "nsPref:changed")) {
   3744    // We know prefs are ASCII here.
   3745    NS_LossyConvertUTF16toASCII strData(aData);
   3746 
   3747    Pref pref(strData, /* isLocked */ false,
   3748              /* isSanitized */ false, Nothing(), Nothing());
   3749 
   3750    Preferences::GetPreference(&pref, GeckoProcessType_Content,
   3751                               GetRemoteType());
   3752 
   3753    // This check is a bit of a hack.  We want to avoid sending excessive
   3754    // preference updates to subprocesses for performance reasons, but we
   3755    // currently don't have a great mechanism for doing so. (See Bug 1819714)
   3756    // We're going to hijack the sanitization mechanism to accomplish our goal
   3757    // but it imposes the following complications:
   3758    // 1) It doesn't avoid sending anything to other (non-web-content)
   3759    //    subprocesses so we're not getting any perf gains there
   3760    // 2) It confuses the subprocesses w.r.t. sanitization.  The point of
   3761    //    sending a preference update of a sanitized preference is so that
   3762    //    content process knows when it's asked to resolve a sanitized
   3763    //    preference, and it can send telemetry and/or crash.  With this
   3764    //    change, a sanitized pref that is created during the browser session
   3765    //    will not be sent to the content process, and therefore the content
   3766    //    process won't know it should telemetry/crash on access - it'll just
   3767    //    silently fail to resolve it.  After browser restart, the sanitized
   3768    //    pref will be populated into the content process via the shared pref
   3769    //    map and _then_ if it is accessed, the content process will crash.
   3770    //    We're seeing good telemetry/crash rates right now, so we're okay with
   3771    //    this limitation.
   3772    if (pref.isSanitized()) {
   3773      return NS_OK;
   3774    }
   3775 
   3776    if (IsInitialized()) {
   3777      MOZ_ASSERT(mQueuedPrefs.IsEmpty());
   3778      if (!SendPreferenceUpdate(pref)) {
   3779        return NS_ERROR_NOT_AVAILABLE;
   3780      }
   3781    } else {
   3782      MOZ_ASSERT(!IsDead());
   3783      mQueuedPrefs.AppendElement(pref);
   3784    }
   3785 
   3786    return NS_OK;
   3787  }
   3788 
   3789  if (!IsAlive()) {
   3790    return NS_OK;
   3791  }
   3792 
   3793  // listening for memory pressure event
   3794  if (!strcmp(aTopic, "memory-pressure")) {
   3795    (void)SendFlushMemory(nsDependentString(aData));
   3796  } else if (!strcmp(aTopic, "application-background")) {
   3797    (void)SendApplicationBackground();
   3798  } else if (!strcmp(aTopic, "application-foreground")) {
   3799    (void)SendApplicationForeground();
   3800  } else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC)) {
   3801    NS_ConvertUTF16toUTF8 dataStr(aData);
   3802    const char* offline = dataStr.get();
   3803    if (!SendSetOffline(!strcmp(offline, "true"))) {
   3804      return NS_ERROR_NOT_AVAILABLE;
   3805    }
   3806  } else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC)) {
   3807    if (!SendSetConnectivity(u"true"_ns.Equals(aData))) {
   3808      return NS_ERROR_NOT_AVAILABLE;
   3809    }
   3810  } else if (!strcmp(aTopic, NS_IPC_CAPTIVE_PORTAL_SET_STATE)) {
   3811    nsCOMPtr<nsICaptivePortalService> cps = do_QueryInterface(aSubject);
   3812    MOZ_ASSERT(cps, "Should QI to a captive portal service");
   3813    if (!cps) {
   3814      return NS_ERROR_FAILURE;
   3815    }
   3816    int32_t state;
   3817    cps->GetState(&state);
   3818    if (!SendSetCaptivePortalState(state)) {
   3819      return NS_ERROR_NOT_AVAILABLE;
   3820    }
   3821  } else if (!strcmp(aTopic, "child-gc-request")) {
   3822    (void)SendGarbageCollect();
   3823  } else if (!strcmp(aTopic, "child-cc-request")) {
   3824    (void)SendCycleCollect();
   3825  } else if (!strcmp(aTopic, "child-mmu-request")) {
   3826    (void)SendMinimizeMemoryUsage();
   3827  } else if (!strcmp(aTopic, "child-ghost-request")) {
   3828    (void)SendUnlinkGhosts();
   3829  } else if (!strcmp(aTopic, "last-pb-context-exited")) {
   3830    (void)SendLastPrivateDocShellDestroyed();
   3831  }
   3832 #ifdef ACCESSIBILITY
   3833  else if (aData && !strcmp(aTopic, "a11y-init-or-shutdown")) {
   3834    if (*aData == '1') {
   3835      // Make sure accessibility is running in content process when
   3836      // accessibility gets initiated in chrome process.
   3837      (void)SendActivateA11y(nsAccessibilityService::GetActiveCacheDomains());
   3838    } else {
   3839      // If possible, shut down accessibility in content process when
   3840      // accessibility gets shutdown in chrome process.
   3841      (void)SendShutdownA11y();
   3842    }
   3843  }
   3844 #endif
   3845  else if (!strcmp(aTopic, "cacheservice:empty-cache")) {
   3846    (void)SendNotifyEmptyHTTPCache();
   3847  } else if (!strcmp(aTopic, "intl:app-locales-changed")) {
   3848    nsTArray<nsCString> appLocales;
   3849    LocaleService::GetInstance()->GetAppLocalesAsBCP47(appLocales);
   3850    (void)SendUpdateAppLocales(appLocales);
   3851  } else if (!strcmp(aTopic, "intl:requested-locales-changed")) {
   3852    nsTArray<nsCString> requestedLocales;
   3853    LocaleService::GetInstance()->GetRequestedLocales(requestedLocales);
   3854    (void)SendUpdateRequestedLocales(requestedLocales);
   3855  } else if (!strcmp(aTopic, "cookie-changed") ||
   3856             !strcmp(aTopic, "private-cookie-changed")) {
   3857    MOZ_ASSERT(aSubject, "cookie changed notification must have subject.");
   3858    nsCOMPtr<nsICookieNotification> notification = do_QueryInterface(aSubject);
   3859    MOZ_ASSERT(notification,
   3860               "cookie changed notification must have nsICookieNotification.");
   3861    nsICookieNotification::Action action = notification->GetAction();
   3862 
   3863    PNeckoParent* neckoParent = LoneManagedOrNullAsserts(ManagedPNeckoParent());
   3864    if (!neckoParent) {
   3865      return NS_OK;
   3866    }
   3867    PCookieServiceParent* csParent =
   3868        LoneManagedOrNullAsserts(neckoParent->ManagedPCookieServiceParent());
   3869    if (!csParent) {
   3870      return NS_OK;
   3871    }
   3872    auto* cs = static_cast<CookieServiceParent*>(csParent);
   3873    MOZ_ASSERT(mCookieInContentListCache.IsEmpty());
   3874 
   3875    if (action == nsICookieNotification::COOKIES_BATCH_DELETED) {
   3876      nsCOMPtr<nsIArray> cookieList;
   3877      DebugOnly<nsresult> rv =
   3878          notification->GetBatchDeletedCookies(getter_AddRefs(cookieList));
   3879      NS_ASSERTION(NS_SUCCEEDED(rv) && cookieList, "couldn't get cookie list");
   3880      cs->RemoveBatchDeletedCookies(cookieList);
   3881      return NS_OK;
   3882    }
   3883 
   3884    if (action == nsICookieNotification::ALL_COOKIES_CLEARED) {
   3885      cs->RemoveAll();
   3886      return NS_OK;
   3887    }
   3888 
   3889    // Do not push these cookie updates to the same process they originated
   3890    // from.
   3891    if (cs->ProcessingCookie()) {
   3892      return NS_OK;
   3893    }
   3894 
   3895    nsCOMPtr<nsICookie> xpcCookie;
   3896    nsresult rv = notification->GetCookie(getter_AddRefs(xpcCookie));
   3897    NS_ASSERTION(NS_SUCCEEDED(rv) && xpcCookie, "couldn't get cookie");
   3898 
   3899    // only broadcast the cookie change to content processes that need it
   3900    const Cookie& cookie = xpcCookie->AsCookie();
   3901 
   3902    // do not send cookie if content process does not have similar cookie
   3903    if (!cs->ContentProcessHasCookie(cookie)) {
   3904      return NS_OK;
   3905    }
   3906 
   3907    nsID* operationID = nullptr;
   3908    rv = notification->GetOperationID(&operationID);
   3909    if (NS_WARN_IF(NS_FAILED(rv))) {
   3910      return NS_OK;
   3911    }
   3912 
   3913    if (action == nsICookieNotification::COOKIE_DELETED) {
   3914      cs->RemoveCookie(cookie, operationID);
   3915    } else if (action == nsICookieNotification::COOKIE_ADDED ||
   3916               action == nsICookieNotification::COOKIE_CHANGED) {
   3917      cs->AddCookie(cookie, operationID);
   3918    }
   3919  } else if (!strcmp(aTopic, NS_NETWORK_LINK_TYPE_TOPIC)) {
   3920    UpdateNetworkLinkType();
   3921  } else if (!strcmp(aTopic, "network:socket-process-crashed")) {
   3922    (void)SendSocketProcessCrashed();
   3923  } else if (!strcmp(aTopic, DEFAULT_TIMEZONE_CHANGED_OBSERVER_TOPIC)) {
   3924    (void)SendSystemTimezoneChanged();
   3925  } else if (!strcmp(aTopic, NS_NETWORK_TRR_MODE_CHANGED_TOPIC)) {
   3926    nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
   3927    nsIDNSService::ResolverMode mode;
   3928    dns->GetCurrentTrrMode(&mode);
   3929    nsIDNSService::ResolverMode modeFromPref =
   3930        static_cast<nsIDNSService::ResolverMode>(
   3931            StaticPrefs::network_trr_mode());
   3932    if (modeFromPref > nsIDNSService::MODE_TRROFF) {
   3933      modeFromPref = nsIDNSService::MODE_TRROFF;
   3934    }
   3935    (void)SendSetTRRMode(mode, modeFromPref);
   3936  }
   3937 
   3938  return NS_OK;
   3939 }
   3940 
   3941 uint32_t ContentParent::UpdateNetworkLinkType() {
   3942  uint32_t linkType = nsINetworkLinkService::LINK_TYPE_UNKNOWN;
   3943  nsresult rv;
   3944  nsCOMPtr<nsINetworkLinkService> nls =
   3945      do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv);
   3946  if (NS_SUCCEEDED(rv)) {
   3947    rv = nls->GetLinkType(&linkType);
   3948    if (NS_SUCCEEDED(rv)) {
   3949      (void)SendNetworkLinkTypeChange(linkType);
   3950    }
   3951  }
   3952 
   3953  return linkType;
   3954 }
   3955 
   3956 NS_IMETHODIMP
   3957 ContentParent::GetInterface(const nsIID& aIID, void** aResult) {
   3958  NS_ENSURE_ARG_POINTER(aResult);
   3959 
   3960  if (aIID.Equals(NS_GET_IID(nsIMessageSender))) {
   3961    nsCOMPtr<nsIMessageSender> mm = GetMessageManager();
   3962    mm.forget(aResult);
   3963    return NS_OK;
   3964  }
   3965 
   3966  return NS_NOINTERFACE;
   3967 }
   3968 
   3969 mozilla::ipc::IPCResult ContentParent::RecvInitBackground(
   3970    Endpoint<PBackgroundStarterParent>&& aEndpoint) {
   3971  if (!BackgroundParent::AllocStarter(this, std::move(aEndpoint))) {
   3972    NS_WARNING("BackgroundParent::Alloc failed");
   3973  }
   3974 
   3975  return IPC_OK();
   3976 }
   3977 
   3978 bool ContentParent::CanOpenBrowser(const IPCTabContext& aContext) {
   3979  // (PopupIPCTabContext lets the child process prove that it has access to
   3980  // the app it's trying to open.)
   3981  // On e10s we also allow UnsafeTabContext to allow service workers to open
   3982  // windows. This is enforced in MaybeInvalidTabContext.
   3983  if (aContext.type() != IPCTabContext::TPopupIPCTabContext) {
   3984    MOZ_CRASH_UNLESS_FUZZING(
   3985        "Unexpected IPCTabContext type.  Aborting AllocPBrowserParent.");
   3986    return false;
   3987  }
   3988 
   3989  if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
   3990    const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext();
   3991 
   3992    auto* opener = BrowserParent::GetFrom(popupContext.opener().AsParent());
   3993    if (!opener) {
   3994      MOZ_CRASH_UNLESS_FUZZING(
   3995          "Got null opener from child; aborting AllocPBrowserParent.");
   3996      return false;
   3997    }
   3998  }
   3999 
   4000  MaybeInvalidTabContext tc(aContext);
   4001  if (!tc.IsValid()) {
   4002    NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext.  (%s)  "
   4003                             "Aborting AllocPBrowserParent.",
   4004                             tc.GetInvalidReason())
   4005                 .get());
   4006    return false;
   4007  }
   4008 
   4009  return true;
   4010 }
   4011 
   4012 static bool CloneIsLegal(ContentParent* aCp, CanonicalBrowsingContext& aSource,
   4013                         CanonicalBrowsingContext& aTarget) {
   4014  // Source and target must be in the same BCG
   4015  if (NS_WARN_IF(aSource.Group() != aTarget.Group())) {
   4016    return false;
   4017  }
   4018  // The source and target must be in different toplevel <browser>s
   4019  if (NS_WARN_IF(aSource.Top() == aTarget.Top())) {
   4020    return false;
   4021  }
   4022 
   4023  // Neither source nor target must be toplevel.
   4024  if (NS_WARN_IF(aSource.IsTop()) || NS_WARN_IF(aTarget.IsTop())) {
   4025    return false;
   4026  }
   4027 
   4028  // Both should be embedded by the same process.
   4029  auto* sourceEmbedder = aSource.GetParentWindowContext();
   4030  if (NS_WARN_IF(!sourceEmbedder) ||
   4031      NS_WARN_IF(sourceEmbedder->GetContentParent() != aCp)) {
   4032    return false;
   4033  }
   4034 
   4035  auto* targetEmbedder = aTarget.GetParentWindowContext();
   4036  if (NS_WARN_IF(!targetEmbedder) ||
   4037      NS_WARN_IF(targetEmbedder->GetContentParent() != aCp)) {
   4038    return false;
   4039  }
   4040 
   4041  // All seems sane.
   4042  return true;
   4043 }
   4044 
   4045 mozilla::ipc::IPCResult ContentParent::RecvCloneDocumentTreeInto(
   4046    const MaybeDiscarded<BrowsingContext>& aSource,
   4047    const MaybeDiscarded<BrowsingContext>& aTarget, PrintData&& aPrintData) {
   4048  if (aSource.IsNullOrDiscarded() || aTarget.IsNullOrDiscarded()) {
   4049    return IPC_OK();
   4050  }
   4051 
   4052  if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
   4053    // All existing processes have potentially been slated for removal already,
   4054    // such that any subsequent call to GetNewOrUsedLaunchingBrowserProcess
   4055    // (normally supposed to find an existing process here) will try to create
   4056    // a new process (but fail) that nobody would ever really use. Let's avoid
   4057    // this together with the expensive CloneDocumentTreeInto operation.
   4058    return IPC_OK();
   4059  }
   4060 
   4061  RefPtr source = aSource.get_canonical();
   4062  RefPtr target = aTarget.get_canonical();
   4063 
   4064  if (!CloneIsLegal(this, *source, *target)) {
   4065    return IPC_FAIL(this, "Illegal subframe clone");
   4066  }
   4067 
   4068  ContentParent* cp = source->GetContentParent();
   4069  if (NS_WARN_IF(!cp)) {
   4070    return IPC_OK();
   4071  }
   4072 
   4073  if (NS_WARN_IF(cp->GetRemoteType() == GetRemoteType())) {
   4074    // Wanted to switch to a target browsing context that's already local again.
   4075    // See bug 1676996 for how this can happen.
   4076    //
   4077    // Dropping the switch on the floor seems fine for this case, though we
   4078    // could also try to clone the local document.
   4079    //
   4080    // If the remote type matches & it's in the same group (which was confirmed
   4081    // by CloneIsLegal), it must be the exact same process.
   4082    MOZ_DIAGNOSTIC_ASSERT(cp == this);
   4083    return IPC_OK();
   4084  }
   4085 
   4086  target->CloneDocumentTreeInto(source, cp->GetRemoteType(),
   4087                                std::move(aPrintData));
   4088  return IPC_OK();
   4089 }
   4090 
   4091 mozilla::ipc::IPCResult ContentParent::RecvUpdateRemotePrintSettings(
   4092    const MaybeDiscarded<BrowsingContext>& aTarget, PrintData&& aPrintData) {
   4093  if (aTarget.IsNullOrDiscarded()) {
   4094    return IPC_OK();
   4095  }
   4096 
   4097  auto* target = aTarget.get_canonical();
   4098  auto* bp = target->GetBrowserParent();
   4099  if (NS_WARN_IF(!bp)) {
   4100    return IPC_OK();
   4101  }
   4102 
   4103  (void)bp->SendUpdateRemotePrintSettings(aPrintData);
   4104  return IPC_OK();
   4105 }
   4106 
   4107 mozilla::ipc::IPCResult ContentParent::RecvConstructPopupBrowser(
   4108    ManagedEndpoint<PBrowserParent>&& aBrowserEp,
   4109    ManagedEndpoint<PWindowGlobalParent>&& aWindowEp, const TabId& aTabId,
   4110    const IPCTabContext& aContext, const WindowGlobalInit& aInitialWindowInit,
   4111    const uint32_t& aChromeFlags) {
   4112  MOZ_ASSERT(XRE_IsParentProcess());
   4113 
   4114  if (!CanOpenBrowser(aContext)) {
   4115    return IPC_FAIL(this, "CanOpenBrowser Failed");
   4116  }
   4117 
   4118  RefPtr<CanonicalBrowsingContext> browsingContext =
   4119      CanonicalBrowsingContext::Get(
   4120          aInitialWindowInit.context().mBrowsingContextId);
   4121  if (!browsingContext || browsingContext->IsDiscarded()) {
   4122    return IPC_FAIL(this, "Null or discarded initial BrowsingContext");
   4123  }
   4124  if (!aInitialWindowInit.principal()) {
   4125    return IPC_FAIL(this, "Cannot create without valid initial principal");
   4126  }
   4127 
   4128  if (!ValidatePrincipal(aInitialWindowInit.principal())) {
   4129    LogAndAssertFailedPrincipalValidationInfo(aInitialWindowInit.principal(),
   4130                                              __func__);
   4131  }
   4132 
   4133  if (browsingContext->GetBrowserParent()) {
   4134    return IPC_FAIL(this, "BrowsingContext already has a BrowserParent");
   4135  }
   4136 
   4137  uint32_t chromeFlags = aChromeFlags;
   4138  TabId openerTabId(0);
   4139  ContentParentId openerCpId(0);
   4140  if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
   4141    // CanOpenBrowser has ensured that the IPCTabContext is of
   4142    // type PopupIPCTabContext, and that the opener BrowserParent is
   4143    // reachable.
   4144    const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext();
   4145    auto* opener = BrowserParent::GetFrom(popupContext.opener().AsParent());
   4146    openerTabId = opener->GetTabId();
   4147    openerCpId = opener->Manager()->ChildID();
   4148 
   4149    // We must ensure that the private browsing and remoteness flags
   4150    // match those of the opener.
   4151    nsCOMPtr<nsILoadContext> loadContext = opener->GetLoadContext();
   4152    if (!loadContext) {
   4153      return IPC_FAIL(this, "Missing Opener LoadContext");
   4154    }
   4155    if (loadContext->UsePrivateBrowsing()) {
   4156      chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
   4157    }
   4158    if (loadContext->UseRemoteSubframes()) {
   4159      chromeFlags |= nsIWebBrowserChrome::CHROME_FISSION_WINDOW;
   4160    }
   4161  }
   4162 
   4163  // And because we're allocating a remote browser, of course the
   4164  // window is remote.
   4165  chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
   4166 
   4167  if (NS_WARN_IF(!browsingContext->IsOwnedByProcess(ChildID()))) {
   4168    return IPC_FAIL(this, "BrowsingContext Owned by Incorrect Process!");
   4169  }
   4170 
   4171  MaybeInvalidTabContext tc(aContext);
   4172  MOZ_ASSERT(tc.IsValid());
   4173 
   4174  RefPtr<WindowGlobalParent> initialWindow =
   4175      WindowGlobalParent::CreateDisconnected(aInitialWindowInit);
   4176  if (!initialWindow) {
   4177    return IPC_FAIL(this, "Failed to create WindowGlobalParent");
   4178  }
   4179 
   4180  auto parent = MakeRefPtr<BrowserParent>(this, aTabId, tc.GetTabContext(),
   4181                                          browsingContext, chromeFlags);
   4182 
   4183  // The creation of PBrowser was triggered from content process through
   4184  // window.open().
   4185  // We need to register remote frame with the child generated tab id.
   4186  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
   4187  if (!cpm || !cpm->RegisterRemoteFrame(parent)) {
   4188    return IPC_FAIL(this, "RegisterRemoteFrame Failed");
   4189  }
   4190 
   4191  // Bind the created BrowserParent to IPC to actually link the actor.
   4192  if (NS_WARN_IF(!BindPBrowserEndpoint(std::move(aBrowserEp), parent))) {
   4193    return IPC_FAIL(this, "BindPBrowserEndpoint failed");
   4194  }
   4195 
   4196  if (NS_WARN_IF(!parent->BindPWindowGlobalEndpoint(std::move(aWindowEp),
   4197                                                    initialWindow))) {
   4198    return IPC_FAIL(this, "BindPWindowGlobalEndpoint failed");
   4199  }
   4200 
   4201  browsingContext->SetCurrentBrowserParent(parent);
   4202 
   4203  initialWindow->Init();
   4204 
   4205  // When enabling input event prioritization, input events may preempt other
   4206  // normal priority IPC messages. To prevent the input events preempt
   4207  // PBrowserConstructor, we use an IPC 'RemoteIsReadyToHandleInputEvents' to
   4208  // notify parent that BrowserChild is created. In this case, PBrowser is
   4209  // initiated from content so that we can set BrowserParent as ready to handle
   4210  // input
   4211  parent->SetReadyToHandleInputEvents();
   4212  return IPC_OK();
   4213 }
   4214 
   4215 mozilla::PRemoteSpellcheckEngineParent*
   4216 ContentParent::AllocPRemoteSpellcheckEngineParent() {
   4217  mozilla::RemoteSpellcheckEngineParent* parent =
   4218      new mozilla::RemoteSpellcheckEngineParent();
   4219  return parent;
   4220 }
   4221 
   4222 bool ContentParent::DeallocPRemoteSpellcheckEngineParent(
   4223    PRemoteSpellcheckEngineParent* parent) {
   4224  delete parent;
   4225  return true;
   4226 }
   4227 
   4228 /* static */
   4229 void ContentParent::SendShutdownTimerCallback(nsITimer* aTimer,
   4230                                              void* aClosure) {
   4231  auto* self = static_cast<ContentParent*>(aClosure);
   4232  self->AsyncSendShutDownMessage();
   4233 }
   4234 
   4235 /* static */
   4236 void ContentParent::ForceKillTimerCallback(nsITimer* aTimer, void* aClosure) {
   4237  // We don't want to time out the content process during XPCShell tests. This
   4238  // is the easiest way to ensure that.
   4239  if (PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR")) {
   4240    return;
   4241  }
   4242 
   4243  auto* self = static_cast<ContentParent*>(aClosure);
   4244  self->KillHard("ShutDownKill");
   4245 }
   4246 
   4247 void ContentParent::GeneratePairedMinidump(const char* aReason) {
   4248  // We're about to kill the child process associated with this content.
   4249  // Something has gone wrong to get us here, so we generate a minidump
   4250  // of the parent and child for submission to the crash server unless we're
   4251  // already shutting down.
   4252  if (mCrashReporter &&
   4253      !AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed) &&
   4254      StaticPrefs::dom_ipc_tabs_createKillHardCrashReports_AtStartup()) {
   4255    // GeneratePairedMinidump creates two minidumps for us - the main
   4256    // one is for the content process we're about to kill, and the other
   4257    // one is for the main browser process. That second one is the extra
   4258    // minidump tagging along, so we have to tell the crash reporter that
   4259    // it exists and is being appended.
   4260    nsAutoCString additionalDumps("browser");
   4261    mCrashReporter->AddAnnotationNSCString(
   4262        CrashReporter::Annotation::additional_minidumps, additionalDumps);
   4263    nsDependentCString reason(aReason);
   4264    mCrashReporter->AddAnnotationNSCString(
   4265        CrashReporter::Annotation::ipc_channel_error, reason);
   4266 
   4267    // Generate the report and insert into the queue for submittal.
   4268    if (mCrashReporter->GenerateMinidumpAndPair(mSubprocess, "browser"_ns)) {
   4269      mCrashReporter->FinalizeCrashReport();
   4270      mCreatedPairedMinidumps = true;
   4271    }
   4272  }
   4273 }
   4274 
   4275 void ContentParent::HandleOrphanedMinidump(nsString* aDumpId) {
   4276  if (CrashReporter::FinalizeOrphanedMinidump(
   4277          OtherPid(), GeckoProcessType_Content, aDumpId)) {
   4278    CrashReporterHost::RecordCrash(GeckoProcessType_Content,
   4279                                   nsICrashService::CRASH_TYPE_CRASH, *aDumpId);
   4280  } else {
   4281    NS_WARNING(nsPrintfCString("content process childID = %d pid = %" PRIPID
   4282                               " crashed without leaving a minidump behind",
   4283                               OtherChildID(), OtherPid())
   4284                   .get());
   4285  }
   4286 }
   4287 
   4288 // WARNING: aReason appears in telemetry, so any new value passed in requires
   4289 // data review.
   4290 void ContentParent::KillHard(const char* aReason) {
   4291  AUTO_PROFILER_LABEL("ContentParent::KillHard", OTHER);
   4292 
   4293  // On Windows, calling KillHard multiple times causes problems - the
   4294  // process handle becomes invalid on the first call, causing a second call
   4295  // to crash our process - more details in bug 890840.
   4296  if (mCalledKillHard) {
   4297    return;
   4298  }
   4299  mCalledKillHard = true;
   4300  if (mSendShutdownTimer) {
   4301    mSendShutdownTimer->Cancel();
   4302    mSendShutdownTimer = nullptr;
   4303  }
   4304  if (mForceKillTimer) {
   4305    mForceKillTimer->Cancel();
   4306    mForceKillTimer = nullptr;
   4307  }
   4308 
   4309  RemoveShutdownBlockers();
   4310  nsCString reason = nsDependentCString(aReason);
   4311 
   4312  // If we find mIsNotifiedShutdownSuccess there is no reason to blame this
   4313  // content process, most probably our parent process is just slow in
   4314  // processing its own main thread queue.
   4315  if (!mIsNotifiedShutdownSuccess) {
   4316    GeneratePairedMinidump(aReason);
   4317  } else {
   4318    reason = nsDependentCString("KillHard after IsNotifiedShutdownSuccess.");
   4319  }
   4320  glean::subprocess::kill_hard.Get(reason).Add(1);
   4321 
   4322  ProcessHandle otherProcessHandle;
   4323  if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle)) {
   4324    NS_ERROR("Failed to open child process when attempting kill.");
   4325    if (CanSend()) {
   4326      GetIPCChannel()->InduceConnectionError();
   4327    }
   4328    return;
   4329  }
   4330 
   4331  if (!KillProcess(otherProcessHandle, base::PROCESS_END_KILLED_BY_USER)) {
   4332    if (mCrashReporter) {
   4333      mCrashReporter->DeleteCrashReport();
   4334    }
   4335    NS_WARNING("failed to kill subprocess!");
   4336  }
   4337 
   4338  if (mSubprocess) {
   4339    MOZ_LOG(
   4340        ContentParent::GetLog(), LogLevel::Verbose,
   4341        ("KillHard Subprocess(%s): ContentParent id=%p mSubprocess id=%p "
   4342         "handle "
   4343         "%" PRIuPTR,
   4344         aReason, this, mSubprocess,
   4345         mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
   4346    mSubprocess->SetAlreadyDead();
   4347  }
   4348 
   4349  // After we've killed the remote process, also ensure we induce a connection
   4350  // error in the IPC channel to immediately stop all IPC communication on this
   4351  // channel.
   4352  if (CanSend()) {
   4353    GetIPCChannel()->InduceConnectionError();
   4354  }
   4355 
   4356  // EnsureProcessTerminated has responsibilty for closing otherProcessHandle.
   4357  XRE_GetAsyncIOEventTarget()->Dispatch(
   4358      NewRunnableFunction("EnsureProcessTerminatedRunnable",
   4359                          &ProcessWatcher::EnsureProcessTerminated,
   4360                          otherProcessHandle, /*force=*/true));
   4361 }
   4362 
   4363 void ContentParent::FriendlyName(nsAString& aName, bool aAnonymize) {
   4364  aName.Truncate();
   4365  if (mIsForBrowser) {
   4366    aName.AssignLiteral("Browser");
   4367  } else if (aAnonymize) {
   4368    aName.AssignLiteral("<anonymized-name>");
   4369  } else {
   4370    aName.AssignLiteral("???");
   4371  }
   4372 }
   4373 
   4374 mozilla::ipc::IPCResult ContentParent::RecvInitCrashReporter(
   4375    const CrashReporter::CrashReporterInitArgs& aInitArgs) {
   4376  mCrashReporter = MakeUnique<CrashReporterHost>(GeckoProcessType_Content,
   4377                                                 OtherPid(), aInitArgs);
   4378  return IPC_OK();
   4379 }
   4380 
   4381 hal_sandbox::PHalParent* ContentParent::AllocPHalParent() {
   4382  return hal_sandbox::CreateHalParent();
   4383 }
   4384 
   4385 bool ContentParent::DeallocPHalParent(hal_sandbox::PHalParent* aHal) {
   4386  delete aHal;
   4387  return true;
   4388 }
   4389 
   4390 devtools::PHeapSnapshotTempFileHelperParent*
   4391 ContentParent::AllocPHeapSnapshotTempFileHelperParent() {
   4392  return devtools::HeapSnapshotTempFileHelperParent::Create();
   4393 }
   4394 
   4395 bool ContentParent::DeallocPHeapSnapshotTempFileHelperParent(
   4396    devtools::PHeapSnapshotTempFileHelperParent* aHeapSnapshotHelper) {
   4397  delete aHeapSnapshotHelper;
   4398  return true;
   4399 }
   4400 
   4401 bool ContentParent::SendRequestMemoryReport(
   4402    const uint32_t& aGeneration, const bool& aAnonymize,
   4403    const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile) {
   4404  // This automatically cancels the previous request.
   4405  mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
   4406  // If we run the callback in response to a reply, then by definition |this|
   4407  // is still alive, so the ref pointer is redundant, but it seems easier
   4408  // to hold a strong reference than to worry about that.
   4409  RefPtr<ContentParent> self(this);
   4410  PContentParent::SendRequestMemoryReport(
   4411      aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile,
   4412      [&, self](const uint32_t& aGeneration2) {
   4413        if (self->mMemoryReportRequest) {
   4414          self->mMemoryReportRequest->Finish(aGeneration2);
   4415          self->mMemoryReportRequest = nullptr;
   4416        }
   4417      },
   4418      [&, self](mozilla::ipc::ResponseRejectReason) {
   4419        self->mMemoryReportRequest = nullptr;
   4420      });
   4421  return IPC_OK();
   4422 }
   4423 
   4424 mozilla::ipc::IPCResult ContentParent::RecvAddMemoryReport(
   4425    const MemoryReport& aReport) {
   4426  if (mMemoryReportRequest) {
   4427    mMemoryReportRequest->RecvReport(aReport);
   4428  }
   4429  return IPC_OK();
   4430 }
   4431 
   4432 PCycleCollectWithLogsParent* ContentParent::AllocPCycleCollectWithLogsParent(
   4433    const bool& aDumpAllTraces, const FileDescriptor& aGCLog,
   4434    const FileDescriptor& aCCLog) {
   4435  MOZ_CRASH("Don't call this; use ContentParent::CycleCollectWithLogs");
   4436 }
   4437 
   4438 bool ContentParent::DeallocPCycleCollectWithLogsParent(
   4439    PCycleCollectWithLogsParent* aActor) {
   4440  delete aActor;
   4441  return true;
   4442 }
   4443 
   4444 bool ContentParent::CycleCollectWithLogs(
   4445    bool aDumpAllTraces, nsICycleCollectorLogSink* aSink,
   4446    nsIDumpGCAndCCLogsCallback* aCallback) {
   4447  return CycleCollectWithLogsParent::AllocAndSendConstructor(
   4448      this, aDumpAllTraces, aSink, aCallback);
   4449 }
   4450 
   4451 PScriptCacheParent* ContentParent::AllocPScriptCacheParent(
   4452    const FileDescOrError& cacheFile, const bool& wantCacheData) {
   4453  return new loader::ScriptCacheParent(wantCacheData);
   4454 }
   4455 
   4456 bool ContentParent::DeallocPScriptCacheParent(PScriptCacheParent* cache) {
   4457  delete static_cast<loader::ScriptCacheParent*>(cache);
   4458  return true;
   4459 }
   4460 
   4461 already_AddRefed<PNeckoParent> ContentParent::AllocPNeckoParent() {
   4462  RefPtr<NeckoParent> actor = new NeckoParent();
   4463  return actor.forget();
   4464 }
   4465 
   4466 mozilla::ipc::IPCResult ContentParent::RecvInitStreamFilter(
   4467    const uint64_t& aChannelId, const nsAString& aAddonId,
   4468    InitStreamFilterResolver&& aResolver) {
   4469  extensions::StreamFilterParent::Create(this, aChannelId, aAddonId)
   4470      ->Then(
   4471          GetCurrentSerialEventTarget(), __func__,
   4472          [aResolver](mozilla::ipc::Endpoint<PStreamFilterChild>&& aEndpoint) {
   4473            aResolver(std::move(aEndpoint));
   4474          },
   4475          [aResolver](bool aDummy) {
   4476            aResolver(mozilla::ipc::Endpoint<PStreamFilterChild>());
   4477          });
   4478 
   4479  return IPC_OK();
   4480 }
   4481 
   4482 mozilla::ipc::IPCResult ContentParent::RecvAddSecurityState(
   4483    const MaybeDiscarded<WindowContext>& aContext, uint32_t aStateFlags) {
   4484  if (aContext.IsNullOrDiscarded()) {
   4485    return IPC_OK();
   4486  }
   4487 
   4488  aContext.get()->AddSecurityState(aStateFlags);
   4489  return IPC_OK();
   4490 }
   4491 
   4492 already_AddRefed<PExternalHelperAppParent>
   4493 ContentParent::AllocPExternalHelperAppParent(
   4494    nsIURI* uri, const mozilla::net::LoadInfoArgs& aLoadInfoArgs,
   4495    const nsACString& aMimeContentType, const nsACString& aContentDisposition,
   4496    const uint32_t& aContentDispositionHint,
   4497    const nsAString& aContentDispositionFilename, const bool& aForceSave,
   4498    const int64_t& aContentLength, const bool& aWasFileChannel,
   4499    nsIURI* aReferrer, const MaybeDiscarded<BrowsingContext>& aContext) {
   4500  RefPtr<ExternalHelperAppParent> parent = new ExternalHelperAppParent(
   4501      uri, aContentLength, aWasFileChannel, aContentDisposition,
   4502      aContentDispositionHint, aContentDispositionFilename);
   4503  return parent.forget();
   4504 }
   4505 
   4506 mozilla::ipc::IPCResult ContentParent::RecvPExternalHelperAppConstructor(
   4507    PExternalHelperAppParent* actor, nsIURI* uri,
   4508    const LoadInfoArgs& loadInfoArgs, const nsACString& aMimeContentType,
   4509    const nsACString& aContentDisposition,
   4510    const uint32_t& aContentDispositionHint,
   4511    const nsAString& aContentDispositionFilename, const bool& aForceSave,
   4512    const int64_t& aContentLength, const bool& aWasFileChannel,
   4513    nsIURI* aReferrer, const MaybeDiscarded<BrowsingContext>& aContext) {
   4514  BrowsingContext* context = aContext.IsDiscarded() ? nullptr : aContext.get();
   4515  if (!static_cast<ExternalHelperAppParent*>(actor)->Init(
   4516          loadInfoArgs, aMimeContentType, aForceSave, aReferrer, context)) {
   4517    return IPC_FAIL(this, "Init failed.");
   4518  }
   4519  return IPC_OK();
   4520 }
   4521 
   4522 already_AddRefed<PHandlerServiceParent>
   4523 ContentParent::AllocPHandlerServiceParent() {
   4524  RefPtr<HandlerServiceParent> actor = new HandlerServiceParent();
   4525  return actor.forget();
   4526 }
   4527 
   4528 media::PMediaParent* ContentParent::AllocPMediaParent() {
   4529  return media::AllocPMediaParent();
   4530 }
   4531 
   4532 bool ContentParent::DeallocPMediaParent(media::PMediaParent* aActor) {
   4533  return media::DeallocPMediaParent(aActor);
   4534 }
   4535 
   4536 #ifdef MOZ_WEBSPEECH
   4537 already_AddRefed<PSpeechSynthesisParent>
   4538 ContentParent::AllocPSpeechSynthesisParent() {
   4539  if (!StaticPrefs::media_webspeech_synth_enabled()) {
   4540    return nullptr;
   4541  }
   4542  RefPtr<SpeechSynthesisParent> actor = new SpeechSynthesisParent();
   4543  return actor.forget();
   4544 }
   4545 
   4546 mozilla::ipc::IPCResult ContentParent::RecvPSpeechSynthesisConstructor(
   4547    PSpeechSynthesisParent* aActor) {
   4548  if (!static_cast<SpeechSynthesisParent*>(aActor)->SendInit()) {
   4549    return IPC_FAIL(this, "SpeechSynthesisParent::SendInit failed.");
   4550  }
   4551  return IPC_OK();
   4552 }
   4553 #endif
   4554 
   4555 mozilla::ipc::IPCResult ContentParent::RecvStartVisitedQueries(
   4556    const nsTArray<RefPtr<nsIURI>>& aUris) {
   4557  nsCOMPtr<IHistory> history = components::History::Service();
   4558  if (!history) {
   4559    return IPC_OK();
   4560  }
   4561  for (const auto& uri : aUris) {
   4562    if (NS_WARN_IF(!uri)) {
   4563      continue;
   4564    }
   4565    history->ScheduleVisitedQuery(uri, this);
   4566  }
   4567  return IPC_OK();
   4568 }
   4569 
   4570 mozilla::ipc::IPCResult ContentParent::RecvSetURITitle(nsIURI* uri,
   4571                                                       const nsAString& title) {
   4572  if (!uri) {
   4573    return IPC_FAIL(this, "uri must not be null.");
   4574  }
   4575  nsCOMPtr<IHistory> history = components::History::Service();
   4576  if (history) {
   4577    history->SetURITitle(uri, title);
   4578  }
   4579  return IPC_OK();
   4580 }
   4581 
   4582 mozilla::ipc::IPCResult ContentParent::RecvIsSecureURI(
   4583    nsIURI* aURI, const OriginAttributes& aOriginAttributes,
   4584    bool* aIsSecureURI) {
   4585  nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID));
   4586  if (!sss) {
   4587    return IPC_FAIL(this, "Failed to get nsISiteSecurityService.");
   4588  }
   4589  if (!aURI) {
   4590    return IPC_FAIL(this, "aURI must not be null.");
   4591  }
   4592  nsresult rv = sss->IsSecureURI(aURI, aOriginAttributes, aIsSecureURI);
   4593  if (NS_FAILED(rv)) {
   4594    return IPC_FAIL(this, "IsSecureURI failed.");
   4595  }
   4596  return IPC_OK();
   4597 }
   4598 
   4599 mozilla::ipc::IPCResult ContentParent::RecvAccumulateMixedContentHSTS(
   4600    nsIURI* aURI, const bool& aActive,
   4601    const OriginAttributes& aOriginAttributes) {
   4602  if (!aURI) {
   4603    return IPC_FAIL(this, "aURI must not be null.");
   4604  }
   4605  nsMixedContentBlocker::AccumulateMixedContentHSTS(aURI, aActive,
   4606                                                    aOriginAttributes);
   4607  return IPC_OK();
   4608 }
   4609 
   4610 mozilla::ipc::IPCResult ContentParent::RecvLoadURIExternal(
   4611    nsIURI* uri, nsIPrincipal* aTriggeringPrincipal,
   4612    nsIPrincipal* aRedirectPrincipal,
   4613    const MaybeDiscarded<BrowsingContext>& aContext,
   4614    bool aWasExternallyTriggered, bool aHasValidUserGestureActivation,
   4615    bool aNewWindowTarget) {
   4616  if (aContext.IsDiscarded()) {
   4617    return IPC_OK();
   4618  }
   4619 
   4620  nsCOMPtr<nsIExternalProtocolService> extProtService(
   4621      do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
   4622  if (!extProtService) {
   4623    return IPC_OK();
   4624  }
   4625 
   4626  if (!uri) {
   4627    return IPC_FAIL(this, "uri must not be null.");
   4628  }
   4629 
   4630  BrowsingContext* bc = aContext.get();
   4631  extProtService->LoadURI(uri, aTriggeringPrincipal, aRedirectPrincipal, bc,
   4632                          aWasExternallyTriggered,
   4633                          aHasValidUserGestureActivation, aNewWindowTarget);
   4634  return IPC_OK();
   4635 }
   4636 
   4637 mozilla::ipc::IPCResult ContentParent::RecvExtProtocolChannelConnectParent(
   4638    const uint64_t& registrarId) {
   4639  nsresult rv;
   4640 
   4641  // First get the real channel created before redirect on the parent.
   4642  nsCOMPtr<nsIChannel> channel;
   4643  rv = NS_LinkRedirectChannels(registrarId, nullptr, getter_AddRefs(channel));
   4644  NS_ENSURE_SUCCESS(rv, IPC_OK());
   4645 
   4646  nsCOMPtr<nsIParentChannel> parent = do_QueryInterface(channel, &rv);
   4647  NS_ENSURE_SUCCESS(rv, IPC_OK());
   4648 
   4649  // The channel itself is its own (faked) parent, link it.
   4650  rv = NS_LinkRedirectChannels(registrarId, parent, getter_AddRefs(channel));
   4651  NS_ENSURE_SUCCESS(rv, IPC_OK());
   4652 
   4653  // Signal the parent channel that it's a redirect-to parent.  This will
   4654  // make AsyncOpen on it do nothing (what we want).
   4655  // Yes, this is a bit of a hack, but I don't think it's necessary to invent
   4656  // a new interface just to set this flag on the channel.
   4657  parent->SetParentListener(nullptr);
   4658 
   4659  return IPC_OK();
   4660 }
   4661 
   4662 mozilla::ipc::IPCResult ContentParent::RecvSyncMessage(
   4663    const nsAString& aMsg, const ClonedMessageData& aData,
   4664    nsTArray<UniquePtr<StructuredCloneData>>* aRetvals) {
   4665  AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("ContentParent::RecvSyncMessage",
   4666                                             OTHER, aMsg);
   4667  MMPrinter::Print("ContentParent::RecvSyncMessage", aMsg, aData);
   4668 
   4669  RefPtr<nsFrameMessageManager> ppm = mMessageManager;
   4670  if (ppm) {
   4671    ipc::StructuredCloneData data;
   4672    ipc::UnpackClonedMessageData(aData, data);
   4673 
   4674    ppm->ReceiveMessage(ppm, nullptr, aMsg, true, &data, aRetvals,
   4675                        IgnoreErrors());
   4676  }
   4677  return IPC_OK();
   4678 }
   4679 
   4680 mozilla::ipc::IPCResult ContentParent::RecvAsyncMessage(
   4681    const nsAString& aMsg, const ClonedMessageData& aData) {
   4682  AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("ContentParent::RecvAsyncMessage",
   4683                                             OTHER, aMsg);
   4684  MMPrinter::Print("ContentParent::RecvAsyncMessage", aMsg, aData);
   4685 
   4686  RefPtr<nsFrameMessageManager> ppm = mMessageManager;
   4687  if (ppm) {
   4688    ipc::StructuredCloneData data;
   4689    ipc::UnpackClonedMessageData(aData, data);
   4690 
   4691    ppm->ReceiveMessage(ppm, nullptr, aMsg, false, &data, nullptr,
   4692                        IgnoreErrors());
   4693  }
   4694  return IPC_OK();
   4695 }
   4696 
   4697 MOZ_CAN_RUN_SCRIPT
   4698 static int32_t AddGeolocationListener(
   4699    nsIDOMGeoPositionCallback* watcher,
   4700    nsIDOMGeoPositionErrorCallback* errorCallBack, bool highAccuracy) {
   4701  RefPtr<Geolocation> geo = Geolocation::NonWindowSingleton();
   4702 
   4703  UniquePtr<PositionOptions> options = MakeUnique<PositionOptions>();
   4704  options->mTimeout = 0;
   4705  options->mMaximumAge = 0;
   4706  options->mEnableHighAccuracy = highAccuracy;
   4707  return geo->WatchPosition(watcher, errorCallBack, std::move(options));
   4708 }
   4709 
   4710 mozilla::ipc::IPCResult ContentParent::RecvAddGeolocationListener(
   4711    const bool& aHighAccuracy) {
   4712  // To ensure no geolocation updates are skipped, we always force the
   4713  // creation of a new listener.
   4714  RecvRemoveGeolocationListener();
   4715  mGeolocationWatchID = AddGeolocationListener(this, this, aHighAccuracy);
   4716  return IPC_OK();
   4717 }
   4718 
   4719 mozilla::ipc::IPCResult ContentParent::RecvRemoveGeolocationListener() {
   4720  if (mGeolocationWatchID != -1) {
   4721    RefPtr<Geolocation> geo = Geolocation::NonWindowSingleton();
   4722    if (geo) {
   4723      geo->ClearWatch(mGeolocationWatchID);
   4724    }
   4725    mGeolocationWatchID = -1;
   4726  }
   4727  return IPC_OK();
   4728 }
   4729 
   4730 mozilla::ipc::IPCResult ContentParent::RecvSetGeolocationHigherAccuracy(
   4731    const bool& aEnable) {
   4732  // This should never be called without a listener already present,
   4733  // so this check allows us to forgo securing privileges.
   4734  if (mGeolocationWatchID != -1) {
   4735    RecvRemoveGeolocationListener();
   4736    mGeolocationWatchID = AddGeolocationListener(this, this, aEnable);
   4737  }
   4738  return IPC_OK();
   4739 }
   4740 
   4741 NS_IMETHODIMP
   4742 ContentParent::HandleEvent(nsIDOMGeoPosition* postion) {
   4743  (void)SendGeolocationUpdate(postion);
   4744  return NS_OK;
   4745 }
   4746 
   4747 NS_IMETHODIMP
   4748 ContentParent::HandleEvent(GeolocationPositionError* positionError) {
   4749  (void)SendGeolocationError(positionError->Code());
   4750  return NS_OK;
   4751 }
   4752 
   4753 mozilla::ipc::IPCResult ContentParent::RecvConsoleMessage(
   4754    const nsAString& aMessage) {
   4755  nsresult rv;
   4756  nsCOMPtr<nsIConsoleService> consoleService =
   4757      do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
   4758  if (NS_SUCCEEDED(rv)) {
   4759    RefPtr<nsConsoleMessage> msg(new nsConsoleMessage(aMessage));
   4760    msg->SetIsForwardedFromContentProcess(true);
   4761    consoleService->LogMessageWithMode(msg, nsIConsoleService::SuppressLog);
   4762  }
   4763  return IPC_OK();
   4764 }
   4765 
   4766 mozilla::ipc::IPCResult ContentParent::RecvReportFrameTimingData(
   4767    const LoadInfoArgs& loadInfoArgs, const nsAString& entryName,
   4768    const nsAString& initiatorType, UniquePtr<PerformanceTimingData>&& aData) {
   4769  if (!aData) {
   4770    return IPC_FAIL(this, "aData should not be null");
   4771  }
   4772 
   4773  RefPtr<WindowGlobalParent> parent =
   4774      WindowGlobalParent::GetByInnerWindowId(loadInfoArgs.innerWindowID());
   4775  if (!parent || !parent->GetContentParent()) {
   4776    return IPC_OK();
   4777  }
   4778 
   4779  MOZ_ASSERT(parent->GetContentParent() != this,
   4780             "No need to bounce around if in the same process");
   4781 
   4782  (void)parent->GetContentParent()->SendReportFrameTimingData(
   4783      loadInfoArgs, entryName, initiatorType, aData);
   4784  return IPC_OK();
   4785 }
   4786 
   4787 mozilla::ipc::IPCResult ContentParent::RecvScriptError(
   4788    const nsAString& aMessage, const nsACString& aSourceName,
   4789    const uint32_t& aLineNumber, const uint32_t& aColNumber,
   4790    const uint32_t& aFlags, const nsACString& aCategory,
   4791    const bool& aIsFromPrivateWindow, const uint64_t& aInnerWindowId,
   4792    const bool& aIsFromChromeContext) {
   4793  return RecvScriptErrorInternal(aMessage, aSourceName, aLineNumber, aColNumber,
   4794                                 aFlags, aCategory, aIsFromPrivateWindow,
   4795                                 aIsFromChromeContext);
   4796 }
   4797 
   4798 mozilla::ipc::IPCResult ContentParent::RecvScriptErrorWithStack(
   4799    const nsAString& aMessage, const nsACString& aSourceName,
   4800    const uint32_t& aLineNumber, const uint32_t& aColNumber,
   4801    const uint32_t& aFlags, const nsACString& aCategory,
   4802    const bool& aIsFromPrivateWindow, const bool& aIsFromChromeContext,
   4803    const ClonedMessageData& aStack) {
   4804  return RecvScriptErrorInternal(aMessage, aSourceName, aLineNumber, aColNumber,
   4805                                 aFlags, aCategory, aIsFromPrivateWindow,
   4806                                 aIsFromChromeContext, &aStack);
   4807 }
   4808 
   4809 mozilla::ipc::IPCResult ContentParent::RecvScriptErrorInternal(
   4810    const nsAString& aMessage, const nsACString& aSourceName,
   4811    const uint32_t& aLineNumber, const uint32_t& aColNumber,
   4812    const uint32_t& aFlags, const nsACString& aCategory,
   4813    const bool& aIsFromPrivateWindow, const bool& aIsFromChromeContext,
   4814    const ClonedMessageData* aStack) {
   4815  nsresult rv;
   4816  nsCOMPtr<nsIConsoleService> consoleService =
   4817      do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
   4818  if (NS_FAILED(rv)) {
   4819    return IPC_OK();
   4820  }
   4821 
   4822  nsCOMPtr<nsIScriptError> msg;
   4823 
   4824  if (aStack) {
   4825    StructuredCloneData data;
   4826    UnpackClonedMessageData(*aStack, data);
   4827 
   4828    AutoJSAPI jsapi;
   4829    if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) {
   4830      MOZ_CRASH();
   4831    }
   4832    JSContext* cx = jsapi.cx();
   4833 
   4834    JS::Rooted<JS::Value> stack(cx);
   4835    ErrorResult rv;
   4836    data.Read(cx, &stack, rv);
   4837    if (rv.Failed() || !stack.isObject()) {
   4838      rv.SuppressException();
   4839      return IPC_OK();
   4840    }
   4841 
   4842    JS::Rooted<JSObject*> stackObj(cx, &stack.toObject());
   4843    if (!JS::IsUnwrappedSavedFrame(stackObj)) {
   4844      return IPC_FAIL(this, "Unexpected object");
   4845    }
   4846 
   4847    JS::Rooted<JSObject*> stackGlobal(cx, JS::GetNonCCWObjectGlobal(stackObj));
   4848    msg = new nsScriptErrorWithStack(JS::NothingHandleValue, stackObj,
   4849                                     stackGlobal);
   4850  } else {
   4851    msg = new nsScriptError();
   4852  }
   4853 
   4854  rv = msg->Init(aMessage, aSourceName, aLineNumber, aColNumber, aFlags,
   4855                 aCategory, aIsFromPrivateWindow, aIsFromChromeContext);
   4856  if (NS_FAILED(rv)) return IPC_OK();
   4857 
   4858  msg->SetIsForwardedFromContentProcess(true);
   4859 
   4860  consoleService->LogMessageWithMode(msg, nsIConsoleService::SuppressLog);
   4861  return IPC_OK();
   4862 }
   4863 
   4864 bool ContentParent::DoLoadMessageManagerScript(const nsAString& aURL,
   4865                                               bool aRunInGlobalScope) {
   4866  MOZ_ASSERT(!aRunInGlobalScope);
   4867  return SendLoadProcessScript(aURL);
   4868 }
   4869 
   4870 nsresult ContentParent::DoSendAsyncMessage(const nsAString& aMessage,
   4871                                           StructuredCloneData& aData) {
   4872  ClonedMessageData data;
   4873  if (!BuildClonedMessageData(aData, data)) {
   4874    return NS_ERROR_DOM_DATA_CLONE_ERR;
   4875  }
   4876  if (!SendAsyncMessage(aMessage, data)) {
   4877    return NS_ERROR_UNEXPECTED;
   4878  }
   4879  return NS_OK;
   4880 }
   4881 
   4882 mozilla::ipc::IPCResult ContentParent::RecvCopyFavicon(
   4883    nsIURI* aOldURI, nsIURI* aNewURI, const bool& aInPrivateBrowsing) {
   4884  if (!aOldURI) {
   4885    return IPC_FAIL(this, "aOldURI should not be null");
   4886  }
   4887  if (!aNewURI) {
   4888    return IPC_FAIL(this, "aNewURI should not be null");
   4889  }
   4890 
   4891  nsDocShell::CopyFavicon(aOldURI, aNewURI, aInPrivateBrowsing);
   4892  return IPC_OK();
   4893 }
   4894 
   4895 mozilla::ipc::IPCResult ContentParent::RecvFindImageText(
   4896    IPCImage&& aImage, nsTArray<nsCString>&& aLanguages,
   4897    FindImageTextResolver&& aResolver) {
   4898  if (!TextRecognition::IsSupported() ||
   4899      !Preferences::GetBool("dom.text-recognition.enabled")) {
   4900    return IPC_FAIL(this, "Text recognition not available.");
   4901  }
   4902 
   4903  RefPtr<DataSourceSurface> surf = nsContentUtils::IPCImageToSurface(aImage);
   4904  if (!surf) {
   4905    aResolver(TextRecognitionResultOrError("Failed to read image"_ns));
   4906    return IPC_OK();
   4907  }
   4908  TextRecognition::FindText(*surf, aLanguages)
   4909      ->Then(
   4910          GetCurrentSerialEventTarget(), __func__,
   4911          [resolver = std::move(aResolver)](
   4912              TextRecognition::NativePromise::ResolveOrRejectValue&& aValue) {
   4913            if (aValue.IsResolve()) {
   4914              resolver(TextRecognitionResultOrError(aValue.ResolveValue()));
   4915            } else {
   4916              resolver(TextRecognitionResultOrError(aValue.RejectValue()));
   4917            }
   4918          });
   4919  return IPC_OK();
   4920 }
   4921 
   4922 bool ContentParent::ShouldContinueFromReplyTimeout() {
   4923  RefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
   4924  return !monitor || !monitor->ShouldTimeOutCPOWs();
   4925 }
   4926 
   4927 mozilla::ipc::IPCResult ContentParent::RecvAddIdleObserver(
   4928    const uint64_t& aObserverId, const uint32_t& aIdleTimeInS) {
   4929  nsresult rv;
   4930  nsCOMPtr<nsIUserIdleService> idleService =
   4931      do_GetService("@mozilla.org/widget/useridleservice;1", &rv);
   4932  NS_ENSURE_SUCCESS(rv, IPC_FAIL(this, "Failed to get UserIdleService."));
   4933 
   4934  RefPtr<ParentIdleListener> listener =
   4935      new ParentIdleListener(this, aObserverId, aIdleTimeInS);
   4936  rv = idleService->AddIdleObserver(listener, aIdleTimeInS);
   4937  NS_ENSURE_SUCCESS(rv, IPC_FAIL(this, "AddIdleObserver failed."));
   4938  mIdleListeners.AppendElement(listener);
   4939  return IPC_OK();
   4940 }
   4941 
   4942 mozilla::ipc::IPCResult ContentParent::RecvRemoveIdleObserver(
   4943    const uint64_t& aObserverId, const uint32_t& aIdleTimeInS) {
   4944  RefPtr<ParentIdleListener> listener;
   4945  for (int32_t i = mIdleListeners.Length() - 1; i >= 0; --i) {
   4946    listener = static_cast<ParentIdleListener*>(mIdleListeners[i].get());
   4947    if (listener->mObserver == aObserverId && listener->mTime == aIdleTimeInS) {
   4948      nsresult rv;
   4949      nsCOMPtr<nsIUserIdleService> idleService =
   4950          do_GetService("@mozilla.org/widget/useridleservice;1", &rv);
   4951      NS_ENSURE_SUCCESS(rv, IPC_FAIL(this, "Failed to get UserIdleService."));
   4952      idleService->RemoveIdleObserver(listener, aIdleTimeInS);
   4953      mIdleListeners.RemoveElementAt(i);
   4954      break;
   4955    }
   4956  }
   4957  return IPC_OK();
   4958 }
   4959 
   4960 mozilla::ipc::IPCResult ContentParent::RecvBackUpXResources(
   4961    const FileDescriptor& aXSocketFd) {
   4962 #ifndef MOZ_X11
   4963  MOZ_CRASH("This message only makes sense on X11 platforms");
   4964 #else
   4965  MOZ_ASSERT(!mChildXSocketFdDup, "Already backed up X resources??");
   4966  if (aXSocketFd.IsValid()) {
   4967    mChildXSocketFdDup = aXSocketFd.ClonePlatformHandle();
   4968  }
   4969 #endif
   4970  return IPC_OK();
   4971 }
   4972 
   4973 class AnonymousTemporaryFileRequestor final : public Runnable {
   4974 public:
   4975  AnonymousTemporaryFileRequestor(ContentParent* aCP, const uint64_t& aID)
   4976      : Runnable("dom::AnonymousTemporaryFileRequestor"),
   4977        mCP(aCP),
   4978        mID(aID),
   4979        mRv(NS_OK),
   4980        mPRFD(nullptr) {}
   4981 
   4982  NS_IMETHOD Run() override {
   4983    if (NS_IsMainThread()) {
   4984      FileDescOrError result;
   4985      if (NS_WARN_IF(NS_FAILED(mRv))) {
   4986        // Returning false will kill the child process; instead
   4987        // propagate the error and let the child handle it.
   4988        result = mRv;
   4989      } else {
   4990        result = FileDescriptor(FileDescriptor::PlatformHandleType(
   4991            PR_FileDesc2NativeHandle(mPRFD)));
   4992        // The FileDescriptor object owns a duplicate of the file handle; we
   4993        // must close the original (and clean up the NSPR descriptor).
   4994        PR_Close(mPRFD);
   4995      }
   4996      (void)mCP->SendProvideAnonymousTemporaryFile(mID, result);
   4997      // It's important to release this reference while wr're on the main
   4998      // thread!
   4999      mCP = nullptr;
   5000    } else {
   5001      mRv = NS_OpenAnonymousTemporaryFile(&mPRFD);
   5002      NS_DispatchToMainThread(this);
   5003    }
   5004    return NS_OK;
   5005  }
   5006 
   5007 private:
   5008  RefPtr<ContentParent> mCP;
   5009  uint64_t mID;
   5010  nsresult mRv;
   5011  PRFileDesc* mPRFD;
   5012 };
   5013 
   5014 mozilla::ipc::IPCResult ContentParent::RecvRequestAnonymousTemporaryFile(
   5015    const uint64_t& aID) {
   5016  // Make sure to send a callback to the child if we bail out early.
   5017  nsresult rv = NS_OK;
   5018  RefPtr<ContentParent> self(this);
   5019  auto autoNotifyChildOnError = MakeScopeExit([&, self]() {
   5020    if (NS_FAILED(rv)) {
   5021      FileDescOrError result(rv);
   5022      (void)self->SendProvideAnonymousTemporaryFile(aID, result);
   5023    }
   5024  });
   5025 
   5026  // We use a helper runnable to open the anonymous temporary file on the IO
   5027  // thread.  The same runnable will call us back on the main thread when the
   5028  // file has been opened.
   5029  nsCOMPtr<nsIEventTarget> target =
   5030      do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
   5031  if (!target) {
   5032    return IPC_OK();
   5033  }
   5034 
   5035  rv = target->Dispatch(new AnonymousTemporaryFileRequestor(this, aID),
   5036                        NS_DISPATCH_NORMAL);
   5037  if (NS_WARN_IF(NS_FAILED(rv))) {
   5038    return IPC_OK();
   5039  }
   5040 
   5041  rv = NS_OK;
   5042  return IPC_OK();
   5043 }
   5044 
   5045 mozilla::ipc::IPCResult ContentParent::RecvCreateAudioIPCConnection(
   5046    CreateAudioIPCConnectionResolver&& aResolver) {
   5047  FileDescriptor fd = CubebUtils::CreateAudioIPCConnection();
   5048  FileDescOrError result;
   5049  if (fd.IsValid()) {
   5050    result = fd;
   5051  } else {
   5052    result = NS_ERROR_FAILURE;
   5053  }
   5054  aResolver(result);
   5055  return IPC_OK();
   5056 }
   5057 
   5058 already_AddRefed<extensions::PExtensionsParent>
   5059 ContentParent::AllocPExtensionsParent() {
   5060  return MakeAndAddRef<extensions::ExtensionsParent>();
   5061 }
   5062 
   5063 void ContentParent::NotifyUpdatedDictionaries() {
   5064  RefPtr<mozSpellChecker> spellChecker(mozSpellChecker::Create());
   5065  MOZ_ASSERT(spellChecker, "No spell checker?");
   5066 
   5067  nsTArray<nsCString> dictionaries;
   5068  spellChecker->GetDictionaryList(&dictionaries);
   5069 
   5070  for (auto* cp : AllProcesses(eLive)) {
   5071    (void)cp->SendUpdateDictionaryList(dictionaries);
   5072  }
   5073 }
   5074 
   5075 void ContentParent::NotifyUpdatedFonts(bool aFullRebuild) {
   5076  if (gfxPlatformFontList::PlatformFontList()->SharedFontList()) {
   5077    for (auto* cp : AllProcesses(eLive)) {
   5078      (void)cp->SendRebuildFontList(aFullRebuild);
   5079    }
   5080    return;
   5081  }
   5082 
   5083  SystemFontList fontList;
   5084  gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList);
   5085 
   5086  for (auto* cp : AllProcesses(eLive)) {
   5087    (void)cp->SendUpdateFontList(fontList);
   5088  }
   5089 }
   5090 
   5091 #ifdef MOZ_WEBRTC
   5092 PWebrtcGlobalParent* ContentParent::AllocPWebrtcGlobalParent() {
   5093  return WebrtcGlobalParent::Alloc();
   5094 }
   5095 
   5096 bool ContentParent::DeallocPWebrtcGlobalParent(PWebrtcGlobalParent* aActor) {
   5097  WebrtcGlobalParent::Dealloc(static_cast<WebrtcGlobalParent*>(aActor));
   5098  return true;
   5099 }
   5100 #endif
   5101 
   5102 PContentPermissionRequestParent*
   5103 ContentParent::AllocPContentPermissionRequestParent(
   5104    const nsTArray<PermissionRequest>& aRequests, nsIPrincipal* aPrincipal,
   5105    nsIPrincipal* aTopLevelPrincipal, const bool& aIsHandlingUserInput,
   5106    const bool& aMaybeUnsafePermissionDelegate, const TabId& aTabId) {
   5107  RefPtr<BrowserParent> tp;
   5108  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
   5109  if (cpm) {
   5110    tp =
   5111        cpm->GetTopLevelBrowserParentByProcessAndTabId(this->ChildID(), aTabId);
   5112  }
   5113  if (!tp) {
   5114    return nullptr;
   5115  }
   5116 
   5117  nsIPrincipal* topPrincipal = aTopLevelPrincipal;
   5118  if (!topPrincipal) {
   5119    nsCOMPtr<nsIPrincipal> principal = tp->GetContentPrincipal();
   5120    topPrincipal = principal;
   5121  }
   5122  return nsContentPermissionUtils::CreateContentPermissionRequestParent(
   5123      aRequests, tp->GetOwnerElement(), aPrincipal, topPrincipal,
   5124      aIsHandlingUserInput, aMaybeUnsafePermissionDelegate, aTabId);
   5125 }
   5126 
   5127 bool ContentParent::DeallocPContentPermissionRequestParent(
   5128    PContentPermissionRequestParent* actor) {
   5129  nsContentPermissionUtils::NotifyRemoveContentPermissionRequestParent(actor);
   5130  delete actor;
   5131  return true;
   5132 }
   5133 
   5134 already_AddRefed<PWebBrowserPersistDocumentParent>
   5135 ContentParent::AllocPWebBrowserPersistDocumentParent(
   5136    PBrowserParent* aBrowser, const MaybeDiscarded<BrowsingContext>& aContext) {
   5137  return MakeAndAddRef<WebBrowserPersistDocumentParent>();
   5138 }
   5139 
   5140 mozilla::ipc::IPCResult ContentParent::CommonCreateWindow(
   5141    PBrowserParent* aThisTab, BrowsingContext& aParent, bool aSetOpener,
   5142    const uint32_t& aChromeFlags, const bool& aCalledFromJS,
   5143    const bool& aForPrinting, const bool& aForWindowDotPrint,
   5144    const bool& aIsTopLevelCreatedByWebContent, nsIURI* aURIToLoad,
   5145    const nsACString& aFeatures, const UserActivation::Modifiers& aModifiers,
   5146    BrowserParent* aNextRemoteBrowser, const nsAString& aName,
   5147    nsresult& aResult, nsCOMPtr<nsIRemoteTab>& aNewRemoteTab,
   5148    bool* aWindowIsNew, int32_t& aOpenLocation,
   5149    nsIPrincipal* aTriggeringPrincipal, nsIReferrerInfo* aReferrerInfo,
   5150    bool aLoadURI, nsIPolicyContainer* aPolicyContainer,
   5151    const OriginAttributes& aOriginAttributes, bool aUserActivation,
   5152    bool aTextDirectiveUserActivation) {
   5153  // The content process should never be in charge of computing whether or
   5154  // not a window should be private - the parent will do that.
   5155  const uint32_t badFlags = nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW |
   5156                            nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW |
   5157                            nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME;
   5158  if (!!(aChromeFlags & badFlags)) {
   5159    return IPC_FAIL(this, "Forbidden aChromeFlags passed");
   5160  }
   5161 
   5162  RefPtr<nsOpenWindowInfo> openInfo = new nsOpenWindowInfo();
   5163  openInfo->mForceNoOpener = !aSetOpener;
   5164  openInfo->mParent = &aParent;
   5165  openInfo->mIsRemote = true;
   5166  openInfo->mIsForPrinting = aForPrinting;
   5167  openInfo->mIsForWindowDotPrint = aForWindowDotPrint;
   5168  openInfo->mNextRemoteBrowser = aNextRemoteBrowser;
   5169  openInfo->mIsTopLevelCreatedByWebContent = aIsTopLevelCreatedByWebContent;
   5170  openInfo->mHasValidUserGestureActivation = aUserActivation;
   5171  openInfo->mTextDirectiveUserActivation = aTextDirectiveUserActivation;
   5172  openInfo->mPrincipalToInheritForAboutBlank = aTriggeringPrincipal;
   5173  MOZ_ASSERT(
   5174      aOriginAttributes == openInfo->GetOriginAttributes(),
   5175      "Open window info gets the expected origin attributes from principal");
   5176 
   5177  MOZ_ASSERT_IF(aForWindowDotPrint, aForPrinting);
   5178 
   5179  RefPtr<BrowserParent> topParent = BrowserParent::GetFrom(aThisTab);
   5180  while (topParent && topParent->GetBrowserBridgeParent()) {
   5181    topParent = topParent->GetBrowserBridgeParent()->Manager();
   5182  }
   5183  RefPtr<BrowserHost> thisBrowserHost =
   5184      topParent ? topParent->GetBrowserHost() : nullptr;
   5185  MOZ_ASSERT_IF(topParent, thisBrowserHost);
   5186  RefPtr<BrowsingContext> topBC =
   5187      topParent ? topParent->GetBrowsingContext() : nullptr;
   5188  MOZ_ASSERT_IF(topParent, topBC);
   5189 
   5190  // The content process should have set its remote and fission flags correctly.
   5191  if (topBC) {
   5192    if ((!!(aChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) !=
   5193         topBC->UseRemoteTabs()) ||
   5194        (!!(aChromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW) !=
   5195         topBC->UseRemoteSubframes())) {
   5196      return IPC_FAIL(this, "Unexpected aChromeFlags passed");
   5197    }
   5198 
   5199    if (!aOriginAttributes.EqualsIgnoringFPD(topBC->OriginAttributesRef())) {
   5200      return IPC_FAIL(this, "Passed-in OriginAttributes does not match opener");
   5201    }
   5202  }
   5203 
   5204  nsCOMPtr<nsIContent> frame;
   5205  if (topParent) {
   5206    frame = topParent->GetOwnerElement();
   5207  }
   5208 
   5209  nsCOMPtr<nsPIDOMWindowOuter> outerWin;
   5210  if (frame) {
   5211    outerWin = frame->OwnerDoc()->GetWindow();
   5212 
   5213    // If our chrome window is in the process of closing, don't try to open a
   5214    // new tab in it.
   5215    if (outerWin && outerWin->Closed()) {
   5216      outerWin = nullptr;
   5217    }
   5218  }
   5219 
   5220  nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
   5221  if (topParent) {
   5222    browserDOMWin = topParent->GetBrowserDOMWindow();
   5223  }
   5224 
   5225  // If we haven't found a chrome window to open in, just use the most recently
   5226  // opened non PBM window.
   5227  if (!outerWin) {
   5228    // The parent was a private window but it's no longer available.
   5229    if (aOriginAttributes.mPrivateBrowsingId !=
   5230        nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID) {
   5231      aResult = NS_ERROR_FAILURE;
   5232      return IPC_OK();
   5233    }
   5234 
   5235    outerWin = nsContentUtils::GetMostRecentNonPBWindow();
   5236    if (NS_WARN_IF(!outerWin)) {
   5237      aResult = NS_ERROR_FAILURE;
   5238      return IPC_OK();
   5239    }
   5240 
   5241    if (nsGlobalWindowOuter::Cast(outerWin)->IsChromeWindow()) {
   5242      browserDOMWin =
   5243          nsGlobalWindowOuter::Cast(outerWin)->GetBrowserDOMWindow();
   5244    }
   5245  }
   5246 
   5247  aOpenLocation = nsWindowWatcher::GetWindowOpenLocation(
   5248      outerWin, aChromeFlags, aModifiers, aCalledFromJS, aForPrinting);
   5249 
   5250  MOZ_ASSERT(aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
   5251             aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB_BACKGROUND ||
   5252             aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB_FOREGROUND ||
   5253             aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWWINDOW ||
   5254             aOpenLocation == nsIBrowserDOMWindow::OPEN_PRINT_BROWSER);
   5255 
   5256  if (NS_WARN_IF(!browserDOMWin)) {
   5257 #ifdef MOZ_GECKOVIEW
   5258    // This might be print preview, but GeckoView doesn't support yet.
   5259    aResult = NS_ERROR_FAILURE;
   5260    return IPC_OK();
   5261 #else
   5262    // Opening in the same window or headless requires an nsIBrowserDOMWindow.
   5263    aOpenLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
   5264 #endif
   5265  }
   5266 
   5267  if (aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
   5268      aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB_BACKGROUND ||
   5269      aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB_FOREGROUND ||
   5270      aOpenLocation == nsIBrowserDOMWindow::OPEN_PRINT_BROWSER) {
   5271    RefPtr<Element> openerElement = do_QueryObject(frame);
   5272 
   5273    nsCOMPtr<nsIOpenURIInFrameParams> params =
   5274        new nsOpenURIInFrameParams(openInfo, openerElement);
   5275    params->SetReferrerInfo(aReferrerInfo);
   5276    MOZ_ASSERT(aTriggeringPrincipal, "need a valid triggeringPrincipal");
   5277    params->SetTriggeringPrincipal(aTriggeringPrincipal);
   5278    params->SetPolicyContainer(aPolicyContainer);
   5279 
   5280    RefPtr<Element> el;
   5281 
   5282    if (aLoadURI) {
   5283      aResult = browserDOMWin->OpenURIInFrame(aURIToLoad, params, aOpenLocation,
   5284                                              nsIBrowserDOMWindow::OPEN_NEW,
   5285                                              aName, getter_AddRefs(el));
   5286    } else {
   5287      aResult = browserDOMWin->CreateContentWindowInFrame(
   5288          aURIToLoad, params, aOpenLocation, nsIBrowserDOMWindow::OPEN_NEW,
   5289          aName, getter_AddRefs(el));
   5290    }
   5291    RefPtr<nsFrameLoaderOwner> frameLoaderOwner = do_QueryObject(el);
   5292    if (NS_SUCCEEDED(aResult) && frameLoaderOwner) {
   5293      RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
   5294      if (frameLoader) {
   5295        aNewRemoteTab = frameLoader->GetRemoteTab();
   5296        // At this point, it's possible the inserted frameloader hasn't gone
   5297        // through layout yet. To ensure that the dimensions that we send down
   5298        // when telling the frameloader to display will be correct (instead of
   5299        // falling back to a 10x10 default), we force layout if necessary to get
   5300        // the most up-to-date dimensions. See bug 1358712 for details.
   5301        frameLoader->ForceLayoutIfNecessary();
   5302      }
   5303    } else if (NS_SUCCEEDED(aResult) && !frameLoaderOwner) {
   5304      // Fall through to the normal window opening code path when there is no
   5305      // window which we can open a new tab in.
   5306      aOpenLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
   5307    } else {
   5308      *aWindowIsNew = false;
   5309    }
   5310 
   5311    // If we didn't retarget our window open into a new window, we should return
   5312    // now.
   5313    if (aOpenLocation != nsIBrowserDOMWindow::OPEN_NEWWINDOW) {
   5314      return IPC_OK();
   5315    }
   5316  }
   5317 
   5318  nsCOMPtr<nsPIWindowWatcher> pwwatch =
   5319      do_GetService(NS_WINDOWWATCHER_CONTRACTID, &aResult);
   5320  if (NS_WARN_IF(NS_FAILED(aResult))) {
   5321    return IPC_OK();
   5322  }
   5323 
   5324  WindowFeatures features;
   5325  features.Tokenize(aFeatures);
   5326 
   5327  aResult = pwwatch->OpenWindowWithRemoteTab(
   5328      thisBrowserHost, features, aModifiers, aCalledFromJS, aParent.FullZoom(),
   5329      openInfo, getter_AddRefs(aNewRemoteTab));
   5330  if (NS_WARN_IF(NS_FAILED(aResult))) {
   5331    return IPC_OK();
   5332  }
   5333 
   5334  MOZ_ASSERT(aNewRemoteTab);
   5335  RefPtr<BrowserHost> newBrowserHost = BrowserHost::GetFrom(aNewRemoteTab);
   5336  RefPtr<BrowserParent> newBrowserParent = newBrowserHost->GetActor();
   5337 
   5338  // At this point, it's possible the inserted frameloader hasn't gone through
   5339  // layout yet. To ensure that the dimensions that we send down when telling
   5340  // the frameloader to display will be correct (instead of falling back to a
   5341  // 10x10 default), we force layout if necessary to get the most up-to-date
   5342  // dimensions. See bug 1358712 for details.
   5343  nsCOMPtr<Element> frameElement = newBrowserHost->GetOwnerElement();
   5344  MOZ_ASSERT(frameElement);
   5345  if (nsWindowWatcher::HaveSpecifiedSize(features)) {
   5346    // We want to flush the layout anyway because of the resize to the specified
   5347    // size. (Bug 1793605).
   5348    RefPtr<Document> chromeDoc = frameElement->OwnerDoc();
   5349    MOZ_ASSERT(chromeDoc);
   5350    chromeDoc->FlushPendingNotifications(FlushType::Layout);
   5351  } else {
   5352    RefPtr<nsFrameLoaderOwner> frameLoaderOwner = do_QueryObject(frameElement);
   5353    MOZ_ASSERT(frameLoaderOwner);
   5354    RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
   5355    MOZ_ASSERT(frameLoader);
   5356    frameLoader->ForceLayoutIfNecessary();
   5357  }
   5358 
   5359  // If we were passed a name for the window which would override the default,
   5360  // we should send it down to the new tab.
   5361  if (nsContentUtils::IsOverridingWindowName(aName)) {
   5362    MOZ_ALWAYS_SUCCEEDS(newBrowserHost->GetBrowsingContext()->SetName(aName));
   5363  }
   5364 
   5365  MOZ_ASSERT(newBrowserHost->GetBrowsingContext()->OriginAttributesRef() ==
   5366             aOriginAttributes);
   5367 
   5368  if (aURIToLoad && aLoadURI) {
   5369    nsCOMPtr<mozIDOMWindowProxy> openerWindow;
   5370    if (aSetOpener && topParent) {
   5371      openerWindow = topParent->GetParentWindowOuter();
   5372    }
   5373    nsCOMPtr<nsIBrowserDOMWindow> newBrowserDOMWin =
   5374        newBrowserParent->GetBrowserDOMWindow();
   5375    if (NS_WARN_IF(!newBrowserDOMWin)) {
   5376      aResult = NS_ERROR_ABORT;
   5377      return IPC_OK();
   5378    }
   5379    RefPtr<BrowsingContext> bc;
   5380    aResult = newBrowserDOMWin->OpenURI(
   5381        aURIToLoad, openInfo, nsIBrowserDOMWindow::OPEN_CURRENTWINDOW,
   5382        nsIBrowserDOMWindow::OPEN_NEW, aTriggeringPrincipal, aPolicyContainer,
   5383        getter_AddRefs(bc));
   5384  }
   5385 
   5386  return IPC_OK();
   5387 }
   5388 
   5389 mozilla::ipc::IPCResult ContentParent::RecvCreateWindow(
   5390    PBrowserParent* aThisTab, const MaybeDiscarded<BrowsingContext>& aParent,
   5391    PBrowserParent* aNewTab, const uint32_t& aChromeFlags,
   5392    const bool& aCalledFromJS, const bool& aForPrinting,
   5393    const bool& aForWindowDotPrint, const bool& aIsTopLevelCreatedByWebContent,
   5394    nsIURI* aURIToLoad, const nsACString& aFeatures,
   5395    const UserActivation::Modifiers& aModifiers,
   5396    nsIPrincipal* aTriggeringPrincipal, nsIPolicyContainer* aPolicyContainer,
   5397    nsIReferrerInfo* aReferrerInfo, const OriginAttributes& aOriginAttributes,
   5398    bool aUserActivation, bool aTextDirectiveUserActivation,
   5399    CreateWindowResolver&& aResolve) {
   5400  if (!aTriggeringPrincipal) {
   5401    return IPC_FAIL(this, "No principal");
   5402  }
   5403 
   5404  if (!ValidatePrincipal(aTriggeringPrincipal)) {
   5405    LogAndAssertFailedPrincipalValidationInfo(aTriggeringPrincipal, __func__);
   5406  }
   5407 
   5408  nsresult rv = NS_OK;
   5409  CreatedWindowInfo cwi;
   5410 
   5411  // We always expect to open a new window here. If we don't, it's an error.
   5412  cwi.windowOpened() = true;
   5413  cwi.maxTouchPoints() = 0;
   5414 
   5415  // Make sure to resolve the resolver when this function exits, even if we
   5416  // failed to generate a valid response.
   5417  auto resolveOnExit = MakeScopeExit([&] {
   5418    // Copy over the nsresult, and then resolve.
   5419    cwi.rv() = rv;
   5420    aResolve(cwi);
   5421  });
   5422 
   5423  RefPtr<BrowserParent> thisTab = BrowserParent::GetFrom(aThisTab);
   5424  RefPtr<BrowserParent> newTab = BrowserParent::GetFrom(aNewTab);
   5425  MOZ_ASSERT(newTab);
   5426 
   5427  auto destroyNewTabOnError = MakeScopeExit([&] {
   5428    // We always expect to open a new window here. If we don't, it's an error.
   5429    if (!cwi.windowOpened() || NS_FAILED(rv)) {
   5430      if (newTab) {
   5431        newTab->Destroy();
   5432      }
   5433    }
   5434  });
   5435 
   5436  // Don't continue to try to create a new window if we've been fully discarded.
   5437  RefPtr<BrowsingContext> parent = aParent.GetMaybeDiscarded();
   5438  if (NS_WARN_IF(!parent)) {
   5439    rv = NS_ERROR_FAILURE;
   5440    return IPC_OK();
   5441  }
   5442 
   5443  // Validate that our new BrowsingContext looks as we would expect it.
   5444  RefPtr<BrowsingContext> newBC = newTab->GetBrowsingContext();
   5445  if (!newBC) {
   5446    return IPC_FAIL(this, "Missing BrowsingContext for new tab");
   5447  }
   5448 
   5449  uint64_t newBCOpenerId = newBC->GetOpenerId();
   5450  if (newBCOpenerId != 0 && parent->Id() != newBCOpenerId) {
   5451    return IPC_FAIL(this, "Invalid opener BrowsingContext for new tab");
   5452  }
   5453  if (newBC->GetParent() != nullptr) {
   5454    return IPC_FAIL(this,
   5455                    "Unexpected non-toplevel BrowsingContext for new tab");
   5456  }
   5457  if (!!(aChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) !=
   5458          newBC->UseRemoteTabs() ||
   5459      !!(aChromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW) !=
   5460          newBC->UseRemoteSubframes()) {
   5461    return IPC_FAIL(this, "Unexpected aChromeFlags passed");
   5462  }
   5463  if (!aOriginAttributes.EqualsIgnoringFPD(newBC->OriginAttributesRef())) {
   5464    return IPC_FAIL(this, "Opened tab has mismatched OriginAttributes");
   5465  }
   5466 
   5467  if (thisTab && BrowserParent::GetFrom(thisTab)->GetBrowsingContext()) {
   5468    BrowsingContext* thisTabBC = thisTab->GetBrowsingContext();
   5469    if (thisTabBC->UseRemoteTabs() != newBC->UseRemoteTabs() ||
   5470        thisTabBC->UseRemoteSubframes() != newBC->UseRemoteSubframes() ||
   5471        thisTabBC->UsePrivateBrowsing() != newBC->UsePrivateBrowsing()) {
   5472      return IPC_FAIL(this, "New BrowsingContext has mismatched LoadContext");
   5473    }
   5474  }
   5475  BrowserParent::AutoUseNewTab aunt(newTab);
   5476 
   5477  nsCOMPtr<nsIRemoteTab> newRemoteTab;
   5478  int32_t openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
   5479  mozilla::ipc::IPCResult ipcResult = CommonCreateWindow(
   5480      aThisTab, *parent, newBCOpenerId != 0, aChromeFlags, aCalledFromJS,
   5481      aForPrinting, aForWindowDotPrint, aIsTopLevelCreatedByWebContent,
   5482      aURIToLoad, aFeatures, aModifiers, newTab, VoidString(), rv, newRemoteTab,
   5483      &cwi.windowOpened(), openLocation, aTriggeringPrincipal, aReferrerInfo,
   5484      /* aLoadUri = */ false, aPolicyContainer, aOriginAttributes,
   5485      aUserActivation, aTextDirectiveUserActivation);
   5486  if (!ipcResult) {
   5487    return ipcResult;
   5488  }
   5489 
   5490  if (NS_WARN_IF(NS_FAILED(rv)) || !newRemoteTab) {
   5491    return IPC_OK();
   5492  }
   5493 
   5494  MOZ_ASSERT(BrowserHost::GetFrom(newRemoteTab.get()) ==
   5495             newTab->GetBrowserHost());
   5496 
   5497  // This used to happen in the child - there may now be a better place to
   5498  // do this work.
   5499  MOZ_ALWAYS_SUCCEEDS(newBC->SetHasSiblings(
   5500      openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
   5501      openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB_BACKGROUND ||
   5502      openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB_FOREGROUND));
   5503 
   5504  newTab->SwapFrameScriptsFrom(cwi.frameScripts());
   5505  newTab->MaybeShowFrame();
   5506 
   5507  nsCOMPtr<nsIWidget> widget = newTab->GetWidget();
   5508  if (widget) {
   5509    cwi.dimensions() = newTab->GetDimensionInfo();
   5510  }
   5511 
   5512  cwi.maxTouchPoints() = newTab->GetMaxTouchPoints();
   5513 
   5514  return IPC_OK();
   5515 }
   5516 
   5517 mozilla::ipc::IPCResult ContentParent::RecvCreateWindowInDifferentProcess(
   5518    PBrowserParent* aThisTab, const MaybeDiscarded<BrowsingContext>& aParent,
   5519    const uint32_t& aChromeFlags, const bool& aCalledFromJS,
   5520    const bool& aIsTopLevelCreatedByWebContent, nsIURI* aURIToLoad,
   5521    const nsACString& aFeatures, const UserActivation::Modifiers& aModifiers,
   5522    const nsAString& aName, nsIPrincipal* aTriggeringPrincipal,
   5523    nsIPolicyContainer* aPolicyContainer, nsIReferrerInfo* aReferrerInfo,
   5524    const OriginAttributes& aOriginAttributes, bool aUserActivation,
   5525    bool aTextDirectiveUserActivation) {
   5526  MOZ_DIAGNOSTIC_ASSERT(!nsContentUtils::IsSpecialName(aName));
   5527 
   5528  // Don't continue to try to create a new window if we've been fully discarded.
   5529  RefPtr<BrowsingContext> parent = aParent.GetMaybeDiscarded();
   5530  if (NS_WARN_IF(!parent)) {
   5531    return IPC_OK();
   5532  }
   5533 
   5534  nsCOMPtr<nsIRemoteTab> newRemoteTab;
   5535  bool windowIsNew;
   5536  int32_t openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
   5537 
   5538  // If we have enough data, check the schemes of the loader and loadee
   5539  // to make sure they make sense.
   5540  if (aURIToLoad && aURIToLoad->SchemeIs("file") &&
   5541      GetRemoteType() != FILE_REMOTE_TYPE &&
   5542      Preferences::GetBool("browser.tabs.remote.enforceRemoteTypeRestrictions",
   5543                           false)) {
   5544 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   5545 #  ifdef DEBUG
   5546    nsAutoCString uriToLoadStr;
   5547    nsAutoCString triggeringUriStr;
   5548    aURIToLoad->GetAsciiSpec(uriToLoadStr);
   5549    aTriggeringPrincipal->GetAsciiSpec(triggeringUriStr);
   5550 
   5551    NS_WARNING(nsPrintfCString(
   5552                   "RecvCreateWindowInDifferentProcess blocked loading file "
   5553                   "scheme from non-file remotetype: %s tried to load %s",
   5554                   triggeringUriStr.get(), uriToLoadStr.get())
   5555                   .get());
   5556 #  endif
   5557    MOZ_CRASH(
   5558        "RecvCreateWindowInDifferentProcess blocked loading improper scheme");
   5559 #endif
   5560    return IPC_OK();
   5561  }
   5562 
   5563  nsresult rv;
   5564  mozilla::ipc::IPCResult ipcResult = CommonCreateWindow(
   5565      aThisTab, *parent, /* aSetOpener = */ false, aChromeFlags, aCalledFromJS,
   5566      /* aForPrinting = */ false,
   5567      /* aForWindowDotPrint = */ false, aIsTopLevelCreatedByWebContent,
   5568      aURIToLoad, aFeatures, aModifiers,
   5569      /* aNextRemoteBrowser = */ nullptr, aName, rv, newRemoteTab, &windowIsNew,
   5570      openLocation, aTriggeringPrincipal, aReferrerInfo,
   5571      /* aLoadUri = */ true, aPolicyContainer, aOriginAttributes,
   5572      aUserActivation, aTextDirectiveUserActivation);
   5573  if (!ipcResult) {
   5574    return ipcResult;
   5575  }
   5576 
   5577  if (NS_FAILED(rv)) {
   5578    NS_WARNING("Call to CommonCreateWindow failed.");
   5579  }
   5580 
   5581  return IPC_OK();
   5582 }
   5583 
   5584 mozilla::ipc::IPCResult ContentParent::RecvShutdownProfile(
   5585    const nsACString& aProfile) {
   5586  profiler_received_exit_profile(aProfile);
   5587  return IPC_OK();
   5588 }
   5589 
   5590 mozilla::ipc::IPCResult ContentParent::RecvShutdownPerfStats(
   5591    const nsACString& aPerfStats) {
   5592  PerfStats::StorePerfStats(this, aPerfStats);
   5593  return IPC_OK();
   5594 }
   5595 
   5596 mozilla::ipc::IPCResult ContentParent::RecvGetFontListShmBlock(
   5597    const uint32_t& aGeneration, const uint32_t& aIndex,
   5598    ReadOnlySharedMemoryHandle* aOut) {
   5599  auto* fontList = gfxPlatformFontList::PlatformFontList();
   5600  MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
   5601  fontList->ShareFontListShmBlockToProcess(aGeneration, aIndex, Pid(), aOut);
   5602  return IPC_OK();
   5603 }
   5604 
   5605 mozilla::ipc::IPCResult ContentParent::RecvInitializeFamily(
   5606    const uint32_t& aGeneration, const uint32_t& aFamilyIndex,
   5607    const bool& aLoadCmaps) {
   5608  auto* fontList = gfxPlatformFontList::PlatformFontList();
   5609  MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
   5610  fontList->InitializeFamily(aGeneration, aFamilyIndex, aLoadCmaps);
   5611  return IPC_OK();
   5612 }
   5613 
   5614 mozilla::ipc::IPCResult ContentParent::RecvSetCharacterMap(
   5615    const uint32_t& aGeneration, const uint32_t& aFamilyIndex,
   5616    const bool& aAlias, const uint32_t& aFaceIndex,
   5617    const gfxSparseBitSet& aMap) {
   5618  auto* fontList = gfxPlatformFontList::PlatformFontList();
   5619  MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
   5620  fontList->SetCharacterMap(aGeneration, aFamilyIndex, aAlias, aFaceIndex,
   5621                            aMap);
   5622  return IPC_OK();
   5623 }
   5624 
   5625 mozilla::ipc::IPCResult ContentParent::RecvInitOtherFamilyNames(
   5626    const uint32_t& aGeneration, const bool& aDefer, bool* aLoaded) {
   5627  auto* fontList = gfxPlatformFontList::PlatformFontList();
   5628  MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
   5629  *aLoaded = fontList->InitOtherFamilyNames(aGeneration, aDefer);
   5630  return IPC_OK();
   5631 }
   5632 
   5633 mozilla::ipc::IPCResult ContentParent::RecvSetupFamilyCharMap(
   5634    const uint32_t& aGeneration, const uint32_t& aIndex, const bool& aAlias) {
   5635  auto* fontList = gfxPlatformFontList::PlatformFontList();
   5636  MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
   5637  fontList->SetupFamilyCharMap(aGeneration, aIndex, aAlias);
   5638  return IPC_OK();
   5639 }
   5640 
   5641 mozilla::ipc::IPCResult ContentParent::RecvStartCmapLoading(
   5642    const uint32_t& aGeneration, const uint32_t& aStartIndex) {
   5643  auto* fontList = gfxPlatformFontList::PlatformFontList();
   5644  MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
   5645  fontList->StartCmapLoading(aGeneration, aStartIndex);
   5646  return IPC_OK();
   5647 }
   5648 
   5649 mozilla::ipc::IPCResult ContentParent::RecvGetHyphDict(
   5650    nsIURI* aURI, ReadOnlySharedMemoryHandle* aOutHandle) {
   5651  if (!aURI) {
   5652    return IPC_FAIL(this, "aURI must not be null.");
   5653  }
   5654  nsHyphenationManager::Instance()->ShareHyphDictToProcess(aURI, Pid(),
   5655                                                           aOutHandle);
   5656  return IPC_OK();
   5657 }
   5658 
   5659 mozilla::ipc::IPCResult ContentParent::RecvGraphicsError(
   5660    const nsACString& aError) {
   5661  if (gfx::LogForwarder* lf = gfx::Factory::GetLogForwarder()) {
   5662    std::stringstream message;
   5663    message << "CP+" << aError;
   5664    lf->UpdateStringsVector(message.str());
   5665  }
   5666  return IPC_OK();
   5667 }
   5668 
   5669 mozilla::ipc::IPCResult ContentParent::RecvBeginDriverCrashGuard(
   5670    const uint32_t& aGuardType, bool* aOutCrashed) {
   5671  // Only one driver crash guard should be active at a time, per-process.
   5672  MOZ_ASSERT(!mDriverCrashGuard);
   5673 
   5674  UniquePtr<gfx::DriverCrashGuard> guard;
   5675  switch (gfx::CrashGuardType(aGuardType)) {
   5676    case gfx::CrashGuardType::D3D11Layers:
   5677      guard = MakeUnique<gfx::D3D11LayersCrashGuard>(this);
   5678      break;
   5679    case gfx::CrashGuardType::GLContext:
   5680      guard = MakeUnique<gfx::GLContextCrashGuard>(this);
   5681      break;
   5682    case gfx::CrashGuardType::WMFVPXVideo:
   5683      guard = MakeUnique<gfx::WMFVPXVideoCrashGuard>(this);
   5684      break;
   5685    default:
   5686      return IPC_FAIL(this, "unknown crash guard type");
   5687  }
   5688 
   5689  if (guard->Crashed()) {
   5690    *aOutCrashed = true;
   5691    return IPC_OK();
   5692  }
   5693 
   5694  *aOutCrashed = false;
   5695  mDriverCrashGuard = std::move(guard);
   5696  return IPC_OK();
   5697 }
   5698 
   5699 mozilla::ipc::IPCResult ContentParent::RecvEndDriverCrashGuard(
   5700    const uint32_t& aGuardType) {
   5701  mDriverCrashGuard = nullptr;
   5702  return IPC_OK();
   5703 }
   5704 
   5705 mozilla::ipc::IPCResult ContentParent::RecvNotifyPushObservers(
   5706    const nsACString& aScope, nsIPrincipal* aPrincipal,
   5707    const nsAString& aMessageId) {
   5708  if (!aPrincipal) {
   5709    return IPC_FAIL(this, "No principal");
   5710  }
   5711 
   5712  if (!ValidatePrincipal(aPrincipal)) {
   5713    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
   5714  }
   5715  PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId, Nothing());
   5716  (void)NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
   5717  return IPC_OK();
   5718 }
   5719 
   5720 mozilla::ipc::IPCResult ContentParent::RecvNotifyPushObserversWithData(
   5721    const nsACString& aScope, nsIPrincipal* aPrincipal,
   5722    const nsAString& aMessageId, nsTArray<uint8_t>&& aData) {
   5723  if (!aPrincipal) {
   5724    return IPC_FAIL(this, "No principal");
   5725  }
   5726 
   5727  if (!ValidatePrincipal(aPrincipal)) {
   5728    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
   5729  }
   5730  PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId,
   5731                                   Some(std::move(aData)));
   5732  (void)NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
   5733  return IPC_OK();
   5734 }
   5735 
   5736 mozilla::ipc::IPCResult ContentParent::RecvPushError(const nsACString& aScope,
   5737                                                     nsIPrincipal* aPrincipal,
   5738                                                     const nsAString& aMessage,
   5739                                                     const uint32_t& aFlags) {
   5740  if (!aPrincipal) {
   5741    return IPC_FAIL(this, "No principal");
   5742  }
   5743 
   5744  if (!ValidatePrincipal(aPrincipal)) {
   5745    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
   5746  }
   5747  PushErrorDispatcher dispatcher(aScope, aPrincipal, aMessage, aFlags);
   5748  (void)NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
   5749  return IPC_OK();
   5750 }
   5751 
   5752 mozilla::ipc::IPCResult
   5753 ContentParent::RecvNotifyPushSubscriptionModifiedObservers(
   5754    const nsACString& aScope, nsIPrincipal* aPrincipal) {
   5755  if (!aPrincipal) {
   5756    return IPC_FAIL(this, "No principal");
   5757  }
   5758 
   5759  if (!ValidatePrincipal(aPrincipal)) {
   5760    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
   5761  }
   5762  PushSubscriptionModifiedDispatcher dispatcher(aScope, aPrincipal);
   5763  (void)NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers()));
   5764  return IPC_OK();
   5765 }
   5766 
   5767 /* static */
   5768 void ContentParent::BroadcastBlobURLRegistration(const nsACString& aURI,
   5769                                                 BlobImpl* aBlobImpl,
   5770                                                 nsIPrincipal* aPrincipal,
   5771                                                 const nsCString& aPartitionKey,
   5772                                                 ContentParent* aIgnoreThisCP) {
   5773  uint64_t originHash = ComputeLoadedOriginHash(aPrincipal);
   5774 
   5775  bool toBeSent =
   5776      BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal);
   5777 
   5778  nsCString uri(aURI);
   5779 
   5780  for (auto* cp : AllProcesses(eLive)) {
   5781    if (cp != aIgnoreThisCP) {
   5782      if (!toBeSent && !cp->mLoadedOriginHashes.Contains(originHash)) {
   5783        continue;
   5784      }
   5785 
   5786      nsresult rv = cp->TransmitPermissionsForPrincipal(aPrincipal);
   5787      if (NS_WARN_IF(NS_FAILED(rv))) {
   5788        break;
   5789      }
   5790 
   5791      IPCBlob ipcBlob;
   5792      rv = IPCBlobUtils::Serialize(aBlobImpl, ipcBlob);
   5793      if (NS_WARN_IF(NS_FAILED(rv))) {
   5794        break;
   5795      }
   5796 
   5797      (void)cp->SendBlobURLRegistration(uri, ipcBlob, aPrincipal,
   5798                                        aPartitionKey);
   5799    }
   5800  }
   5801 }
   5802 
   5803 /* static */
   5804 void ContentParent::BroadcastBlobURLUnregistration(
   5805    const nsTArray<BroadcastBlobURLUnregistrationRequest>& aRequests,
   5806    ContentParent* aIgnoreThisCP) {
   5807  struct DataRequest {
   5808    const BroadcastBlobURLUnregistrationRequest& mRequest;
   5809    uint64_t mOriginHash;
   5810    bool mToBeSent;
   5811  };
   5812 
   5813  nsTArray<DataRequest> dataRequests(aRequests.Length());
   5814  for (const BroadcastBlobURLUnregistrationRequest& request : aRequests) {
   5815    uint64_t originHash = ComputeLoadedOriginHash(request.principal());
   5816 
   5817    bool toBeSent = BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(
   5818        request.principal());
   5819 
   5820    dataRequests.AppendElement(DataRequest{request, originHash, toBeSent});
   5821  }
   5822 
   5823  for (auto* cp : AllProcesses(eLive)) {
   5824    if (cp == aIgnoreThisCP) {
   5825      continue;
   5826    }
   5827 
   5828    nsTArray<nsCString> urls;
   5829    for (const DataRequest& data : dataRequests) {
   5830      if (data.mToBeSent ||
   5831          cp->mLoadedOriginHashes.Contains(data.mOriginHash)) {
   5832        urls.AppendElement(data.mRequest.url());
   5833      }
   5834    }
   5835 
   5836    if (!urls.IsEmpty()) {
   5837      (void)cp->SendBlobURLUnregistration(urls);
   5838    }
   5839  }
   5840 }
   5841 
   5842 mozilla::ipc::IPCResult ContentParent::RecvStoreAndBroadcastBlobURLRegistration(
   5843    const nsACString& aURI, const IPCBlob& aBlob, nsIPrincipal* aPrincipal,
   5844    const nsCString& aPartitionKey) {
   5845  if (!aPrincipal) {
   5846    return IPC_FAIL(this, "No principal");
   5847  }
   5848 
   5849  if (!ValidatePrincipal(aPrincipal, {ValidatePrincipalOptions::AllowSystem})) {
   5850    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
   5851  }
   5852  RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(aBlob);
   5853  if (NS_WARN_IF(!blobImpl)) {
   5854    return IPC_FAIL(this, "Blob deserialization failed.");
   5855  }
   5856 
   5857  BlobURLProtocolHandler::AddDataEntry(aURI, aPrincipal, aPartitionKey,
   5858                                       blobImpl, Some(ChildID()));
   5859  BroadcastBlobURLRegistration(aURI, blobImpl, aPrincipal, aPartitionKey, this);
   5860 
   5861  return IPC_OK();
   5862 }
   5863 
   5864 mozilla::ipc::IPCResult
   5865 ContentParent::RecvUnstoreAndBroadcastBlobURLUnregistration(
   5866    const nsTArray<BroadcastBlobURLUnregistrationRequest>& aRequests) {
   5867  nsTArray<nsCString> uris;
   5868 
   5869  for (const BroadcastBlobURLUnregistrationRequest& request : aRequests) {
   5870    if (!ValidatePrincipal(request.principal(),
   5871                           {ValidatePrincipalOptions::AllowSystem})) {
   5872      LogAndAssertFailedPrincipalValidationInfo(request.principal(), __func__);
   5873    }
   5874 
   5875    uris.AppendElement(request.url());
   5876  }
   5877 
   5878  BroadcastBlobURLUnregistration(aRequests, this);
   5879  BlobURLProtocolHandler::RemoveDataEntries(uris, false /* Don't broadcast */);
   5880 
   5881  return IPC_OK();
   5882 }
   5883 
   5884 mozilla::ipc::IPCResult ContentParent::RecvGetFilesRequest(
   5885    const nsID& aID, nsTArray<nsString>&& aDirectoryPaths,
   5886    const bool& aRecursiveFlag) {
   5887  MOZ_ASSERT(!mGetFilesPendingRequests.GetWeak(aID));
   5888 
   5889  if (!mozilla::Preferences::GetBool("dom.filesystem.pathcheck.disabled",
   5890                                     false)) {
   5891    RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get();
   5892    if (!fss) {
   5893      return IPC_FAIL(this, "Failed to get FileSystemSecurity.");
   5894    }
   5895 
   5896    for (const auto& directoryPath : aDirectoryPaths) {
   5897      if (!fss->ContentProcessHasAccessTo(ChildID(), directoryPath)) {
   5898        return IPC_FAIL(this, "ContentProcessHasAccessTo failed.");
   5899      }
   5900    }
   5901  }
   5902 
   5903  ErrorResult rv;
   5904  RefPtr<GetFilesHelper> helper = GetFilesHelperParent::Create(
   5905      aID, std::move(aDirectoryPaths), aRecursiveFlag, this, rv);
   5906 
   5907  if (NS_WARN_IF(rv.Failed())) {
   5908    if (!SendGetFilesResponse(aID,
   5909                              GetFilesResponseFailure(rv.StealNSResult()))) {
   5910      return IPC_FAIL(this, "SendGetFilesResponse failed.");
   5911    }
   5912    return IPC_OK();
   5913  }
   5914 
   5915  mGetFilesPendingRequests.InsertOrUpdate(aID, std::move(helper));
   5916  return IPC_OK();
   5917 }
   5918 
   5919 mozilla::ipc::IPCResult ContentParent::RecvDeleteGetFilesRequest(
   5920    const nsID& aID) {
   5921  mGetFilesPendingRequests.Remove(aID);
   5922  return IPC_OK();
   5923 }
   5924 
   5925 void ContentParent::SendGetFilesResponseAndForget(
   5926    const nsID& aID, const GetFilesResponseResult& aResult) {
   5927  if (mGetFilesPendingRequests.Remove(aID)) {
   5928    (void)SendGetFilesResponse(aID, aResult);
   5929  }
   5930 }
   5931 
   5932 void ContentParent::PaintTabWhileInterruptingJS(BrowserParent* aBrowserParent) {
   5933  if (!mHangMonitorActor) {
   5934    return;
   5935  }
   5936  ProcessHangMonitor::PaintWhileInterruptingJS(mHangMonitorActor,
   5937                                               aBrowserParent);
   5938 }
   5939 
   5940 void ContentParent::UnloadLayersWhileInterruptingJS(
   5941    BrowserParent* aBrowserParent) {
   5942  if (!mHangMonitorActor) {
   5943    return;
   5944  }
   5945  ProcessHangMonitor::UnloadLayersWhileInterruptingJS(mHangMonitorActor,
   5946                                                      aBrowserParent);
   5947 }
   5948 
   5949 void ContentParent::CancelContentJSExecutionIfRunning(
   5950    BrowserParent* aBrowserParent, nsIRemoteTab::NavigationType aNavigationType,
   5951    const CancelContentJSOptions& aCancelContentJSOptions) {
   5952  if (!mHangMonitorActor) {
   5953    return;
   5954  }
   5955 
   5956  ProcessHangMonitor::CancelContentJSExecutionIfRunning(
   5957      mHangMonitorActor, aBrowserParent, aNavigationType,
   5958      aCancelContentJSOptions);
   5959 }
   5960 
   5961 void ContentParent::SetMainThreadQoSPriority(
   5962    nsIThread::QoSPriority aQoSPriority) {
   5963  if (!mHangMonitorActor) {
   5964    return;
   5965  }
   5966 
   5967  ProcessHangMonitor::SetMainThreadQoSPriority(mHangMonitorActor, aQoSPriority);
   5968 }
   5969 
   5970 void ContentParent::UpdateCookieStatus(nsIChannel* aChannel) {
   5971  PNeckoParent* neckoParent = LoneManagedOrNullAsserts(ManagedPNeckoParent());
   5972  PCookieServiceParent* csParent =
   5973      LoneManagedOrNullAsserts(neckoParent->ManagedPCookieServiceParent());
   5974  if (csParent) {
   5975    auto* cs = static_cast<CookieServiceParent*>(csParent);
   5976    cs->TrackCookieLoad(aChannel);
   5977  }
   5978 }
   5979 
   5980 nsresult ContentParent::AboutToLoadHttpDocumentForChild(
   5981    nsIChannel* aChannel, bool* aShouldWaitForPermissionCookieUpdate) {
   5982  MOZ_ASSERT(aChannel);
   5983 
   5984  if (aShouldWaitForPermissionCookieUpdate) {
   5985    *aShouldWaitForPermissionCookieUpdate = false;
   5986  }
   5987 
   5988  nsresult rv;
   5989  bool isDocument = aChannel->IsDocument();
   5990  if (!isDocument) {
   5991    // We may be looking at a nsIHttpChannel which has isMainDocumentChannel set
   5992    // (e.g. the internal http channel for a view-source: load.).
   5993    nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
   5994    if (httpChannel) {
   5995      rv = httpChannel->GetIsMainDocumentChannel(&isDocument);
   5996      NS_ENSURE_SUCCESS(rv, rv);
   5997    }
   5998  }
   5999  if (!isDocument) {
   6000    return NS_OK;
   6001  }
   6002 
   6003  // Get the principal for the channel result, so that we can get the permission
   6004  // key for the document which will be created from this response.
   6005  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   6006  if (NS_WARN_IF(!ssm)) {
   6007    return NS_ERROR_FAILURE;
   6008  }
   6009 
   6010  nsCOMPtr<nsIPrincipal> principal;
   6011  nsCOMPtr<nsIPrincipal> partitionedPrincipal;
   6012  rv = ssm->GetChannelResultPrincipals(aChannel, getter_AddRefs(principal),
   6013                                       getter_AddRefs(partitionedPrincipal));
   6014  NS_ENSURE_SUCCESS(rv, rv);
   6015 
   6016  // Let the caller know we're going to send main thread IPC for updating
   6017  // permisssions/cookies.
   6018  if (aShouldWaitForPermissionCookieUpdate) {
   6019    *aShouldWaitForPermissionCookieUpdate = true;
   6020  }
   6021 
   6022  TransmitBlobURLsForPrincipal(principal);
   6023 
   6024  // Tranmit permissions for both regular and partitioned principal so that the
   6025  // content process can get permissions for the partitioned principal. For
   6026  // example, the desk-notification permission for a partitioned service worker.
   6027  rv = TransmitPermissionsForPrincipal(principal);
   6028  NS_ENSURE_SUCCESS(rv, rv);
   6029 
   6030  rv = TransmitPermissionsForPrincipal(partitionedPrincipal);
   6031  NS_ENSURE_SUCCESS(rv, rv);
   6032 
   6033  nsLoadFlags newLoadFlags;
   6034  aChannel->GetLoadFlags(&newLoadFlags);
   6035  if (newLoadFlags & nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE) {
   6036    UpdateCookieStatus(aChannel);
   6037  }
   6038 
   6039  RefPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   6040  RefPtr<BrowsingContext> browsingContext;
   6041  rv = loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext));
   6042  NS_ENSURE_SUCCESS(rv, rv);
   6043 
   6044  if (!NextGenLocalStorageEnabled()) {
   6045    return NS_OK;
   6046  }
   6047 
   6048  if (principal->GetIsContentPrincipal()) {
   6049    nsCOMPtr<nsILocalStorageManager> lsm =
   6050        do_GetService("@mozilla.org/dom/localStorage-manager;1");
   6051    if (NS_WARN_IF(!lsm)) {
   6052      return NS_ERROR_FAILURE;
   6053    }
   6054 
   6055    nsCOMPtr<nsIPrincipal> storagePrincipal;
   6056    rv = ssm->GetChannelResultStoragePrincipal(
   6057        aChannel, getter_AddRefs(storagePrincipal));
   6058    NS_ENSURE_SUCCESS(rv, rv);
   6059 
   6060    RefPtr<Promise> dummy;
   6061    rv = lsm->Preload(storagePrincipal, nullptr, getter_AddRefs(dummy));
   6062    if (NS_FAILED(rv)) {
   6063      NS_WARNING("Failed to preload local storage!");
   6064    }
   6065  }
   6066 
   6067  return NS_OK;
   6068 }
   6069 
   6070 nsresult ContentParent::TransmitPermissionsForPrincipal(
   6071    nsIPrincipal* aPrincipal) {
   6072  // Create the key, and send it down to the content process.
   6073  nsTArray<std::pair<nsCString, nsCString>> pairs =
   6074      PermissionManager::GetAllKeysForPrincipal(aPrincipal);
   6075  MOZ_ASSERT(pairs.Length() >= 1);
   6076  for (auto& pair : pairs) {
   6077    EnsurePermissionsByKey(pair.first, pair.second);
   6078  }
   6079 
   6080  // We need to add the Site to the secondary keys of interest here.
   6081  // This allows site-scoped permission updates to propogate when the
   6082  // port is non-standard.
   6083  nsAutoCString siteKey;
   6084  nsresult rv =
   6085      PermissionManager::GetKeyForPrincipal(aPrincipal, false, true, siteKey);
   6086  if (NS_SUCCEEDED(rv) && !siteKey.IsEmpty()) {
   6087    mActiveSecondaryPermissionKeys.EnsureInserted(siteKey);
   6088  }
   6089 
   6090  return NS_OK;
   6091 }
   6092 
   6093 void ContentParent::AddPrincipalToCookieInProcessCache(
   6094    nsIPrincipal* aPrincipal) {
   6095  MOZ_ASSERT(aPrincipal);
   6096  mCookieInContentListCache.AppendElement(aPrincipal);
   6097 }
   6098 
   6099 void ContentParent::TakeCookieInProcessCache(
   6100    nsTArray<nsCOMPtr<nsIPrincipal>>& aList) {
   6101  aList.SwapElements(mCookieInContentListCache);
   6102 }
   6103 
   6104 void ContentParent::TransmitBlobURLsForPrincipal(nsIPrincipal* aPrincipal) {
   6105  // If we're already broadcasting BlobURLs with this principal, we don't need
   6106  // to send them here.
   6107  if (BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal)) {
   6108    return;
   6109  }
   6110 
   6111  // We shouldn't have any Blob URLs with expanded principals, so transmit URLs
   6112  // for each principal in the AllowList instead.
   6113  if (nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(aPrincipal)) {
   6114    for (const auto& prin : ep->AllowList()) {
   6115      TransmitBlobURLsForPrincipal(prin);
   6116    }
   6117    return;
   6118  }
   6119 
   6120  uint64_t originHash = ComputeLoadedOriginHash(aPrincipal);
   6121 
   6122  if (!mLoadedOriginHashes.Contains(originHash)) {
   6123    mLoadedOriginHashes.AppendElement(originHash);
   6124 
   6125    nsTArray<BlobURLRegistrationData> registrations;
   6126    BlobURLProtocolHandler::ForEachBlobURL(
   6127        [&](BlobImpl* aBlobImpl, nsIPrincipal* aBlobPrincipal,
   6128            const nsCString& aPartitionKey, const nsACString& aURI,
   6129            bool aRevoked) {
   6130          // This check uses `ComputeLoadedOriginHash` to compare, rather than
   6131          // doing the more accurate `Equals` check, as it needs to match the
   6132          // behaviour of the logic to broadcast new registrations.
   6133          if (originHash != ComputeLoadedOriginHash(aBlobPrincipal)) {
   6134            return true;
   6135          }
   6136 
   6137          IPCBlob ipcBlob;
   6138          nsresult rv = IPCBlobUtils::Serialize(aBlobImpl, ipcBlob);
   6139          if (NS_WARN_IF(NS_FAILED(rv))) {
   6140            return false;
   6141          }
   6142 
   6143          registrations.AppendElement(BlobURLRegistrationData(
   6144              nsCString(aURI), ipcBlob, WrapNotNull(aPrincipal),
   6145              nsCString(aPartitionKey), aRevoked));
   6146 
   6147          rv = TransmitPermissionsForPrincipal(aBlobPrincipal);
   6148          (void)NS_WARN_IF(NS_FAILED(rv));
   6149          return true;
   6150        });
   6151 
   6152    if (!registrations.IsEmpty()) {
   6153      (void)SendInitBlobURLs(registrations);
   6154    }
   6155  }
   6156 }
   6157 
   6158 void ContentParent::TransmitBlobDataIfBlobURL(nsIURI* aURI) {
   6159  MOZ_ASSERT(aURI);
   6160 
   6161  nsCOMPtr<nsIPrincipal> principal;
   6162  if (BlobURLProtocolHandler::GetBlobURLPrincipal(aURI,
   6163                                                  getter_AddRefs(principal))) {
   6164    TransmitBlobURLsForPrincipal(principal);
   6165  }
   6166 }
   6167 
   6168 void ContentParent::EnsurePermissionsByKey(const nsACString& aKey,
   6169                                           const nsACString& aOrigin) {
   6170  // NOTE: Make sure to initialize the permission manager before updating the
   6171  // mActivePermissionKeys list. If the permission manager is being initialized
   6172  // by this call to GetPermissionManager, and we've added the key to
   6173  // mActivePermissionKeys, then the permission manager will send down a
   6174  // SendAddPermission before receiving the SendSetPermissionsWithKey message.
   6175  RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
   6176  if (!permManager) {
   6177    return;
   6178  }
   6179 
   6180  if (!mActivePermissionKeys.EnsureInserted(aKey)) {
   6181    return;
   6182  }
   6183 
   6184  nsTArray<IPC::Permission> perms;
   6185  if (permManager->GetPermissionsFromOriginOrKey(aOrigin, aKey, perms)) {
   6186    (void)SendSetPermissionsWithKey(aKey, perms);
   6187  }
   6188 }
   6189 
   6190 bool ContentParent::NeedsPermissionsUpdate(
   6191    const nsACString& aPermissionKey) const {
   6192  return mActivePermissionKeys.Contains(aPermissionKey);
   6193 }
   6194 
   6195 bool ContentParent::NeedsSecondaryKeyPermissionsUpdate(
   6196    const nsACString& aPermissionKey) const {
   6197  return mActiveSecondaryPermissionKeys.Contains(aPermissionKey);
   6198 }
   6199 
   6200 mozilla::ipc::IPCResult ContentParent::RecvAccumulateChildHistograms(
   6201    nsTArray<HistogramAccumulation>&& aAccumulations) {
   6202  TelemetryIPC::AccumulateChildHistograms(GetTelemetryProcessID(mRemoteType),
   6203                                          aAccumulations);
   6204  return IPC_OK();
   6205 }
   6206 
   6207 mozilla::ipc::IPCResult ContentParent::RecvAccumulateChildKeyedHistograms(
   6208    nsTArray<KeyedHistogramAccumulation>&& aAccumulations) {
   6209  TelemetryIPC::AccumulateChildKeyedHistograms(
   6210      GetTelemetryProcessID(mRemoteType), aAccumulations);
   6211  return IPC_OK();
   6212 }
   6213 
   6214 mozilla::ipc::IPCResult ContentParent::RecvUpdateChildScalars(
   6215    nsTArray<ScalarAction>&& aScalarActions) {
   6216  TelemetryIPC::UpdateChildScalars(GetTelemetryProcessID(mRemoteType),
   6217                                   aScalarActions);
   6218  return IPC_OK();
   6219 }
   6220 
   6221 mozilla::ipc::IPCResult ContentParent::RecvUpdateChildKeyedScalars(
   6222    nsTArray<KeyedScalarAction>&& aScalarActions) {
   6223  TelemetryIPC::UpdateChildKeyedScalars(GetTelemetryProcessID(mRemoteType),
   6224                                        aScalarActions);
   6225  return IPC_OK();
   6226 }
   6227 
   6228 mozilla::ipc::IPCResult ContentParent::RecvRecordChildEvents(
   6229    nsTArray<mozilla::Telemetry::ChildEventData>&& aEvents) {
   6230  TelemetryIPC::RecordChildEvents(GetTelemetryProcessID(mRemoteType), aEvents);
   6231  return IPC_OK();
   6232 }
   6233 
   6234 mozilla::ipc::IPCResult ContentParent::RecvRecordDiscardedData(
   6235    const mozilla::Telemetry::DiscardedData& aDiscardedData) {
   6236  TelemetryIPC::RecordDiscardedData(GetTelemetryProcessID(mRemoteType),
   6237                                    aDiscardedData);
   6238  return IPC_OK();
   6239 }
   6240 
   6241 static bool WebdriverRunning() {
   6242 #ifdef ENABLE_WEBDRIVER
   6243  nsCOMPtr<nsIMarionette> marionette = do_GetService(NS_MARIONETTE_CONTRACTID);
   6244  if (marionette) {
   6245    bool marionetteRunning = false;
   6246    marionette->GetRunning(&marionetteRunning);
   6247    if (marionetteRunning) {
   6248      return true;
   6249    }
   6250  }
   6251 
   6252  nsCOMPtr<nsIRemoteAgent> agent = do_GetService(NS_REMOTEAGENT_CONTRACTID);
   6253  if (agent) {
   6254    bool remoteAgentRunning = false;
   6255    agent->GetRunning(&remoteAgentRunning);
   6256    if (remoteAgentRunning) {
   6257      return true;
   6258    }
   6259  }
   6260 #endif
   6261 
   6262  return false;
   6263 }
   6264 
   6265 void ContentParent::RecordAndroidAppLinkTelemetry(
   6266    mozilla::performance::pageload_event::PageloadEventData* aPageloadData,
   6267    const TimeStamp& aNavStartTime, uint64_t aAndroidAppLinkLoadIdentifier) {
   6268  MOZ_ASSERT(aPageloadData);
   6269  int32_t appLinkLaunchType =
   6270      GetAndroidAppLinkLaunchType(aAndroidAppLinkLoadIdentifier);
   6271  if (appLinkLaunchType < 0) {
   6272    return;
   6273  }
   6274  ClearAndroidAppLinkLaunchType(aAndroidAppLinkLoadIdentifier);
   6275 
   6276  aPageloadData->set_androidAppLinkLaunchType(appLinkLaunchType);
   6277 
   6278  //  ProcessStart to navigationStart is only meaningful for cold applink
   6279  //  launches
   6280  if (appLinkLaunchType !=
   6281      1 /* mozilla::dom::LoadURIConstants::APPLINK_COLD */) {
   6282    return;
   6283  }
   6284 
   6285  const TimeStamp parentProcessCreationTime = TimeStamp::ProcessCreation();
   6286  if (parentProcessCreationTime.IsNull() || aNavStartTime.IsNull()) {
   6287    return;
   6288  }
   6289 
   6290  const TimeDuration delta = aNavStartTime - parentProcessCreationTime;
   6291  if (delta.IsZero()) {
   6292    return;
   6293  }
   6294 
   6295  aPageloadData->set_androidAppLinkToNavigationStart(
   6296      static_cast<uint32_t>(delta.ToMilliseconds()));
   6297 
   6298  if (profiler_thread_is_being_profiled_for_markers()) {
   6299    PROFILER_MARKER_FMT("Applink Startup", NETWORK,
   6300                        MarkerOptions(MarkerTiming::Interval(
   6301                            parentProcessCreationTime, aNavStartTime)),
   6302                        "ContentParent::RecordAndroidAppLinkTelemetry - Parent "
   6303                        "Process Start To "
   6304                        "Navigation Start for appLinkLaunchType {}",
   6305                        appLinkLaunchType);
   6306  }
   6307 }
   6308 
   6309 mozilla::ipc::IPCResult ContentParent::RecvRecordPageLoadEvent(
   6310    mozilla::performance::pageload_event::PageloadEventData&&
   6311        aPageloadEventData,
   6312    const TimeStamp& aNavigationStartTime,
   6313    uint64_t aAndroidAppLinkLaunchTypeIdentifier) {
   6314  // Check whether a webdriver is running.
   6315  aPageloadEventData.set_usingWebdriver(WebdriverRunning());
   6316 
   6317 #if defined(ANDROID)
   6318  // Get network link type iff android.
   6319  aPageloadEventData.set_networkType(UpdateNetworkLinkType());
   6320 #endif
   6321 
   6322 #if defined(XP_WIN)
   6323  // The "hasSSD" property is only set on Windows during the first
   6324  // call to nsISystemInfo.diskInfo - which is done before
   6325  // browser-startup-idle-tasks-finished
   6326  // Other platforms do not compute hasSSD, so there's no reason to
   6327  // query this on other platforms.
   6328  nsresult rv;
   6329  nsCOMPtr<nsIPropertyBag2> infoService =
   6330      mozilla::components::SystemInfo::Service();
   6331  bool hasSSD;
   6332  rv = infoService->GetPropertyAsBool(u"hasSSD"_ns, &hasSSD);
   6333  if (NS_SUCCEEDED(rv)) {
   6334    aPageloadEventData.set_hasSsd(hasSSD);
   6335  }
   6336 #endif
   6337 
   6338 #ifdef ANDROID
   6339  RecordAndroidAppLinkTelemetry(&aPageloadEventData, aNavigationStartTime,
   6340                                aAndroidAppLinkLaunchTypeIdentifier);
   6341 #endif
   6342 
   6343  // If the domain information exists, then we need to send it using a special
   6344  // page load event ping that is sent via ohttp and stripped of any information
   6345  // that can be used to fingerprint the client.  Otherwise, use the regular
   6346  // pageload event ping.
   6347  if (aPageloadEventData.HasDomain()) {
   6348    aPageloadEventData.SendAsPageLoadDomainEvent();
   6349  } else {
   6350    aPageloadEventData.SendAsPageLoadEvent();
   6351  }
   6352  return IPC_OK();
   6353 }
   6354 
   6355 //////////////////////////////////////////////////////////////////
   6356 // PURLClassifierParent
   6357 
   6358 PURLClassifierParent* ContentParent::AllocPURLClassifierParent(
   6359    nsIPrincipal* aPrincipal, bool* aSuccess) {
   6360  MOZ_ASSERT(NS_IsMainThread());
   6361 
   6362  *aSuccess = true;
   6363  RefPtr<URLClassifierParent> actor = new URLClassifierParent();
   6364  return actor.forget().take();
   6365 }
   6366 
   6367 mozilla::ipc::IPCResult ContentParent::RecvPURLClassifierConstructor(
   6368    PURLClassifierParent* aActor, nsIPrincipal* aPrincipal, bool* aSuccess) {
   6369  MOZ_ASSERT(NS_IsMainThread());
   6370  MOZ_ASSERT(aActor);
   6371  *aSuccess = false;
   6372 
   6373  auto* actor = static_cast<URLClassifierParent*>(aActor);
   6374  nsCOMPtr<nsIPrincipal> principal(aPrincipal);
   6375  if (!principal) {
   6376    actor->ClassificationFailed();
   6377    return IPC_OK();
   6378  }
   6379  if (!ValidatePrincipal(aPrincipal)) {
   6380    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
   6381  }
   6382  return actor->StartClassify(principal, aSuccess);
   6383 }
   6384 
   6385 bool ContentParent::DeallocPURLClassifierParent(PURLClassifierParent* aActor) {
   6386  MOZ_ASSERT(NS_IsMainThread());
   6387  MOZ_ASSERT(aActor);
   6388 
   6389  RefPtr<URLClassifierParent> actor =
   6390      dont_AddRef(static_cast<URLClassifierParent*>(aActor));
   6391  return true;
   6392 }
   6393 
   6394 //////////////////////////////////////////////////////////////////
   6395 // PURLClassifierLocalParent
   6396 
   6397 PURLClassifierLocalParent* ContentParent::AllocPURLClassifierLocalParent(
   6398    nsIURI* aURI, const nsTArray<IPCURLClassifierFeature>& aFeatures) {
   6399  MOZ_ASSERT(NS_IsMainThread());
   6400 
   6401  RefPtr<URLClassifierLocalParent> actor = new URLClassifierLocalParent();
   6402  return actor.forget().take();
   6403 }
   6404 
   6405 mozilla::ipc::IPCResult ContentParent::RecvPURLClassifierLocalConstructor(
   6406    PURLClassifierLocalParent* aActor, nsIURI* aURI,
   6407    nsTArray<IPCURLClassifierFeature>&& aFeatures) {
   6408  MOZ_ASSERT(NS_IsMainThread());
   6409  MOZ_ASSERT(aActor);
   6410 
   6411  nsTArray<IPCURLClassifierFeature> features = std::move(aFeatures);
   6412 
   6413  if (!aURI) {
   6414    return IPC_FAIL(this, "aURI should not be null");
   6415  }
   6416 
   6417  auto* actor = static_cast<URLClassifierLocalParent*>(aActor);
   6418  return actor->StartClassify(aURI, features);
   6419 }
   6420 
   6421 bool ContentParent::DeallocPURLClassifierLocalParent(
   6422    PURLClassifierLocalParent* aActor) {
   6423  MOZ_ASSERT(NS_IsMainThread());
   6424  MOZ_ASSERT(aActor);
   6425 
   6426  RefPtr<URLClassifierLocalParent> actor =
   6427      dont_AddRef(static_cast<URLClassifierLocalParent*>(aActor));
   6428  return true;
   6429 }
   6430 
   6431 //////////////////////////////////////////////////////////////////
   6432 // PURLClassifierLocalByNameParent
   6433 
   6434 PURLClassifierLocalByNameParent*
   6435 ContentParent::AllocPURLClassifierLocalByNameParent(
   6436    nsIURI* aURI, const nsTArray<nsCString>& aFeatures,
   6437    const nsIUrlClassifierFeature::listType& aListType) {
   6438  MOZ_ASSERT(NS_IsMainThread());
   6439 
   6440  RefPtr<URLClassifierLocalByNameParent> actor =
   6441      new URLClassifierLocalByNameParent();
   6442  return actor.forget().take();
   6443 }
   6444 
   6445 mozilla::ipc::IPCResult ContentParent::RecvPURLClassifierLocalByNameConstructor(
   6446    PURLClassifierLocalByNameParent* aActor, nsIURI* aURI,
   6447    nsTArray<nsCString>&& aFeatureNames,
   6448    const nsIUrlClassifierFeature::listType& aListType) {
   6449  MOZ_ASSERT(NS_IsMainThread());
   6450  MOZ_ASSERT(aActor);
   6451  if (!aURI) {
   6452    return IPC_FAIL(this, "aURI should not be null");
   6453  }
   6454 
   6455  nsTArray<IPCURLClassifierFeature> ipcFeatures;
   6456  for (nsCString& featureName : aFeatureNames) {
   6457    RefPtr<nsIUrlClassifierFeature> feature =
   6458        UrlClassifierFeatureFactory::GetFeatureByName(featureName);
   6459    nsAutoCString name;
   6460    nsresult rv = feature->GetName(name);
   6461    if (NS_WARN_IF(NS_FAILED(rv))) {
   6462      continue;
   6463    }
   6464 
   6465    nsTArray<nsCString> tables;
   6466    rv = feature->GetTables(aListType, tables);
   6467    if (NS_WARN_IF(NS_FAILED(rv))) {
   6468      continue;
   6469    }
   6470 
   6471    ipcFeatures.AppendElement(IPCURLClassifierFeature(name, tables));
   6472  }
   6473 
   6474  auto* actor = static_cast<URLClassifierLocalByNameParent*>(aActor);
   6475  return actor->StartClassify(aURI, ipcFeatures, aListType);
   6476 }
   6477 
   6478 bool ContentParent::DeallocPURLClassifierLocalByNameParent(
   6479    PURLClassifierLocalByNameParent* aActor) {
   6480  MOZ_ASSERT(NS_IsMainThread());
   6481  MOZ_ASSERT(aActor);
   6482 
   6483  RefPtr<URLClassifierLocalByNameParent> actor =
   6484      dont_AddRef(static_cast<URLClassifierLocalByNameParent*>(aActor));
   6485  return true;
   6486 }
   6487 
   6488 PSessionStorageObserverParent*
   6489 ContentParent::AllocPSessionStorageObserverParent() {
   6490  MOZ_ASSERT(NS_IsMainThread());
   6491 
   6492  return mozilla::dom::AllocPSessionStorageObserverParent();
   6493 }
   6494 
   6495 mozilla::ipc::IPCResult ContentParent::RecvPSessionStorageObserverConstructor(
   6496    PSessionStorageObserverParent* aActor) {
   6497  MOZ_ASSERT(NS_IsMainThread());
   6498  MOZ_ASSERT(aActor);
   6499 
   6500  if (!mozilla::dom::RecvPSessionStorageObserverConstructor(aActor)) {
   6501    return IPC_FAIL(this, "RecvPSessionStorageObserverConstructor failed.");
   6502  }
   6503  return IPC_OK();
   6504 }
   6505 
   6506 bool ContentParent::DeallocPSessionStorageObserverParent(
   6507    PSessionStorageObserverParent* aActor) {
   6508  MOZ_ASSERT(NS_IsMainThread());
   6509  MOZ_ASSERT(aActor);
   6510 
   6511  return mozilla::dom::DeallocPSessionStorageObserverParent(aActor);
   6512 }
   6513 
   6514 mozilla::ipc::IPCResult ContentParent::RecvBHRThreadHang(
   6515    const HangDetails& aHangDetails) {
   6516  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   6517  if (obs) {
   6518    // Copy the HangDetails recieved over the network into a nsIHangDetails, and
   6519    // then fire our own observer notification.
   6520    // XXX: We should be able to avoid this potentially expensive copy here by
   6521    // moving our deserialized argument.
   6522    nsCOMPtr<nsIHangDetails> hangDetails =
   6523        new nsHangDetails(HangDetails(aHangDetails), PersistedToDisk::No);
   6524    obs->NotifyObservers(hangDetails, "bhr-thread-hang", nullptr);
   6525  }
   6526  return IPC_OK();
   6527 }
   6528 
   6529 mozilla::ipc::IPCResult ContentParent::RecvAddCertException(
   6530    nsIX509Cert* aCert, const nsACString& aHostName, int32_t aPort,
   6531    const OriginAttributes& aOriginAttributes, bool aIsTemporary,
   6532    AddCertExceptionResolver&& aResolver) {
   6533  nsCOMPtr<nsICertOverrideService> overrideService =
   6534      do_GetService(NS_CERTOVERRIDE_CONTRACTID);
   6535  if (!overrideService) {
   6536    aResolver(NS_ERROR_FAILURE);
   6537    return IPC_OK();
   6538  }
   6539  nsresult rv = overrideService->RememberValidityOverride(
   6540      aHostName, aPort, aOriginAttributes, aCert, aIsTemporary);
   6541  aResolver(rv);
   6542  return IPC_OK();
   6543 }
   6544 
   6545 mozilla::ipc::IPCResult
   6546 ContentParent::RecvAutomaticStorageAccessPermissionCanBeGranted(
   6547    nsIPrincipal* aPrincipal,
   6548    AutomaticStorageAccessPermissionCanBeGrantedResolver&& aResolver) {
   6549  if (!aPrincipal) {
   6550    return IPC_FAIL(this, "No principal");
   6551  }
   6552 
   6553  if (!ValidatePrincipal(aPrincipal)) {
   6554    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
   6555  }
   6556  aResolver(Document::AutomaticStorageAccessPermissionCanBeGranted(aPrincipal));
   6557  return IPC_OK();
   6558 }
   6559 
   6560 mozilla::ipc::IPCResult
   6561 ContentParent::RecvStorageAccessPermissionGrantedForOrigin(
   6562    uint64_t aTopLevelWindowId,
   6563    const MaybeDiscarded<BrowsingContext>& aParentContext,
   6564    nsIPrincipal* aTrackingPrincipal, const nsACString& aTrackingOrigin,
   6565    const int& aAllowMode,
   6566    const Maybe<ContentBlockingNotifier::StorageAccessPermissionGrantedReason>&
   6567        aReason,
   6568    const bool& aFrameOnly,
   6569    StorageAccessPermissionGrantedForOriginResolver&& aResolver) {
   6570  if (aParentContext.IsNullOrDiscarded()) {
   6571    return IPC_OK();
   6572  }
   6573 
   6574  if (!aTrackingPrincipal) {
   6575    return IPC_FAIL(this, "No principal");
   6576  }
   6577 
   6578  // We only report here if we cannot report the console directly in the content
   6579  // process. In that case, the `aReason` would be given a value. Otherwise, it
   6580  // will be nothing.
   6581  if (aReason) {
   6582    ContentBlockingNotifier::ReportUnblockingToConsole(
   6583        aParentContext.get_canonical(), NS_ConvertUTF8toUTF16(aTrackingOrigin),
   6584        aReason.value());
   6585  }
   6586 
   6587  StorageAccessAPIHelper::SaveAccessForOriginOnParentProcess(
   6588      aTopLevelWindowId, aParentContext.get_canonical(), aTrackingPrincipal,
   6589      aAllowMode, aFrameOnly)
   6590      ->Then(GetCurrentSerialEventTarget(), __func__,
   6591             [aResolver = std::move(aResolver)](
   6592                 StorageAccessAPIHelper::ParentAccessGrantPromise::
   6593                     ResolveOrRejectValue&& aValue) {
   6594               bool success =
   6595                   aValue.IsResolve() && NS_SUCCEEDED(aValue.ResolveValue());
   6596               aResolver(success);
   6597             });
   6598  return IPC_OK();
   6599 }
   6600 
   6601 mozilla::ipc::IPCResult ContentParent::RecvCompleteAllowAccessFor(
   6602    const MaybeDiscarded<BrowsingContext>& aParentContext,
   6603    uint64_t aTopLevelWindowId, nsIPrincipal* aTrackingPrincipal,
   6604    const nsACString& aTrackingOrigin, uint32_t aCookieBehavior,
   6605    const ContentBlockingNotifier::StorageAccessPermissionGrantedReason&
   6606        aReason,
   6607    CompleteAllowAccessForResolver&& aResolver) {
   6608  if (aParentContext.IsNullOrDiscarded()) {
   6609    return IPC_OK();
   6610  }
   6611 
   6612  StorageAccessAPIHelper::CompleteAllowAccessForOnParentProcess(
   6613      aParentContext.get_canonical(), aTopLevelWindowId, aTrackingPrincipal,
   6614      aTrackingOrigin, aCookieBehavior, aReason, nullptr)
   6615      ->Then(GetCurrentSerialEventTarget(), __func__,
   6616             [aResolver = std::move(aResolver)](
   6617                 StorageAccessAPIHelper::StorageAccessPermissionGrantPromise::
   6618                     ResolveOrRejectValue&& aValue) {
   6619               Maybe<StorageAccessPromptChoices> choice;
   6620               if (aValue.IsResolve()) {
   6621                 choice.emplace(static_cast<StorageAccessPromptChoices>(
   6622                     aValue.ResolveValue()));
   6623               }
   6624               aResolver(choice);
   6625             });
   6626  return IPC_OK();
   6627 }
   6628 
   6629 mozilla::ipc::IPCResult ContentParent::RecvSetAllowStorageAccessRequestFlag(
   6630    nsIPrincipal* aEmbeddedPrincipal, nsIURI* aEmbeddingOrigin,
   6631    SetAllowStorageAccessRequestFlagResolver&& aResolver) {
   6632  MOZ_ASSERT(aEmbeddedPrincipal);
   6633  MOZ_ASSERT(aEmbeddingOrigin);
   6634 
   6635  if (!aEmbeddedPrincipal || !aEmbeddingOrigin) {
   6636    aResolver(false);
   6637    return IPC_OK();
   6638  }
   6639 
   6640  // Get the permission manager and build the key.
   6641  RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
   6642  if (!permManager) {
   6643    aResolver(false);
   6644    return IPC_OK();
   6645  }
   6646  nsCOMPtr<nsIURI> embeddedURI = aEmbeddedPrincipal->GetURI();
   6647  nsCString permissionKey;
   6648  bool success = AntiTrackingUtils::CreateStorageRequestPermissionKey(
   6649      embeddedURI, permissionKey);
   6650  if (!success) {
   6651    aResolver(false);
   6652    return IPC_OK();
   6653  }
   6654 
   6655  // Set the permission to ALLOW for a prefence specified amount of seconds.
   6656  // Time units are inconsistent, be careful
   6657  int64_t when = (PR_Now() / PR_USEC_PER_MSEC) +
   6658                 StaticPrefs::dom_storage_access_forward_declared_lifetime() *
   6659                     PR_MSEC_PER_SEC;
   6660  nsCOMPtr<nsIPrincipal> principal = BasePrincipal::CreateContentPrincipal(
   6661      aEmbeddingOrigin, aEmbeddedPrincipal->OriginAttributesRef());
   6662  nsresult rv = permManager->AddFromPrincipal(
   6663      principal, permissionKey, nsIPermissionManager::ALLOW_ACTION,
   6664      nsIPermissionManager::EXPIRE_TIME, when);
   6665  if (NS_FAILED(rv)) {
   6666    aResolver(false);
   6667    return IPC_OK();
   6668  }
   6669 
   6670  // Resolve with success if we set the permission.
   6671  aResolver(true);
   6672  return IPC_OK();
   6673 }
   6674 
   6675 mozilla::ipc::IPCResult ContentParent::RecvTestAllowStorageAccessRequestFlag(
   6676    nsIPrincipal* aEmbeddingPrincipal, nsIURI* aEmbeddedOrigin,
   6677    TestAllowStorageAccessRequestFlagResolver&& aResolver) {
   6678  MOZ_ASSERT(aEmbeddingPrincipal);
   6679  MOZ_ASSERT(aEmbeddedOrigin);
   6680 
   6681  // Get the permission manager and build the key.
   6682  RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
   6683  if (!permManager) {
   6684    aResolver(false);
   6685    return IPC_OK();
   6686  }
   6687  nsCString requestPermissionKey;
   6688  bool success = AntiTrackingUtils::CreateStorageRequestPermissionKey(
   6689      aEmbeddedOrigin, requestPermissionKey);
   6690  if (!success) {
   6691    aResolver(false);
   6692    return IPC_OK();
   6693  }
   6694 
   6695  // Get the permission and resolve false if it is not set to ALLOW.
   6696  uint32_t access = nsIPermissionManager::UNKNOWN_ACTION;
   6697  nsresult rv = permManager->TestPermissionFromPrincipal(
   6698      aEmbeddingPrincipal, requestPermissionKey, &access);
   6699  if (NS_FAILED(rv)) {
   6700    aResolver(false);
   6701    return IPC_OK();
   6702  }
   6703  if (access != nsIPermissionManager::ALLOW_ACTION) {
   6704    aResolver(false);
   6705    return IPC_OK();
   6706  }
   6707 
   6708  // Remove the permission, failing if the permission manager fails
   6709  rv = permManager->RemoveFromPrincipal(aEmbeddingPrincipal,
   6710                                        requestPermissionKey);
   6711  if (NS_FAILED(rv)) {
   6712    aResolver(false);
   6713    return IPC_OK();
   6714  }
   6715 
   6716  // At this point, signal to our caller that the permission was set
   6717  aResolver(true);
   6718  return IPC_OK();
   6719 }
   6720 
   6721 mozilla::ipc::IPCResult ContentParent::RecvStoreUserInteractionAsPermission(
   6722    nsIPrincipal* aPrincipal) {
   6723  if (!aPrincipal) {
   6724    return IPC_FAIL(this, "No principal");
   6725  }
   6726 
   6727  if (!ValidatePrincipal(aPrincipal)) {
   6728    LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
   6729  }
   6730  ContentBlockingUserInteraction::Observe(aPrincipal);
   6731  return IPC_OK();
   6732 }
   6733 
   6734 mozilla::ipc::IPCResult ContentParent::RecvTestCookiePermissionDecided(
   6735    const MaybeDiscarded<BrowsingContext>& aContext, nsIPrincipal* aPrincipal,
   6736    const TestCookiePermissionDecidedResolver&& aResolver) {
   6737  if (aContext.IsNullOrDiscarded()) {
   6738    return IPC_OK();
   6739  }
   6740 
   6741  if (!aPrincipal) {
   6742    return IPC_FAIL(this, "No principal");
   6743  }
   6744 
   6745  RefPtr<WindowGlobalParent> wgp =
   6746      aContext.get_canonical()->GetCurrentWindowGlobal();
   6747  nsCOMPtr<nsICookieJarSettings> cjs = wgp->CookieJarSettings();
   6748 
   6749  Maybe<bool> result =
   6750      StorageAccessAPIHelper::CheckCookiesPermittedDecidesStorageAccessAPI(
   6751          cjs, aPrincipal);
   6752  aResolver(result);
   6753  return IPC_OK();
   6754 }
   6755 
   6756 mozilla::ipc::IPCResult ContentParent::RecvTestStorageAccessPermission(
   6757    nsIPrincipal* aEmbeddingPrincipal, const nsCString& aEmbeddedOrigin,
   6758    const TestStorageAccessPermissionResolver&& aResolver) {
   6759  // Get the permission manager and build the key.
   6760  RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
   6761  if (!permManager) {
   6762    aResolver(Nothing());
   6763    return IPC_OK();
   6764  }
   6765  nsCString requestPermissionKey;
   6766  AntiTrackingUtils::CreateStoragePermissionKey(aEmbeddedOrigin,
   6767                                                requestPermissionKey);
   6768 
   6769  // Test the permission
   6770  uint32_t access = nsIPermissionManager::UNKNOWN_ACTION;
   6771  nsresult rv = permManager->TestPermissionFromPrincipal(
   6772      aEmbeddingPrincipal, requestPermissionKey, &access);
   6773  if (NS_FAILED(rv)) {
   6774    aResolver(Nothing());
   6775    return IPC_OK();
   6776  }
   6777  if (access == nsIPermissionManager::ALLOW_ACTION) {
   6778    aResolver(Some(true));
   6779  } else if (access == nsIPermissionManager::DENY_ACTION) {
   6780    aResolver(Some(false));
   6781  } else {
   6782    aResolver(Nothing());
   6783  }
   6784 
   6785  return IPC_OK();
   6786 }
   6787 
   6788 mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaPlaybackChanged(
   6789    const MaybeDiscarded<BrowsingContext>& aContext,
   6790    MediaPlaybackState aState) {
   6791  if (aContext.IsNullOrDiscarded()) {
   6792    return IPC_OK();
   6793  }
   6794  if (RefPtr<IMediaInfoUpdater> updater =
   6795          aContext.get_canonical()->GetMediaController()) {
   6796    updater->NotifyMediaPlaybackChanged(aContext.ContextId(), aState);
   6797  }
   6798  return IPC_OK();
   6799 }
   6800 
   6801 mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaAudibleChanged(
   6802    const MaybeDiscarded<BrowsingContext>& aContext, MediaAudibleState aState) {
   6803  if (aContext.IsNullOrDiscarded()) {
   6804    return IPC_OK();
   6805  }
   6806  if (RefPtr<IMediaInfoUpdater> updater =
   6807          aContext.get_canonical()->GetMediaController()) {
   6808    updater->NotifyMediaAudibleChanged(aContext.ContextId(), aState);
   6809  }
   6810  return IPC_OK();
   6811 }
   6812 
   6813 mozilla::ipc::IPCResult ContentParent::RecvNotifyPictureInPictureModeChanged(
   6814    const MaybeDiscarded<BrowsingContext>& aContext, bool aEnabled) {
   6815  if (aContext.IsNullOrDiscarded()) {
   6816    return IPC_OK();
   6817  }
   6818  if (RefPtr<MediaController> controller =
   6819          aContext.get_canonical()->GetMediaController()) {
   6820    controller->SetIsInPictureInPictureMode(aContext.ContextId(), aEnabled);
   6821  }
   6822  return IPC_OK();
   6823 }
   6824 
   6825 mozilla::ipc::IPCResult ContentParent::RecvAbortOtherOrientationPendingPromises(
   6826    const MaybeDiscarded<BrowsingContext>& aContext) {
   6827  if (aContext.IsNullOrDiscarded()) {
   6828    return IPC_OK();
   6829  }
   6830 
   6831  CanonicalBrowsingContext* context = aContext.get_canonical();
   6832 
   6833  context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
   6834    (void)aParent->SendAbortOrientationPendingPromises(context);
   6835  });
   6836 
   6837  return IPC_OK();
   6838 }
   6839 
   6840 mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaSessionUpdated(
   6841    const MaybeDiscarded<BrowsingContext>& aContext, bool aIsCreated) {
   6842  if (aContext.IsNullOrDiscarded()) {
   6843    return IPC_OK();
   6844  }
   6845 
   6846  RefPtr<IMediaInfoUpdater> updater =
   6847      aContext.get_canonical()->GetMediaController();
   6848  if (!updater) {
   6849    return IPC_OK();
   6850  }
   6851  if (aIsCreated) {
   6852    updater->NotifySessionCreated(aContext->Id());
   6853  } else {
   6854    updater->NotifySessionDestroyed(aContext->Id());
   6855  }
   6856  return IPC_OK();
   6857 }
   6858 
   6859 mozilla::ipc::IPCResult ContentParent::RecvNotifyUpdateMediaMetadata(
   6860    const MaybeDiscarded<BrowsingContext>& aContext,
   6861    const Maybe<MediaMetadataBase>& aMetadata) {
   6862  if (aContext.IsNullOrDiscarded()) {
   6863    return IPC_OK();
   6864  }
   6865  if (RefPtr<IMediaInfoUpdater> updater =
   6866          aContext.get_canonical()->GetMediaController()) {
   6867    updater->UpdateMetadata(aContext.ContextId(), aMetadata);
   6868  }
   6869  return IPC_OK();
   6870 }
   6871 
   6872 mozilla::ipc::IPCResult
   6873 ContentParent::RecvNotifyMediaSessionPlaybackStateChanged(
   6874    const MaybeDiscarded<BrowsingContext>& aContext,
   6875    MediaSessionPlaybackState aPlaybackState) {
   6876  if (aContext.IsNullOrDiscarded()) {
   6877    return IPC_OK();
   6878  }
   6879  if (RefPtr<IMediaInfoUpdater> updater =
   6880          aContext.get_canonical()->GetMediaController()) {
   6881    updater->SetDeclaredPlaybackState(aContext.ContextId(), aPlaybackState);
   6882  }
   6883  return IPC_OK();
   6884 }
   6885 
   6886 mozilla::ipc::IPCResult
   6887 ContentParent::RecvNotifyMediaSessionSupportedActionChanged(
   6888    const MaybeDiscarded<BrowsingContext>& aContext, MediaSessionAction aAction,
   6889    bool aEnabled) {
   6890  if (aContext.IsNullOrDiscarded()) {
   6891    return IPC_OK();
   6892  }
   6893  RefPtr<IMediaInfoUpdater> updater =
   6894      aContext.get_canonical()->GetMediaController();
   6895  if (!updater) {
   6896    return IPC_OK();
   6897  }
   6898  if (aEnabled) {
   6899    updater->EnableAction(aContext.ContextId(), aAction);
   6900  } else {
   6901    updater->DisableAction(aContext.ContextId(), aAction);
   6902  }
   6903  return IPC_OK();
   6904 }
   6905 
   6906 mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaFullScreenState(
   6907    const MaybeDiscarded<BrowsingContext>& aContext, bool aIsInFullScreen) {
   6908  if (aContext.IsNullOrDiscarded()) {
   6909    return IPC_OK();
   6910  }
   6911  if (RefPtr<IMediaInfoUpdater> updater =
   6912          aContext.get_canonical()->GetMediaController()) {
   6913    updater->NotifyMediaFullScreenState(aContext.ContextId(), aIsInFullScreen);
   6914  }
   6915  return IPC_OK();
   6916 }
   6917 
   6918 mozilla::ipc::IPCResult ContentParent::RecvNotifyPositionStateChanged(
   6919    const MaybeDiscarded<BrowsingContext>& aContext,
   6920    const Maybe<PositionState>& aState) {
   6921  if (aContext.IsNullOrDiscarded()) {
   6922    return IPC_OK();
   6923  }
   6924  if (RefPtr<IMediaInfoUpdater> updater =
   6925          aContext.get_canonical()->GetMediaController()) {
   6926    updater->UpdatePositionState(aContext.ContextId(), aState);
   6927  }
   6928  return IPC_OK();
   6929 }
   6930 
   6931 mozilla::ipc::IPCResult ContentParent::RecvNotifyGuessedPositionStateChanged(
   6932    const MaybeDiscarded<BrowsingContext>& aContext, const nsID& aMediaId,
   6933    const Maybe<PositionState>& aState) {
   6934  if (aContext.IsNullOrDiscarded()) {
   6935    return IPC_OK();
   6936  }
   6937  if (RefPtr<IMediaInfoUpdater> updater =
   6938          aContext.get_canonical()->GetMediaController()) {
   6939    updater->UpdateGuessedPositionState(aContext.ContextId(), aMediaId, aState);
   6940  }
   6941  return IPC_OK();
   6942 }
   6943 
   6944 mozilla::ipc::IPCResult ContentParent::RecvAddOrRemovePageAwakeRequest(
   6945    const MaybeDiscarded<BrowsingContext>& aContext,
   6946    const bool& aShouldAddCount) {
   6947  if (aContext.IsNullOrDiscarded()) {
   6948    return IPC_OK();
   6949  }
   6950  if (aShouldAddCount) {
   6951    aContext.get_canonical()->AddPageAwakeRequest();
   6952  } else {
   6953    aContext.get_canonical()->RemovePageAwakeRequest();
   6954  }
   6955  return IPC_OK();
   6956 }
   6957 
   6958 #if defined(XP_WIN)
   6959 mozilla::ipc::IPCResult ContentParent::RecvGetModulesTrust(
   6960    ModulePaths&& aModPaths, bool aRunAtNormalPriority,
   6961    GetModulesTrustResolver&& aResolver) {
   6962  RefPtr<DllServices> dllSvc(DllServices::Get());
   6963  dllSvc->GetModulesTrust(std::move(aModPaths), aRunAtNormalPriority)
   6964      ->Then(
   6965          GetMainThreadSerialEventTarget(), __func__,
   6966          [aResolver](ModulesMapResult&& aResult) {
   6967            aResolver(Some(ModulesMapResult(std::move(aResult))));
   6968          },
   6969          [aResolver](nsresult aRv) { aResolver(Nothing()); });
   6970  return IPC_OK();
   6971 }
   6972 #endif  // defined(XP_WIN)
   6973 
   6974 mozilla::ipc::IPCResult ContentParent::RecvCreateBrowsingContext(
   6975    uint64_t aGroupId, BrowsingContext::IPCInitializer&& aInit) {
   6976  RefPtr<WindowGlobalParent> parent;
   6977  if (aInit.mParentId != 0) {
   6978    parent = WindowGlobalParent::GetByInnerWindowId(aInit.mParentId);
   6979    if (!parent) {
   6980      return IPC_FAIL(this, "Parent doesn't exist in parent process");
   6981    }
   6982  }
   6983 
   6984  if (parent && parent->GetContentParent() != this) {
   6985    // We're trying attach a child BrowsingContext to a parent
   6986    // WindowContext in another process. This is illegal since the
   6987    // only thing that could create that child BrowsingContext is the parent
   6988    // window's process.
   6989    return IPC_FAIL(this,
   6990                    "Must create BrowsingContext from the parent's process");
   6991  }
   6992 
   6993  RefPtr<BrowsingContext> opener;
   6994  if (aInit.GetOpenerId() != 0) {
   6995    opener = BrowsingContext::Get(aInit.GetOpenerId());
   6996    if (!opener) {
   6997      return IPC_FAIL(this, "Opener doesn't exist in parent process");
   6998    }
   6999  }
   7000 
   7001  RefPtr<BrowsingContext> child = BrowsingContext::Get(aInit.mId);
   7002  if (child) {
   7003    // This is highly suspicious. BrowsingContexts should only be created once,
   7004    // so finding one indicates that someone is doing something they shouldn't.
   7005    return IPC_FAIL(this, "A BrowsingContext with this ID already exists");
   7006  }
   7007 
   7008  // Ensure that the passed-in BrowsingContextGroup is valid.
   7009  RefPtr<BrowsingContextGroup> group =
   7010      BrowsingContextGroup::GetOrCreate(aGroupId);
   7011  if (parent) {
   7012    if (parent->Group()->Id() != aGroupId) {
   7013      return IPC_FAIL(this, "Parent has different group ID");
   7014    }
   7015    if (parent->IsDiscarded()) {
   7016      return IPC_FAIL(this, "Parent is discarded");
   7017    }
   7018    if (parent->Group() != group) {
   7019      return IPC_FAIL(this, "Parent has different group object");
   7020    }
   7021  }
   7022  if (opener && opener->Group() != group) {
   7023    if (opener->Group()->Id() != aGroupId) {
   7024      return IPC_FAIL(this, "Opener has different group ID");
   7025    }
   7026    return IPC_FAIL(this, "Opener has different group object");
   7027  }
   7028  if (!parent && !opener && !group->Toplevels().IsEmpty()) {
   7029    return IPC_FAIL(this, "Unrelated context from child in stale group");
   7030  }
   7031 
   7032  return BrowsingContext::CreateFromIPC(std::move(aInit), group, this);
   7033 }
   7034 
   7035 bool ContentParent::CheckBrowsingContextEmbedder(CanonicalBrowsingContext* aBC,
   7036                                                 const char* aOperation) const {
   7037  if (!aBC->IsEmbeddedInProcess(ChildID())) {
   7038    MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
   7039            ("ParentIPC: Trying to %s out of process context 0x%08" PRIx64,
   7040             aOperation, aBC->Id()));
   7041    return false;
   7042  }
   7043  return true;
   7044 }
   7045 
   7046 mozilla::ipc::IPCResult ContentParent::RecvDiscardBrowsingContext(
   7047    const MaybeDiscarded<BrowsingContext>& aContext, bool aDoDiscard,
   7048    DiscardBrowsingContextResolver&& aResolve) {
   7049  if (CanonicalBrowsingContext* context =
   7050          CanonicalBrowsingContext::Cast(aContext.GetMaybeDiscarded())) {
   7051    if (aDoDiscard && !context->IsDiscarded()) {
   7052      if (!CheckBrowsingContextEmbedder(context, "discard")) {
   7053        return IPC_FAIL(this, "Illegal Discard attempt");
   7054      }
   7055 
   7056      context->Detach(/* aFromIPC */ true);
   7057    }
   7058    context->AddFinalDiscardListener(aResolve);
   7059    return IPC_OK();
   7060  }
   7061 
   7062  // Resolve the promise, as we've received and handled the message. This will
   7063  // allow the content process to fully-discard references to this BC.
   7064  aResolve(true);
   7065  return IPC_OK();
   7066 }
   7067 
   7068 mozilla::ipc::IPCResult ContentParent::RecvWindowClose(
   7069    const MaybeDiscarded<BrowsingContext>& aContext, bool aTrustedCaller) {
   7070  if (aContext.IsNullOrDiscarded()) {
   7071    MOZ_LOG(
   7072        BrowsingContext::GetLog(), LogLevel::Debug,
   7073        ("ParentIPC: Trying to send a message to dead or detached context"));
   7074    return IPC_OK();
   7075  }
   7076  CanonicalBrowsingContext* context = aContext.get_canonical();
   7077 
   7078  // FIXME Need to check that the sending process has access to the unit of
   7079  // related
   7080  //       browsing contexts of bc.
   7081 
   7082  if (ContentParent* cp = context->GetContentParent()) {
   7083    (void)cp->SendWindowClose(context, aTrustedCaller);
   7084  }
   7085  return IPC_OK();
   7086 }
   7087 
   7088 mozilla::ipc::IPCResult ContentParent::RecvWindowFocus(
   7089    const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType,
   7090    uint64_t aActionId) {
   7091  if (aContext.IsNullOrDiscarded()) {
   7092    MOZ_LOG(
   7093        BrowsingContext::GetLog(), LogLevel::Debug,
   7094        ("ParentIPC: Trying to send a message to dead or detached context"));
   7095    return IPC_OK();
   7096  }
   7097  LOGFOCUS(("ContentParent::RecvWindowFocus actionid: %" PRIu64, aActionId));
   7098  CanonicalBrowsingContext* context = aContext.get_canonical();
   7099 
   7100  if (ContentParent* cp = context->GetContentParent()) {
   7101    (void)cp->SendWindowFocus(context, aCallerType, aActionId);
   7102  }
   7103  return IPC_OK();
   7104 }
   7105 
   7106 mozilla::ipc::IPCResult ContentParent::RecvWindowBlur(
   7107    const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType) {
   7108  if (aContext.IsNullOrDiscarded()) {
   7109    MOZ_LOG(
   7110        BrowsingContext::GetLog(), LogLevel::Debug,
   7111        ("ParentIPC: Trying to send a message to dead or detached context"));
   7112    return IPC_OK();
   7113  }
   7114  CanonicalBrowsingContext* context = aContext.get_canonical();
   7115 
   7116  if (ContentParent* cp = context->GetContentParent()) {
   7117    (void)cp->SendWindowBlur(context, aCallerType);
   7118  }
   7119  return IPC_OK();
   7120 }
   7121 
   7122 mozilla::ipc::IPCResult ContentParent::RecvRaiseWindow(
   7123    const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType,
   7124    uint64_t aActionId) {
   7125  if (aContext.IsNullOrDiscarded()) {
   7126    MOZ_LOG(
   7127        BrowsingContext::GetLog(), LogLevel::Debug,
   7128        ("ParentIPC: Trying to send a message to dead or detached context"));
   7129    return IPC_OK();
   7130  }
   7131  LOGFOCUS(("ContentParent::RecvRaiseWindow actionid: %" PRIu64, aActionId));
   7132 
   7133  CanonicalBrowsingContext* context = aContext.get_canonical();
   7134 
   7135  if (ContentParent* cp = context->GetContentParent()) {
   7136    (void)cp->SendRaiseWindow(context, aCallerType, aActionId);
   7137  }
   7138  return IPC_OK();
   7139 }
   7140 
   7141 mozilla::ipc::IPCResult ContentParent::RecvAdjustWindowFocus(
   7142    const MaybeDiscarded<BrowsingContext>& aContext, bool aIsVisible,
   7143    uint64_t aActionId, bool aShouldClearFocus,
   7144    const MaybeDiscarded<BrowsingContext>& aAncestorBrowsingContextToFocus) {
   7145  if (aContext.IsNullOrDiscarded()) {
   7146    MOZ_LOG(
   7147        BrowsingContext::GetLog(), LogLevel::Debug,
   7148        ("ParentIPC: Trying to send a message to dead or detached context"));
   7149    return IPC_OK();
   7150  }
   7151  LOGFOCUS(
   7152      ("ContentParent::RecvAdjustWindowFocus isVisible %d actionid: %" PRIu64,
   7153       aIsVisible, aActionId));
   7154 
   7155  nsTHashMap<nsPtrHashKey<ContentParent>, bool> processes(2);
   7156  processes.InsertOrUpdate(this, true);
   7157 
   7158  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
   7159  if (cpm) {
   7160    CanonicalBrowsingContext* context = aContext.get_canonical();
   7161    while (context) {
   7162      BrowsingContext* parent = context->GetParent();
   7163      if (!parent) {
   7164        break;
   7165      }
   7166 
   7167      CanonicalBrowsingContext* canonicalParent = parent->Canonical();
   7168      ContentParent* cp = cpm->GetContentProcessById(
   7169          ContentParentId(canonicalParent->OwnerProcessId()));
   7170      if (cp && !processes.Get(cp)) {
   7171        (void)cp->SendAdjustWindowFocus(context, aIsVisible, aActionId,
   7172                                        aShouldClearFocus,
   7173                                        aAncestorBrowsingContextToFocus);
   7174        processes.InsertOrUpdate(cp, true);
   7175      }
   7176      context = canonicalParent;
   7177    }
   7178  }
   7179  return IPC_OK();
   7180 }
   7181 
   7182 mozilla::ipc::IPCResult ContentParent::RecvClearFocus(
   7183    const MaybeDiscarded<BrowsingContext>& aContext) {
   7184  if (aContext.IsNullOrDiscarded()) {
   7185    MOZ_LOG(
   7186        BrowsingContext::GetLog(), LogLevel::Debug,
   7187        ("ParentIPC: Trying to send a message to dead or detached context"));
   7188    return IPC_OK();
   7189  }
   7190  CanonicalBrowsingContext* context = aContext.get_canonical();
   7191 
   7192  if (ContentParent* cp = context->GetContentParent()) {
   7193    (void)cp->SendClearFocus(context);
   7194  }
   7195  return IPC_OK();
   7196 }
   7197 
   7198 mozilla::ipc::IPCResult ContentParent::RecvSetFocusedBrowsingContext(
   7199    const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
   7200  if (aContext.IsNullOrDiscarded()) {
   7201    MOZ_LOG(
   7202        BrowsingContext::GetLog(), LogLevel::Debug,
   7203        ("ParentIPC: Trying to send a message to dead or detached context"));
   7204    return IPC_OK();
   7205  }
   7206  LOGFOCUS(("ContentParent::RecvSetFocusedBrowsingContext actionid: %" PRIu64,
   7207            aActionId));
   7208  CanonicalBrowsingContext* context = aContext.get_canonical();
   7209 
   7210  nsFocusManager* fm = nsFocusManager::GetFocusManager();
   7211  if (!fm) {
   7212    return IPC_OK();
   7213  }
   7214 
   7215  if (!fm->SetFocusedBrowsingContextInChrome(context, aActionId)) {
   7216    LOGFOCUS((
   7217        "Ignoring out-of-sequence attempt [%p] to set focused browsing context "
   7218        "in parent.",
   7219        context));
   7220    (void)SendReviseFocusedBrowsingContext(
   7221        aActionId, fm->GetFocusedBrowsingContextInChrome(),
   7222        fm->GetActionIdForFocusedBrowsingContextInChrome());
   7223    return IPC_OK();
   7224  }
   7225 
   7226  BrowserParent::UpdateFocusFromBrowsingContext();
   7227 
   7228  context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
   7229    (void)aParent->SendSetFocusedBrowsingContext(context, aActionId);
   7230  });
   7231 
   7232  return IPC_OK();
   7233 }
   7234 
   7235 mozilla::ipc::IPCResult ContentParent::RecvSetActiveBrowsingContext(
   7236    const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
   7237  if (aContext.IsNullOrDiscarded()) {
   7238    MOZ_LOG(
   7239        BrowsingContext::GetLog(), LogLevel::Debug,
   7240        ("ParentIPC: Trying to send a message to dead or detached context"));
   7241    return IPC_OK();
   7242  }
   7243  LOGFOCUS(("ContentParent::RecvSetActiveBrowsingContext actionid: %" PRIu64,
   7244            aActionId));
   7245  CanonicalBrowsingContext* context = aContext.get_canonical();
   7246 
   7247  nsFocusManager* fm = nsFocusManager::GetFocusManager();
   7248  if (!fm) {
   7249    return IPC_OK();
   7250  }
   7251 
   7252  if (!fm->SetActiveBrowsingContextInChrome(context, aActionId)) {
   7253    LOGFOCUS(
   7254        ("Ignoring out-of-sequence attempt [%p] to set active browsing context "
   7255         "in parent.",
   7256         context));
   7257    (void)SendReviseActiveBrowsingContext(
   7258        aActionId, fm->GetActiveBrowsingContextInChrome(),
   7259        fm->GetActionIdForActiveBrowsingContextInChrome());
   7260    return IPC_OK();
   7261  }
   7262 
   7263  context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
   7264    (void)aParent->SendSetActiveBrowsingContext(context, aActionId);
   7265  });
   7266 
   7267  return IPC_OK();
   7268 }
   7269 
   7270 mozilla::ipc::IPCResult ContentParent::RecvUnsetActiveBrowsingContext(
   7271    const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
   7272  if (aContext.IsNullOrDiscarded()) {
   7273    MOZ_LOG(
   7274        BrowsingContext::GetLog(), LogLevel::Debug,
   7275        ("ParentIPC: Trying to send a message to dead or detached context"));
   7276    return IPC_OK();
   7277  }
   7278  LOGFOCUS(("ContentParent::RecvUnsetActiveBrowsingContext actionid: %" PRIu64,
   7279            aActionId));
   7280  CanonicalBrowsingContext* context = aContext.get_canonical();
   7281 
   7282  nsFocusManager* fm = nsFocusManager::GetFocusManager();
   7283  if (!fm) {
   7284    return IPC_OK();
   7285  }
   7286 
   7287  if (!fm->SetActiveBrowsingContextInChrome(nullptr, aActionId)) {
   7288    LOGFOCUS(
   7289        ("Ignoring out-of-sequence attempt to unset active browsing context in "
   7290         "parent [%p].",
   7291         context));
   7292    (void)SendReviseActiveBrowsingContext(
   7293        aActionId, fm->GetActiveBrowsingContextInChrome(),
   7294        fm->GetActionIdForActiveBrowsingContextInChrome());
   7295    return IPC_OK();
   7296  }
   7297 
   7298  context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
   7299    (void)aParent->SendUnsetActiveBrowsingContext(context, aActionId);
   7300  });
   7301 
   7302  return IPC_OK();
   7303 }
   7304 
   7305 mozilla::ipc::IPCResult ContentParent::RecvSetFocusedElement(
   7306    const MaybeDiscarded<BrowsingContext>& aContext, bool aNeedsFocus) {
   7307  if (aContext.IsNullOrDiscarded()) {
   7308    MOZ_LOG(
   7309        BrowsingContext::GetLog(), LogLevel::Debug,
   7310        ("ParentIPC: Trying to send a message to dead or detached context"));
   7311    return IPC_OK();
   7312  }
   7313  LOGFOCUS(("ContentParent::RecvSetFocusedElement"));
   7314  CanonicalBrowsingContext* context = aContext.get_canonical();
   7315 
   7316  if (ContentParent* cp = context->GetContentParent()) {
   7317    (void)cp->SendSetFocusedElement(context, aNeedsFocus);
   7318  }
   7319  return IPC_OK();
   7320 }
   7321 
   7322 mozilla::ipc::IPCResult ContentParent::RecvFinalizeFocusOuter(
   7323    const MaybeDiscarded<BrowsingContext>& aContext, bool aCanFocus,
   7324    CallerType aCallerType) {
   7325  if (aContext.IsNullOrDiscarded()) {
   7326    MOZ_LOG(
   7327        BrowsingContext::GetLog(), LogLevel::Debug,
   7328        ("ParentIPC: Trying to send a message to dead or detached context"));
   7329    return IPC_OK();
   7330  }
   7331  LOGFOCUS(("ContentParent::RecvFinalizeFocusOuter"));
   7332  CanonicalBrowsingContext* context = aContext.get_canonical();
   7333  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
   7334  if (cpm) {
   7335    ContentParent* cp = cpm->GetContentProcessById(
   7336        ContentParentId(context->EmbedderProcessId()));
   7337    if (cp) {
   7338      (void)cp->SendFinalizeFocusOuter(context, aCanFocus, aCallerType);
   7339    }
   7340  }
   7341  return IPC_OK();
   7342 }
   7343 
   7344 mozilla::ipc::IPCResult ContentParent::RecvInsertNewFocusActionId(
   7345    uint64_t aActionId) {
   7346  LOGFOCUS(("ContentParent::RecvInsertNewFocusActionId actionid: %" PRIu64,
   7347            aActionId));
   7348  nsFocusManager* fm = nsFocusManager::GetFocusManager();
   7349  if (fm) {
   7350    fm->InsertNewFocusActionId(aActionId);
   7351  }
   7352  return IPC_OK();
   7353 }
   7354 
   7355 mozilla::ipc::IPCResult ContentParent::RecvBlurToParent(
   7356    const MaybeDiscarded<BrowsingContext>& aFocusedBrowsingContext,
   7357    const MaybeDiscarded<BrowsingContext>& aBrowsingContextToClear,
   7358    const MaybeDiscarded<BrowsingContext>& aAncestorBrowsingContextToFocus,
   7359    bool aIsLeavingDocument, bool aAdjustWidget,
   7360    bool aBrowsingContextToClearHandled,
   7361    bool aAncestorBrowsingContextToFocusHandled, uint64_t aActionId) {
   7362  if (aFocusedBrowsingContext.IsNullOrDiscarded()) {
   7363    MOZ_LOG(
   7364        BrowsingContext::GetLog(), LogLevel::Debug,
   7365        ("ParentIPC: Trying to send a message to dead or detached context"));
   7366    return IPC_OK();
   7367  }
   7368 
   7369  LOGFOCUS(
   7370      ("ContentParent::RecvBlurToParent isLeavingDocument %d adjustWidget %d "
   7371       "browsingContextToClearHandled %d ancestorBrowsingContextToFocusHandled "
   7372       "%d actionid: %" PRIu64,
   7373       aIsLeavingDocument, aAdjustWidget, aBrowsingContextToClearHandled,
   7374       aAncestorBrowsingContextToFocusHandled, aActionId));
   7375 
   7376  CanonicalBrowsingContext* focusedBrowsingContext =
   7377      aFocusedBrowsingContext.get_canonical();
   7378 
   7379  // If aBrowsingContextToClear and aAncestorBrowsingContextToFocusHandled
   7380  // didn't get handled in the process that sent this IPC message and they
   7381  // aren't in the same process as aFocusedBrowsingContext, we need to split
   7382  // off their handling here and use SendSetFocusedElement to send them
   7383  // elsewhere than the blurring itself.
   7384 
   7385  bool ancestorDifferent =
   7386      (!aAncestorBrowsingContextToFocusHandled &&
   7387       !aAncestorBrowsingContextToFocus.IsNullOrDiscarded() &&
   7388       (focusedBrowsingContext->OwnerProcessId() !=
   7389        aAncestorBrowsingContextToFocus.get_canonical()->OwnerProcessId()));
   7390  if (!aBrowsingContextToClearHandled &&
   7391      !aBrowsingContextToClear.IsNullOrDiscarded() &&
   7392      (focusedBrowsingContext->OwnerProcessId() !=
   7393       aBrowsingContextToClear.get_canonical()->OwnerProcessId())) {
   7394    MOZ_RELEASE_ASSERT(!ancestorDifferent,
   7395                       "This combination is not supposed to happen.");
   7396    if (ContentParent* cp =
   7397            aBrowsingContextToClear.get_canonical()->GetContentParent()) {
   7398      (void)cp->SendSetFocusedElement(aBrowsingContextToClear, false);
   7399    }
   7400  } else if (ancestorDifferent) {
   7401    if (ContentParent* cp = aAncestorBrowsingContextToFocus.get_canonical()
   7402                                ->GetContentParent()) {
   7403      (void)cp->SendSetFocusedElement(aAncestorBrowsingContextToFocus, true);
   7404    }
   7405  }
   7406 
   7407  if (ContentParent* cp = focusedBrowsingContext->GetContentParent()) {
   7408    (void)cp->SendBlurToChild(aFocusedBrowsingContext, aBrowsingContextToClear,
   7409                              aAncestorBrowsingContextToFocus,
   7410                              aIsLeavingDocument, aAdjustWidget, aActionId);
   7411  }
   7412 
   7413  return IPC_OK();
   7414 }
   7415 
   7416 mozilla::ipc::IPCResult ContentParent::RecvMaybeExitFullscreen(
   7417    const MaybeDiscarded<BrowsingContext>& aContext) {
   7418  if (aContext.IsNullOrDiscarded()) {
   7419    MOZ_LOG(
   7420        BrowsingContext::GetLog(), LogLevel::Debug,
   7421        ("ParentIPC: Trying to send a message to dead or detached context"));
   7422    return IPC_OK();
   7423  }
   7424  CanonicalBrowsingContext* context = aContext.get_canonical();
   7425 
   7426  if (ContentParent* cp = context->GetContentParent()) {
   7427    (void)cp->SendMaybeExitFullscreen(context);
   7428  }
   7429 
   7430  return IPC_OK();
   7431 }
   7432 
   7433 mozilla::ipc::IPCResult ContentParent::RecvWindowPostMessage(
   7434    const MaybeDiscarded<BrowsingContext>& aContext,
   7435    const ClonedOrErrorMessageData& aMessage, const PostMessageData& aData) {
   7436  if (aContext.IsNullOrDiscarded()) {
   7437    MOZ_LOG(
   7438        BrowsingContext::GetLog(), LogLevel::Debug,
   7439        ("ParentIPC: Trying to send a message to dead or detached context"));
   7440    return IPC_OK();
   7441  }
   7442  CanonicalBrowsingContext* context = aContext.get_canonical();
   7443 
   7444  if (aData.source().IsDiscarded()) {
   7445    MOZ_LOG(
   7446        BrowsingContext::GetLog(), LogLevel::Debug,
   7447        ("ParentIPC: Trying to send a message from dead or detached context"));
   7448    return IPC_OK();
   7449  }
   7450 
   7451  RefPtr<ContentParent> cp = context->GetContentParent();
   7452  if (!cp) {
   7453    MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
   7454            ("ParentIPC: Trying to send PostMessage to dead content process"));
   7455    return IPC_OK();
   7456  }
   7457 
   7458  ClonedOrErrorMessageData message;
   7459  StructuredCloneData messageFromChild;
   7460  if (aMessage.type() == ClonedOrErrorMessageData::TClonedMessageData) {
   7461    UnpackClonedMessageData(aMessage, messageFromChild);
   7462 
   7463    ClonedMessageData clonedMessageData;
   7464    if (BuildClonedMessageData(messageFromChild, clonedMessageData)) {
   7465      message = std::move(clonedMessageData);
   7466    } else {
   7467      // FIXME Logging?
   7468      message = ErrorMessageData();
   7469    }
   7470  } else {
   7471    MOZ_ASSERT(aMessage.type() == ClonedOrErrorMessageData::TErrorMessageData);
   7472    message = ErrorMessageData();
   7473  }
   7474 
   7475  (void)cp->SendWindowPostMessage(context, message, aData);
   7476  return IPC_OK();
   7477 }
   7478 
   7479 void ContentParent::AddBrowsingContextGroup(BrowsingContextGroup* aGroup) {
   7480  MOZ_DIAGNOSTIC_ASSERT(aGroup);
   7481  // Ensure that the group has been inserted, and if we're not launching
   7482  // anymore, also begin subscribing. Launching processes will be subscribed if
   7483  // they finish launching in `LaunchSubprocessResolve`.
   7484  if (mGroups.EnsureInserted(aGroup) && !IsLaunching()) {
   7485    aGroup->Subscribe(this);
   7486  }
   7487 }
   7488 
   7489 void ContentParent::RemoveBrowsingContextGroup(BrowsingContextGroup* aGroup) {
   7490  MOZ_DIAGNOSTIC_ASSERT(aGroup);
   7491  // Remove the group from our list. This is called from the
   7492  // BrowsingContextGroup when unsubscribing, so we don't need to do it here.
   7493  if (mGroups.EnsureRemoved(aGroup) && CanSend()) {
   7494    // If we're removing the entry for the first time, tell the content process
   7495    // to clean up the group.
   7496    (void)SendDestroyBrowsingContextGroup(aGroup->Id());
   7497  }
   7498 }
   7499 
   7500 mozilla::ipc::IPCResult ContentParent::RecvCommitBrowsingContextTransaction(
   7501    const MaybeDiscarded<BrowsingContext>& aContext,
   7502    BrowsingContext::BaseTransaction&& aTransaction, uint64_t aEpoch) {
   7503  // Record the new BrowsingContextFieldEpoch associated with this transaction.
   7504  // This should be done unconditionally, so that we're always in-sync.
   7505  //
   7506  // The order the parent process receives transactions is considered the
   7507  // "canonical" ordering, so we don't need to worry about doing any
   7508  // epoch-related validation.
   7509  MOZ_ASSERT(aEpoch == mBrowsingContextFieldEpoch + 1,
   7510             "Child process skipped an epoch?");
   7511  mBrowsingContextFieldEpoch = aEpoch;
   7512 
   7513  return aTransaction.CommitFromIPC(aContext, this);
   7514 }
   7515 
   7516 mozilla::ipc::IPCResult ContentParent::RecvBlobURLDataRequest(
   7517    const nsACString& aBlobURL, nsIPrincipal* aTriggeringPrincipal,
   7518    nsIPrincipal* aLoadingPrincipal, const OriginAttributes& aOriginAttributes,
   7519    uint64_t aInnerWindowId, const nsCString& aPartitionKey,
   7520    BlobURLDataRequestResolver&& aResolver) {
   7521  RefPtr<BlobImpl> blobImpl;
   7522 
   7523  // Since revoked blobs are also retrieved, it is possible that the blob no
   7524  // longer exists (due to the 5 second timeout) when execution reaches here
   7525  if (!BlobURLProtocolHandler::GetDataEntry(
   7526          aBlobURL, getter_AddRefs(blobImpl), aLoadingPrincipal,
   7527          aTriggeringPrincipal, aOriginAttributes, aInnerWindowId,
   7528          aPartitionKey, true /* AlsoIfRevoked */)) {
   7529    aResolver(NS_ERROR_DOM_BAD_URI);
   7530    return IPC_OK();
   7531  }
   7532 
   7533  IPCBlob ipcBlob;
   7534  nsresult rv = IPCBlobUtils::Serialize(blobImpl, ipcBlob);
   7535 
   7536  if (NS_WARN_IF(NS_FAILED(rv))) {
   7537    aResolver(rv);
   7538    return IPC_OK();
   7539  }
   7540 
   7541  aResolver(ipcBlob);
   7542  return IPC_OK();
   7543 }
   7544 
   7545 mozilla::ipc::IPCResult ContentParent::RecvReportServiceWorkerShutdownProgress(
   7546    uint32_t aShutdownStateId, ServiceWorkerShutdownState::Progress aProgress) {
   7547  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   7548  MOZ_RELEASE_ASSERT(swm, "ServiceWorkers should shutdown before SWM.");
   7549 
   7550  swm->ReportServiceWorkerShutdownProgress(aShutdownStateId, aProgress);
   7551 
   7552  return IPC_OK();
   7553 }
   7554 
   7555 mozilla::ipc::IPCResult ContentParent::RecvNotifyOnHistoryReload(
   7556    const MaybeDiscarded<BrowsingContext>& aContext, const bool& aForceReload,
   7557    NotifyOnHistoryReloadResolver&& aResolver) {
   7558  bool canReload = false;
   7559  Maybe<NotNull<RefPtr<nsDocShellLoadState>>> loadState;
   7560  Maybe<bool> reloadActiveEntry;
   7561  if (!aContext.IsNullOrDiscarded()) {
   7562    aContext.get_canonical()->NotifyOnHistoryReload(
   7563        aForceReload, canReload, loadState, reloadActiveEntry);
   7564  }
   7565  aResolver(
   7566      std::tuple<const bool&,
   7567                 const Maybe<NotNull<RefPtr<nsDocShellLoadState>>>&,
   7568                 const Maybe<bool>&>(canReload, loadState, reloadActiveEntry));
   7569  return IPC_OK();
   7570 }
   7571 
   7572 mozilla::ipc::IPCResult ContentParent::RecvHistoryCommit(
   7573    const MaybeDiscarded<BrowsingContext>& aContext, const uint64_t& aLoadID,
   7574    const nsID& aChangeID, const uint32_t& aLoadType,
   7575    const bool& aCloneEntryChildren, const bool& aChannelExpired,
   7576    const uint32_t& aCacheKey) {
   7577  if (!aContext.IsDiscarded()) {
   7578    CanonicalBrowsingContext* canonical = aContext.get_canonical();
   7579    if (!canonical) {
   7580      return IPC_FAIL(
   7581          this, "Could not get canonical. aContext.get_canonical() fails.");
   7582    }
   7583    canonical->SessionHistoryCommit(aLoadID, aChangeID, aLoadType,
   7584                                    aCloneEntryChildren, aChannelExpired,
   7585                                    aCacheKey);
   7586  }
   7587  return IPC_OK();
   7588 }
   7589 
   7590 mozilla::ipc::IPCResult ContentParent::RecvHistoryGo(
   7591    const MaybeDiscarded<BrowsingContext>& aContext, int32_t aOffset,
   7592    uint64_t aHistoryEpoch, bool aRequireUserInteraction, bool aUserActivation,
   7593    bool aCheckForCancelation, HistoryGoResolver&& aResolveRequestedIndex) {
   7594  if (!aContext.IsNullOrDiscarded()) {
   7595    RefPtr<CanonicalBrowsingContext> canonical = aContext.get_canonical();
   7596    aResolveRequestedIndex(canonical->HistoryGo(
   7597        aOffset, aHistoryEpoch, aRequireUserInteraction, aUserActivation,
   7598        aCheckForCancelation, Some(ChildID())));
   7599  }
   7600  return IPC_OK();
   7601 }
   7602 
   7603 mozilla::ipc::IPCResult ContentParent::RecvNavigationTraverse(
   7604    const MaybeDiscarded<BrowsingContext>& aContext, const nsID& aKey,
   7605    uint64_t aHistoryEpoch, bool aUserActivation, bool aCheckForCancelation,
   7606    NavigationTraverseResolver&& aResolver) {
   7607  if (!aContext.IsNullOrDiscarded()) {
   7608    RefPtr<CanonicalBrowsingContext> canonical = aContext.get_canonical();
   7609    canonical->NavigationTraverse(aKey, aHistoryEpoch, aUserActivation,
   7610                                  aCheckForCancelation, Some(ChildID()),
   7611                                  aResolver);
   7612  }
   7613  return IPC_OK();
   7614 }
   7615 
   7616 mozilla::ipc::IPCResult ContentParent::RecvSynchronizeLayoutHistoryState(
   7617    const MaybeDiscarded<BrowsingContext>& aContext,
   7618    nsILayoutHistoryState* aState) {
   7619  if (aContext.IsNull()) {
   7620    return IPC_OK();
   7621  }
   7622 
   7623  BrowsingContext* bc = aContext.GetMaybeDiscarded();
   7624  if (!bc) {
   7625    return IPC_OK();
   7626  }
   7627  SessionHistoryEntry* entry = bc->Canonical()->GetActiveSessionHistoryEntry();
   7628  if (entry) {
   7629    entry->SetLayoutHistoryState(aState);
   7630  }
   7631  return IPC_OK();
   7632 }
   7633 
   7634 mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryTitle(
   7635    const MaybeDiscarded<BrowsingContext>& aContext, const nsAString& aTitle) {
   7636  if (aContext.IsNullOrDiscarded()) {
   7637    return IPC_OK();
   7638  }
   7639 
   7640  SessionHistoryEntry* entry =
   7641      aContext.get_canonical()->GetActiveSessionHistoryEntry();
   7642  if (entry) {
   7643    entry->SetTitle(aTitle);
   7644  }
   7645  return IPC_OK();
   7646 }
   7647 
   7648 mozilla::ipc::IPCResult
   7649 ContentParent::RecvSessionHistoryEntryScrollRestorationIsManual(
   7650    const MaybeDiscarded<BrowsingContext>& aContext, const bool& aIsManual) {
   7651  if (aContext.IsNullOrDiscarded()) {
   7652    return IPC_OK();
   7653  }
   7654 
   7655  SessionHistoryEntry* entry =
   7656      aContext.get_canonical()->GetActiveSessionHistoryEntry();
   7657  if (entry) {
   7658    entry->SetScrollRestorationIsManual(aIsManual);
   7659  }
   7660  return IPC_OK();
   7661 }
   7662 
   7663 mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryScrollPosition(
   7664    const MaybeDiscarded<BrowsingContext>& aContext, const int32_t& aX,
   7665    const int32_t& aY) {
   7666  if (aContext.IsNullOrDiscarded()) {
   7667    return IPC_OK();
   7668  }
   7669 
   7670  SessionHistoryEntry* entry =
   7671      aContext.get_canonical()->GetActiveSessionHistoryEntry();
   7672  if (entry) {
   7673    entry->SetScrollPosition(aX, aY);
   7674  }
   7675  return IPC_OK();
   7676 }
   7677 
   7678 mozilla::ipc::IPCResult
   7679 ContentParent::RecvSessionHistoryEntryStoreWindowNameInContiguousEntries(
   7680    const MaybeDiscarded<BrowsingContext>& aContext, const nsAString& aName) {
   7681  if (aContext.IsNullOrDiscarded()) {
   7682    return IPC_OK();
   7683  }
   7684 
   7685  // Per https://html.spec.whatwg.org/#history-traversal 4.2.1, we need to set
   7686  // the name to all contiguous entries. This has to be called before
   7687  // CanonicalBrowsingContext::SessionHistoryCommit(), so the active entry is
   7688  // still the old entry that we want to set.
   7689 
   7690  SessionHistoryEntry* entry =
   7691      aContext.get_canonical()->GetActiveSessionHistoryEntry();
   7692 
   7693  if (entry) {
   7694    nsSHistory::WalkContiguousEntries(
   7695        entry, [&](nsISHEntry* aEntry) { aEntry->SetName(aName); });
   7696  }
   7697 
   7698  return IPC_OK();
   7699 }
   7700 
   7701 mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryCacheKey(
   7702    const MaybeDiscarded<BrowsingContext>& aContext,
   7703    const uint32_t& aCacheKey) {
   7704  if (aContext.IsNullOrDiscarded()) {
   7705    return IPC_OK();
   7706  }
   7707 
   7708  SessionHistoryEntry* entry =
   7709      aContext.get_canonical()->GetActiveSessionHistoryEntry();
   7710  if (entry) {
   7711    entry->SetCacheKey(aCacheKey);
   7712  }
   7713  return IPC_OK();
   7714 }
   7715 
   7716 mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryWireframe(
   7717    const MaybeDiscarded<BrowsingContext>& aContext,
   7718    const Wireframe& aWireframe) {
   7719  if (aContext.IsNull()) {
   7720    return IPC_OK();
   7721  }
   7722 
   7723  BrowsingContext* bc = aContext.GetMaybeDiscarded();
   7724  if (!bc) {
   7725    return IPC_OK();
   7726  }
   7727 
   7728  SessionHistoryEntry* entry = bc->Canonical()->GetActiveSessionHistoryEntry();
   7729  if (entry) {
   7730    entry->SetWireframe(Some(aWireframe));
   7731  }
   7732  return IPC_OK();
   7733 }
   7734 
   7735 mozilla::ipc::IPCResult
   7736 ContentParent::RecvGetLoadingSessionHistoryInfoFromParent(
   7737    const MaybeDiscarded<BrowsingContext>& aContext,
   7738    GetLoadingSessionHistoryInfoFromParentResolver&& aResolver) {
   7739  if (aContext.IsNullOrDiscarded()) {
   7740    return IPC_OK();
   7741  }
   7742 
   7743  Maybe<LoadingSessionHistoryInfo> info;
   7744  aContext.get_canonical()->GetLoadingSessionHistoryInfoFromParent(info);
   7745  aResolver(info);
   7746 
   7747  return IPC_OK();
   7748 }
   7749 
   7750 mozilla::ipc::IPCResult ContentParent::RecvSynchronizeNavigationAPIState(
   7751    const MaybeDiscarded<BrowsingContext>& aContext,
   7752    const ClonedMessageData& aState) {
   7753  if (aContext.IsNullOrDiscarded()) {
   7754    return IPC_OK();
   7755  }
   7756 
   7757  RefPtr state = MakeRefPtr<nsStructuredCloneContainer>();
   7758  state->CopyFromClonedMessageData(aState);
   7759 
   7760  aContext.get_canonical()->SynchronizeNavigationAPIState(state);
   7761  return IPC_OK();
   7762 }
   7763 
   7764 mozilla::ipc::IPCResult ContentParent::RecvRemoveFromBFCache(
   7765    const MaybeDiscarded<BrowsingContext>& aContext) {
   7766  if (aContext.IsNullOrDiscarded()) {
   7767    return IPC_OK();
   7768  }
   7769 
   7770  nsCOMPtr<nsFrameLoaderOwner> owner =
   7771      do_QueryInterface(aContext.get_canonical()->GetEmbedderElement());
   7772  if (!owner) {
   7773    return IPC_OK();
   7774  }
   7775 
   7776  RefPtr<nsFrameLoader> frameLoader = owner->GetFrameLoader();
   7777  if (!frameLoader || !frameLoader->GetMaybePendingBrowsingContext()) {
   7778    return IPC_OK();
   7779  }
   7780 
   7781  nsCOMPtr<nsISHistory> shistory = frameLoader->GetMaybePendingBrowsingContext()
   7782                                       ->Canonical()
   7783                                       ->GetSessionHistory();
   7784  if (!shistory) {
   7785    return IPC_OK();
   7786  }
   7787 
   7788  uint32_t count = shistory->GetCount();
   7789  for (uint32_t i = 0; i < count; ++i) {
   7790    nsCOMPtr<nsISHEntry> entry;
   7791    shistory->GetEntryAtIndex(i, getter_AddRefs(entry));
   7792    nsCOMPtr<SessionHistoryEntry> she = do_QueryInterface(entry);
   7793    if (she) {
   7794      if (RefPtr<nsFrameLoader> frameLoader = she->GetFrameLoader()) {
   7795        if (frameLoader->GetMaybePendingBrowsingContext() == aContext.get()) {
   7796          she->SetFrameLoader(nullptr);
   7797          frameLoader->Destroy();
   7798          break;
   7799        }
   7800      }
   7801    }
   7802  }
   7803 
   7804  return IPC_OK();
   7805 }
   7806 
   7807 mozilla::ipc::IPCResult ContentParent::RecvSetActiveSessionHistoryEntry(
   7808    const MaybeDiscarded<BrowsingContext>& aContext,
   7809    const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo&& aInfo,
   7810    uint32_t aLoadType, uint32_t aUpdatedCacheKey, const nsID& aChangeID) {
   7811  if (!aContext.IsNullOrDiscarded()) {
   7812    aContext.get_canonical()->SetActiveSessionHistoryEntry(
   7813        aPreviousScrollPos, &aInfo, aLoadType, aUpdatedCacheKey, aChangeID);
   7814  }
   7815  return IPC_OK();
   7816 }
   7817 
   7818 mozilla::ipc::IPCResult ContentParent::RecvReplaceActiveSessionHistoryEntry(
   7819    const MaybeDiscarded<BrowsingContext>& aContext,
   7820    SessionHistoryInfo&& aInfo) {
   7821  if (!aContext.IsNullOrDiscarded()) {
   7822    aContext.get_canonical()->ReplaceActiveSessionHistoryEntry(&aInfo);
   7823  }
   7824  return IPC_OK();
   7825 }
   7826 
   7827 mozilla::ipc::IPCResult
   7828 ContentParent::RecvRemoveDynEntriesFromActiveSessionHistoryEntry(
   7829    const MaybeDiscarded<BrowsingContext>& aContext) {
   7830  if (!aContext.IsNullOrDiscarded()) {
   7831    aContext.get_canonical()->RemoveDynEntriesFromActiveSessionHistoryEntry();
   7832  }
   7833  return IPC_OK();
   7834 }
   7835 
   7836 mozilla::ipc::IPCResult ContentParent::RecvRemoveFromSessionHistory(
   7837    const MaybeDiscarded<BrowsingContext>& aContext, const nsID& aChangeID) {
   7838  if (!aContext.IsNullOrDiscarded()) {
   7839    aContext.get_canonical()->RemoveFromSessionHistory(aChangeID);
   7840  }
   7841  return IPC_OK();
   7842 }
   7843 
   7844 mozilla::ipc::IPCResult ContentParent::RecvHistoryReload(
   7845    const MaybeDiscarded<BrowsingContext>& aContext,
   7846    const uint32_t aReloadFlags) {
   7847  if (!aContext.IsNullOrDiscarded()) {
   7848    nsCOMPtr<nsISHistory> shistory =
   7849        aContext.get_canonical()->GetSessionHistory();
   7850    if (shistory) {
   7851      shistory->Reload(aReloadFlags);
   7852    }
   7853  }
   7854  return IPC_OK();
   7855 }
   7856 
   7857 mozilla::ipc::IPCResult ContentParent::RecvConsumeHistoryActivation(
   7858    const MaybeDiscarded<BrowsingContext>& aTop) {
   7859  if (aTop.IsNullOrDiscarded()) {
   7860    return IPC_OK();
   7861  }
   7862  aTop->Group()->EachOtherParent(this, [aTop](ContentParent* aParent) {
   7863    (void)aParent->SendConsumeHistoryActivation(aTop);
   7864  });
   7865  return IPC_OK();
   7866 }
   7867 
   7868 mozilla::ipc::IPCResult ContentParent::RecvCommitWindowContextTransaction(
   7869    const MaybeDiscarded<WindowContext>& aContext,
   7870    WindowContext::BaseTransaction&& aTransaction, uint64_t aEpoch) {
   7871  // Record the new BrowsingContextFieldEpoch associated with this transaction.
   7872  // This should be done unconditionally, so that we're always in-sync.
   7873  //
   7874  // The order the parent process receives transactions is considered the
   7875  // "canonical" ordering, so we don't need to worry about doing any
   7876  // epoch-related validation.
   7877  MOZ_ASSERT(aEpoch == mBrowsingContextFieldEpoch + 1,
   7878             "Child process skipped an epoch?");
   7879  mBrowsingContextFieldEpoch = aEpoch;
   7880 
   7881  return aTransaction.CommitFromIPC(aContext, this);
   7882 }
   7883 
   7884 NS_IMETHODIMP ContentParent::GetChildID(uint64_t* aOut) {
   7885  *aOut = this->ChildID();
   7886  return NS_OK;
   7887 }
   7888 
   7889 NS_IMETHODIMP ContentParent::GetOsPid(int32_t* aOut) {
   7890  *aOut = Pid();
   7891  return NS_OK;
   7892 }
   7893 
   7894 NS_IMETHODIMP ContentParent::GetRemoteType(nsACString& aRemoteType) {
   7895  aRemoteType = GetRemoteType();
   7896  return NS_OK;
   7897 }
   7898 
   7899 void ContentParent::StartRemoteWorkerService() {
   7900  MOZ_ASSERT(!mRemoteWorkerServiceActor);
   7901  MOZ_ASSERT(mRemoteType != PREALLOC_REMOTE_TYPE);
   7902 
   7903  Endpoint<PRemoteWorkerServiceChild> childEp;
   7904  mRemoteWorkerServiceActor =
   7905      RemoteWorkerServiceParent::CreateForProcess(this, &childEp);
   7906 
   7907  Endpoint<PRemoteWorkerDebuggerManagerChild> remoteDebuggerChildEp;
   7908  mRemoteWorkerDebuggerManagerActor =
   7909      RemoteWorkerDebuggerManagerParent::CreateForProcess(
   7910          &remoteDebuggerChildEp);
   7911  if (mRemoteWorkerServiceActor) {
   7912    (void)SendInitRemoteWorkerService(std::move(childEp),
   7913                                      std::move(remoteDebuggerChildEp));
   7914  }
   7915 }
   7916 
   7917 IPCResult ContentParent::RecvRawMessage(
   7918    const JSActorMessageMeta& aMeta, JSIPCValue&& aData,
   7919    const UniquePtr<ClonedMessageData>& aStack) {
   7920  UniquePtr<StructuredCloneData> stack;
   7921  if (aStack) {
   7922    stack = MakeUnique<StructuredCloneData>();
   7923    stack->BorrowFromClonedMessageData(*aStack);
   7924  }
   7925  ReceiveRawMessage(aMeta, std::move(aData), std::move(stack));
   7926  return IPC_OK();
   7927 }
   7928 
   7929 NS_IMETHODIMP ContentParent::GetActor(const nsACString& aName, JSContext* aCx,
   7930                                      JSProcessActorParent** retval) {
   7931  ErrorResult error;
   7932  RefPtr<JSProcessActorParent> actor =
   7933      JSActorManager::GetActor(aCx, aName, error)
   7934          .downcast<JSProcessActorParent>();
   7935  if (error.MaybeSetPendingException(aCx)) {
   7936    return NS_ERROR_FAILURE;
   7937  }
   7938  actor.forget(retval);
   7939  return NS_OK;
   7940 }
   7941 
   7942 NS_IMETHODIMP ContentParent::GetExistingActor(const nsACString& aName,
   7943                                              JSProcessActorParent** retval) {
   7944  RefPtr<JSProcessActorParent> actor =
   7945      JSActorManager::GetExistingActor(aName).downcast<JSProcessActorParent>();
   7946  actor.forget(retval);
   7947  return NS_OK;
   7948 }
   7949 
   7950 already_AddRefed<JSActor> ContentParent::InitJSActor(
   7951    JS::Handle<JSObject*> aMaybeActor, const nsACString& aName,
   7952    ErrorResult& aRv) {
   7953  RefPtr<JSProcessActorParent> actor;
   7954  if (aMaybeActor.get()) {
   7955    aRv = UNWRAP_OBJECT(JSProcessActorParent, aMaybeActor.get(), actor);
   7956    if (aRv.Failed()) {
   7957      return nullptr;
   7958    }
   7959  } else {
   7960    actor = new JSProcessActorParent();
   7961  }
   7962 
   7963  MOZ_RELEASE_ASSERT(!actor->Manager(),
   7964                     "mManager was already initialized once!");
   7965  actor->Init(aName, this);
   7966  return actor.forget();
   7967 }
   7968 
   7969 IPCResult ContentParent::RecvFOGData(ByteBuf&& buf) {
   7970  glean::FOGData(std::move(buf));
   7971  return IPC_OK();
   7972 }
   7973 
   7974 mozilla::ipc::IPCResult ContentParent::RecvGeckoTraceExport(ByteBuf&& aBuf) {
   7975  recv_gecko_trace_export(aBuf.mData, aBuf.mLen);
   7976  return IPC_OK();
   7977 }
   7978 
   7979 mozilla::ipc::IPCResult ContentParent::RecvSetContainerFeaturePolicy(
   7980    const MaybeDiscardedBrowsingContext& aContainerContext,
   7981    MaybeFeaturePolicyInfo&& aContainerFeaturePolicyInfo) {
   7982  if (aContainerContext.IsNullOrDiscarded()) {
   7983    return IPC_OK();
   7984  }
   7985 
   7986  auto* context = aContainerContext.get_canonical();
   7987  context->SetContainerFeaturePolicy(std::move(aContainerFeaturePolicyInfo));
   7988 
   7989  return IPC_OK();
   7990 }
   7991 
   7992 mozilla::ipc::IPCResult ContentParent::RecvUpdateAncestorOriginsList(
   7993    const MaybeDiscardedBrowsingContext& aContext) {
   7994  if (!aContext.IsNullOrDiscarded()) {
   7995    auto* canonical = aContext.get_canonical();
   7996    if (WindowGlobalParent* windowGlobal =
   7997            canonical->GetCurrentWindowGlobal()) {
   7998      canonical->CreateRedactedAncestorOriginsList(
   7999          windowGlobal->DocumentPrincipal(),
   8000          canonical->GetEmbedderFrameReferrerPolicy());
   8001    }
   8002  }
   8003 
   8004  return IPC_OK();
   8005 }
   8006 
   8007 mozilla::ipc::IPCResult ContentParent::RecvSetReferrerPolicyForEmbedderFrame(
   8008    const MaybeDiscardedBrowsingContext& aContext,
   8009    const ReferrerPolicy& aPolicy) {
   8010  if (!aContext.IsNullOrDiscarded()) {
   8011    auto* canonical = aContext.get_canonical();
   8012    canonical->SetEmbedderFrameReferrerPolicy(aPolicy);
   8013  }
   8014 
   8015  return IPC_OK();
   8016 }
   8017 
   8018 NS_IMETHODIMP ContentParent::GetCanSend(bool* aCanSend) {
   8019  *aCanSend = CanSend();
   8020  return NS_OK;
   8021 }
   8022 
   8023 ContentParent* ContentParent::AsContentParent() { return this; }
   8024 
   8025 JSActorManager* ContentParent::AsJSActorManager() { return this; }
   8026 
   8027 IPCResult ContentParent::RecvGetSystemIcon(nsIURI* aURI,
   8028                                           GetSystemIconResolver&& aResolver) {
   8029  using ResolverArgs = std::tuple<const nsresult&, mozilla::Maybe<ByteBuf>&&>;
   8030 
   8031  if (!aURI) {
   8032    Maybe<ByteBuf> bytebuf = Nothing();
   8033    aResolver(ResolverArgs(NS_ERROR_NULL_POINTER, std::move(bytebuf)));
   8034    return IPC_OK();
   8035  }
   8036 
   8037 #if defined(MOZ_WIDGET_GTK)
   8038  Maybe<ByteBuf> bytebuf = Some(ByteBuf{});
   8039  nsresult rv = nsIconChannel::GetIcon(aURI, bytebuf.ptr());
   8040  if (NS_WARN_IF(NS_FAILED(rv))) {
   8041    bytebuf = Nothing();
   8042  }
   8043  aResolver(ResolverArgs(rv, std::move(bytebuf)));
   8044  return IPC_OK();
   8045 #elif defined(XP_WIN)
   8046  nsIconChannel::GetIconAsync(aURI)->Then(
   8047      GetCurrentSerialEventTarget(), __func__,
   8048      [aResolver](ByteBuf&& aByteBuf) {
   8049        Maybe<ByteBuf> bytebuf = Some(std::move(aByteBuf));
   8050        aResolver(ResolverArgs(NS_OK, std::move(bytebuf)));
   8051      },
   8052      [aResolver](nsresult aErr) {
   8053        Maybe<ByteBuf> bytebuf = Nothing();
   8054        aResolver(ResolverArgs(aErr, std::move(bytebuf)));
   8055      });
   8056  return IPC_OK();
   8057 #else
   8058  MOZ_CRASH(
   8059      "This message is currently implemented only on GTK and Windows "
   8060      "platforms");
   8061 #endif
   8062 }
   8063 
   8064 IPCResult ContentParent::RecvGetSystemGeolocationPermissionBehavior(
   8065    GetSystemGeolocationPermissionBehaviorResolver&& aResolver) {
   8066  aResolver(Geolocation::GetLocationOSPermission());
   8067  return IPC_OK();
   8068 }
   8069 
   8070 IPCResult ContentParent::RecvRequestGeolocationPermissionFromUser(
   8071    const MaybeDiscardedBrowsingContext& aBrowsingContext,
   8072    RequestGeolocationPermissionFromUserResolver&& aResolver) {
   8073  if (MOZ_UNLIKELY(aBrowsingContext.IsNullOrDiscarded())) {
   8074    aResolver(GeolocationPermissionStatus::Error);
   8075    return IPC_OK();
   8076  }
   8077  RefPtr<BrowsingContext> browsingContext = aBrowsingContext.get();
   8078 
   8079  Geolocation::ReallowWithSystemPermissionOrCancel(browsingContext,
   8080                                                   std::move(aResolver));
   8081  return IPC_OK();
   8082 }
   8083 
   8084 #ifdef FUZZING_SNAPSHOT
   8085 IPCResult ContentParent::RecvSignalFuzzingReady() {
   8086  // No action needed here, we already observe this message directly
   8087  // on the channel and act accordingly.
   8088  return IPC_OK();
   8089 }
   8090 #endif
   8091 
   8092 #ifdef FUZZING
   8093 IPCResult ContentParent::RecvKillGPUProcess() {
   8094  gfx::GPUProcessManager* gpm = gfx::GPUProcessManager::Get();
   8095  if (gpm) {
   8096    gpm->KillProcess();
   8097  }
   8098  return IPC_OK();
   8099 }
   8100 #endif
   8101 
   8102 nsCString ThreadsafeContentParentHandle::GetRemoteType() {
   8103  RecursiveMutexAutoLock lock(mMutex);
   8104  return mRemoteType;
   8105 }
   8106 
   8107 UniqueThreadsafeContentParentKeepAlive
   8108 ThreadsafeContentParentHandle::TryAddKeepAlive(uint64_t aBrowserId) {
   8109  RecursiveMutexAutoLock lock(mMutex);
   8110  // If shutdown has already started, we can't keep this ContentParent alive
   8111  // anymore.
   8112  if (mShutdownStarted) {
   8113    return nullptr;
   8114  }
   8115 
   8116  // Otherwise, ensure there is an entry for this BrowserId, and increment it.
   8117  ++mKeepAlivesPerBrowserId.LookupOrInsert(aBrowserId, 0);
   8118  return UniqueThreadsafeContentParentKeepAlive{do_AddRef(this).take(),
   8119                                                {.mBrowserId = aBrowserId}};
   8120 }
   8121 
   8122 void ContentParent::SetAndroidAppLinkLaunchType(uint64_t aLoadIdentifier,
   8123                                                int32_t aAppLinkLaunchType) {
   8124  mAndroidLoadIdentifierToAppLinkLaunchType.InsertOrUpdate(aLoadIdentifier,
   8125                                                           aAppLinkLaunchType);
   8126 }
   8127 
   8128 int32_t ContentParent::GetAndroidAppLinkLaunchType(uint64_t aLoadIdentifier) {
   8129  int32_t appLinkLaunchType = -1;
   8130  (void)mAndroidLoadIdentifierToAppLinkLaunchType.Get(aLoadIdentifier,
   8131                                                      &appLinkLaunchType);
   8132  return appLinkLaunchType;
   8133 }
   8134 
   8135 void ContentParent::ClearAndroidAppLinkLaunchType(uint64_t aLoadIdentifier) {
   8136  mAndroidLoadIdentifierToAppLinkLaunchType.Remove(aLoadIdentifier);
   8137 }
   8138 
   8139 }  // namespace dom
   8140 }  // namespace mozilla
   8141 
   8142 NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
   8143 
   8144 NS_IMETHODIMP
   8145 ParentIdleListener::Observe(nsISupports*, const char* aTopic,
   8146                            const char16_t* aData) {
   8147  (void)mParent->SendNotifyIdleObserver(mObserver, nsDependentCString(aTopic),
   8148                                        nsDependentString(aData));
   8149  return NS_OK;
   8150 }
   8151 
   8152 #undef LOGPDM