Backed out changeset a5ff95602119 (bug 1905021) as requested for causing accessibilit...
[gecko.git] / dom / ipc / ContentParent.cpp
blobd2712650d3181b5bf0e387def5b2bf6d1d5c102b
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/. */
7 #include "mozilla/AppShutdown.h"
8 #include "mozilla/DebugOnly.h"
10 #include "base/basictypes.h"
11 #include "base/shared_memory.h"
13 #include "ContentParent.h"
14 #include "mozilla/ipc/ProcessUtils.h"
15 #include "mozilla/CmdLineAndEnvUtils.h"
16 #include "BrowserParent.h"
18 #include "chrome/common/process_watcher.h"
19 #include "mozilla/Result.h"
20 #include "mozilla/Services.h"
21 #include "mozilla/XREAppData.h"
22 #include "nsComponentManagerUtils.h"
23 #include "nsIBrowserDOMWindow.h"
24 #include "nsIPrivateAttributionService.h"
26 #include "GMPServiceParent.h"
27 #include "HandlerServiceParent.h"
28 #include "IHistory.h"
29 #include <map>
30 #include <utility>
32 #include "ContentProcessManager.h"
33 #include "GeckoProfiler.h"
34 #include "Geolocation.h"
35 #include "GfxInfoBase.h"
36 #include "MMPrinter.h"
37 #include "PreallocatedProcessManager.h"
38 #include "ProcessPriorityManager.h"
39 #include "ProfilerParent.h"
40 #include "SandboxHal.h"
41 #include "SourceSurfaceRawData.h"
42 #include "mozilla/ipc/URIUtils.h"
43 #include "gfxPlatform.h"
44 #include "gfxPlatformFontList.h"
45 #include "nsDNSService2.h"
46 #include "nsPIDNSService.h"
47 #include "mozilla/AntiTrackingUtils.h"
48 #include "mozilla/AppShutdown.h"
49 #include "mozilla/AutoRestore.h"
50 #include "mozilla/BasePrincipal.h"
51 #include "mozilla/BenchmarkStorageParent.h"
52 #include "mozilla/Casting.h"
53 #include "mozilla/ClearOnShutdown.h"
54 #include "mozilla/ClipboardReadRequestParent.h"
55 #include "mozilla/ClipboardWriteRequestParent.h"
56 #include "mozilla/ContentBlockingUserInteraction.h"
57 #include "mozilla/FOGIPC.h"
58 #include "mozilla/GlobalStyleSheetCache.h"
59 #include "mozilla/GeckoArgs.h"
60 #include "mozilla/HangDetails.h"
61 #include "mozilla/LookAndFeel.h"
62 #include "mozilla/Maybe.h"
63 #include "mozilla/NullPrincipal.h"
64 #include "mozilla/Preferences.h"
65 #include "mozilla/PresShell.h"
66 #include "mozilla/ProcessHangMonitor.h"
67 #include "mozilla/ProcessHangMonitorIPC.h"
68 #include "mozilla/ProfilerLabels.h"
69 #include "mozilla/ProfilerMarkers.h"
70 #include "mozilla/RecursiveMutex.h"
71 #include "mozilla/ScopeExit.h"
72 #include "mozilla/ScriptPreloader.h"
73 #include "mozilla/Components.h"
74 #include "mozilla/Sprintf.h"
75 #include "mozilla/StaticPrefs_dom.h"
76 #include "mozilla/StaticPrefs_fission.h"
77 #include "mozilla/StaticPrefs_media.h"
78 #include "mozilla/StaticPrefs_network.h"
79 #include "mozilla/StaticPrefs_threads.h"
80 #include "mozilla/StaticPrefs_widget.h"
81 #include "mozilla/StorageAccessAPIHelper.h"
82 #include "mozilla/StyleSheet.h"
83 #include "mozilla/StyleSheetInlines.h"
84 #include "mozilla/TaskController.h"
85 #include "mozilla/Telemetry.h"
86 #include "mozilla/TelemetryIPC.h"
87 #include "mozilla/ThreadSafety.h"
88 #include "mozilla/Unused.h"
89 #include "mozilla/WebBrowserPersistDocumentParent.h"
90 #include "mozilla/devtools/HeapSnapshotTempFileHelperParent.h"
91 #include "mozilla/dom/BlobURLProtocolHandler.h"
92 #include "mozilla/dom/BrowserHost.h"
93 #include "mozilla/dom/BrowsingContext.h"
94 #include "mozilla/dom/BrowsingContextGroup.h"
95 #include "mozilla/dom/CancelContentJSOptionsBinding.h"
96 #include "mozilla/dom/CanonicalBrowsingContext.h"
97 #include "mozilla/dom/ClientManager.h"
98 #include "mozilla/dom/ContentChild.h"
99 #include "mozilla/dom/DataTransfer.h"
100 #include "mozilla/dom/Document.h"
101 #include "mozilla/dom/Element.h"
102 #include "mozilla/dom/ExternalHelperAppParent.h"
103 #include "mozilla/dom/File.h"
104 #include "mozilla/dom/FileSystemSecurity.h"
105 #include "mozilla/dom/GeolocationBinding.h"
106 #include "mozilla/dom/GeolocationPositionError.h"
107 #include "mozilla/dom/GetFilesHelper.h"
108 #include "mozilla/dom/IPCBlobUtils.h"
109 #include "mozilla/dom/JSActorService.h"
110 #include "mozilla/dom/JSProcessActorBinding.h"
111 #include "mozilla/dom/LocalStorageCommon.h"
112 #include "mozilla/dom/MediaController.h"
113 #include "mozilla/dom/MemoryReportRequest.h"
114 #include "mozilla/dom/MediaStatusManager.h"
115 #include "mozilla/dom/Notification.h"
116 #include "mozilla/dom/PContentPermissionRequestParent.h"
117 #include "mozilla/dom/PCycleCollectWithLogsParent.h"
118 #include "mozilla/dom/ParentProcessMessageManager.h"
119 #include "mozilla/dom/Permissions.h"
120 #include "mozilla/dom/ProcessMessageManager.h"
121 #include "mozilla/dom/PushNotifier.h"
122 #include "mozilla/dom/RemoteWorkerServiceParent.h"
123 #include "mozilla/dom/ServiceWorkerManager.h"
124 #include "mozilla/dom/ServiceWorkerRegistrar.h"
125 #include "mozilla/dom/ServiceWorkerUtils.h"
126 #include "mozilla/dom/SessionHistoryEntry.h"
127 #include "mozilla/dom/SessionStorageManager.h"
128 #include "mozilla/dom/StorageIPC.h"
129 #include "mozilla/dom/UserActivation.h"
130 #include "mozilla/dom/URLClassifierParent.h"
131 #include "mozilla/dom/WindowGlobalParent.h"
132 #include "mozilla/dom/ipc/SharedMap.h"
133 #include "mozilla/dom/ipc/StructuredCloneData.h"
134 #include "mozilla/dom/nsMixedContentBlocker.h"
135 #include "mozilla/dom/power/PowerManagerService.h"
136 #include "mozilla/dom/quota/QuotaManagerService.h"
137 #include "mozilla/extensions/ExtensionsParent.h"
138 #include "mozilla/extensions/StreamFilterParent.h"
139 #include "mozilla/gfx/GPUProcessManager.h"
140 #include "mozilla/gfx/gfxVars.h"
141 #include "mozilla/glean/GleanPings.h"
142 #include "mozilla/hal_sandbox/PHalParent.h"
143 #include "mozilla/intl/L10nRegistry.h"
144 #include "mozilla/intl/LocaleService.h"
145 #include "mozilla/ipc/BackgroundChild.h"
146 #include "mozilla/ipc/BackgroundParent.h"
147 #include "mozilla/ipc/ByteBuf.h"
148 #include "mozilla/ipc/CrashReporterHost.h"
149 #include "mozilla/ipc/Endpoint.h"
150 #include "mozilla/ipc/FileDescriptorUtils.h"
151 #include "mozilla/ipc/IPCStreamUtils.h"
152 #include "mozilla/ipc/TestShellParent.h"
153 #include "mozilla/layers/CompositorThread.h"
154 #include "mozilla/layers/ImageBridgeParent.h"
155 #include "mozilla/layers/LayerTreeOwnerTracker.h"
156 #include "mozilla/layers/PAPZParent.h"
157 #include "mozilla/loader/ScriptCacheActors.h"
158 #include "mozilla/media/MediaParent.h"
159 #include "mozilla/mozSpellChecker.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/CookieKey.h"
165 #include "mozilla/net/TRRService.h"
166 #include "mozilla/TelemetryComms.h"
167 #include "mozilla/TelemetryEventEnums.h"
168 #include "mozilla/RemoteLazyInputStreamParent.h"
169 #include "mozilla/widget/RemoteLookAndFeel.h"
170 #include "mozilla/widget/ScreenManager.h"
171 #include "mozilla/widget/TextRecognition.h"
172 #include "nsAnonymousTemporaryFile.h"
173 #include "nsAppRunner.h"
174 #include "nsCExternalHandlerService.h"
175 #include "nsCOMPtr.h"
176 #include "nsChromeRegistryChrome.h"
177 #include "nsConsoleMessage.h"
178 #include "nsConsoleService.h"
179 #include "nsContentPermissionHelper.h"
180 #include "nsContentUtils.h"
181 #include "nsCRT.h"
182 #include "nsDebugImpl.h"
183 #include "nsDirectoryServiceDefs.h"
184 #include "nsDocShell.h"
185 #include "nsEmbedCID.h"
186 #include "nsFocusManager.h"
187 #include "nsFrameLoader.h"
188 #include "nsFrameMessageManager.h"
189 #include "nsGlobalWindowOuter.h"
190 #include "nsHashPropertyBag.h"
191 #include "nsHyphenationManager.h"
192 #include "nsIAlertsService.h"
193 #include "nsIAppShell.h"
194 #include "nsIAppWindow.h"
195 #include "nsIAsyncInputStream.h"
196 #include "nsIBidiKeyboard.h"
197 #include "nsICaptivePortalService.h"
198 #include "nsICertOverrideService.h"
199 #include "nsIClipboard.h"
200 #include "nsIContentAnalysis.h"
201 #include "nsIContentSecurityPolicy.h"
202 #include "nsICookie.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 "nsIUserIdleService.h"
211 #include "nsIInterfaceRequestorUtils.h"
212 #include "nsILocalStorageManager.h"
213 #include "nsIMemoryInfoDumper.h"
214 #include "nsIMemoryReporter.h"
215 #include "nsINetworkLinkService.h"
216 #include "nsIObserverService.h"
217 #include "nsIParentChannel.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 "nsIWebBrowserChrome.h"
226 #include "nsIX509Cert.h"
227 #include "nsIXULRuntime.h"
228 #include "nsICookieNotification.h"
229 #if defined(MOZ_WIDGET_GTK) || defined(XP_WIN)
230 # include "nsIconChannel.h"
231 #endif
232 #include "nsMemoryInfoDumper.h"
233 #include "nsMemoryReporterManager.h"
234 #include "nsOpenURIInFrameParams.h"
235 #include "nsPIWindowWatcher.h"
236 #include "nsQueryObject.h"
237 #include "nsReadableUtils.h"
238 #include "nsSHistory.h"
239 #include "nsScriptError.h"
240 #include "nsServiceManagerUtils.h"
241 #include "nsStreamUtils.h"
242 #include "nsStyleSheetService.h"
243 #include "nsThread.h"
244 #include "nsThreadUtils.h"
245 #include "nsWidgetsCID.h"
246 #include "nsWindowWatcher.h"
247 #include "prenv.h"
248 #include "prio.h"
249 #include "private/pprio.h"
250 #include "xpcpublic.h"
251 #include "nsOpenWindowInfo.h"
252 #include "nsFrameLoaderOwner.h"
254 #ifdef MOZ_WEBRTC
255 # include "jsapi/WebrtcGlobalParent.h"
256 #endif
258 #if defined(XP_MACOSX)
259 # include "nsMacUtilsImpl.h"
260 # include "mozilla/AvailableMemoryWatcher.h"
261 #endif
263 #if defined(ANDROID) || defined(LINUX)
264 # include "nsSystemInfo.h"
265 #endif
267 #if defined(XP_LINUX)
268 # include "mozilla/Hal.h"
269 #endif
271 #ifdef ANDROID
272 # include "gfxAndroidPlatform.h"
273 #endif
275 #include "mozilla/PermissionManager.h"
277 #ifdef MOZ_WIDGET_ANDROID
278 # include "AndroidBridge.h"
279 # include "mozilla/java/GeckoProcessManagerWrappers.h"
280 # include "mozilla/java/GeckoProcessTypeWrappers.h"
281 #endif
283 #ifdef MOZ_WIDGET_GTK
284 # include <gdk/gdk.h>
285 # include "mozilla/WidgetUtilsGtk.h"
286 #endif
288 #include "mozilla/RemoteSpellCheckEngineParent.h"
290 #include "Crypto.h"
292 #ifdef MOZ_WEBSPEECH
293 # include "mozilla/dom/SpeechSynthesisParent.h"
294 #endif
296 #if defined(MOZ_SANDBOX)
297 # include "mozilla/SandboxSettings.h"
298 # if defined(XP_LINUX)
299 # include "mozilla/SandboxInfo.h"
300 # include "mozilla/SandboxBroker.h"
301 # include "mozilla/SandboxBrokerPolicyFactory.h"
302 # endif
303 # if defined(XP_MACOSX)
304 # include "mozilla/Sandbox.h"
305 # endif
306 #endif
308 #ifdef XP_WIN
309 # include "mozilla/widget/AudioSession.h"
310 # include "mozilla/WinDllServices.h"
311 #endif
313 #ifdef MOZ_CODE_COVERAGE
314 # include "mozilla/CodeCoverageHandler.h"
315 #endif
317 #ifdef FUZZING_SNAPSHOT
318 # include "mozilla/fuzzing/IPCFuzzController.h"
319 #endif
321 #ifdef ENABLE_WEBDRIVER
322 # include "nsIMarionette.h"
323 # include "nsIRemoteAgent.h"
324 #endif
326 // For VP9Benchmark::sBenchmarkFpsPref
327 #include "Benchmark.h"
329 #include "mozilla/RemoteDecodeUtils.h"
330 #include "nsIToolkitProfileService.h"
331 #include "nsIToolkitProfile.h"
333 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
335 using base::KillProcess;
337 using namespace CrashReporter;
338 using namespace mozilla::dom::power;
339 using namespace mozilla::media;
340 using namespace mozilla::embedding;
341 using namespace mozilla::gfx;
342 using namespace mozilla::gmp;
343 using namespace mozilla::hal;
344 using namespace mozilla::ipc;
345 using namespace mozilla::intl;
346 using namespace mozilla::layers;
347 using namespace mozilla::layout;
348 using namespace mozilla::net;
349 using namespace mozilla::psm;
350 using namespace mozilla::widget;
351 using namespace mozilla::Telemetry;
352 using mozilla::loader::PScriptCacheParent;
353 using mozilla::Telemetry::ProcessID;
355 extern mozilla::LazyLogModule gFocusLog;
357 #define LOGFOCUS(args) MOZ_LOG(gFocusLog, mozilla::LogLevel::Debug, args)
359 extern mozilla::LazyLogModule sPDMLog;
360 #define LOGPDM(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
362 namespace mozilla {
363 namespace CubebUtils {
364 extern FileDescriptor CreateAudioIPCConnection();
367 namespace dom {
369 LazyLogModule gProcessLog("Process");
371 static std::map<RemoteDecodeIn, media::MediaCodecsSupported> sCodecsSupported;
373 /* static */
374 uint32_t ContentParent::sMaxContentProcesses = 0;
376 /* static */
377 LogModule* ContentParent::GetLog() { return gProcessLog; }
379 /* static */
380 uint32_t ContentParent::sPageLoadEventCounter = 0;
382 #define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
383 #define NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC "ipc:network:set-connectivity"
385 // IPC receiver for remote GC/CC logging.
386 class CycleCollectWithLogsParent final : public PCycleCollectWithLogsParent {
387 public:
388 MOZ_COUNTED_DTOR(CycleCollectWithLogsParent)
390 static bool AllocAndSendConstructor(ContentParent* aManager,
391 bool aDumpAllTraces,
392 nsICycleCollectorLogSink* aSink,
393 nsIDumpGCAndCCLogsCallback* aCallback) {
394 CycleCollectWithLogsParent* actor;
395 FILE* gcLog;
396 FILE* ccLog;
397 nsresult rv;
399 actor = new CycleCollectWithLogsParent(aSink, aCallback);
400 rv = actor->mSink->Open(&gcLog, &ccLog);
401 if (NS_WARN_IF(NS_FAILED(rv))) {
402 delete actor;
403 return false;
406 return aManager->SendPCycleCollectWithLogsConstructor(
407 actor, aDumpAllTraces, FILEToFileDescriptor(gcLog),
408 FILEToFileDescriptor(ccLog));
411 private:
412 virtual mozilla::ipc::IPCResult RecvCloseGCLog() override {
413 Unused << mSink->CloseGCLog();
414 return IPC_OK();
417 virtual mozilla::ipc::IPCResult RecvCloseCCLog() override {
418 Unused << mSink->CloseCCLog();
419 return IPC_OK();
422 virtual mozilla::ipc::IPCResult Recv__delete__() override {
423 // Report completion to mCallback only on successful
424 // completion of the protocol.
425 nsCOMPtr<nsIFile> gcLog, ccLog;
426 mSink->GetGcLog(getter_AddRefs(gcLog));
427 mSink->GetCcLog(getter_AddRefs(ccLog));
428 Unused << mCallback->OnDump(gcLog, ccLog, /* parent = */ false);
429 return IPC_OK();
432 virtual void ActorDestroy(ActorDestroyReason aReason) override {
433 // If the actor is unexpectedly destroyed, we deliberately
434 // don't call Close[GC]CLog on the sink, because the logs may
435 // be incomplete. See also the nsCycleCollectorLogSinkToFile
436 // implementaiton of those methods, and its destructor.
439 CycleCollectWithLogsParent(nsICycleCollectorLogSink* aSink,
440 nsIDumpGCAndCCLogsCallback* aCallback)
441 : mSink(aSink), mCallback(aCallback) {
442 MOZ_COUNT_CTOR(CycleCollectWithLogsParent);
445 nsCOMPtr<nsICycleCollectorLogSink> mSink;
446 nsCOMPtr<nsIDumpGCAndCCLogsCallback> mCallback;
449 // A memory reporter for ContentParent objects themselves.
450 class ContentParentsMemoryReporter final : public nsIMemoryReporter {
451 ~ContentParentsMemoryReporter() = default;
453 public:
454 NS_DECL_ISUPPORTS
455 NS_DECL_NSIMEMORYREPORTER
458 NS_IMPL_ISUPPORTS(ContentParentsMemoryReporter, nsIMemoryReporter)
460 NS_IMETHODIMP
461 ContentParentsMemoryReporter::CollectReports(
462 nsIHandleReportCallback* aHandleReport, nsISupports* aData,
463 bool aAnonymize) {
464 AutoTArray<ContentParent*, 16> cps;
465 ContentParent::GetAllEvenIfDead(cps);
467 for (uint32_t i = 0; i < cps.Length(); i++) {
468 ContentParent* cp = cps[i];
469 MessageChannel* channel = cp->GetIPCChannel();
471 nsString friendlyName;
472 cp->FriendlyName(friendlyName, aAnonymize);
474 cp->AddRef();
475 nsrefcnt refcnt = cp->Release();
477 const char* channelStr = "no channel";
478 uint32_t numQueuedMessages = 0;
479 if (channel) {
480 if (channel->IsClosed()) {
481 channelStr = "closed channel";
482 } else {
483 channelStr = "open channel";
485 numQueuedMessages =
486 0; // XXX was channel->Unsound_NumQueuedMessages(); Bug 1754876
489 nsPrintfCString path(
490 "queued-ipc-messages/content-parent"
491 "(%s, pid=%d, %s, 0x%p, refcnt=%" PRIuPTR ")",
492 NS_ConvertUTF16toUTF8(friendlyName).get(), cp->Pid(), channelStr,
493 static_cast<nsIObserver*>(cp), refcnt);
495 constexpr auto desc =
496 "The number of unset IPC messages held in this ContentParent's "
497 "channel. A large value here might indicate that we're leaking "
498 "messages. Similarly, a ContentParent object for a process that's no "
499 "longer running could indicate that we're leaking ContentParents."_ns;
501 aHandleReport->Callback(/* process */ ""_ns, path, KIND_OTHER, UNITS_COUNT,
502 numQueuedMessages, desc, aData);
505 return NS_OK;
508 // A hashtable (by type) of processes/ContentParents. This includes
509 // processes that are in the Preallocator cache (which would be type
510 // 'prealloc'), and recycled processes ('web' and in the future
511 // eTLD+1-locked) processes).
512 nsClassHashtable<nsCStringHashKey, nsTArray<ContentParent*>>*
513 ContentParent::sBrowserContentParents;
515 namespace {
517 uint64_t ComputeLoadedOriginHash(nsIPrincipal* aPrincipal) {
518 uint32_t originNoSuffix =
519 BasePrincipal::Cast(aPrincipal)->GetOriginNoSuffixHash();
520 uint32_t originSuffix =
521 BasePrincipal::Cast(aPrincipal)->GetOriginSuffixHash();
523 return ((uint64_t)originNoSuffix) << 32 | originSuffix;
526 ProcessID GetTelemetryProcessID(const nsACString& remoteType) {
527 // OOP WebExtensions run in a content process.
528 // For Telemetry though we want to break out collected data from the
529 // WebExtensions process into a separate bucket, to make sure we can analyze
530 // it separately and avoid skewing normal content process metrics.
531 return remoteType == EXTENSION_REMOTE_TYPE ? ProcessID::Extension
532 : ProcessID::Content;
535 } // anonymous namespace
537 StaticAutoPtr<LinkedList<ContentParent>> ContentParent::sContentParents;
538 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
539 StaticAutoPtr<SandboxBrokerPolicyFactory>
540 ContentParent::sSandboxBrokerPolicyFactory;
541 #endif
542 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
543 StaticAutoPtr<std::vector<std::string>> ContentParent::sMacSandboxParams;
544 #endif
546 // Set to true when the first content process gets created.
547 static bool sCreatedFirstContentProcess = false;
549 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
550 // True when we're running the process selection code, and do not expect to
551 // enter code paths where processes may die.
552 static bool sInProcessSelector = false;
553 #endif
555 // The first content child has ID 1, so the chrome process can have ID 0.
556 static uint64_t gContentChildID = 1;
558 static const char* sObserverTopics[] = {
559 NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
560 NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
561 NS_IPC_CAPTIVE_PORTAL_SET_STATE,
562 "application-background",
563 "application-foreground",
564 "memory-pressure",
565 "child-gc-request",
566 "child-cc-request",
567 "child-mmu-request",
568 "child-ghost-request",
569 "last-pb-context-exited",
570 "file-watcher-update",
571 #ifdef ACCESSIBILITY
572 "a11y-init-or-shutdown",
573 #endif
574 "cacheservice:empty-cache",
575 "intl:app-locales-changed",
576 "intl:requested-locales-changed",
577 "cookie-changed",
578 "private-cookie-changed",
579 NS_NETWORK_LINK_TYPE_TOPIC,
580 NS_NETWORK_TRR_MODE_CHANGED_TOPIC,
581 "network:socket-process-crashed",
582 DEFAULT_TIMEZONE_CHANGED_OBSERVER_TOPIC,
585 void ContentParent_NotifyUpdatedDictionaries() {
586 ContentParent::NotifyUpdatedDictionaries();
589 // PreallocateProcess is called by the PreallocatedProcessManager.
590 // ContentParent then takes this process back within GetNewOrUsedBrowserProcess.
591 /*static*/ UniqueContentParentKeepAlive ContentParent::MakePreallocProcess() {
592 RefPtr<ContentParent> process = new ContentParent(PREALLOC_REMOTE_TYPE);
593 if (NS_WARN_IF(!process->BeginSubprocessLaunch(PROCESS_PRIORITY_PREALLOC))) {
594 process->LaunchSubprocessReject();
595 return nullptr;
597 return process->AddKeepAlive(/* aBrowserId */ 0);
600 /*static*/
601 void ContentParent::StartUp() {
602 // FIXME Bug 1023701 - Stop using ContentParent static methods in
603 // child process
604 if (!XRE_IsParentProcess()) {
605 return;
608 // From this point on, NS_WARNING, NS_ASSERTION, etc. should print out the
609 // PID along with the warning.
610 nsDebugImpl::SetMultiprocessMode("Parent");
612 // Note: This reporter measures all ContentParents.
613 RegisterStrongMemoryReporter(new ContentParentsMemoryReporter());
615 BackgroundChild::Startup();
616 ClientManager::Startup();
618 Preferences::RegisterCallbackAndCall(&OnFissionBlocklistPrefChange,
619 kFissionEnforceBlockList);
620 Preferences::RegisterCallbackAndCall(&OnFissionBlocklistPrefChange,
621 kFissionOmitBlockListValues);
623 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
624 sSandboxBrokerPolicyFactory = new SandboxBrokerPolicyFactory();
625 #endif
627 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
628 sMacSandboxParams = new std::vector<std::string>();
629 #endif
632 /*static*/
633 void ContentParent::ShutDown() {
634 // For the most, we rely on normal process shutdown and
635 // ClearOnShutdown() to clean up our state.
637 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
638 sSandboxBrokerPolicyFactory = nullptr;
639 #endif
641 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
642 sMacSandboxParams = nullptr;
643 #endif
646 /*static*/
647 uint32_t ContentParent::GetPoolSize(const nsACString& aContentProcessType) {
648 if (!sBrowserContentParents) {
649 return 0;
652 nsTArray<ContentParent*>* parents =
653 sBrowserContentParents->Get(aContentProcessType);
655 return parents ? parents->Length() : 0;
658 /*static*/ nsTArray<ContentParent*>& ContentParent::GetOrCreatePool(
659 const nsACString& aContentProcessType) {
660 if (!sBrowserContentParents) {
661 sBrowserContentParents =
662 new nsClassHashtable<nsCStringHashKey, nsTArray<ContentParent*>>;
665 return *sBrowserContentParents->GetOrInsertNew(aContentProcessType);
668 nsDependentCSubstring RemoteTypePrefix(const nsACString& aContentProcessType) {
669 // The suffix after a `=` in a remoteType is dynamic, and used to control the
670 // process pool to use.
671 int32_t equalIdx = aContentProcessType.FindChar(L'=');
672 if (equalIdx == kNotFound) {
673 equalIdx = aContentProcessType.Length();
675 return StringHead(aContentProcessType, equalIdx);
678 bool IsWebRemoteType(const nsACString& aContentProcessType) {
679 // Note: matches webIsolated, web, and webCOOP+COEP types.
680 return StringBeginsWith(aContentProcessType, DEFAULT_REMOTE_TYPE);
683 bool IsWebCoopCoepRemoteType(const nsACString& aContentProcessType) {
684 return StringBeginsWith(aContentProcessType,
685 WITH_COOP_COEP_REMOTE_TYPE_PREFIX);
688 bool IsExtensionRemoteType(const nsACString& aContentProcessType) {
689 return aContentProcessType == EXTENSION_REMOTE_TYPE;
692 /*static*/
693 uint32_t ContentParent::GetMaxProcessCount(
694 const nsACString& aContentProcessType) {
695 // Max process count is based only on the prefix.
696 const nsDependentCSubstring processTypePrefix =
697 RemoteTypePrefix(aContentProcessType);
699 // Check for the default remote type of "web", as it uses different prefs.
700 if (processTypePrefix == DEFAULT_REMOTE_TYPE) {
701 return GetMaxWebProcessCount();
704 // Read the pref controling this remote type. `dom.ipc.processCount` is not
705 // used as a fallback, as it is intended to control the number of "web"
706 // content processes, checked in `mozilla::GetMaxWebProcessCount()`.
707 nsAutoCString processCountPref("dom.ipc.processCount.");
708 processCountPref.Append(processTypePrefix);
710 int32_t maxContentParents = Preferences::GetInt(processCountPref.get(), 1);
711 if (maxContentParents < 1) {
712 maxContentParents = 1;
715 return static_cast<uint32_t>(maxContentParents);
718 /*static*/
719 bool ContentParent::IsMaxProcessCountReached(
720 const nsACString& aContentProcessType) {
721 return GetPoolSize(aContentProcessType) >=
722 GetMaxProcessCount(aContentProcessType);
725 // Really more ReleaseUnneededProcesses()
726 /*static*/
727 void ContentParent::ReleaseCachedProcesses() {
728 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
729 ("ReleaseCachedProcesses:"));
730 if (!sBrowserContentParents) {
731 return;
734 #ifdef DEBUG
735 for (const auto& cps : *sBrowserContentParents) {
736 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
737 ("%s: %zu processes", PromiseFlatCString(cps.GetKey()).get(),
738 cps.GetData()->Length()));
740 #endif
742 // First let's collect all processes and keep a grip.
743 AutoTArray<RefPtr<ContentParent>, 32> fixArray;
744 for (const auto& contentParents : sBrowserContentParents->Values()) {
745 for (auto* cp : *contentParents) {
746 fixArray.AppendElement(cp);
750 for (const auto& cp : fixArray) {
751 if (cp->MaybeBeginShutDown(/* aIgnoreKeepAlivePref */ true)) {
752 // Make sure that this process is no longer accessible from JS by its
753 // message manager.
754 cp->ShutDownMessageManager();
759 /*static*/
760 already_AddRefed<ContentParent> ContentParent::MinTabSelect(
761 const nsTArray<ContentParent*>& aContentParents, int32_t aMaxContentParents,
762 uint64_t aBrowserId) {
763 uint32_t maxSelectable =
764 std::min(static_cast<uint32_t>(aContentParents.Length()),
765 static_cast<uint32_t>(aMaxContentParents));
766 uint32_t min = INT_MAX;
767 RefPtr<ContentParent> candidate;
769 for (uint32_t i = 0; i < maxSelectable; i++) {
770 ContentParent* p = aContentParents[i];
771 MOZ_DIAGNOSTIC_ASSERT(!p->IsDead());
772 if (p->IsShuttingDown()) {
773 continue;
776 // Check how many other tabs are already hosted by this process. Ignore
777 // keepalives without a BrowserId as well as keepalives corresponding to
778 // `aBrowserId` when doing this calculation.
779 ThreadsafeContentParentHandle* handle = p->ThreadsafeHandle();
780 RecursiveMutexAutoLock lock(handle->mMutex);
781 uint32_t keepAliveCount = handle->mKeepAlivesPerBrowserId.Count();
782 if (handle->mKeepAlivesPerBrowserId.Contains(0)) {
783 --keepAliveCount;
785 if (aBrowserId != 0 &&
786 handle->mKeepAlivesPerBrowserId.Contains(aBrowserId)) {
787 --keepAliveCount;
790 if (keepAliveCount < min) {
791 candidate = p;
792 min = keepAliveCount;
796 // If all current processes have at least one tab and we have not yet reached
797 // the maximum, use a new process.
798 if (min > 0 &&
799 aContentParents.Length() < static_cast<uint32_t>(aMaxContentParents)) {
800 return nullptr;
803 // Otherwise we return candidate.
804 return candidate.forget();
807 /* static */
808 already_AddRefed<nsIPrincipal>
809 ContentParent::CreateRemoteTypeIsolationPrincipal(
810 const nsACString& aRemoteType) {
811 if ((RemoteTypePrefix(aRemoteType) != FISSION_WEB_REMOTE_TYPE) &&
812 !StringBeginsWith(aRemoteType, WITH_COOP_COEP_REMOTE_TYPE_PREFIX)) {
813 return nullptr;
816 int32_t offset = aRemoteType.FindChar('=') + 1;
817 MOZ_ASSERT(offset > 1, "can not extract origin from that remote type");
818 nsAutoCString origin(
819 Substring(aRemoteType, offset, aRemoteType.Length() - offset));
821 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
822 nsCOMPtr<nsIPrincipal> principal;
823 ssm->CreateContentPrincipalFromOrigin(origin, getter_AddRefs(principal));
824 return principal.forget();
827 /*static*/
828 UniqueContentParentKeepAlive ContentParent::GetUsedBrowserProcess(
829 const nsACString& aRemoteType, nsTArray<ContentParent*>& aContentParents,
830 uint32_t aMaxContentParents, bool aPreferUsed, ProcessPriority aPriority,
831 uint64_t aBrowserId) {
832 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
833 AutoRestore ar(sInProcessSelector);
834 sInProcessSelector = true;
835 #endif
837 uint32_t numberOfParents = aContentParents.Length();
838 if (aPreferUsed && numberOfParents) {
839 // If we prefer re-using existing content processes, we don't want to create
840 // a new process, and instead re-use an existing one, so pretend the process
841 // limit is at the current number of processes.
842 aMaxContentParents = numberOfParents;
845 // Use MinTabSelect to choose a content process unless content process re-use
846 // has been disabled.
847 RefPtr<ContentParent> selected;
848 if (!StaticPrefs::dom_ipc_disableContentProcessReuse() &&
849 (selected =
850 MinTabSelect(aContentParents, aMaxContentParents, aBrowserId))) {
851 if (profiler_thread_is_being_profiled_for_markers()) {
852 nsPrintfCString marker("Reused process %u",
853 (unsigned int)selected->ChildID());
854 PROFILER_MARKER_TEXT("Process", DOM, {}, marker);
856 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
857 ("GetUsedProcess: Reused process %p (%d) for %s", selected.get(),
858 (unsigned int)selected->ChildID(),
859 PromiseFlatCString(aRemoteType).get()));
860 selected->AssertAlive();
861 return selected->AddKeepAlive(aBrowserId);
864 // Try to take a preallocated process except for certain remote types.
865 // Note: this process may not have finished launching yet
866 UniqueContentParentKeepAlive preallocated;
867 if (aRemoteType != FILE_REMOTE_TYPE &&
868 aRemoteType != PRIVILEGEDABOUT_REMOTE_TYPE &&
869 aRemoteType != EXTENSION_REMOTE_TYPE && // Bug 1638119
870 (preallocated = PreallocatedProcessManager::Take(aRemoteType))) {
871 MOZ_DIAGNOSTIC_ASSERT(preallocated->GetRemoteType() ==
872 PREALLOC_REMOTE_TYPE);
873 preallocated->AssertAlive();
875 if (profiler_thread_is_being_profiled_for_markers()) {
876 nsPrintfCString marker(
877 "Assigned preallocated process %u%s",
878 (unsigned int)preallocated->ChildID(),
879 preallocated->IsLaunching() ? " (still launching)" : "");
880 PROFILER_MARKER_TEXT("Process", DOM, {}, marker);
882 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
883 ("Adopted preallocated process %p for type %s%s",
884 preallocated.get(), PromiseFlatCString(aRemoteType).get(),
885 preallocated->IsLaunching() ? " (still launching)" : ""));
887 // This ensures that the preallocator won't shut down the process once
888 // it finishes starting
889 preallocated->mRemoteType.Assign(aRemoteType);
891 RecursiveMutexAutoLock lock(preallocated->mThreadsafeHandle->mMutex);
892 preallocated->mThreadsafeHandle->mRemoteType = preallocated->mRemoteType;
894 preallocated->mRemoteTypeIsolationPrincipal =
895 CreateRemoteTypeIsolationPrincipal(aRemoteType);
896 preallocated->mActivateTS = TimeStamp::Now();
897 preallocated->AddToPool(aContentParents);
899 // rare, but will happen
900 if (!preallocated->IsLaunching()) {
901 // Specialize this process for the appropriate remote type, and activate
902 // it.
904 Unused << preallocated->SendRemoteType(preallocated->mRemoteType,
905 preallocated->mProfile);
907 preallocated->StartRemoteWorkerService();
909 nsCOMPtr<nsIObserverService> obs =
910 mozilla::services::GetObserverService();
911 if (obs) {
912 nsAutoString cpId;
913 cpId.AppendInt(static_cast<uint64_t>(preallocated->ChildID()));
914 obs->NotifyObservers(static_cast<nsIObserver*>(preallocated.get()),
915 "process-type-set", cpId.get());
916 preallocated->AssertAlive();
919 // NOTE: Make sure to return a keepalive for the requested aBrowserId. The
920 // keepalive used by the preallocated process manager will be released upon
921 // returning.
922 return preallocated->AddKeepAlive(aBrowserId);
925 return nullptr;
928 /*static*/
929 UniqueContentParentKeepAlive ContentParent::GetNewOrUsedLaunchingBrowserProcess(
930 const nsACString& aRemoteType, BrowsingContextGroup* aGroup,
931 ProcessPriority aPriority, bool aPreferUsed, uint64_t aBrowserId) {
932 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
933 ("GetNewOrUsedProcess for type %s",
934 PromiseFlatCString(aRemoteType).get()));
936 // Fallback check (we really want our callers to avoid this).
937 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
938 MOZ_DIAGNOSTIC_ASSERT(
939 false, "Late attempt to GetNewOrUsedLaunchingBrowserProcess!");
940 return nullptr;
943 // If we have an existing host process attached to this BrowsingContextGroup,
944 // always return it, as we can never have multiple host processes within a
945 // single BrowsingContextGroup.
946 UniqueContentParentKeepAlive contentParent;
947 if (aGroup) {
948 if (RefPtr<ContentParent> candidate = aGroup->GetHostProcess(aRemoteType)) {
949 Unused << NS_WARN_IF(candidate->IsShuttingDown());
950 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
951 ("GetNewOrUsedProcess: Existing host process %p (launching %d)",
952 candidate.get(), candidate->IsLaunching()));
953 contentParent = candidate->TryAddKeepAlive(aBrowserId);
957 nsTArray<ContentParent*>& contentParents = GetOrCreatePool(aRemoteType);
959 if (!contentParent) {
960 // No host process. Let's try to re-use an existing process.
961 uint32_t maxContentParents = GetMaxProcessCount(aRemoteType);
963 contentParent =
964 GetUsedBrowserProcess(aRemoteType, contentParents, maxContentParents,
965 aPreferUsed, aPriority, aBrowserId);
968 if (!contentParent) {
969 // No reusable process. Let's create and launch one.
970 // The life cycle will be set to `LifecycleState::LAUNCHING`.
971 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
972 ("Launching new process immediately for type %s",
973 PromiseFlatCString(aRemoteType).get()));
975 RefPtr<ContentParent> newCp = new ContentParent(aRemoteType);
976 if (NS_WARN_IF(!newCp->BeginSubprocessLaunch(aPriority))) {
977 // Launch aborted because of shutdown. Bailout.
978 newCp->LaunchSubprocessReject();
979 return nullptr;
981 contentParent = newCp->AddKeepAlive(aBrowserId);
983 // Until the new process is ready let's not allow to start up any
984 // preallocated processes. The blocker will be removed once we receive
985 // the first idle message.
986 contentParent->mIsAPreallocBlocker = true;
987 PreallocatedProcessManager::AddBlocker(aRemoteType, contentParent.get());
989 // Store this process for future reuse.
990 contentParent->AddToPool(contentParents);
992 MOZ_LOG(
993 ContentParent::GetLog(), LogLevel::Debug,
994 ("GetNewOrUsedProcess: new immediate process %p", contentParent.get()));
996 // else we have an existing or preallocated process (which may be
997 // still launching)
999 contentParent->AssertAlive();
1000 if (aGroup) {
1001 aGroup->EnsureHostProcess(contentParent.get());
1003 return contentParent;
1006 /*static*/
1007 RefPtr<ContentParent::LaunchPromise>
1008 ContentParent::GetNewOrUsedBrowserProcessAsync(const nsACString& aRemoteType,
1009 BrowsingContextGroup* aGroup,
1010 ProcessPriority aPriority,
1011 bool aPreferUsed,
1012 uint64_t aBrowserId) {
1013 // Obtain a `ContentParent` launched asynchronously.
1014 UniqueContentParentKeepAlive contentParent =
1015 GetNewOrUsedLaunchingBrowserProcess(aRemoteType, aGroup, aPriority,
1016 aPreferUsed, aBrowserId);
1017 if (!contentParent) {
1018 // In case of launch error, stop here.
1019 return LaunchPromise::CreateAndReject(NS_ERROR_ILLEGAL_DURING_SHUTDOWN,
1020 __func__);
1022 return contentParent->WaitForLaunchAsync(aPriority, aBrowserId);
1025 /*static*/
1026 UniqueContentParentKeepAlive ContentParent::GetNewOrUsedBrowserProcess(
1027 const nsACString& aRemoteType, BrowsingContextGroup* aGroup,
1028 ProcessPriority aPriority, bool aPreferUsed, uint64_t aBrowserId) {
1029 UniqueContentParentKeepAlive contentParent =
1030 GetNewOrUsedLaunchingBrowserProcess(aRemoteType, aGroup, aPriority,
1031 aPreferUsed, aBrowserId);
1032 if (!contentParent || !contentParent->WaitForLaunchSync(aPriority)) {
1033 // In case of launch error, stop here.
1034 return nullptr;
1036 return contentParent;
1039 RefPtr<ContentParent::LaunchPromise> ContentParent::WaitForLaunchAsync(
1040 ProcessPriority aPriority, uint64_t aBrowserId) {
1041 MOZ_DIAGNOSTIC_ASSERT(!IsDead());
1042 UniqueContentParentKeepAlive self = AddKeepAlive(aBrowserId);
1044 if (!IsLaunching()) {
1045 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1046 ("WaitForLaunchAsync: launched"));
1047 return LaunchPromise::CreateAndResolve(std::move(self), __func__);
1050 // We've started an async content process launch.
1051 Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC, 0);
1053 // We have located a process that hasn't finished initializing, then attempt
1054 // to finish initializing. Both `LaunchSubprocessResolve` and
1055 // `LaunchSubprocessReject` are safe to call multiple times if we race with
1056 // other `WaitForLaunchAsync` callbacks.
1057 return mSubprocess->WhenProcessHandleReady()->Then(
1058 GetCurrentSerialEventTarget(), __func__,
1059 [self = std::move(self), aPriority](
1060 const ProcessHandlePromise::ResolveOrRejectValue& aValue) mutable {
1061 if (aValue.IsResolve() &&
1062 self->LaunchSubprocessResolve(/* aIsSync = */ false, aPriority)) {
1063 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1064 ("WaitForLaunchAsync: async, now launched"));
1065 self->mActivateTS = TimeStamp::Now();
1066 return LaunchPromise::CreateAndResolve(std::move(self), __func__);
1069 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1070 ("WaitForLaunchAsync: async, rejected"));
1071 self->LaunchSubprocessReject();
1072 return LaunchPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
1076 bool ContentParent::WaitForLaunchSync(ProcessPriority aPriority) {
1077 MOZ_DIAGNOSTIC_ASSERT(!IsDead());
1078 if (!IsLaunching()) {
1079 return true;
1082 // We've started a sync content process launch.
1083 Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC, 1);
1085 // We're a process which hasn't finished initializing. We may be racing
1086 // against whoever launched it (and whoever else is already racing). Since
1087 // we're sync, we win the race and finish the initialization.
1088 bool launchSuccess = mSubprocess->WaitForProcessHandle();
1089 if (launchSuccess &&
1090 LaunchSubprocessResolve(/* aIsSync = */ true, aPriority)) {
1091 mActivateTS = TimeStamp::Now();
1092 return true;
1094 // In case of failure.
1095 LaunchSubprocessReject();
1096 return false;
1099 static nsIDocShell* GetOpenerDocShellHelper(Element* aFrameElement) {
1100 // Propagate the private-browsing status of the element's parent
1101 // docshell to the remote docshell, via the chrome flags.
1102 MOZ_ASSERT(aFrameElement);
1103 nsPIDOMWindowOuter* win = aFrameElement->OwnerDoc()->GetWindow();
1104 if (!win) {
1105 NS_WARNING("Remote frame has no window");
1106 return nullptr;
1108 nsIDocShell* docShell = win->GetDocShell();
1109 if (!docShell) {
1110 NS_WARNING("Remote frame has no docshell");
1111 return nullptr;
1114 return docShell;
1117 mozilla::ipc::IPCResult ContentParent::RecvCreateGMPService() {
1118 Endpoint<PGMPServiceParent> parent;
1119 Endpoint<PGMPServiceChild> child;
1121 if (mGMPCreated) {
1122 return IPC_FAIL(this, "GMP Service already created");
1125 nsresult rv;
1126 rv = PGMPService::CreateEndpoints(base::GetCurrentProcId(), OtherPid(),
1127 &parent, &child);
1128 if (NS_FAILED(rv)) {
1129 return IPC_FAIL(this, "CreateEndpoints failed");
1132 if (!GMPServiceParent::Create(std::move(parent))) {
1133 return IPC_FAIL(this, "GMPServiceParent::Create failed");
1136 if (!SendInitGMPService(std::move(child))) {
1137 return IPC_FAIL(this, "SendInitGMPService failed");
1140 mGMPCreated = true;
1142 return IPC_OK();
1145 IPCResult ContentParent::RecvAttributionEvent(
1146 const nsACString& aHost, PrivateAttributionImpressionType aType,
1147 uint32_t aIndex, const nsAString& aAd, const nsACString& aTargetHost) {
1148 nsCOMPtr<nsIPrivateAttributionService> pa =
1149 components::PrivateAttribution::Service();
1150 if (NS_WARN_IF(!pa)) {
1151 return IPC_OK();
1153 pa->OnAttributionEvent(aHost, GetEnumString(aType), aIndex, aAd, aTargetHost);
1154 return IPC_OK();
1157 IPCResult ContentParent::RecvAttributionConversion(
1158 const nsACString& aHost, const nsAString& aTask, uint32_t aHistogramSize,
1159 const Maybe<uint32_t>& aLoopbackDays,
1160 const Maybe<PrivateAttributionImpressionType>& aImpressionType,
1161 const nsTArray<nsString>& aAds, const nsTArray<nsCString>& aSourceHosts) {
1162 nsCOMPtr<nsIPrivateAttributionService> pa =
1163 components::PrivateAttribution::Service();
1164 if (NS_WARN_IF(!pa)) {
1165 return IPC_OK();
1167 pa->OnAttributionConversion(
1168 aHost, aTask, aHistogramSize, aLoopbackDays.valueOr(0),
1169 aImpressionType ? GetEnumString(*aImpressionType) : EmptyCString(), aAds,
1170 aSourceHosts);
1171 return IPC_OK();
1174 Atomic<bool, mozilla::Relaxed> sContentParentTelemetryEventEnabled(false);
1176 /*static*/
1177 void ContentParent::LogAndAssertFailedPrincipalValidationInfo(
1178 nsIPrincipal* aPrincipal, const char* aMethod) {
1179 // nsContentSecurityManager may also enable this same event, but that's okay
1180 if (!sContentParentTelemetryEventEnabled.exchange(true)) {
1181 sContentParentTelemetryEventEnabled = true;
1182 Telemetry::SetEventRecordingEnabled("security"_ns, true);
1185 // Send Telemetry
1186 nsAutoCString principalScheme, principalType, spec;
1187 CopyableTArray<EventExtraEntry> extra(2);
1189 if (!aPrincipal) {
1190 principalType.AssignLiteral("NullPtr");
1191 } else if (aPrincipal->IsSystemPrincipal()) {
1192 principalType.AssignLiteral("SystemPrincipal");
1193 } else if (aPrincipal->GetIsExpandedPrincipal()) {
1194 principalType.AssignLiteral("ExpandedPrincipal");
1195 } else if (aPrincipal->GetIsContentPrincipal()) {
1196 principalType.AssignLiteral("ContentPrincipal");
1197 aPrincipal->GetSpec(spec);
1198 aPrincipal->GetScheme(principalScheme);
1200 extra.AppendElement(EventExtraEntry{"scheme"_ns, principalScheme});
1201 } else {
1202 principalType.AssignLiteral("Unknown");
1205 extra.AppendElement(EventExtraEntry{"principalType"_ns, principalType});
1207 // Do not send telemetry when chrome-debugging is enabled
1208 bool isChromeDebuggingEnabled =
1209 Preferences::GetBool("devtools.chrome.enabled", false);
1210 if (!isChromeDebuggingEnabled) {
1211 Telemetry::EventID eventType =
1212 Telemetry::EventID::Security_Fissionprincipals_Contentparent;
1213 Telemetry::RecordEvent(eventType, mozilla::Some(aMethod),
1214 mozilla::Some(extra));
1217 // And log it
1218 MOZ_LOG(
1219 ContentParent::GetLog(), LogLevel::Error,
1220 (" Receiving unexpected Principal (%s) within %s",
1221 aPrincipal && aPrincipal->GetIsContentPrincipal() ? spec.get()
1222 : principalType.get(),
1223 aMethod));
1225 #ifdef DEBUG
1226 // Not only log but also ensure we do not receive an unexpected
1227 // principal when running in debug mode.
1228 MOZ_ASSERT(false, "Receiving unexpected Principal");
1229 #endif
1232 bool ContentParent::ValidatePrincipal(
1233 nsIPrincipal* aPrincipal,
1234 const EnumSet<ValidatePrincipalOptions>& aOptions) {
1235 // If the pref says we should not validate, then there is nothing to do
1236 if (!StaticPrefs::dom_security_enforceIPCBasedPrincipalVetting()) {
1237 return true;
1240 // If there is no principal, then there is nothing to validate!
1241 if (!aPrincipal) {
1242 return aOptions.contains(ValidatePrincipalOptions::AllowNullPtr);
1245 // We currently do not track relationships between specific null principals
1246 // and content processes, so we can not validate much here - just allow all
1247 // null principals we see because they are generally safe anyway!
1248 if (aPrincipal->GetIsNullPrincipal()) {
1249 return true;
1252 // Only allow the system principal if the passed in options flags
1253 // request permitting the system principal.
1254 if (aPrincipal->IsSystemPrincipal()) {
1255 return aOptions.contains(ValidatePrincipalOptions::AllowSystem);
1258 // XXXckerschb: we should eliminate the resource carve-out here and always
1259 // validate the Principal, see Bug 1686200: Investigate Principal for pdf.js
1260 if (aPrincipal->SchemeIs("resource")) {
1261 return true;
1264 // Validate each inner principal individually, allowing us to catch expanded
1265 // principals containing the system principal, etc.
1266 if (aPrincipal->GetIsExpandedPrincipal()) {
1267 if (!aOptions.contains(ValidatePrincipalOptions::AllowExpanded)) {
1268 return false;
1270 // FIXME: There are more constraints on expanded principals in-practice,
1271 // such as the structure of extension expanded principals. This may need
1272 // to be investigated more in the future.
1273 nsCOMPtr<nsIExpandedPrincipal> expandedPrincipal =
1274 do_QueryInterface(aPrincipal);
1275 const auto& allowList = expandedPrincipal->AllowList();
1276 for (const auto& innerPrincipal : allowList) {
1277 if (!ValidatePrincipal(innerPrincipal, aOptions)) {
1278 return false;
1281 return true;
1284 // A URI with a file:// scheme can never load in a non-file content process
1285 // due to sandboxing.
1286 if (aPrincipal->SchemeIs("file")) {
1287 // If we don't support a separate 'file' process, then we can return here.
1288 if (!StaticPrefs::browser_tabs_remote_separateFileUriProcess()) {
1289 return true;
1291 return mRemoteType == FILE_REMOTE_TYPE;
1294 if (aPrincipal->SchemeIs("about")) {
1295 uint32_t flags = 0;
1296 if (NS_FAILED(aPrincipal->GetAboutModuleFlags(&flags))) {
1297 return false;
1300 // Block principals for about: URIs which can't load in this process.
1301 if (!(flags & (nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
1302 nsIAboutModule::URI_MUST_LOAD_IN_CHILD))) {
1303 return false;
1305 if (flags & nsIAboutModule::URI_MUST_LOAD_IN_EXTENSION_PROCESS) {
1306 return mRemoteType == EXTENSION_REMOTE_TYPE;
1308 return true;
1311 if (!mRemoteTypeIsolationPrincipal ||
1312 RemoteTypePrefix(mRemoteType) != FISSION_WEB_REMOTE_TYPE) {
1313 return true;
1316 // Web content can contain extension content frames, so a content process may
1317 // send us an extension's principal.
1318 auto* addonPolicy = BasePrincipal::Cast(aPrincipal)->AddonPolicy();
1319 if (addonPolicy) {
1320 return true;
1323 // Ensure that the expected site-origin matches the one specified by our
1324 // mRemoteTypeIsolationPrincipal.
1325 nsAutoCString siteOriginNoSuffix;
1326 if (NS_FAILED(aPrincipal->GetSiteOriginNoSuffix(siteOriginNoSuffix))) {
1327 return false;
1329 nsAutoCString remoteTypeSiteOriginNoSuffix;
1330 if (NS_FAILED(mRemoteTypeIsolationPrincipal->GetSiteOriginNoSuffix(
1331 remoteTypeSiteOriginNoSuffix))) {
1332 return false;
1335 return remoteTypeSiteOriginNoSuffix.Equals(siteOriginNoSuffix);
1338 /*static*/
1339 already_AddRefed<RemoteBrowser> ContentParent::CreateBrowser(
1340 const TabContext& aContext, Element* aFrameElement,
1341 const nsACString& aRemoteType, BrowsingContext* aBrowsingContext,
1342 ContentParent* aOpenerContentParent) {
1343 AUTO_PROFILER_LABEL("ContentParent::CreateBrowser", OTHER);
1345 MOZ_DIAGNOSTIC_ASSERT(
1346 !aBrowsingContext->Canonical()->GetBrowserParent(),
1347 "BrowsingContext must not have BrowserParent, or have previous "
1348 "BrowserParent cleared");
1350 // Don't bother creating new content browsers after entering shutdown. This
1351 // could lead to starting a new content process, which may significantly delay
1352 // shutdown, and the content is unlikely to be displayed.
1353 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
1354 NS_WARNING("Ignoring remote browser creation request during shutdown");
1355 return nullptr;
1358 nsAutoCString remoteType(aRemoteType);
1359 if (remoteType.IsEmpty()) {
1360 remoteType = DEFAULT_REMOTE_TYPE;
1363 TabId tabId(nsContentUtils::GenerateTabId());
1365 nsIDocShell* docShell = GetOpenerDocShellHelper(aFrameElement);
1366 TabId openerTabId;
1367 if (docShell) {
1368 openerTabId = BrowserParent::GetTabIdFrom(docShell);
1371 // Hold a KeepAlive on our ContentParent throughout this function. Once the
1372 // `BrowserParent` has been created, it can be cleared, as that BrowserParent
1373 // will establish its own KeepAlive.
1374 UniqueContentParentKeepAlive constructorSender;
1375 MOZ_RELEASE_ASSERT(XRE_IsParentProcess(),
1376 "Cannot allocate BrowserParent in content process");
1377 if (aOpenerContentParent && !aOpenerContentParent->IsShuttingDown()) {
1378 constructorSender =
1379 aOpenerContentParent->AddKeepAlive(aBrowsingContext->BrowserId());
1380 } else {
1381 constructorSender = GetNewOrUsedBrowserProcess(
1382 remoteType, aBrowsingContext->Group(), PROCESS_PRIORITY_FOREGROUND,
1383 /* aPreferUsed */ false,
1384 /* aBrowserId */ aBrowsingContext->BrowserId());
1385 if (!constructorSender) {
1386 return nullptr;
1390 aBrowsingContext->SetEmbedderElement(aFrameElement);
1392 // Ensure that the process which we're using to launch is set as the host
1393 // process for this BrowsingContextGroup.
1394 aBrowsingContext->Group()->EnsureHostProcess(constructorSender.get());
1396 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
1397 docShell->GetTreeOwner(getter_AddRefs(treeOwner));
1398 if (!treeOwner) {
1399 return nullptr;
1402 nsCOMPtr<nsIWebBrowserChrome> wbc = do_GetInterface(treeOwner);
1403 if (!wbc) {
1404 return nullptr;
1406 uint32_t chromeFlags = 0;
1407 wbc->GetChromeFlags(&chromeFlags);
1409 nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
1410 if (loadContext && loadContext->UsePrivateBrowsing()) {
1411 chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
1413 if (loadContext && loadContext->UseRemoteTabs()) {
1414 chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
1416 if (loadContext && loadContext->UseRemoteSubframes()) {
1417 chromeFlags |= nsIWebBrowserChrome::CHROME_FISSION_WINDOW;
1420 if (tabId == 0) {
1421 return nullptr;
1424 aBrowsingContext->Canonical()->SetOwnerProcessId(
1425 constructorSender->ChildID());
1427 RefPtr<BrowserParent> browserParent =
1428 new BrowserParent(constructorSender.get(), tabId, aContext,
1429 aBrowsingContext->Canonical(), chromeFlags);
1431 // Open a remote endpoint for our PBrowser actor.
1432 ManagedEndpoint<PBrowserChild> childEp =
1433 constructorSender->OpenPBrowserEndpoint(browserParent);
1434 if (NS_WARN_IF(!childEp.IsValid())) {
1435 return nullptr;
1438 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
1439 if (NS_WARN_IF(!cpm)) {
1440 return nullptr;
1442 cpm->RegisterRemoteFrame(browserParent);
1444 nsCOMPtr<nsIPrincipal> initialPrincipal =
1445 NullPrincipal::Create(aBrowsingContext->OriginAttributesRef());
1446 WindowGlobalInit windowInit = WindowGlobalActor::AboutBlankInitializer(
1447 aBrowsingContext, initialPrincipal);
1449 RefPtr<WindowGlobalParent> windowParent =
1450 WindowGlobalParent::CreateDisconnected(windowInit);
1451 if (NS_WARN_IF(!windowParent)) {
1452 return nullptr;
1455 // Open a remote endpoint for the initial PWindowGlobal actor.
1456 ManagedEndpoint<PWindowGlobalChild> windowEp =
1457 browserParent->OpenPWindowGlobalEndpoint(windowParent);
1458 if (NS_WARN_IF(!windowEp.IsValid())) {
1459 return nullptr;
1462 // Tell the content process to set up its PBrowserChild.
1463 bool ok = constructorSender->SendConstructBrowser(
1464 std::move(childEp), std::move(windowEp), tabId,
1465 aContext.AsIPCTabContext(), windowInit, chromeFlags,
1466 constructorSender->ChildID(), constructorSender->IsForBrowser(),
1467 /* aIsTopLevel */ true);
1468 if (NS_WARN_IF(!ok)) {
1469 return nullptr;
1472 // Ensure that we're marked as the current BrowserParent on our
1473 // CanonicalBrowsingContext.
1474 aBrowsingContext->Canonical()->SetCurrentBrowserParent(browserParent);
1476 windowParent->Init();
1478 RefPtr<BrowserHost> browserHost = new BrowserHost(browserParent);
1479 browserParent->SetOwnerElement(aFrameElement);
1480 return browserHost.forget();
1483 void ContentParent::GetAll(nsTArray<ContentParent*>& aArray) {
1484 aArray.Clear();
1486 for (auto* cp : AllProcesses(eLive)) {
1487 aArray.AppendElement(cp);
1491 void ContentParent::GetAllEvenIfDead(nsTArray<ContentParent*>& aArray) {
1492 aArray.Clear();
1494 for (auto* cp : AllProcesses(eAll)) {
1495 aArray.AppendElement(cp);
1499 void ContentParent::BroadcastStringBundle(
1500 const StringBundleDescriptor& aBundle) {
1501 AutoTArray<StringBundleDescriptor, 1> array;
1502 array.AppendElement(aBundle);
1504 for (auto* cp : AllProcesses(eLive)) {
1505 Unused << cp->SendRegisterStringBundles(array);
1509 void ContentParent::BroadcastFontListChanged() {
1510 for (auto* cp : AllProcesses(eLive)) {
1511 Unused << cp->SendFontListChanged();
1515 void ContentParent::BroadcastShmBlockAdded(uint32_t aGeneration,
1516 uint32_t aIndex) {
1517 auto* pfl = gfxPlatformFontList::PlatformFontList();
1518 for (auto* cp : AllProcesses(eLive)) {
1519 base::SharedMemoryHandle handle =
1520 pfl->ShareShmBlockToProcess(aIndex, cp->Pid());
1521 if (handle == base::SharedMemory::NULLHandle()) {
1522 // If something went wrong here, we just skip it; the child will need to
1523 // request the block as needed, at some performance cost.
1524 continue;
1526 Unused << cp->SendFontListShmBlockAdded(aGeneration, aIndex,
1527 std::move(handle));
1531 void ContentParent::BroadcastThemeUpdate(widget::ThemeChangeKind aKind) {
1532 const FullLookAndFeel& lnf = *RemoteLookAndFeel::ExtractData();
1533 for (auto* cp : AllProcesses(eLive)) {
1534 Unused << cp->SendThemeChanged(lnf, aKind);
1538 /*static */
1539 void ContentParent::BroadcastMediaCodecsSupportedUpdate(
1540 RemoteDecodeIn aLocation, const media::MediaCodecsSupported& aSupported) {
1541 // Update processes and print the support info from the given location.
1542 sCodecsSupported[aLocation] = aSupported;
1543 for (auto* cp : AllProcesses(eAll)) {
1544 Unused << cp->SendUpdateMediaCodecsSupported(aLocation, aSupported);
1546 nsCString supportString;
1547 media::MCSInfo::GetMediaCodecsSupportedString(supportString, aSupported);
1548 LOGPDM("Broadcast support from '%s', support=%s",
1549 RemoteDecodeInToStr(aLocation), supportString.get());
1551 // Merge incoming support with existing support list from other locations
1552 media::MCSInfo::AddSupport(aSupported);
1553 auto fullSupport = media::MCSInfo::GetSupport();
1555 // Generate + save FULL support string for display in about:support
1556 supportString.Truncate();
1557 media::MCSInfo::GetMediaCodecsSupportedString(supportString, fullSupport);
1558 gfx::gfxVars::SetCodecSupportInfo(supportString);
1561 const nsACString& ContentParent::GetRemoteType() const { return mRemoteType; }
1563 static StaticRefPtr<nsIAsyncShutdownClient> sXPCOMShutdownClient;
1564 static StaticRefPtr<nsIAsyncShutdownClient> sProfileBeforeChangeClient;
1565 static StaticRefPtr<nsIAsyncShutdownClient> sQuitApplicationGrantedClient;
1567 void ContentParent::Init() {
1568 MOZ_ASSERT(sXPCOMShutdownClient);
1570 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
1571 if (obs) {
1572 size_t length = ArrayLength(sObserverTopics);
1573 for (size_t i = 0; i < length; ++i) {
1574 obs->AddObserver(this, sObserverTopics[i], false);
1578 if (obs) {
1579 nsAutoString cpId;
1580 cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
1581 obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-created",
1582 cpId.get());
1585 #ifdef ACCESSIBILITY
1586 // If accessibility is running in chrome process then start it in content
1587 // process.
1588 if (GetAccService()) {
1589 Unused << SendActivateA11y();
1591 #endif // #ifdef ACCESSIBILITY
1593 Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
1595 RefPtr<GeckoMediaPluginServiceParent> gmps(
1596 GeckoMediaPluginServiceParent::GetSingleton());
1597 if (gmps) {
1598 gmps->UpdateContentProcessGMPCapabilities(this);
1601 // Flush any pref updates that happened during launch and weren't
1602 // included in the blobs set up in BeginSubprocessLaunch.
1603 for (const Pref& pref : mQueuedPrefs) {
1604 Unused << NS_WARN_IF(!SendPreferenceUpdate(pref));
1606 mQueuedPrefs.Clear();
1608 Unused << SendInitNextGenLocalStorageEnabled(NextGenLocalStorageEnabled());
1611 void ContentParent::AsyncSendShutDownMessage() {
1612 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
1613 ("AsyncSendShutDownMessage %p", this));
1614 MOZ_ASSERT(NS_IsMainThread());
1616 // In the case of normal shutdown, send a shutdown message to child to
1617 // allow it to perform shutdown tasks.
1618 GetCurrentSerialEventTarget()->Dispatch(NewRunnableMethod<ShutDownMethod>(
1619 "dom::ContentParent::ShutDownProcess", this,
1620 &ContentParent::ShutDownProcess, SEND_SHUTDOWN_MESSAGE));
1623 void MaybeLogBlockShutdownDiagnostics(ContentParent* aSelf, const char* aMsg,
1624 const char* aFile, int32_t aLine) {
1625 #if defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
1626 if (aSelf->IsBlockingShutdown()) {
1627 MOZ_LOG(ContentParent::GetLog(), LogLevel::Info,
1628 ("ContentParent: id=%p pid=%d - %s at %s(%d)", aSelf, aSelf->Pid(),
1629 aMsg, aFile, aLine));
1631 #else
1632 Unused << aSelf;
1633 Unused << aMsg;
1634 Unused << aFile;
1635 Unused << aLine;
1636 #endif
1639 bool ContentParent::ShutDownProcess(ShutDownMethod aMethod) {
1640 bool result = false;
1641 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1642 ("ShutDownProcess: %p", this));
1643 // NB: must MarkAsDead() here so that this isn't accidentally
1644 // returned from Get*() while in the midst of shutdown.
1645 MarkAsDead();
1647 // Shutting down by sending a shutdown message works differently than the
1648 // other methods. We first call Shutdown() in the child. After the child is
1649 // ready, it calls FinishShutdown() on us. Then we close the channel.
1650 if (aMethod == SEND_SHUTDOWN_MESSAGE) {
1651 if (!mShutdownPending) {
1652 if (CanSend()) {
1653 // Stop sending input events with input priority when shutting down.
1654 SetInputPriorityEventEnabled(false);
1655 // If we did not earlier, let's signal the shutdown to JS now.
1656 SignalImpendingShutdownToContentJS();
1658 // Adjust the QoS priorities for shutdown, if they exist.
1659 if (StaticPrefs::threads_use_low_power_enabled() &&
1660 StaticPrefs::
1661 threads_lower_mainthread_priority_in_background_enabled()) {
1662 SetMainThreadQoSPriority(nsIThread::QOS_PRIORITY_NORMAL);
1665 // Send a high priority announcement first. If this fails, SendShutdown
1666 // will also fail.
1667 Unused << SendShutdownConfirmedHP();
1668 // Send the definite message with normal priority.
1669 if (SendShutdown()) {
1670 MaybeLogBlockShutdownDiagnostics(
1671 this, "ShutDownProcess: Sent shutdown message.", __FILE__,
1672 __LINE__);
1673 mShutdownPending = true;
1674 // We start the kill timer only after we asked our process to
1675 // shutdown.
1676 StartForceKillTimer();
1677 result = true;
1678 } else {
1679 MaybeLogBlockShutdownDiagnostics(
1680 this, "ShutDownProcess: !!! Send shutdown message failed! !!!",
1681 __FILE__, __LINE__);
1683 } else {
1684 MaybeLogBlockShutdownDiagnostics(
1685 this, "ShutDownProcess: !!! !CanSend !!!", __FILE__, __LINE__);
1687 } else {
1688 MaybeLogBlockShutdownDiagnostics(
1689 this, "ShutDownProcess: Shutdown already pending.", __FILE__,
1690 __LINE__);
1692 result = true;
1694 // If call was not successful, the channel must have been broken
1695 // somehow, and we will clean up the error in ActorDestroy.
1696 return result;
1699 using mozilla::dom::quota::QuotaManagerService;
1701 if (QuotaManagerService* qms = QuotaManagerService::GetOrCreate()) {
1702 qms->AbortOperationsForProcess(mChildID);
1705 if (aMethod == CLOSE_CHANNEL) {
1706 if (!mCalledClose) {
1707 MaybeLogBlockShutdownDiagnostics(
1708 this, "ShutDownProcess: Closing channel.", __FILE__, __LINE__);
1709 // Close() can only be called once: It kicks off the destruction sequence.
1710 mCalledClose = true;
1711 Close();
1713 result = true;
1716 // A ContentParent object might not get freed until after XPCOM shutdown has
1717 // shut down the cycle collector. But by then it's too late to release any
1718 // CC'ed objects, so we need to null them out here, while we still can. See
1719 // bug 899761.
1720 ShutDownMessageManager();
1721 return result;
1724 mozilla::ipc::IPCResult ContentParent::RecvNotifyShutdownSuccess() {
1725 if (!mShutdownPending) {
1726 return IPC_FAIL(this, "RecvNotifyShutdownSuccess without mShutdownPending");
1729 mIsNotifiedShutdownSuccess = true;
1731 return IPC_OK();
1734 mozilla::ipc::IPCResult ContentParent::RecvFinishShutdown() {
1735 if (!mShutdownPending) {
1736 return IPC_FAIL(this, "RecvFinishShutdown without mShutdownPending");
1739 // At this point, we already called ShutDownProcess once with
1740 // SEND_SHUTDOWN_MESSAGE. To actually close the channel, we call
1741 // ShutDownProcess again with CLOSE_CHANNEL.
1742 if (mCalledClose) {
1743 MaybeLogBlockShutdownDiagnostics(
1744 this, "RecvFinishShutdown: Channel already closed.", __FILE__,
1745 __LINE__);
1748 ShutDownProcess(CLOSE_CHANNEL);
1749 return IPC_OK();
1752 void ContentParent::ShutDownMessageManager() {
1753 if (!mMessageManager) {
1754 return;
1757 mMessageManager->SetOsPid(-1);
1758 mMessageManager->Disconnect();
1759 mMessageManager = nullptr;
1762 void ContentParent::AddToPool(nsTArray<ContentParent*>& aPool) {
1763 MOZ_DIAGNOSTIC_ASSERT(!mIsInPool);
1764 AssertAlive();
1765 MOZ_DIAGNOSTIC_ASSERT(!mCalledKillHard);
1766 aPool.AppendElement(this);
1767 mIsInPool = true;
1770 void ContentParent::RemoveFromPool(nsTArray<ContentParent*>& aPool) {
1771 MOZ_DIAGNOSTIC_ASSERT(mIsInPool);
1772 aPool.RemoveElement(this);
1773 mIsInPool = false;
1776 void ContentParent::AssertNotInPool() {
1777 MOZ_RELEASE_ASSERT(!mIsInPool);
1779 MOZ_RELEASE_ASSERT(!sBrowserContentParents ||
1780 !sBrowserContentParents->Contains(mRemoteType) ||
1781 !sBrowserContentParents->Get(mRemoteType)->Contains(this));
1783 for (const auto& group : mGroups) {
1784 MOZ_RELEASE_ASSERT(group->GetHostProcess(mRemoteType) != this,
1785 "still a host process for one of our groups?");
1789 void ContentParent::AssertAlive() {
1790 MOZ_DIAGNOSTIC_ASSERT(!mIsSignaledImpendingShutdown);
1791 MOZ_DIAGNOSTIC_ASSERT(!IsDead());
1794 void ContentParent::RemoveFromList() {
1795 if (!mIsInPool) {
1796 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1797 AssertNotInPool();
1798 #endif
1799 return;
1802 // Ensure that this BrowsingContextGroup is no longer used to host new
1803 // documents from any associated BrowsingContextGroups. It may become a host
1804 // again in the future, if it is restored to the pool.
1805 for (const auto& group : mGroups) {
1806 group->RemoveHostProcess(this);
1809 if (sBrowserContentParents) {
1810 if (auto entry = sBrowserContentParents->Lookup(mRemoteType)) {
1811 const auto& contentParents = entry.Data();
1812 RemoveFromPool(*contentParents);
1813 if (contentParents->IsEmpty()) {
1814 entry.Remove();
1817 if (sBrowserContentParents->IsEmpty()) {
1818 delete sBrowserContentParents;
1819 sBrowserContentParents = nullptr;
1824 void ContentParent::MarkAsDead() {
1825 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
1826 ("Marking ContentProcess %p as dead", this));
1827 MOZ_DIAGNOSTIC_ASSERT(!sInProcessSelector);
1828 RemoveFromList();
1830 // Flag shutdown has started for us to our threadsafe handle.
1832 // Depending on how we get here, the lock might or might not be set.
1833 RecursiveMutexAutoLock lock(mThreadsafeHandle->mMutex);
1835 mThreadsafeHandle->mShutdownStarted = true;
1838 // Prevent this process from being re-used.
1839 PreallocatedProcessManager::Erase(this);
1841 #if defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_PROFILE_GENERATE)
1842 if (IsAlive()) {
1843 // We're intentionally killing the content process at this point to ensure
1844 // that we never have a "dead" content process sitting around and occupying
1845 // an Android Service.
1847 // The exception is in MOZ_PROFILE_GENERATE builds where we must allow the
1848 // process to shutdown cleanly so that profile data can be dumped. This is
1849 // okay as we will not reach our process limit during the profile run.
1850 nsCOMPtr<nsIEventTarget> launcherThread(GetIPCLauncher());
1851 MOZ_ASSERT(launcherThread);
1853 auto procType = java::GeckoProcessType::CONTENT();
1854 auto selector =
1855 java::GeckoProcessManager::Selector::New(procType, OtherPid());
1857 launcherThread->Dispatch(NS_NewRunnableFunction(
1858 "ContentParent::MarkAsDead",
1859 [selector =
1860 java::GeckoProcessManager::Selector::GlobalRef(selector)]() {
1861 java::GeckoProcessManager::ShutdownProcess(selector);
1862 }));
1864 #endif
1866 mLifecycleState = LifecycleState::DEAD;
1869 void ContentParent::ProcessingError(Result aCode, const char* aReason) {
1870 if (MsgDropped == aCode) {
1871 return;
1873 // Other errors are big deals.
1874 #ifndef FUZZING
1875 KillHard(aReason);
1876 #endif
1877 if (CanSend()) {
1878 GetIPCChannel()->InduceConnectionError();
1882 void ContentParent::ActorDestroy(ActorDestroyReason why) {
1883 #ifdef FUZZING_SNAPSHOT
1884 MOZ_FUZZING_IPC_DROP_PEER("ContentParent::ActorDestroy");
1885 #endif
1887 // Gather process lifetime telemetry.
1888 if (StringBeginsWith(mRemoteType, WEB_REMOTE_TYPE) ||
1889 mRemoteType == FILE_REMOTE_TYPE || mRemoteType == EXTENSION_REMOTE_TYPE) {
1890 TimeDuration runtime = TimeStamp::Now() - mActivateTS;
1891 Telemetry::Accumulate(Telemetry::PROCESS_LIFETIME,
1892 uint64_t(runtime.ToSeconds()));
1895 if (mSendShutdownTimer) {
1896 mSendShutdownTimer->Cancel();
1897 mSendShutdownTimer = nullptr;
1899 if (mForceKillTimer) {
1900 mForceKillTimer->Cancel();
1901 mForceKillTimer = nullptr;
1904 // Signal shutdown completion regardless of error state, so we can
1905 // finish waiting in the xpcom-shutdown/profile-before-change observer.
1906 RemoveShutdownBlockers();
1908 if (mHangMonitorActor) {
1909 ProcessHangMonitor::RemoveProcess(mHangMonitorActor);
1910 mHangMonitorActor = nullptr;
1913 RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get();
1914 if (fss) {
1915 fss->Forget(ChildID());
1918 if (why == NormalShutdown && !mCalledClose) {
1919 // If we shut down normally but haven't called Close, assume somebody
1920 // else called Close on us. In that case, we still need to call
1921 // ShutDownProcess below to perform other necessary clean up.
1922 mCalledClose = true;
1925 // Make sure we always clean up.
1926 ShutDownProcess(CLOSE_CHANNEL);
1928 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
1929 if (obs) {
1930 size_t length = ArrayLength(sObserverTopics);
1931 for (size_t i = 0; i < length; ++i) {
1932 obs->RemoveObserver(static_cast<nsIObserver*>(this), sObserverTopics[i]);
1936 // remove the global remote preferences observers
1937 Preferences::RemoveObserver(this, "");
1938 gfxVars::RemoveReceiver(this);
1940 if (GPUProcessManager* gpu = GPUProcessManager::Get()) {
1941 // Note: the manager could have shutdown already.
1942 gpu->RemoveListener(this);
1945 RecvRemoveGeolocationListener();
1947 // Destroy our JSProcessActors, and reject any pending queries.
1948 JSActorDidDestroy();
1950 if (obs) {
1951 RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
1953 props->SetPropertyAsUint64(u"childID"_ns, mChildID);
1955 if (AbnormalShutdown == why) {
1956 Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT, "content"_ns,
1959 props->SetPropertyAsBool(u"abnormal"_ns, true);
1961 nsAutoString dumpID;
1962 // There's a window in which child processes can crash
1963 // after IPC is established, but before a crash reporter
1964 // is created.
1965 if (mCrashReporter) {
1966 // if mCreatedPairedMinidumps is true, we've already generated
1967 // parent/child dumps for desktop crashes.
1968 if (!mCreatedPairedMinidumps) {
1969 #if defined(XP_MACOSX)
1970 RefPtr<nsAvailableMemoryWatcherBase> memWatcher;
1971 memWatcher = nsAvailableMemoryWatcherBase::GetSingleton();
1972 memWatcher->AddChildAnnotations(mCrashReporter);
1973 #endif
1975 mCrashReporter->GenerateCrashReport(OtherPid());
1978 if (mCrashReporter->HasMinidump()) {
1979 dumpID = mCrashReporter->MinidumpID();
1981 } else {
1982 HandleOrphanedMinidump(&dumpID);
1985 if (!dumpID.IsEmpty()) {
1986 props->SetPropertyAsAString(u"dumpID"_ns, dumpID);
1989 nsAutoString cpId;
1990 cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
1991 obs->NotifyObservers((nsIPropertyBag2*)props, "ipc:content-shutdown",
1992 cpId.get());
1995 // Remove any and all idle listeners.
1996 if (mIdleListeners.Length() > 0) {
1997 nsCOMPtr<nsIUserIdleService> idleService =
1998 do_GetService("@mozilla.org/widget/useridleservice;1");
1999 if (idleService) {
2000 RefPtr<ParentIdleListener> listener;
2001 for (const auto& lentry : mIdleListeners) {
2002 listener = static_cast<ParentIdleListener*>(lentry.get());
2003 idleService->RemoveIdleObserver(listener, listener->mTime);
2006 mIdleListeners.Clear();
2009 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
2010 ("destroying Subprocess in ActorDestroy: ContentParent %p "
2011 "mSubprocess %p handle %" PRIuPTR,
2012 this, mSubprocess,
2013 mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
2014 // FIXME (bug 1520997): does this really need an additional dispatch?
2015 if (GetCurrentSerialEventTarget()) {
2016 GetCurrentSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
2017 "DelayedDeleteSubprocessRunnable", [subprocess = mSubprocess] {
2018 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2019 ("destroyed Subprocess in ActorDestroy: Subprocess %p handle "
2020 "%" PRIuPTR,
2021 subprocess,
2022 subprocess ? (uintptr_t)subprocess->GetChildProcessHandle()
2023 : -1));
2024 subprocess->Destroy();
2025 }));
2027 mSubprocess = nullptr;
2029 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
2030 if (cpm) {
2031 cpm->RemoveContentProcess(this->ChildID());
2034 if (mDriverCrashGuard) {
2035 mDriverCrashGuard->NotifyCrashed();
2038 // Unregister all the BlobURLs registered by the ContentChild.
2039 for (uint32_t i = 0; i < mBlobURLs.Length(); ++i) {
2040 BlobURLProtocolHandler::RemoveDataEntry(mBlobURLs[i]);
2043 mBlobURLs.Clear();
2045 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2046 AssertNotInPool();
2047 #endif
2049 // As this process is going away, ensure that every BrowsingContext hosted by
2050 // it has been detached, and every BrowsingContextGroup has been fully
2051 // unsubscribed.
2052 BrowsingContext::DiscardFromContentParent(this);
2054 const nsTHashSet<RefPtr<BrowsingContextGroup>> groups = std::move(mGroups);
2055 for (const auto& group : groups) {
2056 group->Unsubscribe(this);
2058 MOZ_DIAGNOSTIC_ASSERT(mGroups.IsEmpty());
2060 mPendingLoadStates.Clear();
2063 UniqueContentParentKeepAlive ContentParent::TryAddKeepAlive(
2064 uint64_t aBrowserId) {
2065 return UniqueContentParentKeepAliveFromThreadsafe(
2066 mThreadsafeHandle->TryAddKeepAlive(aBrowserId));
2069 UniqueContentParentKeepAlive ContentParent::AddKeepAlive(uint64_t aBrowserId) {
2070 UniqueContentParentKeepAlive keepAlive = TryAddKeepAlive(aBrowserId);
2071 MOZ_DIAGNOSTIC_ASSERT(keepAlive, "ContentParent is already dead");
2072 return keepAlive;
2075 void ContentParent::RemoveKeepAlive(uint64_t aBrowserId) {
2076 AssertIsOnMainThread();
2079 RecursiveMutexAutoLock lock(mThreadsafeHandle->mMutex);
2080 auto entry = mThreadsafeHandle->mKeepAlivesPerBrowserId.Lookup(aBrowserId);
2081 MOZ_RELEASE_ASSERT(entry, "No KeepAlive for this BrowserId");
2082 if (!--entry.Data()) {
2083 entry.Remove();
2087 MaybeBeginShutDown();
2090 bool ContentParent::MaybeBeginShutDown(bool aIgnoreKeepAlivePref) {
2091 AssertIsOnMainThread();
2094 RecursiveMutexAutoLock lock(mThreadsafeHandle->mMutex);
2095 // If we still have keepalives or are still launching, we're not shutting
2096 // down. Return.
2097 if (IsLaunching() ||
2098 !mThreadsafeHandle->mKeepAlivesPerBrowserId.IsEmpty()) {
2099 return false;
2102 // If we're not in main process shutdown, we might want to keep some content
2103 // processes alive for performance reasons (e.g. test runs and privileged
2104 // content process for some about: pages). We don't want to alter behavior
2105 // if the pref is not set, so default to 0.
2106 if (!aIgnoreKeepAlivePref && mIsInPool &&
2107 !AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
2108 auto* contentParents = sBrowserContentParents->Get(mRemoteType);
2109 MOZ_RELEASE_ASSERT(
2110 contentParents,
2111 "mIsInPool, yet no entry for mRemoteType in sBrowserContentParents?");
2113 nsAutoCString keepAlivePref("dom.ipc.keepProcessesAlive.");
2114 if (StringBeginsWith(mRemoteType, FISSION_WEB_REMOTE_TYPE) &&
2115 xpc::IsInAutomation()) {
2116 keepAlivePref.Append(FISSION_WEB_REMOTE_TYPE);
2117 keepAlivePref.AppendLiteral(".perOrigin");
2118 } else {
2119 keepAlivePref.Append(mRemoteType);
2122 int32_t processesToKeepAlive = 0;
2123 if (NS_SUCCEEDED(Preferences::GetInt(keepAlivePref.get(),
2124 &processesToKeepAlive)) &&
2125 contentParents->Length() <=
2126 static_cast<size_t>(processesToKeepAlive)) {
2127 // We're keeping this process alive even though there are no keepalives
2128 // for it due to the keepalive pref.
2129 return false;
2133 // We're not keeping this process alive, begin shutdown.
2134 mThreadsafeHandle->mShutdownStarted = true;
2137 MarkAsDead();
2138 SignalImpendingShutdownToContentJS();
2140 if (ManagedPBrowserParent().Count() > 0) {
2141 // We still have PBrowser instances which have not been shut down.
2142 // Wait for them to be destroyed before we follow-through and shut down this
2143 // process, but start a shutdown timer to kill them if this takes too long.
2144 StartSendShutdownTimer();
2145 } else {
2146 // All tabs are dead, we can fully begin shutting down.
2147 AsyncSendShutDownMessage();
2149 return true;
2152 void ContentParent::StartSendShutdownTimer() {
2153 if (mSendShutdownTimer || !CanSend()) {
2154 return;
2157 uint32_t timeoutSecs = StaticPrefs::dom_ipc_tabs_shutdownTimeoutSecs();
2158 if (timeoutSecs > 0) {
2159 NS_NewTimerWithFuncCallback(getter_AddRefs(mSendShutdownTimer),
2160 ContentParent::SendShutdownTimerCallback, this,
2161 timeoutSecs * 1000, nsITimer::TYPE_ONE_SHOT,
2162 "dom::ContentParent::StartSendShutdownTimer");
2163 MOZ_ASSERT(mSendShutdownTimer);
2167 void ContentParent::StartForceKillTimer() {
2168 if (mForceKillTimer || !CanSend()) {
2169 return;
2172 uint32_t timeoutSecs = StaticPrefs::dom_ipc_tabs_shutdownTimeoutSecs();
2173 if (timeoutSecs > 0) {
2174 NS_NewTimerWithFuncCallback(getter_AddRefs(mForceKillTimer),
2175 ContentParent::ForceKillTimerCallback, this,
2176 timeoutSecs * 1000, nsITimer::TYPE_ONE_SHOT,
2177 "dom::ContentParent::StartForceKillTimer");
2178 MOZ_ASSERT(mForceKillTimer);
2182 TestShellParent* ContentParent::CreateTestShell() {
2183 RefPtr<TestShellParent> actor = new TestShellParent();
2184 if (!SendPTestShellConstructor(actor)) {
2185 return nullptr;
2187 return actor;
2190 bool ContentParent::DestroyTestShell(TestShellParent* aTestShell) {
2191 return PTestShellParent::Send__delete__(aTestShell);
2194 TestShellParent* ContentParent::GetTestShellSingleton() {
2195 PTestShellParent* p = LoneManagedOrNullAsserts(ManagedPTestShellParent());
2196 return static_cast<TestShellParent*>(p);
2199 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
2200 // Append the sandbox command line parameters that are not static. i.e.,
2201 // parameters that can be different for different child processes.
2202 void ContentParent::AppendDynamicSandboxParams(
2203 std::vector<std::string>& aArgs) {
2204 // For file content processes
2205 if (GetRemoteType() == FILE_REMOTE_TYPE) {
2206 MacSandboxInfo::AppendFileAccessParam(aArgs, true);
2210 // Generate the static sandbox command line parameters and store
2211 // them in the provided params vector to be used each time a new
2212 // content process is launched.
2213 static void CacheSandboxParams(std::vector<std::string>& aCachedParams) {
2214 // This must only be called once and we should
2215 // be starting with an empty list of parameters.
2216 MOZ_ASSERT(aCachedParams.empty());
2218 MacSandboxInfo info;
2219 info.type = MacSandboxType_Content;
2220 info.level = GetEffectiveContentSandboxLevel();
2222 // Sandbox logging
2223 if (Preferences::GetBool("security.sandbox.logging.enabled") ||
2224 PR_GetEnv("MOZ_SANDBOX_LOGGING")) {
2225 info.shouldLog = true;
2228 // Audio access
2229 if (!StaticPrefs::media_cubeb_sandbox()) {
2230 info.hasAudio = true;
2233 // Window server access. If the disconnect-windowserver pref is not
2234 // "true" or out-of-process WebGL is not enabled, allow window server
2235 // access in the sandbox policy.
2236 if (!Preferences::GetBool(
2237 "security.sandbox.content.mac.disconnect-windowserver") ||
2238 !Preferences::GetBool("webgl.out-of-process")) {
2239 info.hasWindowServer = true;
2242 // .app path (normalized)
2243 nsAutoCString appPath;
2244 if (!nsMacUtilsImpl::GetAppPath(appPath)) {
2245 MOZ_CRASH("Failed to get app dir paths");
2247 info.appPath = appPath.get();
2249 // TESTING_READ_PATH1
2250 nsAutoCString testingReadPath1;
2251 Preferences::GetCString("security.sandbox.content.mac.testing_read_path1",
2252 testingReadPath1);
2253 if (!testingReadPath1.IsEmpty()) {
2254 info.testingReadPath1 = testingReadPath1.get();
2257 // TESTING_READ_PATH2
2258 nsAutoCString testingReadPath2;
2259 Preferences::GetCString("security.sandbox.content.mac.testing_read_path2",
2260 testingReadPath2);
2261 if (!testingReadPath2.IsEmpty()) {
2262 info.testingReadPath2 = testingReadPath2.get();
2265 // TESTING_READ_PATH3, TESTING_READ_PATH4. In non-packaged builds,
2266 // these are used to whitelist the repo dir and object dir respectively.
2267 nsresult rv;
2268 if (!mozilla::IsPackagedBuild()) {
2269 // Repo dir
2270 nsCOMPtr<nsIFile> repoDir;
2271 rv = nsMacUtilsImpl::GetRepoDir(getter_AddRefs(repoDir));
2272 if (NS_FAILED(rv)) {
2273 MOZ_CRASH("Failed to get path to repo dir");
2275 nsCString repoDirPath;
2276 Unused << repoDir->GetNativePath(repoDirPath);
2277 info.testingReadPath3 = repoDirPath.get();
2279 // Object dir
2280 nsCOMPtr<nsIFile> objDir;
2281 rv = nsMacUtilsImpl::GetObjDir(getter_AddRefs(objDir));
2282 if (NS_FAILED(rv)) {
2283 MOZ_CRASH("Failed to get path to build object dir");
2285 nsCString objDirPath;
2286 Unused << objDir->GetNativePath(objDirPath);
2287 info.testingReadPath4 = objDirPath.get();
2290 // DEBUG_WRITE_DIR
2291 # ifdef DEBUG
2292 // For bloat/leak logging or when a content process dies intentionally
2293 // (|NoteIntentionalCrash|) for tests, it wants to log that it did this.
2294 // Allow writing to this location.
2295 nsAutoCString bloatLogDirPath;
2296 if (NS_SUCCEEDED(nsMacUtilsImpl::GetBloatLogDir(bloatLogDirPath))) {
2297 info.debugWriteDir = bloatLogDirPath.get();
2299 # endif // DEBUG
2301 info.AppendAsParams(aCachedParams);
2304 // Append sandboxing command line parameters.
2305 void ContentParent::AppendSandboxParams(std::vector<std::string>& aArgs) {
2306 MOZ_ASSERT(sMacSandboxParams != nullptr);
2308 // An empty sMacSandboxParams indicates this is the
2309 // first invocation and we don't have cached params yet.
2310 if (sMacSandboxParams->empty()) {
2311 CacheSandboxParams(*sMacSandboxParams);
2312 MOZ_ASSERT(!sMacSandboxParams->empty());
2315 // Append cached arguments.
2316 aArgs.insert(aArgs.end(), sMacSandboxParams->begin(),
2317 sMacSandboxParams->end());
2319 // Append remaining arguments.
2320 AppendDynamicSandboxParams(aArgs);
2322 #endif // XP_MACOSX && MOZ_SANDBOX
2324 bool ContentParent::BeginSubprocessLaunch(ProcessPriority aPriority) {
2325 AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess", OTHER);
2327 // Ensure we will not rush through our shutdown phases while launching.
2328 // LaunchSubprocessReject will remove them in case of failure,
2329 // otherwise ActorDestroy will take care.
2330 AddShutdownBlockers();
2332 if (!ContentProcessManager::GetSingleton()) {
2333 MOZ_ASSERT(false, "Unable to acquire ContentProcessManager singleton!");
2334 return false;
2337 std::vector<std::string> extraArgs;
2338 geckoargs::sChildID.Put(mChildID, extraArgs);
2339 geckoargs::sIsForBrowser.Put(IsForBrowser(), extraArgs);
2340 geckoargs::sNotForBrowser.Put(!IsForBrowser(), extraArgs);
2342 // Prefs information is passed via anonymous shared memory to avoid bloating
2343 // the command line.
2345 // Instantiate the pref serializer. It will be cleaned up in
2346 // `LaunchSubprocessReject`/`LaunchSubprocessResolve`.
2347 mPrefSerializer = MakeUnique<mozilla::ipc::SharedPreferenceSerializer>();
2348 if (!mPrefSerializer->SerializeToSharedMemory(GeckoProcessType_Content,
2349 GetRemoteType())) {
2350 NS_WARNING("SharedPreferenceSerializer::SerializeToSharedMemory failed");
2351 MarkAsDead();
2352 return false;
2354 mPrefSerializer->AddSharedPrefCmdLineArgs(*mSubprocess, extraArgs);
2356 // The JS engine does some computation during the initialization which can be
2357 // shared across processes. We add command line arguments to pass a file
2358 // handle and its content length, to minimize the startup time of content
2359 // processes.
2360 ::mozilla::ipc::ExportSharedJSInit(*mSubprocess, extraArgs);
2362 // Register ContentParent as an observer for changes to any pref
2363 // whose prefix matches the empty string, i.e. all of them. The
2364 // observation starts here in order to capture pref updates that
2365 // happen during async launch.
2366 Preferences::AddStrongObserver(this, "");
2368 if (gSafeMode) {
2369 geckoargs::sSafeMode.Put(extraArgs);
2372 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
2373 if (IsContentSandboxEnabled()) {
2374 AppendSandboxParams(extraArgs);
2375 mSubprocess->DisableOSActivityMode();
2377 #endif
2379 nsCString parentBuildID(mozilla::PlatformBuildID());
2380 geckoargs::sParentBuildID.Put(parentBuildID.get(), extraArgs);
2382 #ifdef MOZ_WIDGET_GTK
2383 // This is X11-only pending a solution for WebGL in Wayland mode.
2384 if (StaticPrefs::dom_ipc_avoid_gtk() && widget::GdkIsX11Display()) {
2385 mSubprocess->SetEnv("MOZ_HEADLESS", "1");
2387 #endif
2389 mLaunchYieldTS = TimeStamp::Now();
2390 return mSubprocess->AsyncLaunch(std::move(extraArgs));
2393 void ContentParent::LaunchSubprocessReject() {
2394 NS_WARNING("failed to launch child in the parent");
2395 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
2396 ("failed to launch child in the parent"));
2397 // Now that communication with the child is complete, we can cleanup
2398 // the preference serializer.
2399 mPrefSerializer = nullptr;
2400 if (mIsAPreallocBlocker) {
2401 PreallocatedProcessManager::RemoveBlocker(mRemoteType, this);
2402 mIsAPreallocBlocker = false;
2404 MarkAsDead();
2405 RemoveShutdownBlockers();
2408 bool ContentParent::LaunchSubprocessResolve(bool aIsSync,
2409 ProcessPriority aPriority) {
2410 AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess::resolve", OTHER);
2412 if (mLaunchResolved) {
2413 // We've already been called, return.
2414 MOZ_ASSERT(sCreatedFirstContentProcess);
2415 MOZ_ASSERT(!mPrefSerializer);
2416 MOZ_ASSERT(mLifecycleState != LifecycleState::LAUNCHING);
2417 return mLaunchResolvedOk;
2419 mLaunchResolved = true;
2421 // Now that communication with the child is complete, we can cleanup
2422 // the preference serializer.
2423 mPrefSerializer = nullptr;
2425 const auto launchResumeTS = TimeStamp::Now();
2426 if (profiler_thread_is_being_profiled_for_markers()) {
2427 nsPrintfCString marker("Process start%s for %u",
2428 mIsAPreallocBlocker ? " (immediate)" : "",
2429 (unsigned int)ChildID());
2430 PROFILER_MARKER_TEXT(
2431 mIsAPreallocBlocker ? ProfilerString8View("Process Immediate Launch")
2432 : ProfilerString8View("Process Launch"),
2433 DOM, MarkerTiming::Interval(mLaunchTS, launchResumeTS), marker);
2436 if (!sCreatedFirstContentProcess) {
2437 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
2438 obs->NotifyObservers(nullptr, "ipc:first-content-process-created", nullptr);
2439 sCreatedFirstContentProcess = true;
2442 mSubprocess->TakeInitialEndpoint().Bind(this);
2444 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
2445 if (!cpm) {
2446 NS_WARNING("immediately shutting-down caused by our shutdown");
2447 ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
2448 return false;
2450 cpm->AddContentProcess(this);
2452 #ifdef MOZ_CODE_COVERAGE
2453 Unused << SendShareCodeCoverageMutex(
2454 CodeCoverageHandler::Get()->GetMutexHandle());
2455 #endif
2457 // We must be in the LAUNCHING state still. If we've somehow already been
2458 // marked as DEAD, fail the process launch, and immediately begin tearing down
2459 // the content process.
2460 if (IsDead()) {
2461 NS_WARNING("immediately shutting-down already-dead process");
2462 ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
2463 return false;
2465 MOZ_ASSERT(mLifecycleState == LifecycleState::LAUNCHING);
2466 mLifecycleState = LifecycleState::ALIVE;
2468 if (!InitInternal(aPriority)) {
2469 NS_WARNING("failed to initialize child in the parent");
2470 // We've already called Open() by this point, so we need to close the
2471 // channel to avoid leaking the process.
2472 ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
2473 return false;
2476 mHangMonitorActor = ProcessHangMonitor::AddProcess(this);
2478 // Set a reply timeout for CPOWs.
2479 SetReplyTimeoutMs(StaticPrefs::dom_ipc_cpow_timeout());
2481 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
2482 if (obs) {
2483 nsAutoString cpId;
2484 cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
2485 obs->NotifyObservers(static_cast<nsIObserver*>(this),
2486 "ipc:content-initializing", cpId.get());
2489 Init();
2491 mLifecycleState = LifecycleState::INITIALIZED;
2493 if (aIsSync) {
2494 Telemetry::AccumulateTimeDelta(Telemetry::CONTENT_PROCESS_SYNC_LAUNCH_MS,
2495 mLaunchTS);
2496 } else {
2497 Telemetry::AccumulateTimeDelta(Telemetry::CONTENT_PROCESS_LAUNCH_TOTAL_MS,
2498 mLaunchTS);
2500 Telemetry::Accumulate(
2501 Telemetry::CONTENT_PROCESS_LAUNCH_MAINTHREAD_MS,
2502 static_cast<uint32_t>(
2503 ((mLaunchYieldTS - mLaunchTS) + (TimeStamp::Now() - launchResumeTS))
2504 .ToMilliseconds()));
2507 mLaunchResolvedOk = true;
2508 return true;
2511 ContentParent::ContentParent(const nsACString& aRemoteType)
2512 : mSubprocess(nullptr),
2513 mLaunchTS(TimeStamp::Now()),
2514 mLaunchYieldTS(mLaunchTS),
2515 mActivateTS(mLaunchTS),
2516 mIsAPreallocBlocker(false),
2517 mRemoteType(aRemoteType),
2518 mChildID(gContentChildID++),
2519 mGeolocationWatchID(-1),
2520 mThreadsafeHandle(
2521 new ThreadsafeContentParentHandle(this, mChildID, mRemoteType)),
2522 mLifecycleState(LifecycleState::LAUNCHING),
2523 mIsForBrowser(!mRemoteType.IsEmpty()),
2524 mCalledClose(false),
2525 mCalledKillHard(false),
2526 mCreatedPairedMinidumps(false),
2527 mShutdownPending(false),
2528 mLaunchResolved(false),
2529 mLaunchResolvedOk(false),
2530 mIsRemoteInputEventQueueEnabled(false),
2531 mIsInputPriorityEventEnabled(false),
2532 mIsInPool(false),
2533 mGMPCreated(false),
2534 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2535 mBlockShutdownCalled(false),
2536 #endif
2537 mHangMonitorActor(nullptr) {
2538 mRemoteTypeIsolationPrincipal =
2539 CreateRemoteTypeIsolationPrincipal(aRemoteType);
2541 // Insert ourselves into the global linked list of ContentParent objects.
2542 if (!sContentParents) {
2543 sContentParents = new LinkedList<ContentParent>();
2545 sContentParents->insertBack(this);
2547 mMessageManager = nsFrameMessageManager::NewProcessMessageManager(true);
2549 #if defined(XP_WIN)
2550 // Request Windows message deferral behavior on our side of the PContent
2551 // channel. Generally only applies to the situation where we get caught in
2552 // a deadlock with the plugin process when sending CPOWs.
2553 GetIPCChannel()->SetChannelFlags(
2554 MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
2555 #endif
2557 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2558 bool isFile = mRemoteType == FILE_REMOTE_TYPE;
2559 mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content, isFile);
2560 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
2561 ("CreateSubprocess: ContentParent %p mSubprocess %p handle %" PRIuPTR,
2562 this, mSubprocess,
2563 mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
2566 ContentParent::~ContentParent() {
2567 if (mSendShutdownTimer) {
2568 mSendShutdownTimer->Cancel();
2570 if (mForceKillTimer) {
2571 mForceKillTimer->Cancel();
2574 AssertIsOnMainThread();
2576 // Clear the weak reference from the threadsafe handle back to this actor.
2577 mThreadsafeHandle->mWeakActor = nullptr;
2579 if (mIsAPreallocBlocker) {
2580 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2581 ("Removing blocker on ContentProcess destruction"));
2582 PreallocatedProcessManager::RemoveBlocker(mRemoteType, this);
2583 mIsAPreallocBlocker = false;
2586 // We should be removed from all these lists in ActorDestroy.
2587 AssertNotInPool();
2589 // Normally mSubprocess is destroyed in ActorDestroy, but that won't
2590 // happen if the process wasn't launched or if it failed to launch.
2591 if (mSubprocess) {
2592 MOZ_LOG(
2593 ContentParent::GetLog(), LogLevel::Verbose,
2594 ("DestroySubprocess: ContentParent %p mSubprocess %p handle %" PRIuPTR,
2595 this, mSubprocess,
2596 mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
2597 mSubprocess->Destroy();
2601 bool ContentParent::InitInternal(ProcessPriority aInitialPriority) {
2602 // We can't access the locale service after shutdown has started. Since we
2603 // can't init the process without it, and since we're going to be canceling
2604 // whatever load attempt that initiated this process creation anyway, just
2605 // bail out now if shutdown has already started.
2606 if (PastShutdownPhase(ShutdownPhase::XPCOMShutdown)) {
2607 return false;
2610 XPCOMInitData xpcomInit;
2612 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2613 ("ContentParent::InitInternal: %p", (void*)this));
2614 nsCOMPtr<nsIIOService> io(do_GetIOService());
2615 MOZ_ASSERT(io, "No IO service?");
2616 DebugOnly<nsresult> rv = io->GetOffline(&xpcomInit.isOffline());
2617 MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting offline?");
2619 rv = io->GetConnectivity(&xpcomInit.isConnected());
2620 MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting connectivity?");
2622 xpcomInit.captivePortalState() = nsICaptivePortalService::UNKNOWN;
2623 nsCOMPtr<nsICaptivePortalService> cps =
2624 do_GetService(NS_CAPTIVEPORTAL_CONTRACTID);
2625 if (cps) {
2626 cps->GetState(&xpcomInit.captivePortalState());
2629 if (StaticPrefs::fission_processProfileName()) {
2630 nsCOMPtr<nsIToolkitProfileService> profileSvc =
2631 do_GetService(NS_PROFILESERVICE_CONTRACTID);
2632 if (profileSvc) {
2633 nsCOMPtr<nsIToolkitProfile> currentProfile;
2634 nsresult rv =
2635 profileSvc->GetCurrentProfile(getter_AddRefs(currentProfile));
2636 if (NS_SUCCEEDED(rv) && currentProfile) {
2637 currentProfile->GetName(mProfile);
2642 nsIBidiKeyboard* bidi = nsContentUtils::GetBidiKeyboard();
2644 xpcomInit.isLangRTL() = false;
2645 xpcomInit.haveBidiKeyboards() = false;
2646 if (bidi) {
2647 bidi->IsLangRTL(&xpcomInit.isLangRTL());
2648 bidi->GetHaveBidiKeyboards(&xpcomInit.haveBidiKeyboards());
2651 RefPtr<mozSpellChecker> spellChecker(mozSpellChecker::Create());
2652 MOZ_ASSERT(spellChecker, "No spell checker?");
2654 spellChecker->GetDictionaryList(&xpcomInit.dictionaries());
2656 LocaleService::GetInstance()->GetAppLocalesAsBCP47(xpcomInit.appLocales());
2657 LocaleService::GetInstance()->GetRequestedLocales(
2658 xpcomInit.requestedLocales());
2660 L10nRegistry::GetParentProcessFileSourceDescriptors(
2661 xpcomInit.l10nFileSources());
2663 nsCOMPtr<nsIClipboard> clipboard(
2664 do_GetService("@mozilla.org/widget/clipboard;1"));
2665 MOZ_ASSERT(clipboard, "No clipboard?");
2666 MOZ_ASSERT(
2667 clipboard->IsClipboardTypeSupported(nsIClipboard::kGlobalClipboard),
2668 "We should always support the global clipboard.");
2670 xpcomInit.clipboardCaps().supportsSelectionClipboard() =
2671 clipboard->IsClipboardTypeSupported(nsIClipboard::kSelectionClipboard);
2673 xpcomInit.clipboardCaps().supportsFindClipboard() =
2674 clipboard->IsClipboardTypeSupported(nsIClipboard::kFindClipboard);
2676 xpcomInit.clipboardCaps().supportsSelectionCache() =
2677 clipboard->IsClipboardTypeSupported(nsIClipboard::kSelectionCache);
2679 // Let's copy the domain policy from the parent to the child (if it's active).
2680 StructuredCloneData initialData;
2681 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
2682 if (ssm) {
2683 ssm->CloneDomainPolicy(&xpcomInit.domainPolicy());
2685 if (ParentProcessMessageManager* mm =
2686 nsFrameMessageManager::sParentProcessManager) {
2687 AutoJSAPI jsapi;
2688 if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) {
2689 MOZ_CRASH();
2691 JS::Rooted<JS::Value> init(jsapi.cx());
2692 // We'll crash on failure, so use a IgnoredErrorResult (which also
2693 // auto-suppresses exceptions).
2694 IgnoredErrorResult rv;
2695 mm->GetInitialProcessData(jsapi.cx(), &init, rv);
2696 if (NS_WARN_IF(rv.Failed())) {
2697 MOZ_CRASH();
2700 initialData.Write(jsapi.cx(), init, rv);
2701 if (NS_WARN_IF(rv.Failed())) {
2702 MOZ_CRASH();
2706 // This is only implemented (returns a non-empty list) by MacOSX and Linux
2707 // at present.
2708 SystemFontList fontList;
2709 gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList);
2711 const FullLookAndFeel& lnf = *RemoteLookAndFeel::ExtractData();
2713 // If the shared fontlist is in use, collect its shmem block handles to pass
2714 // to the child.
2715 nsTArray<SharedMemoryHandle> sharedFontListBlocks;
2716 gfxPlatformFontList::PlatformFontList()->ShareFontListToProcess(
2717 &sharedFontListBlocks, OtherPid());
2719 // Content processes have no permission to access profile directory, so we
2720 // send the file URL instead.
2721 auto* sheetCache = GlobalStyleSheetCache::Singleton();
2722 if (StyleSheet* ucs = sheetCache->GetUserContentSheet()) {
2723 xpcomInit.userContentSheetURL() = ucs->GetSheetURI();
2724 } else {
2725 xpcomInit.userContentSheetURL() = nullptr;
2728 // 1. Build ContentDeviceData first, as it may affect some gfxVars.
2729 gfxPlatform::GetPlatform()->BuildContentDeviceData(
2730 &xpcomInit.contentDeviceData());
2731 // 2. Gather non-default gfxVars.
2732 xpcomInit.gfxNonDefaultVarUpdates() = gfxVars::FetchNonDefaultVars();
2733 // 3. Start listening for gfxVars updates, to notify content process later on.
2734 gfxVars::AddReceiver(this);
2736 nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
2737 if (gfxInfo) {
2738 GfxInfoBase* gfxInfoRaw = static_cast<GfxInfoBase*>(gfxInfo.get());
2739 xpcomInit.gfxFeatureStatus() = gfxInfoRaw->GetAllFeatures();
2742 // Send the dynamic scalar definitions to the new process.
2743 TelemetryIPC::GetDynamicScalarDefinitions(xpcomInit.dynamicScalarDefs());
2745 for (auto const& [location, supported] : sCodecsSupported) {
2746 Unused << SendUpdateMediaCodecsSupported(location, supported);
2749 // Must send screen info before send initialData
2750 ScreenManager& screenManager = ScreenManager::GetSingleton();
2751 screenManager.CopyScreensToRemote(this);
2753 // Send the UA sheet shared memory buffer and the address it is mapped at.
2754 Maybe<SharedMemoryHandle> sharedUASheetHandle;
2755 uintptr_t sharedUASheetAddress = sheetCache->GetSharedMemoryAddress();
2757 if (SharedMemoryHandle handle = sheetCache->CloneHandle()) {
2758 sharedUASheetHandle.emplace(std::move(handle));
2759 } else {
2760 sharedUASheetAddress = 0;
2763 bool isReadyForBackgroundProcessing = false;
2764 #if defined(XP_WIN)
2765 RefPtr<DllServices> dllSvc(DllServices::Get());
2766 isReadyForBackgroundProcessing = dllSvc->IsReadyForBackgroundProcessing();
2767 #endif
2769 xpcomInit.perfStatsMask() = PerfStats::GetCollectionMask();
2771 nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
2772 dns->GetTrrDomain(xpcomInit.trrDomain());
2774 nsIDNSService::ResolverMode mode;
2775 dns->GetCurrentTrrMode(&mode);
2776 xpcomInit.trrMode() = mode;
2777 xpcomInit.trrModeFromPref() =
2778 static_cast<nsIDNSService::ResolverMode>(StaticPrefs::network_trr_mode());
2780 Unused << SendSetXPCOMProcessAttributes(
2781 xpcomInit, initialData, lnf, fontList, std::move(sharedUASheetHandle),
2782 sharedUASheetAddress, std::move(sharedFontListBlocks),
2783 isReadyForBackgroundProcessing);
2785 ipc::WritableSharedMap* sharedData =
2786 nsFrameMessageManager::sParentProcessManager->SharedData();
2787 sharedData->Flush();
2788 sharedData->SendTo(this);
2790 nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
2791 nsChromeRegistryChrome* chromeRegistry =
2792 static_cast<nsChromeRegistryChrome*>(registrySvc.get());
2793 chromeRegistry->SendRegisteredChrome(this);
2795 nsCOMPtr<nsIStringBundleService> stringBundleService =
2796 components::StringBundle::Service();
2797 stringBundleService->SendContentBundles(this);
2799 if (gAppData) {
2800 nsCString version(gAppData->version);
2801 nsCString buildID(gAppData->buildID);
2802 nsCString name(gAppData->name);
2803 nsCString UAName(gAppData->UAName);
2804 nsCString ID(gAppData->ID);
2805 nsCString vendor(gAppData->vendor);
2806 nsCString sourceURL(gAppData->sourceURL);
2807 nsCString updateURL(gAppData->updateURL);
2809 // Sending all information to content process.
2810 Unused << SendAppInfo(version, buildID, name, UAName, ID, vendor, sourceURL,
2811 updateURL);
2814 // Send the child its remote type. On Mac, this needs to be sent prior
2815 // to the message we send to enable the Sandbox (SendStartProcessSandbox)
2816 // because different remote types require different sandbox privileges.
2818 Unused << SendRemoteType(mRemoteType, mProfile);
2820 if (mRemoteType != PREALLOC_REMOTE_TYPE) {
2821 StartRemoteWorkerService();
2824 ScriptPreloader::InitContentChild(*this);
2826 // Initialize the message manager (and load delayed scripts) now that we
2827 // have established communications with the child.
2828 mMessageManager->InitWithCallback(this);
2829 mMessageManager->SetOsPid(Pid());
2831 // Set the subprocess's priority. We do this early on because we're likely
2832 // /lowering/ the process's CPU and memory priority, which it has inherited
2833 // from this process.
2835 // This call can cause us to send IPC messages to the child process, so it
2836 // must come after the Open() call above.
2837 ProcessPriorityManager::SetProcessPriority(this, aInitialPriority);
2839 // NB: internally, this will send an IPC message to the child
2840 // process to get it to create the CompositorBridgeChild. This
2841 // message goes through the regular IPC queue for this
2842 // channel, so delivery will happen-before any other messages
2843 // we send. The CompositorBridgeChild must be created before any
2844 // PBrowsers are created, because they rely on the Compositor
2845 // already being around. (Creation is async, so can't happen
2846 // on demand.)
2847 GPUProcessManager* gpm = GPUProcessManager::Get();
2849 Endpoint<PCompositorManagerChild> compositor;
2850 Endpoint<PImageBridgeChild> imageBridge;
2851 Endpoint<PVRManagerChild> vrBridge;
2852 Endpoint<PRemoteDecoderManagerChild> videoManager;
2853 AutoTArray<uint32_t, 3> namespaces;
2855 if (!gpm->CreateContentBridges(OtherPid(), &compositor, &imageBridge,
2856 &vrBridge, &videoManager, mChildID,
2857 &namespaces)) {
2858 // This can fail if we've already started shutting down the compositor
2859 // thread. See Bug 1562763 comment 8.
2860 MOZ_ASSERT(AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown));
2861 return false;
2864 Unused << SendInitRendering(std::move(compositor), std::move(imageBridge),
2865 std::move(vrBridge), std::move(videoManager),
2866 namespaces);
2868 gpm->AddListener(this);
2870 nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
2871 if (sheetService) {
2872 // This looks like a lot of work, but in a normal browser session we just
2873 // send two loads.
2875 // The URIs of the Gecko and Servo sheets should be the same, so it
2876 // shouldn't matter which we look at.
2878 for (StyleSheet* sheet : *sheetService->AgentStyleSheets()) {
2879 Unused << SendLoadAndRegisterSheet(sheet->GetSheetURI(),
2880 nsIStyleSheetService::AGENT_SHEET);
2883 for (StyleSheet* sheet : *sheetService->UserStyleSheets()) {
2884 Unused << SendLoadAndRegisterSheet(sheet->GetSheetURI(),
2885 nsIStyleSheetService::USER_SHEET);
2888 for (StyleSheet* sheet : *sheetService->AuthorStyleSheets()) {
2889 Unused << SendLoadAndRegisterSheet(sheet->GetSheetURI(),
2890 nsIStyleSheetService::AUTHOR_SHEET);
2894 #ifdef MOZ_SANDBOX
2895 bool shouldSandbox = true;
2896 Maybe<FileDescriptor> brokerFd;
2897 // XXX: Checking the pref here makes it possible to enable/disable sandboxing
2898 // during an active session. Currently the pref is only used for testing
2899 // purpose. If the decision is made to permanently rely on the pref, this
2900 // should be changed so that it is required to restart firefox for the change
2901 // of value to take effect. Always send SetProcessSandbox message on macOS.
2902 # if !defined(XP_MACOSX)
2903 shouldSandbox = IsContentSandboxEnabled();
2904 # endif
2906 # ifdef XP_LINUX
2907 if (shouldSandbox) {
2908 MOZ_ASSERT(!mSandboxBroker);
2909 bool isFileProcess = mRemoteType == FILE_REMOTE_TYPE;
2910 UniquePtr<SandboxBroker::Policy> policy =
2911 sSandboxBrokerPolicyFactory->GetContentPolicy(Pid(), isFileProcess);
2912 if (policy) {
2913 brokerFd = Some(FileDescriptor());
2914 mSandboxBroker =
2915 SandboxBroker::Create(std::move(policy), Pid(), brokerFd.ref());
2916 if (!mSandboxBroker) {
2917 KillHard("SandboxBroker::Create failed");
2918 return false;
2920 MOZ_ASSERT(brokerFd.ref().IsValid());
2923 # endif
2924 if (shouldSandbox && !SendSetProcessSandbox(brokerFd)) {
2925 KillHard("SandboxInitFailed");
2927 #endif
2929 // Ensure that the default set of permissions are avaliable in the content
2930 // process before we try to load any URIs in it.
2932 // NOTE: All default permissions has to be transmitted to the child process
2933 // before the blob urls in the for loop below (See Bug 1738713 comment 12).
2934 EnsurePermissionsByKey(""_ns, ""_ns);
2937 nsTArray<BlobURLRegistrationData> registrations;
2938 BlobURLProtocolHandler::ForEachBlobURL([&](BlobImpl* aBlobImpl,
2939 nsIPrincipal* aPrincipal,
2940 const nsCString& aPartitionKey,
2941 const nsACString& aURI,
2942 bool aRevoked) {
2943 // We send all moz-extension Blob URL's to all content processes
2944 // because content scripts mean that a moz-extension can live in any
2945 // process. Same thing for system principal Blob URLs. Content Blob
2946 // URL's are sent for content principals on-demand by
2947 // AboutToLoadHttpDocumentForChild and RemoteWorkerManager.
2948 if (!BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal)) {
2949 return true;
2952 IPCBlob ipcBlob;
2953 nsresult rv = IPCBlobUtils::Serialize(aBlobImpl, ipcBlob);
2954 if (NS_WARN_IF(NS_FAILED(rv))) {
2955 return false;
2958 registrations.AppendElement(
2959 BlobURLRegistrationData(nsCString(aURI), ipcBlob, aPrincipal,
2960 nsCString(aPartitionKey), aRevoked));
2962 rv = TransmitPermissionsForPrincipal(aPrincipal);
2963 Unused << NS_WARN_IF(NS_FAILED(rv));
2964 return true;
2967 if (!registrations.IsEmpty()) {
2968 Unused << SendInitBlobURLs(registrations);
2972 // Send down { Parent, Window }ActorOptions at startup to content process.
2973 RefPtr<JSActorService> actorSvc = JSActorService::GetSingleton();
2974 if (actorSvc) {
2975 nsTArray<JSProcessActorInfo> contentInfos;
2976 actorSvc->GetJSProcessActorInfos(contentInfos);
2978 nsTArray<JSWindowActorInfo> windowInfos;
2979 actorSvc->GetJSWindowActorInfos(windowInfos);
2981 Unused << SendInitJSActorInfos(contentInfos, windowInfos);
2984 // Begin subscribing to any BrowsingContextGroups which were hosted by this
2985 // process before it finished launching.
2986 for (const auto& group : mGroups) {
2987 group->Subscribe(this);
2990 MaybeEnableRemoteInputEventQueue();
2992 return true;
2995 bool ContentParent::IsAlive() const {
2996 return mLifecycleState == LifecycleState::ALIVE ||
2997 mLifecycleState == LifecycleState::INITIALIZED;
3000 bool ContentParent::IsInitialized() const {
3001 return mLifecycleState == LifecycleState::INITIALIZED;
3004 int32_t ContentParent::Pid() const {
3005 if (!mSubprocess) {
3006 return -1;
3008 auto pid = mSubprocess->GetChildProcessId();
3009 if (pid == 0) {
3010 return -1;
3012 return ReleaseAssertedCast<int32_t>(pid);
3015 void ContentParent::OnCompositorUnexpectedShutdown() {
3016 GPUProcessManager* gpm = GPUProcessManager::Get();
3018 Endpoint<PCompositorManagerChild> compositor;
3019 Endpoint<PImageBridgeChild> imageBridge;
3020 Endpoint<PVRManagerChild> vrBridge;
3021 Endpoint<PRemoteDecoderManagerChild> videoManager;
3022 AutoTArray<uint32_t, 3> namespaces;
3024 if (!gpm->CreateContentBridges(OtherPid(), &compositor, &imageBridge,
3025 &vrBridge, &videoManager, mChildID,
3026 &namespaces)) {
3027 MOZ_ASSERT(AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown));
3028 return;
3031 Unused << SendReinitRendering(std::move(compositor), std::move(imageBridge),
3032 std::move(vrBridge), std::move(videoManager),
3033 namespaces);
3036 void ContentParent::OnCompositorDeviceReset() {
3037 Unused << SendReinitRenderingForDeviceReset();
3040 void ContentParent::MaybeEnableRemoteInputEventQueue() {
3041 MOZ_ASSERT(!mIsRemoteInputEventQueueEnabled);
3042 if (!IsInputEventQueueSupported()) {
3043 return;
3045 mIsRemoteInputEventQueueEnabled = true;
3046 Unused << SendSetInputEventQueueEnabled();
3047 SetInputPriorityEventEnabled(true);
3050 void ContentParent::SetInputPriorityEventEnabled(bool aEnabled) {
3051 if (!IsInputEventQueueSupported() || !mIsRemoteInputEventQueueEnabled ||
3052 mIsInputPriorityEventEnabled == aEnabled) {
3053 return;
3055 mIsInputPriorityEventEnabled = aEnabled;
3056 // Send IPC messages to flush the pending events in the input event queue and
3057 // the normal event queue. See PContent.ipdl for more details.
3058 Unused << SendSuspendInputEventQueue();
3059 Unused << SendFlushInputEventQueue();
3060 Unused << SendResumeInputEventQueue();
3063 /*static*/
3064 bool ContentParent::IsInputEventQueueSupported() {
3065 static bool sSupported = false;
3066 static bool sInitialized = false;
3067 if (!sInitialized) {
3068 MOZ_ASSERT(Preferences::IsServiceAvailable());
3069 sSupported = Preferences::GetBool("input_event_queue.supported", false);
3070 sInitialized = true;
3072 return sSupported;
3075 void ContentParent::OnVarChanged(const GfxVarUpdate& aVar) {
3076 if (!CanSend()) {
3077 return;
3079 Unused << SendVarUpdate(aVar);
3082 mozilla::ipc::IPCResult ContentParent::RecvSetClipboard(
3083 const IPCTransferable& aTransferable, const int32_t& aWhichClipboard,
3084 const MaybeDiscarded<WindowContext>& aRequestingWindowContext) {
3085 // aRequestingPrincipal is allowed to be nullptr here.
3087 if (!ValidatePrincipal(aTransferable.dataPrincipal(),
3088 {ValidatePrincipalOptions::AllowNullPtr,
3089 ValidatePrincipalOptions::AllowExpanded,
3090 ValidatePrincipalOptions::AllowSystem})) {
3091 LogAndAssertFailedPrincipalValidationInfo(aTransferable.dataPrincipal(),
3092 __func__);
3095 nsresult rv;
3096 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
3097 NS_ENSURE_SUCCESS(rv, IPC_OK());
3099 nsCOMPtr<nsITransferable> trans =
3100 do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
3101 NS_ENSURE_SUCCESS(rv, IPC_OK());
3102 trans->Init(nullptr);
3104 rv = nsContentUtils::IPCTransferableToTransferable(
3105 aTransferable, true /* aAddDataFlavor */, trans,
3106 true /* aFilterUnknownFlavors */);
3107 NS_ENSURE_SUCCESS(rv, IPC_OK());
3109 // OK if this is null
3110 RefPtr<WindowGlobalParent> window;
3111 if (!aRequestingWindowContext.IsDiscarded()) {
3112 window = aRequestingWindowContext.get_canonical();
3114 clipboard->SetData(trans, nullptr, aWhichClipboard, window);
3115 return IPC_OK();
3118 namespace {
3120 static Result<nsCOMPtr<nsITransferable>, nsresult> CreateTransferable(
3121 const nsTArray<nsCString>& aTypes) {
3122 nsresult rv;
3123 nsCOMPtr<nsITransferable> trans =
3124 do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
3125 if (NS_FAILED(rv)) {
3126 return Err(rv);
3129 MOZ_TRY(trans->Init(nullptr));
3130 // The private flag is only used to prevent the data from being cached to the
3131 // disk. The flag is not exported to the IPCDataTransfer object.
3132 // The flag is set because we are not sure whether the clipboard data is used
3133 // in a private browsing context. The transferable is only used in this scope,
3134 // so the cache would not reduce memory consumption anyway.
3135 trans->SetIsPrivateData(true);
3136 // Fill out flavors for transferable
3137 for (uint32_t t = 0; t < aTypes.Length(); t++) {
3138 MOZ_TRY(trans->AddDataFlavor(aTypes[t].get()));
3141 return std::move(trans);
3144 } // anonymous namespace
3146 mozilla::ipc::IPCResult ContentParent::RecvGetClipboard(
3147 nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
3148 const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
3149 IPCTransferableDataOrError* aTransferableDataOrError) {
3150 nsresult rv;
3151 // We expect content processes to always pass a non-null window so Content
3152 // Analysis can analyze it. (if Content Analysis is active)
3153 // There may be some cases when a window is closing, etc., in
3154 // which case returning no clipboard content should not be a problem.
3155 if (aRequestingWindowContext.IsDiscarded()) {
3156 NS_WARNING(
3157 "discarded window passed to RecvGetClipboard(); returning no clipboard "
3158 "content");
3159 *aTransferableDataOrError = NS_ERROR_FAILURE;
3160 return IPC_OK();
3162 if (aRequestingWindowContext.IsNull()) {
3163 return IPC_FAIL(this, "passed null window to RecvGetClipboard()");
3165 RefPtr<WindowGlobalParent> window = aRequestingWindowContext.get_canonical();
3166 // Retrieve clipboard
3167 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
3168 if (NS_FAILED(rv)) {
3169 *aTransferableDataOrError = rv;
3170 return IPC_OK();
3173 // Create transferable
3174 auto result = CreateTransferable(aTypes);
3175 if (result.isErr()) {
3176 *aTransferableDataOrError = result.unwrapErr();
3177 return IPC_OK();
3180 // Get data from clipboard
3181 nsCOMPtr<nsITransferable> trans = result.unwrap();
3182 rv = clipboard->GetData(trans, aWhichClipboard, window);
3183 if (NS_FAILED(rv)) {
3184 *aTransferableDataOrError = rv;
3185 return IPC_OK();
3188 IPCTransferableData transferableData;
3189 nsContentUtils::TransferableToIPCTransferableData(
3190 trans, &transferableData, true /* aInSyncMessage */, this);
3191 *aTransferableDataOrError = std::move(transferableData);
3192 return IPC_OK();
3195 mozilla::ipc::IPCResult ContentParent::RecvEmptyClipboard(
3196 const int32_t& aWhichClipboard) {
3197 nsresult rv;
3198 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
3199 NS_ENSURE_SUCCESS(rv, IPC_OK());
3201 clipboard->EmptyClipboard(aWhichClipboard);
3203 return IPC_OK();
3206 mozilla::ipc::IPCResult ContentParent::RecvClipboardHasType(
3207 nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
3208 bool* aHasType) {
3209 nsresult rv;
3210 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
3211 NS_ENSURE_SUCCESS(rv, IPC_OK());
3213 clipboard->HasDataMatchingFlavors(aTypes, aWhichClipboard, aHasType);
3215 return IPC_OK();
3218 namespace {
3220 static Result<ClipboardReadRequest, nsresult> CreateClipboardReadRequest(
3221 ContentParent& aContentParent,
3222 nsIClipboardDataSnapshot& aClipboardDataSnapshot) {
3223 nsTArray<nsCString> flavors;
3224 nsresult rv = aClipboardDataSnapshot.GetFlavorList(flavors);
3225 if (NS_FAILED(rv)) {
3226 return Err(rv);
3229 auto requestParent = MakeNotNull<RefPtr<ClipboardReadRequestParent>>(
3230 &aContentParent, &aClipboardDataSnapshot);
3232 // Open a remote endpoint for our PClipboardReadRequest actor.
3233 ManagedEndpoint<PClipboardReadRequestChild> childEndpoint =
3234 aContentParent.OpenPClipboardReadRequestEndpoint(requestParent);
3235 if (NS_WARN_IF(!childEndpoint.IsValid())) {
3236 return Err(NS_ERROR_FAILURE);
3239 return ClipboardReadRequest(std::move(childEndpoint), std::move(flavors));
3242 class ClipboardGetCallback final : public nsIClipboardGetDataSnapshotCallback {
3243 public:
3244 ClipboardGetCallback(
3245 ContentParent* aContentParent,
3246 ContentParent::GetClipboardDataSnapshotResolver&& aResolver)
3247 : mContentParent(aContentParent), mResolver(std::move(aResolver)) {}
3249 // This object will never be held by a cycle-collected object, so it doesn't
3250 // need to be cycle-collected despite holding alive cycle-collected objects.
3251 NS_DECL_ISUPPORTS
3253 // nsIClipboardGetDataSnapshotCallback
3254 NS_IMETHOD OnSuccess(
3255 nsIClipboardDataSnapshot* aClipboardDataSnapshot) override {
3256 MOZ_ASSERT(mContentParent);
3257 MOZ_ASSERT(aClipboardDataSnapshot);
3259 auto result =
3260 CreateClipboardReadRequest(*mContentParent, *aClipboardDataSnapshot);
3261 if (result.isErr()) {
3262 return OnError(result.unwrapErr());
3265 mResolver(result.unwrap());
3266 return NS_OK;
3269 NS_IMETHOD OnError(nsresult aResult) override {
3270 mResolver(aResult);
3271 return NS_OK;
3274 protected:
3275 ~ClipboardGetCallback() = default;
3277 RefPtr<ContentParent> mContentParent;
3278 ContentParent::GetClipboardDataSnapshotResolver mResolver;
3281 NS_IMPL_ISUPPORTS(ClipboardGetCallback, nsIClipboardGetDataSnapshotCallback)
3283 } // namespace
3285 mozilla::ipc::IPCResult ContentParent::RecvGetClipboardDataSnapshot(
3286 nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
3287 const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
3288 mozilla::NotNull<nsIPrincipal*> aRequestingPrincipal,
3289 GetClipboardDataSnapshotResolver&& aResolver) {
3290 if (!ValidatePrincipal(aRequestingPrincipal,
3291 {ValidatePrincipalOptions::AllowSystem,
3292 ValidatePrincipalOptions::AllowExpanded})) {
3293 LogAndAssertFailedPrincipalValidationInfo(aRequestingPrincipal, __func__);
3296 // If the requesting context has been discarded, cancel the paste.
3297 if (aRequestingWindowContext.IsDiscarded()) {
3298 aResolver(NS_ERROR_NOT_AVAILABLE);
3299 return IPC_OK();
3302 RefPtr<WindowGlobalParent> requestingWindow =
3303 aRequestingWindowContext.get_canonical();
3304 if (requestingWindow && requestingWindow->GetContentParent() != this) {
3305 return IPC_FAIL(
3306 this, "attempt to paste into WindowContext loaded in another process");
3309 nsresult rv;
3310 // Retrieve clipboard
3311 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
3312 if (NS_FAILED(rv)) {
3313 aResolver(rv);
3314 return IPC_OK();
3317 auto callback = MakeRefPtr<ClipboardGetCallback>(this, std::move(aResolver));
3318 rv = clipboard->GetDataSnapshot(aTypes, aWhichClipboard, requestingWindow,
3319 aRequestingPrincipal, callback);
3320 if (NS_FAILED(rv)) {
3321 callback->OnError(rv);
3322 return IPC_OK();
3325 return IPC_OK();
3328 mozilla::ipc::IPCResult ContentParent::RecvGetClipboardDataSnapshotSync(
3329 nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
3330 const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
3331 ClipboardReadRequestOrError* aRequestOrError) {
3332 // If the requesting context has been discarded, cancel the paste.
3333 if (aRequestingWindowContext.IsDiscarded()) {
3334 *aRequestOrError = NS_ERROR_FAILURE;
3335 return IPC_OK();
3338 RefPtr<WindowGlobalParent> requestingWindow =
3339 aRequestingWindowContext.get_canonical();
3340 if (requestingWindow && requestingWindow->GetContentParent() != this) {
3341 return IPC_FAIL(
3342 this, "attempt to paste into WindowContext loaded in another process");
3345 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID));
3346 if (!clipboard) {
3347 *aRequestOrError = NS_ERROR_FAILURE;
3348 return IPC_OK();
3351 nsCOMPtr<nsIClipboardDataSnapshot> clipboardDataSnapshot;
3352 nsresult rv =
3353 clipboard->GetDataSnapshotSync(aTypes, aWhichClipboard, requestingWindow,
3354 getter_AddRefs(clipboardDataSnapshot));
3355 if (NS_FAILED(rv)) {
3356 *aRequestOrError = rv;
3357 return IPC_OK();
3360 auto result = CreateClipboardReadRequest(*this, *clipboardDataSnapshot);
3361 if (result.isErr()) {
3362 *aRequestOrError = result.unwrapErr();
3363 return IPC_OK();
3366 *aRequestOrError = result.unwrap();
3367 return IPC_OK();
3370 already_AddRefed<PClipboardWriteRequestParent>
3371 ContentParent::AllocPClipboardWriteRequestParent(
3372 const int32_t& aClipboardType,
3373 const MaybeDiscarded<WindowContext>& aSettingWindowContext) {
3374 WindowContext* settingWindowContext = nullptr;
3375 if (!aSettingWindowContext.IsDiscarded()) {
3376 settingWindowContext = aSettingWindowContext.get();
3378 RefPtr<ClipboardWriteRequestParent> request =
3379 MakeAndAddRef<ClipboardWriteRequestParent>(this);
3380 request->Init(aClipboardType, settingWindowContext);
3381 return request.forget();
3384 mozilla::ipc::IPCResult ContentParent::RecvGetIconForExtension(
3385 const nsACString& aFileExt, const uint32_t& aIconSize,
3386 nsTArray<uint8_t>* bits) {
3387 #ifdef MOZ_WIDGET_ANDROID
3388 NS_ASSERTION(AndroidBridge::Bridge() != nullptr,
3389 "AndroidBridge is not available");
3390 if (AndroidBridge::Bridge() == nullptr) {
3391 // Do not fail - just no icon will be shown
3392 return IPC_OK();
3395 bits->AppendElements(aIconSize * aIconSize * 4);
3397 AndroidBridge::Bridge()->GetIconForExtension(aFileExt, aIconSize,
3398 bits->Elements());
3399 #endif
3400 return IPC_OK();
3403 mozilla::ipc::IPCResult ContentParent::RecvFirstIdle() {
3404 // When the ContentChild goes idle, it sends us a FirstIdle message
3405 // which we use as a good time to signal the PreallocatedProcessManager
3406 // that it can start allocating processes from now on.
3407 if (mIsAPreallocBlocker) {
3408 MOZ_LOG(
3409 ContentParent::GetLog(), LogLevel::Verbose,
3410 ("RecvFirstIdle %p: Removing Blocker for %s", this, mRemoteType.get()));
3411 PreallocatedProcessManager::RemoveBlocker(mRemoteType, this);
3412 mIsAPreallocBlocker = false;
3414 return IPC_OK();
3417 already_AddRefed<nsDocShellLoadState> ContentParent::TakePendingLoadStateForId(
3418 uint64_t aLoadIdentifier) {
3419 return mPendingLoadStates.Extract(aLoadIdentifier).valueOr(nullptr).forget();
3422 void ContentParent::StorePendingLoadState(nsDocShellLoadState* aLoadState) {
3423 MOZ_DIAGNOSTIC_ASSERT(
3424 !mPendingLoadStates.Contains(aLoadState->GetLoadIdentifier()),
3425 "The same nsDocShellLoadState was sent to the same content process "
3426 "twice? This will mess with cross-process tracking of loads");
3427 mPendingLoadStates.InsertOrUpdate(aLoadState->GetLoadIdentifier(),
3428 aLoadState);
3431 mozilla::ipc::IPCResult ContentParent::RecvCleanupPendingLoadState(
3432 uint64_t aLoadIdentifier) {
3433 mPendingLoadStates.Remove(aLoadIdentifier);
3434 return IPC_OK();
3437 // We want ContentParent to show up in CC logs for debugging purposes, but we
3438 // don't actually cycle collect it.
3439 NS_IMPL_CYCLE_COLLECTION_0(ContentParent)
3441 NS_IMPL_CYCLE_COLLECTING_ADDREF(ContentParent)
3442 NS_IMPL_CYCLE_COLLECTING_RELEASE(ContentParent)
3444 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ContentParent)
3445 NS_INTERFACE_MAP_ENTRY_CONCRETE(ContentParent)
3446 NS_INTERFACE_MAP_ENTRY(nsIDOMProcessParent)
3447 NS_INTERFACE_MAP_ENTRY(nsIObserver)
3448 NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionCallback)
3449 NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionErrorCallback)
3450 NS_INTERFACE_MAP_ENTRY(nsIAsyncShutdownBlocker)
3451 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
3452 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMProcessParent)
3453 NS_INTERFACE_MAP_END
3455 class RequestContentJSInterruptRunnable final : public Runnable {
3456 public:
3457 explicit RequestContentJSInterruptRunnable(PProcessHangMonitorParent* aActor)
3458 : Runnable("dom::RequestContentJSInterruptRunnable"),
3459 mHangMonitorActor(aActor) {}
3461 NS_IMETHOD Run() override {
3462 MOZ_ASSERT(mHangMonitorActor);
3463 Unused << mHangMonitorActor->SendRequestContentJSInterrupt();
3465 return NS_OK;
3468 private:
3469 // The end-of-life of ContentParent::mHangMonitorActor is bound to
3470 // ContentParent::ActorDestroy and then HangMonitorParent::Shutdown
3471 // dispatches a shutdown runnable to this queue and waits for it to be
3472 // executed. So the runnable needs not to care about keeping it alive,
3473 // as it is surely dispatched earlier than the
3474 // HangMonitorParent::ShutdownOnThread.
3475 RefPtr<PProcessHangMonitorParent> mHangMonitorActor;
3478 void ContentParent::SignalImpendingShutdownToContentJS() {
3479 if (!mIsSignaledImpendingShutdown &&
3480 !AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
3481 MaybeLogBlockShutdownDiagnostics(
3482 this, "BlockShutdown: NotifyImpendingShutdown.", __FILE__, __LINE__);
3483 NotifyImpendingShutdown();
3484 mIsSignaledImpendingShutdown = true;
3485 if (mHangMonitorActor &&
3486 StaticPrefs::dom_abort_script_on_child_shutdown()) {
3487 MaybeLogBlockShutdownDiagnostics(
3488 this, "BlockShutdown: RequestContentJSInterrupt.", __FILE__,
3489 __LINE__);
3490 RefPtr<RequestContentJSInterruptRunnable> r =
3491 new RequestContentJSInterruptRunnable(mHangMonitorActor);
3492 ProcessHangMonitor::Get()->Dispatch(r.forget());
3497 // Async shutdown blocker
3498 NS_IMETHODIMP
3499 ContentParent::BlockShutdown(nsIAsyncShutdownClient* aClient) {
3500 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
3501 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3502 mBlockShutdownCalled = true;
3503 #endif
3504 // Our real shutdown has not yet started. Just notify the impending
3505 // shutdown and eventually cancel content JS.
3506 SignalImpendingShutdownToContentJS();
3507 // This will make our process unusable for normal content, so we need to
3508 // ensure we won't get re-used by GetUsedBrowserProcess as we have not yet
3509 // done MarkAsDead.
3510 PreallocatedProcessManager::Erase(this);
3512 if (sQuitApplicationGrantedClient) {
3513 Unused << sQuitApplicationGrantedClient->RemoveBlocker(this);
3515 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3516 mBlockShutdownCalled = false;
3517 #endif
3518 return NS_OK;
3521 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3522 // We register two final shutdown blockers and both would call us, but if
3523 // things go well we will unregister both as (delayed) reaction to the first
3524 // call we get and thus never receive a second call. Thus we believe that we
3525 // will get called only once except for quit-application-granted, which is
3526 // handled above.
3527 MOZ_ASSERT(!mBlockShutdownCalled);
3528 mBlockShutdownCalled = true;
3529 #endif
3531 if (CanSend()) {
3532 MaybeLogBlockShutdownDiagnostics(this, "BlockShutdown: CanSend.", __FILE__,
3533 __LINE__);
3535 // Make sure that our process will get scheduled.
3536 ProcessPriorityManager::SetProcessPriority(this,
3537 PROCESS_PRIORITY_FOREGROUND);
3538 // The normal shutdown sequence is to send a shutdown message
3539 // to the child and then just wait for ActorDestroy which will
3540 // cleanup everything and remove our blockers.
3541 if (!ShutDownProcess(SEND_SHUTDOWN_MESSAGE)) {
3542 KillHard("Failed to send Shutdown message. Destroying the process...");
3543 return NS_OK;
3545 } else if (IsLaunching()) {
3546 MaybeLogBlockShutdownDiagnostics(
3547 this, "BlockShutdown: !CanSend && IsLaunching.", __FILE__, __LINE__);
3549 // If we get here while we are launching, we must wait for the child to
3550 // be able to react on our commands. Mark this process as dead. This
3551 // will make bail out LaunchSubprocessResolve and kick off the normal
3552 // shutdown sequence.
3553 MarkAsDead();
3554 } else {
3555 MOZ_ASSERT(IsDead());
3556 if (!IsDead()) {
3557 MaybeLogBlockShutdownDiagnostics(
3558 this, "BlockShutdown: !!! !CanSend && !IsLaunching && !IsDead !!!",
3559 __FILE__, __LINE__);
3560 } else {
3561 MaybeLogBlockShutdownDiagnostics(
3562 this, "BlockShutdown: !CanSend && !IsLaunching && IsDead.", __FILE__,
3563 __LINE__);
3565 // Nothing left we can do. We must assume that we race with an ongoing
3566 // process shutdown, such that we can expect our shutdown blockers to be
3567 // removed normally.
3570 return NS_OK;
3573 NS_IMETHODIMP
3574 ContentParent::GetName(nsAString& aName) {
3575 aName.AssignLiteral("ContentParent:");
3576 aName.AppendPrintf(" id=%p", this);
3577 return NS_OK;
3580 NS_IMETHODIMP
3581 ContentParent::GetState(nsIPropertyBag** aResult) {
3582 auto props = MakeRefPtr<nsHashPropertyBag>();
3583 props->SetPropertyAsACString(u"remoteTypePrefix"_ns,
3584 RemoteTypePrefix(mRemoteType));
3585 *aResult = props.forget().downcast<nsIWritablePropertyBag>().take();
3586 return NS_OK;
3589 static void InitShutdownClients() {
3590 if (!sXPCOMShutdownClient) {
3591 nsresult rv;
3592 nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdownService();
3593 if (!svc) {
3594 return;
3597 nsCOMPtr<nsIAsyncShutdownClient> client;
3598 // TODO: It seems as if getPhase from AsyncShutdown.sys.mjs does not check
3599 // if we are beyond our phase already. See bug 1762840.
3600 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMWillShutdown)) {
3601 rv = svc->GetXpcomWillShutdown(getter_AddRefs(client));
3602 if (NS_SUCCEEDED(rv)) {
3603 sXPCOMShutdownClient = client.forget();
3604 ClearOnShutdown(&sXPCOMShutdownClient);
3607 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
3608 rv = svc->GetProfileBeforeChange(getter_AddRefs(client));
3609 if (NS_SUCCEEDED(rv)) {
3610 sProfileBeforeChangeClient = client.forget();
3611 ClearOnShutdown(&sProfileBeforeChangeClient);
3614 // TODO: ShutdownPhase::AppShutdownConfirmed is not mapping to
3615 // QuitApplicationGranted, see bug 1762840 comment 4.
3616 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
3617 rv = svc->GetQuitApplicationGranted(getter_AddRefs(client));
3618 if (NS_SUCCEEDED(rv)) {
3619 sQuitApplicationGrantedClient = client.forget();
3620 ClearOnShutdown(&sQuitApplicationGrantedClient);
3626 void ContentParent::AddShutdownBlockers() {
3627 InitShutdownClients();
3628 MOZ_ASSERT(sXPCOMShutdownClient);
3629 MOZ_ASSERT(sProfileBeforeChangeClient);
3631 if (sXPCOMShutdownClient) {
3632 sXPCOMShutdownClient->AddBlocker(
3633 this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
3635 if (sProfileBeforeChangeClient) {
3636 sProfileBeforeChangeClient->AddBlocker(
3637 this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
3639 if (sQuitApplicationGrantedClient) {
3640 sQuitApplicationGrantedClient->AddBlocker(
3641 this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
3645 void ContentParent::RemoveShutdownBlockers() {
3646 MOZ_ASSERT(sXPCOMShutdownClient);
3647 MOZ_ASSERT(sProfileBeforeChangeClient);
3649 MaybeLogBlockShutdownDiagnostics(this, "RemoveShutdownBlockers", __FILE__,
3650 __LINE__);
3651 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3652 mBlockShutdownCalled = false;
3653 #endif
3655 if (sXPCOMShutdownClient) {
3656 Unused << sXPCOMShutdownClient->RemoveBlocker(this);
3658 if (sProfileBeforeChangeClient) {
3659 Unused << sProfileBeforeChangeClient->RemoveBlocker(this);
3661 if (sQuitApplicationGrantedClient) {
3662 Unused << sQuitApplicationGrantedClient->RemoveBlocker(this);
3666 NS_IMETHODIMP
3667 ContentParent::Observe(nsISupports* aSubject, const char* aTopic,
3668 const char16_t* aData) {
3669 if (IsDead() || !mSubprocess) {
3670 return NS_OK;
3673 if (!strcmp(aTopic, "nsPref:changed")) {
3674 // We know prefs are ASCII here.
3675 NS_LossyConvertUTF16toASCII strData(aData);
3677 Pref pref(strData, /* isLocked */ false,
3678 /* isSanitized */ false, Nothing(), Nothing());
3680 Preferences::GetPreference(&pref, GeckoProcessType_Content,
3681 GetRemoteType());
3683 // This check is a bit of a hack. We want to avoid sending excessive
3684 // preference updates to subprocesses for performance reasons, but we
3685 // currently don't have a great mechanism for doing so. (See Bug 1819714)
3686 // We're going to hijack the sanitization mechanism to accomplish our goal
3687 // but it imposes the following complications:
3688 // 1) It doesn't avoid sending anything to other (non-web-content)
3689 // subprocesses so we're not getting any perf gains there
3690 // 2) It confuses the subprocesses w.r.t. sanitization. The point of
3691 // sending a preference update of a sanitized preference is so that
3692 // content process knows when it's asked to resolve a sanitized
3693 // preference, and it can send telemetry and/or crash. With this
3694 // change, a sanitized pref that is created during the browser session
3695 // will not be sent to the content process, and therefore the content
3696 // process won't know it should telemetry/crash on access - it'll just
3697 // silently fail to resolve it. After browser restart, the sanitized
3698 // pref will be populated into the content process via the shared pref
3699 // map and _then_ if it is accessed, the content process will crash.
3700 // We're seeing good telemetry/crash rates right now, so we're okay with
3701 // this limitation.
3702 if (pref.isSanitized()) {
3703 return NS_OK;
3706 if (IsInitialized()) {
3707 MOZ_ASSERT(mQueuedPrefs.IsEmpty());
3708 if (!SendPreferenceUpdate(pref)) {
3709 return NS_ERROR_NOT_AVAILABLE;
3711 } else {
3712 MOZ_ASSERT(!IsDead());
3713 mQueuedPrefs.AppendElement(pref);
3716 return NS_OK;
3719 if (!IsAlive()) {
3720 return NS_OK;
3723 // listening for memory pressure event
3724 if (!strcmp(aTopic, "memory-pressure")) {
3725 Unused << SendFlushMemory(nsDependentString(aData));
3726 } else if (!strcmp(aTopic, "application-background")) {
3727 Unused << SendApplicationBackground();
3728 } else if (!strcmp(aTopic, "application-foreground")) {
3729 Unused << SendApplicationForeground();
3730 } else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC)) {
3731 NS_ConvertUTF16toUTF8 dataStr(aData);
3732 const char* offline = dataStr.get();
3733 if (!SendSetOffline(!strcmp(offline, "true"))) {
3734 return NS_ERROR_NOT_AVAILABLE;
3736 } else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC)) {
3737 if (!SendSetConnectivity(u"true"_ns.Equals(aData))) {
3738 return NS_ERROR_NOT_AVAILABLE;
3740 } else if (!strcmp(aTopic, NS_IPC_CAPTIVE_PORTAL_SET_STATE)) {
3741 nsCOMPtr<nsICaptivePortalService> cps = do_QueryInterface(aSubject);
3742 MOZ_ASSERT(cps, "Should QI to a captive portal service");
3743 if (!cps) {
3744 return NS_ERROR_FAILURE;
3746 int32_t state;
3747 cps->GetState(&state);
3748 if (!SendSetCaptivePortalState(state)) {
3749 return NS_ERROR_NOT_AVAILABLE;
3752 // listening for alert notifications
3753 else if (!strcmp(aTopic, "alertfinished") ||
3754 !strcmp(aTopic, "alertclickcallback") ||
3755 !strcmp(aTopic, "alertshow") ||
3756 !strcmp(aTopic, "alertdisablecallback") ||
3757 !strcmp(aTopic, "alertsettingscallback")) {
3758 if (!SendNotifyAlertsObserver(nsDependentCString(aTopic),
3759 nsDependentString(aData))) {
3760 return NS_ERROR_NOT_AVAILABLE;
3762 } else if (!strcmp(aTopic, "child-gc-request")) {
3763 Unused << SendGarbageCollect();
3764 } else if (!strcmp(aTopic, "child-cc-request")) {
3765 Unused << SendCycleCollect();
3766 } else if (!strcmp(aTopic, "child-mmu-request")) {
3767 Unused << SendMinimizeMemoryUsage();
3768 } else if (!strcmp(aTopic, "child-ghost-request")) {
3769 Unused << SendUnlinkGhosts();
3770 } else if (!strcmp(aTopic, "last-pb-context-exited")) {
3771 Unused << SendLastPrivateDocShellDestroyed();
3773 #ifdef ACCESSIBILITY
3774 else if (aData && !strcmp(aTopic, "a11y-init-or-shutdown")) {
3775 if (*aData == '1') {
3776 // Make sure accessibility is running in content process when
3777 // accessibility gets initiated in chrome process.
3778 Unused << SendActivateA11y();
3779 } else {
3780 // If possible, shut down accessibility in content process when
3781 // accessibility gets shutdown in chrome process.
3782 Unused << SendShutdownA11y();
3785 #endif
3786 else if (!strcmp(aTopic, "cacheservice:empty-cache")) {
3787 Unused << SendNotifyEmptyHTTPCache();
3788 } else if (!strcmp(aTopic, "intl:app-locales-changed")) {
3789 nsTArray<nsCString> appLocales;
3790 LocaleService::GetInstance()->GetAppLocalesAsBCP47(appLocales);
3791 Unused << SendUpdateAppLocales(appLocales);
3792 } else if (!strcmp(aTopic, "intl:requested-locales-changed")) {
3793 nsTArray<nsCString> requestedLocales;
3794 LocaleService::GetInstance()->GetRequestedLocales(requestedLocales);
3795 Unused << SendUpdateRequestedLocales(requestedLocales);
3796 } else if (!strcmp(aTopic, "cookie-changed") ||
3797 !strcmp(aTopic, "private-cookie-changed")) {
3798 MOZ_ASSERT(aSubject, "cookie changed notification must have subject.");
3799 nsCOMPtr<nsICookieNotification> notification = do_QueryInterface(aSubject);
3800 MOZ_ASSERT(notification,
3801 "cookie changed notification must have nsICookieNotification.");
3802 nsICookieNotification::Action action = notification->GetAction();
3804 PNeckoParent* neckoParent = LoneManagedOrNullAsserts(ManagedPNeckoParent());
3805 if (!neckoParent) {
3806 return NS_OK;
3808 PCookieServiceParent* csParent =
3809 LoneManagedOrNullAsserts(neckoParent->ManagedPCookieServiceParent());
3810 if (!csParent) {
3811 return NS_OK;
3813 auto* cs = static_cast<CookieServiceParent*>(csParent);
3814 if (action == nsICookieNotification::COOKIES_BATCH_DELETED) {
3815 nsCOMPtr<nsIArray> cookieList;
3816 DebugOnly<nsresult> rv =
3817 notification->GetBatchDeletedCookies(getter_AddRefs(cookieList));
3818 NS_ASSERTION(NS_SUCCEEDED(rv) && cookieList, "couldn't get cookie list");
3819 cs->RemoveBatchDeletedCookies(cookieList);
3820 return NS_OK;
3823 if (action == nsICookieNotification::ALL_COOKIES_CLEARED) {
3824 cs->RemoveAll();
3825 return NS_OK;
3828 // Do not push these cookie updates to the same process they originated
3829 // from.
3830 if (cs->ProcessingCookie()) {
3831 return NS_OK;
3834 nsCOMPtr<nsICookie> xpcCookie;
3835 DebugOnly<nsresult> rv = notification->GetCookie(getter_AddRefs(xpcCookie));
3836 NS_ASSERTION(NS_SUCCEEDED(rv) && xpcCookie, "couldn't get cookie");
3838 // only broadcast the cookie change to content processes that need it
3839 const Cookie& cookie = xpcCookie->AsCookie();
3841 // do not send cookie if content process does not have similar cookie
3842 if (!cs->ContentProcessHasCookie(cookie)) {
3843 return NS_OK;
3846 if (action == nsICookieNotification::COOKIE_DELETED) {
3847 cs->RemoveCookie(cookie);
3848 } else if (action == nsICookieNotification::COOKIE_ADDED ||
3849 action == nsICookieNotification::COOKIE_CHANGED) {
3850 cs->AddCookie(cookie);
3852 } else if (!strcmp(aTopic, NS_NETWORK_LINK_TYPE_TOPIC)) {
3853 UpdateNetworkLinkType();
3854 } else if (!strcmp(aTopic, "network:socket-process-crashed")) {
3855 Unused << SendSocketProcessCrashed();
3856 } else if (!strcmp(aTopic, DEFAULT_TIMEZONE_CHANGED_OBSERVER_TOPIC)) {
3857 Unused << SendSystemTimezoneChanged();
3858 } else if (!strcmp(aTopic, NS_NETWORK_TRR_MODE_CHANGED_TOPIC)) {
3859 nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
3860 nsIDNSService::ResolverMode mode;
3861 dns->GetCurrentTrrMode(&mode);
3862 Unused << SendSetTRRMode(mode, static_cast<nsIDNSService::ResolverMode>(
3863 StaticPrefs::network_trr_mode()));
3866 return NS_OK;
3869 void ContentParent::UpdateNetworkLinkType() {
3870 nsresult rv;
3871 nsCOMPtr<nsINetworkLinkService> nls =
3872 do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv);
3873 if (NS_FAILED(rv)) {
3874 return;
3877 uint32_t linkType = nsINetworkLinkService::LINK_TYPE_UNKNOWN;
3878 rv = nls->GetLinkType(&linkType);
3879 if (NS_FAILED(rv)) {
3880 return;
3883 Unused << SendNetworkLinkTypeChange(linkType);
3886 NS_IMETHODIMP
3887 ContentParent::GetInterface(const nsIID& aIID, void** aResult) {
3888 NS_ENSURE_ARG_POINTER(aResult);
3890 if (aIID.Equals(NS_GET_IID(nsIMessageSender))) {
3891 nsCOMPtr<nsIMessageSender> mm = GetMessageManager();
3892 mm.forget(aResult);
3893 return NS_OK;
3896 return NS_NOINTERFACE;
3899 mozilla::ipc::IPCResult ContentParent::RecvInitBackground(
3900 Endpoint<PBackgroundStarterParent>&& aEndpoint) {
3901 if (!BackgroundParent::AllocStarter(this, std::move(aEndpoint))) {
3902 NS_WARNING("BackgroundParent::Alloc failed");
3905 return IPC_OK();
3908 bool ContentParent::CanOpenBrowser(const IPCTabContext& aContext) {
3909 // (PopupIPCTabContext lets the child process prove that it has access to
3910 // the app it's trying to open.)
3911 // On e10s we also allow UnsafeTabContext to allow service workers to open
3912 // windows. This is enforced in MaybeInvalidTabContext.
3913 if (aContext.type() != IPCTabContext::TPopupIPCTabContext) {
3914 MOZ_CRASH_UNLESS_FUZZING(
3915 "Unexpected IPCTabContext type. Aborting AllocPBrowserParent.");
3916 return false;
3919 if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
3920 const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext();
3922 auto* opener = BrowserParent::GetFrom(popupContext.opener().AsParent());
3923 if (!opener) {
3924 MOZ_CRASH_UNLESS_FUZZING(
3925 "Got null opener from child; aborting AllocPBrowserParent.");
3926 return false;
3930 MaybeInvalidTabContext tc(aContext);
3931 if (!tc.IsValid()) {
3932 NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext. (%s) "
3933 "Aborting AllocPBrowserParent.",
3934 tc.GetInvalidReason())
3935 .get());
3936 return false;
3939 return true;
3942 static bool CloneIsLegal(ContentParent* aCp, CanonicalBrowsingContext& aSource,
3943 CanonicalBrowsingContext& aTarget) {
3944 // Source and target must be in the same BCG
3945 if (NS_WARN_IF(aSource.Group() != aTarget.Group())) {
3946 return false;
3948 // The source and target must be in different toplevel <browser>s
3949 if (NS_WARN_IF(aSource.Top() == aTarget.Top())) {
3950 return false;
3953 // Neither source nor target must be toplevel.
3954 if (NS_WARN_IF(aSource.IsTop()) || NS_WARN_IF(aTarget.IsTop())) {
3955 return false;
3958 // Both should be embedded by the same process.
3959 auto* sourceEmbedder = aSource.GetParentWindowContext();
3960 if (NS_WARN_IF(!sourceEmbedder) ||
3961 NS_WARN_IF(sourceEmbedder->GetContentParent() != aCp)) {
3962 return false;
3965 auto* targetEmbedder = aTarget.GetParentWindowContext();
3966 if (NS_WARN_IF(!targetEmbedder) ||
3967 NS_WARN_IF(targetEmbedder->GetContentParent() != aCp)) {
3968 return false;
3971 // All seems sane.
3972 return true;
3975 mozilla::ipc::IPCResult ContentParent::RecvCloneDocumentTreeInto(
3976 const MaybeDiscarded<BrowsingContext>& aSource,
3977 const MaybeDiscarded<BrowsingContext>& aTarget, PrintData&& aPrintData) {
3978 if (aSource.IsNullOrDiscarded() || aTarget.IsNullOrDiscarded()) {
3979 return IPC_OK();
3982 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
3983 // All existing processes have potentially been slated for removal already,
3984 // such that any subsequent call to GetNewOrUsedLaunchingBrowserProcess
3985 // (normally supposed to find an existing process here) will try to create
3986 // a new process (but fail) that nobody would ever really use. Let's avoid
3987 // this together with the expensive CloneDocumentTreeInto operation.
3988 return IPC_OK();
3991 auto* source = aSource.get_canonical();
3992 auto* target = aTarget.get_canonical();
3994 if (!CloneIsLegal(this, *source, *target)) {
3995 return IPC_FAIL(this, "Illegal subframe clone");
3998 ContentParent* cp = source->GetContentParent();
3999 if (NS_WARN_IF(!cp)) {
4000 return IPC_OK();
4003 if (NS_WARN_IF(cp->GetRemoteType() == GetRemoteType())) {
4004 // Wanted to switch to a target browsing context that's already local again.
4005 // See bug 1676996 for how this can happen.
4007 // Dropping the switch on the floor seems fine for this case, though we
4008 // could also try to clone the local document.
4010 // If the remote type matches & it's in the same group (which was confirmed
4011 // by CloneIsLegal), it must be the exact same process.
4012 MOZ_DIAGNOSTIC_ASSERT(cp == this);
4013 return IPC_OK();
4016 target->CloneDocumentTreeInto(source, cp->GetRemoteType(),
4017 std::move(aPrintData));
4018 return IPC_OK();
4021 mozilla::ipc::IPCResult ContentParent::RecvUpdateRemotePrintSettings(
4022 const MaybeDiscarded<BrowsingContext>& aTarget, PrintData&& aPrintData) {
4023 if (aTarget.IsNullOrDiscarded()) {
4024 return IPC_OK();
4027 auto* target = aTarget.get_canonical();
4028 auto* bp = target->GetBrowserParent();
4029 if (NS_WARN_IF(!bp)) {
4030 return IPC_OK();
4033 Unused << bp->SendUpdateRemotePrintSettings(aPrintData);
4034 return IPC_OK();
4037 mozilla::ipc::IPCResult ContentParent::RecvConstructPopupBrowser(
4038 ManagedEndpoint<PBrowserParent>&& aBrowserEp,
4039 ManagedEndpoint<PWindowGlobalParent>&& aWindowEp, const TabId& aTabId,
4040 const IPCTabContext& aContext, const WindowGlobalInit& aInitialWindowInit,
4041 const uint32_t& aChromeFlags) {
4042 MOZ_ASSERT(XRE_IsParentProcess());
4044 if (!CanOpenBrowser(aContext)) {
4045 return IPC_FAIL(this, "CanOpenBrowser Failed");
4048 RefPtr<CanonicalBrowsingContext> browsingContext =
4049 CanonicalBrowsingContext::Get(
4050 aInitialWindowInit.context().mBrowsingContextId);
4051 if (!browsingContext || browsingContext->IsDiscarded()) {
4052 return IPC_FAIL(this, "Null or discarded initial BrowsingContext");
4054 if (!aInitialWindowInit.principal()) {
4055 return IPC_FAIL(this, "Cannot create without valid initial principal");
4058 if (!ValidatePrincipal(aInitialWindowInit.principal())) {
4059 LogAndAssertFailedPrincipalValidationInfo(aInitialWindowInit.principal(),
4060 __func__);
4063 if (browsingContext->GetBrowserParent()) {
4064 return IPC_FAIL(this, "BrowsingContext already has a BrowserParent");
4067 uint32_t chromeFlags = aChromeFlags;
4068 TabId openerTabId(0);
4069 ContentParentId openerCpId(0);
4070 if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
4071 // CanOpenBrowser has ensured that the IPCTabContext is of
4072 // type PopupIPCTabContext, and that the opener BrowserParent is
4073 // reachable.
4074 const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext();
4075 auto* opener = BrowserParent::GetFrom(popupContext.opener().AsParent());
4076 openerTabId = opener->GetTabId();
4077 openerCpId = opener->Manager()->ChildID();
4079 // We must ensure that the private browsing and remoteness flags
4080 // match those of the opener.
4081 nsCOMPtr<nsILoadContext> loadContext = opener->GetLoadContext();
4082 if (!loadContext) {
4083 return IPC_FAIL(this, "Missing Opener LoadContext");
4085 if (loadContext->UsePrivateBrowsing()) {
4086 chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
4088 if (loadContext->UseRemoteSubframes()) {
4089 chromeFlags |= nsIWebBrowserChrome::CHROME_FISSION_WINDOW;
4093 // And because we're allocating a remote browser, of course the
4094 // window is remote.
4095 chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
4097 if (NS_WARN_IF(!browsingContext->IsOwnedByProcess(ChildID()))) {
4098 return IPC_FAIL(this, "BrowsingContext Owned by Incorrect Process!");
4101 MaybeInvalidTabContext tc(aContext);
4102 MOZ_ASSERT(tc.IsValid());
4104 RefPtr<WindowGlobalParent> initialWindow =
4105 WindowGlobalParent::CreateDisconnected(aInitialWindowInit);
4106 if (!initialWindow) {
4107 return IPC_FAIL(this, "Failed to create WindowGlobalParent");
4110 auto parent = MakeRefPtr<BrowserParent>(this, aTabId, tc.GetTabContext(),
4111 browsingContext, chromeFlags);
4113 // Bind the created BrowserParent to IPC to actually link the actor.
4114 if (NS_WARN_IF(!BindPBrowserEndpoint(std::move(aBrowserEp), parent))) {
4115 return IPC_FAIL(this, "BindPBrowserEndpoint failed");
4118 // XXX: Why are we checking these requirements? It seems we should register
4119 // the created frame unconditionally?
4120 if (openerTabId > 0) {
4121 // The creation of PBrowser was triggered from content process through
4122 // window.open().
4123 // We need to register remote frame with the child generated tab id.
4124 auto* cpm = ContentProcessManager::GetSingleton();
4125 if (!cpm || !cpm->RegisterRemoteFrame(parent)) {
4126 return IPC_FAIL(this, "RegisterRemoteFrame Failed");
4130 if (NS_WARN_IF(!parent->BindPWindowGlobalEndpoint(std::move(aWindowEp),
4131 initialWindow))) {
4132 return IPC_FAIL(this, "BindPWindowGlobalEndpoint failed");
4135 browsingContext->SetCurrentBrowserParent(parent);
4137 initialWindow->Init();
4139 // When enabling input event prioritization, input events may preempt other
4140 // normal priority IPC messages. To prevent the input events preempt
4141 // PBrowserConstructor, we use an IPC 'RemoteIsReadyToHandleInputEvents' to
4142 // notify parent that BrowserChild is created. In this case, PBrowser is
4143 // initiated from content so that we can set BrowserParent as ready to handle
4144 // input
4145 parent->SetReadyToHandleInputEvents();
4146 return IPC_OK();
4149 mozilla::PRemoteSpellcheckEngineParent*
4150 ContentParent::AllocPRemoteSpellcheckEngineParent() {
4151 mozilla::RemoteSpellcheckEngineParent* parent =
4152 new mozilla::RemoteSpellcheckEngineParent();
4153 return parent;
4156 bool ContentParent::DeallocPRemoteSpellcheckEngineParent(
4157 PRemoteSpellcheckEngineParent* parent) {
4158 delete parent;
4159 return true;
4162 /* static */
4163 void ContentParent::SendShutdownTimerCallback(nsITimer* aTimer,
4164 void* aClosure) {
4165 auto* self = static_cast<ContentParent*>(aClosure);
4166 self->AsyncSendShutDownMessage();
4169 /* static */
4170 void ContentParent::ForceKillTimerCallback(nsITimer* aTimer, void* aClosure) {
4171 // We don't want to time out the content process during XPCShell tests. This
4172 // is the easiest way to ensure that.
4173 if (PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR")) {
4174 return;
4177 auto* self = static_cast<ContentParent*>(aClosure);
4178 self->KillHard("ShutDownKill");
4181 void ContentParent::GeneratePairedMinidump(const char* aReason) {
4182 // We're about to kill the child process associated with this content.
4183 // Something has gone wrong to get us here, so we generate a minidump
4184 // of the parent and child for submission to the crash server unless we're
4185 // already shutting down.
4186 if (mCrashReporter &&
4187 !AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed) &&
4188 StaticPrefs::dom_ipc_tabs_createKillHardCrashReports_AtStartup()) {
4189 // GeneratePairedMinidump creates two minidumps for us - the main
4190 // one is for the content process we're about to kill, and the other
4191 // one is for the main browser process. That second one is the extra
4192 // minidump tagging along, so we have to tell the crash reporter that
4193 // it exists and is being appended.
4194 nsAutoCString additionalDumps("browser");
4195 mCrashReporter->AddAnnotationNSCString(
4196 CrashReporter::Annotation::additional_minidumps, additionalDumps);
4197 nsDependentCString reason(aReason);
4198 mCrashReporter->AddAnnotationNSCString(
4199 CrashReporter::Annotation::ipc_channel_error, reason);
4201 // Generate the report and insert into the queue for submittal.
4202 if (mCrashReporter->GenerateMinidumpAndPair(mSubprocess, "browser"_ns)) {
4203 mCrashReporter->FinalizeCrashReport();
4204 mCreatedPairedMinidumps = true;
4209 void ContentParent::HandleOrphanedMinidump(nsString* aDumpId) {
4210 if (CrashReporter::FinalizeOrphanedMinidump(
4211 OtherPid(), GeckoProcessType_Content, aDumpId)) {
4212 CrashReporterHost::RecordCrash(GeckoProcessType_Content,
4213 nsICrashService::CRASH_TYPE_CRASH, *aDumpId);
4214 } else {
4215 NS_WARNING(nsPrintfCString("content process pid = %" PRIPID
4216 " crashed without leaving a minidump behind",
4217 OtherPid())
4218 .get());
4222 // WARNING: aReason appears in telemetry, so any new value passed in requires
4223 // data review.
4224 void ContentParent::KillHard(const char* aReason) {
4225 AUTO_PROFILER_LABEL("ContentParent::KillHard", OTHER);
4227 // On Windows, calling KillHard multiple times causes problems - the
4228 // process handle becomes invalid on the first call, causing a second call
4229 // to crash our process - more details in bug 890840.
4230 if (mCalledKillHard) {
4231 return;
4233 mCalledKillHard = true;
4234 if (mSendShutdownTimer) {
4235 mSendShutdownTimer->Cancel();
4236 mSendShutdownTimer = nullptr;
4238 if (mForceKillTimer) {
4239 mForceKillTimer->Cancel();
4240 mForceKillTimer = nullptr;
4243 RemoveShutdownBlockers();
4244 nsCString reason = nsDependentCString(aReason);
4246 // If we find mIsNotifiedShutdownSuccess there is no reason to blame this
4247 // content process, most probably our parent process is just slow in
4248 // processing its own main thread queue.
4249 if (!mIsNotifiedShutdownSuccess) {
4250 GeneratePairedMinidump(aReason);
4251 } else {
4252 reason = nsDependentCString("KillHard after IsNotifiedShutdownSuccess.");
4254 Telemetry::Accumulate(Telemetry::SUBPROCESS_KILL_HARD, reason, 1);
4256 ProcessHandle otherProcessHandle;
4257 if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle)) {
4258 NS_ERROR("Failed to open child process when attempting kill.");
4259 if (CanSend()) {
4260 GetIPCChannel()->InduceConnectionError();
4262 return;
4265 if (!KillProcess(otherProcessHandle, base::PROCESS_END_KILLED_BY_USER)) {
4266 if (mCrashReporter) {
4267 mCrashReporter->DeleteCrashReport();
4269 NS_WARNING("failed to kill subprocess!");
4272 if (mSubprocess) {
4273 MOZ_LOG(
4274 ContentParent::GetLog(), LogLevel::Verbose,
4275 ("KillHard Subprocess(%s): ContentParent %p mSubprocess %p handle "
4276 "%" PRIuPTR,
4277 aReason, this, mSubprocess,
4278 mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
4279 mSubprocess->SetAlreadyDead();
4282 // After we've killed the remote process, also ensure we induce a connection
4283 // error in the IPC channel to immediately stop all IPC communication on this
4284 // channel.
4285 if (CanSend()) {
4286 GetIPCChannel()->InduceConnectionError();
4289 // EnsureProcessTerminated has responsibilty for closing otherProcessHandle.
4290 XRE_GetIOMessageLoop()->PostTask(
4291 NewRunnableFunction("EnsureProcessTerminatedRunnable",
4292 &ProcessWatcher::EnsureProcessTerminated,
4293 otherProcessHandle, /*force=*/true));
4296 void ContentParent::FriendlyName(nsAString& aName, bool aAnonymize) {
4297 aName.Truncate();
4298 if (mIsForBrowser) {
4299 aName.AssignLiteral("Browser");
4300 } else if (aAnonymize) {
4301 aName.AssignLiteral("<anonymized-name>");
4302 } else {
4303 aName.AssignLiteral("???");
4307 mozilla::ipc::IPCResult ContentParent::RecvInitCrashReporter(
4308 const NativeThreadId& aThreadId) {
4309 mCrashReporter =
4310 MakeUnique<CrashReporterHost>(GeckoProcessType_Content, aThreadId);
4312 return IPC_OK();
4315 hal_sandbox::PHalParent* ContentParent::AllocPHalParent() {
4316 return hal_sandbox::CreateHalParent();
4319 bool ContentParent::DeallocPHalParent(hal_sandbox::PHalParent* aHal) {
4320 delete aHal;
4321 return true;
4324 devtools::PHeapSnapshotTempFileHelperParent*
4325 ContentParent::AllocPHeapSnapshotTempFileHelperParent() {
4326 return devtools::HeapSnapshotTempFileHelperParent::Create();
4329 bool ContentParent::DeallocPHeapSnapshotTempFileHelperParent(
4330 devtools::PHeapSnapshotTempFileHelperParent* aHeapSnapshotHelper) {
4331 delete aHeapSnapshotHelper;
4332 return true;
4335 bool ContentParent::SendRequestMemoryReport(
4336 const uint32_t& aGeneration, const bool& aAnonymize,
4337 const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile) {
4338 // This automatically cancels the previous request.
4339 mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
4340 // If we run the callback in response to a reply, then by definition |this|
4341 // is still alive, so the ref pointer is redundant, but it seems easier
4342 // to hold a strong reference than to worry about that.
4343 RefPtr<ContentParent> self(this);
4344 PContentParent::SendRequestMemoryReport(
4345 aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile,
4346 [&, self](const uint32_t& aGeneration2) {
4347 if (self->mMemoryReportRequest) {
4348 self->mMemoryReportRequest->Finish(aGeneration2);
4349 self->mMemoryReportRequest = nullptr;
4352 [&, self](mozilla::ipc::ResponseRejectReason) {
4353 self->mMemoryReportRequest = nullptr;
4355 return IPC_OK();
4358 mozilla::ipc::IPCResult ContentParent::RecvAddMemoryReport(
4359 const MemoryReport& aReport) {
4360 if (mMemoryReportRequest) {
4361 mMemoryReportRequest->RecvReport(aReport);
4363 return IPC_OK();
4366 PCycleCollectWithLogsParent* ContentParent::AllocPCycleCollectWithLogsParent(
4367 const bool& aDumpAllTraces, const FileDescriptor& aGCLog,
4368 const FileDescriptor& aCCLog) {
4369 MOZ_CRASH("Don't call this; use ContentParent::CycleCollectWithLogs");
4372 bool ContentParent::DeallocPCycleCollectWithLogsParent(
4373 PCycleCollectWithLogsParent* aActor) {
4374 delete aActor;
4375 return true;
4378 bool ContentParent::CycleCollectWithLogs(
4379 bool aDumpAllTraces, nsICycleCollectorLogSink* aSink,
4380 nsIDumpGCAndCCLogsCallback* aCallback) {
4381 return CycleCollectWithLogsParent::AllocAndSendConstructor(
4382 this, aDumpAllTraces, aSink, aCallback);
4385 PScriptCacheParent* ContentParent::AllocPScriptCacheParent(
4386 const FileDescOrError& cacheFile, const bool& wantCacheData) {
4387 return new loader::ScriptCacheParent(wantCacheData);
4390 bool ContentParent::DeallocPScriptCacheParent(PScriptCacheParent* cache) {
4391 delete static_cast<loader::ScriptCacheParent*>(cache);
4392 return true;
4395 already_AddRefed<PNeckoParent> ContentParent::AllocPNeckoParent() {
4396 RefPtr<NeckoParent> actor = new NeckoParent();
4397 return actor.forget();
4400 mozilla::ipc::IPCResult ContentParent::RecvInitStreamFilter(
4401 const uint64_t& aChannelId, const nsAString& aAddonId,
4402 InitStreamFilterResolver&& aResolver) {
4403 extensions::StreamFilterParent::Create(this, aChannelId, aAddonId)
4404 ->Then(
4405 GetCurrentSerialEventTarget(), __func__,
4406 [aResolver](mozilla::ipc::Endpoint<PStreamFilterChild>&& aEndpoint) {
4407 aResolver(std::move(aEndpoint));
4409 [aResolver](bool aDummy) {
4410 aResolver(mozilla::ipc::Endpoint<PStreamFilterChild>());
4413 return IPC_OK();
4416 mozilla::ipc::IPCResult ContentParent::RecvAddSecurityState(
4417 const MaybeDiscarded<WindowContext>& aContext, uint32_t aStateFlags) {
4418 if (aContext.IsNullOrDiscarded()) {
4419 return IPC_OK();
4422 aContext.get()->AddSecurityState(aStateFlags);
4423 return IPC_OK();
4426 already_AddRefed<PExternalHelperAppParent>
4427 ContentParent::AllocPExternalHelperAppParent(
4428 nsIURI* uri, const mozilla::net::LoadInfoArgs& aLoadInfoArgs,
4429 const nsACString& aMimeContentType, const nsACString& aContentDisposition,
4430 const uint32_t& aContentDispositionHint,
4431 const nsAString& aContentDispositionFilename, const bool& aForceSave,
4432 const int64_t& aContentLength, const bool& aWasFileChannel,
4433 nsIURI* aReferrer, const MaybeDiscarded<BrowsingContext>& aContext,
4434 const bool& aShouldCloseWindow) {
4435 RefPtr<ExternalHelperAppParent> parent = new ExternalHelperAppParent(
4436 uri, aContentLength, aWasFileChannel, aContentDisposition,
4437 aContentDispositionHint, aContentDispositionFilename);
4438 return parent.forget();
4441 mozilla::ipc::IPCResult ContentParent::RecvPExternalHelperAppConstructor(
4442 PExternalHelperAppParent* actor, nsIURI* uri,
4443 const LoadInfoArgs& loadInfoArgs, const nsACString& aMimeContentType,
4444 const nsACString& aContentDisposition,
4445 const uint32_t& aContentDispositionHint,
4446 const nsAString& aContentDispositionFilename, const bool& aForceSave,
4447 const int64_t& aContentLength, const bool& aWasFileChannel,
4448 nsIURI* aReferrer, const MaybeDiscarded<BrowsingContext>& aContext,
4449 const bool& aShouldCloseWindow) {
4450 BrowsingContext* context = aContext.IsDiscarded() ? nullptr : aContext.get();
4451 if (!static_cast<ExternalHelperAppParent*>(actor)->Init(
4452 loadInfoArgs, aMimeContentType, aForceSave, aReferrer, context,
4453 aShouldCloseWindow)) {
4454 return IPC_FAIL(this, "Init failed.");
4456 return IPC_OK();
4459 already_AddRefed<PHandlerServiceParent>
4460 ContentParent::AllocPHandlerServiceParent() {
4461 RefPtr<HandlerServiceParent> actor = new HandlerServiceParent();
4462 return actor.forget();
4465 media::PMediaParent* ContentParent::AllocPMediaParent() {
4466 return media::AllocPMediaParent();
4469 bool ContentParent::DeallocPMediaParent(media::PMediaParent* aActor) {
4470 return media::DeallocPMediaParent(aActor);
4473 PBenchmarkStorageParent* ContentParent::AllocPBenchmarkStorageParent() {
4474 return new BenchmarkStorageParent;
4477 bool ContentParent::DeallocPBenchmarkStorageParent(
4478 PBenchmarkStorageParent* aActor) {
4479 delete aActor;
4480 return true;
4483 #ifdef MOZ_WEBSPEECH
4484 already_AddRefed<PSpeechSynthesisParent>
4485 ContentParent::AllocPSpeechSynthesisParent() {
4486 if (!StaticPrefs::media_webspeech_synth_enabled()) {
4487 return nullptr;
4489 RefPtr<SpeechSynthesisParent> actor = new SpeechSynthesisParent();
4490 return actor.forget();
4493 mozilla::ipc::IPCResult ContentParent::RecvPSpeechSynthesisConstructor(
4494 PSpeechSynthesisParent* aActor) {
4495 if (!static_cast<SpeechSynthesisParent*>(aActor)->SendInit()) {
4496 return IPC_FAIL(this, "SpeechSynthesisParent::SendInit failed.");
4498 return IPC_OK();
4500 #endif
4502 mozilla::ipc::IPCResult ContentParent::RecvStartVisitedQueries(
4503 const nsTArray<RefPtr<nsIURI>>& aUris) {
4504 nsCOMPtr<IHistory> history = components::History::Service();
4505 if (!history) {
4506 return IPC_OK();
4508 for (const auto& uri : aUris) {
4509 if (NS_WARN_IF(!uri)) {
4510 continue;
4512 history->ScheduleVisitedQuery(uri, this);
4514 return IPC_OK();
4517 mozilla::ipc::IPCResult ContentParent::RecvSetURITitle(nsIURI* uri,
4518 const nsAString& title) {
4519 if (!uri) {
4520 return IPC_FAIL(this, "uri must not be null.");
4522 nsCOMPtr<IHistory> history = components::History::Service();
4523 if (history) {
4524 history->SetURITitle(uri, title);
4526 return IPC_OK();
4529 mozilla::ipc::IPCResult ContentParent::RecvIsSecureURI(
4530 nsIURI* aURI, const OriginAttributes& aOriginAttributes,
4531 bool* aIsSecureURI) {
4532 nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID));
4533 if (!sss) {
4534 return IPC_FAIL(this, "Failed to get nsISiteSecurityService.");
4536 if (!aURI) {
4537 return IPC_FAIL(this, "aURI must not be null.");
4539 nsresult rv = sss->IsSecureURI(aURI, aOriginAttributes, aIsSecureURI);
4540 if (NS_FAILED(rv)) {
4541 return IPC_FAIL(this, "IsSecureURI failed.");
4543 return IPC_OK();
4546 mozilla::ipc::IPCResult ContentParent::RecvAccumulateMixedContentHSTS(
4547 nsIURI* aURI, const bool& aActive,
4548 const OriginAttributes& aOriginAttributes) {
4549 if (!aURI) {
4550 return IPC_FAIL(this, "aURI must not be null.");
4552 nsMixedContentBlocker::AccumulateMixedContentHSTS(aURI, aActive,
4553 aOriginAttributes);
4554 return IPC_OK();
4557 mozilla::ipc::IPCResult ContentParent::RecvLoadURIExternal(
4558 nsIURI* uri, nsIPrincipal* aTriggeringPrincipal,
4559 nsIPrincipal* aRedirectPrincipal,
4560 const MaybeDiscarded<BrowsingContext>& aContext,
4561 bool aWasExternallyTriggered, bool aHasValidUserGestureActivation) {
4562 if (aContext.IsDiscarded()) {
4563 return IPC_OK();
4566 nsCOMPtr<nsIExternalProtocolService> extProtService(
4567 do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
4568 if (!extProtService) {
4569 return IPC_OK();
4572 if (!uri) {
4573 return IPC_FAIL(this, "uri must not be null.");
4576 BrowsingContext* bc = aContext.get();
4577 extProtService->LoadURI(uri, aTriggeringPrincipal, aRedirectPrincipal, bc,
4578 aWasExternallyTriggered,
4579 aHasValidUserGestureActivation);
4580 return IPC_OK();
4583 mozilla::ipc::IPCResult ContentParent::RecvExtProtocolChannelConnectParent(
4584 const uint64_t& registrarId) {
4585 nsresult rv;
4587 // First get the real channel created before redirect on the parent.
4588 nsCOMPtr<nsIChannel> channel;
4589 rv = NS_LinkRedirectChannels(registrarId, nullptr, getter_AddRefs(channel));
4590 NS_ENSURE_SUCCESS(rv, IPC_OK());
4592 nsCOMPtr<nsIParentChannel> parent = do_QueryInterface(channel, &rv);
4593 NS_ENSURE_SUCCESS(rv, IPC_OK());
4595 // The channel itself is its own (faked) parent, link it.
4596 rv = NS_LinkRedirectChannels(registrarId, parent, getter_AddRefs(channel));
4597 NS_ENSURE_SUCCESS(rv, IPC_OK());
4599 // Signal the parent channel that it's a redirect-to parent. This will
4600 // make AsyncOpen on it do nothing (what we want).
4601 // Yes, this is a bit of a hack, but I don't think it's necessary to invent
4602 // a new interface just to set this flag on the channel.
4603 parent->SetParentListener(nullptr);
4605 return IPC_OK();
4608 mozilla::ipc::IPCResult ContentParent::RecvShowAlert(
4609 nsIAlertNotification* aAlert) {
4610 if (!aAlert) {
4611 return IPC_FAIL(this, "aAlert must not be null.");
4613 nsCOMPtr<nsIAlertsService> sysAlerts(components::Alerts::Service());
4614 if (sysAlerts) {
4615 sysAlerts->ShowAlert(aAlert, this);
4617 return IPC_OK();
4620 mozilla::ipc::IPCResult ContentParent::RecvCloseAlert(const nsAString& aName,
4621 bool aContextClosed) {
4622 nsCOMPtr<nsIAlertsService> sysAlerts(components::Alerts::Service());
4623 if (sysAlerts) {
4624 sysAlerts->CloseAlert(aName, aContextClosed);
4627 return IPC_OK();
4630 mozilla::ipc::IPCResult ContentParent::RecvDisableNotifications(
4631 nsIPrincipal* aPrincipal) {
4632 if (!aPrincipal) {
4633 return IPC_FAIL(this, "No principal");
4636 if (!ValidatePrincipal(aPrincipal)) {
4637 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
4639 Unused << Notification::RemovePermission(aPrincipal);
4640 return IPC_OK();
4643 mozilla::ipc::IPCResult ContentParent::RecvOpenNotificationSettings(
4644 nsIPrincipal* aPrincipal) {
4645 if (!aPrincipal) {
4646 return IPC_FAIL(this, "No principal");
4649 if (!ValidatePrincipal(aPrincipal)) {
4650 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
4652 Unused << Notification::OpenSettings(aPrincipal);
4653 return IPC_OK();
4656 mozilla::ipc::IPCResult ContentParent::RecvNotificationEvent(
4657 const nsAString& aType, const NotificationEventData& aData) {
4658 nsCOMPtr<nsIServiceWorkerManager> swm =
4659 mozilla::components::ServiceWorkerManager::Service();
4660 if (NS_WARN_IF(!swm)) {
4661 // Probably shouldn't happen, but no need to crash the child process.
4662 return IPC_OK();
4665 if (aType.EqualsLiteral("click")) {
4666 nsresult rv = swm->SendNotificationClickEvent(
4667 aData.originSuffix(), aData.scope(), aData.ID(), aData.title(),
4668 aData.dir(), aData.lang(), aData.body(), aData.tag(), aData.icon(),
4669 aData.data(), aData.behavior());
4670 Unused << NS_WARN_IF(NS_FAILED(rv));
4671 } else {
4672 MOZ_ASSERT(aType.EqualsLiteral("close"));
4673 nsresult rv = swm->SendNotificationCloseEvent(
4674 aData.originSuffix(), aData.scope(), aData.ID(), aData.title(),
4675 aData.dir(), aData.lang(), aData.body(), aData.tag(), aData.icon(),
4676 aData.data(), aData.behavior());
4677 Unused << NS_WARN_IF(NS_FAILED(rv));
4680 return IPC_OK();
4683 mozilla::ipc::IPCResult ContentParent::RecvSyncMessage(
4684 const nsAString& aMsg, const ClonedMessageData& aData,
4685 nsTArray<StructuredCloneData>* aRetvals) {
4686 AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("ContentParent::RecvSyncMessage",
4687 OTHER, aMsg);
4688 MMPrinter::Print("ContentParent::RecvSyncMessage", aMsg, aData);
4690 RefPtr<nsFrameMessageManager> ppm = mMessageManager;
4691 if (ppm) {
4692 ipc::StructuredCloneData data;
4693 ipc::UnpackClonedMessageData(aData, data);
4695 ppm->ReceiveMessage(ppm, nullptr, aMsg, true, &data, aRetvals,
4696 IgnoreErrors());
4698 return IPC_OK();
4701 mozilla::ipc::IPCResult ContentParent::RecvAsyncMessage(
4702 const nsAString& aMsg, const ClonedMessageData& aData) {
4703 AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("ContentParent::RecvAsyncMessage",
4704 OTHER, aMsg);
4705 MMPrinter::Print("ContentParent::RecvAsyncMessage", aMsg, aData);
4707 RefPtr<nsFrameMessageManager> ppm = mMessageManager;
4708 if (ppm) {
4709 ipc::StructuredCloneData data;
4710 ipc::UnpackClonedMessageData(aData, data);
4712 ppm->ReceiveMessage(ppm, nullptr, aMsg, false, &data, nullptr,
4713 IgnoreErrors());
4715 return IPC_OK();
4718 MOZ_CAN_RUN_SCRIPT
4719 static int32_t AddGeolocationListener(
4720 nsIDOMGeoPositionCallback* watcher,
4721 nsIDOMGeoPositionErrorCallback* errorCallBack, bool highAccuracy) {
4722 RefPtr<Geolocation> geo = Geolocation::NonWindowSingleton();
4724 UniquePtr<PositionOptions> options = MakeUnique<PositionOptions>();
4725 options->mTimeout = 0;
4726 options->mMaximumAge = 0;
4727 options->mEnableHighAccuracy = highAccuracy;
4728 return geo->WatchPosition(watcher, errorCallBack, std::move(options));
4731 mozilla::ipc::IPCResult ContentParent::RecvAddGeolocationListener(
4732 const bool& aHighAccuracy) {
4733 // To ensure no geolocation updates are skipped, we always force the
4734 // creation of a new listener.
4735 RecvRemoveGeolocationListener();
4736 mGeolocationWatchID = AddGeolocationListener(this, this, aHighAccuracy);
4737 return IPC_OK();
4740 mozilla::ipc::IPCResult ContentParent::RecvRemoveGeolocationListener() {
4741 if (mGeolocationWatchID != -1) {
4742 RefPtr<Geolocation> geo = Geolocation::NonWindowSingleton();
4743 if (geo) {
4744 geo->ClearWatch(mGeolocationWatchID);
4746 mGeolocationWatchID = -1;
4748 return IPC_OK();
4751 mozilla::ipc::IPCResult ContentParent::RecvSetGeolocationHigherAccuracy(
4752 const bool& aEnable) {
4753 // This should never be called without a listener already present,
4754 // so this check allows us to forgo securing privileges.
4755 if (mGeolocationWatchID != -1) {
4756 RecvRemoveGeolocationListener();
4757 mGeolocationWatchID = AddGeolocationListener(this, this, aEnable);
4759 return IPC_OK();
4762 NS_IMETHODIMP
4763 ContentParent::HandleEvent(nsIDOMGeoPosition* postion) {
4764 Unused << SendGeolocationUpdate(postion);
4765 return NS_OK;
4768 NS_IMETHODIMP
4769 ContentParent::HandleEvent(GeolocationPositionError* positionError) {
4770 Unused << SendGeolocationError(positionError->Code());
4771 return NS_OK;
4774 mozilla::ipc::IPCResult ContentParent::RecvConsoleMessage(
4775 const nsAString& aMessage) {
4776 nsresult rv;
4777 nsCOMPtr<nsIConsoleService> consoleService =
4778 do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
4779 if (NS_SUCCEEDED(rv)) {
4780 RefPtr<nsConsoleMessage> msg(new nsConsoleMessage(aMessage));
4781 msg->SetIsForwardedFromContentProcess(true);
4782 consoleService->LogMessageWithMode(msg, nsIConsoleService::SuppressLog);
4784 return IPC_OK();
4787 mozilla::ipc::IPCResult ContentParent::RecvReportFrameTimingData(
4788 const LoadInfoArgs& loadInfoArgs, const nsAString& entryName,
4789 const nsAString& initiatorType, UniquePtr<PerformanceTimingData>&& aData) {
4790 if (!aData) {
4791 return IPC_FAIL(this, "aData should not be null");
4794 RefPtr<WindowGlobalParent> parent =
4795 WindowGlobalParent::GetByInnerWindowId(loadInfoArgs.innerWindowID());
4796 if (!parent || !parent->GetContentParent()) {
4797 return IPC_OK();
4800 MOZ_ASSERT(parent->GetContentParent() != this,
4801 "No need to bounce around if in the same process");
4803 Unused << parent->GetContentParent()->SendReportFrameTimingData(
4804 loadInfoArgs, entryName, initiatorType, aData);
4805 return IPC_OK();
4808 mozilla::ipc::IPCResult ContentParent::RecvScriptError(
4809 const nsAString& aMessage, const nsAString& aSourceName,
4810 const nsAString& aSourceLine, const uint32_t& aLineNumber,
4811 const uint32_t& aColNumber, const uint32_t& aFlags,
4812 const nsACString& aCategory, const bool& aIsFromPrivateWindow,
4813 const uint64_t& aInnerWindowId, const bool& aIsFromChromeContext) {
4814 return RecvScriptErrorInternal(aMessage, aSourceName, aSourceLine,
4815 aLineNumber, aColNumber, aFlags, aCategory,
4816 aIsFromPrivateWindow, aIsFromChromeContext);
4819 mozilla::ipc::IPCResult ContentParent::RecvScriptErrorWithStack(
4820 const nsAString& aMessage, const nsAString& aSourceName,
4821 const nsAString& aSourceLine, const uint32_t& aLineNumber,
4822 const uint32_t& aColNumber, const uint32_t& aFlags,
4823 const nsACString& aCategory, const bool& aIsFromPrivateWindow,
4824 const bool& aIsFromChromeContext, const ClonedMessageData& aStack) {
4825 return RecvScriptErrorInternal(
4826 aMessage, aSourceName, aSourceLine, aLineNumber, aColNumber, aFlags,
4827 aCategory, aIsFromPrivateWindow, aIsFromChromeContext, &aStack);
4830 mozilla::ipc::IPCResult ContentParent::RecvScriptErrorInternal(
4831 const nsAString& aMessage, const nsAString& aSourceName,
4832 const nsAString& aSourceLine, const uint32_t& aLineNumber,
4833 const uint32_t& aColNumber, const uint32_t& aFlags,
4834 const nsACString& aCategory, const bool& aIsFromPrivateWindow,
4835 const bool& aIsFromChromeContext, const ClonedMessageData* aStack) {
4836 nsresult rv;
4837 nsCOMPtr<nsIConsoleService> consoleService =
4838 do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
4839 if (NS_FAILED(rv)) {
4840 return IPC_OK();
4843 nsCOMPtr<nsIScriptError> msg;
4845 if (aStack) {
4846 StructuredCloneData data;
4847 UnpackClonedMessageData(*aStack, data);
4849 AutoJSAPI jsapi;
4850 if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) {
4851 MOZ_CRASH();
4853 JSContext* cx = jsapi.cx();
4855 JS::Rooted<JS::Value> stack(cx);
4856 ErrorResult rv;
4857 data.Read(cx, &stack, rv);
4858 if (rv.Failed() || !stack.isObject()) {
4859 rv.SuppressException();
4860 return IPC_OK();
4863 JS::Rooted<JSObject*> stackObj(cx, &stack.toObject());
4864 if (!JS::IsUnwrappedSavedFrame(stackObj)) {
4865 return IPC_FAIL(this, "Unexpected object");
4868 JS::Rooted<JSObject*> stackGlobal(cx, JS::GetNonCCWObjectGlobal(stackObj));
4869 msg = new nsScriptErrorWithStack(JS::NothingHandleValue, stackObj,
4870 stackGlobal);
4871 } else {
4872 msg = new nsScriptError();
4875 rv = msg->Init(aMessage, aSourceName, aSourceLine, aLineNumber, aColNumber,
4876 aFlags, aCategory, aIsFromPrivateWindow, aIsFromChromeContext);
4877 if (NS_FAILED(rv)) return IPC_OK();
4879 msg->SetIsForwardedFromContentProcess(true);
4881 consoleService->LogMessageWithMode(msg, nsIConsoleService::SuppressLog);
4882 return IPC_OK();
4885 bool ContentParent::DoLoadMessageManagerScript(const nsAString& aURL,
4886 bool aRunInGlobalScope) {
4887 MOZ_ASSERT(!aRunInGlobalScope);
4888 return SendLoadProcessScript(aURL);
4891 nsresult ContentParent::DoSendAsyncMessage(const nsAString& aMessage,
4892 StructuredCloneData& aData) {
4893 ClonedMessageData data;
4894 if (!BuildClonedMessageData(aData, data)) {
4895 return NS_ERROR_DOM_DATA_CLONE_ERR;
4897 if (!SendAsyncMessage(aMessage, data)) {
4898 return NS_ERROR_UNEXPECTED;
4900 return NS_OK;
4903 mozilla::ipc::IPCResult ContentParent::RecvCopyFavicon(
4904 nsIURI* aOldURI, nsIURI* aNewURI, const bool& aInPrivateBrowsing) {
4905 if (!aOldURI) {
4906 return IPC_FAIL(this, "aOldURI should not be null");
4908 if (!aNewURI) {
4909 return IPC_FAIL(this, "aNewURI should not be null");
4912 nsDocShell::CopyFavicon(aOldURI, aNewURI, aInPrivateBrowsing);
4913 return IPC_OK();
4916 mozilla::ipc::IPCResult ContentParent::RecvFindImageText(
4917 IPCImage&& aImage, nsTArray<nsCString>&& aLanguages,
4918 FindImageTextResolver&& aResolver) {
4919 if (!TextRecognition::IsSupported() ||
4920 !Preferences::GetBool("dom.text-recognition.enabled")) {
4921 return IPC_FAIL(this, "Text recognition not available.");
4924 RefPtr<DataSourceSurface> surf = nsContentUtils::IPCImageToSurface(aImage);
4925 if (!surf) {
4926 aResolver(TextRecognitionResultOrError("Failed to read image"_ns));
4927 return IPC_OK();
4929 TextRecognition::FindText(*surf, aLanguages)
4930 ->Then(
4931 GetCurrentSerialEventTarget(), __func__,
4932 [resolver = std::move(aResolver)](
4933 TextRecognition::NativePromise::ResolveOrRejectValue&& aValue) {
4934 if (aValue.IsResolve()) {
4935 resolver(TextRecognitionResultOrError(aValue.ResolveValue()));
4936 } else {
4937 resolver(TextRecognitionResultOrError(aValue.RejectValue()));
4940 return IPC_OK();
4943 bool ContentParent::ShouldContinueFromReplyTimeout() {
4944 RefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
4945 return !monitor || !monitor->ShouldTimeOutCPOWs();
4948 mozilla::ipc::IPCResult ContentParent::RecvAddIdleObserver(
4949 const uint64_t& aObserverId, const uint32_t& aIdleTimeInS) {
4950 nsresult rv;
4951 nsCOMPtr<nsIUserIdleService> idleService =
4952 do_GetService("@mozilla.org/widget/useridleservice;1", &rv);
4953 NS_ENSURE_SUCCESS(rv, IPC_FAIL(this, "Failed to get UserIdleService."));
4955 RefPtr<ParentIdleListener> listener =
4956 new ParentIdleListener(this, aObserverId, aIdleTimeInS);
4957 rv = idleService->AddIdleObserver(listener, aIdleTimeInS);
4958 NS_ENSURE_SUCCESS(rv, IPC_FAIL(this, "AddIdleObserver failed."));
4959 mIdleListeners.AppendElement(listener);
4960 return IPC_OK();
4963 mozilla::ipc::IPCResult ContentParent::RecvRemoveIdleObserver(
4964 const uint64_t& aObserverId, const uint32_t& aIdleTimeInS) {
4965 RefPtr<ParentIdleListener> listener;
4966 for (int32_t i = mIdleListeners.Length() - 1; i >= 0; --i) {
4967 listener = static_cast<ParentIdleListener*>(mIdleListeners[i].get());
4968 if (listener->mObserver == aObserverId && listener->mTime == aIdleTimeInS) {
4969 nsresult rv;
4970 nsCOMPtr<nsIUserIdleService> idleService =
4971 do_GetService("@mozilla.org/widget/useridleservice;1", &rv);
4972 NS_ENSURE_SUCCESS(rv, IPC_FAIL(this, "Failed to get UserIdleService."));
4973 idleService->RemoveIdleObserver(listener, aIdleTimeInS);
4974 mIdleListeners.RemoveElementAt(i);
4975 break;
4978 return IPC_OK();
4981 mozilla::ipc::IPCResult ContentParent::RecvBackUpXResources(
4982 const FileDescriptor& aXSocketFd) {
4983 #ifndef MOZ_X11
4984 MOZ_CRASH("This message only makes sense on X11 platforms");
4985 #else
4986 MOZ_ASSERT(!mChildXSocketFdDup, "Already backed up X resources??");
4987 if (aXSocketFd.IsValid()) {
4988 mChildXSocketFdDup = aXSocketFd.ClonePlatformHandle();
4990 #endif
4991 return IPC_OK();
4994 class AnonymousTemporaryFileRequestor final : public Runnable {
4995 public:
4996 AnonymousTemporaryFileRequestor(ContentParent* aCP, const uint64_t& aID)
4997 : Runnable("dom::AnonymousTemporaryFileRequestor"),
4998 mCP(aCP),
4999 mID(aID),
5000 mRv(NS_OK),
5001 mPRFD(nullptr) {}
5003 NS_IMETHOD Run() override {
5004 if (NS_IsMainThread()) {
5005 FileDescOrError result;
5006 if (NS_WARN_IF(NS_FAILED(mRv))) {
5007 // Returning false will kill the child process; instead
5008 // propagate the error and let the child handle it.
5009 result = mRv;
5010 } else {
5011 result = FileDescriptor(FileDescriptor::PlatformHandleType(
5012 PR_FileDesc2NativeHandle(mPRFD)));
5013 // The FileDescriptor object owns a duplicate of the file handle; we
5014 // must close the original (and clean up the NSPR descriptor).
5015 PR_Close(mPRFD);
5017 Unused << mCP->SendProvideAnonymousTemporaryFile(mID, result);
5018 // It's important to release this reference while wr're on the main
5019 // thread!
5020 mCP = nullptr;
5021 } else {
5022 mRv = NS_OpenAnonymousTemporaryFile(&mPRFD);
5023 NS_DispatchToMainThread(this);
5025 return NS_OK;
5028 private:
5029 RefPtr<ContentParent> mCP;
5030 uint64_t mID;
5031 nsresult mRv;
5032 PRFileDesc* mPRFD;
5035 mozilla::ipc::IPCResult ContentParent::RecvRequestAnonymousTemporaryFile(
5036 const uint64_t& aID) {
5037 // Make sure to send a callback to the child if we bail out early.
5038 nsresult rv = NS_OK;
5039 RefPtr<ContentParent> self(this);
5040 auto autoNotifyChildOnError = MakeScopeExit([&, self]() {
5041 if (NS_FAILED(rv)) {
5042 FileDescOrError result(rv);
5043 Unused << self->SendProvideAnonymousTemporaryFile(aID, result);
5047 // We use a helper runnable to open the anonymous temporary file on the IO
5048 // thread. The same runnable will call us back on the main thread when the
5049 // file has been opened.
5050 nsCOMPtr<nsIEventTarget> target =
5051 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
5052 if (!target) {
5053 return IPC_OK();
5056 rv = target->Dispatch(new AnonymousTemporaryFileRequestor(this, aID),
5057 NS_DISPATCH_NORMAL);
5058 if (NS_WARN_IF(NS_FAILED(rv))) {
5059 return IPC_OK();
5062 rv = NS_OK;
5063 return IPC_OK();
5066 mozilla::ipc::IPCResult ContentParent::RecvCreateAudioIPCConnection(
5067 CreateAudioIPCConnectionResolver&& aResolver) {
5068 FileDescriptor fd = CubebUtils::CreateAudioIPCConnection();
5069 FileDescOrError result;
5070 if (fd.IsValid()) {
5071 result = fd;
5072 } else {
5073 result = NS_ERROR_FAILURE;
5075 aResolver(result);
5076 return IPC_OK();
5079 already_AddRefed<extensions::PExtensionsParent>
5080 ContentParent::AllocPExtensionsParent() {
5081 return MakeAndAddRef<extensions::ExtensionsParent>();
5084 void ContentParent::NotifyUpdatedDictionaries() {
5085 RefPtr<mozSpellChecker> spellChecker(mozSpellChecker::Create());
5086 MOZ_ASSERT(spellChecker, "No spell checker?");
5088 nsTArray<nsCString> dictionaries;
5089 spellChecker->GetDictionaryList(&dictionaries);
5091 for (auto* cp : AllProcesses(eLive)) {
5092 Unused << cp->SendUpdateDictionaryList(dictionaries);
5096 void ContentParent::NotifyUpdatedFonts(bool aFullRebuild) {
5097 if (gfxPlatformFontList::PlatformFontList()->SharedFontList()) {
5098 for (auto* cp : AllProcesses(eLive)) {
5099 Unused << cp->SendRebuildFontList(aFullRebuild);
5101 return;
5104 SystemFontList fontList;
5105 gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList);
5107 for (auto* cp : AllProcesses(eLive)) {
5108 Unused << cp->SendUpdateFontList(fontList);
5112 #ifdef MOZ_WEBRTC
5113 PWebrtcGlobalParent* ContentParent::AllocPWebrtcGlobalParent() {
5114 return WebrtcGlobalParent::Alloc();
5117 bool ContentParent::DeallocPWebrtcGlobalParent(PWebrtcGlobalParent* aActor) {
5118 WebrtcGlobalParent::Dealloc(static_cast<WebrtcGlobalParent*>(aActor));
5119 return true;
5121 #endif
5123 void ContentParent::GetIPCTransferableData(
5124 nsIDragSession* aSession, BrowserParent* aParent,
5125 nsTArray<IPCTransferableData>& aIPCTransferables) {
5126 RefPtr<DataTransfer> transfer = aSession->GetDataTransfer();
5127 if (!transfer) {
5128 // Pass eDrop to get DataTransfer with external
5129 // drag formats cached.
5130 transfer = new DataTransfer(nullptr, eDrop, true, -1);
5131 aSession->SetDataTransfer(transfer);
5133 // Note, even though this fills the DataTransfer object with
5134 // external data, the data is usually transfered over IPC lazily when
5135 // needed.
5136 transfer->FillAllExternalData();
5137 nsCOMPtr<nsILoadContext> lc = aParent ? aParent->GetLoadContext() : nullptr;
5138 nsCOMPtr<nsIArray> transferables = transfer->GetTransferables(lc);
5139 nsContentUtils::TransferablesToIPCTransferableDatas(
5140 transferables, aIPCTransferables, false, this);
5143 void ContentParent::MaybeInvokeDragSession(BrowserParent* aParent,
5144 EventMessage aMessage) {
5145 // dnd uses IPCBlob to transfer data to the content process and the IPC
5146 // message is sent as normal priority. When sending input events with input
5147 // priority, the message may be preempted by the later dnd events. To make
5148 // sure the input events and the blob message are processed in time order
5149 // on the content process, we temporarily send the input events with normal
5150 // priority when there is an active dnd session.
5151 SetInputPriorityEventEnabled(false);
5153 nsCOMPtr<nsIDragService> dragService =
5154 do_GetService("@mozilla.org/widget/dragservice;1");
5155 if (!dragService) {
5156 return;
5159 if (dragService->MaybeAddChildProcess(this)) {
5160 nsCOMPtr<nsIDragSession> session;
5161 dragService->GetCurrentSession(getter_AddRefs(session));
5162 if (session) {
5163 // We need to send transferable data to child process.
5164 nsTArray<IPCTransferableData> ipcTransferables;
5165 GetIPCTransferableData(session, aParent, ipcTransferables);
5166 uint32_t action;
5167 session->GetDragAction(&action);
5169 RefPtr<WindowContext> sourceWC;
5170 session->GetSourceWindowContext(getter_AddRefs(sourceWC));
5171 RefPtr<WindowContext> sourceTopWC;
5172 session->GetSourceTopWindowContext(getter_AddRefs(sourceTopWC));
5173 mozilla::Unused << SendInvokeDragSession(
5174 sourceWC, sourceTopWC, std::move(ipcTransferables), action);
5176 return;
5179 if (dragService->MustUpdateDataTransfer(aMessage)) {
5180 nsCOMPtr<nsIDragSession> session;
5181 dragService->GetCurrentSession(getter_AddRefs(session));
5182 if (session) {
5183 // We need to send transferable data to child process.
5184 nsTArray<IPCTransferableData> ipcTransferables;
5185 GetIPCTransferableData(session, aParent, ipcTransferables);
5186 mozilla::Unused << SendUpdateDragSession(std::move(ipcTransferables),
5187 aMessage);
5192 mozilla::ipc::IPCResult ContentParent::RecvUpdateDropEffect(
5193 const uint32_t& aDragAction, const uint32_t& aDropEffect) {
5194 nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
5195 if (dragSession) {
5196 dragSession->SetDragAction(aDragAction);
5197 RefPtr<DataTransfer> dt = dragSession->GetDataTransfer();
5198 if (dt) {
5199 dt->SetDropEffectInt(aDropEffect);
5201 dragSession->UpdateDragEffect();
5203 return IPC_OK();
5206 PContentPermissionRequestParent*
5207 ContentParent::AllocPContentPermissionRequestParent(
5208 const nsTArray<PermissionRequest>& aRequests, nsIPrincipal* aPrincipal,
5209 nsIPrincipal* aTopLevelPrincipal, const bool& aIsHandlingUserInput,
5210 const bool& aMaybeUnsafePermissionDelegate, const TabId& aTabId) {
5211 RefPtr<BrowserParent> tp;
5212 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
5213 if (cpm) {
5214 tp =
5215 cpm->GetTopLevelBrowserParentByProcessAndTabId(this->ChildID(), aTabId);
5217 if (!tp) {
5218 return nullptr;
5221 nsIPrincipal* topPrincipal = aTopLevelPrincipal;
5222 if (!topPrincipal) {
5223 nsCOMPtr<nsIPrincipal> principal = tp->GetContentPrincipal();
5224 topPrincipal = principal;
5226 return nsContentPermissionUtils::CreateContentPermissionRequestParent(
5227 aRequests, tp->GetOwnerElement(), aPrincipal, topPrincipal,
5228 aIsHandlingUserInput, aMaybeUnsafePermissionDelegate, aTabId);
5231 bool ContentParent::DeallocPContentPermissionRequestParent(
5232 PContentPermissionRequestParent* actor) {
5233 nsContentPermissionUtils::NotifyRemoveContentPermissionRequestParent(actor);
5234 delete actor;
5235 return true;
5238 already_AddRefed<PWebBrowserPersistDocumentParent>
5239 ContentParent::AllocPWebBrowserPersistDocumentParent(
5240 PBrowserParent* aBrowser, const MaybeDiscarded<BrowsingContext>& aContext) {
5241 return MakeAndAddRef<WebBrowserPersistDocumentParent>();
5244 mozilla::ipc::IPCResult ContentParent::CommonCreateWindow(
5245 PBrowserParent* aThisTab, BrowsingContext& aParent, bool aSetOpener,
5246 const uint32_t& aChromeFlags, const bool& aCalledFromJS,
5247 const bool& aForPrinting, const bool& aForWindowDotPrint,
5248 const bool& aIsTopLevelCreatedByWebContent, nsIURI* aURIToLoad,
5249 const nsACString& aFeatures, const UserActivation::Modifiers& aModifiers,
5250 BrowserParent* aNextRemoteBrowser, const nsAString& aName,
5251 nsresult& aResult, nsCOMPtr<nsIRemoteTab>& aNewRemoteTab,
5252 bool* aWindowIsNew, int32_t& aOpenLocation,
5253 nsIPrincipal* aTriggeringPrincipal, nsIReferrerInfo* aReferrerInfo,
5254 bool aLoadURI, nsIContentSecurityPolicy* aCsp,
5255 const OriginAttributes& aOriginAttributes, bool aUserActivation,
5256 bool aTextDirectiveUserActivation) {
5257 // The content process should never be in charge of computing whether or
5258 // not a window should be private - the parent will do that.
5259 const uint32_t badFlags = nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW |
5260 nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW |
5261 nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME;
5262 if (!!(aChromeFlags & badFlags)) {
5263 return IPC_FAIL(this, "Forbidden aChromeFlags passed");
5266 RefPtr<nsOpenWindowInfo> openInfo = new nsOpenWindowInfo();
5267 openInfo->mForceNoOpener = !aSetOpener;
5268 openInfo->mParent = &aParent;
5269 openInfo->mIsRemote = true;
5270 openInfo->mIsForPrinting = aForPrinting;
5271 openInfo->mIsForWindowDotPrint = aForWindowDotPrint;
5272 openInfo->mNextRemoteBrowser = aNextRemoteBrowser;
5273 openInfo->mOriginAttributes = aOriginAttributes;
5274 openInfo->mIsTopLevelCreatedByWebContent = aIsTopLevelCreatedByWebContent;
5275 openInfo->mHasValidUserGestureActivation = aUserActivation;
5276 openInfo->mTextDirectiveUserActivation = aTextDirectiveUserActivation;
5278 MOZ_ASSERT_IF(aForWindowDotPrint, aForPrinting);
5280 RefPtr<BrowserParent> topParent = BrowserParent::GetFrom(aThisTab);
5281 while (topParent && topParent->GetBrowserBridgeParent()) {
5282 topParent = topParent->GetBrowserBridgeParent()->Manager();
5284 RefPtr<BrowserHost> thisBrowserHost =
5285 topParent ? topParent->GetBrowserHost() : nullptr;
5286 MOZ_ASSERT_IF(topParent, thisBrowserHost);
5287 RefPtr<BrowsingContext> topBC =
5288 topParent ? topParent->GetBrowsingContext() : nullptr;
5289 MOZ_ASSERT_IF(topParent, topBC);
5291 // The content process should have set its remote and fission flags correctly.
5292 if (topBC) {
5293 if ((!!(aChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) !=
5294 topBC->UseRemoteTabs()) ||
5295 (!!(aChromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW) !=
5296 topBC->UseRemoteSubframes())) {
5297 return IPC_FAIL(this, "Unexpected aChromeFlags passed");
5300 if (!aOriginAttributes.EqualsIgnoringFPD(topBC->OriginAttributesRef())) {
5301 return IPC_FAIL(this, "Passed-in OriginAttributes does not match opener");
5305 nsCOMPtr<nsIContent> frame;
5306 if (topParent) {
5307 frame = topParent->GetOwnerElement();
5310 nsCOMPtr<nsPIDOMWindowOuter> outerWin;
5311 if (frame) {
5312 outerWin = frame->OwnerDoc()->GetWindow();
5314 // If our chrome window is in the process of closing, don't try to open a
5315 // new tab in it.
5316 if (outerWin && outerWin->Closed()) {
5317 outerWin = nullptr;
5321 nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
5322 if (topParent) {
5323 browserDOMWin = topParent->GetBrowserDOMWindow();
5326 // If we haven't found a chrome window to open in, just use the most recently
5327 // opened one.
5328 if (!outerWin) {
5329 outerWin = nsContentUtils::GetMostRecentNonPBWindow();
5330 if (NS_WARN_IF(!outerWin)) {
5331 aResult = NS_ERROR_FAILURE;
5332 return IPC_OK();
5335 if (nsGlobalWindowOuter::Cast(outerWin)->IsChromeWindow()) {
5336 browserDOMWin =
5337 nsGlobalWindowOuter::Cast(outerWin)->GetBrowserDOMWindow();
5341 aOpenLocation = nsWindowWatcher::GetWindowOpenLocation(
5342 outerWin, aChromeFlags, aModifiers, aCalledFromJS, aForPrinting);
5344 MOZ_ASSERT(aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
5345 aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB_BACKGROUND ||
5346 aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWWINDOW ||
5347 aOpenLocation == nsIBrowserDOMWindow::OPEN_PRINT_BROWSER);
5349 if (NS_WARN_IF(!browserDOMWin)) {
5350 // Opening in the same window or headless requires an nsIBrowserDOMWindow.
5351 aOpenLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
5354 if (aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
5355 aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB_BACKGROUND ||
5356 aOpenLocation == nsIBrowserDOMWindow::OPEN_PRINT_BROWSER) {
5357 RefPtr<Element> openerElement = do_QueryObject(frame);
5359 nsCOMPtr<nsIOpenURIInFrameParams> params =
5360 new nsOpenURIInFrameParams(openInfo, openerElement);
5361 params->SetReferrerInfo(aReferrerInfo);
5362 MOZ_ASSERT(aTriggeringPrincipal, "need a valid triggeringPrincipal");
5363 params->SetTriggeringPrincipal(aTriggeringPrincipal);
5364 params->SetCsp(aCsp);
5366 RefPtr<Element> el;
5368 if (aLoadURI) {
5369 aResult = browserDOMWin->OpenURIInFrame(aURIToLoad, params, aOpenLocation,
5370 nsIBrowserDOMWindow::OPEN_NEW,
5371 aName, getter_AddRefs(el));
5372 } else {
5373 aResult = browserDOMWin->CreateContentWindowInFrame(
5374 aURIToLoad, params, aOpenLocation, nsIBrowserDOMWindow::OPEN_NEW,
5375 aName, getter_AddRefs(el));
5377 RefPtr<nsFrameLoaderOwner> frameLoaderOwner = do_QueryObject(el);
5378 if (NS_SUCCEEDED(aResult) && frameLoaderOwner) {
5379 RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
5380 if (frameLoader) {
5381 aNewRemoteTab = frameLoader->GetRemoteTab();
5382 // At this point, it's possible the inserted frameloader hasn't gone
5383 // through layout yet. To ensure that the dimensions that we send down
5384 // when telling the frameloader to display will be correct (instead of
5385 // falling back to a 10x10 default), we force layout if necessary to get
5386 // the most up-to-date dimensions. See bug 1358712 for details.
5387 frameLoader->ForceLayoutIfNecessary();
5389 } else if (NS_SUCCEEDED(aResult) && !frameLoaderOwner) {
5390 // Fall through to the normal window opening code path when there is no
5391 // window which we can open a new tab in.
5392 aOpenLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
5393 } else {
5394 *aWindowIsNew = false;
5397 // If we didn't retarget our window open into a new window, we should return
5398 // now.
5399 if (aOpenLocation != nsIBrowserDOMWindow::OPEN_NEWWINDOW) {
5400 return IPC_OK();
5404 nsCOMPtr<nsPIWindowWatcher> pwwatch =
5405 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &aResult);
5406 if (NS_WARN_IF(NS_FAILED(aResult))) {
5407 return IPC_OK();
5410 WindowFeatures features;
5411 features.Tokenize(aFeatures);
5413 aResult = pwwatch->OpenWindowWithRemoteTab(
5414 thisBrowserHost, features, aModifiers, aCalledFromJS, aParent.FullZoom(),
5415 openInfo, getter_AddRefs(aNewRemoteTab));
5416 if (NS_WARN_IF(NS_FAILED(aResult))) {
5417 return IPC_OK();
5420 MOZ_ASSERT(aNewRemoteTab);
5421 RefPtr<BrowserHost> newBrowserHost = BrowserHost::GetFrom(aNewRemoteTab);
5422 RefPtr<BrowserParent> newBrowserParent = newBrowserHost->GetActor();
5424 // At this point, it's possible the inserted frameloader hasn't gone through
5425 // layout yet. To ensure that the dimensions that we send down when telling
5426 // the frameloader to display will be correct (instead of falling back to a
5427 // 10x10 default), we force layout if necessary to get the most up-to-date
5428 // dimensions. See bug 1358712 for details.
5429 nsCOMPtr<Element> frameElement = newBrowserHost->GetOwnerElement();
5430 MOZ_ASSERT(frameElement);
5431 if (nsWindowWatcher::HaveSpecifiedSize(features)) {
5432 // We want to flush the layout anyway because of the resize to the specified
5433 // size. (Bug 1793605).
5434 RefPtr<Document> chromeDoc = frameElement->OwnerDoc();
5435 MOZ_ASSERT(chromeDoc);
5436 chromeDoc->FlushPendingNotifications(FlushType::Layout);
5437 } else {
5438 RefPtr<nsFrameLoaderOwner> frameLoaderOwner = do_QueryObject(frameElement);
5439 MOZ_ASSERT(frameLoaderOwner);
5440 RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
5441 MOZ_ASSERT(frameLoader);
5442 frameLoader->ForceLayoutIfNecessary();
5445 // If we were passed a name for the window which would override the default,
5446 // we should send it down to the new tab.
5447 if (nsContentUtils::IsOverridingWindowName(aName)) {
5448 MOZ_ALWAYS_SUCCEEDS(newBrowserHost->GetBrowsingContext()->SetName(aName));
5451 MOZ_ASSERT(newBrowserHost->GetBrowsingContext()->OriginAttributesRef() ==
5452 aOriginAttributes);
5454 if (aURIToLoad && aLoadURI) {
5455 nsCOMPtr<mozIDOMWindowProxy> openerWindow;
5456 if (aSetOpener && topParent) {
5457 openerWindow = topParent->GetParentWindowOuter();
5459 nsCOMPtr<nsIBrowserDOMWindow> newBrowserDOMWin =
5460 newBrowserParent->GetBrowserDOMWindow();
5461 if (NS_WARN_IF(!newBrowserDOMWin)) {
5462 aResult = NS_ERROR_ABORT;
5463 return IPC_OK();
5465 RefPtr<BrowsingContext> bc;
5466 aResult = newBrowserDOMWin->OpenURI(
5467 aURIToLoad, openInfo, nsIBrowserDOMWindow::OPEN_CURRENTWINDOW,
5468 nsIBrowserDOMWindow::OPEN_NEW, aTriggeringPrincipal, aCsp,
5469 getter_AddRefs(bc));
5472 return IPC_OK();
5475 mozilla::ipc::IPCResult ContentParent::RecvCreateWindow(
5476 PBrowserParent* aThisTab, const MaybeDiscarded<BrowsingContext>& aParent,
5477 PBrowserParent* aNewTab, const uint32_t& aChromeFlags,
5478 const bool& aCalledFromJS, const bool& aForPrinting,
5479 const bool& aForWindowDotPrint, const bool& aIsTopLevelCreatedByWebContent,
5480 nsIURI* aURIToLoad, const nsACString& aFeatures,
5481 const UserActivation::Modifiers& aModifiers,
5482 nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp,
5483 nsIReferrerInfo* aReferrerInfo, const OriginAttributes& aOriginAttributes,
5484 bool aUserActivation, bool aTextDirectiveUserActivation,
5485 CreateWindowResolver&& aResolve) {
5486 if (!aTriggeringPrincipal) {
5487 return IPC_FAIL(this, "No principal");
5490 if (!ValidatePrincipal(aTriggeringPrincipal)) {
5491 LogAndAssertFailedPrincipalValidationInfo(aTriggeringPrincipal, __func__);
5494 nsresult rv = NS_OK;
5495 CreatedWindowInfo cwi;
5497 // We always expect to open a new window here. If we don't, it's an error.
5498 cwi.windowOpened() = true;
5499 cwi.maxTouchPoints() = 0;
5501 // Make sure to resolve the resolver when this function exits, even if we
5502 // failed to generate a valid response.
5503 auto resolveOnExit = MakeScopeExit([&] {
5504 // Copy over the nsresult, and then resolve.
5505 cwi.rv() = rv;
5506 aResolve(cwi);
5509 RefPtr<BrowserParent> thisTab = BrowserParent::GetFrom(aThisTab);
5510 RefPtr<BrowserParent> newTab = BrowserParent::GetFrom(aNewTab);
5511 MOZ_ASSERT(newTab);
5513 auto destroyNewTabOnError = MakeScopeExit([&] {
5514 // We always expect to open a new window here. If we don't, it's an error.
5515 if (!cwi.windowOpened() || NS_FAILED(rv)) {
5516 if (newTab) {
5517 newTab->Destroy();
5522 // Don't continue to try to create a new window if we've been fully discarded.
5523 RefPtr<BrowsingContext> parent = aParent.GetMaybeDiscarded();
5524 if (NS_WARN_IF(!parent)) {
5525 rv = NS_ERROR_FAILURE;
5526 return IPC_OK();
5529 // Validate that our new BrowsingContext looks as we would expect it.
5530 RefPtr<BrowsingContext> newBC = newTab->GetBrowsingContext();
5531 if (!newBC) {
5532 return IPC_FAIL(this, "Missing BrowsingContext for new tab");
5535 uint64_t newBCOpenerId = newBC->GetOpenerId();
5536 if (newBCOpenerId != 0 && parent->Id() != newBCOpenerId) {
5537 return IPC_FAIL(this, "Invalid opener BrowsingContext for new tab");
5539 if (newBC->GetParent() != nullptr) {
5540 return IPC_FAIL(this,
5541 "Unexpected non-toplevel BrowsingContext for new tab");
5543 if (!!(aChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) !=
5544 newBC->UseRemoteTabs() ||
5545 !!(aChromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW) !=
5546 newBC->UseRemoteSubframes()) {
5547 return IPC_FAIL(this, "Unexpected aChromeFlags passed");
5549 if (!aOriginAttributes.EqualsIgnoringFPD(newBC->OriginAttributesRef())) {
5550 return IPC_FAIL(this, "Opened tab has mismatched OriginAttributes");
5553 if (thisTab && BrowserParent::GetFrom(thisTab)->GetBrowsingContext()) {
5554 BrowsingContext* thisTabBC = thisTab->GetBrowsingContext();
5555 if (thisTabBC->UseRemoteTabs() != newBC->UseRemoteTabs() ||
5556 thisTabBC->UseRemoteSubframes() != newBC->UseRemoteSubframes() ||
5557 thisTabBC->UsePrivateBrowsing() != newBC->UsePrivateBrowsing()) {
5558 return IPC_FAIL(this, "New BrowsingContext has mismatched LoadContext");
5561 BrowserParent::AutoUseNewTab aunt(newTab);
5563 nsCOMPtr<nsIRemoteTab> newRemoteTab;
5564 int32_t openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
5565 mozilla::ipc::IPCResult ipcResult = CommonCreateWindow(
5566 aThisTab, *parent, newBCOpenerId != 0, aChromeFlags, aCalledFromJS,
5567 aForPrinting, aForWindowDotPrint, aIsTopLevelCreatedByWebContent,
5568 aURIToLoad, aFeatures, aModifiers, newTab, VoidString(), rv, newRemoteTab,
5569 &cwi.windowOpened(), openLocation, aTriggeringPrincipal, aReferrerInfo,
5570 /* aLoadUri = */ false, aCsp, aOriginAttributes, aUserActivation,
5571 aTextDirectiveUserActivation);
5572 if (!ipcResult) {
5573 return ipcResult;
5576 if (NS_WARN_IF(NS_FAILED(rv)) || !newRemoteTab) {
5577 return IPC_OK();
5580 MOZ_ASSERT(BrowserHost::GetFrom(newRemoteTab.get()) ==
5581 newTab->GetBrowserHost());
5583 // This used to happen in the child - there may now be a better place to
5584 // do this work.
5585 MOZ_ALWAYS_SUCCEEDS(newBC->SetHasSiblings(
5586 openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
5587 openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB_BACKGROUND));
5589 newTab->SwapFrameScriptsFrom(cwi.frameScripts());
5590 newTab->MaybeShowFrame();
5592 nsCOMPtr<nsIWidget> widget = newTab->GetWidget();
5593 if (widget) {
5594 cwi.dimensions() = newTab->GetDimensionInfo();
5597 cwi.maxTouchPoints() = newTab->GetMaxTouchPoints();
5599 return IPC_OK();
5602 mozilla::ipc::IPCResult ContentParent::RecvCreateWindowInDifferentProcess(
5603 PBrowserParent* aThisTab, const MaybeDiscarded<BrowsingContext>& aParent,
5604 const uint32_t& aChromeFlags, const bool& aCalledFromJS,
5605 const bool& aIsTopLevelCreatedByWebContent, nsIURI* aURIToLoad,
5606 const nsACString& aFeatures, const UserActivation::Modifiers& aModifiers,
5607 const nsAString& aName, nsIPrincipal* aTriggeringPrincipal,
5608 nsIContentSecurityPolicy* aCsp, nsIReferrerInfo* aReferrerInfo,
5609 const OriginAttributes& aOriginAttributes, bool aUserActivation,
5610 bool aTextDirectiveUserActivation) {
5611 MOZ_DIAGNOSTIC_ASSERT(!nsContentUtils::IsSpecialName(aName));
5613 // Don't continue to try to create a new window if we've been fully discarded.
5614 RefPtr<BrowsingContext> parent = aParent.GetMaybeDiscarded();
5615 if (NS_WARN_IF(!parent)) {
5616 return IPC_OK();
5619 nsCOMPtr<nsIRemoteTab> newRemoteTab;
5620 bool windowIsNew;
5621 int32_t openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
5623 // If we have enough data, check the schemes of the loader and loadee
5624 // to make sure they make sense.
5625 if (aURIToLoad && aURIToLoad->SchemeIs("file") &&
5626 GetRemoteType() != FILE_REMOTE_TYPE &&
5627 Preferences::GetBool("browser.tabs.remote.enforceRemoteTypeRestrictions",
5628 false)) {
5629 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
5630 # ifdef DEBUG
5631 nsAutoCString uriToLoadStr;
5632 nsAutoCString triggeringUriStr;
5633 aURIToLoad->GetAsciiSpec(uriToLoadStr);
5634 aTriggeringPrincipal->GetAsciiSpec(triggeringUriStr);
5636 NS_WARNING(nsPrintfCString(
5637 "RecvCreateWindowInDifferentProcess blocked loading file "
5638 "scheme from non-file remotetype: %s tried to load %s",
5639 triggeringUriStr.get(), uriToLoadStr.get())
5640 .get());
5641 # endif
5642 MOZ_CRASH(
5643 "RecvCreateWindowInDifferentProcess blocked loading improper scheme");
5644 #endif
5645 return IPC_OK();
5648 nsresult rv;
5649 mozilla::ipc::IPCResult ipcResult = CommonCreateWindow(
5650 aThisTab, *parent, /* aSetOpener = */ false, aChromeFlags, aCalledFromJS,
5651 /* aForPrinting = */ false,
5652 /* aForWindowDotPrint = */ false, aIsTopLevelCreatedByWebContent,
5653 aURIToLoad, aFeatures, aModifiers,
5654 /* aNextRemoteBrowser = */ nullptr, aName, rv, newRemoteTab, &windowIsNew,
5655 openLocation, aTriggeringPrincipal, aReferrerInfo,
5656 /* aLoadUri = */ true, aCsp, aOriginAttributes, aUserActivation,
5657 aTextDirectiveUserActivation);
5658 if (!ipcResult) {
5659 return ipcResult;
5662 if (NS_FAILED(rv)) {
5663 NS_WARNING("Call to CommonCreateWindow failed.");
5666 return IPC_OK();
5669 mozilla::ipc::IPCResult ContentParent::RecvShutdownProfile(
5670 const nsACString& aProfile) {
5671 profiler_received_exit_profile(aProfile);
5672 return IPC_OK();
5675 mozilla::ipc::IPCResult ContentParent::RecvShutdownPerfStats(
5676 const nsACString& aPerfStats) {
5677 PerfStats::StorePerfStats(this, aPerfStats);
5678 return IPC_OK();
5681 mozilla::ipc::IPCResult ContentParent::RecvGetFontListShmBlock(
5682 const uint32_t& aGeneration, const uint32_t& aIndex,
5683 base::SharedMemoryHandle* aOut) {
5684 auto* fontList = gfxPlatformFontList::PlatformFontList();
5685 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
5686 fontList->ShareFontListShmBlockToProcess(aGeneration, aIndex, Pid(), aOut);
5687 return IPC_OK();
5690 mozilla::ipc::IPCResult ContentParent::RecvInitializeFamily(
5691 const uint32_t& aGeneration, const uint32_t& aFamilyIndex,
5692 const bool& aLoadCmaps) {
5693 auto* fontList = gfxPlatformFontList::PlatformFontList();
5694 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
5695 fontList->InitializeFamily(aGeneration, aFamilyIndex, aLoadCmaps);
5696 return IPC_OK();
5699 mozilla::ipc::IPCResult ContentParent::RecvSetCharacterMap(
5700 const uint32_t& aGeneration, const uint32_t& aFamilyIndex,
5701 const bool& aAlias, const uint32_t& aFaceIndex,
5702 const gfxSparseBitSet& aMap) {
5703 auto* fontList = gfxPlatformFontList::PlatformFontList();
5704 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
5705 fontList->SetCharacterMap(aGeneration, aFamilyIndex, aAlias, aFaceIndex,
5706 aMap);
5707 return IPC_OK();
5710 mozilla::ipc::IPCResult ContentParent::RecvInitOtherFamilyNames(
5711 const uint32_t& aGeneration, const bool& aDefer, bool* aLoaded) {
5712 auto* fontList = gfxPlatformFontList::PlatformFontList();
5713 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
5714 *aLoaded = fontList->InitOtherFamilyNames(aGeneration, aDefer);
5715 return IPC_OK();
5718 mozilla::ipc::IPCResult ContentParent::RecvSetupFamilyCharMap(
5719 const uint32_t& aGeneration, const uint32_t& aIndex, const bool& aAlias) {
5720 auto* fontList = gfxPlatformFontList::PlatformFontList();
5721 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
5722 fontList->SetupFamilyCharMap(aGeneration, aIndex, aAlias);
5723 return IPC_OK();
5726 mozilla::ipc::IPCResult ContentParent::RecvStartCmapLoading(
5727 const uint32_t& aGeneration, const uint32_t& aStartIndex) {
5728 auto* fontList = gfxPlatformFontList::PlatformFontList();
5729 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
5730 fontList->StartCmapLoading(aGeneration, aStartIndex);
5731 return IPC_OK();
5734 mozilla::ipc::IPCResult ContentParent::RecvGetHyphDict(
5735 nsIURI* aURI, base::SharedMemoryHandle* aOutHandle, uint32_t* aOutSize) {
5736 if (!aURI) {
5737 return IPC_FAIL(this, "aURI must not be null.");
5739 nsHyphenationManager::Instance()->ShareHyphDictToProcess(
5740 aURI, Pid(), aOutHandle, aOutSize);
5741 return IPC_OK();
5744 mozilla::ipc::IPCResult ContentParent::RecvGraphicsError(
5745 const nsACString& aError) {
5746 if (gfx::LogForwarder* lf = gfx::Factory::GetLogForwarder()) {
5747 std::stringstream message;
5748 message << "CP+" << aError;
5749 lf->UpdateStringsVector(message.str());
5751 return IPC_OK();
5754 mozilla::ipc::IPCResult ContentParent::RecvBeginDriverCrashGuard(
5755 const uint32_t& aGuardType, bool* aOutCrashed) {
5756 // Only one driver crash guard should be active at a time, per-process.
5757 MOZ_ASSERT(!mDriverCrashGuard);
5759 UniquePtr<gfx::DriverCrashGuard> guard;
5760 switch (gfx::CrashGuardType(aGuardType)) {
5761 case gfx::CrashGuardType::D3D11Layers:
5762 guard = MakeUnique<gfx::D3D11LayersCrashGuard>(this);
5763 break;
5764 case gfx::CrashGuardType::GLContext:
5765 guard = MakeUnique<gfx::GLContextCrashGuard>(this);
5766 break;
5767 case gfx::CrashGuardType::WMFVPXVideo:
5768 guard = MakeUnique<gfx::WMFVPXVideoCrashGuard>(this);
5769 break;
5770 default:
5771 return IPC_FAIL(this, "unknown crash guard type");
5774 if (guard->Crashed()) {
5775 *aOutCrashed = true;
5776 return IPC_OK();
5779 *aOutCrashed = false;
5780 mDriverCrashGuard = std::move(guard);
5781 return IPC_OK();
5784 mozilla::ipc::IPCResult ContentParent::RecvEndDriverCrashGuard(
5785 const uint32_t& aGuardType) {
5786 mDriverCrashGuard = nullptr;
5787 return IPC_OK();
5790 mozilla::ipc::IPCResult ContentParent::RecvNotifyBenchmarkResult(
5791 const nsAString& aCodecName, const uint32_t& aDecodeFPS)
5794 if (aCodecName.EqualsLiteral("VP9")) {
5795 Preferences::SetUint(VP9Benchmark::sBenchmarkFpsPref, aDecodeFPS);
5796 Preferences::SetUint(VP9Benchmark::sBenchmarkFpsVersionCheck,
5797 VP9Benchmark::sBenchmarkVersionID);
5799 return IPC_OK();
5802 mozilla::ipc::IPCResult ContentParent::RecvNotifyPushObservers(
5803 const nsACString& aScope, nsIPrincipal* aPrincipal,
5804 const nsAString& aMessageId) {
5805 if (!aPrincipal) {
5806 return IPC_FAIL(this, "No principal");
5809 if (!ValidatePrincipal(aPrincipal)) {
5810 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
5812 PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId, Nothing());
5813 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
5814 return IPC_OK();
5817 mozilla::ipc::IPCResult ContentParent::RecvNotifyPushObserversWithData(
5818 const nsACString& aScope, nsIPrincipal* aPrincipal,
5819 const nsAString& aMessageId, nsTArray<uint8_t>&& aData) {
5820 if (!aPrincipal) {
5821 return IPC_FAIL(this, "No principal");
5824 if (!ValidatePrincipal(aPrincipal)) {
5825 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
5827 PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId,
5828 Some(std::move(aData)));
5829 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
5830 return IPC_OK();
5833 mozilla::ipc::IPCResult
5834 ContentParent::RecvNotifyPushSubscriptionChangeObservers(
5835 const nsACString& aScope, nsIPrincipal* aPrincipal) {
5836 if (!aPrincipal) {
5837 return IPC_FAIL(this, "No principal");
5840 if (!ValidatePrincipal(aPrincipal)) {
5841 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
5843 PushSubscriptionChangeDispatcher dispatcher(aScope, aPrincipal);
5844 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
5845 return IPC_OK();
5848 mozilla::ipc::IPCResult ContentParent::RecvPushError(const nsACString& aScope,
5849 nsIPrincipal* aPrincipal,
5850 const nsAString& aMessage,
5851 const uint32_t& aFlags) {
5852 if (!aPrincipal) {
5853 return IPC_FAIL(this, "No principal");
5856 if (!ValidatePrincipal(aPrincipal)) {
5857 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
5859 PushErrorDispatcher dispatcher(aScope, aPrincipal, aMessage, aFlags);
5860 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
5861 return IPC_OK();
5864 mozilla::ipc::IPCResult
5865 ContentParent::RecvNotifyPushSubscriptionModifiedObservers(
5866 const nsACString& aScope, nsIPrincipal* aPrincipal) {
5867 if (!aPrincipal) {
5868 return IPC_FAIL(this, "No principal");
5871 if (!ValidatePrincipal(aPrincipal)) {
5872 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
5874 PushSubscriptionModifiedDispatcher dispatcher(aScope, aPrincipal);
5875 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers()));
5876 return IPC_OK();
5879 /* static */
5880 void ContentParent::BroadcastBlobURLRegistration(const nsACString& aURI,
5881 BlobImpl* aBlobImpl,
5882 nsIPrincipal* aPrincipal,
5883 const nsCString& aPartitionKey,
5884 ContentParent* aIgnoreThisCP) {
5885 uint64_t originHash = ComputeLoadedOriginHash(aPrincipal);
5887 bool toBeSent =
5888 BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal);
5890 nsCString uri(aURI);
5892 for (auto* cp : AllProcesses(eLive)) {
5893 if (cp != aIgnoreThisCP) {
5894 if (!toBeSent && !cp->mLoadedOriginHashes.Contains(originHash)) {
5895 continue;
5898 nsresult rv = cp->TransmitPermissionsForPrincipal(aPrincipal);
5899 if (NS_WARN_IF(NS_FAILED(rv))) {
5900 break;
5903 IPCBlob ipcBlob;
5904 rv = IPCBlobUtils::Serialize(aBlobImpl, ipcBlob);
5905 if (NS_WARN_IF(NS_FAILED(rv))) {
5906 break;
5909 Unused << cp->SendBlobURLRegistration(uri, ipcBlob, aPrincipal,
5910 aPartitionKey);
5915 /* static */
5916 void ContentParent::BroadcastBlobURLUnregistration(
5917 const nsACString& aURI, nsIPrincipal* aPrincipal,
5918 ContentParent* aIgnoreThisCP) {
5919 uint64_t originHash = ComputeLoadedOriginHash(aPrincipal);
5921 bool toBeSent =
5922 BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal);
5924 nsCString uri(aURI);
5926 for (auto* cp : AllProcesses(eLive)) {
5927 if (cp != aIgnoreThisCP &&
5928 (toBeSent || cp->mLoadedOriginHashes.Contains(originHash))) {
5929 Unused << cp->SendBlobURLUnregistration(uri);
5934 mozilla::ipc::IPCResult ContentParent::RecvStoreAndBroadcastBlobURLRegistration(
5935 const nsACString& aURI, const IPCBlob& aBlob, nsIPrincipal* aPrincipal,
5936 const nsCString& aPartitionKey) {
5937 if (!aPrincipal) {
5938 return IPC_FAIL(this, "No principal");
5941 if (!ValidatePrincipal(aPrincipal, {ValidatePrincipalOptions::AllowSystem})) {
5942 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
5944 RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(aBlob);
5945 if (NS_WARN_IF(!blobImpl)) {
5946 return IPC_FAIL(this, "Blob deserialization failed.");
5949 BlobURLProtocolHandler::AddDataEntry(aURI, aPrincipal, aPartitionKey,
5950 blobImpl);
5951 BroadcastBlobURLRegistration(aURI, blobImpl, aPrincipal, aPartitionKey, this);
5953 // We want to store this blobURL, so we can unregister it if the child
5954 // crashes.
5955 mBlobURLs.AppendElement(aURI);
5957 return IPC_OK();
5960 mozilla::ipc::IPCResult
5961 ContentParent::RecvUnstoreAndBroadcastBlobURLUnregistration(
5962 const nsACString& aURI, nsIPrincipal* aPrincipal) {
5963 if (!aPrincipal) {
5964 return IPC_FAIL(this, "No principal");
5967 if (!ValidatePrincipal(aPrincipal, {ValidatePrincipalOptions::AllowSystem})) {
5968 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
5970 BlobURLProtocolHandler::RemoveDataEntry(aURI, false /* Don't broadcast */);
5971 BroadcastBlobURLUnregistration(aURI, aPrincipal, this);
5972 mBlobURLs.RemoveElement(aURI);
5973 return IPC_OK();
5976 mozilla::ipc::IPCResult ContentParent::RecvGetFilesRequest(
5977 const nsID& aID, const nsAString& aDirectoryPath,
5978 const bool& aRecursiveFlag) {
5979 MOZ_ASSERT(!mGetFilesPendingRequests.GetWeak(aID));
5981 if (!mozilla::Preferences::GetBool("dom.filesystem.pathcheck.disabled",
5982 false)) {
5983 RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get();
5984 if (!fss) {
5985 return IPC_FAIL(this, "Failed to get FileSystemSecurity.");
5988 if (!fss->ContentProcessHasAccessTo(ChildID(), aDirectoryPath)) {
5989 return IPC_FAIL(this, "ContentProcessHasAccessTo failed.");
5993 ErrorResult rv;
5994 RefPtr<GetFilesHelper> helper = GetFilesHelperParent::Create(
5995 aID, aDirectoryPath, aRecursiveFlag, this, rv);
5997 if (NS_WARN_IF(rv.Failed())) {
5998 if (!SendGetFilesResponse(aID,
5999 GetFilesResponseFailure(rv.StealNSResult()))) {
6000 return IPC_FAIL(this, "SendGetFilesResponse failed.");
6002 return IPC_OK();
6005 mGetFilesPendingRequests.InsertOrUpdate(aID, std::move(helper));
6006 return IPC_OK();
6009 mozilla::ipc::IPCResult ContentParent::RecvDeleteGetFilesRequest(
6010 const nsID& aID) {
6011 mGetFilesPendingRequests.Remove(aID);
6012 return IPC_OK();
6015 void ContentParent::SendGetFilesResponseAndForget(
6016 const nsID& aID, const GetFilesResponseResult& aResult) {
6017 if (mGetFilesPendingRequests.Remove(aID)) {
6018 Unused << SendGetFilesResponse(aID, aResult);
6022 void ContentParent::PaintTabWhileInterruptingJS(BrowserParent* aBrowserParent) {
6023 if (!mHangMonitorActor) {
6024 return;
6026 ProcessHangMonitor::PaintWhileInterruptingJS(mHangMonitorActor,
6027 aBrowserParent);
6030 void ContentParent::UnloadLayersWhileInterruptingJS(
6031 BrowserParent* aBrowserParent) {
6032 if (!mHangMonitorActor) {
6033 return;
6035 ProcessHangMonitor::UnloadLayersWhileInterruptingJS(mHangMonitorActor,
6036 aBrowserParent);
6039 void ContentParent::CancelContentJSExecutionIfRunning(
6040 BrowserParent* aBrowserParent, nsIRemoteTab::NavigationType aNavigationType,
6041 const CancelContentJSOptions& aCancelContentJSOptions) {
6042 if (!mHangMonitorActor) {
6043 return;
6046 ProcessHangMonitor::CancelContentJSExecutionIfRunning(
6047 mHangMonitorActor, aBrowserParent, aNavigationType,
6048 aCancelContentJSOptions);
6051 void ContentParent::SetMainThreadQoSPriority(
6052 nsIThread::QoSPriority aQoSPriority) {
6053 if (!mHangMonitorActor) {
6054 return;
6057 ProcessHangMonitor::SetMainThreadQoSPriority(mHangMonitorActor, aQoSPriority);
6060 void ContentParent::UpdateCookieStatus(nsIChannel* aChannel) {
6061 PNeckoParent* neckoParent = LoneManagedOrNullAsserts(ManagedPNeckoParent());
6062 PCookieServiceParent* csParent =
6063 LoneManagedOrNullAsserts(neckoParent->ManagedPCookieServiceParent());
6064 if (csParent) {
6065 auto* cs = static_cast<CookieServiceParent*>(csParent);
6066 cs->TrackCookieLoad(aChannel);
6070 nsresult ContentParent::AboutToLoadHttpDocumentForChild(
6071 nsIChannel* aChannel, bool* aShouldWaitForPermissionCookieUpdate) {
6072 MOZ_ASSERT(aChannel);
6074 if (aShouldWaitForPermissionCookieUpdate) {
6075 *aShouldWaitForPermissionCookieUpdate = false;
6078 nsresult rv;
6079 bool isDocument = aChannel->IsDocument();
6080 if (!isDocument) {
6081 // We may be looking at a nsIHttpChannel which has isMainDocumentChannel set
6082 // (e.g. the internal http channel for a view-source: load.).
6083 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
6084 if (httpChannel) {
6085 rv = httpChannel->GetIsMainDocumentChannel(&isDocument);
6086 NS_ENSURE_SUCCESS(rv, rv);
6089 if (!isDocument) {
6090 return NS_OK;
6093 // Get the principal for the channel result, so that we can get the permission
6094 // key for the document which will be created from this response.
6095 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
6096 if (NS_WARN_IF(!ssm)) {
6097 return NS_ERROR_FAILURE;
6100 nsCOMPtr<nsIPrincipal> principal;
6101 nsCOMPtr<nsIPrincipal> partitionedPrincipal;
6102 rv = ssm->GetChannelResultPrincipals(aChannel, getter_AddRefs(principal),
6103 getter_AddRefs(partitionedPrincipal));
6104 NS_ENSURE_SUCCESS(rv, rv);
6106 // Let the caller know we're going to send main thread IPC for updating
6107 // permisssions/cookies.
6108 if (aShouldWaitForPermissionCookieUpdate) {
6109 *aShouldWaitForPermissionCookieUpdate = true;
6112 TransmitBlobURLsForPrincipal(principal);
6114 // Tranmit permissions for both regular and partitioned principal so that the
6115 // content process can get permissions for the partitioned principal. For
6116 // example, the desk-notification permission for a partitioned service worker.
6117 rv = TransmitPermissionsForPrincipal(principal);
6118 NS_ENSURE_SUCCESS(rv, rv);
6120 rv = TransmitPermissionsForPrincipal(partitionedPrincipal);
6121 NS_ENSURE_SUCCESS(rv, rv);
6123 nsLoadFlags newLoadFlags;
6124 aChannel->GetLoadFlags(&newLoadFlags);
6125 if (newLoadFlags & nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE) {
6126 UpdateCookieStatus(aChannel);
6129 RefPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
6130 RefPtr<BrowsingContext> browsingContext;
6131 rv = loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext));
6132 NS_ENSURE_SUCCESS(rv, rv);
6134 if (!NextGenLocalStorageEnabled()) {
6135 return NS_OK;
6138 if (principal->GetIsContentPrincipal()) {
6139 nsCOMPtr<nsILocalStorageManager> lsm =
6140 do_GetService("@mozilla.org/dom/localStorage-manager;1");
6141 if (NS_WARN_IF(!lsm)) {
6142 return NS_ERROR_FAILURE;
6145 nsCOMPtr<nsIPrincipal> storagePrincipal;
6146 rv = ssm->GetChannelResultStoragePrincipal(
6147 aChannel, getter_AddRefs(storagePrincipal));
6148 NS_ENSURE_SUCCESS(rv, rv);
6150 RefPtr<Promise> dummy;
6151 rv = lsm->Preload(storagePrincipal, nullptr, getter_AddRefs(dummy));
6152 if (NS_FAILED(rv)) {
6153 NS_WARNING("Failed to preload local storage!");
6157 return NS_OK;
6160 nsresult ContentParent::TransmitPermissionsForPrincipal(
6161 nsIPrincipal* aPrincipal) {
6162 // Create the key, and send it down to the content process.
6163 nsTArray<std::pair<nsCString, nsCString>> pairs =
6164 PermissionManager::GetAllKeysForPrincipal(aPrincipal);
6165 MOZ_ASSERT(pairs.Length() >= 1);
6166 for (auto& pair : pairs) {
6167 EnsurePermissionsByKey(pair.first, pair.second);
6170 // We need to add the Site to the secondary keys of interest here.
6171 // This allows site-scoped permission updates to propogate when the
6172 // port is non-standard.
6173 nsAutoCString siteKey;
6174 nsresult rv =
6175 PermissionManager::GetKeyForPrincipal(aPrincipal, false, true, siteKey);
6176 if (NS_SUCCEEDED(rv) && !siteKey.IsEmpty()) {
6177 mActiveSecondaryPermissionKeys.EnsureInserted(siteKey);
6180 return NS_OK;
6183 void ContentParent::TransmitBlobURLsForPrincipal(nsIPrincipal* aPrincipal) {
6184 // If we're already broadcasting BlobURLs with this principal, we don't need
6185 // to send them here.
6186 if (BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal)) {
6187 return;
6190 // We shouldn't have any Blob URLs with expanded principals, so transmit URLs
6191 // for each principal in the AllowList instead.
6192 if (nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(aPrincipal)) {
6193 for (const auto& prin : ep->AllowList()) {
6194 TransmitBlobURLsForPrincipal(prin);
6196 return;
6199 uint64_t originHash = ComputeLoadedOriginHash(aPrincipal);
6201 if (!mLoadedOriginHashes.Contains(originHash)) {
6202 mLoadedOriginHashes.AppendElement(originHash);
6204 nsTArray<BlobURLRegistrationData> registrations;
6205 BlobURLProtocolHandler::ForEachBlobURL(
6206 [&](BlobImpl* aBlobImpl, nsIPrincipal* aBlobPrincipal,
6207 const nsCString& aPartitionKey, const nsACString& aURI,
6208 bool aRevoked) {
6209 // This check uses `ComputeLoadedOriginHash` to compare, rather than
6210 // doing the more accurate `Equals` check, as it needs to match the
6211 // behaviour of the logic to broadcast new registrations.
6212 if (originHash != ComputeLoadedOriginHash(aBlobPrincipal)) {
6213 return true;
6216 IPCBlob ipcBlob;
6217 nsresult rv = IPCBlobUtils::Serialize(aBlobImpl, ipcBlob);
6218 if (NS_WARN_IF(NS_FAILED(rv))) {
6219 return false;
6222 registrations.AppendElement(
6223 BlobURLRegistrationData(nsCString(aURI), ipcBlob, aPrincipal,
6224 nsCString(aPartitionKey), aRevoked));
6226 rv = TransmitPermissionsForPrincipal(aBlobPrincipal);
6227 Unused << NS_WARN_IF(NS_FAILED(rv));
6228 return true;
6231 if (!registrations.IsEmpty()) {
6232 Unused << SendInitBlobURLs(registrations);
6237 void ContentParent::TransmitBlobDataIfBlobURL(nsIURI* aURI) {
6238 MOZ_ASSERT(aURI);
6240 nsCOMPtr<nsIPrincipal> principal;
6241 if (BlobURLProtocolHandler::GetBlobURLPrincipal(aURI,
6242 getter_AddRefs(principal))) {
6243 TransmitBlobURLsForPrincipal(principal);
6247 void ContentParent::EnsurePermissionsByKey(const nsACString& aKey,
6248 const nsACString& aOrigin) {
6249 // NOTE: Make sure to initialize the permission manager before updating the
6250 // mActivePermissionKeys list. If the permission manager is being initialized
6251 // by this call to GetPermissionManager, and we've added the key to
6252 // mActivePermissionKeys, then the permission manager will send down a
6253 // SendAddPermission before receiving the SendSetPermissionsWithKey message.
6254 RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
6255 if (!permManager) {
6256 return;
6259 if (!mActivePermissionKeys.EnsureInserted(aKey)) {
6260 return;
6263 nsTArray<IPC::Permission> perms;
6264 if (permManager->GetPermissionsFromOriginOrKey(aOrigin, aKey, perms)) {
6265 Unused << SendSetPermissionsWithKey(aKey, perms);
6269 bool ContentParent::NeedsPermissionsUpdate(
6270 const nsACString& aPermissionKey) const {
6271 return mActivePermissionKeys.Contains(aPermissionKey);
6274 bool ContentParent::NeedsSecondaryKeyPermissionsUpdate(
6275 const nsACString& aPermissionKey) const {
6276 return mActiveSecondaryPermissionKeys.Contains(aPermissionKey);
6279 mozilla::ipc::IPCResult ContentParent::RecvAccumulateChildHistograms(
6280 nsTArray<HistogramAccumulation>&& aAccumulations) {
6281 TelemetryIPC::AccumulateChildHistograms(GetTelemetryProcessID(mRemoteType),
6282 aAccumulations);
6283 return IPC_OK();
6286 mozilla::ipc::IPCResult ContentParent::RecvAccumulateChildKeyedHistograms(
6287 nsTArray<KeyedHistogramAccumulation>&& aAccumulations) {
6288 TelemetryIPC::AccumulateChildKeyedHistograms(
6289 GetTelemetryProcessID(mRemoteType), aAccumulations);
6290 return IPC_OK();
6293 mozilla::ipc::IPCResult ContentParent::RecvUpdateChildScalars(
6294 nsTArray<ScalarAction>&& aScalarActions) {
6295 TelemetryIPC::UpdateChildScalars(GetTelemetryProcessID(mRemoteType),
6296 aScalarActions);
6297 return IPC_OK();
6300 mozilla::ipc::IPCResult ContentParent::RecvUpdateChildKeyedScalars(
6301 nsTArray<KeyedScalarAction>&& aScalarActions) {
6302 TelemetryIPC::UpdateChildKeyedScalars(GetTelemetryProcessID(mRemoteType),
6303 aScalarActions);
6304 return IPC_OK();
6307 mozilla::ipc::IPCResult ContentParent::RecvRecordChildEvents(
6308 nsTArray<mozilla::Telemetry::ChildEventData>&& aEvents) {
6309 TelemetryIPC::RecordChildEvents(GetTelemetryProcessID(mRemoteType), aEvents);
6310 return IPC_OK();
6313 mozilla::ipc::IPCResult ContentParent::RecvRecordDiscardedData(
6314 const mozilla::Telemetry::DiscardedData& aDiscardedData) {
6315 TelemetryIPC::RecordDiscardedData(GetTelemetryProcessID(mRemoteType),
6316 aDiscardedData);
6317 return IPC_OK();
6320 static bool WebdriverRunning() {
6321 #ifdef ENABLE_WEBDRIVER
6322 nsCOMPtr<nsIMarionette> marionette = do_GetService(NS_MARIONETTE_CONTRACTID);
6323 if (marionette) {
6324 bool marionetteRunning = false;
6325 marionette->GetRunning(&marionetteRunning);
6326 if (marionetteRunning) {
6327 return true;
6331 nsCOMPtr<nsIRemoteAgent> agent = do_GetService(NS_REMOTEAGENT_CONTRACTID);
6332 if (agent) {
6333 bool remoteAgentRunning = false;
6334 agent->GetRunning(&remoteAgentRunning);
6335 if (remoteAgentRunning) {
6336 return true;
6339 #endif
6341 return false;
6344 mozilla::ipc::IPCResult ContentParent::RecvRecordPageLoadEvent(
6345 mozilla::glean::perf::PageLoadExtra&& aPageLoadEventExtra) {
6346 // Check whether a webdriver is running.
6347 aPageLoadEventExtra.usingWebdriver = mozilla::Some(WebdriverRunning());
6348 mozilla::glean::perf::page_load.Record(mozilla::Some(aPageLoadEventExtra));
6350 // Send the PageLoadPing after every 30 page loads, or on startup.
6351 if (++sPageLoadEventCounter >= 30) {
6352 NS_SUCCEEDED(NS_DispatchToMainThreadQueue(
6353 NS_NewRunnableFunction(
6354 "PageLoadPingIdleTask",
6355 [] { mozilla::glean_pings::Pageload.Submit("threshold"_ns); }),
6356 EventQueuePriority::Idle));
6357 sPageLoadEventCounter = 0;
6360 return IPC_OK();
6363 //////////////////////////////////////////////////////////////////
6364 // PURLClassifierParent
6366 PURLClassifierParent* ContentParent::AllocPURLClassifierParent(
6367 nsIPrincipal* aPrincipal, bool* aSuccess) {
6368 MOZ_ASSERT(NS_IsMainThread());
6370 *aSuccess = true;
6371 RefPtr<URLClassifierParent> actor = new URLClassifierParent();
6372 return actor.forget().take();
6375 mozilla::ipc::IPCResult ContentParent::RecvPURLClassifierConstructor(
6376 PURLClassifierParent* aActor, nsIPrincipal* aPrincipal, bool* aSuccess) {
6377 MOZ_ASSERT(NS_IsMainThread());
6378 MOZ_ASSERT(aActor);
6379 *aSuccess = false;
6381 auto* actor = static_cast<URLClassifierParent*>(aActor);
6382 nsCOMPtr<nsIPrincipal> principal(aPrincipal);
6383 if (!principal) {
6384 actor->ClassificationFailed();
6385 return IPC_OK();
6387 if (!ValidatePrincipal(aPrincipal)) {
6388 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
6390 return actor->StartClassify(principal, aSuccess);
6393 bool ContentParent::DeallocPURLClassifierParent(PURLClassifierParent* aActor) {
6394 MOZ_ASSERT(NS_IsMainThread());
6395 MOZ_ASSERT(aActor);
6397 RefPtr<URLClassifierParent> actor =
6398 dont_AddRef(static_cast<URLClassifierParent*>(aActor));
6399 return true;
6402 //////////////////////////////////////////////////////////////////
6403 // PURLClassifierLocalParent
6405 PURLClassifierLocalParent* ContentParent::AllocPURLClassifierLocalParent(
6406 nsIURI* aURI, const nsTArray<IPCURLClassifierFeature>& aFeatures) {
6407 MOZ_ASSERT(NS_IsMainThread());
6409 RefPtr<URLClassifierLocalParent> actor = new URLClassifierLocalParent();
6410 return actor.forget().take();
6413 mozilla::ipc::IPCResult ContentParent::RecvPURLClassifierLocalConstructor(
6414 PURLClassifierLocalParent* aActor, nsIURI* aURI,
6415 nsTArray<IPCURLClassifierFeature>&& aFeatures) {
6416 MOZ_ASSERT(NS_IsMainThread());
6417 MOZ_ASSERT(aActor);
6419 nsTArray<IPCURLClassifierFeature> features = std::move(aFeatures);
6421 if (!aURI) {
6422 return IPC_FAIL(this, "aURI should not be null");
6425 auto* actor = static_cast<URLClassifierLocalParent*>(aActor);
6426 return actor->StartClassify(aURI, features);
6429 bool ContentParent::DeallocPURLClassifierLocalParent(
6430 PURLClassifierLocalParent* aActor) {
6431 MOZ_ASSERT(NS_IsMainThread());
6432 MOZ_ASSERT(aActor);
6434 RefPtr<URLClassifierLocalParent> actor =
6435 dont_AddRef(static_cast<URLClassifierLocalParent*>(aActor));
6436 return true;
6439 PSessionStorageObserverParent*
6440 ContentParent::AllocPSessionStorageObserverParent() {
6441 MOZ_ASSERT(NS_IsMainThread());
6443 return mozilla::dom::AllocPSessionStorageObserverParent();
6446 mozilla::ipc::IPCResult ContentParent::RecvPSessionStorageObserverConstructor(
6447 PSessionStorageObserverParent* aActor) {
6448 MOZ_ASSERT(NS_IsMainThread());
6449 MOZ_ASSERT(aActor);
6451 if (!mozilla::dom::RecvPSessionStorageObserverConstructor(aActor)) {
6452 return IPC_FAIL(this, "RecvPSessionStorageObserverConstructor failed.");
6454 return IPC_OK();
6457 bool ContentParent::DeallocPSessionStorageObserverParent(
6458 PSessionStorageObserverParent* aActor) {
6459 MOZ_ASSERT(NS_IsMainThread());
6460 MOZ_ASSERT(aActor);
6462 return mozilla::dom::DeallocPSessionStorageObserverParent(aActor);
6465 mozilla::ipc::IPCResult ContentParent::RecvBHRThreadHang(
6466 const HangDetails& aHangDetails) {
6467 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
6468 if (obs) {
6469 // Copy the HangDetails recieved over the network into a nsIHangDetails, and
6470 // then fire our own observer notification.
6471 // XXX: We should be able to avoid this potentially expensive copy here by
6472 // moving our deserialized argument.
6473 nsCOMPtr<nsIHangDetails> hangDetails =
6474 new nsHangDetails(HangDetails(aHangDetails), PersistedToDisk::No);
6475 obs->NotifyObservers(hangDetails, "bhr-thread-hang", nullptr);
6477 return IPC_OK();
6480 mozilla::ipc::IPCResult ContentParent::RecvAddCertException(
6481 nsIX509Cert* aCert, const nsACString& aHostName, int32_t aPort,
6482 const OriginAttributes& aOriginAttributes, bool aIsTemporary,
6483 AddCertExceptionResolver&& aResolver) {
6484 nsCOMPtr<nsICertOverrideService> overrideService =
6485 do_GetService(NS_CERTOVERRIDE_CONTRACTID);
6486 if (!overrideService) {
6487 aResolver(NS_ERROR_FAILURE);
6488 return IPC_OK();
6490 nsresult rv = overrideService->RememberValidityOverride(
6491 aHostName, aPort, aOriginAttributes, aCert, aIsTemporary);
6492 aResolver(rv);
6493 return IPC_OK();
6496 mozilla::ipc::IPCResult
6497 ContentParent::RecvAutomaticStorageAccessPermissionCanBeGranted(
6498 nsIPrincipal* aPrincipal,
6499 AutomaticStorageAccessPermissionCanBeGrantedResolver&& aResolver) {
6500 if (!aPrincipal) {
6501 return IPC_FAIL(this, "No principal");
6504 if (!ValidatePrincipal(aPrincipal)) {
6505 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
6507 aResolver(Document::AutomaticStorageAccessPermissionCanBeGranted(aPrincipal));
6508 return IPC_OK();
6511 mozilla::ipc::IPCResult
6512 ContentParent::RecvStorageAccessPermissionGrantedForOrigin(
6513 uint64_t aTopLevelWindowId,
6514 const MaybeDiscarded<BrowsingContext>& aParentContext,
6515 nsIPrincipal* aTrackingPrincipal, const nsACString& aTrackingOrigin,
6516 const int& aAllowMode,
6517 const Maybe<ContentBlockingNotifier::StorageAccessPermissionGrantedReason>&
6518 aReason,
6519 const bool& aFrameOnly,
6520 StorageAccessPermissionGrantedForOriginResolver&& aResolver) {
6521 if (aParentContext.IsNullOrDiscarded()) {
6522 return IPC_OK();
6525 if (!aTrackingPrincipal) {
6526 return IPC_FAIL(this, "No principal");
6529 // We only report here if we cannot report the console directly in the content
6530 // process. In that case, the `aReason` would be given a value. Otherwise, it
6531 // will be nothing.
6532 if (aReason) {
6533 ContentBlockingNotifier::ReportUnblockingToConsole(
6534 aParentContext.get_canonical(), NS_ConvertUTF8toUTF16(aTrackingOrigin),
6535 aReason.value());
6538 StorageAccessAPIHelper::SaveAccessForOriginOnParentProcess(
6539 aTopLevelWindowId, aParentContext.get_canonical(), aTrackingPrincipal,
6540 aAllowMode, aFrameOnly)
6541 ->Then(GetCurrentSerialEventTarget(), __func__,
6542 [aResolver = std::move(aResolver)](
6543 StorageAccessAPIHelper::ParentAccessGrantPromise::
6544 ResolveOrRejectValue&& aValue) {
6545 bool success =
6546 aValue.IsResolve() && NS_SUCCEEDED(aValue.ResolveValue());
6547 aResolver(success);
6549 return IPC_OK();
6552 mozilla::ipc::IPCResult ContentParent::RecvCompleteAllowAccessFor(
6553 const MaybeDiscarded<BrowsingContext>& aParentContext,
6554 uint64_t aTopLevelWindowId, nsIPrincipal* aTrackingPrincipal,
6555 const nsACString& aTrackingOrigin, uint32_t aCookieBehavior,
6556 const ContentBlockingNotifier::StorageAccessPermissionGrantedReason&
6557 aReason,
6558 CompleteAllowAccessForResolver&& aResolver) {
6559 if (aParentContext.IsNullOrDiscarded()) {
6560 return IPC_OK();
6563 StorageAccessAPIHelper::CompleteAllowAccessForOnParentProcess(
6564 aParentContext.get_canonical(), aTopLevelWindowId, aTrackingPrincipal,
6565 aTrackingOrigin, aCookieBehavior, aReason, nullptr)
6566 ->Then(GetCurrentSerialEventTarget(), __func__,
6567 [aResolver = std::move(aResolver)](
6568 StorageAccessAPIHelper::StorageAccessPermissionGrantPromise::
6569 ResolveOrRejectValue&& aValue) {
6570 Maybe<StorageAccessPromptChoices> choice;
6571 if (aValue.IsResolve()) {
6572 choice.emplace(static_cast<StorageAccessPromptChoices>(
6573 aValue.ResolveValue()));
6575 aResolver(choice);
6577 return IPC_OK();
6580 mozilla::ipc::IPCResult ContentParent::RecvSetAllowStorageAccessRequestFlag(
6581 nsIPrincipal* aEmbeddedPrincipal, nsIURI* aEmbeddingOrigin,
6582 SetAllowStorageAccessRequestFlagResolver&& aResolver) {
6583 MOZ_ASSERT(aEmbeddedPrincipal);
6584 MOZ_ASSERT(aEmbeddingOrigin);
6586 if (!aEmbeddedPrincipal || !aEmbeddingOrigin) {
6587 aResolver(false);
6588 return IPC_OK();
6591 // Get the permission manager and build the key.
6592 RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
6593 if (!permManager) {
6594 aResolver(false);
6595 return IPC_OK();
6597 nsCOMPtr<nsIURI> embeddedURI = aEmbeddedPrincipal->GetURI();
6598 nsCString permissionKey;
6599 bool success = AntiTrackingUtils::CreateStorageRequestPermissionKey(
6600 embeddedURI, permissionKey);
6601 if (!success) {
6602 aResolver(false);
6603 return IPC_OK();
6606 // Set the permission to ALLOW for a prefence specified amount of seconds.
6607 // Time units are inconsistent, be careful
6608 int64_t when = (PR_Now() / PR_USEC_PER_MSEC) +
6609 StaticPrefs::dom_storage_access_forward_declared_lifetime() *
6610 PR_MSEC_PER_SEC;
6611 nsCOMPtr<nsIPrincipal> principal = BasePrincipal::CreateContentPrincipal(
6612 aEmbeddingOrigin, aEmbeddedPrincipal->OriginAttributesRef());
6613 nsresult rv = permManager->AddFromPrincipal(
6614 principal, permissionKey, nsIPermissionManager::ALLOW_ACTION,
6615 nsIPermissionManager::EXPIRE_TIME, when);
6616 if (NS_FAILED(rv)) {
6617 aResolver(false);
6618 return IPC_OK();
6621 // Resolve with success if we set the permission.
6622 aResolver(true);
6623 return IPC_OK();
6626 mozilla::ipc::IPCResult ContentParent::RecvTestAllowStorageAccessRequestFlag(
6627 nsIPrincipal* aEmbeddingPrincipal, nsIURI* aEmbeddedOrigin,
6628 TestAllowStorageAccessRequestFlagResolver&& aResolver) {
6629 MOZ_ASSERT(aEmbeddingPrincipal);
6630 MOZ_ASSERT(aEmbeddedOrigin);
6632 // Get the permission manager and build the key.
6633 RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
6634 if (!permManager) {
6635 aResolver(false);
6636 return IPC_OK();
6638 nsCString requestPermissionKey;
6639 bool success = AntiTrackingUtils::CreateStorageRequestPermissionKey(
6640 aEmbeddedOrigin, requestPermissionKey);
6641 if (!success) {
6642 aResolver(false);
6643 return IPC_OK();
6646 // Get the permission and resolve false if it is not set to ALLOW.
6647 uint32_t access = nsIPermissionManager::UNKNOWN_ACTION;
6648 nsresult rv = permManager->TestPermissionFromPrincipal(
6649 aEmbeddingPrincipal, requestPermissionKey, &access);
6650 if (NS_FAILED(rv)) {
6651 aResolver(false);
6652 return IPC_OK();
6654 if (access != nsIPermissionManager::ALLOW_ACTION) {
6655 aResolver(false);
6656 return IPC_OK();
6659 // Remove the permission, failing if the permission manager fails
6660 rv = permManager->RemoveFromPrincipal(aEmbeddingPrincipal,
6661 requestPermissionKey);
6662 if (NS_FAILED(rv)) {
6663 aResolver(false);
6664 return IPC_OK();
6667 // At this point, signal to our caller that the permission was set
6668 aResolver(true);
6669 return IPC_OK();
6672 mozilla::ipc::IPCResult ContentParent::RecvStoreUserInteractionAsPermission(
6673 nsIPrincipal* aPrincipal) {
6674 if (!aPrincipal) {
6675 return IPC_FAIL(this, "No principal");
6678 if (!ValidatePrincipal(aPrincipal)) {
6679 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
6681 ContentBlockingUserInteraction::Observe(aPrincipal);
6682 return IPC_OK();
6685 mozilla::ipc::IPCResult ContentParent::RecvTestCookiePermissionDecided(
6686 const MaybeDiscarded<BrowsingContext>& aContext, nsIPrincipal* aPrincipal,
6687 const TestCookiePermissionDecidedResolver&& aResolver) {
6688 if (aContext.IsNullOrDiscarded()) {
6689 return IPC_OK();
6692 if (!aPrincipal) {
6693 return IPC_FAIL(this, "No principal");
6696 RefPtr<WindowGlobalParent> wgp =
6697 aContext.get_canonical()->GetCurrentWindowGlobal();
6698 nsCOMPtr<nsICookieJarSettings> cjs = wgp->CookieJarSettings();
6700 Maybe<bool> result =
6701 StorageAccessAPIHelper::CheckCookiesPermittedDecidesStorageAccessAPI(
6702 cjs, aPrincipal);
6703 aResolver(result);
6704 return IPC_OK();
6707 mozilla::ipc::IPCResult ContentParent::RecvTestStorageAccessPermission(
6708 nsIPrincipal* aEmbeddingPrincipal, const nsCString& aEmbeddedOrigin,
6709 const TestStorageAccessPermissionResolver&& aResolver) {
6710 // Get the permission manager and build the key.
6711 RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
6712 if (!permManager) {
6713 aResolver(Nothing());
6714 return IPC_OK();
6716 nsCString requestPermissionKey;
6717 AntiTrackingUtils::CreateStoragePermissionKey(aEmbeddedOrigin,
6718 requestPermissionKey);
6720 // Test the permission
6721 uint32_t access = nsIPermissionManager::UNKNOWN_ACTION;
6722 nsresult rv = permManager->TestPermissionFromPrincipal(
6723 aEmbeddingPrincipal, requestPermissionKey, &access);
6724 if (NS_FAILED(rv)) {
6725 aResolver(Nothing());
6726 return IPC_OK();
6728 if (access == nsIPermissionManager::ALLOW_ACTION) {
6729 aResolver(Some(true));
6730 } else if (access == nsIPermissionManager::DENY_ACTION) {
6731 aResolver(Some(false));
6732 } else {
6733 aResolver(Nothing());
6736 return IPC_OK();
6739 mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaPlaybackChanged(
6740 const MaybeDiscarded<BrowsingContext>& aContext,
6741 MediaPlaybackState aState) {
6742 if (aContext.IsNullOrDiscarded()) {
6743 return IPC_OK();
6745 if (RefPtr<IMediaInfoUpdater> updater =
6746 aContext.get_canonical()->GetMediaController()) {
6747 updater->NotifyMediaPlaybackChanged(aContext.ContextId(), aState);
6749 return IPC_OK();
6752 mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaAudibleChanged(
6753 const MaybeDiscarded<BrowsingContext>& aContext, MediaAudibleState aState) {
6754 if (aContext.IsNullOrDiscarded()) {
6755 return IPC_OK();
6757 if (RefPtr<IMediaInfoUpdater> updater =
6758 aContext.get_canonical()->GetMediaController()) {
6759 updater->NotifyMediaAudibleChanged(aContext.ContextId(), aState);
6761 return IPC_OK();
6764 mozilla::ipc::IPCResult ContentParent::RecvNotifyPictureInPictureModeChanged(
6765 const MaybeDiscarded<BrowsingContext>& aContext, bool aEnabled) {
6766 if (aContext.IsNullOrDiscarded()) {
6767 return IPC_OK();
6769 if (RefPtr<MediaController> controller =
6770 aContext.get_canonical()->GetMediaController()) {
6771 controller->SetIsInPictureInPictureMode(aContext.ContextId(), aEnabled);
6773 return IPC_OK();
6776 mozilla::ipc::IPCResult ContentParent::RecvAbortOtherOrientationPendingPromises(
6777 const MaybeDiscarded<BrowsingContext>& aContext) {
6778 if (aContext.IsNullOrDiscarded()) {
6779 return IPC_OK();
6782 CanonicalBrowsingContext* context = aContext.get_canonical();
6784 context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
6785 Unused << aParent->SendAbortOrientationPendingPromises(context);
6788 return IPC_OK();
6791 mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaSessionUpdated(
6792 const MaybeDiscarded<BrowsingContext>& aContext, bool aIsCreated) {
6793 if (aContext.IsNullOrDiscarded()) {
6794 return IPC_OK();
6797 RefPtr<IMediaInfoUpdater> updater =
6798 aContext.get_canonical()->GetMediaController();
6799 if (!updater) {
6800 return IPC_OK();
6802 if (aIsCreated) {
6803 updater->NotifySessionCreated(aContext->Id());
6804 } else {
6805 updater->NotifySessionDestroyed(aContext->Id());
6807 return IPC_OK();
6810 mozilla::ipc::IPCResult ContentParent::RecvNotifyUpdateMediaMetadata(
6811 const MaybeDiscarded<BrowsingContext>& aContext,
6812 const Maybe<MediaMetadataBase>& aMetadata) {
6813 if (aContext.IsNullOrDiscarded()) {
6814 return IPC_OK();
6816 if (RefPtr<IMediaInfoUpdater> updater =
6817 aContext.get_canonical()->GetMediaController()) {
6818 updater->UpdateMetadata(aContext.ContextId(), aMetadata);
6820 return IPC_OK();
6823 mozilla::ipc::IPCResult
6824 ContentParent::RecvNotifyMediaSessionPlaybackStateChanged(
6825 const MaybeDiscarded<BrowsingContext>& aContext,
6826 MediaSessionPlaybackState aPlaybackState) {
6827 if (aContext.IsNullOrDiscarded()) {
6828 return IPC_OK();
6830 if (RefPtr<IMediaInfoUpdater> updater =
6831 aContext.get_canonical()->GetMediaController()) {
6832 updater->SetDeclaredPlaybackState(aContext.ContextId(), aPlaybackState);
6834 return IPC_OK();
6837 mozilla::ipc::IPCResult
6838 ContentParent::RecvNotifyMediaSessionSupportedActionChanged(
6839 const MaybeDiscarded<BrowsingContext>& aContext, MediaSessionAction aAction,
6840 bool aEnabled) {
6841 if (aContext.IsNullOrDiscarded()) {
6842 return IPC_OK();
6844 RefPtr<IMediaInfoUpdater> updater =
6845 aContext.get_canonical()->GetMediaController();
6846 if (!updater) {
6847 return IPC_OK();
6849 if (aEnabled) {
6850 updater->EnableAction(aContext.ContextId(), aAction);
6851 } else {
6852 updater->DisableAction(aContext.ContextId(), aAction);
6854 return IPC_OK();
6857 mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaFullScreenState(
6858 const MaybeDiscarded<BrowsingContext>& aContext, bool aIsInFullScreen) {
6859 if (aContext.IsNullOrDiscarded()) {
6860 return IPC_OK();
6862 if (RefPtr<IMediaInfoUpdater> updater =
6863 aContext.get_canonical()->GetMediaController()) {
6864 updater->NotifyMediaFullScreenState(aContext.ContextId(), aIsInFullScreen);
6866 return IPC_OK();
6869 mozilla::ipc::IPCResult ContentParent::RecvNotifyPositionStateChanged(
6870 const MaybeDiscarded<BrowsingContext>& aContext,
6871 const Maybe<PositionState>& aState) {
6872 if (aContext.IsNullOrDiscarded()) {
6873 return IPC_OK();
6875 if (RefPtr<IMediaInfoUpdater> updater =
6876 aContext.get_canonical()->GetMediaController()) {
6877 updater->UpdatePositionState(aContext.ContextId(), aState);
6879 return IPC_OK();
6882 mozilla::ipc::IPCResult ContentParent::RecvNotifyGuessedPositionStateChanged(
6883 const MaybeDiscarded<BrowsingContext>& aContext, const nsID& aMediaId,
6884 const Maybe<PositionState>& aState) {
6885 if (aContext.IsNullOrDiscarded()) {
6886 return IPC_OK();
6888 if (RefPtr<IMediaInfoUpdater> updater =
6889 aContext.get_canonical()->GetMediaController()) {
6890 updater->UpdateGuessedPositionState(aContext.ContextId(), aMediaId, aState);
6892 return IPC_OK();
6895 mozilla::ipc::IPCResult ContentParent::RecvAddOrRemovePageAwakeRequest(
6896 const MaybeDiscarded<BrowsingContext>& aContext,
6897 const bool& aShouldAddCount) {
6898 if (aContext.IsNullOrDiscarded()) {
6899 return IPC_OK();
6901 if (aShouldAddCount) {
6902 aContext.get_canonical()->AddPageAwakeRequest();
6903 } else {
6904 aContext.get_canonical()->RemovePageAwakeRequest();
6906 return IPC_OK();
6909 #if defined(XP_WIN)
6910 mozilla::ipc::IPCResult ContentParent::RecvGetModulesTrust(
6911 ModulePaths&& aModPaths, bool aRunAtNormalPriority,
6912 GetModulesTrustResolver&& aResolver) {
6913 RefPtr<DllServices> dllSvc(DllServices::Get());
6914 dllSvc->GetModulesTrust(std::move(aModPaths), aRunAtNormalPriority)
6915 ->Then(
6916 GetMainThreadSerialEventTarget(), __func__,
6917 [aResolver](ModulesMapResult&& aResult) {
6918 aResolver(Some(ModulesMapResult(std::move(aResult))));
6920 [aResolver](nsresult aRv) { aResolver(Nothing()); });
6921 return IPC_OK();
6923 #endif // defined(XP_WIN)
6925 mozilla::ipc::IPCResult ContentParent::RecvCreateBrowsingContext(
6926 uint64_t aGroupId, BrowsingContext::IPCInitializer&& aInit) {
6927 RefPtr<WindowGlobalParent> parent;
6928 if (aInit.mParentId != 0) {
6929 parent = WindowGlobalParent::GetByInnerWindowId(aInit.mParentId);
6930 if (!parent) {
6931 return IPC_FAIL(this, "Parent doesn't exist in parent process");
6935 if (parent && parent->GetContentParent() != this) {
6936 // We're trying attach a child BrowsingContext to a parent
6937 // WindowContext in another process. This is illegal since the
6938 // only thing that could create that child BrowsingContext is the parent
6939 // window's process.
6940 return IPC_FAIL(this,
6941 "Must create BrowsingContext from the parent's process");
6944 RefPtr<BrowsingContext> opener;
6945 if (aInit.GetOpenerId() != 0) {
6946 opener = BrowsingContext::Get(aInit.GetOpenerId());
6947 if (!opener) {
6948 return IPC_FAIL(this, "Opener doesn't exist in parent process");
6952 RefPtr<BrowsingContext> child = BrowsingContext::Get(aInit.mId);
6953 if (child) {
6954 // This is highly suspicious. BrowsingContexts should only be created once,
6955 // so finding one indicates that someone is doing something they shouldn't.
6956 return IPC_FAIL(this, "A BrowsingContext with this ID already exists");
6959 // Ensure that the passed-in BrowsingContextGroup is valid.
6960 RefPtr<BrowsingContextGroup> group =
6961 BrowsingContextGroup::GetOrCreate(aGroupId);
6962 if (parent) {
6963 if (parent->Group()->Id() != aGroupId) {
6964 return IPC_FAIL(this, "Parent has different group ID");
6966 if (parent->IsDiscarded()) {
6967 return IPC_FAIL(this, "Parent is discarded");
6969 if (parent->Group() != group) {
6970 return IPC_FAIL(this, "Parent has different group object");
6973 if (opener && opener->Group() != group) {
6974 if (opener->Group()->Id() != aGroupId) {
6975 return IPC_FAIL(this, "Opener has different group ID");
6977 return IPC_FAIL(this, "Opener has different group object");
6979 if (!parent && !opener && !group->Toplevels().IsEmpty()) {
6980 return IPC_FAIL(this, "Unrelated context from child in stale group");
6983 return BrowsingContext::CreateFromIPC(std::move(aInit), group, this);
6986 bool ContentParent::CheckBrowsingContextEmbedder(CanonicalBrowsingContext* aBC,
6987 const char* aOperation) const {
6988 if (!aBC->IsEmbeddedInProcess(ChildID())) {
6989 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
6990 ("ParentIPC: Trying to %s out of process context 0x%08" PRIx64,
6991 aOperation, aBC->Id()));
6992 return false;
6994 return true;
6997 mozilla::ipc::IPCResult ContentParent::RecvDiscardBrowsingContext(
6998 const MaybeDiscarded<BrowsingContext>& aContext, bool aDoDiscard,
6999 DiscardBrowsingContextResolver&& aResolve) {
7000 if (CanonicalBrowsingContext* context =
7001 CanonicalBrowsingContext::Cast(aContext.GetMaybeDiscarded())) {
7002 if (aDoDiscard && !context->IsDiscarded()) {
7003 if (!CheckBrowsingContextEmbedder(context, "discard")) {
7004 return IPC_FAIL(this, "Illegal Discard attempt");
7007 context->Detach(/* aFromIPC */ true);
7009 context->AddFinalDiscardListener(aResolve);
7010 return IPC_OK();
7013 // Resolve the promise, as we've received and handled the message. This will
7014 // allow the content process to fully-discard references to this BC.
7015 aResolve(true);
7016 return IPC_OK();
7019 mozilla::ipc::IPCResult ContentParent::RecvWindowClose(
7020 const MaybeDiscarded<BrowsingContext>& aContext, bool aTrustedCaller) {
7021 if (aContext.IsNullOrDiscarded()) {
7022 MOZ_LOG(
7023 BrowsingContext::GetLog(), LogLevel::Debug,
7024 ("ParentIPC: Trying to send a message to dead or detached context"));
7025 return IPC_OK();
7027 CanonicalBrowsingContext* context = aContext.get_canonical();
7029 // FIXME Need to check that the sending process has access to the unit of
7030 // related
7031 // browsing contexts of bc.
7033 if (ContentParent* cp = context->GetContentParent()) {
7034 Unused << cp->SendWindowClose(context, aTrustedCaller);
7036 return IPC_OK();
7039 mozilla::ipc::IPCResult ContentParent::RecvWindowFocus(
7040 const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType,
7041 uint64_t aActionId) {
7042 if (aContext.IsNullOrDiscarded()) {
7043 MOZ_LOG(
7044 BrowsingContext::GetLog(), LogLevel::Debug,
7045 ("ParentIPC: Trying to send a message to dead or detached context"));
7046 return IPC_OK();
7048 LOGFOCUS(("ContentParent::RecvWindowFocus actionid: %" PRIu64, aActionId));
7049 CanonicalBrowsingContext* context = aContext.get_canonical();
7051 if (ContentParent* cp = context->GetContentParent()) {
7052 Unused << cp->SendWindowFocus(context, aCallerType, aActionId);
7054 return IPC_OK();
7057 mozilla::ipc::IPCResult ContentParent::RecvWindowBlur(
7058 const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType) {
7059 if (aContext.IsNullOrDiscarded()) {
7060 MOZ_LOG(
7061 BrowsingContext::GetLog(), LogLevel::Debug,
7062 ("ParentIPC: Trying to send a message to dead or detached context"));
7063 return IPC_OK();
7065 CanonicalBrowsingContext* context = aContext.get_canonical();
7067 if (ContentParent* cp = context->GetContentParent()) {
7068 Unused << cp->SendWindowBlur(context, aCallerType);
7070 return IPC_OK();
7073 mozilla::ipc::IPCResult ContentParent::RecvRaiseWindow(
7074 const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType,
7075 uint64_t aActionId) {
7076 if (aContext.IsNullOrDiscarded()) {
7077 MOZ_LOG(
7078 BrowsingContext::GetLog(), LogLevel::Debug,
7079 ("ParentIPC: Trying to send a message to dead or detached context"));
7080 return IPC_OK();
7082 LOGFOCUS(("ContentParent::RecvRaiseWindow actionid: %" PRIu64, aActionId));
7084 CanonicalBrowsingContext* context = aContext.get_canonical();
7086 if (ContentParent* cp = context->GetContentParent()) {
7087 Unused << cp->SendRaiseWindow(context, aCallerType, aActionId);
7089 return IPC_OK();
7092 mozilla::ipc::IPCResult ContentParent::RecvAdjustWindowFocus(
7093 const MaybeDiscarded<BrowsingContext>& aContext, bool aIsVisible,
7094 uint64_t aActionId, bool aShouldClearFocus,
7095 const MaybeDiscarded<BrowsingContext>& aAncestorBrowsingContextToFocus) {
7096 if (aContext.IsNullOrDiscarded()) {
7097 MOZ_LOG(
7098 BrowsingContext::GetLog(), LogLevel::Debug,
7099 ("ParentIPC: Trying to send a message to dead or detached context"));
7100 return IPC_OK();
7102 LOGFOCUS(
7103 ("ContentParent::RecvAdjustWindowFocus isVisible %d actionid: %" PRIu64,
7104 aIsVisible, aActionId));
7106 nsTHashMap<nsPtrHashKey<ContentParent>, bool> processes(2);
7107 processes.InsertOrUpdate(this, true);
7109 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
7110 if (cpm) {
7111 CanonicalBrowsingContext* context = aContext.get_canonical();
7112 while (context) {
7113 BrowsingContext* parent = context->GetParent();
7114 if (!parent) {
7115 break;
7118 CanonicalBrowsingContext* canonicalParent = parent->Canonical();
7119 ContentParent* cp = cpm->GetContentProcessById(
7120 ContentParentId(canonicalParent->OwnerProcessId()));
7121 if (cp && !processes.Get(cp)) {
7122 Unused << cp->SendAdjustWindowFocus(context, aIsVisible, aActionId,
7123 aShouldClearFocus,
7124 aAncestorBrowsingContextToFocus);
7125 processes.InsertOrUpdate(cp, true);
7127 context = canonicalParent;
7130 return IPC_OK();
7133 mozilla::ipc::IPCResult ContentParent::RecvClearFocus(
7134 const MaybeDiscarded<BrowsingContext>& aContext) {
7135 if (aContext.IsNullOrDiscarded()) {
7136 MOZ_LOG(
7137 BrowsingContext::GetLog(), LogLevel::Debug,
7138 ("ParentIPC: Trying to send a message to dead or detached context"));
7139 return IPC_OK();
7141 CanonicalBrowsingContext* context = aContext.get_canonical();
7143 if (ContentParent* cp = context->GetContentParent()) {
7144 Unused << cp->SendClearFocus(context);
7146 return IPC_OK();
7149 mozilla::ipc::IPCResult ContentParent::RecvSetFocusedBrowsingContext(
7150 const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
7151 if (aContext.IsNullOrDiscarded()) {
7152 MOZ_LOG(
7153 BrowsingContext::GetLog(), LogLevel::Debug,
7154 ("ParentIPC: Trying to send a message to dead or detached context"));
7155 return IPC_OK();
7157 LOGFOCUS(("ContentParent::RecvSetFocusedBrowsingContext actionid: %" PRIu64,
7158 aActionId));
7159 CanonicalBrowsingContext* context = aContext.get_canonical();
7161 nsFocusManager* fm = nsFocusManager::GetFocusManager();
7162 if (!fm) {
7163 return IPC_OK();
7166 if (!fm->SetFocusedBrowsingContextInChrome(context, aActionId)) {
7167 LOGFOCUS((
7168 "Ignoring out-of-sequence attempt [%p] to set focused browsing context "
7169 "in parent.",
7170 context));
7171 Unused << SendReviseFocusedBrowsingContext(
7172 aActionId, fm->GetFocusedBrowsingContextInChrome(),
7173 fm->GetActionIdForFocusedBrowsingContextInChrome());
7174 return IPC_OK();
7177 BrowserParent::UpdateFocusFromBrowsingContext();
7179 context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
7180 Unused << aParent->SendSetFocusedBrowsingContext(context, aActionId);
7183 return IPC_OK();
7186 mozilla::ipc::IPCResult ContentParent::RecvSetActiveBrowsingContext(
7187 const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
7188 if (aContext.IsNullOrDiscarded()) {
7189 MOZ_LOG(
7190 BrowsingContext::GetLog(), LogLevel::Debug,
7191 ("ParentIPC: Trying to send a message to dead or detached context"));
7192 return IPC_OK();
7194 LOGFOCUS(("ContentParent::RecvSetActiveBrowsingContext actionid: %" PRIu64,
7195 aActionId));
7196 CanonicalBrowsingContext* context = aContext.get_canonical();
7198 nsFocusManager* fm = nsFocusManager::GetFocusManager();
7199 if (!fm) {
7200 return IPC_OK();
7203 if (!fm->SetActiveBrowsingContextInChrome(context, aActionId)) {
7204 LOGFOCUS(
7205 ("Ignoring out-of-sequence attempt [%p] to set active browsing context "
7206 "in parent.",
7207 context));
7208 Unused << SendReviseActiveBrowsingContext(
7209 aActionId, fm->GetActiveBrowsingContextInChrome(),
7210 fm->GetActionIdForActiveBrowsingContextInChrome());
7211 return IPC_OK();
7214 context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
7215 Unused << aParent->SendSetActiveBrowsingContext(context, aActionId);
7218 return IPC_OK();
7221 mozilla::ipc::IPCResult ContentParent::RecvUnsetActiveBrowsingContext(
7222 const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
7223 if (aContext.IsNullOrDiscarded()) {
7224 MOZ_LOG(
7225 BrowsingContext::GetLog(), LogLevel::Debug,
7226 ("ParentIPC: Trying to send a message to dead or detached context"));
7227 return IPC_OK();
7229 LOGFOCUS(("ContentParent::RecvUnsetActiveBrowsingContext actionid: %" PRIu64,
7230 aActionId));
7231 CanonicalBrowsingContext* context = aContext.get_canonical();
7233 nsFocusManager* fm = nsFocusManager::GetFocusManager();
7234 if (!fm) {
7235 return IPC_OK();
7238 if (!fm->SetActiveBrowsingContextInChrome(nullptr, aActionId)) {
7239 LOGFOCUS(
7240 ("Ignoring out-of-sequence attempt to unset active browsing context in "
7241 "parent [%p].",
7242 context));
7243 Unused << SendReviseActiveBrowsingContext(
7244 aActionId, fm->GetActiveBrowsingContextInChrome(),
7245 fm->GetActionIdForActiveBrowsingContextInChrome());
7246 return IPC_OK();
7249 context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
7250 Unused << aParent->SendUnsetActiveBrowsingContext(context, aActionId);
7253 return IPC_OK();
7256 mozilla::ipc::IPCResult ContentParent::RecvSetFocusedElement(
7257 const MaybeDiscarded<BrowsingContext>& aContext, bool aNeedsFocus) {
7258 if (aContext.IsNullOrDiscarded()) {
7259 MOZ_LOG(
7260 BrowsingContext::GetLog(), LogLevel::Debug,
7261 ("ParentIPC: Trying to send a message to dead or detached context"));
7262 return IPC_OK();
7264 LOGFOCUS(("ContentParent::RecvSetFocusedElement"));
7265 CanonicalBrowsingContext* context = aContext.get_canonical();
7267 if (ContentParent* cp = context->GetContentParent()) {
7268 Unused << cp->SendSetFocusedElement(context, aNeedsFocus);
7270 return IPC_OK();
7273 mozilla::ipc::IPCResult ContentParent::RecvFinalizeFocusOuter(
7274 const MaybeDiscarded<BrowsingContext>& aContext, bool aCanFocus,
7275 CallerType aCallerType) {
7276 if (aContext.IsNullOrDiscarded()) {
7277 MOZ_LOG(
7278 BrowsingContext::GetLog(), LogLevel::Debug,
7279 ("ParentIPC: Trying to send a message to dead or detached context"));
7280 return IPC_OK();
7282 LOGFOCUS(("ContentParent::RecvFinalizeFocusOuter"));
7283 CanonicalBrowsingContext* context = aContext.get_canonical();
7284 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
7285 if (cpm) {
7286 ContentParent* cp = cpm->GetContentProcessById(
7287 ContentParentId(context->EmbedderProcessId()));
7288 if (cp) {
7289 Unused << cp->SendFinalizeFocusOuter(context, aCanFocus, aCallerType);
7292 return IPC_OK();
7295 mozilla::ipc::IPCResult ContentParent::RecvInsertNewFocusActionId(
7296 uint64_t aActionId) {
7297 LOGFOCUS(("ContentParent::RecvInsertNewFocusActionId actionid: %" PRIu64,
7298 aActionId));
7299 nsFocusManager* fm = nsFocusManager::GetFocusManager();
7300 if (fm) {
7301 fm->InsertNewFocusActionId(aActionId);
7303 return IPC_OK();
7306 mozilla::ipc::IPCResult ContentParent::RecvBlurToParent(
7307 const MaybeDiscarded<BrowsingContext>& aFocusedBrowsingContext,
7308 const MaybeDiscarded<BrowsingContext>& aBrowsingContextToClear,
7309 const MaybeDiscarded<BrowsingContext>& aAncestorBrowsingContextToFocus,
7310 bool aIsLeavingDocument, bool aAdjustWidget,
7311 bool aBrowsingContextToClearHandled,
7312 bool aAncestorBrowsingContextToFocusHandled, uint64_t aActionId) {
7313 if (aFocusedBrowsingContext.IsNullOrDiscarded()) {
7314 MOZ_LOG(
7315 BrowsingContext::GetLog(), LogLevel::Debug,
7316 ("ParentIPC: Trying to send a message to dead or detached context"));
7317 return IPC_OK();
7320 LOGFOCUS(
7321 ("ContentParent::RecvBlurToParent isLeavingDocument %d adjustWidget %d "
7322 "browsingContextToClearHandled %d ancestorBrowsingContextToFocusHandled "
7323 "%d actionid: %" PRIu64,
7324 aIsLeavingDocument, aAdjustWidget, aBrowsingContextToClearHandled,
7325 aAncestorBrowsingContextToFocusHandled, aActionId));
7327 CanonicalBrowsingContext* focusedBrowsingContext =
7328 aFocusedBrowsingContext.get_canonical();
7330 // If aBrowsingContextToClear and aAncestorBrowsingContextToFocusHandled
7331 // didn't get handled in the process that sent this IPC message and they
7332 // aren't in the same process as aFocusedBrowsingContext, we need to split
7333 // off their handling here and use SendSetFocusedElement to send them
7334 // elsewhere than the blurring itself.
7336 bool ancestorDifferent =
7337 (!aAncestorBrowsingContextToFocusHandled &&
7338 !aAncestorBrowsingContextToFocus.IsNullOrDiscarded() &&
7339 (focusedBrowsingContext->OwnerProcessId() !=
7340 aAncestorBrowsingContextToFocus.get_canonical()->OwnerProcessId()));
7341 if (!aBrowsingContextToClearHandled &&
7342 !aBrowsingContextToClear.IsNullOrDiscarded() &&
7343 (focusedBrowsingContext->OwnerProcessId() !=
7344 aBrowsingContextToClear.get_canonical()->OwnerProcessId())) {
7345 MOZ_RELEASE_ASSERT(!ancestorDifferent,
7346 "This combination is not supposed to happen.");
7347 if (ContentParent* cp =
7348 aBrowsingContextToClear.get_canonical()->GetContentParent()) {
7349 Unused << cp->SendSetFocusedElement(aBrowsingContextToClear, false);
7351 } else if (ancestorDifferent) {
7352 if (ContentParent* cp = aAncestorBrowsingContextToFocus.get_canonical()
7353 ->GetContentParent()) {
7354 Unused << cp->SendSetFocusedElement(aAncestorBrowsingContextToFocus,
7355 true);
7359 if (ContentParent* cp = focusedBrowsingContext->GetContentParent()) {
7360 Unused << cp->SendBlurToChild(aFocusedBrowsingContext,
7361 aBrowsingContextToClear,
7362 aAncestorBrowsingContextToFocus,
7363 aIsLeavingDocument, aAdjustWidget, aActionId);
7366 return IPC_OK();
7369 mozilla::ipc::IPCResult ContentParent::RecvMaybeExitFullscreen(
7370 const MaybeDiscarded<BrowsingContext>& aContext) {
7371 if (aContext.IsNullOrDiscarded()) {
7372 MOZ_LOG(
7373 BrowsingContext::GetLog(), LogLevel::Debug,
7374 ("ParentIPC: Trying to send a message to dead or detached context"));
7375 return IPC_OK();
7377 CanonicalBrowsingContext* context = aContext.get_canonical();
7379 if (ContentParent* cp = context->GetContentParent()) {
7380 Unused << cp->SendMaybeExitFullscreen(context);
7383 return IPC_OK();
7386 mozilla::ipc::IPCResult ContentParent::RecvWindowPostMessage(
7387 const MaybeDiscarded<BrowsingContext>& aContext,
7388 const ClonedOrErrorMessageData& aMessage, const PostMessageData& aData) {
7389 if (aContext.IsNullOrDiscarded()) {
7390 MOZ_LOG(
7391 BrowsingContext::GetLog(), LogLevel::Debug,
7392 ("ParentIPC: Trying to send a message to dead or detached context"));
7393 return IPC_OK();
7395 CanonicalBrowsingContext* context = aContext.get_canonical();
7397 if (aData.source().IsDiscarded()) {
7398 MOZ_LOG(
7399 BrowsingContext::GetLog(), LogLevel::Debug,
7400 ("ParentIPC: Trying to send a message from dead or detached context"));
7401 return IPC_OK();
7404 RefPtr<ContentParent> cp = context->GetContentParent();
7405 if (!cp) {
7406 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
7407 ("ParentIPC: Trying to send PostMessage to dead content process"));
7408 return IPC_OK();
7411 ClonedOrErrorMessageData message;
7412 StructuredCloneData messageFromChild;
7413 if (aMessage.type() == ClonedOrErrorMessageData::TClonedMessageData) {
7414 UnpackClonedMessageData(aMessage, messageFromChild);
7416 ClonedMessageData clonedMessageData;
7417 if (BuildClonedMessageData(messageFromChild, clonedMessageData)) {
7418 message = std::move(clonedMessageData);
7419 } else {
7420 // FIXME Logging?
7421 message = ErrorMessageData();
7423 } else {
7424 MOZ_ASSERT(aMessage.type() == ClonedOrErrorMessageData::TErrorMessageData);
7425 message = ErrorMessageData();
7428 Unused << cp->SendWindowPostMessage(context, message, aData);
7429 return IPC_OK();
7432 void ContentParent::AddBrowsingContextGroup(BrowsingContextGroup* aGroup) {
7433 MOZ_DIAGNOSTIC_ASSERT(aGroup);
7434 // Ensure that the group has been inserted, and if we're not launching
7435 // anymore, also begin subscribing. Launching processes will be subscribed if
7436 // they finish launching in `LaunchSubprocessResolve`.
7437 if (mGroups.EnsureInserted(aGroup) && !IsLaunching()) {
7438 aGroup->Subscribe(this);
7442 void ContentParent::RemoveBrowsingContextGroup(BrowsingContextGroup* aGroup) {
7443 MOZ_DIAGNOSTIC_ASSERT(aGroup);
7444 // Remove the group from our list. This is called from the
7445 // BrowsingContextGroup when unsubscribing, so we don't need to do it here.
7446 if (mGroups.EnsureRemoved(aGroup) && CanSend()) {
7447 // If we're removing the entry for the first time, tell the content process
7448 // to clean up the group.
7449 Unused << SendDestroyBrowsingContextGroup(aGroup->Id());
7453 mozilla::ipc::IPCResult ContentParent::RecvCommitBrowsingContextTransaction(
7454 const MaybeDiscarded<BrowsingContext>& aContext,
7455 BrowsingContext::BaseTransaction&& aTransaction, uint64_t aEpoch) {
7456 // Record the new BrowsingContextFieldEpoch associated with this transaction.
7457 // This should be done unconditionally, so that we're always in-sync.
7459 // The order the parent process receives transactions is considered the
7460 // "canonical" ordering, so we don't need to worry about doing any
7461 // epoch-related validation.
7462 MOZ_ASSERT(aEpoch == mBrowsingContextFieldEpoch + 1,
7463 "Child process skipped an epoch?");
7464 mBrowsingContextFieldEpoch = aEpoch;
7466 return aTransaction.CommitFromIPC(aContext, this);
7469 mozilla::ipc::IPCResult ContentParent::RecvBlobURLDataRequest(
7470 const nsACString& aBlobURL, nsIPrincipal* aTriggeringPrincipal,
7471 nsIPrincipal* aLoadingPrincipal, const OriginAttributes& aOriginAttributes,
7472 uint64_t aInnerWindowId, const nsCString& aPartitionKey,
7473 BlobURLDataRequestResolver&& aResolver) {
7474 RefPtr<BlobImpl> blobImpl;
7476 // Since revoked blobs are also retrieved, it is possible that the blob no
7477 // longer exists (due to the 5 second timeout) when execution reaches here
7478 if (!BlobURLProtocolHandler::GetDataEntry(
7479 aBlobURL, getter_AddRefs(blobImpl), aLoadingPrincipal,
7480 aTriggeringPrincipal, aOriginAttributes, aInnerWindowId,
7481 aPartitionKey, true /* AlsoIfRevoked */)) {
7482 aResolver(NS_ERROR_DOM_BAD_URI);
7483 return IPC_OK();
7486 IPCBlob ipcBlob;
7487 nsresult rv = IPCBlobUtils::Serialize(blobImpl, ipcBlob);
7489 if (NS_WARN_IF(NS_FAILED(rv))) {
7490 aResolver(rv);
7491 return IPC_OK();
7494 aResolver(ipcBlob);
7495 return IPC_OK();
7498 mozilla::ipc::IPCResult ContentParent::RecvReportServiceWorkerShutdownProgress(
7499 uint32_t aShutdownStateId, ServiceWorkerShutdownState::Progress aProgress) {
7500 RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
7501 MOZ_RELEASE_ASSERT(swm, "ServiceWorkers should shutdown before SWM.");
7503 swm->ReportServiceWorkerShutdownProgress(aShutdownStateId, aProgress);
7505 return IPC_OK();
7508 mozilla::ipc::IPCResult ContentParent::RecvNotifyOnHistoryReload(
7509 const MaybeDiscarded<BrowsingContext>& aContext, const bool& aForceReload,
7510 NotifyOnHistoryReloadResolver&& aResolver) {
7511 bool canReload = false;
7512 Maybe<NotNull<RefPtr<nsDocShellLoadState>>> loadState;
7513 Maybe<bool> reloadActiveEntry;
7514 if (!aContext.IsNullOrDiscarded()) {
7515 aContext.get_canonical()->NotifyOnHistoryReload(
7516 aForceReload, canReload, loadState, reloadActiveEntry);
7518 aResolver(
7519 std::tuple<const bool&,
7520 const Maybe<NotNull<RefPtr<nsDocShellLoadState>>>&,
7521 const Maybe<bool>&>(canReload, loadState, reloadActiveEntry));
7522 return IPC_OK();
7525 mozilla::ipc::IPCResult ContentParent::RecvHistoryCommit(
7526 const MaybeDiscarded<BrowsingContext>& aContext, const uint64_t& aLoadID,
7527 const nsID& aChangeID, const uint32_t& aLoadType, const bool& aPersist,
7528 const bool& aCloneEntryChildren, const bool& aChannelExpired,
7529 const uint32_t& aCacheKey) {
7530 if (!aContext.IsDiscarded()) {
7531 CanonicalBrowsingContext* canonical = aContext.get_canonical();
7532 if (!canonical) {
7533 return IPC_FAIL(
7534 this, "Could not get canonical. aContext.get_canonical() fails.");
7536 canonical->SessionHistoryCommit(aLoadID, aChangeID, aLoadType, aPersist,
7537 aCloneEntryChildren, aChannelExpired,
7538 aCacheKey);
7540 return IPC_OK();
7543 mozilla::ipc::IPCResult ContentParent::RecvHistoryGo(
7544 const MaybeDiscarded<BrowsingContext>& aContext, int32_t aOffset,
7545 uint64_t aHistoryEpoch, bool aRequireUserInteraction, bool aUserActivation,
7546 HistoryGoResolver&& aResolveRequestedIndex) {
7547 if (!aContext.IsNullOrDiscarded()) {
7548 RefPtr<CanonicalBrowsingContext> canonical = aContext.get_canonical();
7549 aResolveRequestedIndex(
7550 canonical->HistoryGo(aOffset, aHistoryEpoch, aRequireUserInteraction,
7551 aUserActivation, Some(ChildID())));
7553 return IPC_OK();
7556 mozilla::ipc::IPCResult ContentParent::RecvSynchronizeLayoutHistoryState(
7557 const MaybeDiscarded<BrowsingContext>& aContext,
7558 nsILayoutHistoryState* aState) {
7559 if (aContext.IsNull()) {
7560 return IPC_OK();
7563 BrowsingContext* bc = aContext.GetMaybeDiscarded();
7564 if (!bc) {
7565 return IPC_OK();
7567 SessionHistoryEntry* entry = bc->Canonical()->GetActiveSessionHistoryEntry();
7568 if (entry) {
7569 entry->SetLayoutHistoryState(aState);
7571 return IPC_OK();
7574 mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryTitle(
7575 const MaybeDiscarded<BrowsingContext>& aContext, const nsAString& aTitle) {
7576 if (aContext.IsNullOrDiscarded()) {
7577 return IPC_OK();
7580 SessionHistoryEntry* entry =
7581 aContext.get_canonical()->GetActiveSessionHistoryEntry();
7582 if (entry) {
7583 entry->SetTitle(aTitle);
7585 return IPC_OK();
7588 mozilla::ipc::IPCResult
7589 ContentParent::RecvSessionHistoryEntryScrollRestorationIsManual(
7590 const MaybeDiscarded<BrowsingContext>& aContext, const bool& aIsManual) {
7591 if (aContext.IsNullOrDiscarded()) {
7592 return IPC_OK();
7595 SessionHistoryEntry* entry =
7596 aContext.get_canonical()->GetActiveSessionHistoryEntry();
7597 if (entry) {
7598 entry->SetScrollRestorationIsManual(aIsManual);
7600 return IPC_OK();
7603 mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryScrollPosition(
7604 const MaybeDiscarded<BrowsingContext>& aContext, const int32_t& aX,
7605 const int32_t& aY) {
7606 if (aContext.IsNullOrDiscarded()) {
7607 return IPC_OK();
7610 SessionHistoryEntry* entry =
7611 aContext.get_canonical()->GetActiveSessionHistoryEntry();
7612 if (entry) {
7613 entry->SetScrollPosition(aX, aY);
7615 return IPC_OK();
7618 mozilla::ipc::IPCResult
7619 ContentParent::RecvSessionHistoryEntryStoreWindowNameInContiguousEntries(
7620 const MaybeDiscarded<BrowsingContext>& aContext, const nsAString& aName) {
7621 if (aContext.IsNullOrDiscarded()) {
7622 return IPC_OK();
7625 // Per https://html.spec.whatwg.org/#history-traversal 4.2.1, we need to set
7626 // the name to all contiguous entries. This has to be called before
7627 // CanonicalBrowsingContext::SessionHistoryCommit(), so the active entry is
7628 // still the old entry that we want to set.
7630 SessionHistoryEntry* entry =
7631 aContext.get_canonical()->GetActiveSessionHistoryEntry();
7633 if (entry) {
7634 nsSHistory::WalkContiguousEntries(
7635 entry, [&](nsISHEntry* aEntry) { aEntry->SetName(aName); });
7638 return IPC_OK();
7641 mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryCacheKey(
7642 const MaybeDiscarded<BrowsingContext>& aContext,
7643 const uint32_t& aCacheKey) {
7644 if (aContext.IsNullOrDiscarded()) {
7645 return IPC_OK();
7648 SessionHistoryEntry* entry =
7649 aContext.get_canonical()->GetActiveSessionHistoryEntry();
7650 if (entry) {
7651 entry->SetCacheKey(aCacheKey);
7653 return IPC_OK();
7656 mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryWireframe(
7657 const MaybeDiscarded<BrowsingContext>& aContext,
7658 const Wireframe& aWireframe) {
7659 if (aContext.IsNull()) {
7660 return IPC_OK();
7663 BrowsingContext* bc = aContext.GetMaybeDiscarded();
7664 if (!bc) {
7665 return IPC_OK();
7668 SessionHistoryEntry* entry = bc->Canonical()->GetActiveSessionHistoryEntry();
7669 if (entry) {
7670 entry->SetWireframe(Some(aWireframe));
7672 return IPC_OK();
7675 mozilla::ipc::IPCResult
7676 ContentParent::RecvGetLoadingSessionHistoryInfoFromParent(
7677 const MaybeDiscarded<BrowsingContext>& aContext,
7678 GetLoadingSessionHistoryInfoFromParentResolver&& aResolver) {
7679 if (aContext.IsNullOrDiscarded()) {
7680 return IPC_OK();
7683 Maybe<LoadingSessionHistoryInfo> info;
7684 aContext.get_canonical()->GetLoadingSessionHistoryInfoFromParent(info);
7685 aResolver(info);
7687 return IPC_OK();
7690 mozilla::ipc::IPCResult ContentParent::RecvRemoveFromBFCache(
7691 const MaybeDiscarded<BrowsingContext>& aContext) {
7692 if (aContext.IsNullOrDiscarded()) {
7693 return IPC_OK();
7696 nsCOMPtr<nsFrameLoaderOwner> owner =
7697 do_QueryInterface(aContext.get_canonical()->GetEmbedderElement());
7698 if (!owner) {
7699 return IPC_OK();
7702 RefPtr<nsFrameLoader> frameLoader = owner->GetFrameLoader();
7703 if (!frameLoader || !frameLoader->GetMaybePendingBrowsingContext()) {
7704 return IPC_OK();
7707 nsCOMPtr<nsISHistory> shistory = frameLoader->GetMaybePendingBrowsingContext()
7708 ->Canonical()
7709 ->GetSessionHistory();
7710 if (!shistory) {
7711 return IPC_OK();
7714 uint32_t count = shistory->GetCount();
7715 for (uint32_t i = 0; i < count; ++i) {
7716 nsCOMPtr<nsISHEntry> entry;
7717 shistory->GetEntryAtIndex(i, getter_AddRefs(entry));
7718 nsCOMPtr<SessionHistoryEntry> she = do_QueryInterface(entry);
7719 if (she) {
7720 if (RefPtr<nsFrameLoader> frameLoader = she->GetFrameLoader()) {
7721 if (frameLoader->GetMaybePendingBrowsingContext() == aContext.get()) {
7722 she->SetFrameLoader(nullptr);
7723 frameLoader->Destroy();
7724 break;
7730 return IPC_OK();
7733 mozilla::ipc::IPCResult ContentParent::RecvSetActiveSessionHistoryEntry(
7734 const MaybeDiscarded<BrowsingContext>& aContext,
7735 const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo&& aInfo,
7736 uint32_t aLoadType, uint32_t aUpdatedCacheKey, const nsID& aChangeID) {
7737 if (!aContext.IsNullOrDiscarded()) {
7738 aContext.get_canonical()->SetActiveSessionHistoryEntry(
7739 aPreviousScrollPos, &aInfo, aLoadType, aUpdatedCacheKey, aChangeID);
7741 return IPC_OK();
7744 mozilla::ipc::IPCResult ContentParent::RecvReplaceActiveSessionHistoryEntry(
7745 const MaybeDiscarded<BrowsingContext>& aContext,
7746 SessionHistoryInfo&& aInfo) {
7747 if (!aContext.IsNullOrDiscarded()) {
7748 aContext.get_canonical()->ReplaceActiveSessionHistoryEntry(&aInfo);
7750 return IPC_OK();
7753 mozilla::ipc::IPCResult
7754 ContentParent::RecvRemoveDynEntriesFromActiveSessionHistoryEntry(
7755 const MaybeDiscarded<BrowsingContext>& aContext) {
7756 if (!aContext.IsNullOrDiscarded()) {
7757 aContext.get_canonical()->RemoveDynEntriesFromActiveSessionHistoryEntry();
7759 return IPC_OK();
7762 mozilla::ipc::IPCResult ContentParent::RecvRemoveFromSessionHistory(
7763 const MaybeDiscarded<BrowsingContext>& aContext, const nsID& aChangeID) {
7764 if (!aContext.IsNullOrDiscarded()) {
7765 aContext.get_canonical()->RemoveFromSessionHistory(aChangeID);
7767 return IPC_OK();
7770 mozilla::ipc::IPCResult ContentParent::RecvHistoryReload(
7771 const MaybeDiscarded<BrowsingContext>& aContext,
7772 const uint32_t aReloadFlags) {
7773 if (!aContext.IsNullOrDiscarded()) {
7774 nsCOMPtr<nsISHistory> shistory =
7775 aContext.get_canonical()->GetSessionHistory();
7776 if (shistory) {
7777 shistory->Reload(aReloadFlags);
7780 return IPC_OK();
7783 mozilla::ipc::IPCResult ContentParent::RecvCommitWindowContextTransaction(
7784 const MaybeDiscarded<WindowContext>& aContext,
7785 WindowContext::BaseTransaction&& aTransaction, uint64_t aEpoch) {
7786 // Record the new BrowsingContextFieldEpoch associated with this transaction.
7787 // This should be done unconditionally, so that we're always in-sync.
7789 // The order the parent process receives transactions is considered the
7790 // "canonical" ordering, so we don't need to worry about doing any
7791 // epoch-related validation.
7792 MOZ_ASSERT(aEpoch == mBrowsingContextFieldEpoch + 1,
7793 "Child process skipped an epoch?");
7794 mBrowsingContextFieldEpoch = aEpoch;
7796 return aTransaction.CommitFromIPC(aContext, this);
7799 NS_IMETHODIMP ContentParent::GetChildID(uint64_t* aOut) {
7800 *aOut = this->ChildID();
7801 return NS_OK;
7804 NS_IMETHODIMP ContentParent::GetOsPid(int32_t* aOut) {
7805 *aOut = Pid();
7806 return NS_OK;
7809 NS_IMETHODIMP ContentParent::GetRemoteType(nsACString& aRemoteType) {
7810 aRemoteType = GetRemoteType();
7811 return NS_OK;
7814 void ContentParent::StartRemoteWorkerService() {
7815 MOZ_ASSERT(!mRemoteWorkerServiceActor);
7816 MOZ_ASSERT(mRemoteType != PREALLOC_REMOTE_TYPE);
7818 Endpoint<PRemoteWorkerServiceChild> childEp;
7819 mRemoteWorkerServiceActor =
7820 RemoteWorkerServiceParent::CreateForProcess(this, &childEp);
7821 if (mRemoteWorkerServiceActor) {
7822 Unused << SendInitRemoteWorkerService(std::move(childEp));
7826 IPCResult ContentParent::RecvRawMessage(
7827 const JSActorMessageMeta& aMeta, const Maybe<ClonedMessageData>& aData,
7828 const Maybe<ClonedMessageData>& aStack) {
7829 Maybe<StructuredCloneData> data;
7830 if (aData) {
7831 data.emplace();
7832 data->BorrowFromClonedMessageData(*aData);
7834 Maybe<StructuredCloneData> stack;
7835 if (aStack) {
7836 stack.emplace();
7837 stack->BorrowFromClonedMessageData(*aStack);
7839 MMPrinter::Print("ContentParent::RecvRawMessage", aMeta.actorName(),
7840 aMeta.messageName(), aData);
7841 ReceiveRawMessage(aMeta, std::move(data), std::move(stack));
7842 return IPC_OK();
7845 NS_IMETHODIMP ContentParent::GetActor(const nsACString& aName, JSContext* aCx,
7846 JSProcessActorParent** retval) {
7847 ErrorResult error;
7848 RefPtr<JSProcessActorParent> actor =
7849 JSActorManager::GetActor(aCx, aName, error)
7850 .downcast<JSProcessActorParent>();
7851 if (error.MaybeSetPendingException(aCx)) {
7852 return NS_ERROR_FAILURE;
7854 actor.forget(retval);
7855 return NS_OK;
7858 NS_IMETHODIMP ContentParent::GetExistingActor(const nsACString& aName,
7859 JSProcessActorParent** retval) {
7860 RefPtr<JSProcessActorParent> actor =
7861 JSActorManager::GetExistingActor(aName).downcast<JSProcessActorParent>();
7862 actor.forget(retval);
7863 return NS_OK;
7866 already_AddRefed<JSActor> ContentParent::InitJSActor(
7867 JS::Handle<JSObject*> aMaybeActor, const nsACString& aName,
7868 ErrorResult& aRv) {
7869 RefPtr<JSProcessActorParent> actor;
7870 if (aMaybeActor.get()) {
7871 aRv = UNWRAP_OBJECT(JSProcessActorParent, aMaybeActor.get(), actor);
7872 if (aRv.Failed()) {
7873 return nullptr;
7875 } else {
7876 actor = new JSProcessActorParent();
7879 MOZ_RELEASE_ASSERT(!actor->Manager(),
7880 "mManager was already initialized once!");
7881 actor->Init(aName, this);
7882 return actor.forget();
7885 IPCResult ContentParent::RecvFOGData(ByteBuf&& buf) {
7886 glean::FOGData(std::move(buf));
7887 return IPC_OK();
7890 mozilla::ipc::IPCResult ContentParent::RecvSetContainerFeaturePolicy(
7891 const MaybeDiscardedBrowsingContext& aContainerContext,
7892 MaybeFeaturePolicyInfo&& aContainerFeaturePolicyInfo) {
7893 if (aContainerContext.IsNullOrDiscarded()) {
7894 return IPC_OK();
7897 auto* context = aContainerContext.get_canonical();
7898 context->SetContainerFeaturePolicy(std::move(aContainerFeaturePolicyInfo));
7900 return IPC_OK();
7903 NS_IMETHODIMP ContentParent::GetCanSend(bool* aCanSend) {
7904 *aCanSend = CanSend();
7905 return NS_OK;
7908 ContentParent* ContentParent::AsContentParent() { return this; }
7910 JSActorManager* ContentParent::AsJSActorManager() { return this; }
7912 IPCResult ContentParent::RecvGetSystemIcon(nsIURI* aURI,
7913 GetSystemIconResolver&& aResolver) {
7914 using ResolverArgs = std::tuple<const nsresult&, mozilla::Maybe<ByteBuf>&&>;
7916 if (!aURI) {
7917 Maybe<ByteBuf> bytebuf = Nothing();
7918 aResolver(ResolverArgs(NS_ERROR_NULL_POINTER, std::move(bytebuf)));
7919 return IPC_OK();
7922 #if defined(MOZ_WIDGET_GTK)
7923 Maybe<ByteBuf> bytebuf = Some(ByteBuf{});
7924 nsresult rv = nsIconChannel::GetIcon(aURI, bytebuf.ptr());
7925 if (NS_WARN_IF(NS_FAILED(rv))) {
7926 bytebuf = Nothing();
7928 aResolver(ResolverArgs(rv, std::move(bytebuf)));
7929 return IPC_OK();
7930 #elif defined(XP_WIN)
7931 nsIconChannel::GetIconAsync(aURI)->Then(
7932 GetCurrentSerialEventTarget(), __func__,
7933 [aResolver](ByteBuf&& aByteBuf) {
7934 Maybe<ByteBuf> bytebuf = Some(std::move(aByteBuf));
7935 aResolver(ResolverArgs(NS_OK, std::move(bytebuf)));
7937 [aResolver](nsresult aErr) {
7938 Maybe<ByteBuf> bytebuf = Nothing();
7939 aResolver(ResolverArgs(aErr, std::move(bytebuf)));
7941 return IPC_OK();
7942 #else
7943 MOZ_CRASH(
7944 "This message is currently implemented only on GTK and Windows "
7945 "platforms");
7946 #endif
7949 #ifdef FUZZING_SNAPSHOT
7950 IPCResult ContentParent::RecvSignalFuzzingReady() {
7951 // No action needed here, we already observe this message directly
7952 // on the channel and act accordingly.
7953 return IPC_OK();
7955 #endif
7957 nsCString ThreadsafeContentParentHandle::GetRemoteType() {
7958 RecursiveMutexAutoLock lock(mMutex);
7959 return mRemoteType;
7962 UniqueThreadsafeContentParentKeepAlive
7963 ThreadsafeContentParentHandle::TryAddKeepAlive(uint64_t aBrowserId) {
7964 RecursiveMutexAutoLock lock(mMutex);
7965 // If shutdown has already started, we can't keep this ContentParent alive
7966 // anymore.
7967 if (mShutdownStarted) {
7968 return nullptr;
7971 // Otherwise, ensure there is an entry for this BrowserId, and increment it.
7972 ++mKeepAlivesPerBrowserId.LookupOrInsert(aBrowserId, 0);
7973 return UniqueThreadsafeContentParentKeepAlive{do_AddRef(this).take(),
7974 {.mBrowserId = aBrowserId}};
7977 } // namespace dom
7978 } // namespace mozilla
7980 NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
7982 NS_IMETHODIMP
7983 ParentIdleListener::Observe(nsISupports*, const char* aTopic,
7984 const char16_t* aData) {
7985 mozilla::Unused << mParent->SendNotifyIdleObserver(
7986 mObserver, nsDependentCString(aTopic), nsDependentString(aData));
7987 return NS_OK;
7990 #undef LOGPDM