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 #ifdef MOZ_WIDGET_ANDROID
8 # include "AndroidDecoderModule.h"
11 #include "mozilla/AppShutdown.h"
12 #include "mozilla/DebugOnly.h"
14 #include "base/basictypes.h"
15 #include "base/shared_memory.h"
17 #include "ContentParent.h"
18 #include "mozilla/ipc/ProcessUtils.h"
19 #include "mozilla/CmdLineAndEnvUtils.h"
20 #include "BrowserParent.h"
22 #include "chrome/common/process_watcher.h"
23 #include "mozilla/Result.h"
24 #include "mozilla/XREAppData.h"
25 #include "nsComponentManagerUtils.h"
26 #include "nsIBrowserDOMWindow.h"
28 #include "GMPServiceParent.h"
29 #include "HandlerServiceParent.h"
34 #include "ContentProcessManager.h"
35 #include "GeckoProfiler.h"
36 #include "Geolocation.h"
37 #include "GfxInfoBase.h"
38 #include "MMPrinter.h"
39 #include "PreallocatedProcessManager.h"
40 #include "ProcessPriorityManager.h"
41 #include "ProfilerParent.h"
42 #include "SandboxHal.h"
43 #include "SourceSurfaceRawData.h"
44 #include "mozilla/ipc/URIUtils.h"
45 #include "gfxPlatform.h"
46 #include "gfxPlatformFontList.h"
47 #include "nsDNSService2.h"
48 #include "nsPIDNSService.h"
49 #include "mozilla/AntiTrackingUtils.h"
50 #include "mozilla/AppShutdown.h"
51 #include "mozilla/AutoRestore.h"
52 #include "mozilla/BasePrincipal.h"
53 #include "mozilla/BenchmarkStorageParent.h"
54 #include "mozilla/Casting.h"
55 #include "mozilla/ClearOnShutdown.h"
56 #include "mozilla/ClipboardReadRequestParent.h"
57 #include "mozilla/ClipboardWriteRequestParent.h"
58 #include "mozilla/ContentBlockingUserInteraction.h"
59 #include "mozilla/FOGIPC.h"
60 #include "mozilla/GlobalStyleSheetCache.h"
61 #include "mozilla/GeckoArgs.h"
62 #include "mozilla/HangDetails.h"
63 #include "mozilla/LookAndFeel.h"
64 #include "mozilla/Maybe.h"
65 #include "mozilla/NullPrincipal.h"
66 #include "mozilla/Preferences.h"
67 #include "mozilla/PresShell.h"
68 #include "mozilla/ProcessHangMonitor.h"
69 #include "mozilla/ProcessHangMonitorIPC.h"
70 #include "mozilla/ProfilerLabels.h"
71 #include "mozilla/ProfilerMarkers.h"
72 #include "mozilla/RecursiveMutex.h"
73 #include "mozilla/ScopeExit.h"
74 #include "mozilla/ScriptPreloader.h"
75 #include "mozilla/Components.h"
76 #include "mozilla/Sprintf.h"
77 #include "mozilla/StaticPrefs_dom.h"
78 #include "mozilla/StaticPrefs_fission.h"
79 #include "mozilla/StaticPrefs_media.h"
80 #include "mozilla/StaticPrefs_network.h"
81 #include "mozilla/StaticPrefs_widget.h"
82 #include "mozilla/StorageAccessAPIHelper.h"
83 #include "mozilla/StyleSheet.h"
84 #include "mozilla/StyleSheetInlines.h"
85 #include "mozilla/TaskController.h"
86 #include "mozilla/Telemetry.h"
87 #include "mozilla/TelemetryIPC.h"
88 #include "mozilla/ThreadSafety.h"
89 #include "mozilla/Unused.h"
90 #include "mozilla/WebBrowserPersistDocumentParent.h"
91 #include "mozilla/devtools/HeapSnapshotTempFileHelperParent.h"
92 #include "mozilla/dom/BlobURLProtocolHandler.h"
93 #include "mozilla/dom/BrowserHost.h"
94 #include "mozilla/dom/BrowsingContext.h"
95 #include "mozilla/dom/BrowsingContextGroup.h"
96 #include "mozilla/dom/CancelContentJSOptionsBinding.h"
97 #include "mozilla/dom/CanonicalBrowsingContext.h"
98 #include "mozilla/dom/ClientManager.h"
99 #include "mozilla/dom/ContentChild.h"
100 #include "mozilla/dom/DataTransfer.h"
101 #include "mozilla/dom/Document.h"
102 #include "mozilla/dom/Element.h"
103 #include "mozilla/dom/ExternalHelperAppParent.h"
104 #include "mozilla/dom/File.h"
105 #include "mozilla/dom/FileSystemSecurity.h"
106 #include "mozilla/dom/GeolocationBinding.h"
107 #include "mozilla/dom/GeolocationPositionError.h"
108 #include "mozilla/dom/GetFilesHelper.h"
109 #include "mozilla/dom/IPCBlobUtils.h"
110 #include "mozilla/dom/JSActorService.h"
111 #include "mozilla/dom/JSProcessActorBinding.h"
112 #include "mozilla/dom/LocalStorageCommon.h"
113 #include "mozilla/dom/MediaController.h"
114 #include "mozilla/dom/MemoryReportRequest.h"
115 #include "mozilla/dom/MediaStatusManager.h"
116 #include "mozilla/dom/Notification.h"
117 #include "mozilla/dom/PContentPermissionRequestParent.h"
118 #include "mozilla/dom/PCycleCollectWithLogsParent.h"
119 #include "mozilla/dom/ParentProcessMessageManager.h"
120 #include "mozilla/dom/Permissions.h"
121 #include "mozilla/dom/ProcessMessageManager.h"
122 #include "mozilla/dom/PushNotifier.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/URLClassifierParent.h"
130 #include "mozilla/dom/WindowGlobalParent.h"
131 #include "mozilla/dom/ipc/SharedMap.h"
132 #include "mozilla/dom/ipc/StructuredCloneData.h"
133 #include "mozilla/dom/nsMixedContentBlocker.h"
134 #include "mozilla/dom/power/PowerManagerService.h"
135 #include "mozilla/dom/quota/QuotaManagerService.h"
136 #include "mozilla/extensions/ExtensionsParent.h"
137 #include "mozilla/extensions/StreamFilterParent.h"
138 #include "mozilla/gfx/GPUProcessManager.h"
139 #include "mozilla/gfx/gfxVars.h"
140 #include "mozilla/glean/GleanPings.h"
141 #include "mozilla/hal_sandbox/PHalParent.h"
142 #include "mozilla/intl/L10nRegistry.h"
143 #include "mozilla/intl/LocaleService.h"
144 #include "mozilla/ipc/BackgroundChild.h"
145 #include "mozilla/ipc/BackgroundParent.h"
146 #include "mozilla/ipc/ByteBuf.h"
147 #include "mozilla/ipc/CrashReporterHost.h"
148 #include "mozilla/ipc/Endpoint.h"
149 #include "mozilla/ipc/FileDescriptorUtils.h"
150 #include "mozilla/ipc/IPCStreamUtils.h"
151 #include "mozilla/ipc/TestShellParent.h"
152 #include "mozilla/layers/CompositorThread.h"
153 #include "mozilla/layers/ImageBridgeParent.h"
154 #include "mozilla/layers/LayerTreeOwnerTracker.h"
155 #include "mozilla/layers/PAPZParent.h"
156 #include "mozilla/loader/ScriptCacheActors.h"
157 #include "mozilla/media/MediaParent.h"
158 #include "mozilla/mozSpellChecker.h"
159 #include "mozilla/net/CookieServiceParent.h"
160 #include "mozilla/net/NeckoMessageUtils.h"
161 #include "mozilla/net/NeckoParent.h"
162 #include "mozilla/net/PCookieServiceParent.h"
163 #include "mozilla/net/CookieKey.h"
164 #include "mozilla/net/TRRService.h"
165 #include "mozilla/TelemetryComms.h"
166 #include "mozilla/TelemetryEventEnums.h"
167 #include "mozilla/RemoteLazyInputStreamParent.h"
168 #include "mozilla/widget/RemoteLookAndFeel.h"
169 #include "mozilla/widget/ScreenManager.h"
170 #include "mozilla/widget/TextRecognition.h"
171 #include "nsAnonymousTemporaryFile.h"
172 #include "nsAppRunner.h"
173 #include "nsCExternalHandlerService.h"
174 #include "nsCOMPtr.h"
175 #include "nsChromeRegistryChrome.h"
176 #include "nsConsoleMessage.h"
177 #include "nsConsoleService.h"
178 #include "nsContentPermissionHelper.h"
179 #include "nsContentUtils.h"
181 #include "nsDebugImpl.h"
182 #include "nsDirectoryServiceDefs.h"
183 #include "nsDocShell.h"
184 #include "nsEmbedCID.h"
185 #include "nsFocusManager.h"
186 #include "nsFrameLoader.h"
187 #include "nsFrameMessageManager.h"
188 #include "nsGlobalWindowOuter.h"
189 #include "nsHashPropertyBag.h"
190 #include "nsHyphenationManager.h"
191 #include "nsIAlertsService.h"
192 #include "nsIAppShell.h"
193 #include "nsIAppWindow.h"
194 #include "nsIAsyncInputStream.h"
195 #include "nsIBidiKeyboard.h"
196 #include "nsICaptivePortalService.h"
197 #include "nsICertOverrideService.h"
198 #include "nsIClipboard.h"
199 #include "nsIContentProcess.h"
200 #include "nsIContentSecurityPolicy.h"
201 #include "nsICookie.h"
202 #include "nsICrashService.h"
203 #include "nsICycleCollectorListener.h"
204 #include "nsIDocShell.h"
205 #include "nsIDocShellTreeOwner.h"
206 #include "nsIDragService.h"
207 #include "nsIExternalProtocolService.h"
208 #include "nsIGfxInfo.h"
209 #include "nsIUserIdleService.h"
210 #include "nsIInterfaceRequestorUtils.h"
211 #include "nsILocalStorageManager.h"
212 #include "nsIMemoryInfoDumper.h"
213 #include "nsIMemoryReporter.h"
214 #include "nsIMozBrowserFrame.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"
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"
232 #include "nsMemoryInfoDumper.h"
233 #include "nsMemoryReporterManager.h"
234 #include "nsOpenURIInFrameParams.h"
235 #include "nsPIWindowWatcher.h"
236 #include "nsPluginTags.h"
237 #include "nsQueryObject.h"
238 #include "nsReadableUtils.h"
239 #include "nsSHistory.h"
240 #include "nsScriptError.h"
241 #include "nsServiceManagerUtils.h"
242 #include "nsStreamUtils.h"
243 #include "nsStyleSheetService.h"
244 #include "nsThread.h"
245 #include "nsThreadUtils.h"
246 #include "nsWidgetsCID.h"
247 #include "nsWindowWatcher.h"
250 #include "private/pprio.h"
251 #include "xpcpublic.h"
252 #include "nsOpenWindowInfo.h"
253 #include "nsFrameLoaderOwner.h"
256 # include "jsapi/WebrtcGlobalParent.h"
259 #if defined(XP_MACOSX)
260 # include "nsMacUtilsImpl.h"
261 # include "mozilla/AvailableMemoryWatcher.h"
264 #if defined(ANDROID) || defined(LINUX)
265 # include "nsSystemInfo.h"
268 #if defined(XP_LINUX)
269 # include "mozilla/Hal.h"
273 # include "gfxAndroidPlatform.h"
276 #include "mozilla/PermissionManager.h"
278 #ifdef MOZ_WIDGET_ANDROID
279 # include "AndroidBridge.h"
280 # include "mozilla/java/GeckoProcessManagerWrappers.h"
281 # include "mozilla/java/GeckoProcessTypeWrappers.h"
284 #ifdef MOZ_WIDGET_GTK
285 # include <gdk/gdk.h>
286 # include "mozilla/WidgetUtilsGtk.h"
289 #include "mozilla/RemoteSpellCheckEngineParent.h"
294 # include "mozilla/dom/SpeechSynthesisParent.h"
297 #if defined(MOZ_SANDBOX)
298 # include "mozilla/SandboxSettings.h"
299 # if defined(XP_LINUX)
300 # include "mozilla/SandboxInfo.h"
301 # include "mozilla/SandboxBroker.h"
302 # include "mozilla/SandboxBrokerPolicyFactory.h"
304 # if defined(XP_MACOSX)
305 # include "mozilla/Sandbox.h"
310 # include "mozilla/widget/AudioSession.h"
311 # include "mozilla/WinDllServices.h"
314 #ifdef MOZ_CODE_COVERAGE
315 # include "mozilla/CodeCoverageHandler.h"
318 #ifdef FUZZING_SNAPSHOT
319 # include "mozilla/fuzzing/IPCFuzzController.h"
322 // For VP9Benchmark::sBenchmarkFpsPref
323 #include "Benchmark.h"
325 #include "mozilla/RemoteDecodeUtils.h"
326 #include "nsIToolkitProfileService.h"
327 #include "nsIToolkitProfile.h"
329 static NS_DEFINE_CID(kCClipboardCID
, NS_CLIPBOARD_CID
);
331 using base::KillProcess
;
333 using namespace CrashReporter
;
334 using namespace mozilla::dom::power
;
335 using namespace mozilla::media
;
336 using namespace mozilla::embedding
;
337 using namespace mozilla::gfx
;
338 using namespace mozilla::gmp
;
339 using namespace mozilla::hal
;
340 using namespace mozilla::ipc
;
341 using namespace mozilla::intl
;
342 using namespace mozilla::layers
;
343 using namespace mozilla::layout
;
344 using namespace mozilla::net
;
345 using namespace mozilla::psm
;
346 using namespace mozilla::widget
;
347 using namespace mozilla::Telemetry
;
348 using mozilla::loader::PScriptCacheParent
;
349 using mozilla::Telemetry::ProcessID
;
351 extern mozilla::LazyLogModule gFocusLog
;
353 #define LOGFOCUS(args) MOZ_LOG(gFocusLog, mozilla::LogLevel::Debug, args)
355 extern mozilla::LazyLogModule sPDMLog
;
356 #define LOGPDM(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
359 namespace CubebUtils
{
360 extern FileDescriptor
CreateAudioIPCConnection();
365 LazyLogModule
gProcessLog("Process");
367 static std::map
<RemoteDecodeIn
, media::MediaCodecsSupported
> sCodecsSupported
;
370 uint32_t ContentParent::sMaxContentProcesses
= 0;
373 LogModule
* ContentParent::GetLog() { return gProcessLog
; }
376 uint32_t ContentParent::sPageLoadEventCounter
= 0;
378 #define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
379 #define NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC "ipc:network:set-connectivity"
381 // IPC receiver for remote GC/CC logging.
382 class CycleCollectWithLogsParent final
: public PCycleCollectWithLogsParent
{
384 MOZ_COUNTED_DTOR(CycleCollectWithLogsParent
)
386 static bool AllocAndSendConstructor(ContentParent
* aManager
,
388 nsICycleCollectorLogSink
* aSink
,
389 nsIDumpGCAndCCLogsCallback
* aCallback
) {
390 CycleCollectWithLogsParent
* actor
;
395 actor
= new CycleCollectWithLogsParent(aSink
, aCallback
);
396 rv
= actor
->mSink
->Open(&gcLog
, &ccLog
);
397 if (NS_WARN_IF(NS_FAILED(rv
))) {
402 return aManager
->SendPCycleCollectWithLogsConstructor(
403 actor
, aDumpAllTraces
, FILEToFileDescriptor(gcLog
),
404 FILEToFileDescriptor(ccLog
));
408 virtual mozilla::ipc::IPCResult
RecvCloseGCLog() override
{
409 Unused
<< mSink
->CloseGCLog();
413 virtual mozilla::ipc::IPCResult
RecvCloseCCLog() override
{
414 Unused
<< mSink
->CloseCCLog();
418 virtual mozilla::ipc::IPCResult
Recv__delete__() override
{
419 // Report completion to mCallback only on successful
420 // completion of the protocol.
421 nsCOMPtr
<nsIFile
> gcLog
, ccLog
;
422 mSink
->GetGcLog(getter_AddRefs(gcLog
));
423 mSink
->GetCcLog(getter_AddRefs(ccLog
));
424 Unused
<< mCallback
->OnDump(gcLog
, ccLog
, /* parent = */ false);
428 virtual void ActorDestroy(ActorDestroyReason aReason
) override
{
429 // If the actor is unexpectedly destroyed, we deliberately
430 // don't call Close[GC]CLog on the sink, because the logs may
431 // be incomplete. See also the nsCycleCollectorLogSinkToFile
432 // implementaiton of those methods, and its destructor.
435 CycleCollectWithLogsParent(nsICycleCollectorLogSink
* aSink
,
436 nsIDumpGCAndCCLogsCallback
* aCallback
)
437 : mSink(aSink
), mCallback(aCallback
) {
438 MOZ_COUNT_CTOR(CycleCollectWithLogsParent
);
441 nsCOMPtr
<nsICycleCollectorLogSink
> mSink
;
442 nsCOMPtr
<nsIDumpGCAndCCLogsCallback
> mCallback
;
445 // A memory reporter for ContentParent objects themselves.
446 class ContentParentsMemoryReporter final
: public nsIMemoryReporter
{
447 ~ContentParentsMemoryReporter() = default;
451 NS_DECL_NSIMEMORYREPORTER
454 NS_IMPL_ISUPPORTS(ContentParentsMemoryReporter
, nsIMemoryReporter
)
457 ContentParentsMemoryReporter::CollectReports(
458 nsIHandleReportCallback
* aHandleReport
, nsISupports
* aData
,
460 AutoTArray
<ContentParent
*, 16> cps
;
461 ContentParent::GetAllEvenIfDead(cps
);
463 for (uint32_t i
= 0; i
< cps
.Length(); i
++) {
464 ContentParent
* cp
= cps
[i
];
465 MessageChannel
* channel
= cp
->GetIPCChannel();
467 nsString friendlyName
;
468 cp
->FriendlyName(friendlyName
, aAnonymize
);
471 nsrefcnt refcnt
= cp
->Release();
473 const char* channelStr
= "no channel";
474 uint32_t numQueuedMessages
= 0;
476 if (channel
->IsClosed()) {
477 channelStr
= "closed channel";
479 channelStr
= "open channel";
482 0; // XXX was channel->Unsound_NumQueuedMessages(); Bug 1754876
485 nsPrintfCString
path(
486 "queued-ipc-messages/content-parent"
487 "(%s, pid=%d, %s, 0x%p, refcnt=%" PRIuPTR
")",
488 NS_ConvertUTF16toUTF8(friendlyName
).get(), cp
->Pid(), channelStr
,
489 static_cast<nsIObserver
*>(cp
), refcnt
);
491 constexpr auto desc
=
492 "The number of unset IPC messages held in this ContentParent's "
493 "channel. A large value here might indicate that we're leaking "
494 "messages. Similarly, a ContentParent object for a process that's no "
495 "longer running could indicate that we're leaking ContentParents."_ns
;
497 aHandleReport
->Callback(/* process */ ""_ns
, path
, KIND_OTHER
, UNITS_COUNT
,
498 numQueuedMessages
, desc
, aData
);
504 // A hashtable (by type) of processes/ContentParents. This includes
505 // processes that are in the Preallocator cache (which would be type
506 // 'prealloc'), and recycled processes ('web' and in the future
507 // eTLD+1-locked) processes).
508 nsClassHashtable
<nsCStringHashKey
, nsTArray
<ContentParent
*>>*
509 ContentParent::sBrowserContentParents
;
513 uint64_t ComputeLoadedOriginHash(nsIPrincipal
* aPrincipal
) {
514 uint32_t originNoSuffix
=
515 BasePrincipal::Cast(aPrincipal
)->GetOriginNoSuffixHash();
516 uint32_t originSuffix
=
517 BasePrincipal::Cast(aPrincipal
)->GetOriginSuffixHash();
519 return ((uint64_t)originNoSuffix
) << 32 | originSuffix
;
522 class ScriptableCPInfo final
: public nsIContentProcessInfo
{
524 explicit ScriptableCPInfo(ContentParent
* aParent
) : mContentParent(aParent
) {
525 MOZ_ASSERT(mContentParent
);
529 NS_DECL_NSICONTENTPROCESSINFO
531 void ProcessDied() { mContentParent
= nullptr; }
534 ~ScriptableCPInfo() { MOZ_ASSERT(!mContentParent
, "must call ProcessDied"); }
536 ContentParent
* mContentParent
;
539 NS_IMPL_ISUPPORTS(ScriptableCPInfo
, nsIContentProcessInfo
)
542 ScriptableCPInfo::GetIsAlive(bool* aIsAlive
) {
543 *aIsAlive
= mContentParent
!= nullptr;
548 ScriptableCPInfo::GetProcessId(int32_t* aPID
) {
549 if (!mContentParent
) {
551 return NS_ERROR_NOT_INITIALIZED
;
554 *aPID
= mContentParent
->Pid();
556 return NS_ERROR_FAILURE
;
563 ScriptableCPInfo::GetTabCount(int32_t* aTabCount
) {
564 if (!mContentParent
) {
565 return NS_ERROR_NOT_INITIALIZED
;
568 ContentProcessManager
* cpm
= ContentProcessManager::GetSingleton();
569 *aTabCount
= cpm
->GetBrowserParentCountByProcessId(mContentParent
->ChildID());
575 ScriptableCPInfo::GetMessageManager(nsISupports
** aMessenger
) {
576 *aMessenger
= nullptr;
577 if (!mContentParent
) {
578 return NS_ERROR_NOT_INITIALIZED
;
581 RefPtr
<ProcessMessageManager
> manager
= mContentParent
->GetMessageManager();
582 manager
.forget(aMessenger
);
586 ProcessID
GetTelemetryProcessID(const nsACString
& remoteType
) {
587 // OOP WebExtensions run in a content process.
588 // For Telemetry though we want to break out collected data from the
589 // WebExtensions process into a separate bucket, to make sure we can analyze
590 // it separately and avoid skewing normal content process metrics.
591 return remoteType
== EXTENSION_REMOTE_TYPE
? ProcessID::Extension
592 : ProcessID::Content
;
595 } // anonymous namespace
597 StaticAutoPtr
<nsTHashMap
<nsUint32HashKey
, ContentParent
*>>
598 ContentParent::sJSPluginContentParents
;
599 StaticAutoPtr
<LinkedList
<ContentParent
>> ContentParent::sContentParents
;
600 StaticRefPtr
<ContentParent
> ContentParent::sRecycledE10SProcess
;
601 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
602 StaticAutoPtr
<SandboxBrokerPolicyFactory
>
603 ContentParent::sSandboxBrokerPolicyFactory
;
605 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
606 StaticAutoPtr
<std::vector
<std::string
>> ContentParent::sMacSandboxParams
;
609 // Set to true when the first content process gets created.
610 static bool sCreatedFirstContentProcess
= false;
612 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
613 // True when we're running the process selection code, and do not expect to
614 // enter code paths where processes may die.
615 static bool sInProcessSelector
= false;
618 // The first content child has ID 1, so the chrome process can have ID 0.
619 static uint64_t gContentChildID
= 1;
621 static const char* sObserverTopics
[] = {
622 NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC
,
623 NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC
,
624 NS_IPC_CAPTIVE_PORTAL_SET_STATE
,
625 "application-background",
626 "application-foreground",
631 "child-ghost-request",
632 "last-pb-context-exited",
633 "file-watcher-update",
635 "a11y-init-or-shutdown",
637 "cacheservice:empty-cache",
638 "intl:app-locales-changed",
639 "intl:requested-locales-changed",
641 "private-cookie-changed",
642 NS_NETWORK_LINK_TYPE_TOPIC
,
643 NS_NETWORK_TRR_MODE_CHANGED_TOPIC
,
644 "network:socket-process-crashed",
645 DEFAULT_TIMEZONE_CHANGED_OBSERVER_TOPIC
,
648 // PreallocateProcess is called by the PreallocatedProcessManager.
649 // ContentParent then takes this process back within GetNewOrUsedBrowserProcess.
650 /*static*/ already_AddRefed
<ContentParent
>
651 ContentParent::MakePreallocProcess() {
652 RefPtr
<ContentParent
> process
= new ContentParent(PREALLOC_REMOTE_TYPE
);
653 return process
.forget();
657 void ContentParent::StartUp() {
658 // FIXME Bug 1023701 - Stop using ContentParent static methods in
660 if (!XRE_IsParentProcess()) {
664 // From this point on, NS_WARNING, NS_ASSERTION, etc. should print out the
665 // PID along with the warning.
666 nsDebugImpl::SetMultiprocessMode("Parent");
668 // Note: This reporter measures all ContentParents.
669 RegisterStrongMemoryReporter(new ContentParentsMemoryReporter());
671 BackgroundChild::Startup();
672 ClientManager::Startup();
674 Preferences::RegisterCallbackAndCall(&OnFissionBlocklistPrefChange
,
675 kFissionEnforceBlockList
);
676 Preferences::RegisterCallbackAndCall(&OnFissionBlocklistPrefChange
,
677 kFissionOmitBlockListValues
);
679 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
680 sSandboxBrokerPolicyFactory
= new SandboxBrokerPolicyFactory();
683 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
684 sMacSandboxParams
= new std::vector
<std::string
>();
689 void ContentParent::ShutDown() {
690 // For the most, we rely on normal process shutdown and
691 // ClearOnShutdown() to clean up our state.
693 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
694 sSandboxBrokerPolicyFactory
= nullptr;
697 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
698 sMacSandboxParams
= nullptr;
703 uint32_t ContentParent::GetPoolSize(const nsACString
& aContentProcessType
) {
704 if (!sBrowserContentParents
) {
708 nsTArray
<ContentParent
*>* parents
=
709 sBrowserContentParents
->Get(aContentProcessType
);
711 return parents
? parents
->Length() : 0;
714 /*static*/ nsTArray
<ContentParent
*>& ContentParent::GetOrCreatePool(
715 const nsACString
& aContentProcessType
) {
716 if (!sBrowserContentParents
) {
717 sBrowserContentParents
=
718 new nsClassHashtable
<nsCStringHashKey
, nsTArray
<ContentParent
*>>;
721 return *sBrowserContentParents
->GetOrInsertNew(aContentProcessType
);
724 const nsDependentCSubstring
RemoteTypePrefix(
725 const nsACString
& aContentProcessType
) {
726 // The suffix after a `=` in a remoteType is dynamic, and used to control the
727 // process pool to use.
728 int32_t equalIdx
= aContentProcessType
.FindChar(L
'=');
729 if (equalIdx
== kNotFound
) {
730 equalIdx
= aContentProcessType
.Length();
732 return StringHead(aContentProcessType
, equalIdx
);
735 bool IsWebRemoteType(const nsACString
& aContentProcessType
) {
736 // Note: matches webIsolated, web, and webCOOP+COEP types.
737 return StringBeginsWith(aContentProcessType
, DEFAULT_REMOTE_TYPE
);
740 bool IsWebCoopCoepRemoteType(const nsACString
& aContentProcessType
) {
741 return StringBeginsWith(aContentProcessType
,
742 WITH_COOP_COEP_REMOTE_TYPE_PREFIX
);
745 bool IsExtensionRemoteType(const nsACString
& aContentProcessType
) {
746 return aContentProcessType
== EXTENSION_REMOTE_TYPE
;
750 uint32_t ContentParent::GetMaxProcessCount(
751 const nsACString
& aContentProcessType
) {
752 // Max process count is based only on the prefix.
753 const nsDependentCSubstring processTypePrefix
=
754 RemoteTypePrefix(aContentProcessType
);
756 // Check for the default remote type of "web", as it uses different prefs.
757 if (processTypePrefix
== DEFAULT_REMOTE_TYPE
) {
758 return GetMaxWebProcessCount();
761 // Read the pref controling this remote type. `dom.ipc.processCount` is not
762 // used as a fallback, as it is intended to control the number of "web"
763 // content processes, checked in `mozilla::GetMaxWebProcessCount()`.
764 nsAutoCString
processCountPref("dom.ipc.processCount.");
765 processCountPref
.Append(processTypePrefix
);
767 int32_t maxContentParents
= Preferences::GetInt(processCountPref
.get(), 1);
768 if (maxContentParents
< 1) {
769 maxContentParents
= 1;
772 return static_cast<uint32_t>(maxContentParents
);
776 bool ContentParent::IsMaxProcessCountReached(
777 const nsACString
& aContentProcessType
) {
778 return GetPoolSize(aContentProcessType
) >=
779 GetMaxProcessCount(aContentProcessType
);
782 // Really more ReleaseUnneededProcesses()
784 void ContentParent::ReleaseCachedProcesses() {
785 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
786 ("ReleaseCachedProcesses:"));
787 if (!sBrowserContentParents
) {
792 for (const auto& cps
: *sBrowserContentParents
) {
793 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
794 ("%s: %zu processes", PromiseFlatCString(cps
.GetKey()).get(),
795 cps
.GetData()->Length()));
799 // First let's collect all processes and keep a grip.
800 AutoTArray
<RefPtr
<ContentParent
>, 32> fixArray
;
801 for (const auto& contentParents
: sBrowserContentParents
->Values()) {
802 for (auto* cp
: *contentParents
) {
803 fixArray
.AppendElement(cp
);
807 for (const auto& cp
: fixArray
) {
808 // Ensure the process cannot be claimed between check and MarkAsDead.
809 RecursiveMutexAutoLock
lock(cp
->ThreadsafeHandleMutex());
811 if (cp
->ManagedPBrowserParent().Count() == 0 &&
812 !cp
->HasActiveWorkerOrJSPlugin() &&
813 cp
->mRemoteType
== DEFAULT_REMOTE_TYPE
) {
814 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
815 (" Shutdown %p (%s)", cp
.get(), cp
->mRemoteType
.get()));
817 PreallocatedProcessManager::Erase(cp
);
818 // Make sure we don't select this process for new tabs or workers.
820 // Start a soft shutdown.
821 cp
->ShutDownProcess(SEND_SHUTDOWN_MESSAGE
);
822 // Make sure that this process is no longer accessible from JS by its
824 cp
->ShutDownMessageManager();
827 ContentParent::GetLog(), LogLevel::Debug
,
828 (" Skipping %p (%s), count %d, HasActiveWorkerOrJSPlugin %d",
829 cp
.get(), cp
->mRemoteType
.get(), cp
->ManagedPBrowserParent().Count(),
830 cp
->HasActiveWorkerOrJSPlugin()));
836 already_AddRefed
<ContentParent
> ContentParent::MinTabSelect(
837 const nsTArray
<ContentParent
*>& aContentParents
,
838 int32_t aMaxContentParents
) {
839 uint32_t maxSelectable
=
840 std::min(static_cast<uint32_t>(aContentParents
.Length()),
841 static_cast<uint32_t>(aMaxContentParents
));
842 uint32_t min
= INT_MAX
;
843 RefPtr
<ContentParent
> candidate
;
844 ContentProcessManager
* cpm
= ContentProcessManager::GetSingleton();
846 for (uint32_t i
= 0; i
< maxSelectable
; i
++) {
847 ContentParent
* p
= aContentParents
[i
];
848 MOZ_DIAGNOSTIC_ASSERT(!p
->IsDead());
850 // Ignore processes that were slated for removal but not yet removed from
851 // the pool (see also GetUsedBrowserProcess and BlockShutdown).
852 if (!p
->IsShuttingDown()) {
853 uint32_t tabCount
= cpm
->GetBrowserParentCountByProcessId(p
->ChildID());
854 if (tabCount
< min
) {
861 // If all current processes have at least one tab and we have not yet reached
862 // the maximum, use a new process.
864 aContentParents
.Length() < static_cast<uint32_t>(aMaxContentParents
)) {
868 // Otherwise we return candidate.
869 return candidate
.forget();
873 already_AddRefed
<nsIPrincipal
>
874 ContentParent::CreateRemoteTypeIsolationPrincipal(
875 const nsACString
& aRemoteType
) {
876 if ((RemoteTypePrefix(aRemoteType
) != FISSION_WEB_REMOTE_TYPE
) &&
877 !StringBeginsWith(aRemoteType
, WITH_COOP_COEP_REMOTE_TYPE_PREFIX
)) {
881 int32_t offset
= aRemoteType
.FindChar('=') + 1;
882 MOZ_ASSERT(offset
> 1, "can not extract origin from that remote type");
883 nsAutoCString
origin(
884 Substring(aRemoteType
, offset
, aRemoteType
.Length() - offset
));
886 nsIScriptSecurityManager
* ssm
= nsContentUtils::GetSecurityManager();
887 nsCOMPtr
<nsIPrincipal
> principal
;
888 ssm
->CreateContentPrincipalFromOrigin(origin
, getter_AddRefs(principal
));
889 return principal
.forget();
893 already_AddRefed
<ContentParent
> ContentParent::GetUsedBrowserProcess(
894 const nsACString
& aRemoteType
, nsTArray
<ContentParent
*>& aContentParents
,
895 uint32_t aMaxContentParents
, bool aPreferUsed
, ProcessPriority aPriority
) {
896 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
897 AutoRestore
ar(sInProcessSelector
);
898 sInProcessSelector
= true;
901 uint32_t numberOfParents
= aContentParents
.Length();
902 nsTArray
<RefPtr
<nsIContentProcessInfo
>> infos(numberOfParents
);
903 for (auto* cp
: aContentParents
) {
904 infos
.AppendElement(cp
->mScriptableHelper
);
907 if (aPreferUsed
&& numberOfParents
) {
908 // If we prefer re-using existing content processes, we don't want to create
909 // a new process, and instead re-use an existing one, so pretend the process
910 // limit is at the current number of processes.
911 aMaxContentParents
= numberOfParents
;
914 nsCOMPtr
<nsIContentProcessProvider
> cpp
=
915 do_GetService("@mozilla.org/ipc/processselector;1");
917 if (cpp
&& NS_SUCCEEDED(cpp
->ProvideProcess(aRemoteType
, infos
,
918 aMaxContentParents
, &index
))) {
919 // If the provider returned an existing ContentParent, use that one.
920 if (0 <= index
&& static_cast<uint32_t>(index
) <= aMaxContentParents
) {
921 RefPtr
<ContentParent
> retval
= aContentParents
[index
];
922 // Ignore processes that were slated for removal but not yet removed from
924 if (!retval
->IsShuttingDown()) {
925 if (profiler_thread_is_being_profiled_for_markers()) {
926 nsPrintfCString
marker("Reused process %u",
927 (unsigned int)retval
->ChildID());
928 PROFILER_MARKER_TEXT("Process", DOM
, {}, marker
);
930 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
931 ("GetUsedProcess: Reused process %p (%u) for %s", retval
.get(),
932 (unsigned int)retval
->ChildID(),
933 PromiseFlatCString(aRemoteType
).get()));
934 retval
->AssertAlive();
935 retval
->StopRecyclingE10SOnly(true);
936 return retval
.forget();
940 // If there was a problem with the JS chooser, fall back to a random
942 NS_WARNING("nsIContentProcessProvider failed to return a process");
943 RefPtr
<ContentParent
> random
;
944 if ((random
= MinTabSelect(aContentParents
, aMaxContentParents
))) {
945 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
946 ("GetUsedProcess: Reused random process %p (%d) for %s",
947 random
.get(), (unsigned int)random
->ChildID(),
948 PromiseFlatCString(aRemoteType
).get()));
949 random
->AssertAlive();
950 random
->StopRecyclingE10SOnly(true);
951 return random
.forget();
955 // If we are loading into the "web" remote type, are choosing to launch a new
956 // tab, and have a recycled E10S process, we should launch into that process.
957 if (aRemoteType
== DEFAULT_REMOTE_TYPE
&& sRecycledE10SProcess
) {
958 RefPtr
<ContentParent
> recycled
= sRecycledE10SProcess
;
959 MOZ_DIAGNOSTIC_ASSERT(recycled
->GetRemoteType() == DEFAULT_REMOTE_TYPE
);
960 recycled
->AssertAlive();
961 recycled
->StopRecyclingE10SOnly(true);
962 if (profiler_thread_is_being_profiled_for_markers()) {
963 nsPrintfCString
marker("Recycled process %u (%p)",
964 (unsigned int)recycled
->ChildID(), recycled
.get());
965 PROFILER_MARKER_TEXT("Process", DOM
, {}, marker
);
967 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
968 ("Recycled process %p", recycled
.get()));
970 return recycled
.forget();
973 // Try to take a preallocated process except for certain remote types.
974 // Note: this process may not have finished launching yet
975 RefPtr
<ContentParent
> preallocated
;
976 if (aRemoteType
!= FILE_REMOTE_TYPE
&&
977 aRemoteType
!= PRIVILEGEDABOUT_REMOTE_TYPE
&&
978 aRemoteType
!= EXTENSION_REMOTE_TYPE
&& // Bug 1638119
979 (preallocated
= PreallocatedProcessManager::Take(aRemoteType
))) {
980 MOZ_DIAGNOSTIC_ASSERT(preallocated
->GetRemoteType() ==
981 PREALLOC_REMOTE_TYPE
);
982 MOZ_DIAGNOSTIC_ASSERT(sRecycledE10SProcess
!= preallocated
);
983 preallocated
->AssertAlive();
985 if (profiler_thread_is_being_profiled_for_markers()) {
986 nsPrintfCString
marker(
987 "Assigned preallocated process %u%s",
988 (unsigned int)preallocated
->ChildID(),
989 preallocated
->IsLaunching() ? " (still launching)" : "");
990 PROFILER_MARKER_TEXT("Process", DOM
, {}, marker
);
992 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
993 ("Adopted preallocated process %p for type %s%s",
994 preallocated
.get(), PromiseFlatCString(aRemoteType
).get(),
995 preallocated
->IsLaunching() ? " (still launching)" : ""));
997 // This ensures that the preallocator won't shut down the process once
998 // it finishes starting
999 preallocated
->mRemoteType
.Assign(aRemoteType
);
1001 RecursiveMutexAutoLock
lock(preallocated
->mThreadsafeHandle
->mMutex
);
1002 preallocated
->mThreadsafeHandle
->mRemoteType
= preallocated
->mRemoteType
;
1004 preallocated
->mRemoteTypeIsolationPrincipal
=
1005 CreateRemoteTypeIsolationPrincipal(aRemoteType
);
1006 preallocated
->mActivateTS
= TimeStamp::Now();
1007 preallocated
->AddToPool(aContentParents
);
1009 // rare, but will happen
1010 if (!preallocated
->IsLaunching()) {
1011 // Specialize this process for the appropriate remote type, and activate
1014 Unused
<< preallocated
->SendRemoteType(preallocated
->mRemoteType
,
1015 preallocated
->mProfile
);
1017 nsCOMPtr
<nsIObserverService
> obs
=
1018 mozilla::services::GetObserverService();
1021 cpId
.AppendInt(static_cast<uint64_t>(preallocated
->ChildID()));
1022 obs
->NotifyObservers(static_cast<nsIObserver
*>(preallocated
),
1023 "process-type-set", cpId
.get());
1024 preallocated
->AssertAlive();
1027 return preallocated
.forget();
1034 already_AddRefed
<ContentParent
>
1035 ContentParent::GetNewOrUsedLaunchingBrowserProcess(
1036 const nsACString
& aRemoteType
, BrowsingContextGroup
* aGroup
,
1037 ProcessPriority aPriority
, bool aPreferUsed
) {
1038 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
1039 ("GetNewOrUsedProcess for type %s",
1040 PromiseFlatCString(aRemoteType
).get()));
1042 // Fallback check (we really want our callers to avoid this).
1043 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
1044 MOZ_DIAGNOSTIC_ASSERT(
1045 false, "Late attempt to GetNewOrUsedLaunchingBrowserProcess!");
1049 // If we have an existing host process attached to this BrowsingContextGroup,
1050 // always return it, as we can never have multiple host processes within a
1051 // single BrowsingContextGroup.
1052 RefPtr
<ContentParent
> contentParent
;
1054 contentParent
= aGroup
->GetHostProcess(aRemoteType
);
1055 Unused
<< NS_WARN_IF(contentParent
&& contentParent
->IsShuttingDown());
1056 if (contentParent
&& !contentParent
->IsShuttingDown()) {
1057 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
1058 ("GetNewOrUsedProcess: Existing host process %p (launching %d)",
1059 contentParent
.get(), contentParent
->IsLaunching()));
1060 contentParent
->AssertAlive();
1061 contentParent
->StopRecyclingE10SOnly(true);
1062 return contentParent
.forget();
1066 nsTArray
<ContentParent
*>& contentParents
= GetOrCreatePool(aRemoteType
);
1067 uint32_t maxContentParents
= GetMaxProcessCount(aRemoteType
);
1069 // Let's try and reuse an existing process.
1070 contentParent
= GetUsedBrowserProcess(
1071 aRemoteType
, contentParents
, maxContentParents
, aPreferUsed
, aPriority
);
1073 if (!contentParent
) {
1074 // No reusable process. Let's create and launch one.
1075 // The life cycle will be set to `LifecycleState::LAUNCHING`.
1076 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
1077 ("Launching new process immediately for type %s",
1078 PromiseFlatCString(aRemoteType
).get()));
1080 contentParent
= new ContentParent(aRemoteType
);
1081 if (NS_WARN_IF(!contentParent
->BeginSubprocessLaunch(aPriority
))) {
1082 // Launch aborted because of shutdown. Bailout.
1083 contentParent
->LaunchSubprocessReject();
1086 // Until the new process is ready let's not allow to start up any
1087 // preallocated processes. The blocker will be removed once we receive
1088 // the first idle message.
1089 contentParent
->mIsAPreallocBlocker
= true;
1090 PreallocatedProcessManager::AddBlocker(aRemoteType
, contentParent
);
1092 // Store this process for future reuse.
1093 contentParent
->AddToPool(contentParents
);
1096 ContentParent::GetLog(), LogLevel::Debug
,
1097 ("GetNewOrUsedProcess: new immediate process %p", contentParent
.get()));
1099 // else we have an existing or preallocated process (which may be
1102 contentParent
->AssertAlive();
1103 contentParent
->StopRecyclingE10SOnly(true);
1105 aGroup
->EnsureHostProcess(contentParent
);
1107 return contentParent
.forget();
1111 RefPtr
<ContentParent::LaunchPromise
>
1112 ContentParent::GetNewOrUsedBrowserProcessAsync(const nsACString
& aRemoteType
,
1113 BrowsingContextGroup
* aGroup
,
1114 ProcessPriority aPriority
,
1116 // Obtain a `ContentParent` launched asynchronously.
1117 RefPtr
<ContentParent
> contentParent
= GetNewOrUsedLaunchingBrowserProcess(
1118 aRemoteType
, aGroup
, aPriority
, aPreferUsed
);
1119 if (!contentParent
) {
1120 // In case of launch error, stop here.
1121 return LaunchPromise::CreateAndReject(NS_ERROR_ILLEGAL_DURING_SHUTDOWN
,
1124 return contentParent
->WaitForLaunchAsync(aPriority
);
1128 already_AddRefed
<ContentParent
> ContentParent::GetNewOrUsedBrowserProcess(
1129 const nsACString
& aRemoteType
, BrowsingContextGroup
* aGroup
,
1130 ProcessPriority aPriority
, bool aPreferUsed
) {
1131 RefPtr
<ContentParent
> contentParent
= GetNewOrUsedLaunchingBrowserProcess(
1132 aRemoteType
, aGroup
, aPriority
, aPreferUsed
);
1133 if (!contentParent
|| !contentParent
->WaitForLaunchSync(aPriority
)) {
1134 // In case of launch error, stop here.
1137 return contentParent
.forget();
1140 RefPtr
<ContentParent::LaunchPromise
> ContentParent::WaitForLaunchAsync(
1141 ProcessPriority aPriority
) {
1142 MOZ_DIAGNOSTIC_ASSERT(!IsDead());
1143 if (!IsLaunching()) {
1144 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
1145 ("WaitForLaunchAsync: launched"));
1146 return LaunchPromise::CreateAndResolve(this, __func__
);
1149 // We've started an async content process launch.
1150 Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC
, 0);
1152 // We have located a process that hasn't finished initializing, then attempt
1153 // to finish initializing. Both `LaunchSubprocessResolve` and
1154 // `LaunchSubprocessReject` are safe to call multiple times if we race with
1155 // other `WaitForLaunchAsync` callbacks.
1156 return mSubprocess
->WhenProcessHandleReady()->Then(
1157 GetCurrentSerialEventTarget(), __func__
,
1158 [self
= RefPtr
{this}, aPriority
]() {
1159 if (self
->LaunchSubprocessResolve(/* aIsSync = */ false, aPriority
)) {
1160 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
1161 ("WaitForLaunchAsync: async, now launched"));
1162 self
->mActivateTS
= TimeStamp::Now();
1163 return LaunchPromise::CreateAndResolve(self
, __func__
);
1166 self
->LaunchSubprocessReject();
1167 return LaunchPromise::CreateAndReject(NS_ERROR_INVALID_ARG
, __func__
);
1169 [self
= RefPtr
{this}]() {
1170 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
1171 ("WaitForLaunchAsync: async, rejected"));
1172 self
->LaunchSubprocessReject();
1173 return LaunchPromise::CreateAndReject(NS_ERROR_FAILURE
, __func__
);
1177 bool ContentParent::WaitForLaunchSync(ProcessPriority aPriority
) {
1178 MOZ_DIAGNOSTIC_ASSERT(!IsDead());
1179 if (!IsLaunching()) {
1183 // We've started a sync content process launch.
1184 Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC
, 1);
1186 // We're a process which hasn't finished initializing. We may be racing
1187 // against whoever launched it (and whoever else is already racing). Since
1188 // we're sync, we win the race and finish the initialization.
1189 bool launchSuccess
= mSubprocess
->WaitForProcessHandle();
1190 if (launchSuccess
&&
1191 LaunchSubprocessResolve(/* aIsSync = */ true, aPriority
)) {
1192 mActivateTS
= TimeStamp::Now();
1195 // In case of failure.
1196 LaunchSubprocessReject();
1201 already_AddRefed
<ContentParent
> ContentParent::GetNewOrUsedJSPluginProcess(
1202 uint32_t aPluginID
, const hal::ProcessPriority
& aPriority
) {
1203 RefPtr
<ContentParent
> p
;
1204 if (sJSPluginContentParents
) {
1205 p
= sJSPluginContentParents
->Get(aPluginID
);
1207 sJSPluginContentParents
= new nsTHashMap
<nsUint32HashKey
, ContentParent
*>();
1214 p
= new ContentParent(aPluginID
);
1216 if (!p
->LaunchSubprocessSync(aPriority
)) {
1220 sJSPluginContentParents
->InsertOrUpdate(aPluginID
, p
);
1225 static nsIDocShell
* GetOpenerDocShellHelper(Element
* aFrameElement
) {
1226 // Propagate the private-browsing status of the element's parent
1227 // docshell to the remote docshell, via the chrome flags.
1228 MOZ_ASSERT(aFrameElement
);
1229 nsPIDOMWindowOuter
* win
= aFrameElement
->OwnerDoc()->GetWindow();
1231 NS_WARNING("Remote frame has no window");
1234 nsIDocShell
* docShell
= win
->GetDocShell();
1236 NS_WARNING("Remote frame has no docshell");
1243 mozilla::ipc::IPCResult
ContentParent::RecvCreateGMPService() {
1244 Endpoint
<PGMPServiceParent
> parent
;
1245 Endpoint
<PGMPServiceChild
> child
;
1248 return IPC_FAIL(this, "GMP Service already created");
1252 rv
= PGMPService::CreateEndpoints(base::GetCurrentProcId(), OtherPid(),
1254 if (NS_FAILED(rv
)) {
1255 return IPC_FAIL(this, "CreateEndpoints failed");
1258 if (!GMPServiceParent::Create(std::move(parent
))) {
1259 return IPC_FAIL(this, "GMPServiceParent::Create failed");
1262 if (!SendInitGMPService(std::move(child
))) {
1263 return IPC_FAIL(this, "SendInitGMPService failed");
1271 Atomic
<bool, mozilla::Relaxed
> sContentParentTelemetryEventEnabled(false);
1274 void ContentParent::LogAndAssertFailedPrincipalValidationInfo(
1275 nsIPrincipal
* aPrincipal
, const char* aMethod
) {
1276 // nsContentSecurityManager may also enable this same event, but that's okay
1277 if (!sContentParentTelemetryEventEnabled
.exchange(true)) {
1278 sContentParentTelemetryEventEnabled
= true;
1279 Telemetry::SetEventRecordingEnabled("security"_ns
, true);
1283 nsAutoCString principalScheme
, principalType
, spec
;
1284 CopyableTArray
<EventExtraEntry
> extra(2);
1287 principalType
.AssignLiteral("NullPtr");
1288 } else if (aPrincipal
->IsSystemPrincipal()) {
1289 principalType
.AssignLiteral("SystemPrincipal");
1290 } else if (aPrincipal
->GetIsExpandedPrincipal()) {
1291 principalType
.AssignLiteral("ExpandedPrincipal");
1292 } else if (aPrincipal
->GetIsContentPrincipal()) {
1293 principalType
.AssignLiteral("ContentPrincipal");
1294 aPrincipal
->GetSpec(spec
);
1295 aPrincipal
->GetScheme(principalScheme
);
1297 extra
.AppendElement(EventExtraEntry
{"scheme"_ns
, principalScheme
});
1299 principalType
.AssignLiteral("Unknown");
1302 extra
.AppendElement(EventExtraEntry
{"principalType"_ns
, principalType
});
1304 // Do not send telemetry when chrome-debugging is enabled
1305 bool isChromeDebuggingEnabled
=
1306 Preferences::GetBool("devtools.chrome.enabled", false);
1307 if (!isChromeDebuggingEnabled
) {
1308 Telemetry::EventID eventType
=
1309 Telemetry::EventID::Security_Fissionprincipals_Contentparent
;
1310 Telemetry::RecordEvent(eventType
, mozilla::Some(aMethod
),
1311 mozilla::Some(extra
));
1316 ContentParent::GetLog(), LogLevel::Error
,
1317 (" Receiving unexpected Principal (%s) within %s",
1318 aPrincipal
&& aPrincipal
->GetIsContentPrincipal() ? spec
.get()
1319 : principalType
.get(),
1323 // Not only log but also ensure we do not receive an unexpected
1324 // principal when running in debug mode.
1325 MOZ_ASSERT(false, "Receiving unexpected Principal");
1329 bool ContentParent::ValidatePrincipal(
1330 nsIPrincipal
* aPrincipal
,
1331 const EnumSet
<ValidatePrincipalOptions
>& aOptions
) {
1332 // If the pref says we should not validate, then there is nothing to do
1333 if (!StaticPrefs::dom_security_enforceIPCBasedPrincipalVetting()) {
1337 // If there is no principal, then there is nothing to validate!
1339 return aOptions
.contains(ValidatePrincipalOptions::AllowNullPtr
);
1342 // We currently do not track relationships between specific null principals
1343 // and content processes, so we can not validate much here - just allow all
1344 // null principals we see because they are generally safe anyway!
1345 if (aPrincipal
->GetIsNullPrincipal()) {
1349 // Only allow the system principal if the passed in options flags
1350 // request permitting the system principal.
1351 if (aPrincipal
->IsSystemPrincipal()) {
1352 return aOptions
.contains(ValidatePrincipalOptions::AllowSystem
);
1355 // XXXckerschb: we should eliminate the resource carve-out here and always
1356 // validate the Principal, see Bug 1686200: Investigate Principal for pdf.js
1357 if (aPrincipal
->SchemeIs("resource")) {
1361 // Validate each inner principal individually, allowing us to catch expanded
1362 // principals containing the system principal, etc.
1363 if (aPrincipal
->GetIsExpandedPrincipal()) {
1364 if (!aOptions
.contains(ValidatePrincipalOptions::AllowExpanded
)) {
1367 // FIXME: There are more constraints on expanded principals in-practice,
1368 // such as the structure of extension expanded principals. This may need
1369 // to be investigated more in the future.
1370 nsCOMPtr
<nsIExpandedPrincipal
> expandedPrincipal
=
1371 do_QueryInterface(aPrincipal
);
1372 const auto& allowList
= expandedPrincipal
->AllowList();
1373 for (const auto& innerPrincipal
: allowList
) {
1374 if (!ValidatePrincipal(innerPrincipal
, aOptions
)) {
1381 // A URI with a file:// scheme can never load in a non-file content process
1382 // due to sandboxing.
1383 if (aPrincipal
->SchemeIs("file")) {
1384 // If we don't support a separate 'file' process, then we can return here.
1385 if (!StaticPrefs::browser_tabs_remote_separateFileUriProcess()) {
1388 return mRemoteType
== FILE_REMOTE_TYPE
;
1391 if (aPrincipal
->SchemeIs("about")) {
1393 if (NS_FAILED(aPrincipal
->GetAboutModuleFlags(&flags
))) {
1397 // Block principals for about: URIs which can't load in this process.
1398 if (!(flags
& (nsIAboutModule::URI_CAN_LOAD_IN_CHILD
|
1399 nsIAboutModule::URI_MUST_LOAD_IN_CHILD
))) {
1402 if (flags
& nsIAboutModule::URI_MUST_LOAD_IN_EXTENSION_PROCESS
) {
1403 return mRemoteType
== EXTENSION_REMOTE_TYPE
;
1408 if (!mRemoteTypeIsolationPrincipal
||
1409 RemoteTypePrefix(mRemoteType
) != FISSION_WEB_REMOTE_TYPE
) {
1413 // Web content can contain extension content frames, so a content process may
1414 // send us an extension's principal.
1415 auto* addonPolicy
= BasePrincipal::Cast(aPrincipal
)->AddonPolicy();
1420 // Ensure that the expected site-origin matches the one specified by our
1421 // mRemoteTypeIsolationPrincipal.
1422 nsAutoCString siteOriginNoSuffix
;
1423 if (NS_FAILED(aPrincipal
->GetSiteOriginNoSuffix(siteOriginNoSuffix
))) {
1426 nsAutoCString remoteTypeSiteOriginNoSuffix
;
1427 if (NS_FAILED(mRemoteTypeIsolationPrincipal
->GetSiteOriginNoSuffix(
1428 remoteTypeSiteOriginNoSuffix
))) {
1432 return remoteTypeSiteOriginNoSuffix
.Equals(siteOriginNoSuffix
);
1436 already_AddRefed
<RemoteBrowser
> ContentParent::CreateBrowser(
1437 const TabContext
& aContext
, Element
* aFrameElement
,
1438 const nsACString
& aRemoteType
, BrowsingContext
* aBrowsingContext
,
1439 ContentParent
* aOpenerContentParent
) {
1440 AUTO_PROFILER_LABEL("ContentParent::CreateBrowser", OTHER
);
1442 MOZ_DIAGNOSTIC_ASSERT(
1443 !aBrowsingContext
->Canonical()->GetBrowserParent(),
1444 "BrowsingContext must not have BrowserParent, or have previous "
1445 "BrowserParent cleared");
1447 nsAutoCString
remoteType(aRemoteType
);
1448 if (remoteType
.IsEmpty()) {
1449 remoteType
= DEFAULT_REMOTE_TYPE
;
1452 TabId
tabId(nsContentUtils::GenerateTabId());
1454 nsIDocShell
* docShell
= GetOpenerDocShellHelper(aFrameElement
);
1457 openerTabId
= BrowserParent::GetTabIdFrom(docShell
);
1460 RefPtr
<ContentParent
> constructorSender
;
1461 MOZ_RELEASE_ASSERT(XRE_IsParentProcess(),
1462 "Cannot allocate BrowserParent in content process");
1463 if (aOpenerContentParent
&& !aOpenerContentParent
->IsShuttingDown()) {
1464 constructorSender
= aOpenerContentParent
;
1466 if (aContext
.IsJSPlugin()) {
1467 constructorSender
= GetNewOrUsedJSPluginProcess(
1468 aContext
.JSPluginId(), PROCESS_PRIORITY_FOREGROUND
);
1470 constructorSender
= GetNewOrUsedBrowserProcess(
1471 remoteType
, aBrowsingContext
->Group(), PROCESS_PRIORITY_FOREGROUND
);
1473 if (!constructorSender
) {
1478 aBrowsingContext
->SetEmbedderElement(aFrameElement
);
1480 // Ensure that the process which we're using to launch is set as the host
1481 // process for this BrowsingContextGroup.
1482 aBrowsingContext
->Group()->EnsureHostProcess(constructorSender
);
1484 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
;
1485 docShell
->GetTreeOwner(getter_AddRefs(treeOwner
));
1490 nsCOMPtr
<nsIWebBrowserChrome
> wbc
= do_GetInterface(treeOwner
);
1494 uint32_t chromeFlags
= 0;
1495 wbc
->GetChromeFlags(&chromeFlags
);
1497 nsCOMPtr
<nsILoadContext
> loadContext
= do_QueryInterface(docShell
);
1498 if (loadContext
&& loadContext
->UsePrivateBrowsing()) {
1499 chromeFlags
|= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW
;
1501 if (loadContext
&& loadContext
->UseRemoteTabs()) {
1502 chromeFlags
|= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW
;
1504 if (loadContext
&& loadContext
->UseRemoteSubframes()) {
1505 chromeFlags
|= nsIWebBrowserChrome::CHROME_FISSION_WINDOW
;
1512 aBrowsingContext
->Canonical()->SetOwnerProcessId(
1513 constructorSender
->ChildID());
1515 RefPtr
<BrowserParent
> browserParent
=
1516 new BrowserParent(constructorSender
, tabId
, aContext
,
1517 aBrowsingContext
->Canonical(), chromeFlags
);
1519 // Open a remote endpoint for our PBrowser actor.
1520 ManagedEndpoint
<PBrowserChild
> childEp
=
1521 constructorSender
->OpenPBrowserEndpoint(browserParent
);
1522 if (NS_WARN_IF(!childEp
.IsValid())) {
1526 ContentProcessManager
* cpm
= ContentProcessManager::GetSingleton();
1527 if (NS_WARN_IF(!cpm
)) {
1530 cpm
->RegisterRemoteFrame(browserParent
);
1532 nsCOMPtr
<nsIPrincipal
> initialPrincipal
=
1533 NullPrincipal::Create(aBrowsingContext
->OriginAttributesRef());
1534 WindowGlobalInit windowInit
= WindowGlobalActor::AboutBlankInitializer(
1535 aBrowsingContext
, initialPrincipal
);
1537 RefPtr
<WindowGlobalParent
> windowParent
=
1538 WindowGlobalParent::CreateDisconnected(windowInit
);
1539 if (NS_WARN_IF(!windowParent
)) {
1543 // Open a remote endpoint for the initial PWindowGlobal actor.
1544 ManagedEndpoint
<PWindowGlobalChild
> windowEp
=
1545 browserParent
->OpenPWindowGlobalEndpoint(windowParent
);
1546 if (NS_WARN_IF(!windowEp
.IsValid())) {
1550 // Tell the content process to set up its PBrowserChild.
1551 bool ok
= constructorSender
->SendConstructBrowser(
1552 std::move(childEp
), std::move(windowEp
), tabId
,
1553 aContext
.AsIPCTabContext(), windowInit
, chromeFlags
,
1554 constructorSender
->ChildID(), constructorSender
->IsForBrowser(),
1555 /* aIsTopLevel */ true);
1556 if (NS_WARN_IF(!ok
)) {
1560 // Ensure that we're marked as the current BrowserParent on our
1561 // CanonicalBrowsingContext.
1562 aBrowsingContext
->Canonical()->SetCurrentBrowserParent(browserParent
);
1564 windowParent
->Init();
1566 RefPtr
<BrowserHost
> browserHost
= new BrowserHost(browserParent
);
1567 browserParent
->SetOwnerElement(aFrameElement
);
1568 return browserHost
.forget();
1571 void ContentParent::GetAll(nsTArray
<ContentParent
*>& aArray
) {
1574 for (auto* cp
: AllProcesses(eLive
)) {
1575 aArray
.AppendElement(cp
);
1579 void ContentParent::GetAllEvenIfDead(nsTArray
<ContentParent
*>& aArray
) {
1582 for (auto* cp
: AllProcesses(eAll
)) {
1583 aArray
.AppendElement(cp
);
1587 void ContentParent::BroadcastStringBundle(
1588 const StringBundleDescriptor
& aBundle
) {
1589 AutoTArray
<StringBundleDescriptor
, 1> array
;
1590 array
.AppendElement(aBundle
);
1592 for (auto* cp
: AllProcesses(eLive
)) {
1593 Unused
<< cp
->SendRegisterStringBundles(array
);
1597 void ContentParent::BroadcastFontListChanged() {
1598 for (auto* cp
: AllProcesses(eLive
)) {
1599 Unused
<< cp
->SendFontListChanged();
1603 void ContentParent::BroadcastShmBlockAdded(uint32_t aGeneration
,
1605 auto* pfl
= gfxPlatformFontList::PlatformFontList();
1606 for (auto* cp
: AllProcesses(eLive
)) {
1607 base::SharedMemoryHandle handle
=
1608 pfl
->ShareShmBlockToProcess(aIndex
, cp
->Pid());
1609 if (handle
== base::SharedMemory::NULLHandle()) {
1610 // If something went wrong here, we just skip it; the child will need to
1611 // request the block as needed, at some performance cost.
1614 Unused
<< cp
->SendFontListShmBlockAdded(aGeneration
, aIndex
,
1619 void ContentParent::BroadcastThemeUpdate(widget::ThemeChangeKind aKind
) {
1620 const FullLookAndFeel
& lnf
= *RemoteLookAndFeel::ExtractData();
1621 for (auto* cp
: AllProcesses(eLive
)) {
1622 Unused
<< cp
->SendThemeChanged(lnf
, aKind
);
1627 void ContentParent::BroadcastMediaCodecsSupportedUpdate(
1628 RemoteDecodeIn aLocation
, const media::MediaCodecsSupported
& aSupported
) {
1629 // Merge incoming codec support with existing support list
1630 media::MCSInfo::AddSupport(aSupported
);
1631 auto support
= media::MCSInfo::GetSupport();
1634 sCodecsSupported
[aLocation
] = support
;
1635 for (auto* cp
: AllProcesses(eAll
)) {
1636 Unused
<< cp
->SendUpdateMediaCodecsSupported(aLocation
, support
);
1639 // Generate + save support string for display in about:support
1640 nsCString supportString
;
1641 media::MCSInfo::GetMediaCodecsSupportedString(supportString
, support
);
1642 gfx::gfxVars::SetCodecSupportInfo(supportString
);
1644 // Print the support info only from the given location for debug purpose.
1645 supportString
.Truncate();
1646 media::MCSInfo::GetMediaCodecsSupportedString(supportString
, aSupported
);
1647 supportString
.ReplaceSubstring("\n"_ns
, ", "_ns
);
1648 LOGPDM("Broadcast support from '%s', support=%s",
1649 RemoteDecodeInToStr(aLocation
), supportString
.get());
1652 const nsACString
& ContentParent::GetRemoteType() const { return mRemoteType
; }
1654 static StaticRefPtr
<nsIAsyncShutdownClient
> sXPCOMShutdownClient
;
1655 static StaticRefPtr
<nsIAsyncShutdownClient
> sProfileBeforeChangeClient
;
1656 static StaticRefPtr
<nsIAsyncShutdownClient
> sQuitApplicationGrantedClient
;
1658 void ContentParent::Init() {
1659 MOZ_ASSERT(sXPCOMShutdownClient
);
1661 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
1663 size_t length
= ArrayLength(sObserverTopics
);
1664 for (size_t i
= 0; i
< length
; ++i
) {
1665 obs
->AddObserver(this, sObserverTopics
[i
], false);
1671 cpId
.AppendInt(static_cast<uint64_t>(this->ChildID()));
1672 obs
->NotifyObservers(static_cast<nsIObserver
*>(this), "ipc:content-created",
1676 #ifdef ACCESSIBILITY
1677 // If accessibility is running in chrome process then start it in content
1679 if (GetAccService()) {
1680 Unused
<< SendActivateA11y();
1682 #endif // #ifdef ACCESSIBILITY
1684 Unused
<< SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
1686 RefPtr
<GeckoMediaPluginServiceParent
> gmps(
1687 GeckoMediaPluginServiceParent::GetSingleton());
1689 gmps
->UpdateContentProcessGMPCapabilities(this);
1692 // Flush any pref updates that happened during launch and weren't
1693 // included in the blobs set up in BeginSubprocessLaunch.
1694 for (const Pref
& pref
: mQueuedPrefs
) {
1695 Unused
<< NS_WARN_IF(!SendPreferenceUpdate(pref
));
1697 mQueuedPrefs
.Clear();
1699 Unused
<< SendInitNextGenLocalStorageEnabled(NextGenLocalStorageEnabled());
1702 // Note that for E10S we can get a false here that will be overruled by
1703 // TryToRecycleE10SOnly as late as MaybeBeginShutdown. We cannot really
1704 // foresee its result here.
1705 bool ContentParent::CheckTabDestroyWillKeepAlive(
1706 uint32_t aExpectedBrowserCount
) {
1707 return ManagedPBrowserParent().Count() != aExpectedBrowserCount
||
1708 ShouldKeepProcessAlive();
1711 RecursiveMutex
& ContentParent::ThreadsafeHandleMutex() {
1712 return mThreadsafeHandle
->mMutex
;
1715 void ContentParent::NotifyTabWillDestroy() {
1716 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)
1717 #if !defined(MOZ_WIDGET_ANDROID)
1718 /* on Android we keep processes alive more agressively, see
1719 NotifyTabDestroying where we omit MaybeBeginShutdown */
1720 || (/* we cannot trust CheckTabDestroyWillKeepAlive in E10S mode */
1721 mozilla::FissionAutostart() &&
1722 !CheckTabDestroyWillKeepAlive(mNumDestroyingTabs
+ 1))
1725 // Once we notify the impending shutdown, the content process will stop
1726 // to process content JS on interrupt (among other things), so we need to
1727 // be sure that the process will not be re-used after this point.
1728 // The inverse is harmless, that is if we decide later to shut it down
1729 // but did not notify here, it will be just notified later (but in rare
1730 // cases too late to avoid a hang).
1731 NotifyImpendingShutdown();
1732 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1733 mNotifiedImpendingShutdownOnTabWillDestroy
= true;
1738 void ContentParent::MaybeBeginShutDown(uint32_t aExpectedBrowserCount
,
1739 bool aSendShutDown
) {
1740 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose
,
1741 ("MaybeBeginShutdown %p, %u vs %u", this,
1742 ManagedPBrowserParent().Count(), aExpectedBrowserCount
));
1743 MOZ_ASSERT(NS_IsMainThread());
1745 // We need to lock our mutex here to ensure the state does not change
1746 // between the check and the MarkAsDead.
1747 // Note that if we come through BrowserParent::Destroy our mutex is
1749 // TODO: We want to get rid of the ThreadsafeHandle, see bug 1683595.
1750 RecursiveMutexAutoLock
lock(mThreadsafeHandle
->mMutex
);
1752 // Both CheckTabDestroyWillKeepAlive and TryToRecycleE10SOnly will return
1753 // false if IsInOrBeyond(AppShutdownConfirmed), so if the parent shuts
1754 // down we will always shutdown the child.
1755 if (CheckTabDestroyWillKeepAlive(aExpectedBrowserCount
) ||
1756 TryToRecycleE10SOnly()) {
1761 ContentParent::GetLog(), LogLevel::Debug
,
1762 ("Beginning ContentParent Shutdown %p (%s)", this, mRemoteType
.get()));
1764 // We're dying now, prevent anything from re-using this process.
1766 SignalImpendingShutdownToContentJS();
1768 if (aSendShutDown
) {
1769 AsyncSendShutDownMessage();
1771 // aSendShutDown is false only when we get called from
1772 // NotifyTabDestroying where we expect a subsequent call from
1773 // NotifyTabDestroyed triggered by a Browser actor destroy
1774 // roundtrip through the content process that might never arrive.
1775 StartSendShutdownTimer();
1779 void ContentParent::AsyncSendShutDownMessage() {
1780 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose
,
1781 ("AsyncSendShutDownMessage %p", this));
1782 MOZ_ASSERT(NS_IsMainThread());
1783 MOZ_ASSERT(sRecycledE10SProcess
!= this);
1785 // In the case of normal shutdown, send a shutdown message to child to
1786 // allow it to perform shutdown tasks.
1787 GetCurrentSerialEventTarget()->Dispatch(NewRunnableMethod
<ShutDownMethod
>(
1788 "dom::ContentParent::ShutDownProcess", this,
1789 &ContentParent::ShutDownProcess
, SEND_SHUTDOWN_MESSAGE
));
1792 void MaybeLogBlockShutdownDiagnostics(ContentParent
* aSelf
, const char* aMsg
,
1793 const char* aFile
, int32_t aLine
) {
1794 #if defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
1795 if (aSelf
->IsBlockingShutdown()) {
1796 MOZ_LOG(ContentParent::GetLog(), LogLevel::Info
,
1797 ("ContentParent: id=%p pid=%d - %s at %s(%d)", aSelf
, aSelf
->Pid(),
1798 aMsg
, aFile
, aLine
));
1808 bool ContentParent::ShutDownProcess(ShutDownMethod aMethod
) {
1809 bool result
= false;
1810 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
1811 ("ShutDownProcess: %p", this));
1812 // NB: must MarkAsDead() here so that this isn't accidentally
1813 // returned from Get*() while in the midst of shutdown.
1816 // Shutting down by sending a shutdown message works differently than the
1817 // other methods. We first call Shutdown() in the child. After the child is
1818 // ready, it calls FinishShutdown() on us. Then we close the channel.
1819 if (aMethod
== SEND_SHUTDOWN_MESSAGE
) {
1820 if (!mShutdownPending
) {
1822 // Stop sending input events with input priority when shutting down.
1823 SetInputPriorityEventEnabled(false);
1824 // If we did not earlier, let's signal the shutdown to JS now.
1825 SignalImpendingShutdownToContentJS();
1826 // Send a high priority announcement first. If this fails, SendShutdown
1828 Unused
<< SendShutdownConfirmedHP();
1829 // Send the definite message with normal priority.
1830 if (SendShutdown()) {
1831 MaybeLogBlockShutdownDiagnostics(
1832 this, "ShutDownProcess: Sent shutdown message.", __FILE__
,
1834 mShutdownPending
= true;
1835 // We start the kill timer only after we asked our process to
1837 StartForceKillTimer();
1840 MaybeLogBlockShutdownDiagnostics(
1841 this, "ShutDownProcess: !!! Send shutdown message failed! !!!",
1842 __FILE__
, __LINE__
);
1845 MaybeLogBlockShutdownDiagnostics(
1846 this, "ShutDownProcess: !!! !CanSend !!!", __FILE__
, __LINE__
);
1849 MaybeLogBlockShutdownDiagnostics(
1850 this, "ShutDownProcess: Shutdown already pending.", __FILE__
,
1855 // If call was not successful, the channel must have been broken
1856 // somehow, and we will clean up the error in ActorDestroy.
1860 using mozilla::dom::quota::QuotaManagerService
;
1862 if (QuotaManagerService
* qms
= QuotaManagerService::GetOrCreate()) {
1863 qms
->AbortOperationsForProcess(mChildID
);
1866 if (aMethod
== CLOSE_CHANNEL
) {
1867 if (!mCalledClose
) {
1868 MaybeLogBlockShutdownDiagnostics(
1869 this, "ShutDownProcess: Closing channel.", __FILE__
, __LINE__
);
1870 // Close() can only be called once: It kicks off the destruction sequence.
1871 mCalledClose
= true;
1877 // A ContentParent object might not get freed until after XPCOM shutdown has
1878 // shut down the cycle collector. But by then it's too late to release any
1879 // CC'ed objects, so we need to null them out here, while we still can. See
1881 ShutDownMessageManager();
1885 mozilla::ipc::IPCResult
ContentParent::RecvNotifyShutdownSuccess() {
1886 if (!mShutdownPending
) {
1887 return IPC_FAIL(this, "RecvNotifyShutdownSuccess without mShutdownPending");
1890 mIsNotifiedShutdownSuccess
= true;
1895 mozilla::ipc::IPCResult
ContentParent::RecvFinishShutdown() {
1896 if (!mShutdownPending
) {
1897 return IPC_FAIL(this, "RecvFinishShutdown without mShutdownPending");
1900 // At this point, we already called ShutDownProcess once with
1901 // SEND_SHUTDOWN_MESSAGE. To actually close the channel, we call
1902 // ShutDownProcess again with CLOSE_CHANNEL.
1904 MaybeLogBlockShutdownDiagnostics(
1905 this, "RecvFinishShutdown: Channel already closed.", __FILE__
,
1909 ShutDownProcess(CLOSE_CHANNEL
);
1913 void ContentParent::ShutDownMessageManager() {
1914 if (!mMessageManager
) {
1918 mMessageManager
->ReceiveMessage(mMessageManager
, nullptr,
1919 CHILD_PROCESS_SHUTDOWN_MESSAGE
, false,
1920 nullptr, nullptr, IgnoreErrors());
1922 mMessageManager
->SetOsPid(-1);
1923 mMessageManager
->Disconnect();
1924 mMessageManager
= nullptr;
1927 void ContentParent::AddToPool(nsTArray
<ContentParent
*>& aPool
) {
1928 MOZ_DIAGNOSTIC_ASSERT(!mIsInPool
);
1930 MOZ_DIAGNOSTIC_ASSERT(!mCalledKillHard
);
1931 aPool
.AppendElement(this);
1935 void ContentParent::RemoveFromPool(nsTArray
<ContentParent
*>& aPool
) {
1936 MOZ_DIAGNOSTIC_ASSERT(mIsInPool
);
1937 aPool
.RemoveElement(this);
1941 void ContentParent::AssertNotInPool() {
1942 MOZ_RELEASE_ASSERT(!mIsInPool
);
1944 MOZ_RELEASE_ASSERT(sRecycledE10SProcess
!= this);
1945 if (IsForJSPlugin()) {
1946 MOZ_RELEASE_ASSERT(!sJSPluginContentParents
||
1947 !sJSPluginContentParents
->Get(mJSPluginID
));
1950 !sBrowserContentParents
||
1951 !sBrowserContentParents
->Contains(mRemoteType
) ||
1952 !sBrowserContentParents
->Get(mRemoteType
)->Contains(this));
1954 for (const auto& group
: mGroups
) {
1955 MOZ_RELEASE_ASSERT(group
->GetHostProcess(mRemoteType
) != this,
1956 "still a host process for one of our groups?");
1961 void ContentParent::AssertAlive() {
1962 MOZ_DIAGNOSTIC_ASSERT(!mNotifiedImpendingShutdownOnTabWillDestroy
);
1963 MOZ_DIAGNOSTIC_ASSERT(!mIsSignaledImpendingShutdown
);
1964 MOZ_DIAGNOSTIC_ASSERT(!IsDead());
1967 void ContentParent::RemoveFromList() {
1968 if (IsForJSPlugin()) {
1969 if (sJSPluginContentParents
) {
1970 sJSPluginContentParents
->Remove(mJSPluginID
);
1971 if (!sJSPluginContentParents
->Count()) {
1972 sJSPluginContentParents
= nullptr;
1979 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1985 // Ensure that this BrowsingContextGroup is no longer used to host new
1986 // documents from any associated BrowsingContextGroups. It may become a host
1987 // again in the future, if it is restored to the pool.
1988 for (const auto& group
: mGroups
) {
1989 group
->RemoveHostProcess(this);
1992 StopRecyclingE10SOnly(/* aForeground */ false);
1994 if (sBrowserContentParents
) {
1995 if (auto entry
= sBrowserContentParents
->Lookup(mRemoteType
)) {
1996 const auto& contentParents
= entry
.Data();
1997 RemoveFromPool(*contentParents
);
1998 if (contentParents
->IsEmpty()) {
2002 if (sBrowserContentParents
->IsEmpty()) {
2003 delete sBrowserContentParents
;
2004 sBrowserContentParents
= nullptr;
2009 void ContentParent::MarkAsDead() {
2010 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose
,
2011 ("Marking ContentProcess %p as dead", this));
2012 MOZ_DIAGNOSTIC_ASSERT(!sInProcessSelector
);
2015 // Flag shutdown has started for us to our threadsafe handle.
2017 // Depending on how we get here, the lock might or might not be set.
2018 RecursiveMutexAutoLock
lock(mThreadsafeHandle
->mMutex
);
2020 mThreadsafeHandle
->mShutdownStarted
= true;
2023 // Prevent this process from being re-used.
2024 PreallocatedProcessManager::Erase(this);
2025 StopRecyclingE10SOnly(false);
2027 #if defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_PROFILE_GENERATE)
2029 // We're intentionally killing the content process at this point to ensure
2030 // that we never have a "dead" content process sitting around and occupying
2031 // an Android Service.
2033 // The exception is in MOZ_PROFILE_GENERATE builds where we must allow the
2034 // process to shutdown cleanly so that profile data can be dumped. This is
2035 // okay as we will not reach our process limit during the profile run.
2036 nsCOMPtr
<nsIEventTarget
> launcherThread(GetIPCLauncher());
2037 MOZ_ASSERT(launcherThread
);
2039 auto procType
= java::GeckoProcessType::CONTENT();
2041 java::GeckoProcessManager::Selector::New(procType
, OtherPid());
2043 launcherThread
->Dispatch(NS_NewRunnableFunction(
2044 "ContentParent::MarkAsDead",
2046 java::GeckoProcessManager::Selector::GlobalRef(selector
)]() {
2047 java::GeckoProcessManager::ShutdownProcess(selector
);
2052 if (mScriptableHelper
) {
2053 static_cast<ScriptableCPInfo
*>(mScriptableHelper
.get())->ProcessDied();
2054 mScriptableHelper
= nullptr;
2057 mLifecycleState
= LifecycleState::DEAD
;
2060 void ContentParent::OnChannelError() {
2061 RefPtr
<ContentParent
> kungFuDeathGrip(this);
2062 PContentParent::OnChannelError();
2065 void ContentParent::ProcessingError(Result aCode
, const char* aReason
) {
2066 if (MsgDropped
== aCode
) {
2069 // Other errors are big deals.
2074 GetIPCChannel()->InduceConnectionError();
2078 void ContentParent::ActorDestroy(ActorDestroyReason why
) {
2079 #ifdef FUZZING_SNAPSHOT
2080 MOZ_FUZZING_IPC_DROP_PEER("ContentParent::ActorDestroy");
2083 if (mSendShutdownTimer
) {
2084 mSendShutdownTimer
->Cancel();
2085 mSendShutdownTimer
= nullptr;
2087 if (mForceKillTimer
) {
2088 mForceKillTimer
->Cancel();
2089 mForceKillTimer
= nullptr;
2092 // Signal shutdown completion regardless of error state, so we can
2093 // finish waiting in the xpcom-shutdown/profile-before-change observer.
2094 RemoveShutdownBlockers();
2096 if (mHangMonitorActor
) {
2097 ProcessHangMonitor::RemoveProcess(mHangMonitorActor
);
2098 mHangMonitorActor
= nullptr;
2101 RefPtr
<FileSystemSecurity
> fss
= FileSystemSecurity::Get();
2103 fss
->Forget(ChildID());
2106 if (why
== NormalShutdown
&& !mCalledClose
) {
2107 // If we shut down normally but haven't called Close, assume somebody
2108 // else called Close on us. In that case, we still need to call
2109 // ShutDownProcess below to perform other necessary clean up.
2110 mCalledClose
= true;
2113 // Make sure we always clean up.
2114 ShutDownProcess(CLOSE_CHANNEL
);
2116 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
2118 size_t length
= ArrayLength(sObserverTopics
);
2119 for (size_t i
= 0; i
< length
; ++i
) {
2120 obs
->RemoveObserver(static_cast<nsIObserver
*>(this), sObserverTopics
[i
]);
2124 // remove the global remote preferences observers
2125 Preferences::RemoveObserver(this, "");
2126 gfxVars::RemoveReceiver(this);
2128 if (GPUProcessManager
* gpu
= GPUProcessManager::Get()) {
2129 // Note: the manager could have shutdown already.
2130 gpu
->RemoveListener(this);
2133 RecvRemoveGeolocationListener();
2135 // Destroy our JSProcessActors, and reject any pending queries.
2136 JSActorDidDestroy();
2139 RefPtr
<nsHashPropertyBag
> props
= new nsHashPropertyBag();
2141 props
->SetPropertyAsUint64(u
"childID"_ns
, mChildID
);
2143 if (AbnormalShutdown
== why
) {
2144 Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT
, "content"_ns
,
2147 props
->SetPropertyAsBool(u
"abnormal"_ns
, true);
2149 nsAutoString dumpID
;
2150 // There's a window in which child processes can crash
2151 // after IPC is established, but before a crash reporter
2153 if (mCrashReporter
) {
2154 // if mCreatedPairedMinidumps is true, we've already generated
2155 // parent/child dumps for desktop crashes.
2156 if (!mCreatedPairedMinidumps
) {
2157 #if defined(XP_MACOSX)
2158 RefPtr
<nsAvailableMemoryWatcherBase
> memWatcher
;
2159 memWatcher
= nsAvailableMemoryWatcherBase::GetSingleton();
2160 memWatcher
->AddChildAnnotations(mCrashReporter
);
2163 mCrashReporter
->GenerateCrashReport(OtherPid());
2166 if (mCrashReporter
->HasMinidump()) {
2167 dumpID
= mCrashReporter
->MinidumpID();
2170 HandleOrphanedMinidump(&dumpID
);
2173 if (!dumpID
.IsEmpty()) {
2174 props
->SetPropertyAsAString(u
"dumpID"_ns
, dumpID
);
2178 cpId
.AppendInt(static_cast<uint64_t>(this->ChildID()));
2179 obs
->NotifyObservers((nsIPropertyBag2
*)props
, "ipc:content-shutdown",
2183 // Remove any and all idle listeners.
2184 if (mIdleListeners
.Length() > 0) {
2185 nsCOMPtr
<nsIUserIdleService
> idleService
=
2186 do_GetService("@mozilla.org/widget/useridleservice;1");
2188 RefPtr
<ParentIdleListener
> listener
;
2189 for (const auto& lentry
: mIdleListeners
) {
2190 listener
= static_cast<ParentIdleListener
*>(lentry
.get());
2191 idleService
->RemoveIdleObserver(listener
, listener
->mTime
);
2194 mIdleListeners
.Clear();
2197 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose
,
2198 ("destroying Subprocess in ActorDestroy: ContentParent %p "
2199 "mSubprocess %p handle %" PRIuPTR
,
2201 mSubprocess
? (uintptr_t)mSubprocess
->GetChildProcessHandle() : -1));
2202 // FIXME (bug 1520997): does this really need an additional dispatch?
2203 if (GetCurrentSerialEventTarget()) {
2204 GetCurrentSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
2205 "DelayedDeleteSubprocessRunnable", [subprocess
= mSubprocess
] {
2206 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
2207 ("destroyed Subprocess in ActorDestroy: Subprocess %p handle "
2210 subprocess
? (uintptr_t)subprocess
->GetChildProcessHandle()
2212 subprocess
->Destroy();
2215 mSubprocess
= nullptr;
2217 ContentProcessManager
* cpm
= ContentProcessManager::GetSingleton();
2219 cpm
->RemoveContentProcess(this->ChildID());
2222 if (mDriverCrashGuard
) {
2223 mDriverCrashGuard
->NotifyCrashed();
2226 // Unregister all the BlobURLs registered by the ContentChild.
2227 for (uint32_t i
= 0; i
< mBlobURLs
.Length(); ++i
) {
2228 BlobURLProtocolHandler::RemoveDataEntry(mBlobURLs
[i
]);
2233 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2237 // As this process is going away, ensure that every BrowsingContext hosted by
2238 // it has been detached, and every BrowsingContextGroup has been fully
2240 BrowsingContext::DiscardFromContentParent(this);
2242 const nsTHashSet
<RefPtr
<BrowsingContextGroup
>> groups
= std::move(mGroups
);
2243 for (const auto& group
: groups
) {
2244 group
->Unsubscribe(this);
2246 MOZ_DIAGNOSTIC_ASSERT(mGroups
.IsEmpty());
2248 mPendingLoadStates
.Clear();
2251 bool ContentParent::TryToRecycleE10SOnly() {
2252 // Only try to recycle "web" content processes, as other remote types are
2253 // generally more unique, and cannot be effectively re-used. This is disabled
2254 // with Fission, as "web" content processes are no longer frequently used.
2256 // Disabling the process pre-allocator will also disable process recycling,
2257 // allowing for more consistent process counts under testing.
2258 if (mRemoteType
!= DEFAULT_REMOTE_TYPE
|| mozilla::FissionAutostart() ||
2259 !PreallocatedProcessManager::Enabled()) {
2263 // This life time check should be replaced by a memory health check (memory
2264 // usage + fragmentation).
2266 // Note that this is specifically to help with edge cases that rapidly
2267 // create-and-destroy processes
2268 const double kMaxLifeSpan
= 5;
2270 ContentParent::GetLog(), LogLevel::Debug
,
2271 ("TryToRecycle ContentProcess %p (%u) with lifespan %f seconds", this,
2272 (unsigned int)ChildID(), (TimeStamp::Now() - mActivateTS
).ToSeconds()));
2274 if (mCalledKillHard
|| !IsAlive() ||
2275 (TimeStamp::Now() - mActivateTS
).ToSeconds() > kMaxLifeSpan
) {
2276 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
2277 ("TryToRecycle did not recycle %p", this));
2279 // It's possible that the process was already cached, and we're being called
2280 // from a different path, and we're now past kMaxLifeSpan (or some other).
2281 // Ensure that if we're going to kill this process we don't recycle it.
2282 StopRecyclingE10SOnly(/* aForeground */ false);
2286 if (!sRecycledE10SProcess
) {
2287 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
2288 ("TryToRecycle began recycling %p", this));
2289 sRecycledE10SProcess
= this;
2291 ProcessPriorityManager::SetProcessPriority(this,
2292 PROCESS_PRIORITY_BACKGROUND
);
2296 if (sRecycledE10SProcess
== this) {
2297 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
2298 ("TryToRecycle continue recycling %p", this));
2302 // Some other process is already being recycled, just shut this one down.
2303 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
2304 ("TryToRecycle did not recycle %p (already recycling %p)", this,
2305 sRecycledE10SProcess
.get()));
2309 void ContentParent::StopRecyclingE10SOnly(bool aForeground
) {
2310 if (sRecycledE10SProcess
!= this) {
2314 sRecycledE10SProcess
= nullptr;
2316 ProcessPriorityManager::SetProcessPriority(this,
2317 PROCESS_PRIORITY_FOREGROUND
);
2321 bool ContentParent::HasActiveWorkerOrJSPlugin() {
2322 if (IsForJSPlugin()) {
2326 // If we have active workers, we need to stay alive.
2328 // Most of the times we'll get here with the mutex acquired, but still.
2329 RecursiveMutexAutoLock
lock(mThreadsafeHandle
->mMutex
);
2330 if (mThreadsafeHandle
->mRemoteWorkerActorCount
) {
2337 bool ContentParent::ShouldKeepProcessAlive() {
2338 if (HasActiveWorkerOrJSPlugin()) {
2342 if (mNumKeepaliveCalls
> 0) {
2346 if (IsLaunching()) {
2350 // If we have already been marked as dead, don't prevent shutdown.
2355 // If everything is going down, there is no need to keep us alive, neither.
2356 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
2360 if (!sBrowserContentParents
) {
2364 auto contentParents
= sBrowserContentParents
->Get(mRemoteType
);
2365 if (!contentParents
) {
2369 // We might want to keep some content processes alive for performance reasons.
2370 // e.g. test runs and privileged content process for some about: pages.
2371 // We don't want to alter behavior if the pref is not set, so default to 0.
2372 int32_t processesToKeepAlive
= 0;
2374 nsAutoCString
keepAlivePref("dom.ipc.keepProcessesAlive.");
2376 if (StringBeginsWith(mRemoteType
, FISSION_WEB_REMOTE_TYPE
) &&
2377 xpc::IsInAutomation()) {
2378 keepAlivePref
.Append(FISSION_WEB_REMOTE_TYPE
);
2379 keepAlivePref
.AppendLiteral(".perOrigin");
2381 keepAlivePref
.Append(mRemoteType
);
2384 Preferences::GetInt(keepAlivePref
.get(), &processesToKeepAlive
))) {
2388 int32_t numberOfAliveProcesses
= contentParents
->Length();
2390 return numberOfAliveProcesses
<= processesToKeepAlive
;
2393 void ContentParent::NotifyTabDestroying() {
2394 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
2395 ("NotifyTabDestroying %p:", this));
2396 // There can be more than one PBrowser for a given app process
2397 // because of popup windows. PBrowsers can also destroy
2398 // concurrently. When all the PBrowsers are destroying, kick off
2399 // another task to ensure the child process *really* shuts down,
2400 // even if the PBrowsers themselves never finish destroying.
2401 ++mNumDestroyingTabs
;
2404 * We intentionally skip this code on Android:
2405 * 1. Android has a fixed upper bound on the number of content processes, so
2406 * we prefer to re-use them whenever possible (as opposed to letting an
2407 * old process wind down while we launch a new one).
2408 * 2. GeckoView always hard-kills content processes (and if it does not,
2409 * Android itself will), so we don't concern ourselves with the ForceKill
2412 #if !defined(MOZ_WIDGET_ANDROID)
2413 MaybeBeginShutDown(/* aExpectedBrowserCount */ mNumDestroyingTabs
,
2414 /* aSendShutDown */ false);
2415 #endif // !defined(MOZ_WIDGET_ANDROID)
2418 void ContentParent::AddKeepAlive() {
2420 // Something wants to keep this content process alive.
2421 ++mNumKeepaliveCalls
;
2424 void ContentParent::RemoveKeepAlive() {
2425 MOZ_DIAGNOSTIC_ASSERT(mNumKeepaliveCalls
> 0);
2426 --mNumKeepaliveCalls
;
2428 MaybeBeginShutDown();
2431 void ContentParent::StartSendShutdownTimer() {
2432 if (mSendShutdownTimer
|| !CanSend()) {
2436 uint32_t timeoutSecs
= StaticPrefs::dom_ipc_tabs_shutdownTimeoutSecs();
2437 if (timeoutSecs
> 0) {
2438 NS_NewTimerWithFuncCallback(getter_AddRefs(mSendShutdownTimer
),
2439 ContentParent::SendShutdownTimerCallback
, this,
2440 timeoutSecs
* 1000, nsITimer::TYPE_ONE_SHOT
,
2441 "dom::ContentParent::StartSendShutdownTimer");
2442 MOZ_ASSERT(mSendShutdownTimer
);
2446 void ContentParent::StartForceKillTimer() {
2447 if (mForceKillTimer
|| !CanSend()) {
2451 uint32_t timeoutSecs
= StaticPrefs::dom_ipc_tabs_shutdownTimeoutSecs();
2452 if (timeoutSecs
> 0) {
2453 NS_NewTimerWithFuncCallback(getter_AddRefs(mForceKillTimer
),
2454 ContentParent::ForceKillTimerCallback
, this,
2455 timeoutSecs
* 1000, nsITimer::TYPE_ONE_SHOT
,
2456 "dom::ContentParent::StartForceKillTimer");
2457 MOZ_ASSERT(mForceKillTimer
);
2461 void ContentParent::NotifyTabDestroyed(const TabId
& aTabId
,
2462 bool aNotifiedDestroying
) {
2463 if (aNotifiedDestroying
) {
2464 --mNumDestroyingTabs
;
2467 nsTArray
<PContentPermissionRequestParent
*> parentArray
=
2468 nsContentPermissionUtils::GetContentPermissionRequestParentById(aTabId
);
2470 // Need to close undeleted ContentPermissionRequestParents before tab is
2472 for (auto& permissionRequestParent
: parentArray
) {
2473 Unused
<< PContentPermissionRequestParent::Send__delete__(
2474 permissionRequestParent
);
2477 // There can be more than one PBrowser for a given app process
2478 // because of popup windows. When the last one closes, shut
2480 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose
,
2481 ("NotifyTabDestroyed %p", this));
2483 MaybeBeginShutDown(/* aExpectedBrowserCount */ 1);
2486 TestShellParent
* ContentParent::CreateTestShell() {
2487 return static_cast<TestShellParent
*>(SendPTestShellConstructor());
2490 bool ContentParent::DestroyTestShell(TestShellParent
* aTestShell
) {
2491 return PTestShellParent::Send__delete__(aTestShell
);
2494 TestShellParent
* ContentParent::GetTestShellSingleton() {
2495 PTestShellParent
* p
= LoneManagedOrNullAsserts(ManagedPTestShellParent());
2496 return static_cast<TestShellParent
*>(p
);
2499 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
2500 // Append the sandbox command line parameters that are not static. i.e.,
2501 // parameters that can be different for different child processes.
2502 void ContentParent::AppendDynamicSandboxParams(
2503 std::vector
<std::string
>& aArgs
) {
2504 // For file content processes
2505 if (GetRemoteType() == FILE_REMOTE_TYPE
) {
2506 MacSandboxInfo::AppendFileAccessParam(aArgs
, true);
2510 // Generate the static sandbox command line parameters and store
2511 // them in the provided params vector to be used each time a new
2512 // content process is launched.
2513 static void CacheSandboxParams(std::vector
<std::string
>& aCachedParams
) {
2514 // This must only be called once and we should
2515 // be starting with an empty list of parameters.
2516 MOZ_ASSERT(aCachedParams
.empty());
2518 MacSandboxInfo info
;
2519 info
.type
= MacSandboxType_Content
;
2520 info
.level
= GetEffectiveContentSandboxLevel();
2523 if (Preferences::GetBool("security.sandbox.logging.enabled") ||
2524 PR_GetEnv("MOZ_SANDBOX_LOGGING")) {
2525 info
.shouldLog
= true;
2529 if (!StaticPrefs::media_cubeb_sandbox()) {
2530 info
.hasAudio
= true;
2533 // Window server access. If the disconnect-windowserver pref is not
2534 // "true" or out-of-process WebGL is not enabled, allow window server
2535 // access in the sandbox policy.
2536 if (!Preferences::GetBool(
2537 "security.sandbox.content.mac.disconnect-windowserver") ||
2538 !Preferences::GetBool("webgl.out-of-process")) {
2539 info
.hasWindowServer
= true;
2542 // .app path (normalized)
2543 nsAutoCString appPath
;
2544 if (!nsMacUtilsImpl::GetAppPath(appPath
)) {
2545 MOZ_CRASH("Failed to get app dir paths");
2547 info
.appPath
= appPath
.get();
2549 // TESTING_READ_PATH1
2550 nsAutoCString testingReadPath1
;
2551 Preferences::GetCString("security.sandbox.content.mac.testing_read_path1",
2553 if (!testingReadPath1
.IsEmpty()) {
2554 info
.testingReadPath1
= testingReadPath1
.get();
2557 // TESTING_READ_PATH2
2558 nsAutoCString testingReadPath2
;
2559 Preferences::GetCString("security.sandbox.content.mac.testing_read_path2",
2561 if (!testingReadPath2
.IsEmpty()) {
2562 info
.testingReadPath2
= testingReadPath2
.get();
2565 // TESTING_READ_PATH3, TESTING_READ_PATH4. In non-packaged builds,
2566 // these are used to whitelist the repo dir and object dir respectively.
2568 if (!mozilla::IsPackagedBuild()) {
2570 nsCOMPtr
<nsIFile
> repoDir
;
2571 rv
= nsMacUtilsImpl::GetRepoDir(getter_AddRefs(repoDir
));
2572 if (NS_FAILED(rv
)) {
2573 MOZ_CRASH("Failed to get path to repo dir");
2575 nsCString repoDirPath
;
2576 Unused
<< repoDir
->GetNativePath(repoDirPath
);
2577 info
.testingReadPath3
= repoDirPath
.get();
2580 nsCOMPtr
<nsIFile
> objDir
;
2581 rv
= nsMacUtilsImpl::GetObjDir(getter_AddRefs(objDir
));
2582 if (NS_FAILED(rv
)) {
2583 MOZ_CRASH("Failed to get path to build object dir");
2585 nsCString objDirPath
;
2586 Unused
<< objDir
->GetNativePath(objDirPath
);
2587 info
.testingReadPath4
= objDirPath
.get();
2592 // For bloat/leak logging or when a content process dies intentionally
2593 // (|NoteIntentionalCrash|) for tests, it wants to log that it did this.
2594 // Allow writing to this location.
2595 nsAutoCString bloatLogDirPath
;
2596 if (NS_SUCCEEDED(nsMacUtilsImpl::GetBloatLogDir(bloatLogDirPath
))) {
2597 info
.debugWriteDir
= bloatLogDirPath
.get();
2601 info
.AppendAsParams(aCachedParams
);
2604 // Append sandboxing command line parameters.
2605 void ContentParent::AppendSandboxParams(std::vector
<std::string
>& aArgs
) {
2606 MOZ_ASSERT(sMacSandboxParams
!= nullptr);
2608 // An empty sMacSandboxParams indicates this is the
2609 // first invocation and we don't have cached params yet.
2610 if (sMacSandboxParams
->empty()) {
2611 CacheSandboxParams(*sMacSandboxParams
);
2612 MOZ_ASSERT(!sMacSandboxParams
->empty());
2615 // Append cached arguments.
2616 aArgs
.insert(aArgs
.end(), sMacSandboxParams
->begin(),
2617 sMacSandboxParams
->end());
2619 // Append remaining arguments.
2620 AppendDynamicSandboxParams(aArgs
);
2622 #endif // XP_MACOSX && MOZ_SANDBOX
2624 bool ContentParent::BeginSubprocessLaunch(ProcessPriority aPriority
) {
2625 AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess", OTHER
);
2627 // Ensure we will not rush through our shutdown phases while launching.
2628 // LaunchSubprocessReject will remove them in case of failure,
2629 // otherwise ActorDestroy will take care.
2630 AddShutdownBlockers();
2632 if (!ContentProcessManager::GetSingleton()) {
2633 MOZ_ASSERT(false, "Unable to acquire ContentProcessManager singleton!");
2637 std::vector
<std::string
> extraArgs
;
2638 geckoargs::sChildID
.Put(mChildID
, extraArgs
);
2639 geckoargs::sIsForBrowser
.Put(IsForBrowser(), extraArgs
);
2640 geckoargs::sNotForBrowser
.Put(!IsForBrowser(), extraArgs
);
2642 // Prefs information is passed via anonymous shared memory to avoid bloating
2643 // the command line.
2645 // Instantiate the pref serializer. It will be cleaned up in
2646 // `LaunchSubprocessReject`/`LaunchSubprocessResolve`.
2647 mPrefSerializer
= MakeUnique
<mozilla::ipc::SharedPreferenceSerializer
>();
2648 if (!mPrefSerializer
->SerializeToSharedMemory(GeckoProcessType_Content
,
2650 NS_WARNING("SharedPreferenceSerializer::SerializeToSharedMemory failed");
2654 mPrefSerializer
->AddSharedPrefCmdLineArgs(*mSubprocess
, extraArgs
);
2656 // The JS engine does some computation during the initialization which can be
2657 // shared across processes. We add command line arguments to pass a file
2658 // handle and its content length, to minimize the startup time of content
2660 ::mozilla::ipc::ExportSharedJSInit(*mSubprocess
, extraArgs
);
2662 // Register ContentParent as an observer for changes to any pref
2663 // whose prefix matches the empty string, i.e. all of them. The
2664 // observation starts here in order to capture pref updates that
2665 // happen during async launch.
2666 Preferences::AddStrongObserver(this, "");
2669 geckoargs::sSafeMode
.Put(extraArgs
);
2672 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
2673 if (IsContentSandboxEnabled()) {
2674 AppendSandboxParams(extraArgs
);
2675 mSubprocess
->DisableOSActivityMode();
2679 nsCString
parentBuildID(mozilla::PlatformBuildID());
2680 geckoargs::sParentBuildID
.Put(parentBuildID
.get(), extraArgs
);
2682 #ifdef MOZ_WIDGET_GTK
2683 // This is X11-only pending a solution for WebGL in Wayland mode.
2684 if (StaticPrefs::dom_ipc_avoid_gtk() &&
2685 StaticPrefs::widget_non_native_theme_enabled() &&
2686 widget::GdkIsX11Display()) {
2687 mSubprocess
->SetEnv("MOZ_HEADLESS", "1");
2691 mLaunchYieldTS
= TimeStamp::Now();
2692 return mSubprocess
->AsyncLaunch(std::move(extraArgs
));
2695 void ContentParent::LaunchSubprocessReject() {
2696 NS_WARNING("failed to launch child in the parent");
2697 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose
,
2698 ("failed to launch child in the parent"));
2699 // Now that communication with the child is complete, we can cleanup
2700 // the preference serializer.
2701 mPrefSerializer
= nullptr;
2702 if (mIsAPreallocBlocker
) {
2703 PreallocatedProcessManager::RemoveBlocker(mRemoteType
, this);
2704 mIsAPreallocBlocker
= false;
2707 RemoveShutdownBlockers();
2710 bool ContentParent::LaunchSubprocessResolve(bool aIsSync
,
2711 ProcessPriority aPriority
) {
2712 AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess::resolve", OTHER
);
2714 if (mLaunchResolved
) {
2715 // We've already been called, return.
2716 MOZ_ASSERT(sCreatedFirstContentProcess
);
2717 MOZ_ASSERT(!mPrefSerializer
);
2718 MOZ_ASSERT(mLifecycleState
!= LifecycleState::LAUNCHING
);
2719 return mLaunchResolvedOk
;
2721 mLaunchResolved
= true;
2723 // Now that communication with the child is complete, we can cleanup
2724 // the preference serializer.
2725 mPrefSerializer
= nullptr;
2727 const auto launchResumeTS
= TimeStamp::Now();
2728 if (profiler_thread_is_being_profiled_for_markers()) {
2729 nsPrintfCString
marker("Process start%s for %u",
2730 mIsAPreallocBlocker
? " (immediate)" : "",
2731 (unsigned int)ChildID());
2732 PROFILER_MARKER_TEXT(
2733 mIsAPreallocBlocker
? ProfilerString8View("Process Immediate Launch")
2734 : ProfilerString8View("Process Launch"),
2735 DOM
, MarkerTiming::Interval(mLaunchTS
, launchResumeTS
), marker
);
2738 if (!sCreatedFirstContentProcess
) {
2739 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
2740 obs
->NotifyObservers(nullptr, "ipc:first-content-process-created", nullptr);
2741 sCreatedFirstContentProcess
= true;
2744 mSubprocess
->TakeInitialEndpoint().Bind(this);
2746 ContentProcessManager
* cpm
= ContentProcessManager::GetSingleton();
2748 NS_WARNING("immediately shutting-down caused by our shutdown");
2749 ShutDownProcess(SEND_SHUTDOWN_MESSAGE
);
2752 cpm
->AddContentProcess(this);
2754 #ifdef MOZ_CODE_COVERAGE
2755 Unused
<< SendShareCodeCoverageMutex(
2756 CodeCoverageHandler::Get()->GetMutexHandle());
2759 // We must be in the LAUNCHING state still. If we've somehow already been
2760 // marked as DEAD, fail the process launch, and immediately begin tearing down
2761 // the content process.
2763 NS_WARNING("immediately shutting-down already-dead process");
2764 ShutDownProcess(SEND_SHUTDOWN_MESSAGE
);
2767 MOZ_ASSERT(mLifecycleState
== LifecycleState::LAUNCHING
);
2768 mLifecycleState
= LifecycleState::ALIVE
;
2770 if (!InitInternal(aPriority
)) {
2771 NS_WARNING("failed to initialize child in the parent");
2772 // We've already called Open() by this point, so we need to close the
2773 // channel to avoid leaking the process.
2774 ShutDownProcess(SEND_SHUTDOWN_MESSAGE
);
2778 mHangMonitorActor
= ProcessHangMonitor::AddProcess(this);
2780 // Set a reply timeout for CPOWs.
2781 SetReplyTimeoutMs(StaticPrefs::dom_ipc_cpow_timeout());
2783 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
2786 cpId
.AppendInt(static_cast<uint64_t>(this->ChildID()));
2787 obs
->NotifyObservers(static_cast<nsIObserver
*>(this),
2788 "ipc:content-initializing", cpId
.get());
2793 mLifecycleState
= LifecycleState::INITIALIZED
;
2796 Telemetry::AccumulateTimeDelta(Telemetry::CONTENT_PROCESS_SYNC_LAUNCH_MS
,
2799 Telemetry::AccumulateTimeDelta(Telemetry::CONTENT_PROCESS_LAUNCH_TOTAL_MS
,
2802 Telemetry::Accumulate(
2803 Telemetry::CONTENT_PROCESS_LAUNCH_MAINTHREAD_MS
,
2804 static_cast<uint32_t>(
2805 ((mLaunchYieldTS
- mLaunchTS
) + (TimeStamp::Now() - launchResumeTS
))
2806 .ToMilliseconds()));
2809 mLaunchResolvedOk
= true;
2813 bool ContentParent::LaunchSubprocessSync(
2814 hal::ProcessPriority aInitialPriority
) {
2815 // We've started a sync content process launch.
2816 Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC
, 1);
2818 if (BeginSubprocessLaunch(aInitialPriority
)) {
2819 const bool ok
= mSubprocess
->WaitForProcessHandle();
2820 if (ok
&& LaunchSubprocessResolve(/* aIsSync = */ true, aInitialPriority
)) {
2824 LaunchSubprocessReject();
2828 RefPtr
<ContentParent::LaunchPromise
> ContentParent::LaunchSubprocessAsync(
2829 hal::ProcessPriority aInitialPriority
) {
2830 // We've started an async content process launch.
2831 Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC
, 0);
2833 if (!BeginSubprocessLaunch(aInitialPriority
)) {
2834 // Launch aborted because of shutdown. Bailout.
2835 LaunchSubprocessReject();
2836 return LaunchPromise::CreateAndReject(NS_ERROR_ILLEGAL_DURING_SHUTDOWN
,
2840 // Otherwise, wait until the process is ready.
2841 RefPtr
<ProcessHandlePromise
> ready
= mSubprocess
->WhenProcessHandleReady();
2842 RefPtr
<ContentParent
> self
= this;
2843 mLaunchYieldTS
= TimeStamp::Now();
2846 GetCurrentSerialEventTarget(), __func__
,
2847 [self
, aInitialPriority
](
2848 const ProcessHandlePromise::ResolveOrRejectValue
& aValue
) {
2849 if (aValue
.IsResolve() &&
2850 self
->LaunchSubprocessResolve(/* aIsSync = */ false,
2851 aInitialPriority
)) {
2852 return LaunchPromise::CreateAndResolve(self
, __func__
);
2854 self
->LaunchSubprocessReject();
2855 return LaunchPromise::CreateAndReject(NS_ERROR_FAILURE
, __func__
);
2859 ContentParent::ContentParent(const nsACString
& aRemoteType
, int32_t aJSPluginID
)
2860 : mSubprocess(nullptr),
2861 mLaunchTS(TimeStamp::Now()),
2862 mLaunchYieldTS(mLaunchTS
),
2863 mActivateTS(mLaunchTS
),
2864 mIsAPreallocBlocker(false),
2865 mRemoteType(aRemoteType
),
2866 mChildID(gContentChildID
++),
2867 mGeolocationWatchID(-1),
2868 mJSPluginID(aJSPluginID
),
2870 new ThreadsafeContentParentHandle(this, mChildID
, mRemoteType
)),
2871 mNumDestroyingTabs(0),
2872 mNumKeepaliveCalls(0),
2873 mLifecycleState(LifecycleState::LAUNCHING
),
2874 mIsForBrowser(!mRemoteType
.IsEmpty()),
2875 mCalledClose(false),
2876 mCalledKillHard(false),
2877 mCreatedPairedMinidumps(false),
2878 mShutdownPending(false),
2879 mLaunchResolved(false),
2880 mLaunchResolvedOk(false),
2881 mIsRemoteInputEventQueueEnabled(false),
2882 mIsInputPriorityEventEnabled(false),
2885 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2886 mBlockShutdownCalled(false),
2888 mHangMonitorActor(nullptr) {
2889 MOZ_DIAGNOSTIC_ASSERT(!IsForJSPlugin(),
2890 "XXX(nika): How are we creating a JSPlugin?");
2892 mRemoteTypeIsolationPrincipal
=
2893 CreateRemoteTypeIsolationPrincipal(aRemoteType
);
2895 // Insert ourselves into the global linked list of ContentParent objects.
2896 if (!sContentParents
) {
2897 sContentParents
= new LinkedList
<ContentParent
>();
2899 sContentParents
->insertBack(this);
2901 mMessageManager
= nsFrameMessageManager::NewProcessMessageManager(true);
2904 // Request Windows message deferral behavior on our side of the PContent
2905 // channel. Generally only applies to the situation where we get caught in
2906 // a deadlock with the plugin process when sending CPOWs.
2907 GetIPCChannel()->SetChannelFlags(
2908 MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION
);
2911 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2912 bool isFile
= mRemoteType
== FILE_REMOTE_TYPE
;
2913 mSubprocess
= new GeckoChildProcessHost(GeckoProcessType_Content
, isFile
);
2914 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose
,
2915 ("CreateSubprocess: ContentParent %p mSubprocess %p handle %" PRIuPTR
,
2917 mSubprocess
? (uintptr_t)mSubprocess
->GetChildProcessHandle() : -1));
2919 // This is safe to do in the constructor, as it doesn't take a strong
2921 mScriptableHelper
= new ScriptableCPInfo(this);
2924 ContentParent::~ContentParent() {
2925 if (mSendShutdownTimer
) {
2926 mSendShutdownTimer
->Cancel();
2928 if (mForceKillTimer
) {
2929 mForceKillTimer
->Cancel();
2932 AssertIsOnMainThread();
2934 // Clear the weak reference from the threadsafe handle back to this actor.
2935 mThreadsafeHandle
->mWeakActor
= nullptr;
2937 if (mIsAPreallocBlocker
) {
2938 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
2939 ("Removing blocker on ContentProcess destruction"));
2940 PreallocatedProcessManager::RemoveBlocker(mRemoteType
, this);
2941 mIsAPreallocBlocker
= false;
2944 // We should be removed from all these lists in ActorDestroy.
2947 // Normally mSubprocess is destroyed in ActorDestroy, but that won't
2948 // happen if the process wasn't launched or if it failed to launch.
2951 ContentParent::GetLog(), LogLevel::Verbose
,
2952 ("DestroySubprocess: ContentParent %p mSubprocess %p handle %" PRIuPTR
,
2954 mSubprocess
? (uintptr_t)mSubprocess
->GetChildProcessHandle() : -1));
2955 mSubprocess
->Destroy();
2958 // Make sure to clear the connection from `mScriptableHelper` if it hasn't
2959 // been cleared yet.
2960 if (mScriptableHelper
) {
2961 static_cast<ScriptableCPInfo
*>(mScriptableHelper
.get())->ProcessDied();
2962 mScriptableHelper
= nullptr;
2966 bool ContentParent::InitInternal(ProcessPriority aInitialPriority
) {
2967 // We can't access the locale service after shutdown has started. Since we
2968 // can't init the process without it, and since we're going to be canceling
2969 // whatever load attempt that initiated this process creation anyway, just
2970 // bail out now if shutdown has already started.
2971 if (PastShutdownPhase(ShutdownPhase::XPCOMShutdown
)) {
2975 XPCOMInitData xpcomInit
;
2977 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug
,
2978 ("ContentParent::InitInternal: %p", (void*)this));
2979 nsCOMPtr
<nsIIOService
> io(do_GetIOService());
2980 MOZ_ASSERT(io
, "No IO service?");
2981 DebugOnly
<nsresult
> rv
= io
->GetOffline(&xpcomInit
.isOffline());
2982 MOZ_ASSERT(NS_SUCCEEDED(rv
), "Failed getting offline?");
2984 rv
= io
->GetConnectivity(&xpcomInit
.isConnected());
2985 MOZ_ASSERT(NS_SUCCEEDED(rv
), "Failed getting connectivity?");
2987 xpcomInit
.captivePortalState() = nsICaptivePortalService::UNKNOWN
;
2988 nsCOMPtr
<nsICaptivePortalService
> cps
=
2989 do_GetService(NS_CAPTIVEPORTAL_CONTRACTID
);
2991 cps
->GetState(&xpcomInit
.captivePortalState());
2994 if (StaticPrefs::fission_processProfileName()) {
2995 nsCOMPtr
<nsIToolkitProfileService
> profileSvc
=
2996 do_GetService(NS_PROFILESERVICE_CONTRACTID
);
2998 nsCOMPtr
<nsIToolkitProfile
> currentProfile
;
3000 profileSvc
->GetCurrentProfile(getter_AddRefs(currentProfile
));
3001 if (NS_SUCCEEDED(rv
) && currentProfile
) {
3002 currentProfile
->GetName(mProfile
);
3007 nsIBidiKeyboard
* bidi
= nsContentUtils::GetBidiKeyboard();
3009 xpcomInit
.isLangRTL() = false;
3010 xpcomInit
.haveBidiKeyboards() = false;
3012 bidi
->IsLangRTL(&xpcomInit
.isLangRTL());
3013 bidi
->GetHaveBidiKeyboards(&xpcomInit
.haveBidiKeyboards());
3016 RefPtr
<mozSpellChecker
> spellChecker(mozSpellChecker::Create());
3017 MOZ_ASSERT(spellChecker
, "No spell checker?");
3019 spellChecker
->GetDictionaryList(&xpcomInit
.dictionaries());
3021 LocaleService::GetInstance()->GetAppLocalesAsBCP47(xpcomInit
.appLocales());
3022 LocaleService::GetInstance()->GetRequestedLocales(
3023 xpcomInit
.requestedLocales());
3025 L10nRegistry::GetParentProcessFileSourceDescriptors(
3026 xpcomInit
.l10nFileSources());
3028 nsCOMPtr
<nsIClipboard
> clipboard(
3029 do_GetService("@mozilla.org/widget/clipboard;1"));
3030 MOZ_ASSERT(clipboard
, "No clipboard?");
3032 clipboard
->IsClipboardTypeSupported(nsIClipboard::kGlobalClipboard
),
3033 "We should always support the global clipboard.");
3035 xpcomInit
.clipboardCaps().supportsSelectionClipboard() =
3036 clipboard
->IsClipboardTypeSupported(nsIClipboard::kSelectionClipboard
);
3038 xpcomInit
.clipboardCaps().supportsFindClipboard() =
3039 clipboard
->IsClipboardTypeSupported(nsIClipboard::kFindClipboard
);
3041 xpcomInit
.clipboardCaps().supportsSelectionCache() =
3042 clipboard
->IsClipboardTypeSupported(nsIClipboard::kSelectionCache
);
3044 // Let's copy the domain policy from the parent to the child (if it's active).
3045 StructuredCloneData initialData
;
3046 nsIScriptSecurityManager
* ssm
= nsContentUtils::GetSecurityManager();
3048 ssm
->CloneDomainPolicy(&xpcomInit
.domainPolicy());
3050 if (ParentProcessMessageManager
* mm
=
3051 nsFrameMessageManager::sParentProcessManager
) {
3053 if (NS_WARN_IF(!jsapi
.Init(xpc::PrivilegedJunkScope()))) {
3056 JS::Rooted
<JS::Value
> init(jsapi
.cx());
3057 // We'll crash on failure, so use a IgnoredErrorResult (which also
3058 // auto-suppresses exceptions).
3059 IgnoredErrorResult rv
;
3060 mm
->GetInitialProcessData(jsapi
.cx(), &init
, rv
);
3061 if (NS_WARN_IF(rv
.Failed())) {
3065 initialData
.Write(jsapi
.cx(), init
, rv
);
3066 if (NS_WARN_IF(rv
.Failed())) {
3071 // This is only implemented (returns a non-empty list) by MacOSX and Linux
3073 SystemFontList fontList
;
3074 gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList
);
3076 const FullLookAndFeel
& lnf
= *RemoteLookAndFeel::ExtractData();
3078 // If the shared fontlist is in use, collect its shmem block handles to pass
3080 nsTArray
<SharedMemoryHandle
> sharedFontListBlocks
;
3081 gfxPlatformFontList::PlatformFontList()->ShareFontListToProcess(
3082 &sharedFontListBlocks
, OtherPid());
3084 // Content processes have no permission to access profile directory, so we
3085 // send the file URL instead.
3086 auto* sheetCache
= GlobalStyleSheetCache::Singleton();
3087 if (StyleSheet
* ucs
= sheetCache
->GetUserContentSheet()) {
3088 xpcomInit
.userContentSheetURL() = ucs
->GetSheetURI();
3090 xpcomInit
.userContentSheetURL() = nullptr;
3093 // 1. Build ContentDeviceData first, as it may affect some gfxVars.
3094 gfxPlatform::GetPlatform()->BuildContentDeviceData(
3095 &xpcomInit
.contentDeviceData());
3096 // 2. Gather non-default gfxVars.
3097 xpcomInit
.gfxNonDefaultVarUpdates() = gfxVars::FetchNonDefaultVars();
3098 // 3. Start listening for gfxVars updates, to notify content process later on.
3099 gfxVars::AddReceiver(this);
3101 nsCOMPtr
<nsIGfxInfo
> gfxInfo
= components::GfxInfo::Service();
3103 GfxInfoBase
* gfxInfoRaw
= static_cast<GfxInfoBase
*>(gfxInfo
.get());
3104 xpcomInit
.gfxFeatureStatus() = gfxInfoRaw
->GetAllFeatures();
3107 // Send the dynamic scalar definitions to the new process.
3108 TelemetryIPC::GetDynamicScalarDefinitions(xpcomInit
.dynamicScalarDefs());
3110 for (auto const& [location
, supported
] : sCodecsSupported
) {
3111 Unused
<< SendUpdateMediaCodecsSupported(location
, supported
);
3114 #ifdef MOZ_WIDGET_ANDROID
3115 if (!(StaticPrefs::media_utility_process_enabled() &&
3116 StaticPrefs::media_utility_android_media_codec_enabled())) {
3117 Unused
<< SendDecoderSupportedMimeTypes(
3118 AndroidDecoderModule::GetSupportedMimeTypesPrefixed());
3122 // Must send screen info before send initialData
3123 ScreenManager
& screenManager
= ScreenManager::GetSingleton();
3124 screenManager
.CopyScreensToRemote(this);
3126 // Send the UA sheet shared memory buffer and the address it is mapped at.
3127 Maybe
<SharedMemoryHandle
> sharedUASheetHandle
;
3128 uintptr_t sharedUASheetAddress
= sheetCache
->GetSharedMemoryAddress();
3130 if (SharedMemoryHandle handle
= sheetCache
->CloneHandle()) {
3131 sharedUASheetHandle
.emplace(std::move(handle
));
3133 sharedUASheetAddress
= 0;
3136 bool isReadyForBackgroundProcessing
= false;
3138 RefPtr
<DllServices
> dllSvc(DllServices::Get());
3139 isReadyForBackgroundProcessing
= dllSvc
->IsReadyForBackgroundProcessing();
3142 xpcomInit
.perfStatsMask() = PerfStats::GetCollectionMask();
3144 nsCOMPtr
<nsIDNSService
> dns
= do_GetService(NS_DNSSERVICE_CONTRACTID
);
3145 dns
->GetTrrDomain(xpcomInit
.trrDomain());
3147 nsIDNSService::ResolverMode mode
;
3148 dns
->GetCurrentTrrMode(&mode
);
3149 xpcomInit
.trrMode() = mode
;
3150 xpcomInit
.trrModeFromPref() =
3151 static_cast<nsIDNSService::ResolverMode
>(StaticPrefs::network_trr_mode());
3153 Unused
<< SendSetXPCOMProcessAttributes(
3154 xpcomInit
, initialData
, lnf
, fontList
, std::move(sharedUASheetHandle
),
3155 sharedUASheetAddress
, std::move(sharedFontListBlocks
),
3156 isReadyForBackgroundProcessing
);
3158 ipc::WritableSharedMap
* sharedData
=
3159 nsFrameMessageManager::sParentProcessManager
->SharedData();
3160 sharedData
->Flush();
3161 sharedData
->SendTo(this);
3163 nsCOMPtr
<nsIChromeRegistry
> registrySvc
= nsChromeRegistry::GetService();
3164 nsChromeRegistryChrome
* chromeRegistry
=
3165 static_cast<nsChromeRegistryChrome
*>(registrySvc
.get());
3166 chromeRegistry
->SendRegisteredChrome(this);
3168 nsCOMPtr
<nsIStringBundleService
> stringBundleService
=
3169 components::StringBundle::Service();
3170 stringBundleService
->SendContentBundles(this);
3173 nsCString
version(gAppData
->version
);
3174 nsCString
buildID(gAppData
->buildID
);
3175 nsCString
name(gAppData
->name
);
3176 nsCString
UAName(gAppData
->UAName
);
3177 nsCString
ID(gAppData
->ID
);
3178 nsCString
vendor(gAppData
->vendor
);
3179 nsCString
sourceURL(gAppData
->sourceURL
);
3180 nsCString
updateURL(gAppData
->updateURL
);
3182 // Sending all information to content process.
3183 Unused
<< SendAppInfo(version
, buildID
, name
, UAName
, ID
, vendor
, sourceURL
,
3187 // Send the child its remote type. On Mac, this needs to be sent prior
3188 // to the message we send to enable the Sandbox (SendStartProcessSandbox)
3189 // because different remote types require different sandbox privileges.
3191 Unused
<< SendRemoteType(mRemoteType
, mProfile
);
3193 ScriptPreloader::InitContentChild(*this);
3195 // Initialize the message manager (and load delayed scripts) now that we
3196 // have established communications with the child.
3197 mMessageManager
->InitWithCallback(this);
3198 mMessageManager
->SetOsPid(Pid());
3200 // Set the subprocess's priority. We do this early on because we're likely
3201 // /lowering/ the process's CPU and memory priority, which it has inherited
3202 // from this process.
3204 // This call can cause us to send IPC messages to the child process, so it
3205 // must come after the Open() call above.
3206 ProcessPriorityManager::SetProcessPriority(this, aInitialPriority
);
3208 // NB: internally, this will send an IPC message to the child
3209 // process to get it to create the CompositorBridgeChild. This
3210 // message goes through the regular IPC queue for this
3211 // channel, so delivery will happen-before any other messages
3212 // we send. The CompositorBridgeChild must be created before any
3213 // PBrowsers are created, because they rely on the Compositor
3214 // already being around. (Creation is async, so can't happen
3216 GPUProcessManager
* gpm
= GPUProcessManager::Get();
3218 Endpoint
<PCompositorManagerChild
> compositor
;
3219 Endpoint
<PImageBridgeChild
> imageBridge
;
3220 Endpoint
<PVRManagerChild
> vrBridge
;
3221 Endpoint
<PRemoteDecoderManagerChild
> videoManager
;
3222 AutoTArray
<uint32_t, 3> namespaces
;
3224 if (!gpm
->CreateContentBridges(OtherPid(), &compositor
, &imageBridge
,
3225 &vrBridge
, &videoManager
, &namespaces
)) {
3226 // This can fail if we've already started shutting down the compositor
3227 // thread. See Bug 1562763 comment 8.
3228 MOZ_ASSERT(AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown
));
3232 Unused
<< SendInitRendering(std::move(compositor
), std::move(imageBridge
),
3233 std::move(vrBridge
), std::move(videoManager
),
3236 gpm
->AddListener(this);
3238 nsStyleSheetService
* sheetService
= nsStyleSheetService::GetInstance();
3240 // This looks like a lot of work, but in a normal browser session we just
3243 // The URIs of the Gecko and Servo sheets should be the same, so it
3244 // shouldn't matter which we look at.
3246 for (StyleSheet
* sheet
: *sheetService
->AgentStyleSheets()) {
3247 Unused
<< SendLoadAndRegisterSheet(sheet
->GetSheetURI(),
3248 nsIStyleSheetService::AGENT_SHEET
);
3251 for (StyleSheet
* sheet
: *sheetService
->UserStyleSheets()) {
3252 Unused
<< SendLoadAndRegisterSheet(sheet
->GetSheetURI(),
3253 nsIStyleSheetService::USER_SHEET
);
3256 for (StyleSheet
* sheet
: *sheetService
->AuthorStyleSheets()) {
3257 Unused
<< SendLoadAndRegisterSheet(sheet
->GetSheetURI(),
3258 nsIStyleSheetService::AUTHOR_SHEET
);
3263 bool shouldSandbox
= true;
3264 Maybe
<FileDescriptor
> brokerFd
;
3265 // XXX: Checking the pref here makes it possible to enable/disable sandboxing
3266 // during an active session. Currently the pref is only used for testing
3267 // purpose. If the decision is made to permanently rely on the pref, this
3268 // should be changed so that it is required to restart firefox for the change
3269 // of value to take effect. Always send SetProcessSandbox message on macOS.
3270 # if !defined(XP_MACOSX)
3271 shouldSandbox
= IsContentSandboxEnabled();
3275 if (shouldSandbox
) {
3276 MOZ_ASSERT(!mSandboxBroker
);
3277 bool isFileProcess
= mRemoteType
== FILE_REMOTE_TYPE
;
3278 UniquePtr
<SandboxBroker::Policy
> policy
=
3279 sSandboxBrokerPolicyFactory
->GetContentPolicy(Pid(), isFileProcess
);
3281 brokerFd
= Some(FileDescriptor());
3283 SandboxBroker::Create(std::move(policy
), Pid(), brokerFd
.ref());
3284 if (!mSandboxBroker
) {
3285 KillHard("SandboxBroker::Create failed");
3288 MOZ_ASSERT(brokerFd
.ref().IsValid());
3292 if (shouldSandbox
&& !SendSetProcessSandbox(brokerFd
)) {
3293 KillHard("SandboxInitFailed");
3297 // Ensure that the default set of permissions are avaliable in the content
3298 // process before we try to load any URIs in it.
3300 // NOTE: All default permissions has to be transmitted to the child process
3301 // before the blob urls in the for loop below (See Bug 1738713 comment 12).
3302 EnsurePermissionsByKey(""_ns
, ""_ns
);
3305 nsTArray
<BlobURLRegistrationData
> registrations
;
3306 BlobURLProtocolHandler::ForEachBlobURL([&](BlobImpl
* aBlobImpl
,
3307 nsIPrincipal
* aPrincipal
,
3308 const nsCString
& aPartitionKey
,
3309 const nsACString
& aURI
,
3311 // We send all moz-extension Blob URL's to all content processes
3312 // because content scripts mean that a moz-extension can live in any
3313 // process. Same thing for system principal Blob URLs. Content Blob
3314 // URL's are sent for content principals on-demand by
3315 // AboutToLoadHttpFtpDocumentForChild and RemoteWorkerManager.
3316 if (!BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal
)) {
3321 nsresult rv
= IPCBlobUtils::Serialize(aBlobImpl
, ipcBlob
);
3322 if (NS_WARN_IF(NS_FAILED(rv
))) {
3326 registrations
.AppendElement(
3327 BlobURLRegistrationData(nsCString(aURI
), ipcBlob
, aPrincipal
,
3328 nsCString(aPartitionKey
), aRevoked
));
3330 rv
= TransmitPermissionsForPrincipal(aPrincipal
);
3331 Unused
<< NS_WARN_IF(NS_FAILED(rv
));
3335 if (!registrations
.IsEmpty()) {
3336 Unused
<< SendInitBlobURLs(registrations
);
3340 // Send down { Parent, Window }ActorOptions at startup to content process.
3341 RefPtr
<JSActorService
> actorSvc
= JSActorService::GetSingleton();
3343 nsTArray
<JSProcessActorInfo
> contentInfos
;
3344 actorSvc
->GetJSProcessActorInfos(contentInfos
);
3346 nsTArray
<JSWindowActorInfo
> windowInfos
;
3347 actorSvc
->GetJSWindowActorInfos(windowInfos
);
3349 Unused
<< SendInitJSActorInfos(contentInfos
, windowInfos
);
3352 // Begin subscribing to any BrowsingContextGroups which were hosted by this
3353 // process before it finished launching.
3354 for (const auto& group
: mGroups
) {
3355 group
->Subscribe(this);
3358 MaybeEnableRemoteInputEventQueue();
3363 bool ContentParent::IsAlive() const {
3364 return mLifecycleState
== LifecycleState::ALIVE
||
3365 mLifecycleState
== LifecycleState::INITIALIZED
;
3368 bool ContentParent::IsInitialized() const {
3369 return mLifecycleState
== LifecycleState::INITIALIZED
;
3372 int32_t ContentParent::Pid() const {
3376 auto pid
= mSubprocess
->GetChildProcessId();
3380 return ReleaseAssertedCast
<int32_t>(pid
);
3383 void ContentParent::OnCompositorUnexpectedShutdown() {
3384 GPUProcessManager
* gpm
= GPUProcessManager::Get();
3386 Endpoint
<PCompositorManagerChild
> compositor
;
3387 Endpoint
<PImageBridgeChild
> imageBridge
;
3388 Endpoint
<PVRManagerChild
> vrBridge
;
3389 Endpoint
<PRemoteDecoderManagerChild
> videoManager
;
3390 AutoTArray
<uint32_t, 3> namespaces
;
3392 if (!gpm
->CreateContentBridges(OtherPid(), &compositor
, &imageBridge
,
3393 &vrBridge
, &videoManager
, &namespaces
)) {
3394 MOZ_ASSERT(AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown
));
3398 Unused
<< SendReinitRendering(std::move(compositor
), std::move(imageBridge
),
3399 std::move(vrBridge
), std::move(videoManager
),
3403 void ContentParent::OnCompositorDeviceReset() {
3404 Unused
<< SendReinitRenderingForDeviceReset();
3407 void ContentParent::MaybeEnableRemoteInputEventQueue() {
3408 MOZ_ASSERT(!mIsRemoteInputEventQueueEnabled
);
3409 if (!IsInputEventQueueSupported()) {
3412 mIsRemoteInputEventQueueEnabled
= true;
3413 Unused
<< SendSetInputEventQueueEnabled();
3414 SetInputPriorityEventEnabled(true);
3417 void ContentParent::SetInputPriorityEventEnabled(bool aEnabled
) {
3418 if (!IsInputEventQueueSupported() || !mIsRemoteInputEventQueueEnabled
||
3419 mIsInputPriorityEventEnabled
== aEnabled
) {
3422 mIsInputPriorityEventEnabled
= aEnabled
;
3423 // Send IPC messages to flush the pending events in the input event queue and
3424 // the normal event queue. See PContent.ipdl for more details.
3425 Unused
<< SendSuspendInputEventQueue();
3426 Unused
<< SendFlushInputEventQueue();
3427 Unused
<< SendResumeInputEventQueue();
3431 bool ContentParent::IsInputEventQueueSupported() {
3432 static bool sSupported
= false;
3433 static bool sInitialized
= false;
3434 if (!sInitialized
) {
3435 MOZ_ASSERT(Preferences::IsServiceAvailable());
3436 sSupported
= Preferences::GetBool("input_event_queue.supported", false);
3437 sInitialized
= true;
3442 void ContentParent::OnVarChanged(const GfxVarUpdate
& aVar
) {
3446 Unused
<< SendVarUpdate(aVar
);
3449 mozilla::ipc::IPCResult
ContentParent::RecvSetClipboard(
3450 const IPCTransferable
& aTransferable
, const int32_t& aWhichClipboard
) {
3451 // aRequestingPrincipal is allowed to be nullptr here.
3453 if (!ValidatePrincipal(aTransferable
.requestingPrincipal(),
3454 {ValidatePrincipalOptions::AllowNullPtr
})) {
3455 LogAndAssertFailedPrincipalValidationInfo(
3456 aTransferable
.requestingPrincipal(), __func__
);
3460 nsCOMPtr
<nsIClipboard
> clipboard(do_GetService(kCClipboardCID
, &rv
));
3461 NS_ENSURE_SUCCESS(rv
, IPC_OK());
3463 nsCOMPtr
<nsITransferable
> trans
=
3464 do_CreateInstance("@mozilla.org/widget/transferable;1", &rv
);
3465 NS_ENSURE_SUCCESS(rv
, IPC_OK());
3466 trans
->Init(nullptr);
3468 rv
= nsContentUtils::IPCTransferableToTransferable(
3469 aTransferable
, true /* aAddDataFlavor */, trans
,
3470 true /* aFilterUnknownFlavors */);
3471 NS_ENSURE_SUCCESS(rv
, IPC_OK());
3473 clipboard
->SetData(trans
, nullptr, aWhichClipboard
);
3479 static Result
<nsCOMPtr
<nsITransferable
>, nsresult
> CreateTransferable(
3480 const nsTArray
<nsCString
>& aTypes
) {
3482 nsCOMPtr
<nsITransferable
> trans
=
3483 do_CreateInstance("@mozilla.org/widget/transferable;1", &rv
);
3484 if (NS_FAILED(rv
)) {
3488 MOZ_TRY(trans
->Init(nullptr));
3489 // The private flag is only used to prevent the data from being cached to the
3490 // disk. The flag is not exported to the IPCDataTransfer object.
3491 // The flag is set because we are not sure whether the clipboard data is used
3492 // in a private browsing context. The transferable is only used in this scope,
3493 // so the cache would not reduce memory consumption anyway.
3494 trans
->SetIsPrivateData(true);
3495 // Fill out flavors for transferable
3496 for (uint32_t t
= 0; t
< aTypes
.Length(); t
++) {
3497 MOZ_TRY(trans
->AddDataFlavor(aTypes
[t
].get()));
3500 return std::move(trans
);
3503 } // anonymous namespace
3505 mozilla::ipc::IPCResult
ContentParent::RecvGetClipboard(
3506 nsTArray
<nsCString
>&& aTypes
, const int32_t& aWhichClipboard
,
3507 IPCTransferableData
* aTransferableData
) {
3509 // Retrieve clipboard
3510 nsCOMPtr
<nsIClipboard
> clipboard(do_GetService(kCClipboardCID
, &rv
));
3511 if (NS_FAILED(rv
)) {
3515 // Create transferable
3516 auto result
= CreateTransferable(aTypes
);
3517 if (result
.isErr()) {
3521 // Get data from clipboard
3522 nsCOMPtr
<nsITransferable
> trans
= result
.unwrap();
3523 clipboard
->GetData(trans
, aWhichClipboard
);
3525 nsContentUtils::TransferableToIPCTransferableData(
3526 trans
, aTransferableData
, true /* aInSyncMessage */, this);
3530 mozilla::ipc::IPCResult
ContentParent::RecvEmptyClipboard(
3531 const int32_t& aWhichClipboard
) {
3533 nsCOMPtr
<nsIClipboard
> clipboard(do_GetService(kCClipboardCID
, &rv
));
3534 NS_ENSURE_SUCCESS(rv
, IPC_OK());
3536 clipboard
->EmptyClipboard(aWhichClipboard
);
3541 mozilla::ipc::IPCResult
ContentParent::RecvClipboardHasType(
3542 nsTArray
<nsCString
>&& aTypes
, const int32_t& aWhichClipboard
,
3545 nsCOMPtr
<nsIClipboard
> clipboard(do_GetService(kCClipboardCID
, &rv
));
3546 NS_ENSURE_SUCCESS(rv
, IPC_OK());
3548 clipboard
->HasDataMatchingFlavors(aTypes
, aWhichClipboard
, aHasType
);
3553 mozilla::ipc::IPCResult
ContentParent::RecvGetExternalClipboardFormats(
3554 const int32_t& aWhichClipboard
, const bool& aPlainTextOnly
,
3555 nsTArray
<nsCString
>* aTypes
) {
3557 DataTransfer::GetExternalClipboardFormats(aWhichClipboard
, aPlainTextOnly
,
3564 class ClipboardGetCallback final
: public nsIAsyncClipboardGetCallback
{
3566 ClipboardGetCallback(ContentParent
* aContentParent
,
3567 ContentParent::GetClipboardAsyncResolver
&& aResolver
)
3568 : mContentParent(aContentParent
), mResolver(std::move(aResolver
)) {}
3570 // This object will never be held by a cycle-collected object, so it doesn't
3571 // need to be cycle-collected despite holding alive cycle-collected objects.
3574 // nsIAsyncClipboardGetCallback
3575 NS_IMETHOD
OnSuccess(
3576 nsIAsyncGetClipboardData
* aAsyncGetClipboardData
) override
{
3577 nsTArray
<nsCString
> flavors
;
3578 nsresult rv
= aAsyncGetClipboardData
->GetFlavorList(flavors
);
3579 if (NS_FAILED(rv
)) {
3583 auto requestParent
= MakeNotNull
<RefPtr
<ClipboardReadRequestParent
>>(
3584 mContentParent
, aAsyncGetClipboardData
);
3585 if (!mContentParent
->SendPClipboardReadRequestConstructor(
3586 requestParent
, std::move(flavors
))) {
3587 return OnError(NS_ERROR_FAILURE
);
3590 mResolver(PClipboardReadRequestOrError(requestParent
));
3594 NS_IMETHOD
OnError(nsresult aResult
) override
{
3600 ~ClipboardGetCallback() = default;
3602 RefPtr
<ContentParent
> mContentParent
;
3603 ContentParent::GetClipboardAsyncResolver mResolver
;
3606 NS_IMPL_ISUPPORTS(ClipboardGetCallback
, nsIAsyncClipboardGetCallback
)
3610 mozilla::ipc::IPCResult
ContentParent::RecvGetClipboardAsync(
3611 nsTArray
<nsCString
>&& aTypes
, const int32_t& aWhichClipboard
,
3612 GetClipboardAsyncResolver
&& aResolver
) {
3614 // Retrieve clipboard
3615 nsCOMPtr
<nsIClipboard
> clipboard(do_GetService(kCClipboardCID
, &rv
));
3616 if (NS_FAILED(rv
)) {
3621 auto callback
= MakeRefPtr
<ClipboardGetCallback
>(this, std::move(aResolver
));
3622 rv
= clipboard
->AsyncGetData(aTypes
, aWhichClipboard
, callback
);
3623 if (NS_FAILED(rv
)) {
3624 callback
->OnError(rv
);
3631 already_AddRefed
<PClipboardWriteRequestParent
>
3632 ContentParent::AllocPClipboardWriteRequestParent(
3633 const int32_t& aClipboardType
) {
3634 RefPtr
<ClipboardWriteRequestParent
> request
=
3635 MakeAndAddRef
<ClipboardWriteRequestParent
>(this);
3636 request
->Init(aClipboardType
);
3637 return request
.forget();
3640 mozilla::ipc::IPCResult
ContentParent::RecvGetIconForExtension(
3641 const nsACString
& aFileExt
, const uint32_t& aIconSize
,
3642 nsTArray
<uint8_t>* bits
) {
3643 #ifdef MOZ_WIDGET_ANDROID
3644 NS_ASSERTION(AndroidBridge::Bridge() != nullptr,
3645 "AndroidBridge is not available");
3646 if (AndroidBridge::Bridge() == nullptr) {
3647 // Do not fail - just no icon will be shown
3651 bits
->AppendElements(aIconSize
* aIconSize
* 4);
3653 AndroidBridge::Bridge()->GetIconForExtension(aFileExt
, aIconSize
,
3659 mozilla::ipc::IPCResult
ContentParent::RecvFirstIdle() {
3660 // When the ContentChild goes idle, it sends us a FirstIdle message
3661 // which we use as a good time to signal the PreallocatedProcessManager
3662 // that it can start allocating processes from now on.
3663 if (mIsAPreallocBlocker
) {
3665 ContentParent::GetLog(), LogLevel::Verbose
,
3666 ("RecvFirstIdle %p: Removing Blocker for %s", this, mRemoteType
.get()));
3667 PreallocatedProcessManager::RemoveBlocker(mRemoteType
, this);
3668 mIsAPreallocBlocker
= false;
3673 already_AddRefed
<nsDocShellLoadState
> ContentParent::TakePendingLoadStateForId(
3674 uint64_t aLoadIdentifier
) {
3675 return mPendingLoadStates
.Extract(aLoadIdentifier
).valueOr(nullptr).forget();
3678 void ContentParent::StorePendingLoadState(nsDocShellLoadState
* aLoadState
) {
3679 MOZ_DIAGNOSTIC_ASSERT(
3680 !mPendingLoadStates
.Contains(aLoadState
->GetLoadIdentifier()),
3681 "The same nsDocShellLoadState was sent to the same content process "
3682 "twice? This will mess with cross-process tracking of loads");
3683 mPendingLoadStates
.InsertOrUpdate(aLoadState
->GetLoadIdentifier(),
3687 mozilla::ipc::IPCResult
ContentParent::RecvCleanupPendingLoadState(
3688 uint64_t aLoadIdentifier
) {
3689 mPendingLoadStates
.Remove(aLoadIdentifier
);
3693 // We want ContentParent to show up in CC logs for debugging purposes, but we
3694 // don't actually cycle collect it.
3695 NS_IMPL_CYCLE_COLLECTION_0(ContentParent
)
3697 NS_IMPL_CYCLE_COLLECTING_ADDREF(ContentParent
)
3698 NS_IMPL_CYCLE_COLLECTING_RELEASE(ContentParent
)
3700 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ContentParent
)
3701 NS_INTERFACE_MAP_ENTRY_CONCRETE(ContentParent
)
3702 NS_INTERFACE_MAP_ENTRY(nsIDOMProcessParent
)
3703 NS_INTERFACE_MAP_ENTRY(nsIObserver
)
3704 NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionCallback
)
3705 NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionErrorCallback
)
3706 NS_INTERFACE_MAP_ENTRY(nsIAsyncShutdownBlocker
)
3707 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor
)
3708 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIDOMProcessParent
)
3709 NS_INTERFACE_MAP_END
3711 class RequestContentJSInterruptRunnable final
: public Runnable
{
3713 explicit RequestContentJSInterruptRunnable(PProcessHangMonitorParent
* aActor
)
3714 : Runnable("dom::RequestContentJSInterruptRunnable"),
3715 mHangMonitorActor(aActor
) {}
3717 NS_IMETHOD
Run() override
{
3718 MOZ_ASSERT(mHangMonitorActor
);
3719 Unused
<< mHangMonitorActor
->SendRequestContentJSInterrupt();
3725 // The end-of-life of ContentParent::mHangMonitorActor is bound to
3726 // ContentParent::ActorDestroy and then HangMonitorParent::Shutdown
3727 // dispatches a shutdown runnable to this queue and waits for it to be
3728 // executed. So the runnable needs not to care about keeping it alive,
3729 // as it is surely dispatched earlier than the
3730 // HangMonitorParent::ShutdownOnThread.
3731 RefPtr
<PProcessHangMonitorParent
> mHangMonitorActor
;
3734 void ContentParent::SignalImpendingShutdownToContentJS() {
3735 if (!mIsSignaledImpendingShutdown
&&
3736 !AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown
)) {
3737 MaybeLogBlockShutdownDiagnostics(
3738 this, "BlockShutdown: NotifyImpendingShutdown.", __FILE__
, __LINE__
);
3739 NotifyImpendingShutdown();
3740 mIsSignaledImpendingShutdown
= true;
3741 if (mHangMonitorActor
&&
3742 StaticPrefs::dom_abort_script_on_child_shutdown()) {
3743 MaybeLogBlockShutdownDiagnostics(
3744 this, "BlockShutdown: RequestContentJSInterrupt.", __FILE__
,
3746 RefPtr
<RequestContentJSInterruptRunnable
> r
=
3747 new RequestContentJSInterruptRunnable(mHangMonitorActor
);
3748 ProcessHangMonitor::Get()->Dispatch(r
.forget());
3753 // Async shutdown blocker
3755 ContentParent::BlockShutdown(nsIAsyncShutdownClient
* aClient
) {
3756 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown
)) {
3757 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3758 mBlockShutdownCalled
= true;
3760 // Our real shutdown has not yet started. Just notify the impending
3761 // shutdown and eventually cancel content JS.
3762 SignalImpendingShutdownToContentJS();
3763 // This will make our process unusable for normal content, so we need to
3764 // ensure we won't get re-used by GetUsedBrowserProcess as we have not yet
3766 PreallocatedProcessManager::Erase(this);
3767 StopRecyclingE10SOnly(false);
3769 if (sQuitApplicationGrantedClient
) {
3770 Unused
<< sQuitApplicationGrantedClient
->RemoveBlocker(this);
3772 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3773 mBlockShutdownCalled
= false;
3778 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3779 // We register two final shutdown blockers and both would call us, but if
3780 // things go well we will unregister both as (delayed) reaction to the first
3781 // call we get and thus never receive a second call. Thus we believe that we
3782 // will get called only once except for quit-application-granted, which is
3784 MOZ_ASSERT(!mBlockShutdownCalled
);
3785 mBlockShutdownCalled
= true;
3789 MaybeLogBlockShutdownDiagnostics(this, "BlockShutdown: CanSend.", __FILE__
,
3792 // Make sure that our process will get scheduled.
3793 ProcessPriorityManager::SetProcessPriority(this,
3794 PROCESS_PRIORITY_FOREGROUND
);
3795 // The normal shutdown sequence is to send a shutdown message
3796 // to the child and then just wait for ActorDestroy which will
3797 // cleanup everything and remove our blockers.
3798 if (!ShutDownProcess(SEND_SHUTDOWN_MESSAGE
)) {
3799 KillHard("Failed to send Shutdown message. Destroying the process...");
3802 } else if (IsLaunching()) {
3803 MaybeLogBlockShutdownDiagnostics(
3804 this, "BlockShutdown: !CanSend && IsLaunching.", __FILE__
, __LINE__
);
3806 // If we get here while we are launching, we must wait for the child to
3807 // be able to react on our commands. Mark this process as dead. This
3808 // will make bail out LaunchSubprocessResolve and kick off the normal
3809 // shutdown sequence.
3812 MOZ_ASSERT(IsDead());
3814 MaybeLogBlockShutdownDiagnostics(
3815 this, "BlockShutdown: !!! !CanSend && !IsLaunching && !IsDead !!!",
3816 __FILE__
, __LINE__
);
3818 MaybeLogBlockShutdownDiagnostics(
3819 this, "BlockShutdown: !CanSend && !IsLaunching && IsDead.", __FILE__
,
3822 // Nothing left we can do. We must assume that we race with an ongoing
3823 // process shutdown, such that we can expect our shutdown blockers to be
3824 // removed normally.
3831 ContentParent::GetName(nsAString
& aName
) {
3832 aName
.AssignLiteral("ContentParent:");
3833 aName
.AppendPrintf(" id=%p", this);
3838 ContentParent::GetState(nsIPropertyBag
** aResult
) {
3839 auto props
= MakeRefPtr
<nsHashPropertyBag
>();
3840 props
->SetPropertyAsACString(u
"remoteTypePrefix"_ns
,
3841 RemoteTypePrefix(mRemoteType
));
3842 *aResult
= props
.forget().downcast
<nsIWritablePropertyBag
>().take();
3846 static void InitShutdownClients() {
3847 if (!sXPCOMShutdownClient
) {
3849 nsCOMPtr
<nsIAsyncShutdownService
> svc
= services::GetAsyncShutdownService();
3854 nsCOMPtr
<nsIAsyncShutdownClient
> client
;
3855 // TODO: It seems as if getPhase from AsyncShutdown.sys.mjs does not check
3856 // if we are beyond our phase already. See bug 1762840.
3857 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMWillShutdown
)) {
3858 rv
= svc
->GetXpcomWillShutdown(getter_AddRefs(client
));
3859 if (NS_SUCCEEDED(rv
)) {
3860 sXPCOMShutdownClient
= client
.forget();
3861 ClearOnShutdown(&sXPCOMShutdownClient
);
3864 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown
)) {
3865 rv
= svc
->GetProfileBeforeChange(getter_AddRefs(client
));
3866 if (NS_SUCCEEDED(rv
)) {
3867 sProfileBeforeChangeClient
= client
.forget();
3868 ClearOnShutdown(&sProfileBeforeChangeClient
);
3871 // TODO: ShutdownPhase::AppShutdownConfirmed is not mapping to
3872 // QuitApplicationGranted, see bug 1762840 comment 4.
3873 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
3874 rv
= svc
->GetQuitApplicationGranted(getter_AddRefs(client
));
3875 if (NS_SUCCEEDED(rv
)) {
3876 sQuitApplicationGrantedClient
= client
.forget();
3877 ClearOnShutdown(&sQuitApplicationGrantedClient
);
3883 void ContentParent::AddShutdownBlockers() {
3884 InitShutdownClients();
3885 MOZ_ASSERT(sXPCOMShutdownClient
);
3886 MOZ_ASSERT(sProfileBeforeChangeClient
);
3888 if (sXPCOMShutdownClient
) {
3889 sXPCOMShutdownClient
->AddBlocker(
3890 this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__
), __LINE__
, u
""_ns
);
3892 if (sProfileBeforeChangeClient
) {
3893 sProfileBeforeChangeClient
->AddBlocker(
3894 this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__
), __LINE__
, u
""_ns
);
3896 if (sQuitApplicationGrantedClient
) {
3897 sQuitApplicationGrantedClient
->AddBlocker(
3898 this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__
), __LINE__
, u
""_ns
);
3902 void ContentParent::RemoveShutdownBlockers() {
3903 MOZ_ASSERT(sXPCOMShutdownClient
);
3904 MOZ_ASSERT(sProfileBeforeChangeClient
);
3906 MaybeLogBlockShutdownDiagnostics(this, "RemoveShutdownBlockers", __FILE__
,
3908 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3909 mBlockShutdownCalled
= false;
3912 if (sXPCOMShutdownClient
) {
3913 Unused
<< sXPCOMShutdownClient
->RemoveBlocker(this);
3915 if (sProfileBeforeChangeClient
) {
3916 Unused
<< sProfileBeforeChangeClient
->RemoveBlocker(this);
3918 if (sQuitApplicationGrantedClient
) {
3919 Unused
<< sQuitApplicationGrantedClient
->RemoveBlocker(this);
3924 ContentParent::Observe(nsISupports
* aSubject
, const char* aTopic
,
3925 const char16_t
* aData
) {
3926 if (IsDead() || !mSubprocess
) {
3930 if (!strcmp(aTopic
, "nsPref:changed")) {
3931 // We know prefs are ASCII here.
3932 NS_LossyConvertUTF16toASCII
strData(aData
);
3934 Pref
pref(strData
, /* isLocked */ false,
3935 /* isSanitized */ false, Nothing(), Nothing());
3937 Preferences::GetPreference(&pref
, GeckoProcessType_Content
,
3940 // This check is a bit of a hack. We want to avoid sending excessive
3941 // preference updates to subprocesses for performance reasons, but we
3942 // currently don't have a great mechanism for doing so. (See Bug 1819714)
3943 // We're going to hijack the sanitization mechanism to accomplish our goal
3944 // but it imposes the following complications:
3945 // 1) It doesn't avoid sending anything to other (non-web-content)
3946 // subprocesses so we're not getting any perf gains there
3947 // 2) It confuses the subprocesses w.r.t. sanitization. The point of
3948 // sending a preference update of a sanitized preference is so that
3949 // content process knows when it's asked to resolve a sanitized
3950 // preference, and it can send telemetry and/or crash. With this
3951 // change, a sanitized pref that is created during the browser session
3952 // will not be sent to the content process, and therefore the content
3953 // process won't know it should telemetry/crash on access - it'll just
3954 // silently fail to resolve it. After browser restart, the sanitized
3955 // pref will be populated into the content process via the shared pref
3956 // map and _then_ if it is accessed, the content process will crash.
3957 // We're seeing good telemetry/crash rates right now, so we're okay with
3959 if (pref
.isSanitized()) {
3963 if (IsInitialized()) {
3964 MOZ_ASSERT(mQueuedPrefs
.IsEmpty());
3965 if (!SendPreferenceUpdate(pref
)) {
3966 return NS_ERROR_NOT_AVAILABLE
;
3969 MOZ_ASSERT(!IsDead());
3970 mQueuedPrefs
.AppendElement(pref
);
3980 // listening for memory pressure event
3981 if (!strcmp(aTopic
, "memory-pressure")) {
3982 Unused
<< SendFlushMemory(nsDependentString(aData
));
3983 } else if (!strcmp(aTopic
, "application-background")) {
3984 Unused
<< SendApplicationBackground();
3985 } else if (!strcmp(aTopic
, "application-foreground")) {
3986 Unused
<< SendApplicationForeground();
3987 } else if (!strcmp(aTopic
, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC
)) {
3988 NS_ConvertUTF16toUTF8
dataStr(aData
);
3989 const char* offline
= dataStr
.get();
3990 if (!SendSetOffline(!strcmp(offline
, "true"))) {
3991 return NS_ERROR_NOT_AVAILABLE
;
3993 } else if (!strcmp(aTopic
, NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC
)) {
3994 if (!SendSetConnectivity(u
"true"_ns
.Equals(aData
))) {
3995 return NS_ERROR_NOT_AVAILABLE
;
3997 } else if (!strcmp(aTopic
, NS_IPC_CAPTIVE_PORTAL_SET_STATE
)) {
3998 nsCOMPtr
<nsICaptivePortalService
> cps
= do_QueryInterface(aSubject
);
3999 MOZ_ASSERT(cps
, "Should QI to a captive portal service");
4001 return NS_ERROR_FAILURE
;
4004 cps
->GetState(&state
);
4005 if (!SendSetCaptivePortalState(state
)) {
4006 return NS_ERROR_NOT_AVAILABLE
;
4009 // listening for alert notifications
4010 else if (!strcmp(aTopic
, "alertfinished") ||
4011 !strcmp(aTopic
, "alertclickcallback") ||
4012 !strcmp(aTopic
, "alertshow") ||
4013 !strcmp(aTopic
, "alertdisablecallback") ||
4014 !strcmp(aTopic
, "alertsettingscallback")) {
4015 if (!SendNotifyAlertsObserver(nsDependentCString(aTopic
),
4016 nsDependentString(aData
)))
4017 return NS_ERROR_NOT_AVAILABLE
;
4018 } else if (!strcmp(aTopic
, "child-gc-request")) {
4019 Unused
<< SendGarbageCollect();
4020 } else if (!strcmp(aTopic
, "child-cc-request")) {
4021 Unused
<< SendCycleCollect();
4022 } else if (!strcmp(aTopic
, "child-mmu-request")) {
4023 Unused
<< SendMinimizeMemoryUsage();
4024 } else if (!strcmp(aTopic
, "child-ghost-request")) {
4025 Unused
<< SendUnlinkGhosts();
4026 } else if (!strcmp(aTopic
, "last-pb-context-exited")) {
4027 Unused
<< SendLastPrivateDocShellDestroyed();
4029 #ifdef ACCESSIBILITY
4030 else if (aData
&& !strcmp(aTopic
, "a11y-init-or-shutdown")) {
4031 if (*aData
== '1') {
4032 // Make sure accessibility is running in content process when
4033 // accessibility gets initiated in chrome process.
4034 Unused
<< SendActivateA11y();
4036 // If possible, shut down accessibility in content process when
4037 // accessibility gets shutdown in chrome process.
4038 Unused
<< SendShutdownA11y();
4042 else if (!strcmp(aTopic
, "cacheservice:empty-cache")) {
4043 Unused
<< SendNotifyEmptyHTTPCache();
4044 } else if (!strcmp(aTopic
, "intl:app-locales-changed")) {
4045 nsTArray
<nsCString
> appLocales
;
4046 LocaleService::GetInstance()->GetAppLocalesAsBCP47(appLocales
);
4047 Unused
<< SendUpdateAppLocales(appLocales
);
4048 } else if (!strcmp(aTopic
, "intl:requested-locales-changed")) {
4049 nsTArray
<nsCString
> requestedLocales
;
4050 LocaleService::GetInstance()->GetRequestedLocales(requestedLocales
);
4051 Unused
<< SendUpdateRequestedLocales(requestedLocales
);
4052 } else if (!strcmp(aTopic
, "cookie-changed") ||
4053 !strcmp(aTopic
, "private-cookie-changed")) {
4054 MOZ_ASSERT(aSubject
, "cookie changed notification must have subject.");
4055 nsCOMPtr
<nsICookieNotification
> notification
= do_QueryInterface(aSubject
);
4056 MOZ_ASSERT(notification
,
4057 "cookie changed notification must have nsICookieNotification.");
4058 nsICookieNotification::Action action
= notification
->GetAction();
4060 PNeckoParent
* neckoParent
= LoneManagedOrNullAsserts(ManagedPNeckoParent());
4064 PCookieServiceParent
* csParent
=
4065 LoneManagedOrNullAsserts(neckoParent
->ManagedPCookieServiceParent());
4069 auto* cs
= static_cast<CookieServiceParent
*>(csParent
);
4070 if (action
== nsICookieNotification::COOKIES_BATCH_DELETED
) {
4071 nsCOMPtr
<nsIArray
> cookieList
;
4072 DebugOnly
<nsresult
> rv
=
4073 notification
->GetBatchDeletedCookies(getter_AddRefs(cookieList
));
4074 NS_ASSERTION(NS_SUCCEEDED(rv
) && cookieList
, "couldn't get cookie list");
4075 cs
->RemoveBatchDeletedCookies(cookieList
);
4079 if (action
== nsICookieNotification::ALL_COOKIES_CLEARED
) {
4084 // Do not push these cookie updates to the same process they originated
4086 if (cs
->ProcessingCookie()) {
4090 nsCOMPtr
<nsICookie
> xpcCookie
;
4091 DebugOnly
<nsresult
> rv
= notification
->GetCookie(getter_AddRefs(xpcCookie
));
4092 NS_ASSERTION(NS_SUCCEEDED(rv
) && xpcCookie
, "couldn't get cookie");
4094 // only broadcast the cookie change to content processes that need it
4095 const Cookie
& cookie
= xpcCookie
->AsCookie();
4097 // do not send cookie if content process does not have similar cookie
4098 if (!cs
->ContentProcessHasCookie(cookie
)) {
4102 if (action
== nsICookieNotification::COOKIE_DELETED
) {
4103 cs
->RemoveCookie(cookie
);
4104 } else if (action
== nsICookieNotification::COOKIE_ADDED
||
4105 action
== nsICookieNotification::COOKIE_CHANGED
) {
4106 cs
->AddCookie(cookie
);
4108 } else if (!strcmp(aTopic
, NS_NETWORK_LINK_TYPE_TOPIC
)) {
4109 UpdateNetworkLinkType();
4110 } else if (!strcmp(aTopic
, "network:socket-process-crashed")) {
4111 Unused
<< SendSocketProcessCrashed();
4112 } else if (!strcmp(aTopic
, DEFAULT_TIMEZONE_CHANGED_OBSERVER_TOPIC
)) {
4113 Unused
<< SendSystemTimezoneChanged();
4114 } else if (!strcmp(aTopic
, NS_NETWORK_TRR_MODE_CHANGED_TOPIC
)) {
4115 nsCOMPtr
<nsIDNSService
> dns
= do_GetService(NS_DNSSERVICE_CONTRACTID
);
4116 nsIDNSService::ResolverMode mode
;
4117 dns
->GetCurrentTrrMode(&mode
);
4118 Unused
<< SendSetTRRMode(mode
, static_cast<nsIDNSService::ResolverMode
>(
4119 StaticPrefs::network_trr_mode()));
4125 void ContentParent::UpdateNetworkLinkType() {
4127 nsCOMPtr
<nsINetworkLinkService
> nls
=
4128 do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID
, &rv
);
4129 if (NS_FAILED(rv
)) {
4133 uint32_t linkType
= nsINetworkLinkService::LINK_TYPE_UNKNOWN
;
4134 rv
= nls
->GetLinkType(&linkType
);
4135 if (NS_FAILED(rv
)) {
4139 Unused
<< SendNetworkLinkTypeChange(linkType
);
4143 ContentParent::GetInterface(const nsIID
& aIID
, void** aResult
) {
4144 NS_ENSURE_ARG_POINTER(aResult
);
4146 if (aIID
.Equals(NS_GET_IID(nsIMessageSender
))) {
4147 nsCOMPtr
<nsIMessageSender
> mm
= GetMessageManager();
4152 return NS_NOINTERFACE
;
4155 mozilla::ipc::IPCResult
ContentParent::RecvInitBackground(
4156 Endpoint
<PBackgroundStarterParent
>&& aEndpoint
) {
4157 if (!BackgroundParent::AllocStarter(this, std::move(aEndpoint
))) {
4158 NS_WARNING("BackgroundParent::Alloc failed");
4164 bool ContentParent::CanOpenBrowser(const IPCTabContext
& aContext
) {
4165 // (PopupIPCTabContext lets the child process prove that it has access to
4166 // the app it's trying to open.)
4167 // On e10s we also allow UnsafeTabContext to allow service workers to open
4168 // windows. This is enforced in MaybeInvalidTabContext.
4169 if (aContext
.type() != IPCTabContext::TPopupIPCTabContext
) {
4170 MOZ_CRASH_UNLESS_FUZZING(
4171 "Unexpected IPCTabContext type. Aborting AllocPBrowserParent.");
4175 if (aContext
.type() == IPCTabContext::TPopupIPCTabContext
) {
4176 const PopupIPCTabContext
& popupContext
= aContext
.get_PopupIPCTabContext();
4178 auto opener
= BrowserParent::GetFrom(popupContext
.opener().AsParent());
4180 MOZ_CRASH_UNLESS_FUZZING(
4181 "Got null opener from child; aborting AllocPBrowserParent.");
4186 MaybeInvalidTabContext
tc(aContext
);
4187 if (!tc
.IsValid()) {
4188 NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext. (%s) "
4189 "Aborting AllocPBrowserParent.",
4190 tc
.GetInvalidReason())
4198 static bool CloneIsLegal(ContentParent
* aCp
, CanonicalBrowsingContext
& aSource
,
4199 CanonicalBrowsingContext
& aTarget
) {
4200 // Source and target must be in the same BCG
4201 if (NS_WARN_IF(aSource
.Group() != aTarget
.Group())) {
4204 // The source and target must be in different toplevel <browser>s
4205 if (NS_WARN_IF(aSource
.Top() == aTarget
.Top())) {
4209 // Neither source nor target must be toplevel.
4210 if (NS_WARN_IF(aSource
.IsTop()) || NS_WARN_IF(aTarget
.IsTop())) {
4214 // Both should be embedded by the same process.
4215 auto* sourceEmbedder
= aSource
.GetParentWindowContext();
4216 if (NS_WARN_IF(!sourceEmbedder
) ||
4217 NS_WARN_IF(sourceEmbedder
->GetContentParent() != aCp
)) {
4221 auto* targetEmbedder
= aSource
.GetParentWindowContext();
4222 if (NS_WARN_IF(!targetEmbedder
) ||
4223 NS_WARN_IF(targetEmbedder
->GetContentParent() != aCp
)) {
4231 mozilla::ipc::IPCResult
ContentParent::RecvCloneDocumentTreeInto(
4232 const MaybeDiscarded
<BrowsingContext
>& aSource
,
4233 const MaybeDiscarded
<BrowsingContext
>& aTarget
, PrintData
&& aPrintData
) {
4234 if (aSource
.IsNullOrDiscarded() || aTarget
.IsNullOrDiscarded()) {
4238 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
4239 // All existing processes have potentially been slated for removal already,
4240 // such that any subsequent call to GetNewOrUsedLaunchingBrowserProcess
4241 // (normally supposed to find an existing process here) will try to create
4242 // a new process (but fail) that nobody would ever really use. Let's avoid
4243 // this together with the expensive CloneDocumentTreeInto operation.
4247 auto* source
= aSource
.get_canonical();
4248 auto* target
= aTarget
.get_canonical();
4250 if (!CloneIsLegal(this, *source
, *target
)) {
4251 return IPC_FAIL(this, "Illegal subframe clone");
4254 ContentParent
* cp
= source
->GetContentParent();
4255 if (NS_WARN_IF(!cp
)) {
4259 if (NS_WARN_IF(cp
->GetRemoteType() == GetRemoteType())) {
4260 // Wanted to switch to a target browsing context that's already local again.
4261 // See bug 1676996 for how this can happen.
4263 // Dropping the switch on the floor seems fine for this case, though we
4264 // could also try to clone the local document.
4266 // If the remote type matches & it's in the same group (which was confirmed
4267 // by CloneIsLegal), it must be the exact same process.
4268 MOZ_DIAGNOSTIC_ASSERT(cp
== this);
4272 target
->CloneDocumentTreeInto(source
, cp
->GetRemoteType(),
4273 std::move(aPrintData
));
4277 mozilla::ipc::IPCResult
ContentParent::RecvUpdateRemotePrintSettings(
4278 const MaybeDiscarded
<BrowsingContext
>& aTarget
, PrintData
&& aPrintData
) {
4279 if (aTarget
.IsNullOrDiscarded()) {
4283 auto* target
= aTarget
.get_canonical();
4284 auto* bp
= target
->GetBrowserParent();
4285 if (NS_WARN_IF(!bp
)) {
4289 Unused
<< bp
->SendUpdateRemotePrintSettings(std::move(aPrintData
));
4293 mozilla::ipc::IPCResult
ContentParent::RecvConstructPopupBrowser(
4294 ManagedEndpoint
<PBrowserParent
>&& aBrowserEp
,
4295 ManagedEndpoint
<PWindowGlobalParent
>&& aWindowEp
, const TabId
& aTabId
,
4296 const IPCTabContext
& aContext
, const WindowGlobalInit
& aInitialWindowInit
,
4297 const uint32_t& aChromeFlags
) {
4298 MOZ_ASSERT(XRE_IsParentProcess());
4300 if (!CanOpenBrowser(aContext
)) {
4301 return IPC_FAIL(this, "CanOpenBrowser Failed");
4304 RefPtr
<CanonicalBrowsingContext
> browsingContext
=
4305 CanonicalBrowsingContext::Get(
4306 aInitialWindowInit
.context().mBrowsingContextId
);
4307 if (!browsingContext
|| browsingContext
->IsDiscarded()) {
4308 return IPC_FAIL(this, "Null or discarded initial BrowsingContext");
4310 if (!aInitialWindowInit
.principal()) {
4311 return IPC_FAIL(this, "Cannot create without valid initial principal");
4314 if (!ValidatePrincipal(aInitialWindowInit
.principal())) {
4315 LogAndAssertFailedPrincipalValidationInfo(aInitialWindowInit
.principal(),
4319 if (browsingContext
->GetBrowserParent()) {
4320 return IPC_FAIL(this, "BrowsingContext already has a BrowserParent");
4323 uint32_t chromeFlags
= aChromeFlags
;
4324 TabId
openerTabId(0);
4325 ContentParentId
openerCpId(0);
4326 if (aContext
.type() == IPCTabContext::TPopupIPCTabContext
) {
4327 // CanOpenBrowser has ensured that the IPCTabContext is of
4328 // type PopupIPCTabContext, and that the opener BrowserParent is
4330 const PopupIPCTabContext
& popupContext
= aContext
.get_PopupIPCTabContext();
4331 auto opener
= BrowserParent::GetFrom(popupContext
.opener().AsParent());
4332 openerTabId
= opener
->GetTabId();
4333 openerCpId
= opener
->Manager()->ChildID();
4335 // We must ensure that the private browsing and remoteness flags
4336 // match those of the opener.
4337 nsCOMPtr
<nsILoadContext
> loadContext
= opener
->GetLoadContext();
4339 return IPC_FAIL(this, "Missing Opener LoadContext");
4341 if (loadContext
->UsePrivateBrowsing()) {
4342 chromeFlags
|= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW
;
4344 if (loadContext
->UseRemoteSubframes()) {
4345 chromeFlags
|= nsIWebBrowserChrome::CHROME_FISSION_WINDOW
;
4349 // And because we're allocating a remote browser, of course the
4350 // window is remote.
4351 chromeFlags
|= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW
;
4353 if (NS_WARN_IF(!browsingContext
->IsOwnedByProcess(ChildID()))) {
4354 return IPC_FAIL(this, "BrowsingContext Owned by Incorrect Process!");
4357 MaybeInvalidTabContext
tc(aContext
);
4358 MOZ_ASSERT(tc
.IsValid());
4360 RefPtr
<WindowGlobalParent
> initialWindow
=
4361 WindowGlobalParent::CreateDisconnected(aInitialWindowInit
);
4362 if (!initialWindow
) {
4363 return IPC_FAIL(this, "Failed to create WindowGlobalParent");
4366 auto parent
= MakeRefPtr
<BrowserParent
>(this, aTabId
, tc
.GetTabContext(),
4367 browsingContext
, chromeFlags
);
4369 // Bind the created BrowserParent to IPC to actually link the actor.
4370 if (NS_WARN_IF(!BindPBrowserEndpoint(std::move(aBrowserEp
), parent
))) {
4371 return IPC_FAIL(this, "BindPBrowserEndpoint failed");
4374 // XXX: Why are we checking these requirements? It seems we should register
4375 // the created frame unconditionally?
4376 if (openerTabId
> 0) {
4377 // The creation of PBrowser was triggered from content process through
4379 // We need to register remote frame with the child generated tab id.
4380 auto* cpm
= ContentProcessManager::GetSingleton();
4381 if (!cpm
|| !cpm
->RegisterRemoteFrame(parent
)) {
4382 return IPC_FAIL(this, "RegisterRemoteFrame Failed");
4386 if (NS_WARN_IF(!parent
->BindPWindowGlobalEndpoint(std::move(aWindowEp
),
4388 return IPC_FAIL(this, "BindPWindowGlobalEndpoint failed");
4391 browsingContext
->SetCurrentBrowserParent(parent
);
4393 initialWindow
->Init();
4395 // When enabling input event prioritization, input events may preempt other
4396 // normal priority IPC messages. To prevent the input events preempt
4397 // PBrowserConstructor, we use an IPC 'RemoteIsReadyToHandleInputEvents' to
4398 // notify parent that BrowserChild is created. In this case, PBrowser is
4399 // initiated from content so that we can set BrowserParent as ready to handle
4401 parent
->SetReadyToHandleInputEvents();
4405 mozilla::PRemoteSpellcheckEngineParent
*
4406 ContentParent::AllocPRemoteSpellcheckEngineParent() {
4407 mozilla::RemoteSpellcheckEngineParent
* parent
=
4408 new mozilla::RemoteSpellcheckEngineParent();
4412 bool ContentParent::DeallocPRemoteSpellcheckEngineParent(
4413 PRemoteSpellcheckEngineParent
* parent
) {
4419 void ContentParent::SendShutdownTimerCallback(nsITimer
* aTimer
,
4421 auto* self
= static_cast<ContentParent
*>(aClosure
);
4422 self
->AsyncSendShutDownMessage();
4426 void ContentParent::ForceKillTimerCallback(nsITimer
* aTimer
, void* aClosure
) {
4427 // We don't want to time out the content process during XPCShell tests. This
4428 // is the easiest way to ensure that.
4429 if (PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR")) {
4433 auto* self
= static_cast<ContentParent
*>(aClosure
);
4434 self
->KillHard("ShutDownKill");
4437 void ContentParent::GeneratePairedMinidump(const char* aReason
) {
4438 // We're about to kill the child process associated with this content.
4439 // Something has gone wrong to get us here, so we generate a minidump
4440 // of the parent and child for submission to the crash server unless we're
4441 // already shutting down.
4442 if (mCrashReporter
&&
4443 !AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
) &&
4444 StaticPrefs::dom_ipc_tabs_createKillHardCrashReports_AtStartup()) {
4445 // GeneratePairedMinidump creates two minidumps for us - the main
4446 // one is for the content process we're about to kill, and the other
4447 // one is for the main browser process. That second one is the extra
4448 // minidump tagging along, so we have to tell the crash reporter that
4449 // it exists and is being appended.
4450 nsAutoCString
additionalDumps("browser");
4451 mCrashReporter
->AddAnnotation(
4452 CrashReporter::Annotation::additional_minidumps
, additionalDumps
);
4453 nsDependentCString
reason(aReason
);
4454 mCrashReporter
->AddAnnotation(CrashReporter::Annotation::ipc_channel_error
,
4457 // Generate the report and insert into the queue for submittal.
4458 if (mCrashReporter
->GenerateMinidumpAndPair(this, "browser"_ns
)) {
4459 mCrashReporter
->FinalizeCrashReport();
4460 mCreatedPairedMinidumps
= true;
4465 void ContentParent::HandleOrphanedMinidump(nsString
* aDumpId
) {
4466 if (CrashReporter::FinalizeOrphanedMinidump(
4467 OtherPid(), GeckoProcessType_Content
, aDumpId
)) {
4468 CrashReporterHost::RecordCrash(GeckoProcessType_Content
,
4469 nsICrashService::CRASH_TYPE_CRASH
, *aDumpId
);
4471 NS_WARNING(nsPrintfCString("content process pid = %" PRIPID
4472 " crashed without leaving a minidump behind",
4478 // WARNING: aReason appears in telemetry, so any new value passed in requires
4480 void ContentParent::KillHard(const char* aReason
) {
4481 AUTO_PROFILER_LABEL("ContentParent::KillHard", OTHER
);
4483 // On Windows, calling KillHard multiple times causes problems - the
4484 // process handle becomes invalid on the first call, causing a second call
4485 // to crash our process - more details in bug 890840.
4486 if (mCalledKillHard
) {
4489 mCalledKillHard
= true;
4490 if (mSendShutdownTimer
) {
4491 mSendShutdownTimer
->Cancel();
4492 mSendShutdownTimer
= nullptr;
4494 if (mForceKillTimer
) {
4495 mForceKillTimer
->Cancel();
4496 mForceKillTimer
= nullptr;
4499 RemoveShutdownBlockers();
4500 nsCString reason
= nsDependentCString(aReason
);
4502 // If we find mIsNotifiedShutdownSuccess there is no reason to blame this
4503 // content process, most probably our parent process is just slow in
4504 // processing its own main thread queue.
4505 if (!mIsNotifiedShutdownSuccess
) {
4506 GeneratePairedMinidump(aReason
);
4508 reason
= nsDependentCString("KillHard after IsNotifiedShutdownSuccess.");
4510 Telemetry::Accumulate(Telemetry::SUBPROCESS_KILL_HARD
, reason
, 1);
4512 ProcessHandle otherProcessHandle
;
4513 if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle
)) {
4514 NS_ERROR("Failed to open child process when attempting kill.");
4516 GetIPCChannel()->InduceConnectionError();
4521 if (!KillProcess(otherProcessHandle
, base::PROCESS_END_KILLED_BY_USER
)) {
4522 if (mCrashReporter
) {
4523 mCrashReporter
->DeleteCrashReport();
4525 NS_WARNING("failed to kill subprocess!");
4530 ContentParent::GetLog(), LogLevel::Verbose
,
4531 ("KillHard Subprocess(%s): ContentParent %p mSubprocess %p handle "
4533 aReason
, this, mSubprocess
,
4534 mSubprocess
? (uintptr_t)mSubprocess
->GetChildProcessHandle() : -1));
4535 mSubprocess
->SetAlreadyDead();
4538 // After we've killed the remote process, also ensure we induce a connection
4539 // error in the IPC channel to immediately stop all IPC communication on this
4542 GetIPCChannel()->InduceConnectionError();
4545 // EnsureProcessTerminated has responsibilty for closing otherProcessHandle.
4546 XRE_GetIOMessageLoop()->PostTask(
4547 NewRunnableFunction("EnsureProcessTerminatedRunnable",
4548 &ProcessWatcher::EnsureProcessTerminated
,
4549 otherProcessHandle
, /*force=*/true));
4552 void ContentParent::FriendlyName(nsAString
& aName
, bool aAnonymize
) {
4554 if (mIsForBrowser
) {
4555 aName
.AssignLiteral("Browser");
4556 } else if (aAnonymize
) {
4557 aName
.AssignLiteral("<anonymized-name>");
4559 aName
.AssignLiteral("???");
4563 mozilla::ipc::IPCResult
ContentParent::RecvInitCrashReporter(
4564 const NativeThreadId
& aThreadId
) {
4566 MakeUnique
<CrashReporterHost
>(GeckoProcessType_Content
, aThreadId
);
4571 hal_sandbox::PHalParent
* ContentParent::AllocPHalParent() {
4572 return hal_sandbox::CreateHalParent();
4575 bool ContentParent::DeallocPHalParent(hal_sandbox::PHalParent
* aHal
) {
4580 devtools::PHeapSnapshotTempFileHelperParent
*
4581 ContentParent::AllocPHeapSnapshotTempFileHelperParent() {
4582 return devtools::HeapSnapshotTempFileHelperParent::Create();
4585 bool ContentParent::DeallocPHeapSnapshotTempFileHelperParent(
4586 devtools::PHeapSnapshotTempFileHelperParent
* aHeapSnapshotHelper
) {
4587 delete aHeapSnapshotHelper
;
4591 bool ContentParent::SendRequestMemoryReport(
4592 const uint32_t& aGeneration
, const bool& aAnonymize
,
4593 const bool& aMinimizeMemoryUsage
, const Maybe
<FileDescriptor
>& aDMDFile
) {
4594 // This automatically cancels the previous request.
4595 mMemoryReportRequest
= MakeUnique
<MemoryReportRequestHost
>(aGeneration
);
4596 // If we run the callback in response to a reply, then by definition |this|
4597 // is still alive, so the ref pointer is redundant, but it seems easier
4598 // to hold a strong reference than to worry about that.
4599 RefPtr
<ContentParent
> self(this);
4600 PContentParent::SendRequestMemoryReport(
4601 aGeneration
, aAnonymize
, aMinimizeMemoryUsage
, aDMDFile
,
4602 [&, self
](const uint32_t& aGeneration2
) {
4603 if (self
->mMemoryReportRequest
) {
4604 self
->mMemoryReportRequest
->Finish(aGeneration2
);
4605 self
->mMemoryReportRequest
= nullptr;
4608 [&, self
](mozilla::ipc::ResponseRejectReason
) {
4609 self
->mMemoryReportRequest
= nullptr;
4614 mozilla::ipc::IPCResult
ContentParent::RecvAddMemoryReport(
4615 const MemoryReport
& aReport
) {
4616 if (mMemoryReportRequest
) {
4617 mMemoryReportRequest
->RecvReport(aReport
);
4622 PCycleCollectWithLogsParent
* ContentParent::AllocPCycleCollectWithLogsParent(
4623 const bool& aDumpAllTraces
, const FileDescriptor
& aGCLog
,
4624 const FileDescriptor
& aCCLog
) {
4625 MOZ_CRASH("Don't call this; use ContentParent::CycleCollectWithLogs");
4628 bool ContentParent::DeallocPCycleCollectWithLogsParent(
4629 PCycleCollectWithLogsParent
* aActor
) {
4634 bool ContentParent::CycleCollectWithLogs(
4635 bool aDumpAllTraces
, nsICycleCollectorLogSink
* aSink
,
4636 nsIDumpGCAndCCLogsCallback
* aCallback
) {
4637 return CycleCollectWithLogsParent::AllocAndSendConstructor(
4638 this, aDumpAllTraces
, aSink
, aCallback
);
4641 PTestShellParent
* ContentParent::AllocPTestShellParent() {
4642 return new TestShellParent();
4645 bool ContentParent::DeallocPTestShellParent(PTestShellParent
* shell
) {
4650 PScriptCacheParent
* ContentParent::AllocPScriptCacheParent(
4651 const FileDescOrError
& cacheFile
, const bool& wantCacheData
) {
4652 return new loader::ScriptCacheParent(wantCacheData
);
4655 bool ContentParent::DeallocPScriptCacheParent(PScriptCacheParent
* cache
) {
4656 delete static_cast<loader::ScriptCacheParent
*>(cache
);
4660 already_AddRefed
<PNeckoParent
> ContentParent::AllocPNeckoParent() {
4661 RefPtr
<NeckoParent
> actor
= new NeckoParent();
4662 return actor
.forget();
4665 mozilla::ipc::IPCResult
ContentParent::RecvInitStreamFilter(
4666 const uint64_t& aChannelId
, const nsAString
& aAddonId
,
4667 InitStreamFilterResolver
&& aResolver
) {
4668 extensions::StreamFilterParent::Create(this, aChannelId
, aAddonId
)
4670 GetCurrentSerialEventTarget(), __func__
,
4671 [aResolver
](mozilla::ipc::Endpoint
<PStreamFilterChild
>&& aEndpoint
) {
4672 aResolver(std::move(aEndpoint
));
4674 [aResolver
](bool aDummy
) {
4675 aResolver(mozilla::ipc::Endpoint
<PStreamFilterChild
>());
4681 mozilla::ipc::IPCResult
ContentParent::RecvAddSecurityState(
4682 const MaybeDiscarded
<WindowContext
>& aContext
, uint32_t aStateFlags
) {
4683 if (aContext
.IsNullOrDiscarded()) {
4687 aContext
.get()->AddSecurityState(aStateFlags
);
4691 already_AddRefed
<PExternalHelperAppParent
>
4692 ContentParent::AllocPExternalHelperAppParent(
4693 nsIURI
* uri
, const mozilla::net::LoadInfoArgs
& aLoadInfoArgs
,
4694 const nsACString
& aMimeContentType
, const nsACString
& aContentDisposition
,
4695 const uint32_t& aContentDispositionHint
,
4696 const nsAString
& aContentDispositionFilename
, const bool& aForceSave
,
4697 const int64_t& aContentLength
, const bool& aWasFileChannel
,
4698 nsIURI
* aReferrer
, const MaybeDiscarded
<BrowsingContext
>& aContext
,
4699 const bool& aShouldCloseWindow
) {
4700 RefPtr
<ExternalHelperAppParent
> parent
= new ExternalHelperAppParent(
4701 uri
, aContentLength
, aWasFileChannel
, aContentDisposition
,
4702 aContentDispositionHint
, aContentDispositionFilename
);
4703 return parent
.forget();
4706 mozilla::ipc::IPCResult
ContentParent::RecvPExternalHelperAppConstructor(
4707 PExternalHelperAppParent
* actor
, nsIURI
* uri
,
4708 const LoadInfoArgs
& loadInfoArgs
, const nsACString
& aMimeContentType
,
4709 const nsACString
& aContentDisposition
,
4710 const uint32_t& aContentDispositionHint
,
4711 const nsAString
& aContentDispositionFilename
, const bool& aForceSave
,
4712 const int64_t& aContentLength
, const bool& aWasFileChannel
,
4713 nsIURI
* aReferrer
, const MaybeDiscarded
<BrowsingContext
>& aContext
,
4714 const bool& aShouldCloseWindow
) {
4715 BrowsingContext
* context
= aContext
.IsDiscarded() ? nullptr : aContext
.get();
4716 if (!static_cast<ExternalHelperAppParent
*>(actor
)->Init(
4717 loadInfoArgs
, aMimeContentType
, aForceSave
, aReferrer
, context
,
4718 aShouldCloseWindow
)) {
4719 return IPC_FAIL(this, "Init failed.");
4724 already_AddRefed
<PHandlerServiceParent
>
4725 ContentParent::AllocPHandlerServiceParent() {
4726 RefPtr
<HandlerServiceParent
> actor
= new HandlerServiceParent();
4727 return actor
.forget();
4730 media::PMediaParent
* ContentParent::AllocPMediaParent() {
4731 return media::AllocPMediaParent();
4734 bool ContentParent::DeallocPMediaParent(media::PMediaParent
* aActor
) {
4735 return media::DeallocPMediaParent(aActor
);
4738 PBenchmarkStorageParent
* ContentParent::AllocPBenchmarkStorageParent() {
4739 return new BenchmarkStorageParent
;
4742 bool ContentParent::DeallocPBenchmarkStorageParent(
4743 PBenchmarkStorageParent
* aActor
) {
4748 #ifdef MOZ_WEBSPEECH
4749 PSpeechSynthesisParent
* ContentParent::AllocPSpeechSynthesisParent() {
4750 if (!StaticPrefs::media_webspeech_synth_enabled()) {
4753 return new mozilla::dom::SpeechSynthesisParent();
4756 bool ContentParent::DeallocPSpeechSynthesisParent(
4757 PSpeechSynthesisParent
* aActor
) {
4762 mozilla::ipc::IPCResult
ContentParent::RecvPSpeechSynthesisConstructor(
4763 PSpeechSynthesisParent
* aActor
) {
4764 if (!static_cast<SpeechSynthesisParent
*>(aActor
)->SendInit()) {
4765 return IPC_FAIL(this, "SpeechSynthesisParent::SendInit failed.");
4771 mozilla::ipc::IPCResult
ContentParent::RecvStartVisitedQueries(
4772 const nsTArray
<RefPtr
<nsIURI
>>& aUris
) {
4773 nsCOMPtr
<IHistory
> history
= components::History::Service();
4777 for (const auto& uri
: aUris
) {
4778 if (NS_WARN_IF(!uri
)) {
4781 history
->ScheduleVisitedQuery(uri
, this);
4786 mozilla::ipc::IPCResult
ContentParent::RecvSetURITitle(nsIURI
* uri
,
4787 const nsAString
& title
) {
4789 return IPC_FAIL(this, "uri must not be null.");
4791 nsCOMPtr
<IHistory
> history
= components::History::Service();
4793 history
->SetURITitle(uri
, title
);
4798 mozilla::ipc::IPCResult
ContentParent::RecvIsSecureURI(
4799 nsIURI
* aURI
, const OriginAttributes
& aOriginAttributes
,
4800 bool* aIsSecureURI
) {
4801 nsCOMPtr
<nsISiteSecurityService
> sss(do_GetService(NS_SSSERVICE_CONTRACTID
));
4803 return IPC_FAIL(this, "Failed to get nsISiteSecurityService.");
4806 return IPC_FAIL(this, "aURI must not be null.");
4808 nsresult rv
= sss
->IsSecureURI(aURI
, aOriginAttributes
, aIsSecureURI
);
4809 if (NS_FAILED(rv
)) {
4810 return IPC_FAIL(this, "IsSecureURI failed.");
4815 mozilla::ipc::IPCResult
ContentParent::RecvAccumulateMixedContentHSTS(
4816 nsIURI
* aURI
, const bool& aActive
,
4817 const OriginAttributes
& aOriginAttributes
) {
4819 return IPC_FAIL(this, "aURI must not be null.");
4821 nsMixedContentBlocker::AccumulateMixedContentHSTS(aURI
, aActive
,
4826 mozilla::ipc::IPCResult
ContentParent::RecvLoadURIExternal(
4827 nsIURI
* uri
, nsIPrincipal
* aTriggeringPrincipal
,
4828 nsIPrincipal
* aRedirectPrincipal
,
4829 const MaybeDiscarded
<BrowsingContext
>& aContext
,
4830 bool aWasExternallyTriggered
, bool aHasValidUserGestureActivation
) {
4831 if (aContext
.IsDiscarded()) {
4835 nsCOMPtr
<nsIExternalProtocolService
> extProtService(
4836 do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID
));
4837 if (!extProtService
) {
4842 return IPC_FAIL(this, "uri must not be null.");
4845 BrowsingContext
* bc
= aContext
.get();
4846 extProtService
->LoadURI(uri
, aTriggeringPrincipal
, aRedirectPrincipal
, bc
,
4847 aWasExternallyTriggered
,
4848 aHasValidUserGestureActivation
);
4852 mozilla::ipc::IPCResult
ContentParent::RecvExtProtocolChannelConnectParent(
4853 const uint64_t& registrarId
) {
4856 // First get the real channel created before redirect on the parent.
4857 nsCOMPtr
<nsIChannel
> channel
;
4858 rv
= NS_LinkRedirectChannels(registrarId
, nullptr, getter_AddRefs(channel
));
4859 NS_ENSURE_SUCCESS(rv
, IPC_OK());
4861 nsCOMPtr
<nsIParentChannel
> parent
= do_QueryInterface(channel
, &rv
);
4862 NS_ENSURE_SUCCESS(rv
, IPC_OK());
4864 // The channel itself is its own (faked) parent, link it.
4865 rv
= NS_LinkRedirectChannels(registrarId
, parent
, getter_AddRefs(channel
));
4866 NS_ENSURE_SUCCESS(rv
, IPC_OK());
4868 // Signal the parent channel that it's a redirect-to parent. This will
4869 // make AsyncOpen on it do nothing (what we want).
4870 // Yes, this is a bit of a hack, but I don't think it's necessary to invent
4871 // a new interface just to set this flag on the channel.
4872 parent
->SetParentListener(nullptr);
4877 mozilla::ipc::IPCResult
ContentParent::RecvShowAlert(
4878 nsIAlertNotification
* aAlert
) {
4880 return IPC_FAIL(this, "aAlert must not be null.");
4882 nsCOMPtr
<nsIAlertsService
> sysAlerts(components::Alerts::Service());
4884 sysAlerts
->ShowAlert(aAlert
, this);
4889 mozilla::ipc::IPCResult
ContentParent::RecvCloseAlert(const nsAString
& aName
,
4890 bool aContextClosed
) {
4891 nsCOMPtr
<nsIAlertsService
> sysAlerts(components::Alerts::Service());
4893 sysAlerts
->CloseAlert(aName
, aContextClosed
);
4899 mozilla::ipc::IPCResult
ContentParent::RecvDisableNotifications(
4900 nsIPrincipal
* aPrincipal
) {
4902 return IPC_FAIL(this, "No principal");
4905 if (!ValidatePrincipal(aPrincipal
)) {
4906 LogAndAssertFailedPrincipalValidationInfo(aPrincipal
, __func__
);
4908 Unused
<< Notification::RemovePermission(aPrincipal
);
4912 mozilla::ipc::IPCResult
ContentParent::RecvOpenNotificationSettings(
4913 nsIPrincipal
* aPrincipal
) {
4915 return IPC_FAIL(this, "No principal");
4918 if (!ValidatePrincipal(aPrincipal
)) {
4919 LogAndAssertFailedPrincipalValidationInfo(aPrincipal
, __func__
);
4921 Unused
<< Notification::OpenSettings(aPrincipal
);
4925 mozilla::ipc::IPCResult
ContentParent::RecvNotificationEvent(
4926 const nsAString
& aType
, const NotificationEventData
& aData
) {
4927 nsCOMPtr
<nsIServiceWorkerManager
> swm
=
4928 mozilla::components::ServiceWorkerManager::Service();
4929 if (NS_WARN_IF(!swm
)) {
4930 // Probably shouldn't happen, but no need to crash the child process.
4934 if (aType
.EqualsLiteral("click")) {
4935 nsresult rv
= swm
->SendNotificationClickEvent(
4936 aData
.originSuffix(), aData
.scope(), aData
.ID(), aData
.title(),
4937 aData
.dir(), aData
.lang(), aData
.body(), aData
.tag(), aData
.icon(),
4938 aData
.data(), aData
.behavior());
4939 Unused
<< NS_WARN_IF(NS_FAILED(rv
));
4941 MOZ_ASSERT(aType
.EqualsLiteral("close"));
4942 nsresult rv
= swm
->SendNotificationCloseEvent(
4943 aData
.originSuffix(), aData
.scope(), aData
.ID(), aData
.title(),
4944 aData
.dir(), aData
.lang(), aData
.body(), aData
.tag(), aData
.icon(),
4945 aData
.data(), aData
.behavior());
4946 Unused
<< NS_WARN_IF(NS_FAILED(rv
));
4952 mozilla::ipc::IPCResult
ContentParent::RecvSyncMessage(
4953 const nsAString
& aMsg
, const ClonedMessageData
& aData
,
4954 nsTArray
<StructuredCloneData
>* aRetvals
) {
4955 AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("ContentParent::RecvSyncMessage",
4957 MMPrinter::Print("ContentParent::RecvSyncMessage", aMsg
, aData
);
4959 RefPtr
<nsFrameMessageManager
> ppm
= mMessageManager
;
4961 ipc::StructuredCloneData data
;
4962 ipc::UnpackClonedMessageData(aData
, data
);
4964 ppm
->ReceiveMessage(ppm
, nullptr, aMsg
, true, &data
, aRetvals
,
4970 mozilla::ipc::IPCResult
ContentParent::RecvAsyncMessage(
4971 const nsAString
& aMsg
, const ClonedMessageData
& aData
) {
4972 AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("ContentParent::RecvAsyncMessage",
4974 MMPrinter::Print("ContentParent::RecvAsyncMessage", aMsg
, aData
);
4976 RefPtr
<nsFrameMessageManager
> ppm
= mMessageManager
;
4978 ipc::StructuredCloneData data
;
4979 ipc::UnpackClonedMessageData(aData
, data
);
4981 ppm
->ReceiveMessage(ppm
, nullptr, aMsg
, false, &data
, nullptr,
4988 static int32_t AddGeolocationListener(
4989 nsIDOMGeoPositionCallback
* watcher
,
4990 nsIDOMGeoPositionErrorCallback
* errorCallBack
, bool highAccuracy
) {
4991 RefPtr
<Geolocation
> geo
= Geolocation::NonWindowSingleton();
4993 UniquePtr
<PositionOptions
> options
= MakeUnique
<PositionOptions
>();
4994 options
->mTimeout
= 0;
4995 options
->mMaximumAge
= 0;
4996 options
->mEnableHighAccuracy
= highAccuracy
;
4997 return geo
->WatchPosition(watcher
, errorCallBack
, std::move(options
));
5000 mozilla::ipc::IPCResult
ContentParent::RecvAddGeolocationListener(
5001 const bool& aHighAccuracy
) {
5002 // To ensure no geolocation updates are skipped, we always force the
5003 // creation of a new listener.
5004 RecvRemoveGeolocationListener();
5005 mGeolocationWatchID
= AddGeolocationListener(this, this, aHighAccuracy
);
5009 mozilla::ipc::IPCResult
ContentParent::RecvRemoveGeolocationListener() {
5010 if (mGeolocationWatchID
!= -1) {
5011 RefPtr
<Geolocation
> geo
= Geolocation::NonWindowSingleton();
5013 geo
->ClearWatch(mGeolocationWatchID
);
5015 mGeolocationWatchID
= -1;
5020 mozilla::ipc::IPCResult
ContentParent::RecvSetGeolocationHigherAccuracy(
5021 const bool& aEnable
) {
5022 // This should never be called without a listener already present,
5023 // so this check allows us to forgo securing privileges.
5024 if (mGeolocationWatchID
!= -1) {
5025 RecvRemoveGeolocationListener();
5026 mGeolocationWatchID
= AddGeolocationListener(this, this, aEnable
);
5032 ContentParent::HandleEvent(nsIDOMGeoPosition
* postion
) {
5033 Unused
<< SendGeolocationUpdate(postion
);
5038 ContentParent::HandleEvent(GeolocationPositionError
* positionError
) {
5039 Unused
<< SendGeolocationError(positionError
->Code());
5043 mozilla::ipc::IPCResult
ContentParent::RecvConsoleMessage(
5044 const nsAString
& aMessage
) {
5046 nsCOMPtr
<nsIConsoleService
> consoleService
=
5047 do_GetService(NS_CONSOLESERVICE_CONTRACTID
, &rv
);
5048 if (NS_SUCCEEDED(rv
)) {
5049 RefPtr
<nsConsoleMessage
> msg(new nsConsoleMessage(aMessage
));
5050 msg
->SetIsForwardedFromContentProcess(true);
5051 consoleService
->LogMessageWithMode(msg
, nsIConsoleService::SuppressLog
);
5056 mozilla::ipc::IPCResult
ContentParent::RecvReportFrameTimingData(
5057 const LoadInfoArgs
& loadInfoArgs
, const nsAString
& entryName
,
5058 const nsAString
& initiatorType
, UniquePtr
<PerformanceTimingData
>&& aData
) {
5060 return IPC_FAIL(this, "aData should not be null");
5063 RefPtr
<WindowGlobalParent
> parent
=
5064 WindowGlobalParent::GetByInnerWindowId(loadInfoArgs
.innerWindowID());
5065 if (!parent
|| !parent
->GetContentParent()) {
5069 MOZ_ASSERT(parent
->GetContentParent() != this,
5070 "No need to bounce around if in the same process");
5072 Unused
<< parent
->GetContentParent()->SendReportFrameTimingData(
5073 loadInfoArgs
, entryName
, initiatorType
, std::move(aData
));
5077 mozilla::ipc::IPCResult
ContentParent::RecvScriptError(
5078 const nsAString
& aMessage
, const nsAString
& aSourceName
,
5079 const nsAString
& aSourceLine
, const uint32_t& aLineNumber
,
5080 const uint32_t& aColNumber
, const uint32_t& aFlags
,
5081 const nsACString
& aCategory
, const bool& aFromPrivateWindow
,
5082 const uint64_t& aInnerWindowId
, const bool& aFromChromeContext
) {
5083 return RecvScriptErrorInternal(aMessage
, aSourceName
, aSourceLine
,
5084 aLineNumber
, aColNumber
, aFlags
, aCategory
,
5085 aFromPrivateWindow
, aFromChromeContext
);
5088 mozilla::ipc::IPCResult
ContentParent::RecvScriptErrorWithStack(
5089 const nsAString
& aMessage
, const nsAString
& aSourceName
,
5090 const nsAString
& aSourceLine
, const uint32_t& aLineNumber
,
5091 const uint32_t& aColNumber
, const uint32_t& aFlags
,
5092 const nsACString
& aCategory
, const bool& aFromPrivateWindow
,
5093 const bool& aFromChromeContext
, const ClonedMessageData
& aFrame
) {
5094 return RecvScriptErrorInternal(
5095 aMessage
, aSourceName
, aSourceLine
, aLineNumber
, aColNumber
, aFlags
,
5096 aCategory
, aFromPrivateWindow
, aFromChromeContext
, &aFrame
);
5099 mozilla::ipc::IPCResult
ContentParent::RecvScriptErrorInternal(
5100 const nsAString
& aMessage
, const nsAString
& aSourceName
,
5101 const nsAString
& aSourceLine
, const uint32_t& aLineNumber
,
5102 const uint32_t& aColNumber
, const uint32_t& aFlags
,
5103 const nsACString
& aCategory
, const bool& aFromPrivateWindow
,
5104 const bool& aFromChromeContext
, const ClonedMessageData
* aStack
) {
5106 nsCOMPtr
<nsIConsoleService
> consoleService
=
5107 do_GetService(NS_CONSOLESERVICE_CONTRACTID
, &rv
);
5108 if (NS_FAILED(rv
)) {
5112 nsCOMPtr
<nsIScriptError
> msg
;
5115 StructuredCloneData data
;
5116 UnpackClonedMessageData(*aStack
, data
);
5119 if (NS_WARN_IF(!jsapi
.Init(xpc::PrivilegedJunkScope()))) {
5122 JSContext
* cx
= jsapi
.cx();
5124 JS::Rooted
<JS::Value
> stack(cx
);
5126 data
.Read(cx
, &stack
, rv
);
5127 if (rv
.Failed() || !stack
.isObject()) {
5128 rv
.SuppressException();
5132 JS::Rooted
<JSObject
*> stackObj(cx
, &stack
.toObject());
5133 MOZ_ASSERT(JS::IsUnwrappedSavedFrame(stackObj
));
5135 JS::Rooted
<JSObject
*> stackGlobal(cx
, JS::GetNonCCWObjectGlobal(stackObj
));
5136 msg
= new nsScriptErrorWithStack(JS::NothingHandleValue
, stackObj
,
5139 msg
= new nsScriptError();
5142 rv
= msg
->Init(aMessage
, aSourceName
, aSourceLine
, aLineNumber
, aColNumber
,
5143 aFlags
, aCategory
, aFromPrivateWindow
, aFromChromeContext
);
5144 if (NS_FAILED(rv
)) return IPC_OK();
5146 msg
->SetIsForwardedFromContentProcess(true);
5148 consoleService
->LogMessageWithMode(msg
, nsIConsoleService::SuppressLog
);
5152 bool ContentParent::DoLoadMessageManagerScript(const nsAString
& aURL
,
5153 bool aRunInGlobalScope
) {
5154 MOZ_ASSERT(!aRunInGlobalScope
);
5155 return SendLoadProcessScript(aURL
);
5158 nsresult
ContentParent::DoSendAsyncMessage(const nsAString
& aMessage
,
5159 StructuredCloneData
& aHelper
) {
5160 ClonedMessageData data
;
5161 if (!BuildClonedMessageData(aHelper
, data
)) {
5162 return NS_ERROR_DOM_DATA_CLONE_ERR
;
5164 if (!SendAsyncMessage(aMessage
, data
)) {
5165 return NS_ERROR_UNEXPECTED
;
5170 mozilla::ipc::IPCResult
ContentParent::RecvCopyFavicon(
5171 nsIURI
* aOldURI
, nsIURI
* aNewURI
, const bool& aInPrivateBrowsing
) {
5173 return IPC_FAIL(this, "aOldURI should not be null");
5176 return IPC_FAIL(this, "aNewURI should not be null");
5179 nsDocShell::CopyFavicon(aOldURI
, aNewURI
, aInPrivateBrowsing
);
5183 mozilla::ipc::IPCResult
ContentParent::RecvFindImageText(
5184 IPCImage
&& aImage
, nsTArray
<nsCString
>&& aLanguages
,
5185 FindImageTextResolver
&& aResolver
) {
5186 if (!TextRecognition::IsSupported() ||
5187 !Preferences::GetBool("dom.text-recognition.enabled")) {
5188 return IPC_FAIL(this, "Text recognition not available.");
5191 RefPtr
<DataSourceSurface
> surf
=
5192 nsContentUtils::IPCImageToSurface(std::move(aImage
));
5194 aResolver(TextRecognitionResultOrError("Failed to read image"_ns
));
5197 TextRecognition::FindText(*surf
, aLanguages
)
5199 GetCurrentSerialEventTarget(), __func__
,
5200 [resolver
= std::move(aResolver
)](
5201 TextRecognition::NativePromise::ResolveOrRejectValue
&& aValue
) {
5202 if (aValue
.IsResolve()) {
5203 resolver(TextRecognitionResultOrError(aValue
.ResolveValue()));
5205 resolver(TextRecognitionResultOrError(aValue
.RejectValue()));
5211 bool ContentParent::ShouldContinueFromReplyTimeout() {
5212 RefPtr
<ProcessHangMonitor
> monitor
= ProcessHangMonitor::Get();
5213 return !monitor
|| !monitor
->ShouldTimeOutCPOWs();
5216 mozilla::ipc::IPCResult
ContentParent::RecvAddIdleObserver(
5217 const uint64_t& aObserver
, const uint32_t& aIdleTimeInS
) {
5219 nsCOMPtr
<nsIUserIdleService
> idleService
=
5220 do_GetService("@mozilla.org/widget/useridleservice;1", &rv
);
5221 NS_ENSURE_SUCCESS(rv
, IPC_FAIL(this, "Failed to get UserIdleService."));
5223 RefPtr
<ParentIdleListener
> listener
=
5224 new ParentIdleListener(this, aObserver
, aIdleTimeInS
);
5225 rv
= idleService
->AddIdleObserver(listener
, aIdleTimeInS
);
5226 NS_ENSURE_SUCCESS(rv
, IPC_FAIL(this, "AddIdleObserver failed."));
5227 mIdleListeners
.AppendElement(listener
);
5231 mozilla::ipc::IPCResult
ContentParent::RecvRemoveIdleObserver(
5232 const uint64_t& aObserver
, const uint32_t& aIdleTimeInS
) {
5233 RefPtr
<ParentIdleListener
> listener
;
5234 for (int32_t i
= mIdleListeners
.Length() - 1; i
>= 0; --i
) {
5235 listener
= static_cast<ParentIdleListener
*>(mIdleListeners
[i
].get());
5236 if (listener
->mObserver
== aObserver
&& listener
->mTime
== aIdleTimeInS
) {
5238 nsCOMPtr
<nsIUserIdleService
> idleService
=
5239 do_GetService("@mozilla.org/widget/useridleservice;1", &rv
);
5240 NS_ENSURE_SUCCESS(rv
, IPC_FAIL(this, "Failed to get UserIdleService."));
5241 idleService
->RemoveIdleObserver(listener
, aIdleTimeInS
);
5242 mIdleListeners
.RemoveElementAt(i
);
5249 mozilla::ipc::IPCResult
ContentParent::RecvBackUpXResources(
5250 const FileDescriptor
& aXSocketFd
) {
5252 MOZ_CRASH("This message only makes sense on X11 platforms");
5254 MOZ_ASSERT(0 > mChildXSocketFdDup
.get(), "Already backed up X resources??");
5255 if (aXSocketFd
.IsValid()) {
5256 auto rawFD
= aXSocketFd
.ClonePlatformHandle();
5257 mChildXSocketFdDup
.reset(rawFD
.release());
5263 class AnonymousTemporaryFileRequestor final
: public Runnable
{
5265 AnonymousTemporaryFileRequestor(ContentParent
* aCP
, const uint64_t& aID
)
5266 : Runnable("dom::AnonymousTemporaryFileRequestor"),
5272 NS_IMETHOD
Run() override
{
5273 if (NS_IsMainThread()) {
5274 FileDescOrError result
;
5275 if (NS_WARN_IF(NS_FAILED(mRv
))) {
5276 // Returning false will kill the child process; instead
5277 // propagate the error and let the child handle it.
5280 result
= FileDescriptor(FileDescriptor::PlatformHandleType(
5281 PR_FileDesc2NativeHandle(mPRFD
)));
5282 // The FileDescriptor object owns a duplicate of the file handle; we
5283 // must close the original (and clean up the NSPR descriptor).
5286 Unused
<< mCP
->SendProvideAnonymousTemporaryFile(mID
, result
);
5287 // It's important to release this reference while wr're on the main
5291 mRv
= NS_OpenAnonymousTemporaryFile(&mPRFD
);
5292 NS_DispatchToMainThread(this);
5298 RefPtr
<ContentParent
> mCP
;
5304 mozilla::ipc::IPCResult
ContentParent::RecvRequestAnonymousTemporaryFile(
5305 const uint64_t& aID
) {
5306 // Make sure to send a callback to the child if we bail out early.
5307 nsresult rv
= NS_OK
;
5308 RefPtr
<ContentParent
> self(this);
5309 auto autoNotifyChildOnError
= MakeScopeExit([&, self
]() {
5310 if (NS_FAILED(rv
)) {
5311 FileDescOrError
result(rv
);
5312 Unused
<< self
->SendProvideAnonymousTemporaryFile(aID
, result
);
5316 // We use a helper runnable to open the anonymous temporary file on the IO
5317 // thread. The same runnable will call us back on the main thread when the
5318 // file has been opened.
5319 nsCOMPtr
<nsIEventTarget
> target
=
5320 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
, &rv
);
5325 rv
= target
->Dispatch(new AnonymousTemporaryFileRequestor(this, aID
),
5326 NS_DISPATCH_NORMAL
);
5327 if (NS_WARN_IF(NS_FAILED(rv
))) {
5335 mozilla::ipc::IPCResult
ContentParent::RecvCreateAudioIPCConnection(
5336 CreateAudioIPCConnectionResolver
&& aResolver
) {
5337 FileDescriptor fd
= CubebUtils::CreateAudioIPCConnection();
5338 FileDescOrError result
;
5342 result
= NS_ERROR_FAILURE
;
5344 aResolver(std::move(result
));
5348 already_AddRefed
<extensions::PExtensionsParent
>
5349 ContentParent::AllocPExtensionsParent() {
5350 return MakeAndAddRef
<extensions::ExtensionsParent
>();
5353 void ContentParent::NotifyUpdatedDictionaries() {
5354 RefPtr
<mozSpellChecker
> spellChecker(mozSpellChecker::Create());
5355 MOZ_ASSERT(spellChecker
, "No spell checker?");
5357 nsTArray
<nsCString
> dictionaries
;
5358 spellChecker
->GetDictionaryList(&dictionaries
);
5360 for (auto* cp
: AllProcesses(eLive
)) {
5361 Unused
<< cp
->SendUpdateDictionaryList(dictionaries
);
5365 void ContentParent::NotifyUpdatedFonts(bool aFullRebuild
) {
5366 if (gfxPlatformFontList::PlatformFontList()->SharedFontList()) {
5367 for (auto* cp
: AllProcesses(eLive
)) {
5368 Unused
<< cp
->SendRebuildFontList(aFullRebuild
);
5373 SystemFontList fontList
;
5374 gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList
);
5376 for (auto* cp
: AllProcesses(eLive
)) {
5377 Unused
<< cp
->SendUpdateFontList(fontList
);
5382 PWebrtcGlobalParent
* ContentParent::AllocPWebrtcGlobalParent() {
5383 return WebrtcGlobalParent::Alloc();
5386 bool ContentParent::DeallocPWebrtcGlobalParent(PWebrtcGlobalParent
* aActor
) {
5387 WebrtcGlobalParent::Dealloc(static_cast<WebrtcGlobalParent
*>(aActor
));
5392 void ContentParent::MaybeInvokeDragSession(BrowserParent
* aParent
) {
5393 // dnd uses IPCBlob to transfer data to the content process and the IPC
5394 // message is sent as normal priority. When sending input events with input
5395 // priority, the message may be preempted by the later dnd events. To make
5396 // sure the input events and the blob message are processed in time order
5397 // on the content process, we temporarily send the input events with normal
5398 // priority when there is an active dnd session.
5399 SetInputPriorityEventEnabled(false);
5401 nsCOMPtr
<nsIDragService
> dragService
=
5402 do_GetService("@mozilla.org/widget/dragservice;1");
5403 if (dragService
&& dragService
->MaybeAddChildProcess(this)) {
5404 // We need to send transferable data to child process.
5405 nsCOMPtr
<nsIDragSession
> session
;
5406 dragService
->GetCurrentSession(getter_AddRefs(session
));
5408 nsTArray
<IPCTransferableData
> ipcTransferables
;
5409 RefPtr
<DataTransfer
> transfer
= session
->GetDataTransfer();
5411 // Pass eDrop to get DataTransfer with external
5412 // drag formats cached.
5413 transfer
= new DataTransfer(nullptr, eDrop
, true, -1);
5414 session
->SetDataTransfer(transfer
);
5416 // Note, even though this fills the DataTransfer object with
5417 // external data, the data is usually transfered over IPC lazily when
5419 transfer
->FillAllExternalData();
5420 nsCOMPtr
<nsILoadContext
> lc
=
5421 aParent
? aParent
->GetLoadContext() : nullptr;
5422 nsCOMPtr
<nsIArray
> transferables
= transfer
->GetTransferables(lc
);
5423 nsContentUtils::TransferablesToIPCTransferableDatas(
5424 transferables
, ipcTransferables
, false, this);
5426 session
->GetDragAction(&action
);
5428 RefPtr
<WindowContext
> sourceWC
;
5429 session
->GetSourceWindowContext(getter_AddRefs(sourceWC
));
5430 RefPtr
<WindowContext
> sourceTopWC
;
5431 session
->GetSourceTopWindowContext(getter_AddRefs(sourceTopWC
));
5432 mozilla::Unused
<< SendInvokeDragSession(
5433 sourceWC
, sourceTopWC
, std::move(ipcTransferables
), action
);
5438 mozilla::ipc::IPCResult
ContentParent::RecvUpdateDropEffect(
5439 const uint32_t& aDragAction
, const uint32_t& aDropEffect
) {
5440 nsCOMPtr
<nsIDragSession
> dragSession
= nsContentUtils::GetDragSession();
5442 dragSession
->SetDragAction(aDragAction
);
5443 RefPtr
<DataTransfer
> dt
= dragSession
->GetDataTransfer();
5445 dt
->SetDropEffectInt(aDropEffect
);
5447 dragSession
->UpdateDragEffect();
5452 PContentPermissionRequestParent
*
5453 ContentParent::AllocPContentPermissionRequestParent(
5454 const nsTArray
<PermissionRequest
>& aRequests
, nsIPrincipal
* aPrincipal
,
5455 nsIPrincipal
* aTopLevelPrincipal
, const bool& aIsHandlingUserInput
,
5456 const bool& aMaybeUnsafePermissionDelegate
, const TabId
& aTabId
) {
5457 RefPtr
<BrowserParent
> tp
;
5458 ContentProcessManager
* cpm
= ContentProcessManager::GetSingleton();
5461 cpm
->GetTopLevelBrowserParentByProcessAndTabId(this->ChildID(), aTabId
);
5467 nsIPrincipal
* topPrincipal
= aTopLevelPrincipal
;
5468 if (!topPrincipal
) {
5469 nsCOMPtr
<nsIPrincipal
> principal
= tp
->GetContentPrincipal();
5470 topPrincipal
= principal
;
5472 return nsContentPermissionUtils::CreateContentPermissionRequestParent(
5473 aRequests
, tp
->GetOwnerElement(), aPrincipal
, topPrincipal
,
5474 aIsHandlingUserInput
, aMaybeUnsafePermissionDelegate
, aTabId
);
5477 bool ContentParent::DeallocPContentPermissionRequestParent(
5478 PContentPermissionRequestParent
* actor
) {
5479 nsContentPermissionUtils::NotifyRemoveContentPermissionRequestParent(actor
);
5484 PWebBrowserPersistDocumentParent
*
5485 ContentParent::AllocPWebBrowserPersistDocumentParent(
5486 PBrowserParent
* aBrowser
, const MaybeDiscarded
<BrowsingContext
>& aContext
) {
5487 return new WebBrowserPersistDocumentParent();
5490 bool ContentParent::DeallocPWebBrowserPersistDocumentParent(
5491 PWebBrowserPersistDocumentParent
* aActor
) {
5496 mozilla::ipc::IPCResult
ContentParent::CommonCreateWindow(
5497 PBrowserParent
* aThisTab
, BrowsingContext
& aParent
, bool aSetOpener
,
5498 const uint32_t& aChromeFlags
, const bool& aCalledFromJS
,
5499 const bool& aForPrinting
, const bool& aForWindowDotPrint
,
5500 nsIURI
* aURIToLoad
, const nsACString
& aFeatures
,
5501 BrowserParent
* aNextRemoteBrowser
, const nsAString
& aName
,
5502 nsresult
& aResult
, nsCOMPtr
<nsIRemoteTab
>& aNewRemoteTab
,
5503 bool* aWindowIsNew
, int32_t& aOpenLocation
,
5504 nsIPrincipal
* aTriggeringPrincipal
, nsIReferrerInfo
* aReferrerInfo
,
5505 bool aLoadURI
, nsIContentSecurityPolicy
* aCsp
,
5506 const OriginAttributes
& aOriginAttributes
) {
5507 // The content process should never be in charge of computing whether or
5508 // not a window should be private - the parent will do that.
5509 const uint32_t badFlags
= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW
|
5510 nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW
|
5511 nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME
;
5512 if (!!(aChromeFlags
& badFlags
)) {
5513 return IPC_FAIL(this, "Forbidden aChromeFlags passed");
5516 RefPtr
<nsOpenWindowInfo
> openInfo
= new nsOpenWindowInfo();
5517 openInfo
->mForceNoOpener
= !aSetOpener
;
5518 openInfo
->mParent
= &aParent
;
5519 openInfo
->mIsRemote
= true;
5520 openInfo
->mIsForPrinting
= aForPrinting
;
5521 openInfo
->mIsForWindowDotPrint
= aForWindowDotPrint
;
5522 openInfo
->mNextRemoteBrowser
= aNextRemoteBrowser
;
5523 openInfo
->mOriginAttributes
= aOriginAttributes
;
5525 MOZ_ASSERT_IF(aForWindowDotPrint
, aForPrinting
);
5527 RefPtr
<BrowserParent
> topParent
= BrowserParent::GetFrom(aThisTab
);
5528 while (topParent
&& topParent
->GetBrowserBridgeParent()) {
5529 topParent
= topParent
->GetBrowserBridgeParent()->Manager();
5531 RefPtr
<BrowserHost
> thisBrowserHost
=
5532 topParent
? topParent
->GetBrowserHost() : nullptr;
5533 MOZ_ASSERT_IF(topParent
, thisBrowserHost
);
5534 RefPtr
<BrowsingContext
> topBC
=
5535 topParent
? topParent
->GetBrowsingContext() : nullptr;
5536 MOZ_ASSERT_IF(topParent
, topBC
);
5538 // The content process should have set its remote and fission flags correctly.
5540 if ((!!(aChromeFlags
& nsIWebBrowserChrome::CHROME_REMOTE_WINDOW
) !=
5541 topBC
->UseRemoteTabs()) ||
5542 (!!(aChromeFlags
& nsIWebBrowserChrome::CHROME_FISSION_WINDOW
) !=
5543 topBC
->UseRemoteSubframes())) {
5544 return IPC_FAIL(this, "Unexpected aChromeFlags passed");
5547 if (!aOriginAttributes
.EqualsIgnoringFPD(topBC
->OriginAttributesRef())) {
5548 return IPC_FAIL(this, "Passed-in OriginAttributes does not match opener");
5552 nsCOMPtr
<nsIContent
> frame
;
5554 frame
= topParent
->GetOwnerElement();
5557 nsCOMPtr
<nsPIDOMWindowOuter
> outerWin
;
5559 outerWin
= frame
->OwnerDoc()->GetWindow();
5561 // If our chrome window is in the process of closing, don't try to open a
5563 if (outerWin
&& outerWin
->Closed()) {
5568 nsCOMPtr
<nsIBrowserDOMWindow
> browserDOMWin
;
5570 browserDOMWin
= topParent
->GetBrowserDOMWindow();
5573 // If we haven't found a chrome window to open in, just use the most recently
5576 outerWin
= nsContentUtils::GetMostRecentNonPBWindow();
5577 if (NS_WARN_IF(!outerWin
)) {
5578 aResult
= NS_ERROR_FAILURE
;
5582 if (nsGlobalWindowOuter::Cast(outerWin
)->IsChromeWindow()) {
5584 nsGlobalWindowOuter::Cast(outerWin
)->GetBrowserDOMWindow();
5588 aOpenLocation
= nsWindowWatcher::GetWindowOpenLocation(
5589 outerWin
, aChromeFlags
, aCalledFromJS
, aForPrinting
);
5591 MOZ_ASSERT(aOpenLocation
== nsIBrowserDOMWindow::OPEN_NEWTAB
||
5592 aOpenLocation
== nsIBrowserDOMWindow::OPEN_NEWWINDOW
||
5593 aOpenLocation
== nsIBrowserDOMWindow::OPEN_PRINT_BROWSER
);
5595 if (NS_WARN_IF(!browserDOMWin
)) {
5596 // Opening in the same window or headless requires an nsIBrowserDOMWindow.
5597 aOpenLocation
= nsIBrowserDOMWindow::OPEN_NEWWINDOW
;
5600 if (aOpenLocation
== nsIBrowserDOMWindow::OPEN_NEWTAB
||
5601 aOpenLocation
== nsIBrowserDOMWindow::OPEN_PRINT_BROWSER
) {
5602 RefPtr
<Element
> openerElement
= do_QueryObject(frame
);
5604 nsCOMPtr
<nsIOpenURIInFrameParams
> params
=
5605 new nsOpenURIInFrameParams(openInfo
, openerElement
);
5606 params
->SetReferrerInfo(aReferrerInfo
);
5607 MOZ_ASSERT(aTriggeringPrincipal
, "need a valid triggeringPrincipal");
5608 params
->SetTriggeringPrincipal(aTriggeringPrincipal
);
5609 params
->SetCsp(aCsp
);
5614 aResult
= browserDOMWin
->OpenURIInFrame(aURIToLoad
, params
, aOpenLocation
,
5615 nsIBrowserDOMWindow::OPEN_NEW
,
5616 aName
, getter_AddRefs(el
));
5618 aResult
= browserDOMWin
->CreateContentWindowInFrame(
5619 aURIToLoad
, params
, aOpenLocation
, nsIBrowserDOMWindow::OPEN_NEW
,
5620 aName
, getter_AddRefs(el
));
5622 RefPtr
<nsFrameLoaderOwner
> frameLoaderOwner
= do_QueryObject(el
);
5623 if (NS_SUCCEEDED(aResult
) && frameLoaderOwner
) {
5624 RefPtr
<nsFrameLoader
> frameLoader
= frameLoaderOwner
->GetFrameLoader();
5626 aNewRemoteTab
= frameLoader
->GetRemoteTab();
5627 // At this point, it's possible the inserted frameloader hasn't gone
5628 // through layout yet. To ensure that the dimensions that we send down
5629 // when telling the frameloader to display will be correct (instead of
5630 // falling back to a 10x10 default), we force layout if necessary to get
5631 // the most up-to-date dimensions. See bug 1358712 for details.
5632 frameLoader
->ForceLayoutIfNecessary();
5634 } else if (NS_SUCCEEDED(aResult
) && !frameLoaderOwner
) {
5635 // Fall through to the normal window opening code path when there is no
5636 // window which we can open a new tab in.
5637 aOpenLocation
= nsIBrowserDOMWindow::OPEN_NEWWINDOW
;
5639 *aWindowIsNew
= false;
5642 // If we didn't retarget our window open into a new window, we should return
5644 if (aOpenLocation
!= nsIBrowserDOMWindow::OPEN_NEWWINDOW
) {
5649 nsCOMPtr
<nsPIWindowWatcher
> pwwatch
=
5650 do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &aResult
);
5651 if (NS_WARN_IF(NS_FAILED(aResult
))) {
5655 WindowFeatures features
;
5656 features
.Tokenize(aFeatures
);
5658 aResult
= pwwatch
->OpenWindowWithRemoteTab(
5659 thisBrowserHost
, features
, aCalledFromJS
, aParent
.FullZoom(), openInfo
,
5660 getter_AddRefs(aNewRemoteTab
));
5661 if (NS_WARN_IF(NS_FAILED(aResult
))) {
5665 MOZ_ASSERT(aNewRemoteTab
);
5666 RefPtr
<BrowserHost
> newBrowserHost
= BrowserHost::GetFrom(aNewRemoteTab
);
5667 RefPtr
<BrowserParent
> newBrowserParent
= newBrowserHost
->GetActor();
5669 // At this point, it's possible the inserted frameloader hasn't gone through
5670 // layout yet. To ensure that the dimensions that we send down when telling
5671 // the frameloader to display will be correct (instead of falling back to a
5672 // 10x10 default), we force layout if necessary to get the most up-to-date
5673 // dimensions. See bug 1358712 for details.
5674 nsCOMPtr
<Element
> frameElement
= newBrowserHost
->GetOwnerElement();
5675 MOZ_ASSERT(frameElement
);
5676 if (nsWindowWatcher::HaveSpecifiedSize(features
)) {
5677 // We want to flush the layout anyway because of the resize to the specified
5678 // size. (Bug 1793605).
5679 RefPtr
<Document
> chromeDoc
= frameElement
->OwnerDoc();
5680 MOZ_ASSERT(chromeDoc
);
5681 chromeDoc
->FlushPendingNotifications(FlushType::Layout
);
5683 RefPtr
<nsFrameLoaderOwner
> frameLoaderOwner
= do_QueryObject(frameElement
);
5684 MOZ_ASSERT(frameLoaderOwner
);
5685 RefPtr
<nsFrameLoader
> frameLoader
= frameLoaderOwner
->GetFrameLoader();
5686 MOZ_ASSERT(frameLoader
);
5687 frameLoader
->ForceLayoutIfNecessary();
5690 // If we were passed a name for the window which would override the default,
5691 // we should send it down to the new tab.
5692 if (nsContentUtils::IsOverridingWindowName(aName
)) {
5693 MOZ_ALWAYS_SUCCEEDS(newBrowserHost
->GetBrowsingContext()->SetName(aName
));
5696 MOZ_ASSERT(newBrowserHost
->GetBrowsingContext()->OriginAttributesRef() ==
5699 if (aURIToLoad
&& aLoadURI
) {
5700 nsCOMPtr
<mozIDOMWindowProxy
> openerWindow
;
5701 if (aSetOpener
&& topParent
) {
5702 openerWindow
= topParent
->GetParentWindowOuter();
5704 nsCOMPtr
<nsIBrowserDOMWindow
> newBrowserDOMWin
=
5705 newBrowserParent
->GetBrowserDOMWindow();
5706 if (NS_WARN_IF(!newBrowserDOMWin
)) {
5707 aResult
= NS_ERROR_ABORT
;
5710 RefPtr
<BrowsingContext
> bc
;
5711 aResult
= newBrowserDOMWin
->OpenURI(
5712 aURIToLoad
, openInfo
, nsIBrowserDOMWindow::OPEN_CURRENTWINDOW
,
5713 nsIBrowserDOMWindow::OPEN_NEW
, aTriggeringPrincipal
, aCsp
,
5714 getter_AddRefs(bc
));
5720 mozilla::ipc::IPCResult
ContentParent::RecvCreateWindow(
5721 PBrowserParent
* aThisTab
, const MaybeDiscarded
<BrowsingContext
>& aParent
,
5722 PBrowserParent
* aNewTab
, const uint32_t& aChromeFlags
,
5723 const bool& aCalledFromJS
, const bool& aForPrinting
,
5724 const bool& aForPrintPreview
, nsIURI
* aURIToLoad
,
5725 const nsACString
& aFeatures
, nsIPrincipal
* aTriggeringPrincipal
,
5726 nsIContentSecurityPolicy
* aCsp
, nsIReferrerInfo
* aReferrerInfo
,
5727 const OriginAttributes
& aOriginAttributes
,
5728 CreateWindowResolver
&& aResolve
) {
5729 if (!aTriggeringPrincipal
) {
5730 return IPC_FAIL(this, "No principal");
5733 if (!ValidatePrincipal(aTriggeringPrincipal
)) {
5734 LogAndAssertFailedPrincipalValidationInfo(aTriggeringPrincipal
, __func__
);
5737 nsresult rv
= NS_OK
;
5738 CreatedWindowInfo cwi
;
5740 // We always expect to open a new window here. If we don't, it's an error.
5741 cwi
.windowOpened() = true;
5742 cwi
.maxTouchPoints() = 0;
5744 // Make sure to resolve the resolver when this function exits, even if we
5745 // failed to generate a valid response.
5746 auto resolveOnExit
= MakeScopeExit([&] {
5747 // Copy over the nsresult, and then resolve.
5752 RefPtr
<BrowserParent
> thisTab
= BrowserParent::GetFrom(aThisTab
);
5753 RefPtr
<BrowserParent
> newTab
= BrowserParent::GetFrom(aNewTab
);
5756 auto destroyNewTabOnError
= MakeScopeExit([&] {
5757 // We always expect to open a new window here. If we don't, it's an error.
5758 if (!cwi
.windowOpened() || NS_FAILED(rv
)) {
5765 // Don't continue to try to create a new window if we've been fully discarded.
5766 RefPtr
<BrowsingContext
> parent
= aParent
.GetMaybeDiscarded();
5767 if (NS_WARN_IF(!parent
)) {
5768 rv
= NS_ERROR_FAILURE
;
5772 // Validate that our new BrowsingContext looks as we would expect it.
5773 RefPtr
<BrowsingContext
> newBC
= newTab
->GetBrowsingContext();
5775 return IPC_FAIL(this, "Missing BrowsingContext for new tab");
5778 uint64_t newBCOpenerId
= newBC
->GetOpenerId();
5779 if (newBCOpenerId
!= 0 && parent
->Id() != newBCOpenerId
) {
5780 return IPC_FAIL(this, "Invalid opener BrowsingContext for new tab");
5782 if (newBC
->GetParent() != nullptr) {
5783 return IPC_FAIL(this,
5784 "Unexpected non-toplevel BrowsingContext for new tab");
5786 if (!!(aChromeFlags
& nsIWebBrowserChrome::CHROME_REMOTE_WINDOW
) !=
5787 newBC
->UseRemoteTabs() ||
5788 !!(aChromeFlags
& nsIWebBrowserChrome::CHROME_FISSION_WINDOW
) !=
5789 newBC
->UseRemoteSubframes()) {
5790 return IPC_FAIL(this, "Unexpected aChromeFlags passed");
5792 if (!aOriginAttributes
.EqualsIgnoringFPD(newBC
->OriginAttributesRef())) {
5793 return IPC_FAIL(this, "Opened tab has mismatched OriginAttributes");
5796 if (thisTab
&& BrowserParent::GetFrom(thisTab
)->GetBrowsingContext()) {
5797 BrowsingContext
* thisTabBC
= thisTab
->GetBrowsingContext();
5798 if (thisTabBC
->UseRemoteTabs() != newBC
->UseRemoteTabs() ||
5799 thisTabBC
->UseRemoteSubframes() != newBC
->UseRemoteSubframes() ||
5800 thisTabBC
->UsePrivateBrowsing() != newBC
->UsePrivateBrowsing()) {
5801 return IPC_FAIL(this, "New BrowsingContext has mismatched LoadContext");
5804 BrowserParent::AutoUseNewTab
aunt(newTab
);
5806 nsCOMPtr
<nsIRemoteTab
> newRemoteTab
;
5807 int32_t openLocation
= nsIBrowserDOMWindow::OPEN_NEWWINDOW
;
5808 mozilla::ipc::IPCResult ipcResult
= CommonCreateWindow(
5809 aThisTab
, *parent
, newBCOpenerId
!= 0, aChromeFlags
, aCalledFromJS
,
5810 aForPrinting
, aForPrintPreview
, aURIToLoad
, aFeatures
, newTab
,
5811 VoidString(), rv
, newRemoteTab
, &cwi
.windowOpened(), openLocation
,
5812 aTriggeringPrincipal
, aReferrerInfo
, /* aLoadUri = */ false, aCsp
,
5818 if (NS_WARN_IF(NS_FAILED(rv
)) || !newRemoteTab
) {
5822 MOZ_ASSERT(BrowserHost::GetFrom(newRemoteTab
.get()) ==
5823 newTab
->GetBrowserHost());
5825 // This used to happen in the child - there may now be a better place to
5827 MOZ_ALWAYS_SUCCEEDS(
5828 newBC
->SetHasSiblings(openLocation
== nsIBrowserDOMWindow::OPEN_NEWTAB
));
5830 newTab
->SwapFrameScriptsFrom(cwi
.frameScripts());
5831 newTab
->MaybeShowFrame();
5833 nsCOMPtr
<nsIWidget
> widget
= newTab
->GetWidget();
5835 cwi
.dimensions() = newTab
->GetDimensionInfo();
5838 cwi
.maxTouchPoints() = newTab
->GetMaxTouchPoints();
5843 mozilla::ipc::IPCResult
ContentParent::RecvCreateWindowInDifferentProcess(
5844 PBrowserParent
* aThisTab
, const MaybeDiscarded
<BrowsingContext
>& aParent
,
5845 const uint32_t& aChromeFlags
, const bool& aCalledFromJS
, nsIURI
* aURIToLoad
,
5846 const nsACString
& aFeatures
, const nsAString
& aName
,
5847 nsIPrincipal
* aTriggeringPrincipal
, nsIContentSecurityPolicy
* aCsp
,
5848 nsIReferrerInfo
* aReferrerInfo
, const OriginAttributes
& aOriginAttributes
) {
5849 MOZ_DIAGNOSTIC_ASSERT(!nsContentUtils::IsSpecialName(aName
));
5851 // Don't continue to try to create a new window if we've been fully discarded.
5852 RefPtr
<BrowsingContext
> parent
= aParent
.GetMaybeDiscarded();
5853 if (NS_WARN_IF(!parent
)) {
5857 nsCOMPtr
<nsIRemoteTab
> newRemoteTab
;
5859 int32_t openLocation
= nsIBrowserDOMWindow::OPEN_NEWWINDOW
;
5861 // If we have enough data, check the schemes of the loader and loadee
5862 // to make sure they make sense.
5863 if (aURIToLoad
&& aURIToLoad
->SchemeIs("file") &&
5864 GetRemoteType() != FILE_REMOTE_TYPE
&&
5865 Preferences::GetBool("browser.tabs.remote.enforceRemoteTypeRestrictions",
5867 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
5869 nsAutoCString uriToLoadStr
;
5870 nsAutoCString triggeringUriStr
;
5871 aURIToLoad
->GetAsciiSpec(uriToLoadStr
);
5872 aTriggeringPrincipal
->GetAsciiSpec(triggeringUriStr
);
5874 NS_WARNING(nsPrintfCString(
5875 "RecvCreateWindowInDifferentProcess blocked loading file "
5876 "scheme from non-file remotetype: %s tried to load %s",
5877 triggeringUriStr
.get(), uriToLoadStr
.get())
5881 "RecvCreateWindowInDifferentProcess blocked loading improper scheme");
5887 mozilla::ipc::IPCResult ipcResult
= CommonCreateWindow(
5888 aThisTab
, *parent
, /* aSetOpener = */ false, aChromeFlags
, aCalledFromJS
,
5889 /* aForPrinting = */ false,
5890 /* aForPrintPreview = */ false, aURIToLoad
, aFeatures
,
5891 /* aNextRemoteBrowser = */ nullptr, aName
, rv
, newRemoteTab
, &windowIsNew
,
5892 openLocation
, aTriggeringPrincipal
, aReferrerInfo
,
5893 /* aLoadUri = */ true, aCsp
, aOriginAttributes
);
5898 if (NS_FAILED(rv
)) {
5899 NS_WARNING("Call to CommonCreateWindow failed.");
5905 mozilla::ipc::IPCResult
ContentParent::RecvShutdownProfile(
5906 const nsACString
& aProfile
) {
5907 profiler_received_exit_profile(aProfile
);
5911 mozilla::ipc::IPCResult
ContentParent::RecvShutdownPerfStats(
5912 const nsACString
& aPerfStats
) {
5913 PerfStats::StorePerfStats(this, aPerfStats
);
5917 mozilla::ipc::IPCResult
ContentParent::RecvGetFontListShmBlock(
5918 const uint32_t& aGeneration
, const uint32_t& aIndex
,
5919 base::SharedMemoryHandle
* aOut
) {
5920 auto* fontList
= gfxPlatformFontList::PlatformFontList();
5921 MOZ_RELEASE_ASSERT(fontList
, "gfxPlatformFontList not initialized?");
5922 fontList
->ShareFontListShmBlockToProcess(aGeneration
, aIndex
, Pid(), aOut
);
5926 mozilla::ipc::IPCResult
ContentParent::RecvInitializeFamily(
5927 const uint32_t& aGeneration
, const uint32_t& aFamilyIndex
,
5928 const bool& aLoadCmaps
) {
5929 auto* fontList
= gfxPlatformFontList::PlatformFontList();
5930 MOZ_RELEASE_ASSERT(fontList
, "gfxPlatformFontList not initialized?");
5931 fontList
->InitializeFamily(aGeneration
, aFamilyIndex
, aLoadCmaps
);
5935 mozilla::ipc::IPCResult
ContentParent::RecvSetCharacterMap(
5936 const uint32_t& aGeneration
, const mozilla::fontlist::Pointer
& aFacePtr
,
5937 const gfxSparseBitSet
& aMap
) {
5938 auto* fontList
= gfxPlatformFontList::PlatformFontList();
5939 MOZ_RELEASE_ASSERT(fontList
, "gfxPlatformFontList not initialized?");
5940 fontList
->SetCharacterMap(aGeneration
, aFacePtr
, aMap
);
5944 mozilla::ipc::IPCResult
ContentParent::RecvInitOtherFamilyNames(
5945 const uint32_t& aGeneration
, const bool& aDefer
, bool* aLoaded
) {
5946 auto* fontList
= gfxPlatformFontList::PlatformFontList();
5947 MOZ_RELEASE_ASSERT(fontList
, "gfxPlatformFontList not initialized?");
5948 *aLoaded
= fontList
->InitOtherFamilyNames(aGeneration
, aDefer
);
5952 mozilla::ipc::IPCResult
ContentParent::RecvSetupFamilyCharMap(
5953 const uint32_t& aGeneration
, const mozilla::fontlist::Pointer
& aFamilyPtr
) {
5954 auto* fontList
= gfxPlatformFontList::PlatformFontList();
5955 MOZ_RELEASE_ASSERT(fontList
, "gfxPlatformFontList not initialized?");
5956 fontList
->SetupFamilyCharMap(aGeneration
, aFamilyPtr
);
5960 mozilla::ipc::IPCResult
ContentParent::RecvStartCmapLoading(
5961 const uint32_t& aGeneration
, const uint32_t& aStartIndex
) {
5962 auto* fontList
= gfxPlatformFontList::PlatformFontList();
5963 MOZ_RELEASE_ASSERT(fontList
, "gfxPlatformFontList not initialized?");
5964 fontList
->StartCmapLoading(aGeneration
, aStartIndex
);
5968 mozilla::ipc::IPCResult
ContentParent::RecvGetHyphDict(
5969 nsIURI
* aURI
, base::SharedMemoryHandle
* aOutHandle
, uint32_t* aOutSize
) {
5971 return IPC_FAIL(this, "aURI must not be null.");
5973 nsHyphenationManager::Instance()->ShareHyphDictToProcess(
5974 aURI
, Pid(), aOutHandle
, aOutSize
);
5978 mozilla::ipc::IPCResult
ContentParent::RecvGraphicsError(
5979 const nsACString
& aError
) {
5980 if (gfx::LogForwarder
* lf
= gfx::Factory::GetLogForwarder()) {
5981 std::stringstream message
;
5982 message
<< "CP+" << aError
;
5983 lf
->UpdateStringsVector(message
.str());
5988 mozilla::ipc::IPCResult
ContentParent::RecvBeginDriverCrashGuard(
5989 const uint32_t& aGuardType
, bool* aOutCrashed
) {
5990 // Only one driver crash guard should be active at a time, per-process.
5991 MOZ_ASSERT(!mDriverCrashGuard
);
5993 UniquePtr
<gfx::DriverCrashGuard
> guard
;
5994 switch (gfx::CrashGuardType(aGuardType
)) {
5995 case gfx::CrashGuardType::D3D11Layers
:
5996 guard
= MakeUnique
<gfx::D3D11LayersCrashGuard
>(this);
5998 case gfx::CrashGuardType::GLContext
:
5999 guard
= MakeUnique
<gfx::GLContextCrashGuard
>(this);
6001 case gfx::CrashGuardType::WMFVPXVideo
:
6002 guard
= MakeUnique
<gfx::WMFVPXVideoCrashGuard
>(this);
6005 return IPC_FAIL(this, "unknown crash guard type");
6008 if (guard
->Crashed()) {
6009 *aOutCrashed
= true;
6013 *aOutCrashed
= false;
6014 mDriverCrashGuard
= std::move(guard
);
6018 mozilla::ipc::IPCResult
ContentParent::RecvEndDriverCrashGuard(
6019 const uint32_t& aGuardType
) {
6020 mDriverCrashGuard
= nullptr;
6024 mozilla::ipc::IPCResult
ContentParent::RecvNotifyBenchmarkResult(
6025 const nsAString
& aCodecName
, const uint32_t& aDecodeFPS
)
6028 if (aCodecName
.EqualsLiteral("VP9")) {
6029 Preferences::SetUint(VP9Benchmark::sBenchmarkFpsPref
, aDecodeFPS
);
6030 Preferences::SetUint(VP9Benchmark::sBenchmarkFpsVersionCheck
,
6031 VP9Benchmark::sBenchmarkVersionID
);
6036 mozilla::ipc::IPCResult
ContentParent::RecvNotifyPushObservers(
6037 const nsACString
& aScope
, nsIPrincipal
* aPrincipal
,
6038 const nsAString
& aMessageId
) {
6040 return IPC_FAIL(this, "No principal");
6043 if (!ValidatePrincipal(aPrincipal
)) {
6044 LogAndAssertFailedPrincipalValidationInfo(aPrincipal
, __func__
);
6046 PushMessageDispatcher
dispatcher(aScope
, aPrincipal
, aMessageId
, Nothing());
6047 Unused
<< NS_WARN_IF(NS_FAILED(dispatcher
.NotifyObserversAndWorkers()));
6051 mozilla::ipc::IPCResult
ContentParent::RecvNotifyPushObserversWithData(
6052 const nsACString
& aScope
, nsIPrincipal
* aPrincipal
,
6053 const nsAString
& aMessageId
, nsTArray
<uint8_t>&& aData
) {
6055 return IPC_FAIL(this, "No principal");
6058 if (!ValidatePrincipal(aPrincipal
)) {
6059 LogAndAssertFailedPrincipalValidationInfo(aPrincipal
, __func__
);
6061 PushMessageDispatcher
dispatcher(aScope
, aPrincipal
, aMessageId
,
6062 Some(std::move(aData
)));
6063 Unused
<< NS_WARN_IF(NS_FAILED(dispatcher
.NotifyObserversAndWorkers()));
6067 mozilla::ipc::IPCResult
6068 ContentParent::RecvNotifyPushSubscriptionChangeObservers(
6069 const nsACString
& aScope
, nsIPrincipal
* aPrincipal
) {
6071 return IPC_FAIL(this, "No principal");
6074 if (!ValidatePrincipal(aPrincipal
)) {
6075 LogAndAssertFailedPrincipalValidationInfo(aPrincipal
, __func__
);
6077 PushSubscriptionChangeDispatcher
dispatcher(aScope
, aPrincipal
);
6078 Unused
<< NS_WARN_IF(NS_FAILED(dispatcher
.NotifyObserversAndWorkers()));
6082 mozilla::ipc::IPCResult
ContentParent::RecvPushError(const nsACString
& aScope
,
6083 nsIPrincipal
* aPrincipal
,
6084 const nsAString
& aMessage
,
6085 const uint32_t& aFlags
) {
6087 return IPC_FAIL(this, "No principal");
6090 if (!ValidatePrincipal(aPrincipal
)) {
6091 LogAndAssertFailedPrincipalValidationInfo(aPrincipal
, __func__
);
6093 PushErrorDispatcher
dispatcher(aScope
, aPrincipal
, aMessage
, aFlags
);
6094 Unused
<< NS_WARN_IF(NS_FAILED(dispatcher
.NotifyObserversAndWorkers()));
6098 mozilla::ipc::IPCResult
6099 ContentParent::RecvNotifyPushSubscriptionModifiedObservers(
6100 const nsACString
& aScope
, nsIPrincipal
* aPrincipal
) {
6102 return IPC_FAIL(this, "No principal");
6105 if (!ValidatePrincipal(aPrincipal
)) {
6106 LogAndAssertFailedPrincipalValidationInfo(aPrincipal
, __func__
);
6108 PushSubscriptionModifiedDispatcher
dispatcher(aScope
, aPrincipal
);
6109 Unused
<< NS_WARN_IF(NS_FAILED(dispatcher
.NotifyObservers()));
6114 void ContentParent::BroadcastBlobURLRegistration(const nsACString
& aURI
,
6115 BlobImpl
* aBlobImpl
,
6116 nsIPrincipal
* aPrincipal
,
6117 const nsCString
& aPartitionKey
,
6118 ContentParent
* aIgnoreThisCP
) {
6119 uint64_t originHash
= ComputeLoadedOriginHash(aPrincipal
);
6122 BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal
);
6124 nsCString
uri(aURI
);
6126 for (auto* cp
: AllProcesses(eLive
)) {
6127 if (cp
!= aIgnoreThisCP
) {
6128 if (!toBeSent
&& !cp
->mLoadedOriginHashes
.Contains(originHash
)) {
6132 nsresult rv
= cp
->TransmitPermissionsForPrincipal(aPrincipal
);
6133 if (NS_WARN_IF(NS_FAILED(rv
))) {
6138 rv
= IPCBlobUtils::Serialize(aBlobImpl
, ipcBlob
);
6139 if (NS_WARN_IF(NS_FAILED(rv
))) {
6143 Unused
<< cp
->SendBlobURLRegistration(uri
, ipcBlob
, aPrincipal
,
6150 void ContentParent::BroadcastBlobURLUnregistration(
6151 const nsACString
& aURI
, nsIPrincipal
* aPrincipal
,
6152 ContentParent
* aIgnoreThisCP
) {
6153 uint64_t originHash
= ComputeLoadedOriginHash(aPrincipal
);
6156 BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal
);
6158 nsCString
uri(aURI
);
6160 for (auto* cp
: AllProcesses(eLive
)) {
6161 if (cp
!= aIgnoreThisCP
&&
6162 (toBeSent
|| cp
->mLoadedOriginHashes
.Contains(originHash
))) {
6163 Unused
<< cp
->SendBlobURLUnregistration(uri
);
6168 mozilla::ipc::IPCResult
ContentParent::RecvStoreAndBroadcastBlobURLRegistration(
6169 const nsACString
& aURI
, const IPCBlob
& aBlob
, nsIPrincipal
* aPrincipal
,
6170 const nsCString
& aPartitionKey
) {
6172 return IPC_FAIL(this, "No principal");
6175 if (!ValidatePrincipal(aPrincipal
, {ValidatePrincipalOptions::AllowSystem
})) {
6176 LogAndAssertFailedPrincipalValidationInfo(aPrincipal
, __func__
);
6178 RefPtr
<BlobImpl
> blobImpl
= IPCBlobUtils::Deserialize(aBlob
);
6179 if (NS_WARN_IF(!blobImpl
)) {
6180 return IPC_FAIL(this, "Blob deserialization failed.");
6183 BlobURLProtocolHandler::AddDataEntry(aURI
, aPrincipal
, aPartitionKey
,
6185 BroadcastBlobURLRegistration(aURI
, blobImpl
, aPrincipal
, aPartitionKey
, this);
6187 // We want to store this blobURL, so we can unregister it if the child
6189 mBlobURLs
.AppendElement(aURI
);
6194 mozilla::ipc::IPCResult
6195 ContentParent::RecvUnstoreAndBroadcastBlobURLUnregistration(
6196 const nsACString
& aURI
, nsIPrincipal
* aPrincipal
) {
6198 return IPC_FAIL(this, "No principal");
6201 if (!ValidatePrincipal(aPrincipal
, {ValidatePrincipalOptions::AllowSystem
})) {
6202 LogAndAssertFailedPrincipalValidationInfo(aPrincipal
, __func__
);
6204 BlobURLProtocolHandler::RemoveDataEntry(aURI
, false /* Don't broadcast */);
6205 BroadcastBlobURLUnregistration(aURI
, aPrincipal
, this);
6206 mBlobURLs
.RemoveElement(aURI
);
6210 mozilla::ipc::IPCResult
ContentParent::RecvGetFilesRequest(
6211 const nsID
& aUUID
, const nsAString
& aDirectoryPath
,
6212 const bool& aRecursiveFlag
) {
6213 MOZ_ASSERT(!mGetFilesPendingRequests
.GetWeak(aUUID
));
6215 if (!mozilla::Preferences::GetBool("dom.filesystem.pathcheck.disabled",
6217 RefPtr
<FileSystemSecurity
> fss
= FileSystemSecurity::Get();
6219 return IPC_FAIL(this, "Failed to get FileSystemSecurity.");
6222 if (!fss
->ContentProcessHasAccessTo(ChildID(), aDirectoryPath
)) {
6223 return IPC_FAIL(this, "ContentProcessHasAccessTo failed.");
6228 RefPtr
<GetFilesHelper
> helper
= GetFilesHelperParent::Create(
6229 aUUID
, aDirectoryPath
, aRecursiveFlag
, this, rv
);
6231 if (NS_WARN_IF(rv
.Failed())) {
6232 if (!SendGetFilesResponse(aUUID
,
6233 GetFilesResponseFailure(rv
.StealNSResult()))) {
6234 return IPC_FAIL(this, "SendGetFilesResponse failed.");
6239 mGetFilesPendingRequests
.InsertOrUpdate(aUUID
, std::move(helper
));
6243 mozilla::ipc::IPCResult
ContentParent::RecvDeleteGetFilesRequest(
6244 const nsID
& aUUID
) {
6245 mGetFilesPendingRequests
.Remove(aUUID
);
6249 void ContentParent::SendGetFilesResponseAndForget(
6250 const nsID
& aUUID
, const GetFilesResponseResult
& aResult
) {
6251 if (mGetFilesPendingRequests
.Remove(aUUID
)) {
6252 Unused
<< SendGetFilesResponse(aUUID
, aResult
);
6256 void ContentParent::PaintTabWhileInterruptingJS(BrowserParent
* aBrowserParent
) {
6257 if (!mHangMonitorActor
) {
6260 ProcessHangMonitor::PaintWhileInterruptingJS(mHangMonitorActor
,
6264 void ContentParent::UnloadLayersWhileInterruptingJS(
6265 BrowserParent
* aBrowserParent
) {
6266 if (!mHangMonitorActor
) {
6269 ProcessHangMonitor::UnloadLayersWhileInterruptingJS(mHangMonitorActor
,
6273 void ContentParent::CancelContentJSExecutionIfRunning(
6274 BrowserParent
* aBrowserParent
, nsIRemoteTab::NavigationType aNavigationType
,
6275 const CancelContentJSOptions
& aCancelContentJSOptions
) {
6276 if (!mHangMonitorActor
) {
6280 ProcessHangMonitor::CancelContentJSExecutionIfRunning(
6281 mHangMonitorActor
, aBrowserParent
, aNavigationType
,
6282 aCancelContentJSOptions
);
6285 void ContentParent::SetMainThreadQoSPriority(
6286 nsIThread::QoSPriority aQoSPriority
) {
6287 if (!mHangMonitorActor
) {
6291 ProcessHangMonitor::SetMainThreadQoSPriority(mHangMonitorActor
, aQoSPriority
);
6294 void ContentParent::UpdateCookieStatus(nsIChannel
* aChannel
) {
6295 PNeckoParent
* neckoParent
= LoneManagedOrNullAsserts(ManagedPNeckoParent());
6296 PCookieServiceParent
* csParent
=
6297 LoneManagedOrNullAsserts(neckoParent
->ManagedPCookieServiceParent());
6299 auto* cs
= static_cast<CookieServiceParent
*>(csParent
);
6300 cs
->TrackCookieLoad(aChannel
);
6304 nsresult
ContentParent::AboutToLoadHttpFtpDocumentForChild(
6305 nsIChannel
* aChannel
, bool* aShouldWaitForPermissionCookieUpdate
) {
6306 MOZ_ASSERT(aChannel
);
6308 if (aShouldWaitForPermissionCookieUpdate
) {
6309 *aShouldWaitForPermissionCookieUpdate
= false;
6313 bool isDocument
= aChannel
->IsDocument();
6315 // We may be looking at a nsIHttpChannel which has isMainDocumentChannel set
6316 // (e.g. the internal http channel for a view-source: load.).
6317 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aChannel
);
6319 rv
= httpChannel
->GetIsMainDocumentChannel(&isDocument
);
6320 NS_ENSURE_SUCCESS(rv
, rv
);
6327 // Get the principal for the channel result, so that we can get the permission
6328 // key for the document which will be created from this response.
6329 nsIScriptSecurityManager
* ssm
= nsContentUtils::GetSecurityManager();
6330 if (NS_WARN_IF(!ssm
)) {
6331 return NS_ERROR_FAILURE
;
6334 nsCOMPtr
<nsIPrincipal
> principal
;
6335 nsCOMPtr
<nsIPrincipal
> partitionedPrincipal
;
6336 rv
= ssm
->GetChannelResultPrincipals(aChannel
, getter_AddRefs(principal
),
6337 getter_AddRefs(partitionedPrincipal
));
6338 NS_ENSURE_SUCCESS(rv
, rv
);
6340 // Let the caller know we're going to send main thread IPC for updating
6341 // permisssions/cookies.
6342 if (aShouldWaitForPermissionCookieUpdate
) {
6343 *aShouldWaitForPermissionCookieUpdate
= true;
6346 TransmitBlobURLsForPrincipal(principal
);
6348 // Tranmit permissions for both regular and partitioned principal so that the
6349 // content process can get permissions for the partitioned principal. For
6350 // example, the desk-notification permission for a partitioned service worker.
6351 rv
= TransmitPermissionsForPrincipal(principal
);
6352 NS_ENSURE_SUCCESS(rv
, rv
);
6354 rv
= TransmitPermissionsForPrincipal(partitionedPrincipal
);
6355 NS_ENSURE_SUCCESS(rv
, rv
);
6357 nsLoadFlags newLoadFlags
;
6358 aChannel
->GetLoadFlags(&newLoadFlags
);
6359 if (newLoadFlags
& nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE
) {
6360 UpdateCookieStatus(aChannel
);
6363 RefPtr
<nsILoadInfo
> loadInfo
= aChannel
->LoadInfo();
6364 RefPtr
<BrowsingContext
> browsingContext
;
6365 rv
= loadInfo
->GetTargetBrowsingContext(getter_AddRefs(browsingContext
));
6366 NS_ENSURE_SUCCESS(rv
, rv
);
6368 if (!NextGenLocalStorageEnabled()) {
6372 if (principal
->GetIsContentPrincipal()) {
6373 nsCOMPtr
<nsILocalStorageManager
> lsm
=
6374 do_GetService("@mozilla.org/dom/localStorage-manager;1");
6375 if (NS_WARN_IF(!lsm
)) {
6376 return NS_ERROR_FAILURE
;
6379 nsCOMPtr
<nsIPrincipal
> storagePrincipal
;
6380 rv
= ssm
->GetChannelResultStoragePrincipal(
6381 aChannel
, getter_AddRefs(storagePrincipal
));
6382 NS_ENSURE_SUCCESS(rv
, rv
);
6384 RefPtr
<Promise
> dummy
;
6385 rv
= lsm
->Preload(storagePrincipal
, nullptr, getter_AddRefs(dummy
));
6386 if (NS_FAILED(rv
)) {
6387 NS_WARNING("Failed to preload local storage!");
6394 nsresult
ContentParent::TransmitPermissionsForPrincipal(
6395 nsIPrincipal
* aPrincipal
) {
6396 // Create the key, and send it down to the content process.
6397 nsTArray
<std::pair
<nsCString
, nsCString
>> pairs
=
6398 PermissionManager::GetAllKeysForPrincipal(aPrincipal
);
6399 MOZ_ASSERT(pairs
.Length() >= 1);
6400 for (auto& pair
: pairs
) {
6401 EnsurePermissionsByKey(pair
.first
, pair
.second
);
6404 // We need to add the Site to the secondary keys of interest here.
6405 // This allows site-scoped permission updates to propogate when the
6406 // port is non-standard.
6407 nsAutoCString siteKey
;
6409 PermissionManager::GetKeyForPrincipal(aPrincipal
, false, true, siteKey
);
6410 if (NS_SUCCEEDED(rv
) && !siteKey
.IsEmpty()) {
6411 mActiveSecondaryPermissionKeys
.EnsureInserted(siteKey
);
6417 void ContentParent::TransmitBlobURLsForPrincipal(nsIPrincipal
* aPrincipal
) {
6418 // If we're already broadcasting BlobURLs with this principal, we don't need
6419 // to send them here.
6420 if (BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal
)) {
6424 // We shouldn't have any Blob URLs with expanded principals, so transmit URLs
6425 // for each principal in the AllowList instead.
6426 if (nsCOMPtr
<nsIExpandedPrincipal
> ep
= do_QueryInterface(aPrincipal
)) {
6427 for (const auto& prin
: ep
->AllowList()) {
6428 TransmitBlobURLsForPrincipal(prin
);
6433 uint64_t originHash
= ComputeLoadedOriginHash(aPrincipal
);
6435 if (!mLoadedOriginHashes
.Contains(originHash
)) {
6436 mLoadedOriginHashes
.AppendElement(originHash
);
6438 nsTArray
<BlobURLRegistrationData
> registrations
;
6439 BlobURLProtocolHandler::ForEachBlobURL(
6440 [&](BlobImpl
* aBlobImpl
, nsIPrincipal
* aBlobPrincipal
,
6441 const nsCString
& aPartitionKey
, const nsACString
& aURI
,
6443 // This check uses `ComputeLoadedOriginHash` to compare, rather than
6444 // doing the more accurate `Equals` check, as it needs to match the
6445 // behaviour of the logic to broadcast new registrations.
6446 if (originHash
!= ComputeLoadedOriginHash(aBlobPrincipal
)) {
6451 nsresult rv
= IPCBlobUtils::Serialize(aBlobImpl
, ipcBlob
);
6452 if (NS_WARN_IF(NS_FAILED(rv
))) {
6456 registrations
.AppendElement(
6457 BlobURLRegistrationData(nsCString(aURI
), ipcBlob
, aPrincipal
,
6458 nsCString(aPartitionKey
), aRevoked
));
6460 rv
= TransmitPermissionsForPrincipal(aBlobPrincipal
);
6461 Unused
<< NS_WARN_IF(NS_FAILED(rv
));
6465 if (!registrations
.IsEmpty()) {
6466 Unused
<< SendInitBlobURLs(registrations
);
6471 void ContentParent::TransmitBlobDataIfBlobURL(nsIURI
* aURI
) {
6474 nsCOMPtr
<nsIPrincipal
> principal
;
6475 if (BlobURLProtocolHandler::GetBlobURLPrincipal(aURI
,
6476 getter_AddRefs(principal
))) {
6477 TransmitBlobURLsForPrincipal(principal
);
6481 void ContentParent::EnsurePermissionsByKey(const nsACString
& aKey
,
6482 const nsACString
& aOrigin
) {
6483 // NOTE: Make sure to initialize the permission manager before updating the
6484 // mActivePermissionKeys list. If the permission manager is being initialized
6485 // by this call to GetPermissionManager, and we've added the key to
6486 // mActivePermissionKeys, then the permission manager will send down a
6487 // SendAddPermission before receiving the SendSetPermissionsWithKey message.
6488 RefPtr
<PermissionManager
> permManager
= PermissionManager::GetInstance();
6493 if (!mActivePermissionKeys
.EnsureInserted(aKey
)) {
6497 nsTArray
<IPC::Permission
> perms
;
6498 if (permManager
->GetPermissionsFromOriginOrKey(aOrigin
, aKey
, perms
)) {
6499 Unused
<< SendSetPermissionsWithKey(aKey
, perms
);
6503 bool ContentParent::NeedsPermissionsUpdate(
6504 const nsACString
& aPermissionKey
) const {
6505 return mActivePermissionKeys
.Contains(aPermissionKey
);
6508 bool ContentParent::NeedsSecondaryKeyPermissionsUpdate(
6509 const nsACString
& aPermissionKey
) const {
6510 return mActiveSecondaryPermissionKeys
.Contains(aPermissionKey
);
6513 mozilla::ipc::IPCResult
ContentParent::RecvAccumulateChildHistograms(
6514 nsTArray
<HistogramAccumulation
>&& aAccumulations
) {
6515 TelemetryIPC::AccumulateChildHistograms(GetTelemetryProcessID(mRemoteType
),
6520 mozilla::ipc::IPCResult
ContentParent::RecvAccumulateChildKeyedHistograms(
6521 nsTArray
<KeyedHistogramAccumulation
>&& aAccumulations
) {
6522 TelemetryIPC::AccumulateChildKeyedHistograms(
6523 GetTelemetryProcessID(mRemoteType
), aAccumulations
);
6527 mozilla::ipc::IPCResult
ContentParent::RecvUpdateChildScalars(
6528 nsTArray
<ScalarAction
>&& aScalarActions
) {
6529 TelemetryIPC::UpdateChildScalars(GetTelemetryProcessID(mRemoteType
),
6534 mozilla::ipc::IPCResult
ContentParent::RecvUpdateChildKeyedScalars(
6535 nsTArray
<KeyedScalarAction
>&& aScalarActions
) {
6536 TelemetryIPC::UpdateChildKeyedScalars(GetTelemetryProcessID(mRemoteType
),
6541 mozilla::ipc::IPCResult
ContentParent::RecvRecordChildEvents(
6542 nsTArray
<mozilla::Telemetry::ChildEventData
>&& aEvents
) {
6543 TelemetryIPC::RecordChildEvents(GetTelemetryProcessID(mRemoteType
), aEvents
);
6547 mozilla::ipc::IPCResult
ContentParent::RecvRecordDiscardedData(
6548 const mozilla::Telemetry::DiscardedData
& aDiscardedData
) {
6549 TelemetryIPC::RecordDiscardedData(GetTelemetryProcessID(mRemoteType
),
6554 mozilla::ipc::IPCResult
ContentParent::RecvRecordPageLoadEvent(
6555 const mozilla::glean::perf::PageLoadExtra
& aPageLoadEventExtra
) {
6556 mozilla::glean::perf::page_load
.Record(mozilla::Some(aPageLoadEventExtra
));
6558 // Send the PageLoadPing after every 30 page loads, or on startup.
6559 if (++sPageLoadEventCounter
>= 30) {
6560 NS_SUCCEEDED(NS_DispatchToMainThreadQueue(
6561 NS_NewRunnableFunction(
6562 "PageLoadPingIdleTask",
6563 [] { mozilla::glean_pings::Pageload
.Submit("threshold"_ns
); }),
6564 EventQueuePriority::Idle
));
6565 sPageLoadEventCounter
= 0;
6571 //////////////////////////////////////////////////////////////////
6572 // PURLClassifierParent
6574 PURLClassifierParent
* ContentParent::AllocPURLClassifierParent(
6575 nsIPrincipal
* aPrincipal
, bool* aSuccess
) {
6576 MOZ_ASSERT(NS_IsMainThread());
6579 RefPtr
<URLClassifierParent
> actor
= new URLClassifierParent();
6580 return actor
.forget().take();
6583 mozilla::ipc::IPCResult
ContentParent::RecvPURLClassifierConstructor(
6584 PURLClassifierParent
* aActor
, nsIPrincipal
* aPrincipal
, bool* aSuccess
) {
6585 MOZ_ASSERT(NS_IsMainThread());
6589 auto* actor
= static_cast<URLClassifierParent
*>(aActor
);
6590 nsCOMPtr
<nsIPrincipal
> principal(aPrincipal
);
6592 actor
->ClassificationFailed();
6595 if (!ValidatePrincipal(aPrincipal
)) {
6596 LogAndAssertFailedPrincipalValidationInfo(aPrincipal
, __func__
);
6598 return actor
->StartClassify(principal
, aSuccess
);
6601 bool ContentParent::DeallocPURLClassifierParent(PURLClassifierParent
* aActor
) {
6602 MOZ_ASSERT(NS_IsMainThread());
6605 RefPtr
<URLClassifierParent
> actor
=
6606 dont_AddRef(static_cast<URLClassifierParent
*>(aActor
));
6610 //////////////////////////////////////////////////////////////////
6611 // PURLClassifierLocalParent
6613 PURLClassifierLocalParent
* ContentParent::AllocPURLClassifierLocalParent(
6614 nsIURI
* aURI
, const nsTArray
<IPCURLClassifierFeature
>& aFeatures
) {
6615 MOZ_ASSERT(NS_IsMainThread());
6617 RefPtr
<URLClassifierLocalParent
> actor
= new URLClassifierLocalParent();
6618 return actor
.forget().take();
6621 mozilla::ipc::IPCResult
ContentParent::RecvPURLClassifierLocalConstructor(
6622 PURLClassifierLocalParent
* aActor
, nsIURI
* aURI
,
6623 nsTArray
<IPCURLClassifierFeature
>&& aFeatures
) {
6624 MOZ_ASSERT(NS_IsMainThread());
6627 nsTArray
<IPCURLClassifierFeature
> features
= std::move(aFeatures
);
6630 return IPC_FAIL(this, "aURI should not be null");
6633 auto* actor
= static_cast<URLClassifierLocalParent
*>(aActor
);
6634 return actor
->StartClassify(aURI
, features
);
6637 bool ContentParent::DeallocPURLClassifierLocalParent(
6638 PURLClassifierLocalParent
* aActor
) {
6639 MOZ_ASSERT(NS_IsMainThread());
6642 RefPtr
<URLClassifierLocalParent
> actor
=
6643 dont_AddRef(static_cast<URLClassifierLocalParent
*>(aActor
));
6647 PSessionStorageObserverParent
*
6648 ContentParent::AllocPSessionStorageObserverParent() {
6649 MOZ_ASSERT(NS_IsMainThread());
6651 return mozilla::dom::AllocPSessionStorageObserverParent();
6654 mozilla::ipc::IPCResult
ContentParent::RecvPSessionStorageObserverConstructor(
6655 PSessionStorageObserverParent
* aActor
) {
6656 MOZ_ASSERT(NS_IsMainThread());
6659 if (!mozilla::dom::RecvPSessionStorageObserverConstructor(aActor
)) {
6660 return IPC_FAIL(this, "RecvPSessionStorageObserverConstructor failed.");
6665 bool ContentParent::DeallocPSessionStorageObserverParent(
6666 PSessionStorageObserverParent
* aActor
) {
6667 MOZ_ASSERT(NS_IsMainThread());
6670 return mozilla::dom::DeallocPSessionStorageObserverParent(aActor
);
6673 mozilla::ipc::IPCResult
ContentParent::RecvBHRThreadHang(
6674 const HangDetails
& aDetails
) {
6675 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
6677 // Copy the HangDetails recieved over the network into a nsIHangDetails, and
6678 // then fire our own observer notification.
6679 // XXX: We should be able to avoid this potentially expensive copy here by
6680 // moving our deserialized argument.
6681 nsCOMPtr
<nsIHangDetails
> hangDetails
=
6682 new nsHangDetails(HangDetails(aDetails
), PersistedToDisk::No
);
6683 obs
->NotifyObservers(hangDetails
, "bhr-thread-hang", nullptr);
6688 mozilla::ipc::IPCResult
ContentParent::RecvAddCertException(
6689 nsIX509Cert
* aCert
, const nsACString
& aHostName
, int32_t aPort
,
6690 const OriginAttributes
& aOriginAttributes
, bool aIsTemporary
,
6691 AddCertExceptionResolver
&& aResolver
) {
6692 nsCOMPtr
<nsICertOverrideService
> overrideService
=
6693 do_GetService(NS_CERTOVERRIDE_CONTRACTID
);
6694 if (!overrideService
) {
6695 aResolver(NS_ERROR_FAILURE
);
6698 nsresult rv
= overrideService
->RememberValidityOverride(
6699 aHostName
, aPort
, aOriginAttributes
, aCert
, aIsTemporary
);
6704 mozilla::ipc::IPCResult
6705 ContentParent::RecvAutomaticStorageAccessPermissionCanBeGranted(
6706 nsIPrincipal
* aPrincipal
,
6707 AutomaticStorageAccessPermissionCanBeGrantedResolver
&& aResolver
) {
6709 return IPC_FAIL(this, "No principal");
6712 if (!ValidatePrincipal(aPrincipal
)) {
6713 LogAndAssertFailedPrincipalValidationInfo(aPrincipal
, __func__
);
6715 aResolver(Document::AutomaticStorageAccessPermissionCanBeGranted(aPrincipal
));
6719 mozilla::ipc::IPCResult
6720 ContentParent::RecvStorageAccessPermissionGrantedForOrigin(
6721 uint64_t aTopLevelWindowId
,
6722 const MaybeDiscarded
<BrowsingContext
>& aParentContext
,
6723 nsIPrincipal
* aTrackingPrincipal
, const nsACString
& aTrackingOrigin
,
6724 const int& aAllowMode
,
6725 const Maybe
<ContentBlockingNotifier::StorageAccessPermissionGrantedReason
>&
6727 const bool& aFrameOnly
,
6728 StorageAccessPermissionGrantedForOriginResolver
&& aResolver
) {
6729 if (aParentContext
.IsNullOrDiscarded()) {
6733 if (!aTrackingPrincipal
) {
6734 return IPC_FAIL(this, "No principal");
6737 // We only report here if we cannot report the console directly in the content
6738 // process. In that case, the `aReason` would be given a value. Otherwise, it
6741 ContentBlockingNotifier::ReportUnblockingToConsole(
6742 aParentContext
.get_canonical(), NS_ConvertUTF8toUTF16(aTrackingOrigin
),
6746 StorageAccessAPIHelper::SaveAccessForOriginOnParentProcess(
6747 aTopLevelWindowId
, aParentContext
.get_canonical(), aTrackingPrincipal
,
6748 aAllowMode
, aFrameOnly
)
6749 ->Then(GetCurrentSerialEventTarget(), __func__
,
6750 [aResolver
= std::move(aResolver
)](
6751 StorageAccessAPIHelper::ParentAccessGrantPromise::
6752 ResolveOrRejectValue
&& aValue
) {
6754 aValue
.IsResolve() && NS_SUCCEEDED(aValue
.ResolveValue());
6760 mozilla::ipc::IPCResult
ContentParent::RecvCompleteAllowAccessFor(
6761 const MaybeDiscarded
<BrowsingContext
>& aParentContext
,
6762 uint64_t aTopLevelWindowId
, nsIPrincipal
* aTrackingPrincipal
,
6763 const nsACString
& aTrackingOrigin
, uint32_t aCookieBehavior
,
6764 const ContentBlockingNotifier::StorageAccessPermissionGrantedReason
&
6766 CompleteAllowAccessForResolver
&& aResolver
) {
6767 if (aParentContext
.IsNullOrDiscarded()) {
6771 StorageAccessAPIHelper::CompleteAllowAccessFor(
6772 aParentContext
.get_canonical(), aTopLevelWindowId
, aTrackingPrincipal
,
6773 aTrackingOrigin
, aCookieBehavior
, aReason
, nullptr)
6774 ->Then(GetCurrentSerialEventTarget(), __func__
,
6775 [aResolver
= std::move(aResolver
)](
6776 StorageAccessAPIHelper::StorageAccessPermissionGrantPromise::
6777 ResolveOrRejectValue
&& aValue
) {
6778 Maybe
<StorageAccessPromptChoices
> choice
;
6779 if (aValue
.IsResolve()) {
6780 choice
.emplace(static_cast<StorageAccessPromptChoices
>(
6781 aValue
.ResolveValue()));
6788 mozilla::ipc::IPCResult
ContentParent::RecvSetAllowStorageAccessRequestFlag(
6789 nsIPrincipal
* aEmbeddedPrincipal
, nsIURI
* aEmbeddingOrigin
,
6790 SetAllowStorageAccessRequestFlagResolver
&& aResolver
) {
6791 MOZ_ASSERT(aEmbeddedPrincipal
);
6792 MOZ_ASSERT(aEmbeddingOrigin
);
6794 if (!aEmbeddedPrincipal
|| !aEmbeddingOrigin
) {
6799 // Get the permission manager and build the key.
6800 RefPtr
<PermissionManager
> permManager
= PermissionManager::GetInstance();
6805 nsCOMPtr
<nsIURI
> embeddedURI
= aEmbeddedPrincipal
->GetURI();
6806 nsCString permissionKey
;
6807 bool success
= AntiTrackingUtils::CreateStorageRequestPermissionKey(
6808 embeddedURI
, permissionKey
);
6814 // Set the permission to ALLOW for a prefence specified amount of seconds.
6815 // Time units are inconsistent, be careful
6816 int64_t when
= (PR_Now() / PR_USEC_PER_MSEC
) +
6817 StaticPrefs::dom_storage_access_forward_declared_lifetime() *
6819 nsCOMPtr
<nsIPrincipal
> principal
= BasePrincipal::CreateContentPrincipal(
6820 aEmbeddingOrigin
, aEmbeddedPrincipal
->OriginAttributesRef());
6821 nsresult rv
= permManager
->AddFromPrincipal(
6822 principal
, permissionKey
, nsIPermissionManager::ALLOW_ACTION
,
6823 nsIPermissionManager::EXPIRE_TIME
, when
);
6824 if (NS_FAILED(rv
)) {
6829 // Resolve with success if we set the permission.
6834 mozilla::ipc::IPCResult
ContentParent::RecvTestAllowStorageAccessRequestFlag(
6835 nsIPrincipal
* aEmbeddingPrincipal
, nsIURI
* aEmbeddedOrigin
,
6836 TestAllowStorageAccessRequestFlagResolver
&& aResolver
) {
6837 MOZ_ASSERT(aEmbeddingPrincipal
);
6838 MOZ_ASSERT(aEmbeddedOrigin
);
6840 // Get the permission manager and build the key.
6841 RefPtr
<PermissionManager
> permManager
= PermissionManager::GetInstance();
6846 nsCString requestPermissionKey
;
6847 bool success
= AntiTrackingUtils::CreateStorageRequestPermissionKey(
6848 aEmbeddedOrigin
, requestPermissionKey
);
6854 // Get the permission and resolve false if it is not set to ALLOW.
6855 uint32_t access
= nsIPermissionManager::UNKNOWN_ACTION
;
6856 nsresult rv
= permManager
->TestPermissionFromPrincipal(
6857 aEmbeddingPrincipal
, requestPermissionKey
, &access
);
6858 if (NS_FAILED(rv
)) {
6862 if (access
!= nsIPermissionManager::ALLOW_ACTION
) {
6867 // Remove the permission, failing if the permission manager fails
6868 rv
= permManager
->RemoveFromPrincipal(aEmbeddingPrincipal
,
6869 requestPermissionKey
);
6870 if (NS_FAILED(rv
)) {
6875 // At this point, signal to our caller that the permission was set
6880 mozilla::ipc::IPCResult
ContentParent::RecvStoreUserInteractionAsPermission(
6881 nsIPrincipal
* aPrincipal
) {
6883 return IPC_FAIL(this, "No principal");
6886 if (!ValidatePrincipal(aPrincipal
)) {
6887 LogAndAssertFailedPrincipalValidationInfo(aPrincipal
, __func__
);
6889 ContentBlockingUserInteraction::Observe(aPrincipal
);
6893 mozilla::ipc::IPCResult
ContentParent::RecvTestCookiePermissionDecided(
6894 const MaybeDiscarded
<BrowsingContext
>& aContext
, nsIPrincipal
* aPrincipal
,
6895 const TestCookiePermissionDecidedResolver
&& aResolver
) {
6896 if (aContext
.IsNullOrDiscarded()) {
6901 return IPC_FAIL(this, "No principal");
6904 RefPtr
<WindowGlobalParent
> wgp
=
6905 aContext
.get_canonical()->GetCurrentWindowGlobal();
6906 nsCOMPtr
<nsICookieJarSettings
> cjs
= wgp
->CookieJarSettings();
6908 Maybe
<bool> result
=
6909 StorageAccessAPIHelper::CheckCookiesPermittedDecidesStorageAccessAPI(
6915 mozilla::ipc::IPCResult
ContentParent::RecvTestStorageAccessPermission(
6916 nsIPrincipal
* aEmbeddingPrincipal
, const nsCString
& aEmbeddedOrigin
,
6917 const TestStorageAccessPermissionResolver
&& aResolver
) {
6918 // Get the permission manager and build the key.
6919 RefPtr
<PermissionManager
> permManager
= PermissionManager::GetInstance();
6921 aResolver(Nothing());
6924 nsCString requestPermissionKey
;
6925 AntiTrackingUtils::CreateStoragePermissionKey(aEmbeddedOrigin
,
6926 requestPermissionKey
);
6928 // Test the permission
6929 uint32_t access
= nsIPermissionManager::UNKNOWN_ACTION
;
6930 nsresult rv
= permManager
->TestPermissionFromPrincipal(
6931 aEmbeddingPrincipal
, requestPermissionKey
, &access
);
6932 if (NS_FAILED(rv
)) {
6933 aResolver(Nothing());
6936 if (access
== nsIPermissionManager::ALLOW_ACTION
) {
6937 aResolver(Some(true));
6938 } else if (access
== nsIPermissionManager::DENY_ACTION
) {
6939 aResolver(Some(false));
6941 aResolver(Nothing());
6947 mozilla::ipc::IPCResult
ContentParent::RecvNotifyMediaPlaybackChanged(
6948 const MaybeDiscarded
<BrowsingContext
>& aContext
,
6949 MediaPlaybackState aState
) {
6950 if (aContext
.IsNullOrDiscarded()) {
6953 if (RefPtr
<IMediaInfoUpdater
> updater
=
6954 aContext
.get_canonical()->GetMediaController()) {
6955 updater
->NotifyMediaPlaybackChanged(aContext
.ContextId(), aState
);
6960 mozilla::ipc::IPCResult
ContentParent::RecvNotifyMediaAudibleChanged(
6961 const MaybeDiscarded
<BrowsingContext
>& aContext
, MediaAudibleState aState
) {
6962 if (aContext
.IsNullOrDiscarded()) {
6965 if (RefPtr
<IMediaInfoUpdater
> updater
=
6966 aContext
.get_canonical()->GetMediaController()) {
6967 updater
->NotifyMediaAudibleChanged(aContext
.ContextId(), aState
);
6972 mozilla::ipc::IPCResult
ContentParent::RecvNotifyPictureInPictureModeChanged(
6973 const MaybeDiscarded
<BrowsingContext
>& aContext
, bool aEnabled
) {
6974 if (aContext
.IsNullOrDiscarded()) {
6977 if (RefPtr
<MediaController
> controller
=
6978 aContext
.get_canonical()->GetMediaController()) {
6979 controller
->SetIsInPictureInPictureMode(aContext
.ContextId(), aEnabled
);
6984 mozilla::ipc::IPCResult
ContentParent::RecvAbortOtherOrientationPendingPromises(
6985 const MaybeDiscarded
<BrowsingContext
>& aContext
) {
6986 if (aContext
.IsNullOrDiscarded()) {
6990 CanonicalBrowsingContext
* context
= aContext
.get_canonical();
6992 context
->Group()->EachOtherParent(this, [&](ContentParent
* aParent
) {
6993 Unused
<< aParent
->SendAbortOrientationPendingPromises(context
);
6999 mozilla::ipc::IPCResult
ContentParent::RecvNotifyMediaSessionUpdated(
7000 const MaybeDiscarded
<BrowsingContext
>& aContext
, bool aIsCreated
) {
7001 if (aContext
.IsNullOrDiscarded()) {
7005 RefPtr
<IMediaInfoUpdater
> updater
=
7006 aContext
.get_canonical()->GetMediaController();
7011 updater
->NotifySessionCreated(aContext
->Id());
7013 updater
->NotifySessionDestroyed(aContext
->Id());
7018 mozilla::ipc::IPCResult
ContentParent::RecvNotifyUpdateMediaMetadata(
7019 const MaybeDiscarded
<BrowsingContext
>& aContext
,
7020 const Maybe
<MediaMetadataBase
>& aMetadata
) {
7021 if (aContext
.IsNullOrDiscarded()) {
7024 if (RefPtr
<IMediaInfoUpdater
> updater
=
7025 aContext
.get_canonical()->GetMediaController()) {
7026 updater
->UpdateMetadata(aContext
.ContextId(), aMetadata
);
7031 mozilla::ipc::IPCResult
7032 ContentParent::RecvNotifyMediaSessionPlaybackStateChanged(
7033 const MaybeDiscarded
<BrowsingContext
>& aContext
,
7034 MediaSessionPlaybackState aPlaybackState
) {
7035 if (aContext
.IsNullOrDiscarded()) {
7038 if (RefPtr
<IMediaInfoUpdater
> updater
=
7039 aContext
.get_canonical()->GetMediaController()) {
7040 updater
->SetDeclaredPlaybackState(aContext
.ContextId(), aPlaybackState
);
7045 mozilla::ipc::IPCResult
7046 ContentParent::RecvNotifyMediaSessionSupportedActionChanged(
7047 const MaybeDiscarded
<BrowsingContext
>& aContext
, MediaSessionAction aAction
,
7049 if (aContext
.IsNullOrDiscarded()) {
7052 RefPtr
<IMediaInfoUpdater
> updater
=
7053 aContext
.get_canonical()->GetMediaController();
7058 updater
->EnableAction(aContext
.ContextId(), aAction
);
7060 updater
->DisableAction(aContext
.ContextId(), aAction
);
7065 mozilla::ipc::IPCResult
ContentParent::RecvNotifyMediaFullScreenState(
7066 const MaybeDiscarded
<BrowsingContext
>& aContext
, bool aIsInFullScreen
) {
7067 if (aContext
.IsNullOrDiscarded()) {
7070 if (RefPtr
<IMediaInfoUpdater
> updater
=
7071 aContext
.get_canonical()->GetMediaController()) {
7072 updater
->NotifyMediaFullScreenState(aContext
.ContextId(), aIsInFullScreen
);
7077 mozilla::ipc::IPCResult
ContentParent::RecvNotifyPositionStateChanged(
7078 const MaybeDiscarded
<BrowsingContext
>& aContext
,
7079 const PositionState
& aState
) {
7080 if (aContext
.IsNullOrDiscarded()) {
7083 if (RefPtr
<IMediaInfoUpdater
> updater
=
7084 aContext
.get_canonical()->GetMediaController()) {
7085 updater
->UpdatePositionState(aContext
.ContextId(), aState
);
7090 mozilla::ipc::IPCResult
ContentParent::RecvAddOrRemovePageAwakeRequest(
7091 const MaybeDiscarded
<BrowsingContext
>& aContext
,
7092 const bool& aShouldAddCount
) {
7093 if (aContext
.IsNullOrDiscarded()) {
7096 if (aShouldAddCount
) {
7097 aContext
.get_canonical()->AddPageAwakeRequest();
7099 aContext
.get_canonical()->RemovePageAwakeRequest();
7105 mozilla::ipc::IPCResult
ContentParent::RecvGetModulesTrust(
7106 ModulePaths
&& aModPaths
, bool aRunAtNormalPriority
,
7107 GetModulesTrustResolver
&& aResolver
) {
7108 RefPtr
<DllServices
> dllSvc(DllServices::Get());
7109 dllSvc
->GetModulesTrust(std::move(aModPaths
), aRunAtNormalPriority
)
7111 GetMainThreadSerialEventTarget(), __func__
,
7112 [aResolver
](ModulesMapResult
&& aResult
) {
7113 aResolver(Some(ModulesMapResult(std::move(aResult
))));
7115 [aResolver
](nsresult aRv
) { aResolver(Nothing()); });
7118 #endif // defined(XP_WIN)
7120 mozilla::ipc::IPCResult
ContentParent::RecvCreateBrowsingContext(
7121 uint64_t aGroupId
, BrowsingContext::IPCInitializer
&& aInit
) {
7122 RefPtr
<WindowGlobalParent
> parent
;
7123 if (aInit
.mParentId
!= 0) {
7124 parent
= WindowGlobalParent::GetByInnerWindowId(aInit
.mParentId
);
7126 return IPC_FAIL(this, "Parent doesn't exist in parent process");
7130 if (parent
&& parent
->GetContentParent() != this) {
7131 // We're trying attach a child BrowsingContext to a parent
7132 // WindowContext in another process. This is illegal since the
7133 // only thing that could create that child BrowsingContext is the parent
7134 // window's process.
7135 return IPC_FAIL(this,
7136 "Must create BrowsingContext from the parent's process");
7139 RefPtr
<BrowsingContext
> opener
;
7140 if (aInit
.GetOpenerId() != 0) {
7141 opener
= BrowsingContext::Get(aInit
.GetOpenerId());
7143 return IPC_FAIL(this, "Opener doesn't exist in parent process");
7147 RefPtr
<BrowsingContext
> child
= BrowsingContext::Get(aInit
.mId
);
7149 // This is highly suspicious. BrowsingContexts should only be created once,
7150 // so finding one indicates that someone is doing something they shouldn't.
7151 return IPC_FAIL(this, "A BrowsingContext with this ID already exists");
7154 // Ensure that the passed-in BrowsingContextGroup is valid.
7155 RefPtr
<BrowsingContextGroup
> group
=
7156 BrowsingContextGroup::GetOrCreate(aGroupId
);
7157 if (parent
&& parent
->Group() != group
) {
7158 if (parent
->Group()->Id() != aGroupId
) {
7159 return IPC_FAIL(this, "Parent has different group ID");
7161 return IPC_FAIL(this, "Parent has different group object");
7164 if (opener
&& opener
->Group() != group
) {
7165 if (opener
->Group()->Id() != aGroupId
) {
7166 return IPC_FAIL(this, "Opener has different group ID");
7168 return IPC_FAIL(this, "Opener has different group object");
7171 if (!parent
&& !opener
&& !group
->Toplevels().IsEmpty()) {
7172 return IPC_FAIL(this, "Unrelated context from child in stale group");
7175 return BrowsingContext::CreateFromIPC(std::move(aInit
), group
, this);
7178 bool ContentParent::CheckBrowsingContextEmbedder(CanonicalBrowsingContext
* aBC
,
7179 const char* aOperation
) const {
7180 if (!aBC
->IsEmbeddedInProcess(ChildID())) {
7181 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning
,
7182 ("ParentIPC: Trying to %s out of process context 0x%08" PRIx64
,
7183 aOperation
, aBC
->Id()));
7189 mozilla::ipc::IPCResult
ContentParent::RecvDiscardBrowsingContext(
7190 const MaybeDiscarded
<BrowsingContext
>& aContext
, bool aDoDiscard
,
7191 DiscardBrowsingContextResolver
&& aResolve
) {
7192 if (CanonicalBrowsingContext
* context
=
7193 CanonicalBrowsingContext::Cast(aContext
.GetMaybeDiscarded())) {
7194 if (aDoDiscard
&& !context
->IsDiscarded()) {
7195 if (!CheckBrowsingContextEmbedder(context
, "discard")) {
7196 return IPC_FAIL(this, "Illegal Discard attempt");
7199 context
->Detach(/* aFromIPC */ true);
7201 context
->AddFinalDiscardListener(aResolve
);
7205 // Resolve the promise, as we've received and handled the message. This will
7206 // allow the content process to fully-discard references to this BC.
7211 void ContentParent::UnregisterRemoveWorkerActor() {
7212 MOZ_ASSERT(NS_IsMainThread());
7215 RecursiveMutexAutoLock
lock(mThreadsafeHandle
->mMutex
);
7216 if (--mThreadsafeHandle
->mRemoteWorkerActorCount
) {
7221 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose
,
7222 ("UnregisterRemoveWorkerActor %p", this));
7223 MaybeBeginShutDown();
7226 mozilla::ipc::IPCResult
ContentParent::RecvWindowClose(
7227 const MaybeDiscarded
<BrowsingContext
>& aContext
, bool aTrustedCaller
) {
7228 if (aContext
.IsNullOrDiscarded()) {
7230 BrowsingContext::GetLog(), LogLevel::Debug
,
7231 ("ParentIPC: Trying to send a message to dead or detached context"));
7234 CanonicalBrowsingContext
* context
= aContext
.get_canonical();
7236 // FIXME Need to check that the sending process has access to the unit of
7238 // browsing contexts of bc.
7240 if (ContentParent
* cp
= context
->GetContentParent()) {
7241 Unused
<< cp
->SendWindowClose(context
, aTrustedCaller
);
7246 mozilla::ipc::IPCResult
ContentParent::RecvWindowFocus(
7247 const MaybeDiscarded
<BrowsingContext
>& aContext
, CallerType aCallerType
,
7248 uint64_t aActionId
) {
7249 if (aContext
.IsNullOrDiscarded()) {
7251 BrowsingContext::GetLog(), LogLevel::Debug
,
7252 ("ParentIPC: Trying to send a message to dead or detached context"));
7255 LOGFOCUS(("ContentParent::RecvWindowFocus actionid: %" PRIu64
, aActionId
));
7256 CanonicalBrowsingContext
* context
= aContext
.get_canonical();
7258 if (ContentParent
* cp
= context
->GetContentParent()) {
7259 Unused
<< cp
->SendWindowFocus(context
, aCallerType
, aActionId
);
7264 mozilla::ipc::IPCResult
ContentParent::RecvWindowBlur(
7265 const MaybeDiscarded
<BrowsingContext
>& aContext
, CallerType aCallerType
) {
7266 if (aContext
.IsNullOrDiscarded()) {
7268 BrowsingContext::GetLog(), LogLevel::Debug
,
7269 ("ParentIPC: Trying to send a message to dead or detached context"));
7272 CanonicalBrowsingContext
* context
= aContext
.get_canonical();
7274 if (ContentParent
* cp
= context
->GetContentParent()) {
7275 Unused
<< cp
->SendWindowBlur(context
, aCallerType
);
7280 mozilla::ipc::IPCResult
ContentParent::RecvRaiseWindow(
7281 const MaybeDiscarded
<BrowsingContext
>& aContext
, CallerType aCallerType
,
7282 uint64_t aActionId
) {
7283 if (aContext
.IsNullOrDiscarded()) {
7285 BrowsingContext::GetLog(), LogLevel::Debug
,
7286 ("ParentIPC: Trying to send a message to dead or detached context"));
7289 LOGFOCUS(("ContentParent::RecvRaiseWindow actionid: %" PRIu64
, aActionId
));
7291 CanonicalBrowsingContext
* context
= aContext
.get_canonical();
7293 if (ContentParent
* cp
= context
->GetContentParent()) {
7294 Unused
<< cp
->SendRaiseWindow(context
, aCallerType
, aActionId
);
7299 mozilla::ipc::IPCResult
ContentParent::RecvAdjustWindowFocus(
7300 const MaybeDiscarded
<BrowsingContext
>& aContext
, bool aIsVisible
,
7301 uint64_t aActionId
) {
7302 if (aContext
.IsNullOrDiscarded()) {
7304 BrowsingContext::GetLog(), LogLevel::Debug
,
7305 ("ParentIPC: Trying to send a message to dead or detached context"));
7309 ("ContentParent::RecvAdjustWindowFocus isVisible %d actionid: %" PRIu64
,
7310 aIsVisible
, aActionId
));
7312 nsTHashMap
<nsPtrHashKey
<ContentParent
>, bool> processes(2);
7313 processes
.InsertOrUpdate(this, true);
7315 ContentProcessManager
* cpm
= ContentProcessManager::GetSingleton();
7317 CanonicalBrowsingContext
* context
= aContext
.get_canonical();
7319 BrowsingContext
* parent
= context
->GetParent();
7324 CanonicalBrowsingContext
* canonicalParent
= parent
->Canonical();
7325 ContentParent
* cp
= cpm
->GetContentProcessById(
7326 ContentParentId(canonicalParent
->OwnerProcessId()));
7327 if (cp
&& !processes
.Get(cp
)) {
7328 Unused
<< cp
->SendAdjustWindowFocus(context
, aIsVisible
, aActionId
);
7329 processes
.InsertOrUpdate(cp
, true);
7331 context
= canonicalParent
;
7337 mozilla::ipc::IPCResult
ContentParent::RecvClearFocus(
7338 const MaybeDiscarded
<BrowsingContext
>& aContext
) {
7339 if (aContext
.IsNullOrDiscarded()) {
7341 BrowsingContext::GetLog(), LogLevel::Debug
,
7342 ("ParentIPC: Trying to send a message to dead or detached context"));
7345 CanonicalBrowsingContext
* context
= aContext
.get_canonical();
7347 if (ContentParent
* cp
= context
->GetContentParent()) {
7348 Unused
<< cp
->SendClearFocus(context
);
7353 mozilla::ipc::IPCResult
ContentParent::RecvSetFocusedBrowsingContext(
7354 const MaybeDiscarded
<BrowsingContext
>& aContext
, uint64_t aActionId
) {
7355 if (aContext
.IsNullOrDiscarded()) {
7357 BrowsingContext::GetLog(), LogLevel::Debug
,
7358 ("ParentIPC: Trying to send a message to dead or detached context"));
7361 LOGFOCUS(("ContentParent::RecvSetFocusedBrowsingContext actionid: %" PRIu64
,
7363 CanonicalBrowsingContext
* context
= aContext
.get_canonical();
7365 nsFocusManager
* fm
= nsFocusManager::GetFocusManager();
7370 if (!fm
->SetFocusedBrowsingContextInChrome(context
, aActionId
)) {
7372 "Ignoring out-of-sequence attempt [%p] to set focused browsing context "
7375 Unused
<< SendReviseFocusedBrowsingContext(
7376 aActionId
, fm
->GetFocusedBrowsingContextInChrome(),
7377 fm
->GetActionIdForFocusedBrowsingContextInChrome());
7381 BrowserParent::UpdateFocusFromBrowsingContext();
7383 context
->Group()->EachOtherParent(this, [&](ContentParent
* aParent
) {
7384 Unused
<< aParent
->SendSetFocusedBrowsingContext(context
, aActionId
);
7390 mozilla::ipc::IPCResult
ContentParent::RecvSetActiveBrowsingContext(
7391 const MaybeDiscarded
<BrowsingContext
>& aContext
, uint64_t aActionId
) {
7392 if (aContext
.IsNullOrDiscarded()) {
7394 BrowsingContext::GetLog(), LogLevel::Debug
,
7395 ("ParentIPC: Trying to send a message to dead or detached context"));
7398 LOGFOCUS(("ContentParent::RecvSetActiveBrowsingContext actionid: %" PRIu64
,
7400 CanonicalBrowsingContext
* context
= aContext
.get_canonical();
7402 nsFocusManager
* fm
= nsFocusManager::GetFocusManager();
7407 if (!fm
->SetActiveBrowsingContextInChrome(context
, aActionId
)) {
7409 ("Ignoring out-of-sequence attempt [%p] to set active browsing context "
7412 Unused
<< SendReviseActiveBrowsingContext(
7413 aActionId
, fm
->GetActiveBrowsingContextInChrome(),
7414 fm
->GetActionIdForActiveBrowsingContextInChrome());
7418 context
->Group()->EachOtherParent(this, [&](ContentParent
* aParent
) {
7419 Unused
<< aParent
->SendSetActiveBrowsingContext(context
, aActionId
);
7425 mozilla::ipc::IPCResult
ContentParent::RecvUnsetActiveBrowsingContext(
7426 const MaybeDiscarded
<BrowsingContext
>& aContext
, uint64_t aActionId
) {
7427 if (aContext
.IsNullOrDiscarded()) {
7429 BrowsingContext::GetLog(), LogLevel::Debug
,
7430 ("ParentIPC: Trying to send a message to dead or detached context"));
7433 LOGFOCUS(("ContentParent::RecvUnsetActiveBrowsingContext actionid: %" PRIu64
,
7435 CanonicalBrowsingContext
* context
= aContext
.get_canonical();
7437 nsFocusManager
* fm
= nsFocusManager::GetFocusManager();
7442 if (!fm
->SetActiveBrowsingContextInChrome(nullptr, aActionId
)) {
7444 ("Ignoring out-of-sequence attempt to unset active browsing context in "
7447 Unused
<< SendReviseActiveBrowsingContext(
7448 aActionId
, fm
->GetActiveBrowsingContextInChrome(),
7449 fm
->GetActionIdForActiveBrowsingContextInChrome());
7453 context
->Group()->EachOtherParent(this, [&](ContentParent
* aParent
) {
7454 Unused
<< aParent
->SendUnsetActiveBrowsingContext(context
, aActionId
);
7460 mozilla::ipc::IPCResult
ContentParent::RecvSetFocusedElement(
7461 const MaybeDiscarded
<BrowsingContext
>& aContext
, bool aNeedsFocus
) {
7462 if (aContext
.IsNullOrDiscarded()) {
7464 BrowsingContext::GetLog(), LogLevel::Debug
,
7465 ("ParentIPC: Trying to send a message to dead or detached context"));
7468 LOGFOCUS(("ContentParent::RecvSetFocusedElement"));
7469 CanonicalBrowsingContext
* context
= aContext
.get_canonical();
7471 if (ContentParent
* cp
= context
->GetContentParent()) {
7472 Unused
<< cp
->SendSetFocusedElement(context
, aNeedsFocus
);
7477 mozilla::ipc::IPCResult
ContentParent::RecvFinalizeFocusOuter(
7478 const MaybeDiscarded
<BrowsingContext
>& aContext
, bool aCanFocus
,
7479 CallerType aCallerType
) {
7480 if (aContext
.IsNullOrDiscarded()) {
7482 BrowsingContext::GetLog(), LogLevel::Debug
,
7483 ("ParentIPC: Trying to send a message to dead or detached context"));
7486 LOGFOCUS(("ContentParent::RecvFinalizeFocusOuter"));
7487 CanonicalBrowsingContext
* context
= aContext
.get_canonical();
7488 ContentProcessManager
* cpm
= ContentProcessManager::GetSingleton();
7490 ContentParent
* cp
= cpm
->GetContentProcessById(
7491 ContentParentId(context
->EmbedderProcessId()));
7493 Unused
<< cp
->SendFinalizeFocusOuter(context
, aCanFocus
, aCallerType
);
7499 mozilla::ipc::IPCResult
ContentParent::RecvInsertNewFocusActionId(
7500 uint64_t aActionId
) {
7501 LOGFOCUS(("ContentParent::RecvInsertNewFocusActionId actionid: %" PRIu64
,
7503 nsFocusManager
* fm
= nsFocusManager::GetFocusManager();
7505 fm
->InsertNewFocusActionId(aActionId
);
7510 mozilla::ipc::IPCResult
ContentParent::RecvBlurToParent(
7511 const MaybeDiscarded
<BrowsingContext
>& aFocusedBrowsingContext
,
7512 const MaybeDiscarded
<BrowsingContext
>& aBrowsingContextToClear
,
7513 const MaybeDiscarded
<BrowsingContext
>& aAncestorBrowsingContextToFocus
,
7514 bool aIsLeavingDocument
, bool aAdjustWidget
,
7515 bool aBrowsingContextToClearHandled
,
7516 bool aAncestorBrowsingContextToFocusHandled
, uint64_t aActionId
) {
7517 if (aFocusedBrowsingContext
.IsNullOrDiscarded()) {
7519 BrowsingContext::GetLog(), LogLevel::Debug
,
7520 ("ParentIPC: Trying to send a message to dead or detached context"));
7525 ("ContentParent::RecvBlurToParent isLeavingDocument %d adjustWidget %d "
7526 "browsingContextToClearHandled %d ancestorBrowsingContextToFocusHandled "
7527 "%d actionid: %" PRIu64
,
7528 aIsLeavingDocument
, aAdjustWidget
, aBrowsingContextToClearHandled
,
7529 aAncestorBrowsingContextToFocusHandled
, aActionId
));
7531 CanonicalBrowsingContext
* focusedBrowsingContext
=
7532 aFocusedBrowsingContext
.get_canonical();
7534 // If aBrowsingContextToClear and aAncestorBrowsingContextToFocusHandled
7535 // didn't get handled in the process that sent this IPC message and they
7536 // aren't in the same process as aFocusedBrowsingContext, we need to split
7537 // off their handling here and use SendSetFocusedElement to send them
7538 // elsewhere than the blurring itself.
7540 bool ancestorDifferent
=
7541 (!aAncestorBrowsingContextToFocusHandled
&&
7542 !aAncestorBrowsingContextToFocus
.IsNullOrDiscarded() &&
7543 (focusedBrowsingContext
->OwnerProcessId() !=
7544 aAncestorBrowsingContextToFocus
.get_canonical()->OwnerProcessId()));
7545 if (!aBrowsingContextToClearHandled
&&
7546 !aBrowsingContextToClear
.IsNullOrDiscarded() &&
7547 (focusedBrowsingContext
->OwnerProcessId() !=
7548 aBrowsingContextToClear
.get_canonical()->OwnerProcessId())) {
7549 MOZ_RELEASE_ASSERT(!ancestorDifferent
,
7550 "This combination is not supposed to happen.");
7551 if (ContentParent
* cp
=
7552 aBrowsingContextToClear
.get_canonical()->GetContentParent()) {
7553 Unused
<< cp
->SendSetFocusedElement(aBrowsingContextToClear
, false);
7555 } else if (ancestorDifferent
) {
7556 if (ContentParent
* cp
= aAncestorBrowsingContextToFocus
.get_canonical()
7557 ->GetContentParent()) {
7558 Unused
<< cp
->SendSetFocusedElement(aAncestorBrowsingContextToFocus
,
7563 if (ContentParent
* cp
= focusedBrowsingContext
->GetContentParent()) {
7564 Unused
<< cp
->SendBlurToChild(aFocusedBrowsingContext
,
7565 aBrowsingContextToClear
,
7566 aAncestorBrowsingContextToFocus
,
7567 aIsLeavingDocument
, aAdjustWidget
, aActionId
);
7573 mozilla::ipc::IPCResult
ContentParent::RecvMaybeExitFullscreen(
7574 const MaybeDiscarded
<BrowsingContext
>& aContext
) {
7575 if (aContext
.IsNullOrDiscarded()) {
7577 BrowsingContext::GetLog(), LogLevel::Debug
,
7578 ("ParentIPC: Trying to send a message to dead or detached context"));
7581 CanonicalBrowsingContext
* context
= aContext
.get_canonical();
7583 if (ContentParent
* cp
= context
->GetContentParent()) {
7584 Unused
<< cp
->SendMaybeExitFullscreen(context
);
7590 mozilla::ipc::IPCResult
ContentParent::RecvWindowPostMessage(
7591 const MaybeDiscarded
<BrowsingContext
>& aContext
,
7592 const ClonedOrErrorMessageData
& aMessage
, const PostMessageData
& aData
) {
7593 if (aContext
.IsNullOrDiscarded()) {
7595 BrowsingContext::GetLog(), LogLevel::Debug
,
7596 ("ParentIPC: Trying to send a message to dead or detached context"));
7599 CanonicalBrowsingContext
* context
= aContext
.get_canonical();
7601 if (aData
.source().IsDiscarded()) {
7603 BrowsingContext::GetLog(), LogLevel::Debug
,
7604 ("ParentIPC: Trying to send a message from dead or detached context"));
7608 RefPtr
<ContentParent
> cp
= context
->GetContentParent();
7610 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug
,
7611 ("ParentIPC: Trying to send PostMessage to dead content process"));
7615 ClonedOrErrorMessageData message
;
7616 StructuredCloneData messageFromChild
;
7617 if (aMessage
.type() == ClonedOrErrorMessageData::TClonedMessageData
) {
7618 UnpackClonedMessageData(aMessage
, messageFromChild
);
7620 ClonedMessageData clonedMessageData
;
7621 if (BuildClonedMessageData(messageFromChild
, clonedMessageData
)) {
7622 message
= std::move(clonedMessageData
);
7625 message
= ErrorMessageData();
7628 MOZ_ASSERT(aMessage
.type() == ClonedOrErrorMessageData::TErrorMessageData
);
7629 message
= ErrorMessageData();
7632 Unused
<< cp
->SendWindowPostMessage(context
, message
, aData
);
7636 void ContentParent::AddBrowsingContextGroup(BrowsingContextGroup
* aGroup
) {
7637 MOZ_DIAGNOSTIC_ASSERT(aGroup
);
7638 // Ensure that the group has been inserted, and if we're not launching
7639 // anymore, also begin subscribing. Launching processes will be subscribed if
7640 // they finish launching in `LaunchSubprocessResolve`.
7641 if (mGroups
.EnsureInserted(aGroup
) && !IsLaunching()) {
7642 aGroup
->Subscribe(this);
7646 void ContentParent::RemoveBrowsingContextGroup(BrowsingContextGroup
* aGroup
) {
7647 MOZ_DIAGNOSTIC_ASSERT(aGroup
);
7648 // Remove the group from our list. This is called from the
7649 // BrowsingContextGroup when unsubscribing, so we don't need to do it here.
7650 if (mGroups
.EnsureRemoved(aGroup
) && CanSend()) {
7651 // If we're removing the entry for the first time, tell the content process
7652 // to clean up the group.
7653 Unused
<< SendDestroyBrowsingContextGroup(aGroup
->Id());
7657 mozilla::ipc::IPCResult
ContentParent::RecvCommitBrowsingContextTransaction(
7658 const MaybeDiscarded
<BrowsingContext
>& aContext
,
7659 BrowsingContext::BaseTransaction
&& aTransaction
, uint64_t aEpoch
) {
7660 // Record the new BrowsingContextFieldEpoch associated with this transaction.
7661 // This should be done unconditionally, so that we're always in-sync.
7663 // The order the parent process receives transactions is considered the
7664 // "canonical" ordering, so we don't need to worry about doing any
7665 // epoch-related validation.
7666 MOZ_ASSERT(aEpoch
== mBrowsingContextFieldEpoch
+ 1,
7667 "Child process skipped an epoch?");
7668 mBrowsingContextFieldEpoch
= aEpoch
;
7670 return aTransaction
.CommitFromIPC(aContext
, this);
7673 mozilla::ipc::IPCResult
ContentParent::RecvBlobURLDataRequest(
7674 const nsACString
& aBlobURL
, nsIPrincipal
* aTriggeringPrincipal
,
7675 nsIPrincipal
* aLoadingPrincipal
, const OriginAttributes
& aOriginAttributes
,
7676 uint64_t aInnerWindowId
, const nsCString
& aPartitionKey
,
7677 BlobURLDataRequestResolver
&& aResolver
) {
7678 RefPtr
<BlobImpl
> blobImpl
;
7680 // Since revoked blobs are also retrieved, it is possible that the blob no
7681 // longer exists (due to the 5 second timeout) when execution reaches here
7682 if (!BlobURLProtocolHandler::GetDataEntry(
7683 aBlobURL
, getter_AddRefs(blobImpl
), aLoadingPrincipal
,
7684 aTriggeringPrincipal
, aOriginAttributes
, aInnerWindowId
,
7685 aPartitionKey
, true /* AlsoIfRevoked */)) {
7686 aResolver(NS_ERROR_DOM_BAD_URI
);
7691 nsresult rv
= IPCBlobUtils::Serialize(blobImpl
, ipcBlob
);
7693 if (NS_WARN_IF(NS_FAILED(rv
))) {
7702 mozilla::ipc::IPCResult
ContentParent::RecvReportServiceWorkerShutdownProgress(
7703 uint32_t aShutdownStateId
, ServiceWorkerShutdownState::Progress aProgress
) {
7704 RefPtr
<ServiceWorkerManager
> swm
= ServiceWorkerManager::GetInstance();
7705 MOZ_RELEASE_ASSERT(swm
, "ServiceWorkers should shutdown before SWM.");
7707 swm
->ReportServiceWorkerShutdownProgress(aShutdownStateId
, aProgress
);
7712 mozilla::ipc::IPCResult
ContentParent::RecvNotifyOnHistoryReload(
7713 const MaybeDiscarded
<BrowsingContext
>& aContext
, const bool& aForceReload
,
7714 NotifyOnHistoryReloadResolver
&& aResolver
) {
7715 bool canReload
= false;
7716 Maybe
<NotNull
<RefPtr
<nsDocShellLoadState
>>> loadState
;
7717 Maybe
<bool> reloadActiveEntry
;
7718 if (!aContext
.IsNullOrDiscarded()) {
7719 aContext
.get_canonical()->NotifyOnHistoryReload(
7720 aForceReload
, canReload
, loadState
, reloadActiveEntry
);
7723 std::tuple
<const bool&,
7724 const Maybe
<NotNull
<RefPtr
<nsDocShellLoadState
>>>&,
7725 const Maybe
<bool>&>(canReload
, loadState
, reloadActiveEntry
));
7729 mozilla::ipc::IPCResult
ContentParent::RecvHistoryCommit(
7730 const MaybeDiscarded
<BrowsingContext
>& aContext
, const uint64_t& aLoadID
,
7731 const nsID
& aChangeID
, const uint32_t& aLoadType
, const bool& aPersist
,
7732 const bool& aCloneEntryChildren
, const bool& aChannelExpired
,
7733 const uint32_t& aCacheKey
) {
7734 if (!aContext
.IsDiscarded()) {
7735 CanonicalBrowsingContext
* canonical
= aContext
.get_canonical();
7738 this, "Could not get canonical. aContext.get_canonical() fails.");
7740 canonical
->SessionHistoryCommit(aLoadID
, aChangeID
, aLoadType
, aPersist
,
7741 aCloneEntryChildren
, aChannelExpired
,
7747 mozilla::ipc::IPCResult
ContentParent::RecvHistoryGo(
7748 const MaybeDiscarded
<BrowsingContext
>& aContext
, int32_t aOffset
,
7749 uint64_t aHistoryEpoch
, bool aRequireUserInteraction
, bool aUserActivation
,
7750 HistoryGoResolver
&& aResolveRequestedIndex
) {
7751 if (!aContext
.IsNullOrDiscarded()) {
7752 RefPtr
<CanonicalBrowsingContext
> canonical
= aContext
.get_canonical();
7753 aResolveRequestedIndex(
7754 canonical
->HistoryGo(aOffset
, aHistoryEpoch
, aRequireUserInteraction
,
7755 aUserActivation
, Some(ChildID())));
7760 mozilla::ipc::IPCResult
ContentParent::RecvSynchronizeLayoutHistoryState(
7761 const MaybeDiscarded
<BrowsingContext
>& aContext
,
7762 nsILayoutHistoryState
* aState
) {
7763 if (aContext
.IsNull()) {
7767 BrowsingContext
* bc
= aContext
.GetMaybeDiscarded();
7771 SessionHistoryEntry
* entry
= bc
->Canonical()->GetActiveSessionHistoryEntry();
7773 entry
->SetLayoutHistoryState(aState
);
7778 mozilla::ipc::IPCResult
ContentParent::RecvSessionHistoryEntryTitle(
7779 const MaybeDiscarded
<BrowsingContext
>& aContext
, const nsAString
& aTitle
) {
7780 if (aContext
.IsNullOrDiscarded()) {
7784 SessionHistoryEntry
* entry
=
7785 aContext
.get_canonical()->GetActiveSessionHistoryEntry();
7787 entry
->SetTitle(aTitle
);
7792 mozilla::ipc::IPCResult
7793 ContentParent::RecvSessionHistoryEntryScrollRestorationIsManual(
7794 const MaybeDiscarded
<BrowsingContext
>& aContext
, const bool& aIsManual
) {
7795 if (aContext
.IsNullOrDiscarded()) {
7799 SessionHistoryEntry
* entry
=
7800 aContext
.get_canonical()->GetActiveSessionHistoryEntry();
7802 entry
->SetScrollRestorationIsManual(aIsManual
);
7807 mozilla::ipc::IPCResult
ContentParent::RecvSessionHistoryEntryScrollPosition(
7808 const MaybeDiscarded
<BrowsingContext
>& aContext
, const int32_t& aX
,
7809 const int32_t& aY
) {
7810 if (aContext
.IsNullOrDiscarded()) {
7814 SessionHistoryEntry
* entry
=
7815 aContext
.get_canonical()->GetActiveSessionHistoryEntry();
7817 entry
->SetScrollPosition(aX
, aY
);
7822 mozilla::ipc::IPCResult
7823 ContentParent::RecvSessionHistoryEntryStoreWindowNameInContiguousEntries(
7824 const MaybeDiscarded
<BrowsingContext
>& aContext
, const nsAString
& aName
) {
7825 if (aContext
.IsNullOrDiscarded()) {
7829 // Per https://html.spec.whatwg.org/#history-traversal 4.2.1, we need to set
7830 // the name to all contiguous entries. This has to be called before
7831 // CanonicalBrowsingContext::SessionHistoryCommit(), so the active entry is
7832 // still the old entry that we want to set.
7834 SessionHistoryEntry
* entry
=
7835 aContext
.get_canonical()->GetActiveSessionHistoryEntry();
7838 nsSHistory::WalkContiguousEntries(
7839 entry
, [&](nsISHEntry
* aEntry
) { aEntry
->SetName(aName
); });
7845 mozilla::ipc::IPCResult
ContentParent::RecvSessionHistoryEntryCacheKey(
7846 const MaybeDiscarded
<BrowsingContext
>& aContext
,
7847 const uint32_t& aCacheKey
) {
7848 if (aContext
.IsNullOrDiscarded()) {
7852 SessionHistoryEntry
* entry
=
7853 aContext
.get_canonical()->GetActiveSessionHistoryEntry();
7855 entry
->SetCacheKey(aCacheKey
);
7860 mozilla::ipc::IPCResult
ContentParent::RecvSessionHistoryEntryWireframe(
7861 const MaybeDiscarded
<BrowsingContext
>& aContext
,
7862 const Wireframe
& aWireframe
) {
7863 if (aContext
.IsNull()) {
7867 BrowsingContext
* bc
= aContext
.GetMaybeDiscarded();
7872 SessionHistoryEntry
* entry
= bc
->Canonical()->GetActiveSessionHistoryEntry();
7874 entry
->SetWireframe(Some(aWireframe
));
7879 mozilla::ipc::IPCResult
7880 ContentParent::RecvGetLoadingSessionHistoryInfoFromParent(
7881 const MaybeDiscarded
<BrowsingContext
>& aContext
,
7882 GetLoadingSessionHistoryInfoFromParentResolver
&& aResolver
) {
7883 if (aContext
.IsNullOrDiscarded()) {
7887 Maybe
<LoadingSessionHistoryInfo
> info
;
7888 aContext
.get_canonical()->GetLoadingSessionHistoryInfoFromParent(info
);
7894 mozilla::ipc::IPCResult
ContentParent::RecvRemoveFromBFCache(
7895 const MaybeDiscarded
<BrowsingContext
>& aContext
) {
7896 if (aContext
.IsNullOrDiscarded()) {
7900 nsCOMPtr
<nsFrameLoaderOwner
> owner
=
7901 do_QueryInterface(aContext
.get_canonical()->GetEmbedderElement());
7906 RefPtr
<nsFrameLoader
> frameLoader
= owner
->GetFrameLoader();
7907 if (!frameLoader
|| !frameLoader
->GetMaybePendingBrowsingContext()) {
7911 nsCOMPtr
<nsISHistory
> shistory
= frameLoader
->GetMaybePendingBrowsingContext()
7913 ->GetSessionHistory();
7918 uint32_t count
= shistory
->GetCount();
7919 for (uint32_t i
= 0; i
< count
; ++i
) {
7920 nsCOMPtr
<nsISHEntry
> entry
;
7921 shistory
->GetEntryAtIndex(i
, getter_AddRefs(entry
));
7922 nsCOMPtr
<SessionHistoryEntry
> she
= do_QueryInterface(entry
);
7924 if (RefPtr
<nsFrameLoader
> frameLoader
= she
->GetFrameLoader()) {
7925 if (frameLoader
->GetMaybePendingBrowsingContext() == aContext
.get()) {
7926 she
->SetFrameLoader(nullptr);
7927 frameLoader
->Destroy();
7937 mozilla::ipc::IPCResult
ContentParent::RecvSetActiveSessionHistoryEntry(
7938 const MaybeDiscarded
<BrowsingContext
>& aContext
,
7939 const Maybe
<nsPoint
>& aPreviousScrollPos
, SessionHistoryInfo
&& aInfo
,
7940 uint32_t aLoadType
, uint32_t aUpdatedCacheKey
, const nsID
& aChangeID
) {
7941 if (!aContext
.IsNullOrDiscarded()) {
7942 aContext
.get_canonical()->SetActiveSessionHistoryEntry(
7943 aPreviousScrollPos
, &aInfo
, aLoadType
, aUpdatedCacheKey
, aChangeID
);
7948 mozilla::ipc::IPCResult
ContentParent::RecvReplaceActiveSessionHistoryEntry(
7949 const MaybeDiscarded
<BrowsingContext
>& aContext
,
7950 SessionHistoryInfo
&& aInfo
) {
7951 if (!aContext
.IsNullOrDiscarded()) {
7952 aContext
.get_canonical()->ReplaceActiveSessionHistoryEntry(&aInfo
);
7957 mozilla::ipc::IPCResult
7958 ContentParent::RecvRemoveDynEntriesFromActiveSessionHistoryEntry(
7959 const MaybeDiscarded
<BrowsingContext
>& aContext
) {
7960 if (!aContext
.IsNullOrDiscarded()) {
7961 aContext
.get_canonical()->RemoveDynEntriesFromActiveSessionHistoryEntry();
7966 mozilla::ipc::IPCResult
ContentParent::RecvRemoveFromSessionHistory(
7967 const MaybeDiscarded
<BrowsingContext
>& aContext
, const nsID
& aChangeID
) {
7968 if (!aContext
.IsNullOrDiscarded()) {
7969 aContext
.get_canonical()->RemoveFromSessionHistory(aChangeID
);
7974 mozilla::ipc::IPCResult
ContentParent::RecvHistoryReload(
7975 const MaybeDiscarded
<BrowsingContext
>& aContext
,
7976 const uint32_t aReloadFlags
) {
7977 if (!aContext
.IsNullOrDiscarded()) {
7978 nsCOMPtr
<nsISHistory
> shistory
=
7979 aContext
.get_canonical()->GetSessionHistory();
7981 shistory
->Reload(aReloadFlags
);
7987 mozilla::ipc::IPCResult
ContentParent::RecvCommitWindowContextTransaction(
7988 const MaybeDiscarded
<WindowContext
>& aContext
,
7989 WindowContext::BaseTransaction
&& aTransaction
, uint64_t aEpoch
) {
7990 // Record the new BrowsingContextFieldEpoch associated with this transaction.
7991 // This should be done unconditionally, so that we're always in-sync.
7993 // The order the parent process receives transactions is considered the
7994 // "canonical" ordering, so we don't need to worry about doing any
7995 // epoch-related validation.
7996 MOZ_ASSERT(aEpoch
== mBrowsingContextFieldEpoch
+ 1,
7997 "Child process skipped an epoch?");
7998 mBrowsingContextFieldEpoch
= aEpoch
;
8000 return aTransaction
.CommitFromIPC(aContext
, this);
8003 NS_IMETHODIMP
ContentParent::GetChildID(uint64_t* aOut
) {
8004 *aOut
= this->ChildID();
8008 NS_IMETHODIMP
ContentParent::GetOsPid(int32_t* aOut
) {
8013 NS_IMETHODIMP
ContentParent::GetRemoteType(nsACString
& aRemoteType
) {
8014 aRemoteType
= GetRemoteType();
8018 IPCResult
ContentParent::RecvRawMessage(
8019 const JSActorMessageMeta
& aMeta
, const Maybe
<ClonedMessageData
>& aData
,
8020 const Maybe
<ClonedMessageData
>& aStack
) {
8021 Maybe
<StructuredCloneData
> data
;
8024 data
->BorrowFromClonedMessageData(*aData
);
8026 Maybe
<StructuredCloneData
> stack
;
8029 stack
->BorrowFromClonedMessageData(*aStack
);
8031 ReceiveRawMessage(aMeta
, std::move(data
), std::move(stack
));
8035 NS_IMETHODIMP
ContentParent::GetActor(const nsACString
& aName
, JSContext
* aCx
,
8036 JSProcessActorParent
** retval
) {
8038 RefPtr
<JSProcessActorParent
> actor
=
8039 JSActorManager::GetActor(aCx
, aName
, error
)
8040 .downcast
<JSProcessActorParent
>();
8041 if (error
.MaybeSetPendingException(aCx
)) {
8042 return NS_ERROR_FAILURE
;
8044 actor
.forget(retval
);
8048 NS_IMETHODIMP
ContentParent::GetExistingActor(const nsACString
& aName
,
8049 JSProcessActorParent
** retval
) {
8050 RefPtr
<JSProcessActorParent
> actor
=
8051 JSActorManager::GetExistingActor(aName
).downcast
<JSProcessActorParent
>();
8052 actor
.forget(retval
);
8056 already_AddRefed
<JSActor
> ContentParent::InitJSActor(
8057 JS::Handle
<JSObject
*> aMaybeActor
, const nsACString
& aName
,
8059 RefPtr
<JSProcessActorParent
> actor
;
8060 if (aMaybeActor
.get()) {
8061 aRv
= UNWRAP_OBJECT(JSProcessActorParent
, aMaybeActor
.get(), actor
);
8066 actor
= new JSProcessActorParent();
8069 MOZ_RELEASE_ASSERT(!actor
->Manager(),
8070 "mManager was already initialized once!");
8071 actor
->Init(aName
, this);
8072 return actor
.forget();
8075 IPCResult
ContentParent::RecvFOGData(ByteBuf
&& buf
) {
8076 glean::FOGData(std::move(buf
));
8080 mozilla::ipc::IPCResult
ContentParent::RecvSetContainerFeaturePolicy(
8081 const MaybeDiscardedBrowsingContext
& aContainerContext
,
8082 FeaturePolicy
* aContainerFeaturePolicy
) {
8083 if (aContainerContext
.IsNullOrDiscarded()) {
8087 auto* context
= aContainerContext
.get_canonical();
8088 context
->SetContainerFeaturePolicy(aContainerFeaturePolicy
);
8093 NS_IMETHODIMP
ContentParent::GetCanSend(bool* aCanSend
) {
8094 *aCanSend
= CanSend();
8098 ContentParent
* ContentParent::AsContentParent() { return this; }
8100 JSActorManager
* ContentParent::AsJSActorManager() { return this; }
8102 IPCResult
ContentParent::RecvGetSystemIcon(nsIURI
* aURI
,
8103 GetSystemIconResolver
&& aResolver
) {
8104 using ResolverArgs
= std::tuple
<const nsresult
&, mozilla::Maybe
<ByteBuf
>&&>;
8107 Maybe
<ByteBuf
> bytebuf
= Nothing();
8108 aResolver(ResolverArgs(NS_ERROR_NULL_POINTER
, std::move(bytebuf
)));
8112 #if defined(MOZ_WIDGET_GTK)
8113 Maybe
<ByteBuf
> bytebuf
= Some(ByteBuf
{});
8114 nsresult rv
= nsIconChannel::GetIcon(aURI
, bytebuf
.ptr());
8115 if (NS_WARN_IF(NS_FAILED(rv
))) {
8116 bytebuf
= Nothing();
8118 aResolver(ResolverArgs(rv
, std::move(bytebuf
)));
8120 #elif defined(XP_WIN)
8121 nsIconChannel::GetIconAsync(aURI
)->Then(
8122 GetCurrentSerialEventTarget(), __func__
,
8123 [aResolver
](ByteBuf
&& aByteBuf
) {
8124 Maybe
<ByteBuf
> bytebuf
= Some(std::move(aByteBuf
));
8125 aResolver(ResolverArgs(NS_OK
, std::move(bytebuf
)));
8127 [aResolver
](nsresult aErr
) {
8128 Maybe
<ByteBuf
> bytebuf
= Nothing();
8129 aResolver(ResolverArgs(aErr
, std::move(bytebuf
)));
8134 "This message is currently implemented only on GTK and Windows "
8139 #ifdef FUZZING_SNAPSHOT
8140 IPCResult
ContentParent::RecvSignalFuzzingReady() {
8141 // No action needed here, we already observe this message directly
8142 // on the channel and act accordingly.
8147 nsCString
ThreadsafeContentParentHandle::GetRemoteType() {
8148 RecursiveMutexAutoLock
lock(mMutex
);
8152 bool ThreadsafeContentParentHandle::MaybeRegisterRemoteWorkerActor(
8153 MoveOnlyFunction
<bool(uint32_t, bool)> aCallback
) {
8154 RecursiveMutexAutoLock
lock(mMutex
);
8155 if (aCallback(mRemoteWorkerActorCount
, mShutdownStarted
)) {
8156 // TODO: I'd wish we could assert here that our ContentParent is alive.
8157 ++mRemoteWorkerActorCount
;
8164 } // namespace mozilla
8166 NS_IMPL_ISUPPORTS(ParentIdleListener
, nsIObserver
)
8169 ParentIdleListener::Observe(nsISupports
*, const char* aTopic
,
8170 const char16_t
* aData
) {
8171 mozilla::Unused
<< mParent
->SendNotifyIdleObserver(
8172 mObserver
, nsDependentCString(aTopic
), nsDependentString(aData
));