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