Bug 1885602 - Part 5: Implement navigating to the SUMO help topic from the menu heade...
[gecko.git] / dom / ipc / ContentParent.cpp
blob412b7e87966439b96d684c6dc8f819afcf4a952b
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"
9 #endif
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"
30 #include "IHistory.h"
31 #include <map>
32 #include <utility>
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_threads.h"
82 #include "mozilla/StaticPrefs_widget.h"
83 #include "mozilla/StorageAccessAPIHelper.h"
84 #include "mozilla/StyleSheet.h"
85 #include "mozilla/StyleSheetInlines.h"
86 #include "mozilla/TaskController.h"
87 #include "mozilla/Telemetry.h"
88 #include "mozilla/TelemetryIPC.h"
89 #include "mozilla/ThreadSafety.h"
90 #include "mozilla/Unused.h"
91 #include "mozilla/WebBrowserPersistDocumentParent.h"
92 #include "mozilla/devtools/HeapSnapshotTempFileHelperParent.h"
93 #include "mozilla/dom/BlobURLProtocolHandler.h"
94 #include "mozilla/dom/BrowserHost.h"
95 #include "mozilla/dom/BrowsingContext.h"
96 #include "mozilla/dom/BrowsingContextGroup.h"
97 #include "mozilla/dom/CancelContentJSOptionsBinding.h"
98 #include "mozilla/dom/CanonicalBrowsingContext.h"
99 #include "mozilla/dom/ClientManager.h"
100 #include "mozilla/dom/ContentChild.h"
101 #include "mozilla/dom/DataTransfer.h"
102 #include "mozilla/dom/Document.h"
103 #include "mozilla/dom/Element.h"
104 #include "mozilla/dom/ExternalHelperAppParent.h"
105 #include "mozilla/dom/File.h"
106 #include "mozilla/dom/FileSystemSecurity.h"
107 #include "mozilla/dom/GeolocationBinding.h"
108 #include "mozilla/dom/GeolocationPositionError.h"
109 #include "mozilla/dom/GetFilesHelper.h"
110 #include "mozilla/dom/IPCBlobUtils.h"
111 #include "mozilla/dom/JSActorService.h"
112 #include "mozilla/dom/JSProcessActorBinding.h"
113 #include "mozilla/dom/LocalStorageCommon.h"
114 #include "mozilla/dom/MediaController.h"
115 #include "mozilla/dom/MemoryReportRequest.h"
116 #include "mozilla/dom/MediaStatusManager.h"
117 #include "mozilla/dom/Notification.h"
118 #include "mozilla/dom/PContentPermissionRequestParent.h"
119 #include "mozilla/dom/PCycleCollectWithLogsParent.h"
120 #include "mozilla/dom/ParentProcessMessageManager.h"
121 #include "mozilla/dom/Permissions.h"
122 #include "mozilla/dom/ProcessMessageManager.h"
123 #include "mozilla/dom/PushNotifier.h"
124 #include "mozilla/dom/ServiceWorkerManager.h"
125 #include "mozilla/dom/ServiceWorkerRegistrar.h"
126 #include "mozilla/dom/ServiceWorkerUtils.h"
127 #include "mozilla/dom/SessionHistoryEntry.h"
128 #include "mozilla/dom/SessionStorageManager.h"
129 #include "mozilla/dom/StorageIPC.h"
130 #include "mozilla/dom/UserActivation.h"
131 #include "mozilla/dom/URLClassifierParent.h"
132 #include "mozilla/dom/WindowGlobalParent.h"
133 #include "mozilla/dom/ipc/SharedMap.h"
134 #include "mozilla/dom/ipc/StructuredCloneData.h"
135 #include "mozilla/dom/nsMixedContentBlocker.h"
136 #include "mozilla/dom/power/PowerManagerService.h"
137 #include "mozilla/dom/quota/QuotaManagerService.h"
138 #include "mozilla/extensions/ExtensionsParent.h"
139 #include "mozilla/extensions/StreamFilterParent.h"
140 #include "mozilla/gfx/GPUProcessManager.h"
141 #include "mozilla/gfx/gfxVars.h"
142 #include "mozilla/glean/GleanPings.h"
143 #include "mozilla/hal_sandbox/PHalParent.h"
144 #include "mozilla/intl/L10nRegistry.h"
145 #include "mozilla/intl/LocaleService.h"
146 #include "mozilla/ipc/BackgroundChild.h"
147 #include "mozilla/ipc/BackgroundParent.h"
148 #include "mozilla/ipc/ByteBuf.h"
149 #include "mozilla/ipc/CrashReporterHost.h"
150 #include "mozilla/ipc/Endpoint.h"
151 #include "mozilla/ipc/FileDescriptorUtils.h"
152 #include "mozilla/ipc/IPCStreamUtils.h"
153 #include "mozilla/ipc/TestShellParent.h"
154 #include "mozilla/layers/CompositorThread.h"
155 #include "mozilla/layers/ImageBridgeParent.h"
156 #include "mozilla/layers/LayerTreeOwnerTracker.h"
157 #include "mozilla/layers/PAPZParent.h"
158 #include "mozilla/loader/ScriptCacheActors.h"
159 #include "mozilla/media/MediaParent.h"
160 #include "mozilla/mozSpellChecker.h"
161 #include "mozilla/net/CookieServiceParent.h"
162 #include "mozilla/net/NeckoMessageUtils.h"
163 #include "mozilla/net/NeckoParent.h"
164 #include "mozilla/net/PCookieServiceParent.h"
165 #include "mozilla/net/CookieKey.h"
166 #include "mozilla/net/TRRService.h"
167 #include "mozilla/TelemetryComms.h"
168 #include "mozilla/TelemetryEventEnums.h"
169 #include "mozilla/RemoteLazyInputStreamParent.h"
170 #include "mozilla/widget/RemoteLookAndFeel.h"
171 #include "mozilla/widget/ScreenManager.h"
172 #include "mozilla/widget/TextRecognition.h"
173 #include "nsAnonymousTemporaryFile.h"
174 #include "nsAppRunner.h"
175 #include "nsCExternalHandlerService.h"
176 #include "nsCOMPtr.h"
177 #include "nsChromeRegistryChrome.h"
178 #include "nsConsoleMessage.h"
179 #include "nsConsoleService.h"
180 #include "nsContentPermissionHelper.h"
181 #include "nsContentUtils.h"
182 #include "nsCRT.h"
183 #include "nsDebugImpl.h"
184 #include "nsDirectoryServiceDefs.h"
185 #include "nsDocShell.h"
186 #include "nsEmbedCID.h"
187 #include "nsFocusManager.h"
188 #include "nsFrameLoader.h"
189 #include "nsFrameMessageManager.h"
190 #include "nsGlobalWindowOuter.h"
191 #include "nsHashPropertyBag.h"
192 #include "nsHyphenationManager.h"
193 #include "nsIAlertsService.h"
194 #include "nsIAppShell.h"
195 #include "nsIAppWindow.h"
196 #include "nsIAsyncInputStream.h"
197 #include "nsIBidiKeyboard.h"
198 #include "nsICaptivePortalService.h"
199 #include "nsICertOverrideService.h"
200 #include "nsIClipboard.h"
201 #include "nsIContentAnalysis.h"
202 #include "nsIContentProcess.h"
203 #include "nsIContentSecurityPolicy.h"
204 #include "nsICookie.h"
205 #include "nsICrashService.h"
206 #include "nsICycleCollectorListener.h"
207 #include "nsIDocShell.h"
208 #include "nsIDocShellTreeOwner.h"
209 #include "nsIDragService.h"
210 #include "nsIExternalProtocolService.h"
211 #include "nsIGfxInfo.h"
212 #include "nsIUserIdleService.h"
213 #include "nsIInterfaceRequestorUtils.h"
214 #include "nsILocalStorageManager.h"
215 #include "nsIMemoryInfoDumper.h"
216 #include "nsIMemoryReporter.h"
217 #include "nsINetworkLinkService.h"
218 #include "nsIObserverService.h"
219 #include "nsIParentChannel.h"
220 #include "nsIScriptError.h"
221 #include "nsIScriptSecurityManager.h"
222 #include "nsIServiceWorkerManager.h"
223 #include "nsISiteSecurityService.h"
224 #include "nsIStringBundle.h"
225 #include "nsITimer.h"
226 #include "nsIURL.h"
227 #include "nsIWebBrowserChrome.h"
228 #include "nsIX509Cert.h"
229 #include "nsIXULRuntime.h"
230 #include "nsICookieNotification.h"
231 #if defined(MOZ_WIDGET_GTK) || defined(XP_WIN)
232 # include "nsIconChannel.h"
233 #endif
234 #include "nsMemoryInfoDumper.h"
235 #include "nsMemoryReporterManager.h"
236 #include "nsOpenURIInFrameParams.h"
237 #include "nsPIWindowWatcher.h"
238 #include "nsQueryObject.h"
239 #include "nsReadableUtils.h"
240 #include "nsSHistory.h"
241 #include "nsScriptError.h"
242 #include "nsServiceManagerUtils.h"
243 #include "nsStreamUtils.h"
244 #include "nsStyleSheetService.h"
245 #include "nsThread.h"
246 #include "nsThreadUtils.h"
247 #include "nsWidgetsCID.h"
248 #include "nsWindowWatcher.h"
249 #include "prenv.h"
250 #include "prio.h"
251 #include "private/pprio.h"
252 #include "xpcpublic.h"
253 #include "nsOpenWindowInfo.h"
254 #include "nsFrameLoaderOwner.h"
256 #ifdef MOZ_WEBRTC
257 # include "jsapi/WebrtcGlobalParent.h"
258 #endif
260 #if defined(XP_MACOSX)
261 # include "nsMacUtilsImpl.h"
262 # include "mozilla/AvailableMemoryWatcher.h"
263 #endif
265 #if defined(ANDROID) || defined(LINUX)
266 # include "nsSystemInfo.h"
267 #endif
269 #if defined(XP_LINUX)
270 # include "mozilla/Hal.h"
271 #endif
273 #ifdef ANDROID
274 # include "gfxAndroidPlatform.h"
275 #endif
277 #include "mozilla/PermissionManager.h"
279 #ifdef MOZ_WIDGET_ANDROID
280 # include "AndroidBridge.h"
281 # include "mozilla/java/GeckoProcessManagerWrappers.h"
282 # include "mozilla/java/GeckoProcessTypeWrappers.h"
283 #endif
285 #ifdef MOZ_WIDGET_GTK
286 # include <gdk/gdk.h>
287 # include "mozilla/WidgetUtilsGtk.h"
288 #endif
290 #include "mozilla/RemoteSpellCheckEngineParent.h"
292 #include "Crypto.h"
294 #ifdef MOZ_WEBSPEECH
295 # include "mozilla/dom/SpeechSynthesisParent.h"
296 #endif
298 #if defined(MOZ_SANDBOX)
299 # include "mozilla/SandboxSettings.h"
300 # if defined(XP_LINUX)
301 # include "mozilla/SandboxInfo.h"
302 # include "mozilla/SandboxBroker.h"
303 # include "mozilla/SandboxBrokerPolicyFactory.h"
304 # endif
305 # if defined(XP_MACOSX)
306 # include "mozilla/Sandbox.h"
307 # endif
308 #endif
310 #ifdef XP_WIN
311 # include "mozilla/widget/AudioSession.h"
312 # include "mozilla/WinDllServices.h"
313 #endif
315 #ifdef MOZ_CODE_COVERAGE
316 # include "mozilla/CodeCoverageHandler.h"
317 #endif
319 #ifdef FUZZING_SNAPSHOT
320 # include "mozilla/fuzzing/IPCFuzzController.h"
321 #endif
323 // For VP9Benchmark::sBenchmarkFpsPref
324 #include "Benchmark.h"
326 #include "mozilla/RemoteDecodeUtils.h"
327 #include "nsIToolkitProfileService.h"
328 #include "nsIToolkitProfile.h"
330 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
332 using base::KillProcess;
334 using namespace CrashReporter;
335 using namespace mozilla::dom::power;
336 using namespace mozilla::media;
337 using namespace mozilla::embedding;
338 using namespace mozilla::gfx;
339 using namespace mozilla::gmp;
340 using namespace mozilla::hal;
341 using namespace mozilla::ipc;
342 using namespace mozilla::intl;
343 using namespace mozilla::layers;
344 using namespace mozilla::layout;
345 using namespace mozilla::net;
346 using namespace mozilla::psm;
347 using namespace mozilla::widget;
348 using namespace mozilla::Telemetry;
349 using mozilla::loader::PScriptCacheParent;
350 using mozilla::Telemetry::ProcessID;
352 extern mozilla::LazyLogModule gFocusLog;
354 #define LOGFOCUS(args) MOZ_LOG(gFocusLog, mozilla::LogLevel::Debug, args)
356 extern mozilla::LazyLogModule sPDMLog;
357 #define LOGPDM(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
359 namespace mozilla {
360 namespace CubebUtils {
361 extern FileDescriptor CreateAudioIPCConnection();
364 namespace dom {
366 LazyLogModule gProcessLog("Process");
368 static std::map<RemoteDecodeIn, media::MediaCodecsSupported> sCodecsSupported;
370 /* static */
371 uint32_t ContentParent::sMaxContentProcesses = 0;
373 /* static */
374 LogModule* ContentParent::GetLog() { return gProcessLog; }
376 /* static */
377 uint32_t ContentParent::sPageLoadEventCounter = 0;
379 #define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
380 #define NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC "ipc:network:set-connectivity"
382 // IPC receiver for remote GC/CC logging.
383 class CycleCollectWithLogsParent final : public PCycleCollectWithLogsParent {
384 public:
385 MOZ_COUNTED_DTOR(CycleCollectWithLogsParent)
387 static bool AllocAndSendConstructor(ContentParent* aManager,
388 bool aDumpAllTraces,
389 nsICycleCollectorLogSink* aSink,
390 nsIDumpGCAndCCLogsCallback* aCallback) {
391 CycleCollectWithLogsParent* actor;
392 FILE* gcLog;
393 FILE* ccLog;
394 nsresult rv;
396 actor = new CycleCollectWithLogsParent(aSink, aCallback);
397 rv = actor->mSink->Open(&gcLog, &ccLog);
398 if (NS_WARN_IF(NS_FAILED(rv))) {
399 delete actor;
400 return false;
403 return aManager->SendPCycleCollectWithLogsConstructor(
404 actor, aDumpAllTraces, FILEToFileDescriptor(gcLog),
405 FILEToFileDescriptor(ccLog));
408 private:
409 virtual mozilla::ipc::IPCResult RecvCloseGCLog() override {
410 Unused << mSink->CloseGCLog();
411 return IPC_OK();
414 virtual mozilla::ipc::IPCResult RecvCloseCCLog() override {
415 Unused << mSink->CloseCCLog();
416 return IPC_OK();
419 virtual mozilla::ipc::IPCResult Recv__delete__() override {
420 // Report completion to mCallback only on successful
421 // completion of the protocol.
422 nsCOMPtr<nsIFile> gcLog, ccLog;
423 mSink->GetGcLog(getter_AddRefs(gcLog));
424 mSink->GetCcLog(getter_AddRefs(ccLog));
425 Unused << mCallback->OnDump(gcLog, ccLog, /* parent = */ false);
426 return IPC_OK();
429 virtual void ActorDestroy(ActorDestroyReason aReason) override {
430 // If the actor is unexpectedly destroyed, we deliberately
431 // don't call Close[GC]CLog on the sink, because the logs may
432 // be incomplete. See also the nsCycleCollectorLogSinkToFile
433 // implementaiton of those methods, and its destructor.
436 CycleCollectWithLogsParent(nsICycleCollectorLogSink* aSink,
437 nsIDumpGCAndCCLogsCallback* aCallback)
438 : mSink(aSink), mCallback(aCallback) {
439 MOZ_COUNT_CTOR(CycleCollectWithLogsParent);
442 nsCOMPtr<nsICycleCollectorLogSink> mSink;
443 nsCOMPtr<nsIDumpGCAndCCLogsCallback> mCallback;
446 // A memory reporter for ContentParent objects themselves.
447 class ContentParentsMemoryReporter final : public nsIMemoryReporter {
448 ~ContentParentsMemoryReporter() = default;
450 public:
451 NS_DECL_ISUPPORTS
452 NS_DECL_NSIMEMORYREPORTER
455 NS_IMPL_ISUPPORTS(ContentParentsMemoryReporter, nsIMemoryReporter)
457 NS_IMETHODIMP
458 ContentParentsMemoryReporter::CollectReports(
459 nsIHandleReportCallback* aHandleReport, nsISupports* aData,
460 bool aAnonymize) {
461 AutoTArray<ContentParent*, 16> cps;
462 ContentParent::GetAllEvenIfDead(cps);
464 for (uint32_t i = 0; i < cps.Length(); i++) {
465 ContentParent* cp = cps[i];
466 MessageChannel* channel = cp->GetIPCChannel();
468 nsString friendlyName;
469 cp->FriendlyName(friendlyName, aAnonymize);
471 cp->AddRef();
472 nsrefcnt refcnt = cp->Release();
474 const char* channelStr = "no channel";
475 uint32_t numQueuedMessages = 0;
476 if (channel) {
477 if (channel->IsClosed()) {
478 channelStr = "closed channel";
479 } else {
480 channelStr = "open channel";
482 numQueuedMessages =
483 0; // XXX was channel->Unsound_NumQueuedMessages(); Bug 1754876
486 nsPrintfCString path(
487 "queued-ipc-messages/content-parent"
488 "(%s, pid=%d, %s, 0x%p, refcnt=%" PRIuPTR ")",
489 NS_ConvertUTF16toUTF8(friendlyName).get(), cp->Pid(), channelStr,
490 static_cast<nsIObserver*>(cp), refcnt);
492 constexpr auto desc =
493 "The number of unset IPC messages held in this ContentParent's "
494 "channel. A large value here might indicate that we're leaking "
495 "messages. Similarly, a ContentParent object for a process that's no "
496 "longer running could indicate that we're leaking ContentParents."_ns;
498 aHandleReport->Callback(/* process */ ""_ns, path, KIND_OTHER, UNITS_COUNT,
499 numQueuedMessages, desc, aData);
502 return NS_OK;
505 // A hashtable (by type) of processes/ContentParents. This includes
506 // processes that are in the Preallocator cache (which would be type
507 // 'prealloc'), and recycled processes ('web' and in the future
508 // eTLD+1-locked) processes).
509 nsClassHashtable<nsCStringHashKey, nsTArray<ContentParent*>>*
510 ContentParent::sBrowserContentParents;
512 namespace {
514 uint64_t ComputeLoadedOriginHash(nsIPrincipal* aPrincipal) {
515 uint32_t originNoSuffix =
516 BasePrincipal::Cast(aPrincipal)->GetOriginNoSuffixHash();
517 uint32_t originSuffix =
518 BasePrincipal::Cast(aPrincipal)->GetOriginSuffixHash();
520 return ((uint64_t)originNoSuffix) << 32 | originSuffix;
523 class ScriptableCPInfo final : public nsIContentProcessInfo {
524 public:
525 explicit ScriptableCPInfo(ContentParent* aParent) : mContentParent(aParent) {
526 MOZ_ASSERT(mContentParent);
529 NS_DECL_ISUPPORTS
530 NS_DECL_NSICONTENTPROCESSINFO
532 void ProcessDied() { mContentParent = nullptr; }
534 private:
535 ~ScriptableCPInfo() { MOZ_ASSERT(!mContentParent, "must call ProcessDied"); }
537 ContentParent* mContentParent;
540 NS_IMPL_ISUPPORTS(ScriptableCPInfo, nsIContentProcessInfo)
542 NS_IMETHODIMP
543 ScriptableCPInfo::GetIsAlive(bool* aIsAlive) {
544 *aIsAlive = mContentParent != nullptr;
545 return NS_OK;
548 NS_IMETHODIMP
549 ScriptableCPInfo::GetProcessId(int32_t* aPID) {
550 if (!mContentParent) {
551 *aPID = -1;
552 return NS_ERROR_NOT_INITIALIZED;
555 *aPID = mContentParent->Pid();
556 if (*aPID == -1) {
557 return NS_ERROR_FAILURE;
560 return NS_OK;
563 NS_IMETHODIMP
564 ScriptableCPInfo::GetTabCount(int32_t* aTabCount) {
565 if (!mContentParent) {
566 return NS_ERROR_NOT_INITIALIZED;
569 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
570 *aTabCount = cpm->GetBrowserParentCountByProcessId(mContentParent->ChildID());
572 return NS_OK;
575 NS_IMETHODIMP
576 ScriptableCPInfo::GetMessageManager(nsISupports** aMessenger) {
577 *aMessenger = nullptr;
578 if (!mContentParent) {
579 return NS_ERROR_NOT_INITIALIZED;
582 RefPtr<ProcessMessageManager> manager = mContentParent->GetMessageManager();
583 manager.forget(aMessenger);
584 return NS_OK;
587 ProcessID GetTelemetryProcessID(const nsACString& remoteType) {
588 // OOP WebExtensions run in a content process.
589 // For Telemetry though we want to break out collected data from the
590 // WebExtensions process into a separate bucket, to make sure we can analyze
591 // it separately and avoid skewing normal content process metrics.
592 return remoteType == EXTENSION_REMOTE_TYPE ? ProcessID::Extension
593 : ProcessID::Content;
596 } // anonymous namespace
598 StaticAutoPtr<LinkedList<ContentParent>> ContentParent::sContentParents;
599 StaticRefPtr<ContentParent> ContentParent::sRecycledE10SProcess;
600 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
601 StaticAutoPtr<SandboxBrokerPolicyFactory>
602 ContentParent::sSandboxBrokerPolicyFactory;
603 #endif
604 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
605 StaticAutoPtr<std::vector<std::string>> ContentParent::sMacSandboxParams;
606 #endif
608 // Set to true when the first content process gets created.
609 static bool sCreatedFirstContentProcess = false;
611 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
612 // True when we're running the process selection code, and do not expect to
613 // enter code paths where processes may die.
614 static bool sInProcessSelector = false;
615 #endif
617 // The first content child has ID 1, so the chrome process can have ID 0.
618 static uint64_t gContentChildID = 1;
620 static const char* sObserverTopics[] = {
621 NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
622 NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
623 NS_IPC_CAPTIVE_PORTAL_SET_STATE,
624 "application-background",
625 "application-foreground",
626 "memory-pressure",
627 "child-gc-request",
628 "child-cc-request",
629 "child-mmu-request",
630 "child-ghost-request",
631 "last-pb-context-exited",
632 "file-watcher-update",
633 #ifdef ACCESSIBILITY
634 "a11y-init-or-shutdown",
635 #endif
636 "cacheservice:empty-cache",
637 "intl:app-locales-changed",
638 "intl:requested-locales-changed",
639 "cookie-changed",
640 "private-cookie-changed",
641 NS_NETWORK_LINK_TYPE_TOPIC,
642 NS_NETWORK_TRR_MODE_CHANGED_TOPIC,
643 "network:socket-process-crashed",
644 DEFAULT_TIMEZONE_CHANGED_OBSERVER_TOPIC,
647 void ContentParent_NotifyUpdatedDictionaries() {
648 ContentParent::NotifyUpdatedDictionaries();
651 // PreallocateProcess is called by the PreallocatedProcessManager.
652 // ContentParent then takes this process back within GetNewOrUsedBrowserProcess.
653 /*static*/ already_AddRefed<ContentParent>
654 ContentParent::MakePreallocProcess() {
655 RefPtr<ContentParent> process = new ContentParent(PREALLOC_REMOTE_TYPE);
656 return process.forget();
659 /*static*/
660 void ContentParent::StartUp() {
661 // FIXME Bug 1023701 - Stop using ContentParent static methods in
662 // child process
663 if (!XRE_IsParentProcess()) {
664 return;
667 // From this point on, NS_WARNING, NS_ASSERTION, etc. should print out the
668 // PID along with the warning.
669 nsDebugImpl::SetMultiprocessMode("Parent");
671 // Note: This reporter measures all ContentParents.
672 RegisterStrongMemoryReporter(new ContentParentsMemoryReporter());
674 BackgroundChild::Startup();
675 ClientManager::Startup();
677 Preferences::RegisterCallbackAndCall(&OnFissionBlocklistPrefChange,
678 kFissionEnforceBlockList);
679 Preferences::RegisterCallbackAndCall(&OnFissionBlocklistPrefChange,
680 kFissionOmitBlockListValues);
682 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
683 sSandboxBrokerPolicyFactory = new SandboxBrokerPolicyFactory();
684 #endif
686 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
687 sMacSandboxParams = new std::vector<std::string>();
688 #endif
691 /*static*/
692 void ContentParent::ShutDown() {
693 // For the most, we rely on normal process shutdown and
694 // ClearOnShutdown() to clean up our state.
696 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
697 sSandboxBrokerPolicyFactory = nullptr;
698 #endif
700 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
701 sMacSandboxParams = nullptr;
702 #endif
705 /*static*/
706 uint32_t ContentParent::GetPoolSize(const nsACString& aContentProcessType) {
707 if (!sBrowserContentParents) {
708 return 0;
711 nsTArray<ContentParent*>* parents =
712 sBrowserContentParents->Get(aContentProcessType);
714 return parents ? parents->Length() : 0;
717 /*static*/ nsTArray<ContentParent*>& ContentParent::GetOrCreatePool(
718 const nsACString& aContentProcessType) {
719 if (!sBrowserContentParents) {
720 sBrowserContentParents =
721 new nsClassHashtable<nsCStringHashKey, nsTArray<ContentParent*>>;
724 return *sBrowserContentParents->GetOrInsertNew(aContentProcessType);
727 const nsDependentCSubstring RemoteTypePrefix(
728 const nsACString& aContentProcessType) {
729 // The suffix after a `=` in a remoteType is dynamic, and used to control the
730 // process pool to use.
731 int32_t equalIdx = aContentProcessType.FindChar(L'=');
732 if (equalIdx == kNotFound) {
733 equalIdx = aContentProcessType.Length();
735 return StringHead(aContentProcessType, equalIdx);
738 bool IsWebRemoteType(const nsACString& aContentProcessType) {
739 // Note: matches webIsolated, web, and webCOOP+COEP types.
740 return StringBeginsWith(aContentProcessType, DEFAULT_REMOTE_TYPE);
743 bool IsWebCoopCoepRemoteType(const nsACString& aContentProcessType) {
744 return StringBeginsWith(aContentProcessType,
745 WITH_COOP_COEP_REMOTE_TYPE_PREFIX);
748 bool IsExtensionRemoteType(const nsACString& aContentProcessType) {
749 return aContentProcessType == EXTENSION_REMOTE_TYPE;
752 /*static*/
753 uint32_t ContentParent::GetMaxProcessCount(
754 const nsACString& aContentProcessType) {
755 // Max process count is based only on the prefix.
756 const nsDependentCSubstring processTypePrefix =
757 RemoteTypePrefix(aContentProcessType);
759 // Check for the default remote type of "web", as it uses different prefs.
760 if (processTypePrefix == DEFAULT_REMOTE_TYPE) {
761 return GetMaxWebProcessCount();
764 // Read the pref controling this remote type. `dom.ipc.processCount` is not
765 // used as a fallback, as it is intended to control the number of "web"
766 // content processes, checked in `mozilla::GetMaxWebProcessCount()`.
767 nsAutoCString processCountPref("dom.ipc.processCount.");
768 processCountPref.Append(processTypePrefix);
770 int32_t maxContentParents = Preferences::GetInt(processCountPref.get(), 1);
771 if (maxContentParents < 1) {
772 maxContentParents = 1;
775 return static_cast<uint32_t>(maxContentParents);
778 /*static*/
779 bool ContentParent::IsMaxProcessCountReached(
780 const nsACString& aContentProcessType) {
781 return GetPoolSize(aContentProcessType) >=
782 GetMaxProcessCount(aContentProcessType);
785 // Really more ReleaseUnneededProcesses()
786 /*static*/
787 void ContentParent::ReleaseCachedProcesses() {
788 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
789 ("ReleaseCachedProcesses:"));
790 if (!sBrowserContentParents) {
791 return;
794 #ifdef DEBUG
795 for (const auto& cps : *sBrowserContentParents) {
796 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
797 ("%s: %zu processes", PromiseFlatCString(cps.GetKey()).get(),
798 cps.GetData()->Length()));
800 #endif
802 // First let's collect all processes and keep a grip.
803 AutoTArray<RefPtr<ContentParent>, 32> fixArray;
804 for (const auto& contentParents : sBrowserContentParents->Values()) {
805 for (auto* cp : *contentParents) {
806 fixArray.AppendElement(cp);
810 for (const auto& cp : fixArray) {
811 // Ensure the process cannot be claimed between check and MarkAsDead.
812 RecursiveMutexAutoLock lock(cp->ThreadsafeHandleMutex());
814 if (cp->ManagedPBrowserParent().Count() == 0 && !cp->HasActiveWorker() &&
815 cp->mRemoteType == DEFAULT_REMOTE_TYPE) {
816 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
817 (" Shutdown %p (%s)", cp.get(), cp->mRemoteType.get()));
819 PreallocatedProcessManager::Erase(cp);
820 // Make sure we don't select this process for new tabs or workers.
821 cp->MarkAsDead();
822 // Start a soft shutdown.
823 cp->ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
824 // Make sure that this process is no longer accessible from JS by its
825 // message manager.
826 cp->ShutDownMessageManager();
827 } else {
828 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
829 (" Skipping %p (%s), count %d, HasActiveWorker %d", cp.get(),
830 cp->mRemoteType.get(), cp->ManagedPBrowserParent().Count(),
831 cp->HasActiveWorker()));
836 /*static*/
837 already_AddRefed<ContentParent> ContentParent::MinTabSelect(
838 const nsTArray<ContentParent*>& aContentParents,
839 int32_t aMaxContentParents) {
840 uint32_t maxSelectable =
841 std::min(static_cast<uint32_t>(aContentParents.Length()),
842 static_cast<uint32_t>(aMaxContentParents));
843 uint32_t min = INT_MAX;
844 RefPtr<ContentParent> candidate;
845 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
847 for (uint32_t i = 0; i < maxSelectable; i++) {
848 ContentParent* p = aContentParents[i];
849 MOZ_DIAGNOSTIC_ASSERT(!p->IsDead());
851 // Ignore processes that were slated for removal but not yet removed from
852 // the pool (see also GetUsedBrowserProcess and BlockShutdown).
853 if (!p->IsShuttingDown()) {
854 uint32_t tabCount = cpm->GetBrowserParentCountByProcessId(p->ChildID());
855 if (tabCount < min) {
856 candidate = p;
857 min = tabCount;
862 // If all current processes have at least one tab and we have not yet reached
863 // the maximum, use a new process.
864 if (min > 0 &&
865 aContentParents.Length() < static_cast<uint32_t>(aMaxContentParents)) {
866 return nullptr;
869 // Otherwise we return candidate.
870 return candidate.forget();
873 /* static */
874 already_AddRefed<nsIPrincipal>
875 ContentParent::CreateRemoteTypeIsolationPrincipal(
876 const nsACString& aRemoteType) {
877 if ((RemoteTypePrefix(aRemoteType) != FISSION_WEB_REMOTE_TYPE) &&
878 !StringBeginsWith(aRemoteType, WITH_COOP_COEP_REMOTE_TYPE_PREFIX)) {
879 return nullptr;
882 int32_t offset = aRemoteType.FindChar('=') + 1;
883 MOZ_ASSERT(offset > 1, "can not extract origin from that remote type");
884 nsAutoCString origin(
885 Substring(aRemoteType, offset, aRemoteType.Length() - offset));
887 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
888 nsCOMPtr<nsIPrincipal> principal;
889 ssm->CreateContentPrincipalFromOrigin(origin, getter_AddRefs(principal));
890 return principal.forget();
893 /*static*/
894 already_AddRefed<ContentParent> ContentParent::GetUsedBrowserProcess(
895 const nsACString& aRemoteType, nsTArray<ContentParent*>& aContentParents,
896 uint32_t aMaxContentParents, bool aPreferUsed, ProcessPriority aPriority) {
897 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
898 AutoRestore ar(sInProcessSelector);
899 sInProcessSelector = true;
900 #endif
902 uint32_t numberOfParents = aContentParents.Length();
903 nsTArray<RefPtr<nsIContentProcessInfo>> infos(numberOfParents);
904 for (auto* cp : aContentParents) {
905 infos.AppendElement(cp->mScriptableHelper);
908 if (aPreferUsed && numberOfParents) {
909 // If we prefer re-using existing content processes, we don't want to create
910 // a new process, and instead re-use an existing one, so pretend the process
911 // limit is at the current number of processes.
912 aMaxContentParents = numberOfParents;
915 nsCOMPtr<nsIContentProcessProvider> cpp =
916 do_GetService("@mozilla.org/ipc/processselector;1");
917 int32_t index;
918 if (cpp && NS_SUCCEEDED(cpp->ProvideProcess(aRemoteType, infos,
919 aMaxContentParents, &index))) {
920 // If the provider returned an existing ContentParent, use that one.
921 if (0 <= index && static_cast<uint32_t>(index) <= aMaxContentParents) {
922 RefPtr<ContentParent> retval = aContentParents[index];
923 // Ignore processes that were slated for removal but not yet removed from
924 // the pool.
925 if (!retval->IsShuttingDown()) {
926 if (profiler_thread_is_being_profiled_for_markers()) {
927 nsPrintfCString marker("Reused process %u",
928 (unsigned int)retval->ChildID());
929 PROFILER_MARKER_TEXT("Process", DOM, {}, marker);
931 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
932 ("GetUsedProcess: Reused process %p (%u) for %s", retval.get(),
933 (unsigned int)retval->ChildID(),
934 PromiseFlatCString(aRemoteType).get()));
935 retval->AssertAlive();
936 retval->StopRecyclingE10SOnly(true);
937 return retval.forget();
940 } else {
941 // If there was a problem with the JS chooser, fall back to a random
942 // selection.
943 NS_WARNING("nsIContentProcessProvider failed to return a process");
944 RefPtr<ContentParent> random;
945 if ((random = MinTabSelect(aContentParents, aMaxContentParents))) {
946 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
947 ("GetUsedProcess: Reused random process %p (%d) for %s",
948 random.get(), (unsigned int)random->ChildID(),
949 PromiseFlatCString(aRemoteType).get()));
950 random->AssertAlive();
951 random->StopRecyclingE10SOnly(true);
952 return random.forget();
956 // If we are loading into the "web" remote type, are choosing to launch a new
957 // tab, and have a recycled E10S process, we should launch into that process.
958 if (aRemoteType == DEFAULT_REMOTE_TYPE && sRecycledE10SProcess) {
959 RefPtr<ContentParent> recycled = sRecycledE10SProcess;
960 MOZ_DIAGNOSTIC_ASSERT(recycled->GetRemoteType() == DEFAULT_REMOTE_TYPE);
961 recycled->AssertAlive();
962 recycled->StopRecyclingE10SOnly(true);
963 if (profiler_thread_is_being_profiled_for_markers()) {
964 nsPrintfCString marker("Recycled process %u (%p)",
965 (unsigned int)recycled->ChildID(), recycled.get());
966 PROFILER_MARKER_TEXT("Process", DOM, {}, marker);
968 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
969 ("Recycled process %p", recycled.get()));
971 return recycled.forget();
974 // Try to take a preallocated process except for certain remote types.
975 // Note: this process may not have finished launching yet
976 RefPtr<ContentParent> preallocated;
977 if (aRemoteType != FILE_REMOTE_TYPE &&
978 aRemoteType != PRIVILEGEDABOUT_REMOTE_TYPE &&
979 aRemoteType != EXTENSION_REMOTE_TYPE && // Bug 1638119
980 (preallocated = PreallocatedProcessManager::Take(aRemoteType))) {
981 MOZ_DIAGNOSTIC_ASSERT(preallocated->GetRemoteType() ==
982 PREALLOC_REMOTE_TYPE);
983 MOZ_DIAGNOSTIC_ASSERT(sRecycledE10SProcess != preallocated);
984 preallocated->AssertAlive();
986 if (profiler_thread_is_being_profiled_for_markers()) {
987 nsPrintfCString marker(
988 "Assigned preallocated process %u%s",
989 (unsigned int)preallocated->ChildID(),
990 preallocated->IsLaunching() ? " (still launching)" : "");
991 PROFILER_MARKER_TEXT("Process", DOM, {}, marker);
993 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
994 ("Adopted preallocated process %p for type %s%s",
995 preallocated.get(), PromiseFlatCString(aRemoteType).get(),
996 preallocated->IsLaunching() ? " (still launching)" : ""));
998 // This ensures that the preallocator won't shut down the process once
999 // it finishes starting
1000 preallocated->mRemoteType.Assign(aRemoteType);
1002 RecursiveMutexAutoLock lock(preallocated->mThreadsafeHandle->mMutex);
1003 preallocated->mThreadsafeHandle->mRemoteType = preallocated->mRemoteType;
1005 preallocated->mRemoteTypeIsolationPrincipal =
1006 CreateRemoteTypeIsolationPrincipal(aRemoteType);
1007 preallocated->mActivateTS = TimeStamp::Now();
1008 preallocated->AddToPool(aContentParents);
1010 // rare, but will happen
1011 if (!preallocated->IsLaunching()) {
1012 // Specialize this process for the appropriate remote type, and activate
1013 // it.
1015 Unused << preallocated->SendRemoteType(preallocated->mRemoteType,
1016 preallocated->mProfile);
1018 nsCOMPtr<nsIObserverService> obs =
1019 mozilla::services::GetObserverService();
1020 if (obs) {
1021 nsAutoString cpId;
1022 cpId.AppendInt(static_cast<uint64_t>(preallocated->ChildID()));
1023 obs->NotifyObservers(static_cast<nsIObserver*>(preallocated),
1024 "process-type-set", cpId.get());
1025 preallocated->AssertAlive();
1028 return preallocated.forget();
1031 return nullptr;
1034 /*static*/
1035 already_AddRefed<ContentParent>
1036 ContentParent::GetNewOrUsedLaunchingBrowserProcess(
1037 const nsACString& aRemoteType, BrowsingContextGroup* aGroup,
1038 ProcessPriority aPriority, bool aPreferUsed) {
1039 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1040 ("GetNewOrUsedProcess for type %s",
1041 PromiseFlatCString(aRemoteType).get()));
1043 // Fallback check (we really want our callers to avoid this).
1044 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
1045 MOZ_DIAGNOSTIC_ASSERT(
1046 false, "Late attempt to GetNewOrUsedLaunchingBrowserProcess!");
1047 return nullptr;
1050 // If we have an existing host process attached to this BrowsingContextGroup,
1051 // always return it, as we can never have multiple host processes within a
1052 // single BrowsingContextGroup.
1053 RefPtr<ContentParent> contentParent;
1054 if (aGroup) {
1055 contentParent = aGroup->GetHostProcess(aRemoteType);
1056 Unused << NS_WARN_IF(contentParent && contentParent->IsShuttingDown());
1057 if (contentParent && !contentParent->IsShuttingDown()) {
1058 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1059 ("GetNewOrUsedProcess: Existing host process %p (launching %d)",
1060 contentParent.get(), contentParent->IsLaunching()));
1061 contentParent->AssertAlive();
1062 contentParent->StopRecyclingE10SOnly(true);
1063 return contentParent.forget();
1067 nsTArray<ContentParent*>& contentParents = GetOrCreatePool(aRemoteType);
1068 uint32_t maxContentParents = GetMaxProcessCount(aRemoteType);
1070 // Let's try and reuse an existing process.
1071 contentParent = GetUsedBrowserProcess(
1072 aRemoteType, contentParents, maxContentParents, aPreferUsed, aPriority);
1074 if (!contentParent) {
1075 // No reusable process. Let's create and launch one.
1076 // The life cycle will be set to `LifecycleState::LAUNCHING`.
1077 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1078 ("Launching new process immediately for type %s",
1079 PromiseFlatCString(aRemoteType).get()));
1081 contentParent = new ContentParent(aRemoteType);
1082 if (NS_WARN_IF(!contentParent->BeginSubprocessLaunch(aPriority))) {
1083 // Launch aborted because of shutdown. Bailout.
1084 contentParent->LaunchSubprocessReject();
1085 return nullptr;
1087 // Until the new process is ready let's not allow to start up any
1088 // preallocated processes. The blocker will be removed once we receive
1089 // the first idle message.
1090 contentParent->mIsAPreallocBlocker = true;
1091 PreallocatedProcessManager::AddBlocker(aRemoteType, contentParent);
1093 // Store this process for future reuse.
1094 contentParent->AddToPool(contentParents);
1096 MOZ_LOG(
1097 ContentParent::GetLog(), LogLevel::Debug,
1098 ("GetNewOrUsedProcess: new immediate process %p", contentParent.get()));
1100 // else we have an existing or preallocated process (which may be
1101 // still launching)
1103 contentParent->AssertAlive();
1104 contentParent->StopRecyclingE10SOnly(true);
1105 if (aGroup) {
1106 aGroup->EnsureHostProcess(contentParent);
1108 return contentParent.forget();
1111 /*static*/
1112 RefPtr<ContentParent::LaunchPromise>
1113 ContentParent::GetNewOrUsedBrowserProcessAsync(const nsACString& aRemoteType,
1114 BrowsingContextGroup* aGroup,
1115 ProcessPriority aPriority,
1116 bool aPreferUsed) {
1117 // Obtain a `ContentParent` launched asynchronously.
1118 RefPtr<ContentParent> contentParent = GetNewOrUsedLaunchingBrowserProcess(
1119 aRemoteType, aGroup, aPriority, aPreferUsed);
1120 if (!contentParent) {
1121 // In case of launch error, stop here.
1122 return LaunchPromise::CreateAndReject(NS_ERROR_ILLEGAL_DURING_SHUTDOWN,
1123 __func__);
1125 return contentParent->WaitForLaunchAsync(aPriority);
1128 /*static*/
1129 already_AddRefed<ContentParent> ContentParent::GetNewOrUsedBrowserProcess(
1130 const nsACString& aRemoteType, BrowsingContextGroup* aGroup,
1131 ProcessPriority aPriority, bool aPreferUsed) {
1132 RefPtr<ContentParent> contentParent = GetNewOrUsedLaunchingBrowserProcess(
1133 aRemoteType, aGroup, aPriority, aPreferUsed);
1134 if (!contentParent || !contentParent->WaitForLaunchSync(aPriority)) {
1135 // In case of launch error, stop here.
1136 return nullptr;
1138 return contentParent.forget();
1141 RefPtr<ContentParent::LaunchPromise> ContentParent::WaitForLaunchAsync(
1142 ProcessPriority aPriority) {
1143 MOZ_DIAGNOSTIC_ASSERT(!IsDead());
1144 if (!IsLaunching()) {
1145 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1146 ("WaitForLaunchAsync: launched"));
1147 return LaunchPromise::CreateAndResolve(this, __func__);
1150 // We've started an async content process launch.
1151 Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC, 0);
1153 // We have located a process that hasn't finished initializing, then attempt
1154 // to finish initializing. Both `LaunchSubprocessResolve` and
1155 // `LaunchSubprocessReject` are safe to call multiple times if we race with
1156 // other `WaitForLaunchAsync` callbacks.
1157 return mSubprocess->WhenProcessHandleReady()->Then(
1158 GetCurrentSerialEventTarget(), __func__,
1159 [self = RefPtr{this}, aPriority]() {
1160 if (self->LaunchSubprocessResolve(/* aIsSync = */ false, aPriority)) {
1161 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1162 ("WaitForLaunchAsync: async, now launched"));
1163 self->mActivateTS = TimeStamp::Now();
1164 return LaunchPromise::CreateAndResolve(self, __func__);
1167 self->LaunchSubprocessReject();
1168 return LaunchPromise::CreateAndReject(NS_ERROR_INVALID_ARG, __func__);
1170 [self = RefPtr{this}]() {
1171 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1172 ("WaitForLaunchAsync: async, rejected"));
1173 self->LaunchSubprocessReject();
1174 return LaunchPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
1178 bool ContentParent::WaitForLaunchSync(ProcessPriority aPriority) {
1179 MOZ_DIAGNOSTIC_ASSERT(!IsDead());
1180 if (!IsLaunching()) {
1181 return true;
1184 // We've started a sync content process launch.
1185 Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC, 1);
1187 // We're a process which hasn't finished initializing. We may be racing
1188 // against whoever launched it (and whoever else is already racing). Since
1189 // we're sync, we win the race and finish the initialization.
1190 bool launchSuccess = mSubprocess->WaitForProcessHandle();
1191 if (launchSuccess &&
1192 LaunchSubprocessResolve(/* aIsSync = */ true, aPriority)) {
1193 mActivateTS = TimeStamp::Now();
1194 return true;
1196 // In case of failure.
1197 LaunchSubprocessReject();
1198 return false;
1201 static nsIDocShell* GetOpenerDocShellHelper(Element* aFrameElement) {
1202 // Propagate the private-browsing status of the element's parent
1203 // docshell to the remote docshell, via the chrome flags.
1204 MOZ_ASSERT(aFrameElement);
1205 nsPIDOMWindowOuter* win = aFrameElement->OwnerDoc()->GetWindow();
1206 if (!win) {
1207 NS_WARNING("Remote frame has no window");
1208 return nullptr;
1210 nsIDocShell* docShell = win->GetDocShell();
1211 if (!docShell) {
1212 NS_WARNING("Remote frame has no docshell");
1213 return nullptr;
1216 return docShell;
1219 mozilla::ipc::IPCResult ContentParent::RecvCreateGMPService() {
1220 Endpoint<PGMPServiceParent> parent;
1221 Endpoint<PGMPServiceChild> child;
1223 if (mGMPCreated) {
1224 return IPC_FAIL(this, "GMP Service already created");
1227 nsresult rv;
1228 rv = PGMPService::CreateEndpoints(base::GetCurrentProcId(), OtherPid(),
1229 &parent, &child);
1230 if (NS_FAILED(rv)) {
1231 return IPC_FAIL(this, "CreateEndpoints failed");
1234 if (!GMPServiceParent::Create(std::move(parent))) {
1235 return IPC_FAIL(this, "GMPServiceParent::Create failed");
1238 if (!SendInitGMPService(std::move(child))) {
1239 return IPC_FAIL(this, "SendInitGMPService failed");
1242 mGMPCreated = true;
1244 return IPC_OK();
1247 Atomic<bool, mozilla::Relaxed> sContentParentTelemetryEventEnabled(false);
1249 /*static*/
1250 void ContentParent::LogAndAssertFailedPrincipalValidationInfo(
1251 nsIPrincipal* aPrincipal, const char* aMethod) {
1252 // nsContentSecurityManager may also enable this same event, but that's okay
1253 if (!sContentParentTelemetryEventEnabled.exchange(true)) {
1254 sContentParentTelemetryEventEnabled = true;
1255 Telemetry::SetEventRecordingEnabled("security"_ns, true);
1258 // Send Telemetry
1259 nsAutoCString principalScheme, principalType, spec;
1260 CopyableTArray<EventExtraEntry> extra(2);
1262 if (!aPrincipal) {
1263 principalType.AssignLiteral("NullPtr");
1264 } else if (aPrincipal->IsSystemPrincipal()) {
1265 principalType.AssignLiteral("SystemPrincipal");
1266 } else if (aPrincipal->GetIsExpandedPrincipal()) {
1267 principalType.AssignLiteral("ExpandedPrincipal");
1268 } else if (aPrincipal->GetIsContentPrincipal()) {
1269 principalType.AssignLiteral("ContentPrincipal");
1270 aPrincipal->GetSpec(spec);
1271 aPrincipal->GetScheme(principalScheme);
1273 extra.AppendElement(EventExtraEntry{"scheme"_ns, principalScheme});
1274 } else {
1275 principalType.AssignLiteral("Unknown");
1278 extra.AppendElement(EventExtraEntry{"principalType"_ns, principalType});
1280 // Do not send telemetry when chrome-debugging is enabled
1281 bool isChromeDebuggingEnabled =
1282 Preferences::GetBool("devtools.chrome.enabled", false);
1283 if (!isChromeDebuggingEnabled) {
1284 Telemetry::EventID eventType =
1285 Telemetry::EventID::Security_Fissionprincipals_Contentparent;
1286 Telemetry::RecordEvent(eventType, mozilla::Some(aMethod),
1287 mozilla::Some(extra));
1290 // And log it
1291 MOZ_LOG(
1292 ContentParent::GetLog(), LogLevel::Error,
1293 (" Receiving unexpected Principal (%s) within %s",
1294 aPrincipal && aPrincipal->GetIsContentPrincipal() ? spec.get()
1295 : principalType.get(),
1296 aMethod));
1298 #ifdef DEBUG
1299 // Not only log but also ensure we do not receive an unexpected
1300 // principal when running in debug mode.
1301 MOZ_ASSERT(false, "Receiving unexpected Principal");
1302 #endif
1305 bool ContentParent::ValidatePrincipal(
1306 nsIPrincipal* aPrincipal,
1307 const EnumSet<ValidatePrincipalOptions>& aOptions) {
1308 // If the pref says we should not validate, then there is nothing to do
1309 if (!StaticPrefs::dom_security_enforceIPCBasedPrincipalVetting()) {
1310 return true;
1313 // If there is no principal, then there is nothing to validate!
1314 if (!aPrincipal) {
1315 return aOptions.contains(ValidatePrincipalOptions::AllowNullPtr);
1318 // We currently do not track relationships between specific null principals
1319 // and content processes, so we can not validate much here - just allow all
1320 // null principals we see because they are generally safe anyway!
1321 if (aPrincipal->GetIsNullPrincipal()) {
1322 return true;
1325 // Only allow the system principal if the passed in options flags
1326 // request permitting the system principal.
1327 if (aPrincipal->IsSystemPrincipal()) {
1328 return aOptions.contains(ValidatePrincipalOptions::AllowSystem);
1331 // XXXckerschb: we should eliminate the resource carve-out here and always
1332 // validate the Principal, see Bug 1686200: Investigate Principal for pdf.js
1333 if (aPrincipal->SchemeIs("resource")) {
1334 return true;
1337 // Validate each inner principal individually, allowing us to catch expanded
1338 // principals containing the system principal, etc.
1339 if (aPrincipal->GetIsExpandedPrincipal()) {
1340 if (!aOptions.contains(ValidatePrincipalOptions::AllowExpanded)) {
1341 return false;
1343 // FIXME: There are more constraints on expanded principals in-practice,
1344 // such as the structure of extension expanded principals. This may need
1345 // to be investigated more in the future.
1346 nsCOMPtr<nsIExpandedPrincipal> expandedPrincipal =
1347 do_QueryInterface(aPrincipal);
1348 const auto& allowList = expandedPrincipal->AllowList();
1349 for (const auto& innerPrincipal : allowList) {
1350 if (!ValidatePrincipal(innerPrincipal, aOptions)) {
1351 return false;
1354 return true;
1357 // A URI with a file:// scheme can never load in a non-file content process
1358 // due to sandboxing.
1359 if (aPrincipal->SchemeIs("file")) {
1360 // If we don't support a separate 'file' process, then we can return here.
1361 if (!StaticPrefs::browser_tabs_remote_separateFileUriProcess()) {
1362 return true;
1364 return mRemoteType == FILE_REMOTE_TYPE;
1367 if (aPrincipal->SchemeIs("about")) {
1368 uint32_t flags = 0;
1369 if (NS_FAILED(aPrincipal->GetAboutModuleFlags(&flags))) {
1370 return false;
1373 // Block principals for about: URIs which can't load in this process.
1374 if (!(flags & (nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
1375 nsIAboutModule::URI_MUST_LOAD_IN_CHILD))) {
1376 return false;
1378 if (flags & nsIAboutModule::URI_MUST_LOAD_IN_EXTENSION_PROCESS) {
1379 return mRemoteType == EXTENSION_REMOTE_TYPE;
1381 return true;
1384 if (!mRemoteTypeIsolationPrincipal ||
1385 RemoteTypePrefix(mRemoteType) != FISSION_WEB_REMOTE_TYPE) {
1386 return true;
1389 // Web content can contain extension content frames, so a content process may
1390 // send us an extension's principal.
1391 auto* addonPolicy = BasePrincipal::Cast(aPrincipal)->AddonPolicy();
1392 if (addonPolicy) {
1393 return true;
1396 // Ensure that the expected site-origin matches the one specified by our
1397 // mRemoteTypeIsolationPrincipal.
1398 nsAutoCString siteOriginNoSuffix;
1399 if (NS_FAILED(aPrincipal->GetSiteOriginNoSuffix(siteOriginNoSuffix))) {
1400 return false;
1402 nsAutoCString remoteTypeSiteOriginNoSuffix;
1403 if (NS_FAILED(mRemoteTypeIsolationPrincipal->GetSiteOriginNoSuffix(
1404 remoteTypeSiteOriginNoSuffix))) {
1405 return false;
1408 return remoteTypeSiteOriginNoSuffix.Equals(siteOriginNoSuffix);
1411 /*static*/
1412 already_AddRefed<RemoteBrowser> ContentParent::CreateBrowser(
1413 const TabContext& aContext, Element* aFrameElement,
1414 const nsACString& aRemoteType, BrowsingContext* aBrowsingContext,
1415 ContentParent* aOpenerContentParent) {
1416 AUTO_PROFILER_LABEL("ContentParent::CreateBrowser", OTHER);
1418 MOZ_DIAGNOSTIC_ASSERT(
1419 !aBrowsingContext->Canonical()->GetBrowserParent(),
1420 "BrowsingContext must not have BrowserParent, or have previous "
1421 "BrowserParent cleared");
1423 // Don't bother creating new content browsers after entering shutdown. This
1424 // could lead to starting a new content process, which may significantly delay
1425 // shutdown, and the content is unlikely to be displayed.
1426 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
1427 NS_WARNING("Ignoring remote browser creation request during shutdown");
1428 return nullptr;
1431 nsAutoCString remoteType(aRemoteType);
1432 if (remoteType.IsEmpty()) {
1433 remoteType = DEFAULT_REMOTE_TYPE;
1436 TabId tabId(nsContentUtils::GenerateTabId());
1438 nsIDocShell* docShell = GetOpenerDocShellHelper(aFrameElement);
1439 TabId openerTabId;
1440 if (docShell) {
1441 openerTabId = BrowserParent::GetTabIdFrom(docShell);
1444 RefPtr<ContentParent> constructorSender;
1445 MOZ_RELEASE_ASSERT(XRE_IsParentProcess(),
1446 "Cannot allocate BrowserParent in content process");
1447 if (aOpenerContentParent && !aOpenerContentParent->IsShuttingDown()) {
1448 constructorSender = aOpenerContentParent;
1449 } else {
1450 constructorSender = GetNewOrUsedBrowserProcess(
1451 remoteType, aBrowsingContext->Group(), PROCESS_PRIORITY_FOREGROUND);
1452 if (!constructorSender) {
1453 return nullptr;
1457 aBrowsingContext->SetEmbedderElement(aFrameElement);
1459 // Ensure that the process which we're using to launch is set as the host
1460 // process for this BrowsingContextGroup.
1461 aBrowsingContext->Group()->EnsureHostProcess(constructorSender);
1463 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
1464 docShell->GetTreeOwner(getter_AddRefs(treeOwner));
1465 if (!treeOwner) {
1466 return nullptr;
1469 nsCOMPtr<nsIWebBrowserChrome> wbc = do_GetInterface(treeOwner);
1470 if (!wbc) {
1471 return nullptr;
1473 uint32_t chromeFlags = 0;
1474 wbc->GetChromeFlags(&chromeFlags);
1476 nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
1477 if (loadContext && loadContext->UsePrivateBrowsing()) {
1478 chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
1480 if (loadContext && loadContext->UseRemoteTabs()) {
1481 chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
1483 if (loadContext && loadContext->UseRemoteSubframes()) {
1484 chromeFlags |= nsIWebBrowserChrome::CHROME_FISSION_WINDOW;
1487 if (tabId == 0) {
1488 return nullptr;
1491 aBrowsingContext->Canonical()->SetOwnerProcessId(
1492 constructorSender->ChildID());
1494 RefPtr<BrowserParent> browserParent =
1495 new BrowserParent(constructorSender, tabId, aContext,
1496 aBrowsingContext->Canonical(), chromeFlags);
1498 // Open a remote endpoint for our PBrowser actor.
1499 ManagedEndpoint<PBrowserChild> childEp =
1500 constructorSender->OpenPBrowserEndpoint(browserParent);
1501 if (NS_WARN_IF(!childEp.IsValid())) {
1502 return nullptr;
1505 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
1506 if (NS_WARN_IF(!cpm)) {
1507 return nullptr;
1509 cpm->RegisterRemoteFrame(browserParent);
1511 nsCOMPtr<nsIPrincipal> initialPrincipal =
1512 NullPrincipal::Create(aBrowsingContext->OriginAttributesRef());
1513 WindowGlobalInit windowInit = WindowGlobalActor::AboutBlankInitializer(
1514 aBrowsingContext, initialPrincipal);
1516 RefPtr<WindowGlobalParent> windowParent =
1517 WindowGlobalParent::CreateDisconnected(windowInit);
1518 if (NS_WARN_IF(!windowParent)) {
1519 return nullptr;
1522 // Open a remote endpoint for the initial PWindowGlobal actor.
1523 ManagedEndpoint<PWindowGlobalChild> windowEp =
1524 browserParent->OpenPWindowGlobalEndpoint(windowParent);
1525 if (NS_WARN_IF(!windowEp.IsValid())) {
1526 return nullptr;
1529 // Tell the content process to set up its PBrowserChild.
1530 bool ok = constructorSender->SendConstructBrowser(
1531 std::move(childEp), std::move(windowEp), tabId,
1532 aContext.AsIPCTabContext(), windowInit, chromeFlags,
1533 constructorSender->ChildID(), constructorSender->IsForBrowser(),
1534 /* aIsTopLevel */ true);
1535 if (NS_WARN_IF(!ok)) {
1536 return nullptr;
1539 // Ensure that we're marked as the current BrowserParent on our
1540 // CanonicalBrowsingContext.
1541 aBrowsingContext->Canonical()->SetCurrentBrowserParent(browserParent);
1543 windowParent->Init();
1545 RefPtr<BrowserHost> browserHost = new BrowserHost(browserParent);
1546 browserParent->SetOwnerElement(aFrameElement);
1547 return browserHost.forget();
1550 void ContentParent::GetAll(nsTArray<ContentParent*>& aArray) {
1551 aArray.Clear();
1553 for (auto* cp : AllProcesses(eLive)) {
1554 aArray.AppendElement(cp);
1558 void ContentParent::GetAllEvenIfDead(nsTArray<ContentParent*>& aArray) {
1559 aArray.Clear();
1561 for (auto* cp : AllProcesses(eAll)) {
1562 aArray.AppendElement(cp);
1566 void ContentParent::BroadcastStringBundle(
1567 const StringBundleDescriptor& aBundle) {
1568 AutoTArray<StringBundleDescriptor, 1> array;
1569 array.AppendElement(aBundle);
1571 for (auto* cp : AllProcesses(eLive)) {
1572 Unused << cp->SendRegisterStringBundles(array);
1576 void ContentParent::BroadcastFontListChanged() {
1577 for (auto* cp : AllProcesses(eLive)) {
1578 Unused << cp->SendFontListChanged();
1582 void ContentParent::BroadcastShmBlockAdded(uint32_t aGeneration,
1583 uint32_t aIndex) {
1584 auto* pfl = gfxPlatformFontList::PlatformFontList();
1585 for (auto* cp : AllProcesses(eLive)) {
1586 base::SharedMemoryHandle handle =
1587 pfl->ShareShmBlockToProcess(aIndex, cp->Pid());
1588 if (handle == base::SharedMemory::NULLHandle()) {
1589 // If something went wrong here, we just skip it; the child will need to
1590 // request the block as needed, at some performance cost.
1591 continue;
1593 Unused << cp->SendFontListShmBlockAdded(aGeneration, aIndex,
1594 std::move(handle));
1598 void ContentParent::BroadcastThemeUpdate(widget::ThemeChangeKind aKind) {
1599 const FullLookAndFeel& lnf = *RemoteLookAndFeel::ExtractData();
1600 for (auto* cp : AllProcesses(eLive)) {
1601 Unused << cp->SendThemeChanged(lnf, aKind);
1605 /*static */
1606 void ContentParent::BroadcastMediaCodecsSupportedUpdate(
1607 RemoteDecodeIn aLocation, const media::MediaCodecsSupported& aSupported) {
1608 // Update processes and print the support info from the given location.
1609 sCodecsSupported[aLocation] = aSupported;
1610 for (auto* cp : AllProcesses(eAll)) {
1611 Unused << cp->SendUpdateMediaCodecsSupported(aLocation, aSupported);
1613 nsCString supportString;
1614 media::MCSInfo::GetMediaCodecsSupportedString(supportString, aSupported);
1615 LOGPDM("Broadcast support from '%s', support=%s",
1616 RemoteDecodeInToStr(aLocation), supportString.get());
1618 // Merge incoming support with existing support list from other locations
1619 media::MCSInfo::AddSupport(aSupported);
1620 auto fullSupport = media::MCSInfo::GetSupport();
1622 // Generate + save FULL support string for display in about:support
1623 supportString.Truncate();
1624 media::MCSInfo::GetMediaCodecsSupportedString(supportString, fullSupport);
1625 gfx::gfxVars::SetCodecSupportInfo(supportString);
1628 const nsACString& ContentParent::GetRemoteType() const { return mRemoteType; }
1630 static StaticRefPtr<nsIAsyncShutdownClient> sXPCOMShutdownClient;
1631 static StaticRefPtr<nsIAsyncShutdownClient> sProfileBeforeChangeClient;
1632 static StaticRefPtr<nsIAsyncShutdownClient> sQuitApplicationGrantedClient;
1634 void ContentParent::Init() {
1635 MOZ_ASSERT(sXPCOMShutdownClient);
1637 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
1638 if (obs) {
1639 size_t length = ArrayLength(sObserverTopics);
1640 for (size_t i = 0; i < length; ++i) {
1641 obs->AddObserver(this, sObserverTopics[i], false);
1645 if (obs) {
1646 nsAutoString cpId;
1647 cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
1648 obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-created",
1649 cpId.get());
1652 #ifdef ACCESSIBILITY
1653 // If accessibility is running in chrome process then start it in content
1654 // process.
1655 if (GetAccService()) {
1656 Unused << SendActivateA11y();
1658 #endif // #ifdef ACCESSIBILITY
1660 Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
1662 RefPtr<GeckoMediaPluginServiceParent> gmps(
1663 GeckoMediaPluginServiceParent::GetSingleton());
1664 if (gmps) {
1665 gmps->UpdateContentProcessGMPCapabilities(this);
1668 // Flush any pref updates that happened during launch and weren't
1669 // included in the blobs set up in BeginSubprocessLaunch.
1670 for (const Pref& pref : mQueuedPrefs) {
1671 Unused << NS_WARN_IF(!SendPreferenceUpdate(pref));
1673 mQueuedPrefs.Clear();
1675 Unused << SendInitNextGenLocalStorageEnabled(NextGenLocalStorageEnabled());
1678 // Note that for E10S we can get a false here that will be overruled by
1679 // TryToRecycleE10SOnly as late as MaybeBeginShutdown. We cannot really
1680 // foresee its result here.
1681 bool ContentParent::CheckTabDestroyWillKeepAlive(
1682 uint32_t aExpectedBrowserCount) {
1683 return ManagedPBrowserParent().Count() != aExpectedBrowserCount ||
1684 ShouldKeepProcessAlive();
1687 RecursiveMutex& ContentParent::ThreadsafeHandleMutex() {
1688 return mThreadsafeHandle->mMutex;
1691 void ContentParent::NotifyTabWillDestroy() {
1692 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)
1693 #if !defined(MOZ_WIDGET_ANDROID)
1694 /* on Android we keep processes alive more agressively, see
1695 NotifyTabDestroying where we omit MaybeBeginShutdown */
1696 || (/* we cannot trust CheckTabDestroyWillKeepAlive in E10S mode */
1697 mozilla::FissionAutostart() &&
1698 !CheckTabDestroyWillKeepAlive(mNumDestroyingTabs + 1))
1699 #endif
1701 // Once we notify the impending shutdown, the content process will stop
1702 // to process content JS on interrupt (among other things), so we need to
1703 // be sure that the process will not be re-used after this point.
1704 // The inverse is harmless, that is if we decide later to shut it down
1705 // but did not notify here, it will be just notified later (but in rare
1706 // cases too late to avoid a hang).
1707 NotifyImpendingShutdown();
1708 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1709 mNotifiedImpendingShutdownOnTabWillDestroy = true;
1710 #endif
1714 void ContentParent::MaybeBeginShutDown(uint32_t aExpectedBrowserCount,
1715 bool aSendShutDown) {
1716 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
1717 ("MaybeBeginShutdown %p, %u vs %u", this,
1718 ManagedPBrowserParent().Count(), aExpectedBrowserCount));
1719 MOZ_ASSERT(NS_IsMainThread());
1721 // We need to lock our mutex here to ensure the state does not change
1722 // between the check and the MarkAsDead.
1723 // Note that if we come through BrowserParent::Destroy our mutex is
1724 // already locked.
1725 // TODO: We want to get rid of the ThreadsafeHandle, see bug 1683595.
1726 RecursiveMutexAutoLock lock(mThreadsafeHandle->mMutex);
1728 // Both CheckTabDestroyWillKeepAlive and TryToRecycleE10SOnly will return
1729 // false if IsInOrBeyond(AppShutdownConfirmed), so if the parent shuts
1730 // down we will always shutdown the child.
1731 if (CheckTabDestroyWillKeepAlive(aExpectedBrowserCount) ||
1732 TryToRecycleE10SOnly()) {
1733 return;
1736 MOZ_LOG(
1737 ContentParent::GetLog(), LogLevel::Debug,
1738 ("Beginning ContentParent Shutdown %p (%s)", this, mRemoteType.get()));
1740 // We're dying now, prevent anything from re-using this process.
1741 MarkAsDead();
1742 SignalImpendingShutdownToContentJS();
1744 if (aSendShutDown) {
1745 AsyncSendShutDownMessage();
1746 } else {
1747 // aSendShutDown is false only when we get called from
1748 // NotifyTabDestroying where we expect a subsequent call from
1749 // NotifyTabDestroyed triggered by a Browser actor destroy
1750 // roundtrip through the content process that might never arrive.
1751 StartSendShutdownTimer();
1755 void ContentParent::AsyncSendShutDownMessage() {
1756 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
1757 ("AsyncSendShutDownMessage %p", this));
1758 MOZ_ASSERT(NS_IsMainThread());
1759 MOZ_ASSERT(sRecycledE10SProcess != this);
1761 // In the case of normal shutdown, send a shutdown message to child to
1762 // allow it to perform shutdown tasks.
1763 GetCurrentSerialEventTarget()->Dispatch(NewRunnableMethod<ShutDownMethod>(
1764 "dom::ContentParent::ShutDownProcess", this,
1765 &ContentParent::ShutDownProcess, SEND_SHUTDOWN_MESSAGE));
1768 void MaybeLogBlockShutdownDiagnostics(ContentParent* aSelf, const char* aMsg,
1769 const char* aFile, int32_t aLine) {
1770 #if defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
1771 if (aSelf->IsBlockingShutdown()) {
1772 MOZ_LOG(ContentParent::GetLog(), LogLevel::Info,
1773 ("ContentParent: id=%p pid=%d - %s at %s(%d)", aSelf, aSelf->Pid(),
1774 aMsg, aFile, aLine));
1776 #else
1777 Unused << aSelf;
1778 Unused << aMsg;
1779 Unused << aFile;
1780 Unused << aLine;
1781 #endif
1784 bool ContentParent::ShutDownProcess(ShutDownMethod aMethod) {
1785 bool result = false;
1786 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1787 ("ShutDownProcess: %p", this));
1788 // NB: must MarkAsDead() here so that this isn't accidentally
1789 // returned from Get*() while in the midst of shutdown.
1790 MarkAsDead();
1792 // Shutting down by sending a shutdown message works differently than the
1793 // other methods. We first call Shutdown() in the child. After the child is
1794 // ready, it calls FinishShutdown() on us. Then we close the channel.
1795 if (aMethod == SEND_SHUTDOWN_MESSAGE) {
1796 if (!mShutdownPending) {
1797 if (CanSend()) {
1798 // Stop sending input events with input priority when shutting down.
1799 SetInputPriorityEventEnabled(false);
1800 // If we did not earlier, let's signal the shutdown to JS now.
1801 SignalImpendingShutdownToContentJS();
1803 // Adjust the QoS priorities for shutdown, if they exist.
1804 if (StaticPrefs::threads_use_low_power_enabled() &&
1805 StaticPrefs::
1806 threads_lower_mainthread_priority_in_background_enabled()) {
1807 SetMainThreadQoSPriority(nsIThread::QOS_PRIORITY_NORMAL);
1810 // Send a high priority announcement first. If this fails, SendShutdown
1811 // will also fail.
1812 Unused << SendShutdownConfirmedHP();
1813 // Send the definite message with normal priority.
1814 if (SendShutdown()) {
1815 MaybeLogBlockShutdownDiagnostics(
1816 this, "ShutDownProcess: Sent shutdown message.", __FILE__,
1817 __LINE__);
1818 mShutdownPending = true;
1819 // We start the kill timer only after we asked our process to
1820 // shutdown.
1821 StartForceKillTimer();
1822 result = true;
1823 } else {
1824 MaybeLogBlockShutdownDiagnostics(
1825 this, "ShutDownProcess: !!! Send shutdown message failed! !!!",
1826 __FILE__, __LINE__);
1828 } else {
1829 MaybeLogBlockShutdownDiagnostics(
1830 this, "ShutDownProcess: !!! !CanSend !!!", __FILE__, __LINE__);
1832 } else {
1833 MaybeLogBlockShutdownDiagnostics(
1834 this, "ShutDownProcess: Shutdown already pending.", __FILE__,
1835 __LINE__);
1837 result = true;
1839 // If call was not successful, the channel must have been broken
1840 // somehow, and we will clean up the error in ActorDestroy.
1841 return result;
1844 using mozilla::dom::quota::QuotaManagerService;
1846 if (QuotaManagerService* qms = QuotaManagerService::GetOrCreate()) {
1847 qms->AbortOperationsForProcess(mChildID);
1850 if (aMethod == CLOSE_CHANNEL) {
1851 if (!mCalledClose) {
1852 MaybeLogBlockShutdownDiagnostics(
1853 this, "ShutDownProcess: Closing channel.", __FILE__, __LINE__);
1854 // Close() can only be called once: It kicks off the destruction sequence.
1855 mCalledClose = true;
1856 Close();
1858 result = true;
1861 // A ContentParent object might not get freed until after XPCOM shutdown has
1862 // shut down the cycle collector. But by then it's too late to release any
1863 // CC'ed objects, so we need to null them out here, while we still can. See
1864 // bug 899761.
1865 ShutDownMessageManager();
1866 return result;
1869 mozilla::ipc::IPCResult ContentParent::RecvNotifyShutdownSuccess() {
1870 if (!mShutdownPending) {
1871 return IPC_FAIL(this, "RecvNotifyShutdownSuccess without mShutdownPending");
1874 mIsNotifiedShutdownSuccess = true;
1876 return IPC_OK();
1879 mozilla::ipc::IPCResult ContentParent::RecvFinishShutdown() {
1880 if (!mShutdownPending) {
1881 return IPC_FAIL(this, "RecvFinishShutdown without mShutdownPending");
1884 // At this point, we already called ShutDownProcess once with
1885 // SEND_SHUTDOWN_MESSAGE. To actually close the channel, we call
1886 // ShutDownProcess again with CLOSE_CHANNEL.
1887 if (mCalledClose) {
1888 MaybeLogBlockShutdownDiagnostics(
1889 this, "RecvFinishShutdown: Channel already closed.", __FILE__,
1890 __LINE__);
1893 ShutDownProcess(CLOSE_CHANNEL);
1894 return IPC_OK();
1897 void ContentParent::ShutDownMessageManager() {
1898 if (!mMessageManager) {
1899 return;
1902 mMessageManager->SetOsPid(-1);
1903 mMessageManager->Disconnect();
1904 mMessageManager = nullptr;
1907 void ContentParent::AddToPool(nsTArray<ContentParent*>& aPool) {
1908 MOZ_DIAGNOSTIC_ASSERT(!mIsInPool);
1909 AssertAlive();
1910 MOZ_DIAGNOSTIC_ASSERT(!mCalledKillHard);
1911 aPool.AppendElement(this);
1912 mIsInPool = true;
1915 void ContentParent::RemoveFromPool(nsTArray<ContentParent*>& aPool) {
1916 MOZ_DIAGNOSTIC_ASSERT(mIsInPool);
1917 aPool.RemoveElement(this);
1918 mIsInPool = false;
1921 void ContentParent::AssertNotInPool() {
1922 MOZ_RELEASE_ASSERT(!mIsInPool);
1924 MOZ_RELEASE_ASSERT(sRecycledE10SProcess != this);
1925 MOZ_RELEASE_ASSERT(!sBrowserContentParents ||
1926 !sBrowserContentParents->Contains(mRemoteType) ||
1927 !sBrowserContentParents->Get(mRemoteType)->Contains(this));
1929 for (const auto& group : mGroups) {
1930 MOZ_RELEASE_ASSERT(group->GetHostProcess(mRemoteType) != this,
1931 "still a host process for one of our groups?");
1935 void ContentParent::AssertAlive() {
1936 MOZ_DIAGNOSTIC_ASSERT(!mNotifiedImpendingShutdownOnTabWillDestroy);
1937 MOZ_DIAGNOSTIC_ASSERT(!mIsSignaledImpendingShutdown);
1938 MOZ_DIAGNOSTIC_ASSERT(!IsDead());
1941 void ContentParent::RemoveFromList() {
1942 if (!mIsInPool) {
1943 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1944 AssertNotInPool();
1945 #endif
1946 return;
1949 // Ensure that this BrowsingContextGroup is no longer used to host new
1950 // documents from any associated BrowsingContextGroups. It may become a host
1951 // again in the future, if it is restored to the pool.
1952 for (const auto& group : mGroups) {
1953 group->RemoveHostProcess(this);
1956 StopRecyclingE10SOnly(/* aForeground */ false);
1958 if (sBrowserContentParents) {
1959 if (auto entry = sBrowserContentParents->Lookup(mRemoteType)) {
1960 const auto& contentParents = entry.Data();
1961 RemoveFromPool(*contentParents);
1962 if (contentParents->IsEmpty()) {
1963 entry.Remove();
1966 if (sBrowserContentParents->IsEmpty()) {
1967 delete sBrowserContentParents;
1968 sBrowserContentParents = nullptr;
1973 void ContentParent::MarkAsDead() {
1974 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
1975 ("Marking ContentProcess %p as dead", this));
1976 MOZ_DIAGNOSTIC_ASSERT(!sInProcessSelector);
1977 RemoveFromList();
1979 // Flag shutdown has started for us to our threadsafe handle.
1981 // Depending on how we get here, the lock might or might not be set.
1982 RecursiveMutexAutoLock lock(mThreadsafeHandle->mMutex);
1984 mThreadsafeHandle->mShutdownStarted = true;
1987 // Prevent this process from being re-used.
1988 PreallocatedProcessManager::Erase(this);
1989 StopRecyclingE10SOnly(false);
1991 #if defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_PROFILE_GENERATE)
1992 if (IsAlive()) {
1993 // We're intentionally killing the content process at this point to ensure
1994 // that we never have a "dead" content process sitting around and occupying
1995 // an Android Service.
1997 // The exception is in MOZ_PROFILE_GENERATE builds where we must allow the
1998 // process to shutdown cleanly so that profile data can be dumped. This is
1999 // okay as we will not reach our process limit during the profile run.
2000 nsCOMPtr<nsIEventTarget> launcherThread(GetIPCLauncher());
2001 MOZ_ASSERT(launcherThread);
2003 auto procType = java::GeckoProcessType::CONTENT();
2004 auto selector =
2005 java::GeckoProcessManager::Selector::New(procType, OtherPid());
2007 launcherThread->Dispatch(NS_NewRunnableFunction(
2008 "ContentParent::MarkAsDead",
2009 [selector =
2010 java::GeckoProcessManager::Selector::GlobalRef(selector)]() {
2011 java::GeckoProcessManager::ShutdownProcess(selector);
2012 }));
2014 #endif
2016 if (mScriptableHelper) {
2017 static_cast<ScriptableCPInfo*>(mScriptableHelper.get())->ProcessDied();
2018 mScriptableHelper = nullptr;
2021 mLifecycleState = LifecycleState::DEAD;
2024 void ContentParent::OnChannelError() {
2025 RefPtr<ContentParent> kungFuDeathGrip(this);
2026 PContentParent::OnChannelError();
2029 void ContentParent::ProcessingError(Result aCode, const char* aReason) {
2030 if (MsgDropped == aCode) {
2031 return;
2033 // Other errors are big deals.
2034 #ifndef FUZZING
2035 KillHard(aReason);
2036 #endif
2037 if (CanSend()) {
2038 GetIPCChannel()->InduceConnectionError();
2042 void ContentParent::ActorDestroy(ActorDestroyReason why) {
2043 #ifdef FUZZING_SNAPSHOT
2044 MOZ_FUZZING_IPC_DROP_PEER("ContentParent::ActorDestroy");
2045 #endif
2047 if (mSendShutdownTimer) {
2048 mSendShutdownTimer->Cancel();
2049 mSendShutdownTimer = nullptr;
2051 if (mForceKillTimer) {
2052 mForceKillTimer->Cancel();
2053 mForceKillTimer = nullptr;
2056 // Signal shutdown completion regardless of error state, so we can
2057 // finish waiting in the xpcom-shutdown/profile-before-change observer.
2058 RemoveShutdownBlockers();
2060 if (mHangMonitorActor) {
2061 ProcessHangMonitor::RemoveProcess(mHangMonitorActor);
2062 mHangMonitorActor = nullptr;
2065 RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get();
2066 if (fss) {
2067 fss->Forget(ChildID());
2070 if (why == NormalShutdown && !mCalledClose) {
2071 // If we shut down normally but haven't called Close, assume somebody
2072 // else called Close on us. In that case, we still need to call
2073 // ShutDownProcess below to perform other necessary clean up.
2074 mCalledClose = true;
2077 // Make sure we always clean up.
2078 ShutDownProcess(CLOSE_CHANNEL);
2080 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
2081 if (obs) {
2082 size_t length = ArrayLength(sObserverTopics);
2083 for (size_t i = 0; i < length; ++i) {
2084 obs->RemoveObserver(static_cast<nsIObserver*>(this), sObserverTopics[i]);
2088 // remove the global remote preferences observers
2089 Preferences::RemoveObserver(this, "");
2090 gfxVars::RemoveReceiver(this);
2092 if (GPUProcessManager* gpu = GPUProcessManager::Get()) {
2093 // Note: the manager could have shutdown already.
2094 gpu->RemoveListener(this);
2097 RecvRemoveGeolocationListener();
2099 // Destroy our JSProcessActors, and reject any pending queries.
2100 JSActorDidDestroy();
2102 if (obs) {
2103 RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
2105 props->SetPropertyAsUint64(u"childID"_ns, mChildID);
2107 if (AbnormalShutdown == why) {
2108 Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT, "content"_ns,
2111 props->SetPropertyAsBool(u"abnormal"_ns, true);
2113 nsAutoString dumpID;
2114 // There's a window in which child processes can crash
2115 // after IPC is established, but before a crash reporter
2116 // is created.
2117 if (mCrashReporter) {
2118 // if mCreatedPairedMinidumps is true, we've already generated
2119 // parent/child dumps for desktop crashes.
2120 if (!mCreatedPairedMinidumps) {
2121 #if defined(XP_MACOSX)
2122 RefPtr<nsAvailableMemoryWatcherBase> memWatcher;
2123 memWatcher = nsAvailableMemoryWatcherBase::GetSingleton();
2124 memWatcher->AddChildAnnotations(mCrashReporter);
2125 #endif
2127 mCrashReporter->GenerateCrashReport(OtherPid());
2130 if (mCrashReporter->HasMinidump()) {
2131 dumpID = mCrashReporter->MinidumpID();
2133 } else {
2134 HandleOrphanedMinidump(&dumpID);
2137 if (!dumpID.IsEmpty()) {
2138 props->SetPropertyAsAString(u"dumpID"_ns, dumpID);
2141 nsAutoString cpId;
2142 cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
2143 obs->NotifyObservers((nsIPropertyBag2*)props, "ipc:content-shutdown",
2144 cpId.get());
2147 // Remove any and all idle listeners.
2148 if (mIdleListeners.Length() > 0) {
2149 nsCOMPtr<nsIUserIdleService> idleService =
2150 do_GetService("@mozilla.org/widget/useridleservice;1");
2151 if (idleService) {
2152 RefPtr<ParentIdleListener> listener;
2153 for (const auto& lentry : mIdleListeners) {
2154 listener = static_cast<ParentIdleListener*>(lentry.get());
2155 idleService->RemoveIdleObserver(listener, listener->mTime);
2158 mIdleListeners.Clear();
2161 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
2162 ("destroying Subprocess in ActorDestroy: ContentParent %p "
2163 "mSubprocess %p handle %" PRIuPTR,
2164 this, mSubprocess,
2165 mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
2166 // FIXME (bug 1520997): does this really need an additional dispatch?
2167 if (GetCurrentSerialEventTarget()) {
2168 GetCurrentSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
2169 "DelayedDeleteSubprocessRunnable", [subprocess = mSubprocess] {
2170 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2171 ("destroyed Subprocess in ActorDestroy: Subprocess %p handle "
2172 "%" PRIuPTR,
2173 subprocess,
2174 subprocess ? (uintptr_t)subprocess->GetChildProcessHandle()
2175 : -1));
2176 subprocess->Destroy();
2177 }));
2179 mSubprocess = nullptr;
2181 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
2182 if (cpm) {
2183 cpm->RemoveContentProcess(this->ChildID());
2186 if (mDriverCrashGuard) {
2187 mDriverCrashGuard->NotifyCrashed();
2190 // Unregister all the BlobURLs registered by the ContentChild.
2191 for (uint32_t i = 0; i < mBlobURLs.Length(); ++i) {
2192 BlobURLProtocolHandler::RemoveDataEntry(mBlobURLs[i]);
2195 mBlobURLs.Clear();
2197 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2198 AssertNotInPool();
2199 #endif
2201 // As this process is going away, ensure that every BrowsingContext hosted by
2202 // it has been detached, and every BrowsingContextGroup has been fully
2203 // unsubscribed.
2204 BrowsingContext::DiscardFromContentParent(this);
2206 const nsTHashSet<RefPtr<BrowsingContextGroup>> groups = std::move(mGroups);
2207 for (const auto& group : groups) {
2208 group->Unsubscribe(this);
2210 MOZ_DIAGNOSTIC_ASSERT(mGroups.IsEmpty());
2212 mPendingLoadStates.Clear();
2215 bool ContentParent::TryToRecycleE10SOnly() {
2216 // Only try to recycle "web" content processes, as other remote types are
2217 // generally more unique, and cannot be effectively re-used. This is disabled
2218 // with Fission, as "web" content processes are no longer frequently used.
2220 // Disabling the process pre-allocator will also disable process recycling,
2221 // allowing for more consistent process counts under testing.
2222 if (mRemoteType != DEFAULT_REMOTE_TYPE || mozilla::FissionAutostart() ||
2223 !PreallocatedProcessManager::Enabled()) {
2224 return false;
2227 // This life time check should be replaced by a memory health check (memory
2228 // usage + fragmentation).
2230 // Note that this is specifically to help with edge cases that rapidly
2231 // create-and-destroy processes
2232 const double kMaxLifeSpan = 5;
2233 MOZ_LOG(
2234 ContentParent::GetLog(), LogLevel::Debug,
2235 ("TryToRecycle ContentProcess %p (%u) with lifespan %f seconds", this,
2236 (unsigned int)ChildID(), (TimeStamp::Now() - mActivateTS).ToSeconds()));
2238 if (mCalledKillHard || !IsAlive() ||
2239 (TimeStamp::Now() - mActivateTS).ToSeconds() > kMaxLifeSpan) {
2240 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2241 ("TryToRecycle did not recycle %p", this));
2243 // It's possible that the process was already cached, and we're being called
2244 // from a different path, and we're now past kMaxLifeSpan (or some other).
2245 // Ensure that if we're going to kill this process we don't recycle it.
2246 StopRecyclingE10SOnly(/* aForeground */ false);
2247 return false;
2250 if (!sRecycledE10SProcess) {
2251 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2252 ("TryToRecycle began recycling %p", this));
2253 sRecycledE10SProcess = this;
2255 ProcessPriorityManager::SetProcessPriority(this,
2256 PROCESS_PRIORITY_BACKGROUND);
2257 return true;
2260 if (sRecycledE10SProcess == this) {
2261 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2262 ("TryToRecycle continue recycling %p", this));
2263 return true;
2266 // Some other process is already being recycled, just shut this one down.
2267 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2268 ("TryToRecycle did not recycle %p (already recycling %p)", this,
2269 sRecycledE10SProcess.get()));
2270 return false;
2273 void ContentParent::StopRecyclingE10SOnly(bool aForeground) {
2274 if (sRecycledE10SProcess != this) {
2275 return;
2278 sRecycledE10SProcess = nullptr;
2279 if (aForeground) {
2280 ProcessPriorityManager::SetProcessPriority(this,
2281 PROCESS_PRIORITY_FOREGROUND);
2285 bool ContentParent::HasActiveWorker() {
2286 // If we have active workers, we need to stay alive.
2288 // Most of the times we'll get here with the mutex acquired, but still.
2289 RecursiveMutexAutoLock lock(mThreadsafeHandle->mMutex);
2290 if (mThreadsafeHandle->mRemoteWorkerActorCount) {
2291 return true;
2294 return false;
2297 bool ContentParent::ShouldKeepProcessAlive() {
2298 if (HasActiveWorker()) {
2299 return true;
2302 if (mNumKeepaliveCalls > 0) {
2303 return true;
2306 if (IsLaunching()) {
2307 return true;
2310 // If we have already been marked as dead, don't prevent shutdown.
2311 if (IsDead()) {
2312 return false;
2315 // If everything is going down, there is no need to keep us alive, neither.
2316 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
2317 return false;
2320 if (!sBrowserContentParents) {
2321 return false;
2324 auto contentParents = sBrowserContentParents->Get(mRemoteType);
2325 if (!contentParents) {
2326 return false;
2329 // We might want to keep some content processes alive for performance reasons.
2330 // e.g. test runs and privileged content process for some about: pages.
2331 // We don't want to alter behavior if the pref is not set, so default to 0.
2332 int32_t processesToKeepAlive = 0;
2334 nsAutoCString keepAlivePref("dom.ipc.keepProcessesAlive.");
2336 if (StringBeginsWith(mRemoteType, FISSION_WEB_REMOTE_TYPE) &&
2337 xpc::IsInAutomation()) {
2338 keepAlivePref.Append(FISSION_WEB_REMOTE_TYPE);
2339 keepAlivePref.AppendLiteral(".perOrigin");
2340 } else {
2341 keepAlivePref.Append(mRemoteType);
2343 if (NS_FAILED(
2344 Preferences::GetInt(keepAlivePref.get(), &processesToKeepAlive))) {
2345 return false;
2348 int32_t numberOfAliveProcesses = contentParents->Length();
2350 return numberOfAliveProcesses <= processesToKeepAlive;
2353 void ContentParent::NotifyTabDestroying() {
2354 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2355 ("NotifyTabDestroying %p:", this));
2356 // There can be more than one PBrowser for a given app process
2357 // because of popup windows. PBrowsers can also destroy
2358 // concurrently. When all the PBrowsers are destroying, kick off
2359 // another task to ensure the child process *really* shuts down,
2360 // even if the PBrowsers themselves never finish destroying.
2361 ++mNumDestroyingTabs;
2364 * We intentionally skip this code on Android:
2365 * 1. Android has a fixed upper bound on the number of content processes, so
2366 * we prefer to re-use them whenever possible (as opposed to letting an
2367 * old process wind down while we launch a new one).
2368 * 2. GeckoView always hard-kills content processes (and if it does not,
2369 * Android itself will), so we don't concern ourselves with the ForceKill
2370 * timer either.
2372 #if !defined(MOZ_WIDGET_ANDROID)
2373 MaybeBeginShutDown(/* aExpectedBrowserCount */ mNumDestroyingTabs,
2374 /* aSendShutDown */ false);
2375 #endif // !defined(MOZ_WIDGET_ANDROID)
2378 void ContentParent::AddKeepAlive() {
2379 AssertAlive();
2380 // Something wants to keep this content process alive.
2381 ++mNumKeepaliveCalls;
2384 void ContentParent::RemoveKeepAlive() {
2385 MOZ_DIAGNOSTIC_ASSERT(mNumKeepaliveCalls > 0);
2386 --mNumKeepaliveCalls;
2388 MaybeBeginShutDown();
2391 void ContentParent::StartSendShutdownTimer() {
2392 if (mSendShutdownTimer || !CanSend()) {
2393 return;
2396 uint32_t timeoutSecs = StaticPrefs::dom_ipc_tabs_shutdownTimeoutSecs();
2397 if (timeoutSecs > 0) {
2398 NS_NewTimerWithFuncCallback(getter_AddRefs(mSendShutdownTimer),
2399 ContentParent::SendShutdownTimerCallback, this,
2400 timeoutSecs * 1000, nsITimer::TYPE_ONE_SHOT,
2401 "dom::ContentParent::StartSendShutdownTimer");
2402 MOZ_ASSERT(mSendShutdownTimer);
2406 void ContentParent::StartForceKillTimer() {
2407 if (mForceKillTimer || !CanSend()) {
2408 return;
2411 uint32_t timeoutSecs = StaticPrefs::dom_ipc_tabs_shutdownTimeoutSecs();
2412 if (timeoutSecs > 0) {
2413 NS_NewTimerWithFuncCallback(getter_AddRefs(mForceKillTimer),
2414 ContentParent::ForceKillTimerCallback, this,
2415 timeoutSecs * 1000, nsITimer::TYPE_ONE_SHOT,
2416 "dom::ContentParent::StartForceKillTimer");
2417 MOZ_ASSERT(mForceKillTimer);
2421 void ContentParent::NotifyTabDestroyed(const TabId& aTabId,
2422 bool aNotifiedDestroying) {
2423 if (aNotifiedDestroying) {
2424 --mNumDestroyingTabs;
2427 nsTArray<PContentPermissionRequestParent*> parentArray =
2428 nsContentPermissionUtils::GetContentPermissionRequestParentById(aTabId);
2430 // Need to close undeleted ContentPermissionRequestParents before tab is
2431 // closed.
2432 for (auto& permissionRequestParent : parentArray) {
2433 Unused << PContentPermissionRequestParent::Send__delete__(
2434 permissionRequestParent);
2437 // There can be more than one PBrowser for a given app process
2438 // because of popup windows. When the last one closes, shut
2439 // us down.
2440 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
2441 ("NotifyTabDestroyed %p", this));
2443 MaybeBeginShutDown(/* aExpectedBrowserCount */ 1);
2446 TestShellParent* ContentParent::CreateTestShell() {
2447 RefPtr<TestShellParent> actor = new TestShellParent();
2448 if (!SendPTestShellConstructor(actor)) {
2449 return nullptr;
2451 return actor;
2454 bool ContentParent::DestroyTestShell(TestShellParent* aTestShell) {
2455 return PTestShellParent::Send__delete__(aTestShell);
2458 TestShellParent* ContentParent::GetTestShellSingleton() {
2459 PTestShellParent* p = LoneManagedOrNullAsserts(ManagedPTestShellParent());
2460 return static_cast<TestShellParent*>(p);
2463 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
2464 // Append the sandbox command line parameters that are not static. i.e.,
2465 // parameters that can be different for different child processes.
2466 void ContentParent::AppendDynamicSandboxParams(
2467 std::vector<std::string>& aArgs) {
2468 // For file content processes
2469 if (GetRemoteType() == FILE_REMOTE_TYPE) {
2470 MacSandboxInfo::AppendFileAccessParam(aArgs, true);
2474 // Generate the static sandbox command line parameters and store
2475 // them in the provided params vector to be used each time a new
2476 // content process is launched.
2477 static void CacheSandboxParams(std::vector<std::string>& aCachedParams) {
2478 // This must only be called once and we should
2479 // be starting with an empty list of parameters.
2480 MOZ_ASSERT(aCachedParams.empty());
2482 MacSandboxInfo info;
2483 info.type = MacSandboxType_Content;
2484 info.level = GetEffectiveContentSandboxLevel();
2486 // Sandbox logging
2487 if (Preferences::GetBool("security.sandbox.logging.enabled") ||
2488 PR_GetEnv("MOZ_SANDBOX_LOGGING")) {
2489 info.shouldLog = true;
2492 // Audio access
2493 if (!StaticPrefs::media_cubeb_sandbox()) {
2494 info.hasAudio = true;
2497 // Window server access. If the disconnect-windowserver pref is not
2498 // "true" or out-of-process WebGL is not enabled, allow window server
2499 // access in the sandbox policy.
2500 if (!Preferences::GetBool(
2501 "security.sandbox.content.mac.disconnect-windowserver") ||
2502 !Preferences::GetBool("webgl.out-of-process")) {
2503 info.hasWindowServer = true;
2506 // .app path (normalized)
2507 nsAutoCString appPath;
2508 if (!nsMacUtilsImpl::GetAppPath(appPath)) {
2509 MOZ_CRASH("Failed to get app dir paths");
2511 info.appPath = appPath.get();
2513 // TESTING_READ_PATH1
2514 nsAutoCString testingReadPath1;
2515 Preferences::GetCString("security.sandbox.content.mac.testing_read_path1",
2516 testingReadPath1);
2517 if (!testingReadPath1.IsEmpty()) {
2518 info.testingReadPath1 = testingReadPath1.get();
2521 // TESTING_READ_PATH2
2522 nsAutoCString testingReadPath2;
2523 Preferences::GetCString("security.sandbox.content.mac.testing_read_path2",
2524 testingReadPath2);
2525 if (!testingReadPath2.IsEmpty()) {
2526 info.testingReadPath2 = testingReadPath2.get();
2529 // TESTING_READ_PATH3, TESTING_READ_PATH4. In non-packaged builds,
2530 // these are used to whitelist the repo dir and object dir respectively.
2531 nsresult rv;
2532 if (!mozilla::IsPackagedBuild()) {
2533 // Repo dir
2534 nsCOMPtr<nsIFile> repoDir;
2535 rv = nsMacUtilsImpl::GetRepoDir(getter_AddRefs(repoDir));
2536 if (NS_FAILED(rv)) {
2537 MOZ_CRASH("Failed to get path to repo dir");
2539 nsCString repoDirPath;
2540 Unused << repoDir->GetNativePath(repoDirPath);
2541 info.testingReadPath3 = repoDirPath.get();
2543 // Object dir
2544 nsCOMPtr<nsIFile> objDir;
2545 rv = nsMacUtilsImpl::GetObjDir(getter_AddRefs(objDir));
2546 if (NS_FAILED(rv)) {
2547 MOZ_CRASH("Failed to get path to build object dir");
2549 nsCString objDirPath;
2550 Unused << objDir->GetNativePath(objDirPath);
2551 info.testingReadPath4 = objDirPath.get();
2554 // DEBUG_WRITE_DIR
2555 # ifdef DEBUG
2556 // For bloat/leak logging or when a content process dies intentionally
2557 // (|NoteIntentionalCrash|) for tests, it wants to log that it did this.
2558 // Allow writing to this location.
2559 nsAutoCString bloatLogDirPath;
2560 if (NS_SUCCEEDED(nsMacUtilsImpl::GetBloatLogDir(bloatLogDirPath))) {
2561 info.debugWriteDir = bloatLogDirPath.get();
2563 # endif // DEBUG
2565 info.AppendAsParams(aCachedParams);
2568 // Append sandboxing command line parameters.
2569 void ContentParent::AppendSandboxParams(std::vector<std::string>& aArgs) {
2570 MOZ_ASSERT(sMacSandboxParams != nullptr);
2572 // An empty sMacSandboxParams indicates this is the
2573 // first invocation and we don't have cached params yet.
2574 if (sMacSandboxParams->empty()) {
2575 CacheSandboxParams(*sMacSandboxParams);
2576 MOZ_ASSERT(!sMacSandboxParams->empty());
2579 // Append cached arguments.
2580 aArgs.insert(aArgs.end(), sMacSandboxParams->begin(),
2581 sMacSandboxParams->end());
2583 // Append remaining arguments.
2584 AppendDynamicSandboxParams(aArgs);
2586 #endif // XP_MACOSX && MOZ_SANDBOX
2588 bool ContentParent::BeginSubprocessLaunch(ProcessPriority aPriority) {
2589 AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess", OTHER);
2591 // Ensure we will not rush through our shutdown phases while launching.
2592 // LaunchSubprocessReject will remove them in case of failure,
2593 // otherwise ActorDestroy will take care.
2594 AddShutdownBlockers();
2596 if (!ContentProcessManager::GetSingleton()) {
2597 MOZ_ASSERT(false, "Unable to acquire ContentProcessManager singleton!");
2598 return false;
2601 std::vector<std::string> extraArgs;
2602 geckoargs::sChildID.Put(mChildID, extraArgs);
2603 geckoargs::sIsForBrowser.Put(IsForBrowser(), extraArgs);
2604 geckoargs::sNotForBrowser.Put(!IsForBrowser(), extraArgs);
2606 // Prefs information is passed via anonymous shared memory to avoid bloating
2607 // the command line.
2609 // Instantiate the pref serializer. It will be cleaned up in
2610 // `LaunchSubprocessReject`/`LaunchSubprocessResolve`.
2611 mPrefSerializer = MakeUnique<mozilla::ipc::SharedPreferenceSerializer>();
2612 if (!mPrefSerializer->SerializeToSharedMemory(GeckoProcessType_Content,
2613 GetRemoteType())) {
2614 NS_WARNING("SharedPreferenceSerializer::SerializeToSharedMemory failed");
2615 MarkAsDead();
2616 return false;
2618 mPrefSerializer->AddSharedPrefCmdLineArgs(*mSubprocess, extraArgs);
2620 // The JS engine does some computation during the initialization which can be
2621 // shared across processes. We add command line arguments to pass a file
2622 // handle and its content length, to minimize the startup time of content
2623 // processes.
2624 ::mozilla::ipc::ExportSharedJSInit(*mSubprocess, extraArgs);
2626 // Register ContentParent as an observer for changes to any pref
2627 // whose prefix matches the empty string, i.e. all of them. The
2628 // observation starts here in order to capture pref updates that
2629 // happen during async launch.
2630 Preferences::AddStrongObserver(this, "");
2632 if (gSafeMode) {
2633 geckoargs::sSafeMode.Put(extraArgs);
2636 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
2637 if (IsContentSandboxEnabled()) {
2638 AppendSandboxParams(extraArgs);
2639 mSubprocess->DisableOSActivityMode();
2641 #endif
2643 nsCString parentBuildID(mozilla::PlatformBuildID());
2644 geckoargs::sParentBuildID.Put(parentBuildID.get(), extraArgs);
2646 #ifdef MOZ_WIDGET_GTK
2647 // This is X11-only pending a solution for WebGL in Wayland mode.
2648 if (StaticPrefs::dom_ipc_avoid_gtk() &&
2649 StaticPrefs::widget_non_native_theme_enabled() &&
2650 widget::GdkIsX11Display()) {
2651 mSubprocess->SetEnv("MOZ_HEADLESS", "1");
2653 #endif
2655 mLaunchYieldTS = TimeStamp::Now();
2656 return mSubprocess->AsyncLaunch(std::move(extraArgs));
2659 void ContentParent::LaunchSubprocessReject() {
2660 NS_WARNING("failed to launch child in the parent");
2661 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
2662 ("failed to launch child in the parent"));
2663 // Now that communication with the child is complete, we can cleanup
2664 // the preference serializer.
2665 mPrefSerializer = nullptr;
2666 if (mIsAPreallocBlocker) {
2667 PreallocatedProcessManager::RemoveBlocker(mRemoteType, this);
2668 mIsAPreallocBlocker = false;
2670 MarkAsDead();
2671 RemoveShutdownBlockers();
2674 bool ContentParent::LaunchSubprocessResolve(bool aIsSync,
2675 ProcessPriority aPriority) {
2676 AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess::resolve", OTHER);
2678 if (mLaunchResolved) {
2679 // We've already been called, return.
2680 MOZ_ASSERT(sCreatedFirstContentProcess);
2681 MOZ_ASSERT(!mPrefSerializer);
2682 MOZ_ASSERT(mLifecycleState != LifecycleState::LAUNCHING);
2683 return mLaunchResolvedOk;
2685 mLaunchResolved = true;
2687 // Now that communication with the child is complete, we can cleanup
2688 // the preference serializer.
2689 mPrefSerializer = nullptr;
2691 const auto launchResumeTS = TimeStamp::Now();
2692 if (profiler_thread_is_being_profiled_for_markers()) {
2693 nsPrintfCString marker("Process start%s for %u",
2694 mIsAPreallocBlocker ? " (immediate)" : "",
2695 (unsigned int)ChildID());
2696 PROFILER_MARKER_TEXT(
2697 mIsAPreallocBlocker ? ProfilerString8View("Process Immediate Launch")
2698 : ProfilerString8View("Process Launch"),
2699 DOM, MarkerTiming::Interval(mLaunchTS, launchResumeTS), marker);
2702 if (!sCreatedFirstContentProcess) {
2703 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
2704 obs->NotifyObservers(nullptr, "ipc:first-content-process-created", nullptr);
2705 sCreatedFirstContentProcess = true;
2708 mSubprocess->TakeInitialEndpoint().Bind(this);
2710 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
2711 if (!cpm) {
2712 NS_WARNING("immediately shutting-down caused by our shutdown");
2713 ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
2714 return false;
2716 cpm->AddContentProcess(this);
2718 #ifdef MOZ_CODE_COVERAGE
2719 Unused << SendShareCodeCoverageMutex(
2720 CodeCoverageHandler::Get()->GetMutexHandle());
2721 #endif
2723 // We must be in the LAUNCHING state still. If we've somehow already been
2724 // marked as DEAD, fail the process launch, and immediately begin tearing down
2725 // the content process.
2726 if (IsDead()) {
2727 NS_WARNING("immediately shutting-down already-dead process");
2728 ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
2729 return false;
2731 MOZ_ASSERT(mLifecycleState == LifecycleState::LAUNCHING);
2732 mLifecycleState = LifecycleState::ALIVE;
2734 if (!InitInternal(aPriority)) {
2735 NS_WARNING("failed to initialize child in the parent");
2736 // We've already called Open() by this point, so we need to close the
2737 // channel to avoid leaking the process.
2738 ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
2739 return false;
2742 mHangMonitorActor = ProcessHangMonitor::AddProcess(this);
2744 // Set a reply timeout for CPOWs.
2745 SetReplyTimeoutMs(StaticPrefs::dom_ipc_cpow_timeout());
2747 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
2748 if (obs) {
2749 nsAutoString cpId;
2750 cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
2751 obs->NotifyObservers(static_cast<nsIObserver*>(this),
2752 "ipc:content-initializing", cpId.get());
2755 Init();
2757 mLifecycleState = LifecycleState::INITIALIZED;
2759 if (aIsSync) {
2760 Telemetry::AccumulateTimeDelta(Telemetry::CONTENT_PROCESS_SYNC_LAUNCH_MS,
2761 mLaunchTS);
2762 } else {
2763 Telemetry::AccumulateTimeDelta(Telemetry::CONTENT_PROCESS_LAUNCH_TOTAL_MS,
2764 mLaunchTS);
2766 Telemetry::Accumulate(
2767 Telemetry::CONTENT_PROCESS_LAUNCH_MAINTHREAD_MS,
2768 static_cast<uint32_t>(
2769 ((mLaunchYieldTS - mLaunchTS) + (TimeStamp::Now() - launchResumeTS))
2770 .ToMilliseconds()));
2773 mLaunchResolvedOk = true;
2774 return true;
2777 bool ContentParent::LaunchSubprocessSync(
2778 hal::ProcessPriority aInitialPriority) {
2779 // We've started a sync content process launch.
2780 Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC, 1);
2782 if (BeginSubprocessLaunch(aInitialPriority)) {
2783 const bool ok = mSubprocess->WaitForProcessHandle();
2784 if (ok && LaunchSubprocessResolve(/* aIsSync = */ true, aInitialPriority)) {
2785 return true;
2788 LaunchSubprocessReject();
2789 return false;
2792 RefPtr<ContentParent::LaunchPromise> ContentParent::LaunchSubprocessAsync(
2793 hal::ProcessPriority aInitialPriority) {
2794 // We've started an async content process launch.
2795 Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC, 0);
2797 if (!BeginSubprocessLaunch(aInitialPriority)) {
2798 // Launch aborted because of shutdown. Bailout.
2799 LaunchSubprocessReject();
2800 return LaunchPromise::CreateAndReject(NS_ERROR_ILLEGAL_DURING_SHUTDOWN,
2801 __func__);
2804 // Otherwise, wait until the process is ready.
2805 RefPtr<ProcessHandlePromise> ready = mSubprocess->WhenProcessHandleReady();
2806 RefPtr<ContentParent> self = this;
2807 mLaunchYieldTS = TimeStamp::Now();
2809 return ready->Then(
2810 GetCurrentSerialEventTarget(), __func__,
2811 [self, aInitialPriority](
2812 const ProcessHandlePromise::ResolveOrRejectValue& aValue) {
2813 if (aValue.IsResolve() &&
2814 self->LaunchSubprocessResolve(/* aIsSync = */ false,
2815 aInitialPriority)) {
2816 return LaunchPromise::CreateAndResolve(self, __func__);
2818 self->LaunchSubprocessReject();
2819 return LaunchPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
2823 ContentParent::ContentParent(const nsACString& aRemoteType)
2824 : mSubprocess(nullptr),
2825 mLaunchTS(TimeStamp::Now()),
2826 mLaunchYieldTS(mLaunchTS),
2827 mActivateTS(mLaunchTS),
2828 mIsAPreallocBlocker(false),
2829 mRemoteType(aRemoteType),
2830 mChildID(gContentChildID++),
2831 mGeolocationWatchID(-1),
2832 mThreadsafeHandle(
2833 new ThreadsafeContentParentHandle(this, mChildID, mRemoteType)),
2834 mNumDestroyingTabs(0),
2835 mNumKeepaliveCalls(0),
2836 mLifecycleState(LifecycleState::LAUNCHING),
2837 mIsForBrowser(!mRemoteType.IsEmpty()),
2838 mCalledClose(false),
2839 mCalledKillHard(false),
2840 mCreatedPairedMinidumps(false),
2841 mShutdownPending(false),
2842 mLaunchResolved(false),
2843 mLaunchResolvedOk(false),
2844 mIsRemoteInputEventQueueEnabled(false),
2845 mIsInputPriorityEventEnabled(false),
2846 mIsInPool(false),
2847 mGMPCreated(false),
2848 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2849 mBlockShutdownCalled(false),
2850 #endif
2851 mHangMonitorActor(nullptr) {
2852 mRemoteTypeIsolationPrincipal =
2853 CreateRemoteTypeIsolationPrincipal(aRemoteType);
2855 // Insert ourselves into the global linked list of ContentParent objects.
2856 if (!sContentParents) {
2857 sContentParents = new LinkedList<ContentParent>();
2859 sContentParents->insertBack(this);
2861 mMessageManager = nsFrameMessageManager::NewProcessMessageManager(true);
2863 #if defined(XP_WIN)
2864 // Request Windows message deferral behavior on our side of the PContent
2865 // channel. Generally only applies to the situation where we get caught in
2866 // a deadlock with the plugin process when sending CPOWs.
2867 GetIPCChannel()->SetChannelFlags(
2868 MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
2869 #endif
2871 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2872 bool isFile = mRemoteType == FILE_REMOTE_TYPE;
2873 mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content, isFile);
2874 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
2875 ("CreateSubprocess: ContentParent %p mSubprocess %p handle %" PRIuPTR,
2876 this, mSubprocess,
2877 mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
2879 // This is safe to do in the constructor, as it doesn't take a strong
2880 // reference.
2881 mScriptableHelper = new ScriptableCPInfo(this);
2884 ContentParent::~ContentParent() {
2885 if (mSendShutdownTimer) {
2886 mSendShutdownTimer->Cancel();
2888 if (mForceKillTimer) {
2889 mForceKillTimer->Cancel();
2892 AssertIsOnMainThread();
2894 // Clear the weak reference from the threadsafe handle back to this actor.
2895 mThreadsafeHandle->mWeakActor = nullptr;
2897 if (mIsAPreallocBlocker) {
2898 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2899 ("Removing blocker on ContentProcess destruction"));
2900 PreallocatedProcessManager::RemoveBlocker(mRemoteType, this);
2901 mIsAPreallocBlocker = false;
2904 // We should be removed from all these lists in ActorDestroy.
2905 AssertNotInPool();
2907 // Normally mSubprocess is destroyed in ActorDestroy, but that won't
2908 // happen if the process wasn't launched or if it failed to launch.
2909 if (mSubprocess) {
2910 MOZ_LOG(
2911 ContentParent::GetLog(), LogLevel::Verbose,
2912 ("DestroySubprocess: ContentParent %p mSubprocess %p handle %" PRIuPTR,
2913 this, mSubprocess,
2914 mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
2915 mSubprocess->Destroy();
2918 // Make sure to clear the connection from `mScriptableHelper` if it hasn't
2919 // been cleared yet.
2920 if (mScriptableHelper) {
2921 static_cast<ScriptableCPInfo*>(mScriptableHelper.get())->ProcessDied();
2922 mScriptableHelper = nullptr;
2926 bool ContentParent::InitInternal(ProcessPriority aInitialPriority) {
2927 // We can't access the locale service after shutdown has started. Since we
2928 // can't init the process without it, and since we're going to be canceling
2929 // whatever load attempt that initiated this process creation anyway, just
2930 // bail out now if shutdown has already started.
2931 if (PastShutdownPhase(ShutdownPhase::XPCOMShutdown)) {
2932 return false;
2935 XPCOMInitData xpcomInit;
2937 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2938 ("ContentParent::InitInternal: %p", (void*)this));
2939 nsCOMPtr<nsIIOService> io(do_GetIOService());
2940 MOZ_ASSERT(io, "No IO service?");
2941 DebugOnly<nsresult> rv = io->GetOffline(&xpcomInit.isOffline());
2942 MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting offline?");
2944 rv = io->GetConnectivity(&xpcomInit.isConnected());
2945 MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting connectivity?");
2947 xpcomInit.captivePortalState() = nsICaptivePortalService::UNKNOWN;
2948 nsCOMPtr<nsICaptivePortalService> cps =
2949 do_GetService(NS_CAPTIVEPORTAL_CONTRACTID);
2950 if (cps) {
2951 cps->GetState(&xpcomInit.captivePortalState());
2954 if (StaticPrefs::fission_processProfileName()) {
2955 nsCOMPtr<nsIToolkitProfileService> profileSvc =
2956 do_GetService(NS_PROFILESERVICE_CONTRACTID);
2957 if (profileSvc) {
2958 nsCOMPtr<nsIToolkitProfile> currentProfile;
2959 nsresult rv =
2960 profileSvc->GetCurrentProfile(getter_AddRefs(currentProfile));
2961 if (NS_SUCCEEDED(rv) && currentProfile) {
2962 currentProfile->GetName(mProfile);
2967 nsIBidiKeyboard* bidi = nsContentUtils::GetBidiKeyboard();
2969 xpcomInit.isLangRTL() = false;
2970 xpcomInit.haveBidiKeyboards() = false;
2971 if (bidi) {
2972 bidi->IsLangRTL(&xpcomInit.isLangRTL());
2973 bidi->GetHaveBidiKeyboards(&xpcomInit.haveBidiKeyboards());
2976 RefPtr<mozSpellChecker> spellChecker(mozSpellChecker::Create());
2977 MOZ_ASSERT(spellChecker, "No spell checker?");
2979 spellChecker->GetDictionaryList(&xpcomInit.dictionaries());
2981 LocaleService::GetInstance()->GetAppLocalesAsBCP47(xpcomInit.appLocales());
2982 LocaleService::GetInstance()->GetRequestedLocales(
2983 xpcomInit.requestedLocales());
2985 L10nRegistry::GetParentProcessFileSourceDescriptors(
2986 xpcomInit.l10nFileSources());
2988 nsCOMPtr<nsIClipboard> clipboard(
2989 do_GetService("@mozilla.org/widget/clipboard;1"));
2990 MOZ_ASSERT(clipboard, "No clipboard?");
2991 MOZ_ASSERT(
2992 clipboard->IsClipboardTypeSupported(nsIClipboard::kGlobalClipboard),
2993 "We should always support the global clipboard.");
2995 xpcomInit.clipboardCaps().supportsSelectionClipboard() =
2996 clipboard->IsClipboardTypeSupported(nsIClipboard::kSelectionClipboard);
2998 xpcomInit.clipboardCaps().supportsFindClipboard() =
2999 clipboard->IsClipboardTypeSupported(nsIClipboard::kFindClipboard);
3001 xpcomInit.clipboardCaps().supportsSelectionCache() =
3002 clipboard->IsClipboardTypeSupported(nsIClipboard::kSelectionCache);
3004 // Let's copy the domain policy from the parent to the child (if it's active).
3005 StructuredCloneData initialData;
3006 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
3007 if (ssm) {
3008 ssm->CloneDomainPolicy(&xpcomInit.domainPolicy());
3010 if (ParentProcessMessageManager* mm =
3011 nsFrameMessageManager::sParentProcessManager) {
3012 AutoJSAPI jsapi;
3013 if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) {
3014 MOZ_CRASH();
3016 JS::Rooted<JS::Value> init(jsapi.cx());
3017 // We'll crash on failure, so use a IgnoredErrorResult (which also
3018 // auto-suppresses exceptions).
3019 IgnoredErrorResult rv;
3020 mm->GetInitialProcessData(jsapi.cx(), &init, rv);
3021 if (NS_WARN_IF(rv.Failed())) {
3022 MOZ_CRASH();
3025 initialData.Write(jsapi.cx(), init, rv);
3026 if (NS_WARN_IF(rv.Failed())) {
3027 MOZ_CRASH();
3031 // This is only implemented (returns a non-empty list) by MacOSX and Linux
3032 // at present.
3033 SystemFontList fontList;
3034 gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList);
3036 const FullLookAndFeel& lnf = *RemoteLookAndFeel::ExtractData();
3038 // If the shared fontlist is in use, collect its shmem block handles to pass
3039 // to the child.
3040 nsTArray<SharedMemoryHandle> sharedFontListBlocks;
3041 gfxPlatformFontList::PlatformFontList()->ShareFontListToProcess(
3042 &sharedFontListBlocks, OtherPid());
3044 // Content processes have no permission to access profile directory, so we
3045 // send the file URL instead.
3046 auto* sheetCache = GlobalStyleSheetCache::Singleton();
3047 if (StyleSheet* ucs = sheetCache->GetUserContentSheet()) {
3048 xpcomInit.userContentSheetURL() = ucs->GetSheetURI();
3049 } else {
3050 xpcomInit.userContentSheetURL() = nullptr;
3053 // 1. Build ContentDeviceData first, as it may affect some gfxVars.
3054 gfxPlatform::GetPlatform()->BuildContentDeviceData(
3055 &xpcomInit.contentDeviceData());
3056 // 2. Gather non-default gfxVars.
3057 xpcomInit.gfxNonDefaultVarUpdates() = gfxVars::FetchNonDefaultVars();
3058 // 3. Start listening for gfxVars updates, to notify content process later on.
3059 gfxVars::AddReceiver(this);
3061 nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
3062 if (gfxInfo) {
3063 GfxInfoBase* gfxInfoRaw = static_cast<GfxInfoBase*>(gfxInfo.get());
3064 xpcomInit.gfxFeatureStatus() = gfxInfoRaw->GetAllFeatures();
3067 // Send the dynamic scalar definitions to the new process.
3068 TelemetryIPC::GetDynamicScalarDefinitions(xpcomInit.dynamicScalarDefs());
3070 for (auto const& [location, supported] : sCodecsSupported) {
3071 Unused << SendUpdateMediaCodecsSupported(location, supported);
3074 #ifdef MOZ_WIDGET_ANDROID
3075 if (!(StaticPrefs::media_utility_process_enabled() &&
3076 StaticPrefs::media_utility_android_media_codec_enabled())) {
3077 Unused << SendDecoderSupportedMimeTypes(
3078 AndroidDecoderModule::GetSupportedMimeTypesPrefixed());
3080 #endif
3082 // Must send screen info before send initialData
3083 ScreenManager& screenManager = ScreenManager::GetSingleton();
3084 screenManager.CopyScreensToRemote(this);
3086 // Send the UA sheet shared memory buffer and the address it is mapped at.
3087 Maybe<SharedMemoryHandle> sharedUASheetHandle;
3088 uintptr_t sharedUASheetAddress = sheetCache->GetSharedMemoryAddress();
3090 if (SharedMemoryHandle handle = sheetCache->CloneHandle()) {
3091 sharedUASheetHandle.emplace(std::move(handle));
3092 } else {
3093 sharedUASheetAddress = 0;
3096 bool isReadyForBackgroundProcessing = false;
3097 #if defined(XP_WIN)
3098 RefPtr<DllServices> dllSvc(DllServices::Get());
3099 isReadyForBackgroundProcessing = dllSvc->IsReadyForBackgroundProcessing();
3100 #endif
3102 xpcomInit.perfStatsMask() = PerfStats::GetCollectionMask();
3104 nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
3105 dns->GetTrrDomain(xpcomInit.trrDomain());
3107 nsIDNSService::ResolverMode mode;
3108 dns->GetCurrentTrrMode(&mode);
3109 xpcomInit.trrMode() = mode;
3110 xpcomInit.trrModeFromPref() =
3111 static_cast<nsIDNSService::ResolverMode>(StaticPrefs::network_trr_mode());
3113 Unused << SendSetXPCOMProcessAttributes(
3114 xpcomInit, initialData, lnf, fontList, std::move(sharedUASheetHandle),
3115 sharedUASheetAddress, std::move(sharedFontListBlocks),
3116 isReadyForBackgroundProcessing);
3118 ipc::WritableSharedMap* sharedData =
3119 nsFrameMessageManager::sParentProcessManager->SharedData();
3120 sharedData->Flush();
3121 sharedData->SendTo(this);
3123 nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
3124 nsChromeRegistryChrome* chromeRegistry =
3125 static_cast<nsChromeRegistryChrome*>(registrySvc.get());
3126 chromeRegistry->SendRegisteredChrome(this);
3128 nsCOMPtr<nsIStringBundleService> stringBundleService =
3129 components::StringBundle::Service();
3130 stringBundleService->SendContentBundles(this);
3132 if (gAppData) {
3133 nsCString version(gAppData->version);
3134 nsCString buildID(gAppData->buildID);
3135 nsCString name(gAppData->name);
3136 nsCString UAName(gAppData->UAName);
3137 nsCString ID(gAppData->ID);
3138 nsCString vendor(gAppData->vendor);
3139 nsCString sourceURL(gAppData->sourceURL);
3140 nsCString updateURL(gAppData->updateURL);
3142 // Sending all information to content process.
3143 Unused << SendAppInfo(version, buildID, name, UAName, ID, vendor, sourceURL,
3144 updateURL);
3147 // Send the child its remote type. On Mac, this needs to be sent prior
3148 // to the message we send to enable the Sandbox (SendStartProcessSandbox)
3149 // because different remote types require different sandbox privileges.
3151 Unused << SendRemoteType(mRemoteType, mProfile);
3153 ScriptPreloader::InitContentChild(*this);
3155 // Initialize the message manager (and load delayed scripts) now that we
3156 // have established communications with the child.
3157 mMessageManager->InitWithCallback(this);
3158 mMessageManager->SetOsPid(Pid());
3160 // Set the subprocess's priority. We do this early on because we're likely
3161 // /lowering/ the process's CPU and memory priority, which it has inherited
3162 // from this process.
3164 // This call can cause us to send IPC messages to the child process, so it
3165 // must come after the Open() call above.
3166 ProcessPriorityManager::SetProcessPriority(this, aInitialPriority);
3168 // NB: internally, this will send an IPC message to the child
3169 // process to get it to create the CompositorBridgeChild. This
3170 // message goes through the regular IPC queue for this
3171 // channel, so delivery will happen-before any other messages
3172 // we send. The CompositorBridgeChild must be created before any
3173 // PBrowsers are created, because they rely on the Compositor
3174 // already being around. (Creation is async, so can't happen
3175 // on demand.)
3176 GPUProcessManager* gpm = GPUProcessManager::Get();
3178 Endpoint<PCompositorManagerChild> compositor;
3179 Endpoint<PImageBridgeChild> imageBridge;
3180 Endpoint<PVRManagerChild> vrBridge;
3181 Endpoint<PRemoteDecoderManagerChild> videoManager;
3182 AutoTArray<uint32_t, 3> namespaces;
3184 if (!gpm->CreateContentBridges(OtherPid(), &compositor, &imageBridge,
3185 &vrBridge, &videoManager, mChildID,
3186 &namespaces)) {
3187 // This can fail if we've already started shutting down the compositor
3188 // thread. See Bug 1562763 comment 8.
3189 MOZ_ASSERT(AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown));
3190 return false;
3193 Unused << SendInitRendering(std::move(compositor), std::move(imageBridge),
3194 std::move(vrBridge), std::move(videoManager),
3195 namespaces);
3197 gpm->AddListener(this);
3199 nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
3200 if (sheetService) {
3201 // This looks like a lot of work, but in a normal browser session we just
3202 // send two loads.
3204 // The URIs of the Gecko and Servo sheets should be the same, so it
3205 // shouldn't matter which we look at.
3207 for (StyleSheet* sheet : *sheetService->AgentStyleSheets()) {
3208 Unused << SendLoadAndRegisterSheet(sheet->GetSheetURI(),
3209 nsIStyleSheetService::AGENT_SHEET);
3212 for (StyleSheet* sheet : *sheetService->UserStyleSheets()) {
3213 Unused << SendLoadAndRegisterSheet(sheet->GetSheetURI(),
3214 nsIStyleSheetService::USER_SHEET);
3217 for (StyleSheet* sheet : *sheetService->AuthorStyleSheets()) {
3218 Unused << SendLoadAndRegisterSheet(sheet->GetSheetURI(),
3219 nsIStyleSheetService::AUTHOR_SHEET);
3223 #ifdef MOZ_SANDBOX
3224 bool shouldSandbox = true;
3225 Maybe<FileDescriptor> brokerFd;
3226 // XXX: Checking the pref here makes it possible to enable/disable sandboxing
3227 // during an active session. Currently the pref is only used for testing
3228 // purpose. If the decision is made to permanently rely on the pref, this
3229 // should be changed so that it is required to restart firefox for the change
3230 // of value to take effect. Always send SetProcessSandbox message on macOS.
3231 # if !defined(XP_MACOSX)
3232 shouldSandbox = IsContentSandboxEnabled();
3233 # endif
3235 # ifdef XP_LINUX
3236 if (shouldSandbox) {
3237 MOZ_ASSERT(!mSandboxBroker);
3238 bool isFileProcess = mRemoteType == FILE_REMOTE_TYPE;
3239 UniquePtr<SandboxBroker::Policy> policy =
3240 sSandboxBrokerPolicyFactory->GetContentPolicy(Pid(), isFileProcess);
3241 if (policy) {
3242 brokerFd = Some(FileDescriptor());
3243 mSandboxBroker =
3244 SandboxBroker::Create(std::move(policy), Pid(), brokerFd.ref());
3245 if (!mSandboxBroker) {
3246 KillHard("SandboxBroker::Create failed");
3247 return false;
3249 MOZ_ASSERT(brokerFd.ref().IsValid());
3252 # endif
3253 if (shouldSandbox && !SendSetProcessSandbox(brokerFd)) {
3254 KillHard("SandboxInitFailed");
3256 #endif
3258 // Ensure that the default set of permissions are avaliable in the content
3259 // process before we try to load any URIs in it.
3261 // NOTE: All default permissions has to be transmitted to the child process
3262 // before the blob urls in the for loop below (See Bug 1738713 comment 12).
3263 EnsurePermissionsByKey(""_ns, ""_ns);
3266 nsTArray<BlobURLRegistrationData> registrations;
3267 BlobURLProtocolHandler::ForEachBlobURL([&](BlobImpl* aBlobImpl,
3268 nsIPrincipal* aPrincipal,
3269 const nsCString& aPartitionKey,
3270 const nsACString& aURI,
3271 bool aRevoked) {
3272 // We send all moz-extension Blob URL's to all content processes
3273 // because content scripts mean that a moz-extension can live in any
3274 // process. Same thing for system principal Blob URLs. Content Blob
3275 // URL's are sent for content principals on-demand by
3276 // AboutToLoadHttpDocumentForChild and RemoteWorkerManager.
3277 if (!BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal)) {
3278 return true;
3281 IPCBlob ipcBlob;
3282 nsresult rv = IPCBlobUtils::Serialize(aBlobImpl, ipcBlob);
3283 if (NS_WARN_IF(NS_FAILED(rv))) {
3284 return false;
3287 registrations.AppendElement(
3288 BlobURLRegistrationData(nsCString(aURI), ipcBlob, aPrincipal,
3289 nsCString(aPartitionKey), aRevoked));
3291 rv = TransmitPermissionsForPrincipal(aPrincipal);
3292 Unused << NS_WARN_IF(NS_FAILED(rv));
3293 return true;
3296 if (!registrations.IsEmpty()) {
3297 Unused << SendInitBlobURLs(registrations);
3301 // Send down { Parent, Window }ActorOptions at startup to content process.
3302 RefPtr<JSActorService> actorSvc = JSActorService::GetSingleton();
3303 if (actorSvc) {
3304 nsTArray<JSProcessActorInfo> contentInfos;
3305 actorSvc->GetJSProcessActorInfos(contentInfos);
3307 nsTArray<JSWindowActorInfo> windowInfos;
3308 actorSvc->GetJSWindowActorInfos(windowInfos);
3310 Unused << SendInitJSActorInfos(contentInfos, windowInfos);
3313 // Begin subscribing to any BrowsingContextGroups which were hosted by this
3314 // process before it finished launching.
3315 for (const auto& group : mGroups) {
3316 group->Subscribe(this);
3319 MaybeEnableRemoteInputEventQueue();
3321 return true;
3324 bool ContentParent::IsAlive() const {
3325 return mLifecycleState == LifecycleState::ALIVE ||
3326 mLifecycleState == LifecycleState::INITIALIZED;
3329 bool ContentParent::IsInitialized() const {
3330 return mLifecycleState == LifecycleState::INITIALIZED;
3333 int32_t ContentParent::Pid() const {
3334 if (!mSubprocess) {
3335 return -1;
3337 auto pid = mSubprocess->GetChildProcessId();
3338 if (pid == 0) {
3339 return -1;
3341 return ReleaseAssertedCast<int32_t>(pid);
3344 void ContentParent::OnCompositorUnexpectedShutdown() {
3345 GPUProcessManager* gpm = GPUProcessManager::Get();
3347 Endpoint<PCompositorManagerChild> compositor;
3348 Endpoint<PImageBridgeChild> imageBridge;
3349 Endpoint<PVRManagerChild> vrBridge;
3350 Endpoint<PRemoteDecoderManagerChild> videoManager;
3351 AutoTArray<uint32_t, 3> namespaces;
3353 if (!gpm->CreateContentBridges(OtherPid(), &compositor, &imageBridge,
3354 &vrBridge, &videoManager, mChildID,
3355 &namespaces)) {
3356 MOZ_ASSERT(AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown));
3357 return;
3360 Unused << SendReinitRendering(std::move(compositor), std::move(imageBridge),
3361 std::move(vrBridge), std::move(videoManager),
3362 namespaces);
3365 void ContentParent::OnCompositorDeviceReset() {
3366 Unused << SendReinitRenderingForDeviceReset();
3369 void ContentParent::MaybeEnableRemoteInputEventQueue() {
3370 MOZ_ASSERT(!mIsRemoteInputEventQueueEnabled);
3371 if (!IsInputEventQueueSupported()) {
3372 return;
3374 mIsRemoteInputEventQueueEnabled = true;
3375 Unused << SendSetInputEventQueueEnabled();
3376 SetInputPriorityEventEnabled(true);
3379 void ContentParent::SetInputPriorityEventEnabled(bool aEnabled) {
3380 if (!IsInputEventQueueSupported() || !mIsRemoteInputEventQueueEnabled ||
3381 mIsInputPriorityEventEnabled == aEnabled) {
3382 return;
3384 mIsInputPriorityEventEnabled = aEnabled;
3385 // Send IPC messages to flush the pending events in the input event queue and
3386 // the normal event queue. See PContent.ipdl for more details.
3387 Unused << SendSuspendInputEventQueue();
3388 Unused << SendFlushInputEventQueue();
3389 Unused << SendResumeInputEventQueue();
3392 /*static*/
3393 bool ContentParent::IsInputEventQueueSupported() {
3394 static bool sSupported = false;
3395 static bool sInitialized = false;
3396 if (!sInitialized) {
3397 MOZ_ASSERT(Preferences::IsServiceAvailable());
3398 sSupported = Preferences::GetBool("input_event_queue.supported", false);
3399 sInitialized = true;
3401 return sSupported;
3404 void ContentParent::OnVarChanged(const GfxVarUpdate& aVar) {
3405 if (!CanSend()) {
3406 return;
3408 Unused << SendVarUpdate(aVar);
3411 mozilla::ipc::IPCResult ContentParent::RecvSetClipboard(
3412 const IPCTransferable& aTransferable, const int32_t& aWhichClipboard) {
3413 // aRequestingPrincipal is allowed to be nullptr here.
3415 if (!ValidatePrincipal(aTransferable.requestingPrincipal(),
3416 {ValidatePrincipalOptions::AllowNullPtr,
3417 ValidatePrincipalOptions::AllowExpanded,
3418 ValidatePrincipalOptions::AllowSystem})) {
3419 LogAndAssertFailedPrincipalValidationInfo(
3420 aTransferable.requestingPrincipal(), __func__);
3423 nsresult rv;
3424 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
3425 NS_ENSURE_SUCCESS(rv, IPC_OK());
3427 nsCOMPtr<nsITransferable> trans =
3428 do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
3429 NS_ENSURE_SUCCESS(rv, IPC_OK());
3430 trans->Init(nullptr);
3432 rv = nsContentUtils::IPCTransferableToTransferable(
3433 aTransferable, true /* aAddDataFlavor */, trans,
3434 true /* aFilterUnknownFlavors */);
3435 NS_ENSURE_SUCCESS(rv, IPC_OK());
3437 clipboard->SetData(trans, nullptr, aWhichClipboard);
3438 return IPC_OK();
3441 namespace {
3443 static Result<nsCOMPtr<nsITransferable>, nsresult> CreateTransferable(
3444 const nsTArray<nsCString>& aTypes) {
3445 nsresult rv;
3446 nsCOMPtr<nsITransferable> trans =
3447 do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
3448 if (NS_FAILED(rv)) {
3449 return Err(rv);
3452 MOZ_TRY(trans->Init(nullptr));
3453 // The private flag is only used to prevent the data from being cached to the
3454 // disk. The flag is not exported to the IPCDataTransfer object.
3455 // The flag is set because we are not sure whether the clipboard data is used
3456 // in a private browsing context. The transferable is only used in this scope,
3457 // so the cache would not reduce memory consumption anyway.
3458 trans->SetIsPrivateData(true);
3459 // Fill out flavors for transferable
3460 for (uint32_t t = 0; t < aTypes.Length(); t++) {
3461 MOZ_TRY(trans->AddDataFlavor(aTypes[t].get()));
3464 return std::move(trans);
3467 } // anonymous namespace
3469 mozilla::ipc::IPCResult ContentParent::RecvGetClipboard(
3470 nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
3471 const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
3472 IPCTransferableData* aTransferableData) {
3473 nsresult rv;
3474 // We expect content processes to always pass a non-null window so Content
3475 // Analysis can analyze it. (if Content Analysis is active)
3476 // There may be some cases when a window is closing, etc., in
3477 // which case returning no clipboard content should not be a problem.
3478 if (aRequestingWindowContext.IsDiscarded()) {
3479 NS_WARNING(
3480 "discarded window passed to RecvGetClipboard(); returning no clipboard "
3481 "content");
3482 return IPC_OK();
3484 if (aRequestingWindowContext.IsNull()) {
3485 return IPC_FAIL(this, "passed null window to RecvGetClipboard()");
3487 RefPtr<WindowGlobalParent> window = aRequestingWindowContext.get_canonical();
3488 // Retrieve clipboard
3489 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
3490 if (NS_FAILED(rv)) {
3491 return IPC_OK();
3494 // Create transferable
3495 auto result = CreateTransferable(aTypes);
3496 if (result.isErr()) {
3497 return IPC_OK();
3500 // Get data from clipboard
3501 nsCOMPtr<nsITransferable> trans = result.unwrap();
3502 clipboard->GetData(trans, aWhichClipboard, window);
3504 nsContentUtils::TransferableToIPCTransferableData(
3505 trans, aTransferableData, true /* aInSyncMessage */, this);
3506 return IPC_OK();
3509 mozilla::ipc::IPCResult ContentParent::RecvEmptyClipboard(
3510 const int32_t& aWhichClipboard) {
3511 nsresult rv;
3512 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
3513 NS_ENSURE_SUCCESS(rv, IPC_OK());
3515 clipboard->EmptyClipboard(aWhichClipboard);
3517 return IPC_OK();
3520 mozilla::ipc::IPCResult ContentParent::RecvClipboardHasType(
3521 nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
3522 bool* aHasType) {
3523 nsresult rv;
3524 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
3525 NS_ENSURE_SUCCESS(rv, IPC_OK());
3527 clipboard->HasDataMatchingFlavors(aTypes, aWhichClipboard, aHasType);
3529 return IPC_OK();
3532 namespace {
3534 static Result<ClipboardReadRequest, nsresult> CreateClipboardReadRequest(
3535 ContentParent& aContentParent,
3536 nsIAsyncGetClipboardData& aAsyncGetClipboardData) {
3537 nsTArray<nsCString> flavors;
3538 nsresult rv = aAsyncGetClipboardData.GetFlavorList(flavors);
3539 if (NS_FAILED(rv)) {
3540 return Err(rv);
3543 auto requestParent = MakeNotNull<RefPtr<ClipboardReadRequestParent>>(
3544 &aContentParent, &aAsyncGetClipboardData);
3546 // Open a remote endpoint for our PClipboardReadRequest actor.
3547 ManagedEndpoint<PClipboardReadRequestChild> childEndpoint =
3548 aContentParent.OpenPClipboardReadRequestEndpoint(requestParent);
3549 if (NS_WARN_IF(!childEndpoint.IsValid())) {
3550 return Err(NS_ERROR_FAILURE);
3553 return ClipboardReadRequest(std::move(childEndpoint), std::move(flavors));
3556 class ClipboardGetCallback final : public nsIAsyncClipboardGetCallback {
3557 public:
3558 ClipboardGetCallback(ContentParent* aContentParent,
3559 ContentParent::GetClipboardAsyncResolver&& aResolver)
3560 : mContentParent(aContentParent), mResolver(std::move(aResolver)) {}
3562 // This object will never be held by a cycle-collected object, so it doesn't
3563 // need to be cycle-collected despite holding alive cycle-collected objects.
3564 NS_DECL_ISUPPORTS
3566 // nsIAsyncClipboardGetCallback
3567 NS_IMETHOD OnSuccess(
3568 nsIAsyncGetClipboardData* aAsyncGetClipboardData) override {
3569 MOZ_ASSERT(mContentParent);
3570 MOZ_ASSERT(aAsyncGetClipboardData);
3572 auto result =
3573 CreateClipboardReadRequest(*mContentParent, *aAsyncGetClipboardData);
3574 if (result.isErr()) {
3575 return OnError(result.unwrapErr());
3578 mResolver(result.unwrap());
3579 return NS_OK;
3582 NS_IMETHOD OnError(nsresult aResult) override {
3583 mResolver(aResult);
3584 return NS_OK;
3587 protected:
3588 ~ClipboardGetCallback() = default;
3590 RefPtr<ContentParent> mContentParent;
3591 ContentParent::GetClipboardAsyncResolver mResolver;
3594 NS_IMPL_ISUPPORTS(ClipboardGetCallback, nsIAsyncClipboardGetCallback)
3596 } // namespace
3598 mozilla::ipc::IPCResult ContentParent::RecvGetClipboardAsync(
3599 nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
3600 const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
3601 mozilla::NotNull<nsIPrincipal*> aRequestingPrincipal,
3602 GetClipboardAsyncResolver&& aResolver) {
3603 if (!ValidatePrincipal(aRequestingPrincipal,
3604 {ValidatePrincipalOptions::AllowSystem,
3605 ValidatePrincipalOptions::AllowExpanded})) {
3606 LogAndAssertFailedPrincipalValidationInfo(aRequestingPrincipal, __func__);
3609 // If the requesting context has been discarded, cancel the paste.
3610 if (aRequestingWindowContext.IsDiscarded()) {
3611 aResolver(NS_ERROR_NOT_AVAILABLE);
3612 return IPC_OK();
3615 RefPtr<WindowGlobalParent> requestingWindow =
3616 aRequestingWindowContext.get_canonical();
3617 if (requestingWindow && requestingWindow->GetContentParent() != this) {
3618 return IPC_FAIL(
3619 this, "attempt to paste into WindowContext loaded in another process");
3622 nsresult rv;
3623 // Retrieve clipboard
3624 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
3625 if (NS_FAILED(rv)) {
3626 aResolver(rv);
3627 return IPC_OK();
3630 auto callback = MakeRefPtr<ClipboardGetCallback>(this, std::move(aResolver));
3631 rv = clipboard->AsyncGetData(aTypes, aWhichClipboard, requestingWindow,
3632 aRequestingPrincipal, callback);
3633 if (NS_FAILED(rv)) {
3634 callback->OnError(rv);
3635 return IPC_OK();
3638 return IPC_OK();
3641 mozilla::ipc::IPCResult ContentParent::RecvGetClipboardDataSnapshotSync(
3642 nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
3643 const MaybeDiscarded<WindowContext>& aRequestingWindowContext,
3644 ClipboardReadRequestOrError* aRequestOrError) {
3645 // If the requesting context has been discarded, cancel the paste.
3646 if (aRequestingWindowContext.IsDiscarded()) {
3647 *aRequestOrError = NS_ERROR_FAILURE;
3648 return IPC_OK();
3651 RefPtr<WindowGlobalParent> requestingWindow =
3652 aRequestingWindowContext.get_canonical();
3653 if (requestingWindow && requestingWindow->GetContentParent() != this) {
3654 return IPC_FAIL(
3655 this, "attempt to paste into WindowContext loaded in another process");
3658 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID));
3659 if (!clipboard) {
3660 *aRequestOrError = NS_ERROR_FAILURE;
3661 return IPC_OK();
3664 nsCOMPtr<nsIAsyncGetClipboardData> asyncGetClipboardData;
3665 nsresult rv =
3666 clipboard->GetDataSnapshotSync(aTypes, aWhichClipboard, requestingWindow,
3667 getter_AddRefs(asyncGetClipboardData));
3668 if (NS_FAILED(rv)) {
3669 *aRequestOrError = rv;
3670 return IPC_OK();
3673 auto result = CreateClipboardReadRequest(*this, *asyncGetClipboardData);
3674 if (result.isErr()) {
3675 *aRequestOrError = result.unwrapErr();
3676 return IPC_OK();
3679 *aRequestOrError = result.unwrap();
3680 return IPC_OK();
3683 already_AddRefed<PClipboardWriteRequestParent>
3684 ContentParent::AllocPClipboardWriteRequestParent(
3685 const int32_t& aClipboardType) {
3686 RefPtr<ClipboardWriteRequestParent> request =
3687 MakeAndAddRef<ClipboardWriteRequestParent>(this);
3688 request->Init(aClipboardType);
3689 return request.forget();
3692 mozilla::ipc::IPCResult ContentParent::RecvGetIconForExtension(
3693 const nsACString& aFileExt, const uint32_t& aIconSize,
3694 nsTArray<uint8_t>* bits) {
3695 #ifdef MOZ_WIDGET_ANDROID
3696 NS_ASSERTION(AndroidBridge::Bridge() != nullptr,
3697 "AndroidBridge is not available");
3698 if (AndroidBridge::Bridge() == nullptr) {
3699 // Do not fail - just no icon will be shown
3700 return IPC_OK();
3703 bits->AppendElements(aIconSize * aIconSize * 4);
3705 AndroidBridge::Bridge()->GetIconForExtension(aFileExt, aIconSize,
3706 bits->Elements());
3707 #endif
3708 return IPC_OK();
3711 mozilla::ipc::IPCResult ContentParent::RecvFirstIdle() {
3712 // When the ContentChild goes idle, it sends us a FirstIdle message
3713 // which we use as a good time to signal the PreallocatedProcessManager
3714 // that it can start allocating processes from now on.
3715 if (mIsAPreallocBlocker) {
3716 MOZ_LOG(
3717 ContentParent::GetLog(), LogLevel::Verbose,
3718 ("RecvFirstIdle %p: Removing Blocker for %s", this, mRemoteType.get()));
3719 PreallocatedProcessManager::RemoveBlocker(mRemoteType, this);
3720 mIsAPreallocBlocker = false;
3722 return IPC_OK();
3725 already_AddRefed<nsDocShellLoadState> ContentParent::TakePendingLoadStateForId(
3726 uint64_t aLoadIdentifier) {
3727 return mPendingLoadStates.Extract(aLoadIdentifier).valueOr(nullptr).forget();
3730 void ContentParent::StorePendingLoadState(nsDocShellLoadState* aLoadState) {
3731 MOZ_DIAGNOSTIC_ASSERT(
3732 !mPendingLoadStates.Contains(aLoadState->GetLoadIdentifier()),
3733 "The same nsDocShellLoadState was sent to the same content process "
3734 "twice? This will mess with cross-process tracking of loads");
3735 mPendingLoadStates.InsertOrUpdate(aLoadState->GetLoadIdentifier(),
3736 aLoadState);
3739 mozilla::ipc::IPCResult ContentParent::RecvCleanupPendingLoadState(
3740 uint64_t aLoadIdentifier) {
3741 mPendingLoadStates.Remove(aLoadIdentifier);
3742 return IPC_OK();
3745 // We want ContentParent to show up in CC logs for debugging purposes, but we
3746 // don't actually cycle collect it.
3747 NS_IMPL_CYCLE_COLLECTION_0(ContentParent)
3749 NS_IMPL_CYCLE_COLLECTING_ADDREF(ContentParent)
3750 NS_IMPL_CYCLE_COLLECTING_RELEASE(ContentParent)
3752 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ContentParent)
3753 NS_INTERFACE_MAP_ENTRY_CONCRETE(ContentParent)
3754 NS_INTERFACE_MAP_ENTRY(nsIDOMProcessParent)
3755 NS_INTERFACE_MAP_ENTRY(nsIObserver)
3756 NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionCallback)
3757 NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionErrorCallback)
3758 NS_INTERFACE_MAP_ENTRY(nsIAsyncShutdownBlocker)
3759 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
3760 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMProcessParent)
3761 NS_INTERFACE_MAP_END
3763 class RequestContentJSInterruptRunnable final : public Runnable {
3764 public:
3765 explicit RequestContentJSInterruptRunnable(PProcessHangMonitorParent* aActor)
3766 : Runnable("dom::RequestContentJSInterruptRunnable"),
3767 mHangMonitorActor(aActor) {}
3769 NS_IMETHOD Run() override {
3770 MOZ_ASSERT(mHangMonitorActor);
3771 Unused << mHangMonitorActor->SendRequestContentJSInterrupt();
3773 return NS_OK;
3776 private:
3777 // The end-of-life of ContentParent::mHangMonitorActor is bound to
3778 // ContentParent::ActorDestroy and then HangMonitorParent::Shutdown
3779 // dispatches a shutdown runnable to this queue and waits for it to be
3780 // executed. So the runnable needs not to care about keeping it alive,
3781 // as it is surely dispatched earlier than the
3782 // HangMonitorParent::ShutdownOnThread.
3783 RefPtr<PProcessHangMonitorParent> mHangMonitorActor;
3786 void ContentParent::SignalImpendingShutdownToContentJS() {
3787 if (!mIsSignaledImpendingShutdown &&
3788 !AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
3789 MaybeLogBlockShutdownDiagnostics(
3790 this, "BlockShutdown: NotifyImpendingShutdown.", __FILE__, __LINE__);
3791 NotifyImpendingShutdown();
3792 mIsSignaledImpendingShutdown = true;
3793 if (mHangMonitorActor &&
3794 StaticPrefs::dom_abort_script_on_child_shutdown()) {
3795 MaybeLogBlockShutdownDiagnostics(
3796 this, "BlockShutdown: RequestContentJSInterrupt.", __FILE__,
3797 __LINE__);
3798 RefPtr<RequestContentJSInterruptRunnable> r =
3799 new RequestContentJSInterruptRunnable(mHangMonitorActor);
3800 ProcessHangMonitor::Get()->Dispatch(r.forget());
3805 // Async shutdown blocker
3806 NS_IMETHODIMP
3807 ContentParent::BlockShutdown(nsIAsyncShutdownClient* aClient) {
3808 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
3809 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3810 mBlockShutdownCalled = true;
3811 #endif
3812 // Our real shutdown has not yet started. Just notify the impending
3813 // shutdown and eventually cancel content JS.
3814 SignalImpendingShutdownToContentJS();
3815 // This will make our process unusable for normal content, so we need to
3816 // ensure we won't get re-used by GetUsedBrowserProcess as we have not yet
3817 // done MarkAsDead.
3818 PreallocatedProcessManager::Erase(this);
3819 StopRecyclingE10SOnly(false);
3821 if (sQuitApplicationGrantedClient) {
3822 Unused << sQuitApplicationGrantedClient->RemoveBlocker(this);
3824 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3825 mBlockShutdownCalled = false;
3826 #endif
3827 return NS_OK;
3830 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3831 // We register two final shutdown blockers and both would call us, but if
3832 // things go well we will unregister both as (delayed) reaction to the first
3833 // call we get and thus never receive a second call. Thus we believe that we
3834 // will get called only once except for quit-application-granted, which is
3835 // handled above.
3836 MOZ_ASSERT(!mBlockShutdownCalled);
3837 mBlockShutdownCalled = true;
3838 #endif
3840 if (CanSend()) {
3841 MaybeLogBlockShutdownDiagnostics(this, "BlockShutdown: CanSend.", __FILE__,
3842 __LINE__);
3844 // Make sure that our process will get scheduled.
3845 ProcessPriorityManager::SetProcessPriority(this,
3846 PROCESS_PRIORITY_FOREGROUND);
3847 // The normal shutdown sequence is to send a shutdown message
3848 // to the child and then just wait for ActorDestroy which will
3849 // cleanup everything and remove our blockers.
3850 if (!ShutDownProcess(SEND_SHUTDOWN_MESSAGE)) {
3851 KillHard("Failed to send Shutdown message. Destroying the process...");
3852 return NS_OK;
3854 } else if (IsLaunching()) {
3855 MaybeLogBlockShutdownDiagnostics(
3856 this, "BlockShutdown: !CanSend && IsLaunching.", __FILE__, __LINE__);
3858 // If we get here while we are launching, we must wait for the child to
3859 // be able to react on our commands. Mark this process as dead. This
3860 // will make bail out LaunchSubprocessResolve and kick off the normal
3861 // shutdown sequence.
3862 MarkAsDead();
3863 } else {
3864 MOZ_ASSERT(IsDead());
3865 if (!IsDead()) {
3866 MaybeLogBlockShutdownDiagnostics(
3867 this, "BlockShutdown: !!! !CanSend && !IsLaunching && !IsDead !!!",
3868 __FILE__, __LINE__);
3869 } else {
3870 MaybeLogBlockShutdownDiagnostics(
3871 this, "BlockShutdown: !CanSend && !IsLaunching && IsDead.", __FILE__,
3872 __LINE__);
3874 // Nothing left we can do. We must assume that we race with an ongoing
3875 // process shutdown, such that we can expect our shutdown blockers to be
3876 // removed normally.
3879 return NS_OK;
3882 NS_IMETHODIMP
3883 ContentParent::GetName(nsAString& aName) {
3884 aName.AssignLiteral("ContentParent:");
3885 aName.AppendPrintf(" id=%p", this);
3886 return NS_OK;
3889 NS_IMETHODIMP
3890 ContentParent::GetState(nsIPropertyBag** aResult) {
3891 auto props = MakeRefPtr<nsHashPropertyBag>();
3892 props->SetPropertyAsACString(u"remoteTypePrefix"_ns,
3893 RemoteTypePrefix(mRemoteType));
3894 *aResult = props.forget().downcast<nsIWritablePropertyBag>().take();
3895 return NS_OK;
3898 static void InitShutdownClients() {
3899 if (!sXPCOMShutdownClient) {
3900 nsresult rv;
3901 nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdownService();
3902 if (!svc) {
3903 return;
3906 nsCOMPtr<nsIAsyncShutdownClient> client;
3907 // TODO: It seems as if getPhase from AsyncShutdown.sys.mjs does not check
3908 // if we are beyond our phase already. See bug 1762840.
3909 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMWillShutdown)) {
3910 rv = svc->GetXpcomWillShutdown(getter_AddRefs(client));
3911 if (NS_SUCCEEDED(rv)) {
3912 sXPCOMShutdownClient = client.forget();
3913 ClearOnShutdown(&sXPCOMShutdownClient);
3916 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
3917 rv = svc->GetProfileBeforeChange(getter_AddRefs(client));
3918 if (NS_SUCCEEDED(rv)) {
3919 sProfileBeforeChangeClient = client.forget();
3920 ClearOnShutdown(&sProfileBeforeChangeClient);
3923 // TODO: ShutdownPhase::AppShutdownConfirmed is not mapping to
3924 // QuitApplicationGranted, see bug 1762840 comment 4.
3925 if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
3926 rv = svc->GetQuitApplicationGranted(getter_AddRefs(client));
3927 if (NS_SUCCEEDED(rv)) {
3928 sQuitApplicationGrantedClient = client.forget();
3929 ClearOnShutdown(&sQuitApplicationGrantedClient);
3935 void ContentParent::AddShutdownBlockers() {
3936 InitShutdownClients();
3937 MOZ_ASSERT(sXPCOMShutdownClient);
3938 MOZ_ASSERT(sProfileBeforeChangeClient);
3940 if (sXPCOMShutdownClient) {
3941 sXPCOMShutdownClient->AddBlocker(
3942 this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
3944 if (sProfileBeforeChangeClient) {
3945 sProfileBeforeChangeClient->AddBlocker(
3946 this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
3948 if (sQuitApplicationGrantedClient) {
3949 sQuitApplicationGrantedClient->AddBlocker(
3950 this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
3954 void ContentParent::RemoveShutdownBlockers() {
3955 MOZ_ASSERT(sXPCOMShutdownClient);
3956 MOZ_ASSERT(sProfileBeforeChangeClient);
3958 MaybeLogBlockShutdownDiagnostics(this, "RemoveShutdownBlockers", __FILE__,
3959 __LINE__);
3960 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3961 mBlockShutdownCalled = false;
3962 #endif
3964 if (sXPCOMShutdownClient) {
3965 Unused << sXPCOMShutdownClient->RemoveBlocker(this);
3967 if (sProfileBeforeChangeClient) {
3968 Unused << sProfileBeforeChangeClient->RemoveBlocker(this);
3970 if (sQuitApplicationGrantedClient) {
3971 Unused << sQuitApplicationGrantedClient->RemoveBlocker(this);
3975 NS_IMETHODIMP
3976 ContentParent::Observe(nsISupports* aSubject, const char* aTopic,
3977 const char16_t* aData) {
3978 if (IsDead() || !mSubprocess) {
3979 return NS_OK;
3982 if (!strcmp(aTopic, "nsPref:changed")) {
3983 // We know prefs are ASCII here.
3984 NS_LossyConvertUTF16toASCII strData(aData);
3986 Pref pref(strData, /* isLocked */ false,
3987 /* isSanitized */ false, Nothing(), Nothing());
3989 Preferences::GetPreference(&pref, GeckoProcessType_Content,
3990 GetRemoteType());
3992 // This check is a bit of a hack. We want to avoid sending excessive
3993 // preference updates to subprocesses for performance reasons, but we
3994 // currently don't have a great mechanism for doing so. (See Bug 1819714)
3995 // We're going to hijack the sanitization mechanism to accomplish our goal
3996 // but it imposes the following complications:
3997 // 1) It doesn't avoid sending anything to other (non-web-content)
3998 // subprocesses so we're not getting any perf gains there
3999 // 2) It confuses the subprocesses w.r.t. sanitization. The point of
4000 // sending a preference update of a sanitized preference is so that
4001 // content process knows when it's asked to resolve a sanitized
4002 // preference, and it can send telemetry and/or crash. With this
4003 // change, a sanitized pref that is created during the browser session
4004 // will not be sent to the content process, and therefore the content
4005 // process won't know it should telemetry/crash on access - it'll just
4006 // silently fail to resolve it. After browser restart, the sanitized
4007 // pref will be populated into the content process via the shared pref
4008 // map and _then_ if it is accessed, the content process will crash.
4009 // We're seeing good telemetry/crash rates right now, so we're okay with
4010 // this limitation.
4011 if (pref.isSanitized()) {
4012 return NS_OK;
4015 if (IsInitialized()) {
4016 MOZ_ASSERT(mQueuedPrefs.IsEmpty());
4017 if (!SendPreferenceUpdate(pref)) {
4018 return NS_ERROR_NOT_AVAILABLE;
4020 } else {
4021 MOZ_ASSERT(!IsDead());
4022 mQueuedPrefs.AppendElement(pref);
4025 return NS_OK;
4028 if (!IsAlive()) {
4029 return NS_OK;
4032 // listening for memory pressure event
4033 if (!strcmp(aTopic, "memory-pressure")) {
4034 Unused << SendFlushMemory(nsDependentString(aData));
4035 } else if (!strcmp(aTopic, "application-background")) {
4036 Unused << SendApplicationBackground();
4037 } else if (!strcmp(aTopic, "application-foreground")) {
4038 Unused << SendApplicationForeground();
4039 } else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC)) {
4040 NS_ConvertUTF16toUTF8 dataStr(aData);
4041 const char* offline = dataStr.get();
4042 if (!SendSetOffline(!strcmp(offline, "true"))) {
4043 return NS_ERROR_NOT_AVAILABLE;
4045 } else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC)) {
4046 if (!SendSetConnectivity(u"true"_ns.Equals(aData))) {
4047 return NS_ERROR_NOT_AVAILABLE;
4049 } else if (!strcmp(aTopic, NS_IPC_CAPTIVE_PORTAL_SET_STATE)) {
4050 nsCOMPtr<nsICaptivePortalService> cps = do_QueryInterface(aSubject);
4051 MOZ_ASSERT(cps, "Should QI to a captive portal service");
4052 if (!cps) {
4053 return NS_ERROR_FAILURE;
4055 int32_t state;
4056 cps->GetState(&state);
4057 if (!SendSetCaptivePortalState(state)) {
4058 return NS_ERROR_NOT_AVAILABLE;
4061 // listening for alert notifications
4062 else if (!strcmp(aTopic, "alertfinished") ||
4063 !strcmp(aTopic, "alertclickcallback") ||
4064 !strcmp(aTopic, "alertshow") ||
4065 !strcmp(aTopic, "alertdisablecallback") ||
4066 !strcmp(aTopic, "alertsettingscallback")) {
4067 if (!SendNotifyAlertsObserver(nsDependentCString(aTopic),
4068 nsDependentString(aData)))
4069 return NS_ERROR_NOT_AVAILABLE;
4070 } else if (!strcmp(aTopic, "child-gc-request")) {
4071 Unused << SendGarbageCollect();
4072 } else if (!strcmp(aTopic, "child-cc-request")) {
4073 Unused << SendCycleCollect();
4074 } else if (!strcmp(aTopic, "child-mmu-request")) {
4075 Unused << SendMinimizeMemoryUsage();
4076 } else if (!strcmp(aTopic, "child-ghost-request")) {
4077 Unused << SendUnlinkGhosts();
4078 } else if (!strcmp(aTopic, "last-pb-context-exited")) {
4079 Unused << SendLastPrivateDocShellDestroyed();
4081 #ifdef ACCESSIBILITY
4082 else if (aData && !strcmp(aTopic, "a11y-init-or-shutdown")) {
4083 if (*aData == '1') {
4084 // Make sure accessibility is running in content process when
4085 // accessibility gets initiated in chrome process.
4086 Unused << SendActivateA11y();
4087 } else {
4088 // If possible, shut down accessibility in content process when
4089 // accessibility gets shutdown in chrome process.
4090 Unused << SendShutdownA11y();
4093 #endif
4094 else if (!strcmp(aTopic, "cacheservice:empty-cache")) {
4095 Unused << SendNotifyEmptyHTTPCache();
4096 } else if (!strcmp(aTopic, "intl:app-locales-changed")) {
4097 nsTArray<nsCString> appLocales;
4098 LocaleService::GetInstance()->GetAppLocalesAsBCP47(appLocales);
4099 Unused << SendUpdateAppLocales(appLocales);
4100 } else if (!strcmp(aTopic, "intl:requested-locales-changed")) {
4101 nsTArray<nsCString> requestedLocales;
4102 LocaleService::GetInstance()->GetRequestedLocales(requestedLocales);
4103 Unused << SendUpdateRequestedLocales(requestedLocales);
4104 } else if (!strcmp(aTopic, "cookie-changed") ||
4105 !strcmp(aTopic, "private-cookie-changed")) {
4106 MOZ_ASSERT(aSubject, "cookie changed notification must have subject.");
4107 nsCOMPtr<nsICookieNotification> notification = do_QueryInterface(aSubject);
4108 MOZ_ASSERT(notification,
4109 "cookie changed notification must have nsICookieNotification.");
4110 nsICookieNotification::Action action = notification->GetAction();
4112 PNeckoParent* neckoParent = LoneManagedOrNullAsserts(ManagedPNeckoParent());
4113 if (!neckoParent) {
4114 return NS_OK;
4116 PCookieServiceParent* csParent =
4117 LoneManagedOrNullAsserts(neckoParent->ManagedPCookieServiceParent());
4118 if (!csParent) {
4119 return NS_OK;
4121 auto* cs = static_cast<CookieServiceParent*>(csParent);
4122 if (action == nsICookieNotification::COOKIES_BATCH_DELETED) {
4123 nsCOMPtr<nsIArray> cookieList;
4124 DebugOnly<nsresult> rv =
4125 notification->GetBatchDeletedCookies(getter_AddRefs(cookieList));
4126 NS_ASSERTION(NS_SUCCEEDED(rv) && cookieList, "couldn't get cookie list");
4127 cs->RemoveBatchDeletedCookies(cookieList);
4128 return NS_OK;
4131 if (action == nsICookieNotification::ALL_COOKIES_CLEARED) {
4132 cs->RemoveAll();
4133 return NS_OK;
4136 // Do not push these cookie updates to the same process they originated
4137 // from.
4138 if (cs->ProcessingCookie()) {
4139 return NS_OK;
4142 nsCOMPtr<nsICookie> xpcCookie;
4143 DebugOnly<nsresult> rv = notification->GetCookie(getter_AddRefs(xpcCookie));
4144 NS_ASSERTION(NS_SUCCEEDED(rv) && xpcCookie, "couldn't get cookie");
4146 // only broadcast the cookie change to content processes that need it
4147 const Cookie& cookie = xpcCookie->AsCookie();
4149 // do not send cookie if content process does not have similar cookie
4150 if (!cs->ContentProcessHasCookie(cookie)) {
4151 return NS_OK;
4154 if (action == nsICookieNotification::COOKIE_DELETED) {
4155 cs->RemoveCookie(cookie);
4156 } else if (action == nsICookieNotification::COOKIE_ADDED ||
4157 action == nsICookieNotification::COOKIE_CHANGED) {
4158 cs->AddCookie(cookie);
4160 } else if (!strcmp(aTopic, NS_NETWORK_LINK_TYPE_TOPIC)) {
4161 UpdateNetworkLinkType();
4162 } else if (!strcmp(aTopic, "network:socket-process-crashed")) {
4163 Unused << SendSocketProcessCrashed();
4164 } else if (!strcmp(aTopic, DEFAULT_TIMEZONE_CHANGED_OBSERVER_TOPIC)) {
4165 Unused << SendSystemTimezoneChanged();
4166 } else if (!strcmp(aTopic, NS_NETWORK_TRR_MODE_CHANGED_TOPIC)) {
4167 nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
4168 nsIDNSService::ResolverMode mode;
4169 dns->GetCurrentTrrMode(&mode);
4170 Unused << SendSetTRRMode(mode, static_cast<nsIDNSService::ResolverMode>(
4171 StaticPrefs::network_trr_mode()));
4174 return NS_OK;
4177 void ContentParent::UpdateNetworkLinkType() {
4178 nsresult rv;
4179 nsCOMPtr<nsINetworkLinkService> nls =
4180 do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv);
4181 if (NS_FAILED(rv)) {
4182 return;
4185 uint32_t linkType = nsINetworkLinkService::LINK_TYPE_UNKNOWN;
4186 rv = nls->GetLinkType(&linkType);
4187 if (NS_FAILED(rv)) {
4188 return;
4191 Unused << SendNetworkLinkTypeChange(linkType);
4194 NS_IMETHODIMP
4195 ContentParent::GetInterface(const nsIID& aIID, void** aResult) {
4196 NS_ENSURE_ARG_POINTER(aResult);
4198 if (aIID.Equals(NS_GET_IID(nsIMessageSender))) {
4199 nsCOMPtr<nsIMessageSender> mm = GetMessageManager();
4200 mm.forget(aResult);
4201 return NS_OK;
4204 return NS_NOINTERFACE;
4207 mozilla::ipc::IPCResult ContentParent::RecvInitBackground(
4208 Endpoint<PBackgroundStarterParent>&& aEndpoint) {
4209 if (!BackgroundParent::AllocStarter(this, std::move(aEndpoint))) {
4210 NS_WARNING("BackgroundParent::Alloc failed");
4213 return IPC_OK();
4216 bool ContentParent::CanOpenBrowser(const IPCTabContext& aContext) {
4217 // (PopupIPCTabContext lets the child process prove that it has access to
4218 // the app it's trying to open.)
4219 // On e10s we also allow UnsafeTabContext to allow service workers to open
4220 // windows. This is enforced in MaybeInvalidTabContext.
4221 if (aContext.type() != IPCTabContext::TPopupIPCTabContext) {
4222 MOZ_CRASH_UNLESS_FUZZING(
4223 "Unexpected IPCTabContext type. Aborting AllocPBrowserParent.");
4224 return false;
4227 if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
4228 const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext();
4230 auto opener = BrowserParent::GetFrom(popupContext.opener().AsParent());
4231 if (!opener) {
4232 MOZ_CRASH_UNLESS_FUZZING(
4233 "Got null opener from child; aborting AllocPBrowserParent.");
4234 return false;
4238 MaybeInvalidTabContext tc(aContext);
4239 if (!tc.IsValid()) {
4240 NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext. (%s) "
4241 "Aborting AllocPBrowserParent.",
4242 tc.GetInvalidReason())
4243 .get());
4244 return false;
4247 return true;
4250 static bool CloneIsLegal(ContentParent* aCp, CanonicalBrowsingContext& aSource,
4251 CanonicalBrowsingContext& aTarget) {
4252 // Source and target must be in the same BCG
4253 if (NS_WARN_IF(aSource.Group() != aTarget.Group())) {
4254 return false;
4256 // The source and target must be in different toplevel <browser>s
4257 if (NS_WARN_IF(aSource.Top() == aTarget.Top())) {
4258 return false;
4261 // Neither source nor target must be toplevel.
4262 if (NS_WARN_IF(aSource.IsTop()) || NS_WARN_IF(aTarget.IsTop())) {
4263 return false;
4266 // Both should be embedded by the same process.
4267 auto* sourceEmbedder = aSource.GetParentWindowContext();
4268 if (NS_WARN_IF(!sourceEmbedder) ||
4269 NS_WARN_IF(sourceEmbedder->GetContentParent() != aCp)) {
4270 return false;
4273 auto* targetEmbedder = aTarget.GetParentWindowContext();
4274 if (NS_WARN_IF(!targetEmbedder) ||
4275 NS_WARN_IF(targetEmbedder->GetContentParent() != aCp)) {
4276 return false;
4279 // All seems sane.
4280 return true;
4283 mozilla::ipc::IPCResult ContentParent::RecvCloneDocumentTreeInto(
4284 const MaybeDiscarded<BrowsingContext>& aSource,
4285 const MaybeDiscarded<BrowsingContext>& aTarget, PrintData&& aPrintData) {
4286 if (aSource.IsNullOrDiscarded() || aTarget.IsNullOrDiscarded()) {
4287 return IPC_OK();
4290 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
4291 // All existing processes have potentially been slated for removal already,
4292 // such that any subsequent call to GetNewOrUsedLaunchingBrowserProcess
4293 // (normally supposed to find an existing process here) will try to create
4294 // a new process (but fail) that nobody would ever really use. Let's avoid
4295 // this together with the expensive CloneDocumentTreeInto operation.
4296 return IPC_OK();
4299 auto* source = aSource.get_canonical();
4300 auto* target = aTarget.get_canonical();
4302 if (!CloneIsLegal(this, *source, *target)) {
4303 return IPC_FAIL(this, "Illegal subframe clone");
4306 ContentParent* cp = source->GetContentParent();
4307 if (NS_WARN_IF(!cp)) {
4308 return IPC_OK();
4311 if (NS_WARN_IF(cp->GetRemoteType() == GetRemoteType())) {
4312 // Wanted to switch to a target browsing context that's already local again.
4313 // See bug 1676996 for how this can happen.
4315 // Dropping the switch on the floor seems fine for this case, though we
4316 // could also try to clone the local document.
4318 // If the remote type matches & it's in the same group (which was confirmed
4319 // by CloneIsLegal), it must be the exact same process.
4320 MOZ_DIAGNOSTIC_ASSERT(cp == this);
4321 return IPC_OK();
4324 target->CloneDocumentTreeInto(source, cp->GetRemoteType(),
4325 std::move(aPrintData));
4326 return IPC_OK();
4329 mozilla::ipc::IPCResult ContentParent::RecvUpdateRemotePrintSettings(
4330 const MaybeDiscarded<BrowsingContext>& aTarget, PrintData&& aPrintData) {
4331 if (aTarget.IsNullOrDiscarded()) {
4332 return IPC_OK();
4335 auto* target = aTarget.get_canonical();
4336 auto* bp = target->GetBrowserParent();
4337 if (NS_WARN_IF(!bp)) {
4338 return IPC_OK();
4341 Unused << bp->SendUpdateRemotePrintSettings(std::move(aPrintData));
4342 return IPC_OK();
4345 mozilla::ipc::IPCResult ContentParent::RecvConstructPopupBrowser(
4346 ManagedEndpoint<PBrowserParent>&& aBrowserEp,
4347 ManagedEndpoint<PWindowGlobalParent>&& aWindowEp, const TabId& aTabId,
4348 const IPCTabContext& aContext, const WindowGlobalInit& aInitialWindowInit,
4349 const uint32_t& aChromeFlags) {
4350 MOZ_ASSERT(XRE_IsParentProcess());
4352 if (!CanOpenBrowser(aContext)) {
4353 return IPC_FAIL(this, "CanOpenBrowser Failed");
4356 RefPtr<CanonicalBrowsingContext> browsingContext =
4357 CanonicalBrowsingContext::Get(
4358 aInitialWindowInit.context().mBrowsingContextId);
4359 if (!browsingContext || browsingContext->IsDiscarded()) {
4360 return IPC_FAIL(this, "Null or discarded initial BrowsingContext");
4362 if (!aInitialWindowInit.principal()) {
4363 return IPC_FAIL(this, "Cannot create without valid initial principal");
4366 if (!ValidatePrincipal(aInitialWindowInit.principal())) {
4367 LogAndAssertFailedPrincipalValidationInfo(aInitialWindowInit.principal(),
4368 __func__);
4371 if (browsingContext->GetBrowserParent()) {
4372 return IPC_FAIL(this, "BrowsingContext already has a BrowserParent");
4375 uint32_t chromeFlags = aChromeFlags;
4376 TabId openerTabId(0);
4377 ContentParentId openerCpId(0);
4378 if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
4379 // CanOpenBrowser has ensured that the IPCTabContext is of
4380 // type PopupIPCTabContext, and that the opener BrowserParent is
4381 // reachable.
4382 const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext();
4383 auto opener = BrowserParent::GetFrom(popupContext.opener().AsParent());
4384 openerTabId = opener->GetTabId();
4385 openerCpId = opener->Manager()->ChildID();
4387 // We must ensure that the private browsing and remoteness flags
4388 // match those of the opener.
4389 nsCOMPtr<nsILoadContext> loadContext = opener->GetLoadContext();
4390 if (!loadContext) {
4391 return IPC_FAIL(this, "Missing Opener LoadContext");
4393 if (loadContext->UsePrivateBrowsing()) {
4394 chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
4396 if (loadContext->UseRemoteSubframes()) {
4397 chromeFlags |= nsIWebBrowserChrome::CHROME_FISSION_WINDOW;
4401 // And because we're allocating a remote browser, of course the
4402 // window is remote.
4403 chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
4405 if (NS_WARN_IF(!browsingContext->IsOwnedByProcess(ChildID()))) {
4406 return IPC_FAIL(this, "BrowsingContext Owned by Incorrect Process!");
4409 MaybeInvalidTabContext tc(aContext);
4410 MOZ_ASSERT(tc.IsValid());
4412 RefPtr<WindowGlobalParent> initialWindow =
4413 WindowGlobalParent::CreateDisconnected(aInitialWindowInit);
4414 if (!initialWindow) {
4415 return IPC_FAIL(this, "Failed to create WindowGlobalParent");
4418 auto parent = MakeRefPtr<BrowserParent>(this, aTabId, tc.GetTabContext(),
4419 browsingContext, chromeFlags);
4421 // Bind the created BrowserParent to IPC to actually link the actor.
4422 if (NS_WARN_IF(!BindPBrowserEndpoint(std::move(aBrowserEp), parent))) {
4423 return IPC_FAIL(this, "BindPBrowserEndpoint failed");
4426 // XXX: Why are we checking these requirements? It seems we should register
4427 // the created frame unconditionally?
4428 if (openerTabId > 0) {
4429 // The creation of PBrowser was triggered from content process through
4430 // window.open().
4431 // We need to register remote frame with the child generated tab id.
4432 auto* cpm = ContentProcessManager::GetSingleton();
4433 if (!cpm || !cpm->RegisterRemoteFrame(parent)) {
4434 return IPC_FAIL(this, "RegisterRemoteFrame Failed");
4438 if (NS_WARN_IF(!parent->BindPWindowGlobalEndpoint(std::move(aWindowEp),
4439 initialWindow))) {
4440 return IPC_FAIL(this, "BindPWindowGlobalEndpoint failed");
4443 browsingContext->SetCurrentBrowserParent(parent);
4445 initialWindow->Init();
4447 // When enabling input event prioritization, input events may preempt other
4448 // normal priority IPC messages. To prevent the input events preempt
4449 // PBrowserConstructor, we use an IPC 'RemoteIsReadyToHandleInputEvents' to
4450 // notify parent that BrowserChild is created. In this case, PBrowser is
4451 // initiated from content so that we can set BrowserParent as ready to handle
4452 // input
4453 parent->SetReadyToHandleInputEvents();
4454 return IPC_OK();
4457 mozilla::PRemoteSpellcheckEngineParent*
4458 ContentParent::AllocPRemoteSpellcheckEngineParent() {
4459 mozilla::RemoteSpellcheckEngineParent* parent =
4460 new mozilla::RemoteSpellcheckEngineParent();
4461 return parent;
4464 bool ContentParent::DeallocPRemoteSpellcheckEngineParent(
4465 PRemoteSpellcheckEngineParent* parent) {
4466 delete parent;
4467 return true;
4470 /* static */
4471 void ContentParent::SendShutdownTimerCallback(nsITimer* aTimer,
4472 void* aClosure) {
4473 auto* self = static_cast<ContentParent*>(aClosure);
4474 self->AsyncSendShutDownMessage();
4477 /* static */
4478 void ContentParent::ForceKillTimerCallback(nsITimer* aTimer, void* aClosure) {
4479 // We don't want to time out the content process during XPCShell tests. This
4480 // is the easiest way to ensure that.
4481 if (PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR")) {
4482 return;
4485 auto* self = static_cast<ContentParent*>(aClosure);
4486 self->KillHard("ShutDownKill");
4489 void ContentParent::GeneratePairedMinidump(const char* aReason) {
4490 // We're about to kill the child process associated with this content.
4491 // Something has gone wrong to get us here, so we generate a minidump
4492 // of the parent and child for submission to the crash server unless we're
4493 // already shutting down.
4494 if (mCrashReporter &&
4495 !AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed) &&
4496 StaticPrefs::dom_ipc_tabs_createKillHardCrashReports_AtStartup()) {
4497 // GeneratePairedMinidump creates two minidumps for us - the main
4498 // one is for the content process we're about to kill, and the other
4499 // one is for the main browser process. That second one is the extra
4500 // minidump tagging along, so we have to tell the crash reporter that
4501 // it exists and is being appended.
4502 nsAutoCString additionalDumps("browser");
4503 mCrashReporter->AddAnnotationNSCString(
4504 CrashReporter::Annotation::additional_minidumps, additionalDumps);
4505 nsDependentCString reason(aReason);
4506 mCrashReporter->AddAnnotationNSCString(
4507 CrashReporter::Annotation::ipc_channel_error, reason);
4509 // Generate the report and insert into the queue for submittal.
4510 if (mCrashReporter->GenerateMinidumpAndPair(this, "browser"_ns)) {
4511 mCrashReporter->FinalizeCrashReport();
4512 mCreatedPairedMinidumps = true;
4517 void ContentParent::HandleOrphanedMinidump(nsString* aDumpId) {
4518 if (CrashReporter::FinalizeOrphanedMinidump(
4519 OtherPid(), GeckoProcessType_Content, aDumpId)) {
4520 CrashReporterHost::RecordCrash(GeckoProcessType_Content,
4521 nsICrashService::CRASH_TYPE_CRASH, *aDumpId);
4522 } else {
4523 NS_WARNING(nsPrintfCString("content process pid = %" PRIPID
4524 " crashed without leaving a minidump behind",
4525 OtherPid())
4526 .get());
4530 // WARNING: aReason appears in telemetry, so any new value passed in requires
4531 // data review.
4532 void ContentParent::KillHard(const char* aReason) {
4533 AUTO_PROFILER_LABEL("ContentParent::KillHard", OTHER);
4535 // On Windows, calling KillHard multiple times causes problems - the
4536 // process handle becomes invalid on the first call, causing a second call
4537 // to crash our process - more details in bug 890840.
4538 if (mCalledKillHard) {
4539 return;
4541 mCalledKillHard = true;
4542 if (mSendShutdownTimer) {
4543 mSendShutdownTimer->Cancel();
4544 mSendShutdownTimer = nullptr;
4546 if (mForceKillTimer) {
4547 mForceKillTimer->Cancel();
4548 mForceKillTimer = nullptr;
4551 RemoveShutdownBlockers();
4552 nsCString reason = nsDependentCString(aReason);
4554 // If we find mIsNotifiedShutdownSuccess there is no reason to blame this
4555 // content process, most probably our parent process is just slow in
4556 // processing its own main thread queue.
4557 if (!mIsNotifiedShutdownSuccess) {
4558 GeneratePairedMinidump(aReason);
4559 } else {
4560 reason = nsDependentCString("KillHard after IsNotifiedShutdownSuccess.");
4562 Telemetry::Accumulate(Telemetry::SUBPROCESS_KILL_HARD, reason, 1);
4564 ProcessHandle otherProcessHandle;
4565 if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle)) {
4566 NS_ERROR("Failed to open child process when attempting kill.");
4567 if (CanSend()) {
4568 GetIPCChannel()->InduceConnectionError();
4570 return;
4573 if (!KillProcess(otherProcessHandle, base::PROCESS_END_KILLED_BY_USER)) {
4574 if (mCrashReporter) {
4575 mCrashReporter->DeleteCrashReport();
4577 NS_WARNING("failed to kill subprocess!");
4580 if (mSubprocess) {
4581 MOZ_LOG(
4582 ContentParent::GetLog(), LogLevel::Verbose,
4583 ("KillHard Subprocess(%s): ContentParent %p mSubprocess %p handle "
4584 "%" PRIuPTR,
4585 aReason, this, mSubprocess,
4586 mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
4587 mSubprocess->SetAlreadyDead();
4590 // After we've killed the remote process, also ensure we induce a connection
4591 // error in the IPC channel to immediately stop all IPC communication on this
4592 // channel.
4593 if (CanSend()) {
4594 GetIPCChannel()->InduceConnectionError();
4597 // EnsureProcessTerminated has responsibilty for closing otherProcessHandle.
4598 XRE_GetIOMessageLoop()->PostTask(
4599 NewRunnableFunction("EnsureProcessTerminatedRunnable",
4600 &ProcessWatcher::EnsureProcessTerminated,
4601 otherProcessHandle, /*force=*/true));
4604 void ContentParent::FriendlyName(nsAString& aName, bool aAnonymize) {
4605 aName.Truncate();
4606 if (mIsForBrowser) {
4607 aName.AssignLiteral("Browser");
4608 } else if (aAnonymize) {
4609 aName.AssignLiteral("<anonymized-name>");
4610 } else {
4611 aName.AssignLiteral("???");
4615 mozilla::ipc::IPCResult ContentParent::RecvInitCrashReporter(
4616 const NativeThreadId& aThreadId) {
4617 mCrashReporter =
4618 MakeUnique<CrashReporterHost>(GeckoProcessType_Content, aThreadId);
4620 return IPC_OK();
4623 hal_sandbox::PHalParent* ContentParent::AllocPHalParent() {
4624 return hal_sandbox::CreateHalParent();
4627 bool ContentParent::DeallocPHalParent(hal_sandbox::PHalParent* aHal) {
4628 delete aHal;
4629 return true;
4632 devtools::PHeapSnapshotTempFileHelperParent*
4633 ContentParent::AllocPHeapSnapshotTempFileHelperParent() {
4634 return devtools::HeapSnapshotTempFileHelperParent::Create();
4637 bool ContentParent::DeallocPHeapSnapshotTempFileHelperParent(
4638 devtools::PHeapSnapshotTempFileHelperParent* aHeapSnapshotHelper) {
4639 delete aHeapSnapshotHelper;
4640 return true;
4643 bool ContentParent::SendRequestMemoryReport(
4644 const uint32_t& aGeneration, const bool& aAnonymize,
4645 const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile) {
4646 // This automatically cancels the previous request.
4647 mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
4648 // If we run the callback in response to a reply, then by definition |this|
4649 // is still alive, so the ref pointer is redundant, but it seems easier
4650 // to hold a strong reference than to worry about that.
4651 RefPtr<ContentParent> self(this);
4652 PContentParent::SendRequestMemoryReport(
4653 aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile,
4654 [&, self](const uint32_t& aGeneration2) {
4655 if (self->mMemoryReportRequest) {
4656 self->mMemoryReportRequest->Finish(aGeneration2);
4657 self->mMemoryReportRequest = nullptr;
4660 [&, self](mozilla::ipc::ResponseRejectReason) {
4661 self->mMemoryReportRequest = nullptr;
4663 return IPC_OK();
4666 mozilla::ipc::IPCResult ContentParent::RecvAddMemoryReport(
4667 const MemoryReport& aReport) {
4668 if (mMemoryReportRequest) {
4669 mMemoryReportRequest->RecvReport(aReport);
4671 return IPC_OK();
4674 PCycleCollectWithLogsParent* ContentParent::AllocPCycleCollectWithLogsParent(
4675 const bool& aDumpAllTraces, const FileDescriptor& aGCLog,
4676 const FileDescriptor& aCCLog) {
4677 MOZ_CRASH("Don't call this; use ContentParent::CycleCollectWithLogs");
4680 bool ContentParent::DeallocPCycleCollectWithLogsParent(
4681 PCycleCollectWithLogsParent* aActor) {
4682 delete aActor;
4683 return true;
4686 bool ContentParent::CycleCollectWithLogs(
4687 bool aDumpAllTraces, nsICycleCollectorLogSink* aSink,
4688 nsIDumpGCAndCCLogsCallback* aCallback) {
4689 return CycleCollectWithLogsParent::AllocAndSendConstructor(
4690 this, aDumpAllTraces, aSink, aCallback);
4693 PScriptCacheParent* ContentParent::AllocPScriptCacheParent(
4694 const FileDescOrError& cacheFile, const bool& wantCacheData) {
4695 return new loader::ScriptCacheParent(wantCacheData);
4698 bool ContentParent::DeallocPScriptCacheParent(PScriptCacheParent* cache) {
4699 delete static_cast<loader::ScriptCacheParent*>(cache);
4700 return true;
4703 already_AddRefed<PNeckoParent> ContentParent::AllocPNeckoParent() {
4704 RefPtr<NeckoParent> actor = new NeckoParent();
4705 return actor.forget();
4708 mozilla::ipc::IPCResult ContentParent::RecvInitStreamFilter(
4709 const uint64_t& aChannelId, const nsAString& aAddonId,
4710 InitStreamFilterResolver&& aResolver) {
4711 extensions::StreamFilterParent::Create(this, aChannelId, aAddonId)
4712 ->Then(
4713 GetCurrentSerialEventTarget(), __func__,
4714 [aResolver](mozilla::ipc::Endpoint<PStreamFilterChild>&& aEndpoint) {
4715 aResolver(std::move(aEndpoint));
4717 [aResolver](bool aDummy) {
4718 aResolver(mozilla::ipc::Endpoint<PStreamFilterChild>());
4721 return IPC_OK();
4724 mozilla::ipc::IPCResult ContentParent::RecvAddSecurityState(
4725 const MaybeDiscarded<WindowContext>& aContext, uint32_t aStateFlags) {
4726 if (aContext.IsNullOrDiscarded()) {
4727 return IPC_OK();
4730 aContext.get()->AddSecurityState(aStateFlags);
4731 return IPC_OK();
4734 already_AddRefed<PExternalHelperAppParent>
4735 ContentParent::AllocPExternalHelperAppParent(
4736 nsIURI* uri, const mozilla::net::LoadInfoArgs& aLoadInfoArgs,
4737 const nsACString& aMimeContentType, const nsACString& aContentDisposition,
4738 const uint32_t& aContentDispositionHint,
4739 const nsAString& aContentDispositionFilename, const bool& aForceSave,
4740 const int64_t& aContentLength, const bool& aWasFileChannel,
4741 nsIURI* aReferrer, const MaybeDiscarded<BrowsingContext>& aContext,
4742 const bool& aShouldCloseWindow) {
4743 RefPtr<ExternalHelperAppParent> parent = new ExternalHelperAppParent(
4744 uri, aContentLength, aWasFileChannel, aContentDisposition,
4745 aContentDispositionHint, aContentDispositionFilename);
4746 return parent.forget();
4749 mozilla::ipc::IPCResult ContentParent::RecvPExternalHelperAppConstructor(
4750 PExternalHelperAppParent* actor, nsIURI* uri,
4751 const LoadInfoArgs& loadInfoArgs, const nsACString& aMimeContentType,
4752 const nsACString& aContentDisposition,
4753 const uint32_t& aContentDispositionHint,
4754 const nsAString& aContentDispositionFilename, const bool& aForceSave,
4755 const int64_t& aContentLength, const bool& aWasFileChannel,
4756 nsIURI* aReferrer, const MaybeDiscarded<BrowsingContext>& aContext,
4757 const bool& aShouldCloseWindow) {
4758 BrowsingContext* context = aContext.IsDiscarded() ? nullptr : aContext.get();
4759 if (!static_cast<ExternalHelperAppParent*>(actor)->Init(
4760 loadInfoArgs, aMimeContentType, aForceSave, aReferrer, context,
4761 aShouldCloseWindow)) {
4762 return IPC_FAIL(this, "Init failed.");
4764 return IPC_OK();
4767 already_AddRefed<PHandlerServiceParent>
4768 ContentParent::AllocPHandlerServiceParent() {
4769 RefPtr<HandlerServiceParent> actor = new HandlerServiceParent();
4770 return actor.forget();
4773 media::PMediaParent* ContentParent::AllocPMediaParent() {
4774 return media::AllocPMediaParent();
4777 bool ContentParent::DeallocPMediaParent(media::PMediaParent* aActor) {
4778 return media::DeallocPMediaParent(aActor);
4781 PBenchmarkStorageParent* ContentParent::AllocPBenchmarkStorageParent() {
4782 return new BenchmarkStorageParent;
4785 bool ContentParent::DeallocPBenchmarkStorageParent(
4786 PBenchmarkStorageParent* aActor) {
4787 delete aActor;
4788 return true;
4791 #ifdef MOZ_WEBSPEECH
4792 already_AddRefed<PSpeechSynthesisParent>
4793 ContentParent::AllocPSpeechSynthesisParent() {
4794 if (!StaticPrefs::media_webspeech_synth_enabled()) {
4795 return nullptr;
4797 RefPtr<SpeechSynthesisParent> actor = new SpeechSynthesisParent();
4798 return actor.forget();
4801 mozilla::ipc::IPCResult ContentParent::RecvPSpeechSynthesisConstructor(
4802 PSpeechSynthesisParent* aActor) {
4803 if (!static_cast<SpeechSynthesisParent*>(aActor)->SendInit()) {
4804 return IPC_FAIL(this, "SpeechSynthesisParent::SendInit failed.");
4806 return IPC_OK();
4808 #endif
4810 mozilla::ipc::IPCResult ContentParent::RecvStartVisitedQueries(
4811 const nsTArray<RefPtr<nsIURI>>& aUris) {
4812 nsCOMPtr<IHistory> history = components::History::Service();
4813 if (!history) {
4814 return IPC_OK();
4816 for (const auto& uri : aUris) {
4817 if (NS_WARN_IF(!uri)) {
4818 continue;
4820 history->ScheduleVisitedQuery(uri, this);
4822 return IPC_OK();
4825 mozilla::ipc::IPCResult ContentParent::RecvSetURITitle(nsIURI* uri,
4826 const nsAString& title) {
4827 if (!uri) {
4828 return IPC_FAIL(this, "uri must not be null.");
4830 nsCOMPtr<IHistory> history = components::History::Service();
4831 if (history) {
4832 history->SetURITitle(uri, title);
4834 return IPC_OK();
4837 mozilla::ipc::IPCResult ContentParent::RecvIsSecureURI(
4838 nsIURI* aURI, const OriginAttributes& aOriginAttributes,
4839 bool* aIsSecureURI) {
4840 nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID));
4841 if (!sss) {
4842 return IPC_FAIL(this, "Failed to get nsISiteSecurityService.");
4844 if (!aURI) {
4845 return IPC_FAIL(this, "aURI must not be null.");
4847 nsresult rv = sss->IsSecureURI(aURI, aOriginAttributes, aIsSecureURI);
4848 if (NS_FAILED(rv)) {
4849 return IPC_FAIL(this, "IsSecureURI failed.");
4851 return IPC_OK();
4854 mozilla::ipc::IPCResult ContentParent::RecvAccumulateMixedContentHSTS(
4855 nsIURI* aURI, const bool& aActive,
4856 const OriginAttributes& aOriginAttributes) {
4857 if (!aURI) {
4858 return IPC_FAIL(this, "aURI must not be null.");
4860 nsMixedContentBlocker::AccumulateMixedContentHSTS(aURI, aActive,
4861 aOriginAttributes);
4862 return IPC_OK();
4865 mozilla::ipc::IPCResult ContentParent::RecvLoadURIExternal(
4866 nsIURI* uri, nsIPrincipal* aTriggeringPrincipal,
4867 nsIPrincipal* aRedirectPrincipal,
4868 const MaybeDiscarded<BrowsingContext>& aContext,
4869 bool aWasExternallyTriggered, bool aHasValidUserGestureActivation) {
4870 if (aContext.IsDiscarded()) {
4871 return IPC_OK();
4874 nsCOMPtr<nsIExternalProtocolService> extProtService(
4875 do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
4876 if (!extProtService) {
4877 return IPC_OK();
4880 if (!uri) {
4881 return IPC_FAIL(this, "uri must not be null.");
4884 BrowsingContext* bc = aContext.get();
4885 extProtService->LoadURI(uri, aTriggeringPrincipal, aRedirectPrincipal, bc,
4886 aWasExternallyTriggered,
4887 aHasValidUserGestureActivation);
4888 return IPC_OK();
4891 mozilla::ipc::IPCResult ContentParent::RecvExtProtocolChannelConnectParent(
4892 const uint64_t& registrarId) {
4893 nsresult rv;
4895 // First get the real channel created before redirect on the parent.
4896 nsCOMPtr<nsIChannel> channel;
4897 rv = NS_LinkRedirectChannels(registrarId, nullptr, getter_AddRefs(channel));
4898 NS_ENSURE_SUCCESS(rv, IPC_OK());
4900 nsCOMPtr<nsIParentChannel> parent = do_QueryInterface(channel, &rv);
4901 NS_ENSURE_SUCCESS(rv, IPC_OK());
4903 // The channel itself is its own (faked) parent, link it.
4904 rv = NS_LinkRedirectChannels(registrarId, parent, getter_AddRefs(channel));
4905 NS_ENSURE_SUCCESS(rv, IPC_OK());
4907 // Signal the parent channel that it's a redirect-to parent. This will
4908 // make AsyncOpen on it do nothing (what we want).
4909 // Yes, this is a bit of a hack, but I don't think it's necessary to invent
4910 // a new interface just to set this flag on the channel.
4911 parent->SetParentListener(nullptr);
4913 return IPC_OK();
4916 mozilla::ipc::IPCResult ContentParent::RecvShowAlert(
4917 nsIAlertNotification* aAlert) {
4918 if (!aAlert) {
4919 return IPC_FAIL(this, "aAlert must not be null.");
4921 nsCOMPtr<nsIAlertsService> sysAlerts(components::Alerts::Service());
4922 if (sysAlerts) {
4923 sysAlerts->ShowAlert(aAlert, this);
4925 return IPC_OK();
4928 mozilla::ipc::IPCResult ContentParent::RecvCloseAlert(const nsAString& aName,
4929 bool aContextClosed) {
4930 nsCOMPtr<nsIAlertsService> sysAlerts(components::Alerts::Service());
4931 if (sysAlerts) {
4932 sysAlerts->CloseAlert(aName, aContextClosed);
4935 return IPC_OK();
4938 mozilla::ipc::IPCResult ContentParent::RecvDisableNotifications(
4939 nsIPrincipal* aPrincipal) {
4940 if (!aPrincipal) {
4941 return IPC_FAIL(this, "No principal");
4944 if (!ValidatePrincipal(aPrincipal)) {
4945 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
4947 Unused << Notification::RemovePermission(aPrincipal);
4948 return IPC_OK();
4951 mozilla::ipc::IPCResult ContentParent::RecvOpenNotificationSettings(
4952 nsIPrincipal* aPrincipal) {
4953 if (!aPrincipal) {
4954 return IPC_FAIL(this, "No principal");
4957 if (!ValidatePrincipal(aPrincipal)) {
4958 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
4960 Unused << Notification::OpenSettings(aPrincipal);
4961 return IPC_OK();
4964 mozilla::ipc::IPCResult ContentParent::RecvNotificationEvent(
4965 const nsAString& aType, const NotificationEventData& aData) {
4966 nsCOMPtr<nsIServiceWorkerManager> swm =
4967 mozilla::components::ServiceWorkerManager::Service();
4968 if (NS_WARN_IF(!swm)) {
4969 // Probably shouldn't happen, but no need to crash the child process.
4970 return IPC_OK();
4973 if (aType.EqualsLiteral("click")) {
4974 nsresult rv = swm->SendNotificationClickEvent(
4975 aData.originSuffix(), aData.scope(), aData.ID(), aData.title(),
4976 aData.dir(), aData.lang(), aData.body(), aData.tag(), aData.icon(),
4977 aData.data(), aData.behavior());
4978 Unused << NS_WARN_IF(NS_FAILED(rv));
4979 } else {
4980 MOZ_ASSERT(aType.EqualsLiteral("close"));
4981 nsresult rv = swm->SendNotificationCloseEvent(
4982 aData.originSuffix(), aData.scope(), aData.ID(), aData.title(),
4983 aData.dir(), aData.lang(), aData.body(), aData.tag(), aData.icon(),
4984 aData.data(), aData.behavior());
4985 Unused << NS_WARN_IF(NS_FAILED(rv));
4988 return IPC_OK();
4991 mozilla::ipc::IPCResult ContentParent::RecvSyncMessage(
4992 const nsAString& aMsg, const ClonedMessageData& aData,
4993 nsTArray<StructuredCloneData>* aRetvals) {
4994 AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("ContentParent::RecvSyncMessage",
4995 OTHER, aMsg);
4996 MMPrinter::Print("ContentParent::RecvSyncMessage", aMsg, aData);
4998 RefPtr<nsFrameMessageManager> ppm = mMessageManager;
4999 if (ppm) {
5000 ipc::StructuredCloneData data;
5001 ipc::UnpackClonedMessageData(aData, data);
5003 ppm->ReceiveMessage(ppm, nullptr, aMsg, true, &data, aRetvals,
5004 IgnoreErrors());
5006 return IPC_OK();
5009 mozilla::ipc::IPCResult ContentParent::RecvAsyncMessage(
5010 const nsAString& aMsg, const ClonedMessageData& aData) {
5011 AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("ContentParent::RecvAsyncMessage",
5012 OTHER, aMsg);
5013 MMPrinter::Print("ContentParent::RecvAsyncMessage", aMsg, aData);
5015 RefPtr<nsFrameMessageManager> ppm = mMessageManager;
5016 if (ppm) {
5017 ipc::StructuredCloneData data;
5018 ipc::UnpackClonedMessageData(aData, data);
5020 ppm->ReceiveMessage(ppm, nullptr, aMsg, false, &data, nullptr,
5021 IgnoreErrors());
5023 return IPC_OK();
5026 MOZ_CAN_RUN_SCRIPT
5027 static int32_t AddGeolocationListener(
5028 nsIDOMGeoPositionCallback* watcher,
5029 nsIDOMGeoPositionErrorCallback* errorCallBack, bool highAccuracy) {
5030 RefPtr<Geolocation> geo = Geolocation::NonWindowSingleton();
5032 UniquePtr<PositionOptions> options = MakeUnique<PositionOptions>();
5033 options->mTimeout = 0;
5034 options->mMaximumAge = 0;
5035 options->mEnableHighAccuracy = highAccuracy;
5036 return geo->WatchPosition(watcher, errorCallBack, std::move(options));
5039 mozilla::ipc::IPCResult ContentParent::RecvAddGeolocationListener(
5040 const bool& aHighAccuracy) {
5041 // To ensure no geolocation updates are skipped, we always force the
5042 // creation of a new listener.
5043 RecvRemoveGeolocationListener();
5044 mGeolocationWatchID = AddGeolocationListener(this, this, aHighAccuracy);
5045 return IPC_OK();
5048 mozilla::ipc::IPCResult ContentParent::RecvRemoveGeolocationListener() {
5049 if (mGeolocationWatchID != -1) {
5050 RefPtr<Geolocation> geo = Geolocation::NonWindowSingleton();
5051 if (geo) {
5052 geo->ClearWatch(mGeolocationWatchID);
5054 mGeolocationWatchID = -1;
5056 return IPC_OK();
5059 mozilla::ipc::IPCResult ContentParent::RecvSetGeolocationHigherAccuracy(
5060 const bool& aEnable) {
5061 // This should never be called without a listener already present,
5062 // so this check allows us to forgo securing privileges.
5063 if (mGeolocationWatchID != -1) {
5064 RecvRemoveGeolocationListener();
5065 mGeolocationWatchID = AddGeolocationListener(this, this, aEnable);
5067 return IPC_OK();
5070 NS_IMETHODIMP
5071 ContentParent::HandleEvent(nsIDOMGeoPosition* postion) {
5072 Unused << SendGeolocationUpdate(postion);
5073 return NS_OK;
5076 NS_IMETHODIMP
5077 ContentParent::HandleEvent(GeolocationPositionError* positionError) {
5078 Unused << SendGeolocationError(positionError->Code());
5079 return NS_OK;
5082 mozilla::ipc::IPCResult ContentParent::RecvConsoleMessage(
5083 const nsAString& aMessage) {
5084 nsresult rv;
5085 nsCOMPtr<nsIConsoleService> consoleService =
5086 do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
5087 if (NS_SUCCEEDED(rv)) {
5088 RefPtr<nsConsoleMessage> msg(new nsConsoleMessage(aMessage));
5089 msg->SetIsForwardedFromContentProcess(true);
5090 consoleService->LogMessageWithMode(msg, nsIConsoleService::SuppressLog);
5092 return IPC_OK();
5095 mozilla::ipc::IPCResult ContentParent::RecvReportFrameTimingData(
5096 const LoadInfoArgs& loadInfoArgs, const nsAString& entryName,
5097 const nsAString& initiatorType, UniquePtr<PerformanceTimingData>&& aData) {
5098 if (!aData) {
5099 return IPC_FAIL(this, "aData should not be null");
5102 RefPtr<WindowGlobalParent> parent =
5103 WindowGlobalParent::GetByInnerWindowId(loadInfoArgs.innerWindowID());
5104 if (!parent || !parent->GetContentParent()) {
5105 return IPC_OK();
5108 MOZ_ASSERT(parent->GetContentParent() != this,
5109 "No need to bounce around if in the same process");
5111 Unused << parent->GetContentParent()->SendReportFrameTimingData(
5112 loadInfoArgs, entryName, initiatorType, std::move(aData));
5113 return IPC_OK();
5116 mozilla::ipc::IPCResult ContentParent::RecvScriptError(
5117 const nsAString& aMessage, const nsAString& aSourceName,
5118 const nsAString& aSourceLine, const uint32_t& aLineNumber,
5119 const uint32_t& aColNumber, const uint32_t& aFlags,
5120 const nsACString& aCategory, const bool& aFromPrivateWindow,
5121 const uint64_t& aInnerWindowId, const bool& aFromChromeContext) {
5122 return RecvScriptErrorInternal(aMessage, aSourceName, aSourceLine,
5123 aLineNumber, aColNumber, aFlags, aCategory,
5124 aFromPrivateWindow, aFromChromeContext);
5127 mozilla::ipc::IPCResult ContentParent::RecvScriptErrorWithStack(
5128 const nsAString& aMessage, const nsAString& aSourceName,
5129 const nsAString& aSourceLine, const uint32_t& aLineNumber,
5130 const uint32_t& aColNumber, const uint32_t& aFlags,
5131 const nsACString& aCategory, const bool& aFromPrivateWindow,
5132 const bool& aFromChromeContext, const ClonedMessageData& aFrame) {
5133 return RecvScriptErrorInternal(
5134 aMessage, aSourceName, aSourceLine, aLineNumber, aColNumber, aFlags,
5135 aCategory, aFromPrivateWindow, aFromChromeContext, &aFrame);
5138 mozilla::ipc::IPCResult ContentParent::RecvScriptErrorInternal(
5139 const nsAString& aMessage, const nsAString& aSourceName,
5140 const nsAString& aSourceLine, const uint32_t& aLineNumber,
5141 const uint32_t& aColNumber, const uint32_t& aFlags,
5142 const nsACString& aCategory, const bool& aFromPrivateWindow,
5143 const bool& aFromChromeContext, const ClonedMessageData* aStack) {
5144 nsresult rv;
5145 nsCOMPtr<nsIConsoleService> consoleService =
5146 do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
5147 if (NS_FAILED(rv)) {
5148 return IPC_OK();
5151 nsCOMPtr<nsIScriptError> msg;
5153 if (aStack) {
5154 StructuredCloneData data;
5155 UnpackClonedMessageData(*aStack, data);
5157 AutoJSAPI jsapi;
5158 if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) {
5159 MOZ_CRASH();
5161 JSContext* cx = jsapi.cx();
5163 JS::Rooted<JS::Value> stack(cx);
5164 ErrorResult rv;
5165 data.Read(cx, &stack, rv);
5166 if (rv.Failed() || !stack.isObject()) {
5167 rv.SuppressException();
5168 return IPC_OK();
5171 JS::Rooted<JSObject*> stackObj(cx, &stack.toObject());
5172 if (!JS::IsUnwrappedSavedFrame(stackObj)) {
5173 return IPC_FAIL(this, "Unexpected object");
5176 JS::Rooted<JSObject*> stackGlobal(cx, JS::GetNonCCWObjectGlobal(stackObj));
5177 msg = new nsScriptErrorWithStack(JS::NothingHandleValue, stackObj,
5178 stackGlobal);
5179 } else {
5180 msg = new nsScriptError();
5183 rv = msg->Init(aMessage, aSourceName, aSourceLine, aLineNumber, aColNumber,
5184 aFlags, aCategory, aFromPrivateWindow, aFromChromeContext);
5185 if (NS_FAILED(rv)) return IPC_OK();
5187 msg->SetIsForwardedFromContentProcess(true);
5189 consoleService->LogMessageWithMode(msg, nsIConsoleService::SuppressLog);
5190 return IPC_OK();
5193 bool ContentParent::DoLoadMessageManagerScript(const nsAString& aURL,
5194 bool aRunInGlobalScope) {
5195 MOZ_ASSERT(!aRunInGlobalScope);
5196 return SendLoadProcessScript(aURL);
5199 nsresult ContentParent::DoSendAsyncMessage(const nsAString& aMessage,
5200 StructuredCloneData& aHelper) {
5201 ClonedMessageData data;
5202 if (!BuildClonedMessageData(aHelper, data)) {
5203 return NS_ERROR_DOM_DATA_CLONE_ERR;
5205 if (!SendAsyncMessage(aMessage, data)) {
5206 return NS_ERROR_UNEXPECTED;
5208 return NS_OK;
5211 mozilla::ipc::IPCResult ContentParent::RecvCopyFavicon(
5212 nsIURI* aOldURI, nsIURI* aNewURI, const bool& aInPrivateBrowsing) {
5213 if (!aOldURI) {
5214 return IPC_FAIL(this, "aOldURI should not be null");
5216 if (!aNewURI) {
5217 return IPC_FAIL(this, "aNewURI should not be null");
5220 nsDocShell::CopyFavicon(aOldURI, aNewURI, aInPrivateBrowsing);
5221 return IPC_OK();
5224 mozilla::ipc::IPCResult ContentParent::RecvFindImageText(
5225 IPCImage&& aImage, nsTArray<nsCString>&& aLanguages,
5226 FindImageTextResolver&& aResolver) {
5227 if (!TextRecognition::IsSupported() ||
5228 !Preferences::GetBool("dom.text-recognition.enabled")) {
5229 return IPC_FAIL(this, "Text recognition not available.");
5232 RefPtr<DataSourceSurface> surf =
5233 nsContentUtils::IPCImageToSurface(std::move(aImage));
5234 if (!surf) {
5235 aResolver(TextRecognitionResultOrError("Failed to read image"_ns));
5236 return IPC_OK();
5238 TextRecognition::FindText(*surf, aLanguages)
5239 ->Then(
5240 GetCurrentSerialEventTarget(), __func__,
5241 [resolver = std::move(aResolver)](
5242 TextRecognition::NativePromise::ResolveOrRejectValue&& aValue) {
5243 if (aValue.IsResolve()) {
5244 resolver(TextRecognitionResultOrError(aValue.ResolveValue()));
5245 } else {
5246 resolver(TextRecognitionResultOrError(aValue.RejectValue()));
5249 return IPC_OK();
5252 bool ContentParent::ShouldContinueFromReplyTimeout() {
5253 RefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
5254 return !monitor || !monitor->ShouldTimeOutCPOWs();
5257 mozilla::ipc::IPCResult ContentParent::RecvAddIdleObserver(
5258 const uint64_t& aObserver, const uint32_t& aIdleTimeInS) {
5259 nsresult rv;
5260 nsCOMPtr<nsIUserIdleService> idleService =
5261 do_GetService("@mozilla.org/widget/useridleservice;1", &rv);
5262 NS_ENSURE_SUCCESS(rv, IPC_FAIL(this, "Failed to get UserIdleService."));
5264 RefPtr<ParentIdleListener> listener =
5265 new ParentIdleListener(this, aObserver, aIdleTimeInS);
5266 rv = idleService->AddIdleObserver(listener, aIdleTimeInS);
5267 NS_ENSURE_SUCCESS(rv, IPC_FAIL(this, "AddIdleObserver failed."));
5268 mIdleListeners.AppendElement(listener);
5269 return IPC_OK();
5272 mozilla::ipc::IPCResult ContentParent::RecvRemoveIdleObserver(
5273 const uint64_t& aObserver, const uint32_t& aIdleTimeInS) {
5274 RefPtr<ParentIdleListener> listener;
5275 for (int32_t i = mIdleListeners.Length() - 1; i >= 0; --i) {
5276 listener = static_cast<ParentIdleListener*>(mIdleListeners[i].get());
5277 if (listener->mObserver == aObserver && listener->mTime == aIdleTimeInS) {
5278 nsresult rv;
5279 nsCOMPtr<nsIUserIdleService> idleService =
5280 do_GetService("@mozilla.org/widget/useridleservice;1", &rv);
5281 NS_ENSURE_SUCCESS(rv, IPC_FAIL(this, "Failed to get UserIdleService."));
5282 idleService->RemoveIdleObserver(listener, aIdleTimeInS);
5283 mIdleListeners.RemoveElementAt(i);
5284 break;
5287 return IPC_OK();
5290 mozilla::ipc::IPCResult ContentParent::RecvBackUpXResources(
5291 const FileDescriptor& aXSocketFd) {
5292 #ifndef MOZ_X11
5293 MOZ_CRASH("This message only makes sense on X11 platforms");
5294 #else
5295 MOZ_ASSERT(!mChildXSocketFdDup, "Already backed up X resources??");
5296 if (aXSocketFd.IsValid()) {
5297 mChildXSocketFdDup = aXSocketFd.ClonePlatformHandle();
5299 #endif
5300 return IPC_OK();
5303 class AnonymousTemporaryFileRequestor final : public Runnable {
5304 public:
5305 AnonymousTemporaryFileRequestor(ContentParent* aCP, const uint64_t& aID)
5306 : Runnable("dom::AnonymousTemporaryFileRequestor"),
5307 mCP(aCP),
5308 mID(aID),
5309 mRv(NS_OK),
5310 mPRFD(nullptr) {}
5312 NS_IMETHOD Run() override {
5313 if (NS_IsMainThread()) {
5314 FileDescOrError result;
5315 if (NS_WARN_IF(NS_FAILED(mRv))) {
5316 // Returning false will kill the child process; instead
5317 // propagate the error and let the child handle it.
5318 result = mRv;
5319 } else {
5320 result = FileDescriptor(FileDescriptor::PlatformHandleType(
5321 PR_FileDesc2NativeHandle(mPRFD)));
5322 // The FileDescriptor object owns a duplicate of the file handle; we
5323 // must close the original (and clean up the NSPR descriptor).
5324 PR_Close(mPRFD);
5326 Unused << mCP->SendProvideAnonymousTemporaryFile(mID, result);
5327 // It's important to release this reference while wr're on the main
5328 // thread!
5329 mCP = nullptr;
5330 } else {
5331 mRv = NS_OpenAnonymousTemporaryFile(&mPRFD);
5332 NS_DispatchToMainThread(this);
5334 return NS_OK;
5337 private:
5338 RefPtr<ContentParent> mCP;
5339 uint64_t mID;
5340 nsresult mRv;
5341 PRFileDesc* mPRFD;
5344 mozilla::ipc::IPCResult ContentParent::RecvRequestAnonymousTemporaryFile(
5345 const uint64_t& aID) {
5346 // Make sure to send a callback to the child if we bail out early.
5347 nsresult rv = NS_OK;
5348 RefPtr<ContentParent> self(this);
5349 auto autoNotifyChildOnError = MakeScopeExit([&, self]() {
5350 if (NS_FAILED(rv)) {
5351 FileDescOrError result(rv);
5352 Unused << self->SendProvideAnonymousTemporaryFile(aID, result);
5356 // We use a helper runnable to open the anonymous temporary file on the IO
5357 // thread. The same runnable will call us back on the main thread when the
5358 // file has been opened.
5359 nsCOMPtr<nsIEventTarget> target =
5360 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
5361 if (!target) {
5362 return IPC_OK();
5365 rv = target->Dispatch(new AnonymousTemporaryFileRequestor(this, aID),
5366 NS_DISPATCH_NORMAL);
5367 if (NS_WARN_IF(NS_FAILED(rv))) {
5368 return IPC_OK();
5371 rv = NS_OK;
5372 return IPC_OK();
5375 mozilla::ipc::IPCResult ContentParent::RecvCreateAudioIPCConnection(
5376 CreateAudioIPCConnectionResolver&& aResolver) {
5377 FileDescriptor fd = CubebUtils::CreateAudioIPCConnection();
5378 FileDescOrError result;
5379 if (fd.IsValid()) {
5380 result = fd;
5381 } else {
5382 result = NS_ERROR_FAILURE;
5384 aResolver(std::move(result));
5385 return IPC_OK();
5388 already_AddRefed<extensions::PExtensionsParent>
5389 ContentParent::AllocPExtensionsParent() {
5390 return MakeAndAddRef<extensions::ExtensionsParent>();
5393 void ContentParent::NotifyUpdatedDictionaries() {
5394 RefPtr<mozSpellChecker> spellChecker(mozSpellChecker::Create());
5395 MOZ_ASSERT(spellChecker, "No spell checker?");
5397 nsTArray<nsCString> dictionaries;
5398 spellChecker->GetDictionaryList(&dictionaries);
5400 for (auto* cp : AllProcesses(eLive)) {
5401 Unused << cp->SendUpdateDictionaryList(dictionaries);
5405 void ContentParent::NotifyUpdatedFonts(bool aFullRebuild) {
5406 if (gfxPlatformFontList::PlatformFontList()->SharedFontList()) {
5407 for (auto* cp : AllProcesses(eLive)) {
5408 Unused << cp->SendRebuildFontList(aFullRebuild);
5410 return;
5413 SystemFontList fontList;
5414 gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList);
5416 for (auto* cp : AllProcesses(eLive)) {
5417 Unused << cp->SendUpdateFontList(fontList);
5421 #ifdef MOZ_WEBRTC
5422 PWebrtcGlobalParent* ContentParent::AllocPWebrtcGlobalParent() {
5423 return WebrtcGlobalParent::Alloc();
5426 bool ContentParent::DeallocPWebrtcGlobalParent(PWebrtcGlobalParent* aActor) {
5427 WebrtcGlobalParent::Dealloc(static_cast<WebrtcGlobalParent*>(aActor));
5428 return true;
5430 #endif
5432 void ContentParent::GetIPCTransferableData(
5433 nsIDragSession* aSession, BrowserParent* aParent,
5434 nsTArray<IPCTransferableData>& aIPCTransferables) {
5435 RefPtr<DataTransfer> transfer = aSession->GetDataTransfer();
5436 if (!transfer) {
5437 // Pass eDrop to get DataTransfer with external
5438 // drag formats cached.
5439 transfer = new DataTransfer(nullptr, eDrop, true, -1);
5440 aSession->SetDataTransfer(transfer);
5442 // Note, even though this fills the DataTransfer object with
5443 // external data, the data is usually transfered over IPC lazily when
5444 // needed.
5445 transfer->FillAllExternalData();
5446 nsCOMPtr<nsILoadContext> lc = aParent ? aParent->GetLoadContext() : nullptr;
5447 nsCOMPtr<nsIArray> transferables = transfer->GetTransferables(lc);
5448 nsContentUtils::TransferablesToIPCTransferableDatas(
5449 transferables, aIPCTransferables, false, this);
5452 void ContentParent::MaybeInvokeDragSession(BrowserParent* aParent,
5453 EventMessage aMessage) {
5454 // dnd uses IPCBlob to transfer data to the content process and the IPC
5455 // message is sent as normal priority. When sending input events with input
5456 // priority, the message may be preempted by the later dnd events. To make
5457 // sure the input events and the blob message are processed in time order
5458 // on the content process, we temporarily send the input events with normal
5459 // priority when there is an active dnd session.
5460 SetInputPriorityEventEnabled(false);
5462 nsCOMPtr<nsIDragService> dragService =
5463 do_GetService("@mozilla.org/widget/dragservice;1");
5464 if (!dragService) {
5465 return;
5468 if (dragService->MaybeAddChildProcess(this)) {
5469 nsCOMPtr<nsIDragSession> session;
5470 dragService->GetCurrentSession(getter_AddRefs(session));
5471 if (session) {
5472 // We need to send transferable data to child process.
5473 nsTArray<IPCTransferableData> ipcTransferables;
5474 GetIPCTransferableData(session, aParent, ipcTransferables);
5475 uint32_t action;
5476 session->GetDragAction(&action);
5478 RefPtr<WindowContext> sourceWC;
5479 session->GetSourceWindowContext(getter_AddRefs(sourceWC));
5480 RefPtr<WindowContext> sourceTopWC;
5481 session->GetSourceTopWindowContext(getter_AddRefs(sourceTopWC));
5482 mozilla::Unused << SendInvokeDragSession(
5483 sourceWC, sourceTopWC, std::move(ipcTransferables), action);
5485 return;
5488 if (dragService->MustUpdateDataTransfer(aMessage)) {
5489 nsCOMPtr<nsIDragSession> session;
5490 dragService->GetCurrentSession(getter_AddRefs(session));
5491 if (session) {
5492 // We need to send transferable data to child process.
5493 nsTArray<IPCTransferableData> ipcTransferables;
5494 GetIPCTransferableData(session, aParent, ipcTransferables);
5495 mozilla::Unused << SendUpdateDragSession(std::move(ipcTransferables),
5496 aMessage);
5501 mozilla::ipc::IPCResult ContentParent::RecvUpdateDropEffect(
5502 const uint32_t& aDragAction, const uint32_t& aDropEffect) {
5503 nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
5504 if (dragSession) {
5505 dragSession->SetDragAction(aDragAction);
5506 RefPtr<DataTransfer> dt = dragSession->GetDataTransfer();
5507 if (dt) {
5508 dt->SetDropEffectInt(aDropEffect);
5510 dragSession->UpdateDragEffect();
5512 return IPC_OK();
5515 PContentPermissionRequestParent*
5516 ContentParent::AllocPContentPermissionRequestParent(
5517 const nsTArray<PermissionRequest>& aRequests, nsIPrincipal* aPrincipal,
5518 nsIPrincipal* aTopLevelPrincipal, const bool& aIsHandlingUserInput,
5519 const bool& aMaybeUnsafePermissionDelegate, const TabId& aTabId) {
5520 RefPtr<BrowserParent> tp;
5521 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
5522 if (cpm) {
5523 tp =
5524 cpm->GetTopLevelBrowserParentByProcessAndTabId(this->ChildID(), aTabId);
5526 if (!tp) {
5527 return nullptr;
5530 nsIPrincipal* topPrincipal = aTopLevelPrincipal;
5531 if (!topPrincipal) {
5532 nsCOMPtr<nsIPrincipal> principal = tp->GetContentPrincipal();
5533 topPrincipal = principal;
5535 return nsContentPermissionUtils::CreateContentPermissionRequestParent(
5536 aRequests, tp->GetOwnerElement(), aPrincipal, topPrincipal,
5537 aIsHandlingUserInput, aMaybeUnsafePermissionDelegate, aTabId);
5540 bool ContentParent::DeallocPContentPermissionRequestParent(
5541 PContentPermissionRequestParent* actor) {
5542 nsContentPermissionUtils::NotifyRemoveContentPermissionRequestParent(actor);
5543 delete actor;
5544 return true;
5547 already_AddRefed<PWebBrowserPersistDocumentParent>
5548 ContentParent::AllocPWebBrowserPersistDocumentParent(
5549 PBrowserParent* aBrowser, const MaybeDiscarded<BrowsingContext>& aContext) {
5550 return MakeAndAddRef<WebBrowserPersistDocumentParent>();
5553 mozilla::ipc::IPCResult ContentParent::CommonCreateWindow(
5554 PBrowserParent* aThisTab, BrowsingContext& aParent, bool aSetOpener,
5555 const uint32_t& aChromeFlags, const bool& aCalledFromJS,
5556 const bool& aForPrinting, const bool& aForWindowDotPrint,
5557 nsIURI* aURIToLoad, const nsACString& aFeatures,
5558 const UserActivation::Modifiers& aModifiers,
5559 BrowserParent* aNextRemoteBrowser, const nsAString& aName,
5560 nsresult& aResult, nsCOMPtr<nsIRemoteTab>& aNewRemoteTab,
5561 bool* aWindowIsNew, int32_t& aOpenLocation,
5562 nsIPrincipal* aTriggeringPrincipal, nsIReferrerInfo* aReferrerInfo,
5563 bool aLoadURI, nsIContentSecurityPolicy* aCsp,
5564 const OriginAttributes& aOriginAttributes) {
5565 // The content process should never be in charge of computing whether or
5566 // not a window should be private - the parent will do that.
5567 const uint32_t badFlags = nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW |
5568 nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW |
5569 nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME;
5570 if (!!(aChromeFlags & badFlags)) {
5571 return IPC_FAIL(this, "Forbidden aChromeFlags passed");
5574 RefPtr<nsOpenWindowInfo> openInfo = new nsOpenWindowInfo();
5575 openInfo->mForceNoOpener = !aSetOpener;
5576 openInfo->mParent = &aParent;
5577 openInfo->mIsRemote = true;
5578 openInfo->mIsForPrinting = aForPrinting;
5579 openInfo->mIsForWindowDotPrint = aForWindowDotPrint;
5580 openInfo->mNextRemoteBrowser = aNextRemoteBrowser;
5581 openInfo->mOriginAttributes = aOriginAttributes;
5583 MOZ_ASSERT_IF(aForWindowDotPrint, aForPrinting);
5585 RefPtr<BrowserParent> topParent = BrowserParent::GetFrom(aThisTab);
5586 while (topParent && topParent->GetBrowserBridgeParent()) {
5587 topParent = topParent->GetBrowserBridgeParent()->Manager();
5589 RefPtr<BrowserHost> thisBrowserHost =
5590 topParent ? topParent->GetBrowserHost() : nullptr;
5591 MOZ_ASSERT_IF(topParent, thisBrowserHost);
5592 RefPtr<BrowsingContext> topBC =
5593 topParent ? topParent->GetBrowsingContext() : nullptr;
5594 MOZ_ASSERT_IF(topParent, topBC);
5596 // The content process should have set its remote and fission flags correctly.
5597 if (topBC) {
5598 if ((!!(aChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) !=
5599 topBC->UseRemoteTabs()) ||
5600 (!!(aChromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW) !=
5601 topBC->UseRemoteSubframes())) {
5602 return IPC_FAIL(this, "Unexpected aChromeFlags passed");
5605 if (!aOriginAttributes.EqualsIgnoringFPD(topBC->OriginAttributesRef())) {
5606 return IPC_FAIL(this, "Passed-in OriginAttributes does not match opener");
5610 nsCOMPtr<nsIContent> frame;
5611 if (topParent) {
5612 frame = topParent->GetOwnerElement();
5615 nsCOMPtr<nsPIDOMWindowOuter> outerWin;
5616 if (frame) {
5617 outerWin = frame->OwnerDoc()->GetWindow();
5619 // If our chrome window is in the process of closing, don't try to open a
5620 // new tab in it.
5621 if (outerWin && outerWin->Closed()) {
5622 outerWin = nullptr;
5626 nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
5627 if (topParent) {
5628 browserDOMWin = topParent->GetBrowserDOMWindow();
5631 // If we haven't found a chrome window to open in, just use the most recently
5632 // opened one.
5633 if (!outerWin) {
5634 outerWin = nsContentUtils::GetMostRecentNonPBWindow();
5635 if (NS_WARN_IF(!outerWin)) {
5636 aResult = NS_ERROR_FAILURE;
5637 return IPC_OK();
5640 if (nsGlobalWindowOuter::Cast(outerWin)->IsChromeWindow()) {
5641 browserDOMWin =
5642 nsGlobalWindowOuter::Cast(outerWin)->GetBrowserDOMWindow();
5646 aOpenLocation = nsWindowWatcher::GetWindowOpenLocation(
5647 outerWin, aChromeFlags, aModifiers, aCalledFromJS, aForPrinting);
5649 MOZ_ASSERT(aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
5650 aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB_BACKGROUND ||
5651 aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWWINDOW ||
5652 aOpenLocation == nsIBrowserDOMWindow::OPEN_PRINT_BROWSER);
5654 if (NS_WARN_IF(!browserDOMWin)) {
5655 // Opening in the same window or headless requires an nsIBrowserDOMWindow.
5656 aOpenLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
5659 if (aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
5660 aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB_BACKGROUND ||
5661 aOpenLocation == nsIBrowserDOMWindow::OPEN_PRINT_BROWSER) {
5662 RefPtr<Element> openerElement = do_QueryObject(frame);
5664 nsCOMPtr<nsIOpenURIInFrameParams> params =
5665 new nsOpenURIInFrameParams(openInfo, openerElement);
5666 params->SetReferrerInfo(aReferrerInfo);
5667 MOZ_ASSERT(aTriggeringPrincipal, "need a valid triggeringPrincipal");
5668 params->SetTriggeringPrincipal(aTriggeringPrincipal);
5669 params->SetCsp(aCsp);
5671 RefPtr<Element> el;
5673 if (aLoadURI) {
5674 aResult = browserDOMWin->OpenURIInFrame(aURIToLoad, params, aOpenLocation,
5675 nsIBrowserDOMWindow::OPEN_NEW,
5676 aName, getter_AddRefs(el));
5677 } else {
5678 aResult = browserDOMWin->CreateContentWindowInFrame(
5679 aURIToLoad, params, aOpenLocation, nsIBrowserDOMWindow::OPEN_NEW,
5680 aName, getter_AddRefs(el));
5682 RefPtr<nsFrameLoaderOwner> frameLoaderOwner = do_QueryObject(el);
5683 if (NS_SUCCEEDED(aResult) && frameLoaderOwner) {
5684 RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
5685 if (frameLoader) {
5686 aNewRemoteTab = frameLoader->GetRemoteTab();
5687 // At this point, it's possible the inserted frameloader hasn't gone
5688 // through layout yet. To ensure that the dimensions that we send down
5689 // when telling the frameloader to display will be correct (instead of
5690 // falling back to a 10x10 default), we force layout if necessary to get
5691 // the most up-to-date dimensions. See bug 1358712 for details.
5692 frameLoader->ForceLayoutIfNecessary();
5694 } else if (NS_SUCCEEDED(aResult) && !frameLoaderOwner) {
5695 // Fall through to the normal window opening code path when there is no
5696 // window which we can open a new tab in.
5697 aOpenLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
5698 } else {
5699 *aWindowIsNew = false;
5702 // If we didn't retarget our window open into a new window, we should return
5703 // now.
5704 if (aOpenLocation != nsIBrowserDOMWindow::OPEN_NEWWINDOW) {
5705 return IPC_OK();
5709 nsCOMPtr<nsPIWindowWatcher> pwwatch =
5710 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &aResult);
5711 if (NS_WARN_IF(NS_FAILED(aResult))) {
5712 return IPC_OK();
5715 WindowFeatures features;
5716 features.Tokenize(aFeatures);
5718 aResult = pwwatch->OpenWindowWithRemoteTab(
5719 thisBrowserHost, features, aModifiers, aCalledFromJS, aParent.FullZoom(),
5720 openInfo, getter_AddRefs(aNewRemoteTab));
5721 if (NS_WARN_IF(NS_FAILED(aResult))) {
5722 return IPC_OK();
5725 MOZ_ASSERT(aNewRemoteTab);
5726 RefPtr<BrowserHost> newBrowserHost = BrowserHost::GetFrom(aNewRemoteTab);
5727 RefPtr<BrowserParent> newBrowserParent = newBrowserHost->GetActor();
5729 // At this point, it's possible the inserted frameloader hasn't gone through
5730 // layout yet. To ensure that the dimensions that we send down when telling
5731 // the frameloader to display will be correct (instead of falling back to a
5732 // 10x10 default), we force layout if necessary to get the most up-to-date
5733 // dimensions. See bug 1358712 for details.
5734 nsCOMPtr<Element> frameElement = newBrowserHost->GetOwnerElement();
5735 MOZ_ASSERT(frameElement);
5736 if (nsWindowWatcher::HaveSpecifiedSize(features)) {
5737 // We want to flush the layout anyway because of the resize to the specified
5738 // size. (Bug 1793605).
5739 RefPtr<Document> chromeDoc = frameElement->OwnerDoc();
5740 MOZ_ASSERT(chromeDoc);
5741 chromeDoc->FlushPendingNotifications(FlushType::Layout);
5742 } else {
5743 RefPtr<nsFrameLoaderOwner> frameLoaderOwner = do_QueryObject(frameElement);
5744 MOZ_ASSERT(frameLoaderOwner);
5745 RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
5746 MOZ_ASSERT(frameLoader);
5747 frameLoader->ForceLayoutIfNecessary();
5750 // If we were passed a name for the window which would override the default,
5751 // we should send it down to the new tab.
5752 if (nsContentUtils::IsOverridingWindowName(aName)) {
5753 MOZ_ALWAYS_SUCCEEDS(newBrowserHost->GetBrowsingContext()->SetName(aName));
5756 MOZ_ASSERT(newBrowserHost->GetBrowsingContext()->OriginAttributesRef() ==
5757 aOriginAttributes);
5759 if (aURIToLoad && aLoadURI) {
5760 nsCOMPtr<mozIDOMWindowProxy> openerWindow;
5761 if (aSetOpener && topParent) {
5762 openerWindow = topParent->GetParentWindowOuter();
5764 nsCOMPtr<nsIBrowserDOMWindow> newBrowserDOMWin =
5765 newBrowserParent->GetBrowserDOMWindow();
5766 if (NS_WARN_IF(!newBrowserDOMWin)) {
5767 aResult = NS_ERROR_ABORT;
5768 return IPC_OK();
5770 RefPtr<BrowsingContext> bc;
5771 aResult = newBrowserDOMWin->OpenURI(
5772 aURIToLoad, openInfo, nsIBrowserDOMWindow::OPEN_CURRENTWINDOW,
5773 nsIBrowserDOMWindow::OPEN_NEW, aTriggeringPrincipal, aCsp,
5774 getter_AddRefs(bc));
5777 return IPC_OK();
5780 mozilla::ipc::IPCResult ContentParent::RecvCreateWindow(
5781 PBrowserParent* aThisTab, const MaybeDiscarded<BrowsingContext>& aParent,
5782 PBrowserParent* aNewTab, const uint32_t& aChromeFlags,
5783 const bool& aCalledFromJS, const bool& aForPrinting,
5784 const bool& aForPrintPreview, nsIURI* aURIToLoad,
5785 const nsACString& aFeatures, const UserActivation::Modifiers& aModifiers,
5786 nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp,
5787 nsIReferrerInfo* aReferrerInfo, const OriginAttributes& aOriginAttributes,
5788 CreateWindowResolver&& aResolve) {
5789 if (!aTriggeringPrincipal) {
5790 return IPC_FAIL(this, "No principal");
5793 if (!ValidatePrincipal(aTriggeringPrincipal)) {
5794 LogAndAssertFailedPrincipalValidationInfo(aTriggeringPrincipal, __func__);
5797 nsresult rv = NS_OK;
5798 CreatedWindowInfo cwi;
5800 // We always expect to open a new window here. If we don't, it's an error.
5801 cwi.windowOpened() = true;
5802 cwi.maxTouchPoints() = 0;
5804 // Make sure to resolve the resolver when this function exits, even if we
5805 // failed to generate a valid response.
5806 auto resolveOnExit = MakeScopeExit([&] {
5807 // Copy over the nsresult, and then resolve.
5808 cwi.rv() = rv;
5809 aResolve(cwi);
5812 RefPtr<BrowserParent> thisTab = BrowserParent::GetFrom(aThisTab);
5813 RefPtr<BrowserParent> newTab = BrowserParent::GetFrom(aNewTab);
5814 MOZ_ASSERT(newTab);
5816 auto destroyNewTabOnError = MakeScopeExit([&] {
5817 // We always expect to open a new window here. If we don't, it's an error.
5818 if (!cwi.windowOpened() || NS_FAILED(rv)) {
5819 if (newTab) {
5820 newTab->Destroy();
5825 // Don't continue to try to create a new window if we've been fully discarded.
5826 RefPtr<BrowsingContext> parent = aParent.GetMaybeDiscarded();
5827 if (NS_WARN_IF(!parent)) {
5828 rv = NS_ERROR_FAILURE;
5829 return IPC_OK();
5832 // Validate that our new BrowsingContext looks as we would expect it.
5833 RefPtr<BrowsingContext> newBC = newTab->GetBrowsingContext();
5834 if (!newBC) {
5835 return IPC_FAIL(this, "Missing BrowsingContext for new tab");
5838 uint64_t newBCOpenerId = newBC->GetOpenerId();
5839 if (newBCOpenerId != 0 && parent->Id() != newBCOpenerId) {
5840 return IPC_FAIL(this, "Invalid opener BrowsingContext for new tab");
5842 if (newBC->GetParent() != nullptr) {
5843 return IPC_FAIL(this,
5844 "Unexpected non-toplevel BrowsingContext for new tab");
5846 if (!!(aChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) !=
5847 newBC->UseRemoteTabs() ||
5848 !!(aChromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW) !=
5849 newBC->UseRemoteSubframes()) {
5850 return IPC_FAIL(this, "Unexpected aChromeFlags passed");
5852 if (!aOriginAttributes.EqualsIgnoringFPD(newBC->OriginAttributesRef())) {
5853 return IPC_FAIL(this, "Opened tab has mismatched OriginAttributes");
5856 if (thisTab && BrowserParent::GetFrom(thisTab)->GetBrowsingContext()) {
5857 BrowsingContext* thisTabBC = thisTab->GetBrowsingContext();
5858 if (thisTabBC->UseRemoteTabs() != newBC->UseRemoteTabs() ||
5859 thisTabBC->UseRemoteSubframes() != newBC->UseRemoteSubframes() ||
5860 thisTabBC->UsePrivateBrowsing() != newBC->UsePrivateBrowsing()) {
5861 return IPC_FAIL(this, "New BrowsingContext has mismatched LoadContext");
5864 BrowserParent::AutoUseNewTab aunt(newTab);
5866 nsCOMPtr<nsIRemoteTab> newRemoteTab;
5867 int32_t openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
5868 mozilla::ipc::IPCResult ipcResult = CommonCreateWindow(
5869 aThisTab, *parent, newBCOpenerId != 0, aChromeFlags, aCalledFromJS,
5870 aForPrinting, aForPrintPreview, aURIToLoad, aFeatures, aModifiers, newTab,
5871 VoidString(), rv, newRemoteTab, &cwi.windowOpened(), openLocation,
5872 aTriggeringPrincipal, aReferrerInfo, /* aLoadUri = */ false, aCsp,
5873 aOriginAttributes);
5874 if (!ipcResult) {
5875 return ipcResult;
5878 if (NS_WARN_IF(NS_FAILED(rv)) || !newRemoteTab) {
5879 return IPC_OK();
5882 MOZ_ASSERT(BrowserHost::GetFrom(newRemoteTab.get()) ==
5883 newTab->GetBrowserHost());
5885 // This used to happen in the child - there may now be a better place to
5886 // do this work.
5887 MOZ_ALWAYS_SUCCEEDS(newBC->SetHasSiblings(
5888 openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
5889 openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB_BACKGROUND));
5891 newTab->SwapFrameScriptsFrom(cwi.frameScripts());
5892 newTab->MaybeShowFrame();
5894 nsCOMPtr<nsIWidget> widget = newTab->GetWidget();
5895 if (widget) {
5896 cwi.dimensions() = newTab->GetDimensionInfo();
5899 cwi.maxTouchPoints() = newTab->GetMaxTouchPoints();
5901 return IPC_OK();
5904 mozilla::ipc::IPCResult ContentParent::RecvCreateWindowInDifferentProcess(
5905 PBrowserParent* aThisTab, const MaybeDiscarded<BrowsingContext>& aParent,
5906 const uint32_t& aChromeFlags, const bool& aCalledFromJS, nsIURI* aURIToLoad,
5907 const nsACString& aFeatures, const UserActivation::Modifiers& aModifiers,
5908 const nsAString& aName, nsIPrincipal* aTriggeringPrincipal,
5909 nsIContentSecurityPolicy* aCsp, nsIReferrerInfo* aReferrerInfo,
5910 const OriginAttributes& aOriginAttributes) {
5911 MOZ_DIAGNOSTIC_ASSERT(!nsContentUtils::IsSpecialName(aName));
5913 // Don't continue to try to create a new window if we've been fully discarded.
5914 RefPtr<BrowsingContext> parent = aParent.GetMaybeDiscarded();
5915 if (NS_WARN_IF(!parent)) {
5916 return IPC_OK();
5919 nsCOMPtr<nsIRemoteTab> newRemoteTab;
5920 bool windowIsNew;
5921 int32_t openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
5923 // If we have enough data, check the schemes of the loader and loadee
5924 // to make sure they make sense.
5925 if (aURIToLoad && aURIToLoad->SchemeIs("file") &&
5926 GetRemoteType() != FILE_REMOTE_TYPE &&
5927 Preferences::GetBool("browser.tabs.remote.enforceRemoteTypeRestrictions",
5928 false)) {
5929 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
5930 # ifdef DEBUG
5931 nsAutoCString uriToLoadStr;
5932 nsAutoCString triggeringUriStr;
5933 aURIToLoad->GetAsciiSpec(uriToLoadStr);
5934 aTriggeringPrincipal->GetAsciiSpec(triggeringUriStr);
5936 NS_WARNING(nsPrintfCString(
5937 "RecvCreateWindowInDifferentProcess blocked loading file "
5938 "scheme from non-file remotetype: %s tried to load %s",
5939 triggeringUriStr.get(), uriToLoadStr.get())
5940 .get());
5941 # endif
5942 MOZ_CRASH(
5943 "RecvCreateWindowInDifferentProcess blocked loading improper scheme");
5944 #endif
5945 return IPC_OK();
5948 nsresult rv;
5949 mozilla::ipc::IPCResult ipcResult = CommonCreateWindow(
5950 aThisTab, *parent, /* aSetOpener = */ false, aChromeFlags, aCalledFromJS,
5951 /* aForPrinting = */ false,
5952 /* aForPrintPreview = */ false, aURIToLoad, aFeatures, aModifiers,
5953 /* aNextRemoteBrowser = */ nullptr, aName, rv, newRemoteTab, &windowIsNew,
5954 openLocation, aTriggeringPrincipal, aReferrerInfo,
5955 /* aLoadUri = */ true, aCsp, aOriginAttributes);
5956 if (!ipcResult) {
5957 return ipcResult;
5960 if (NS_FAILED(rv)) {
5961 NS_WARNING("Call to CommonCreateWindow failed.");
5964 return IPC_OK();
5967 mozilla::ipc::IPCResult ContentParent::RecvShutdownProfile(
5968 const nsACString& aProfile) {
5969 profiler_received_exit_profile(aProfile);
5970 return IPC_OK();
5973 mozilla::ipc::IPCResult ContentParent::RecvShutdownPerfStats(
5974 const nsACString& aPerfStats) {
5975 PerfStats::StorePerfStats(this, aPerfStats);
5976 return IPC_OK();
5979 mozilla::ipc::IPCResult ContentParent::RecvGetFontListShmBlock(
5980 const uint32_t& aGeneration, const uint32_t& aIndex,
5981 base::SharedMemoryHandle* aOut) {
5982 auto* fontList = gfxPlatformFontList::PlatformFontList();
5983 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
5984 fontList->ShareFontListShmBlockToProcess(aGeneration, aIndex, Pid(), aOut);
5985 return IPC_OK();
5988 mozilla::ipc::IPCResult ContentParent::RecvInitializeFamily(
5989 const uint32_t& aGeneration, const uint32_t& aFamilyIndex,
5990 const bool& aLoadCmaps) {
5991 auto* fontList = gfxPlatformFontList::PlatformFontList();
5992 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
5993 fontList->InitializeFamily(aGeneration, aFamilyIndex, aLoadCmaps);
5994 return IPC_OK();
5997 mozilla::ipc::IPCResult ContentParent::RecvSetCharacterMap(
5998 const uint32_t& aGeneration, const uint32_t& aFamilyIndex,
5999 const bool& aAlias, const uint32_t& aFaceIndex,
6000 const gfxSparseBitSet& aMap) {
6001 auto* fontList = gfxPlatformFontList::PlatformFontList();
6002 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
6003 fontList->SetCharacterMap(aGeneration, aFamilyIndex, aAlias, aFaceIndex,
6004 aMap);
6005 return IPC_OK();
6008 mozilla::ipc::IPCResult ContentParent::RecvInitOtherFamilyNames(
6009 const uint32_t& aGeneration, const bool& aDefer, bool* aLoaded) {
6010 auto* fontList = gfxPlatformFontList::PlatformFontList();
6011 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
6012 *aLoaded = fontList->InitOtherFamilyNames(aGeneration, aDefer);
6013 return IPC_OK();
6016 mozilla::ipc::IPCResult ContentParent::RecvSetupFamilyCharMap(
6017 const uint32_t& aGeneration, const uint32_t& aIndex, const bool& aAlias) {
6018 auto* fontList = gfxPlatformFontList::PlatformFontList();
6019 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
6020 fontList->SetupFamilyCharMap(aGeneration, aIndex, aAlias);
6021 return IPC_OK();
6024 mozilla::ipc::IPCResult ContentParent::RecvStartCmapLoading(
6025 const uint32_t& aGeneration, const uint32_t& aStartIndex) {
6026 auto* fontList = gfxPlatformFontList::PlatformFontList();
6027 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
6028 fontList->StartCmapLoading(aGeneration, aStartIndex);
6029 return IPC_OK();
6032 mozilla::ipc::IPCResult ContentParent::RecvGetHyphDict(
6033 nsIURI* aURI, base::SharedMemoryHandle* aOutHandle, uint32_t* aOutSize) {
6034 if (!aURI) {
6035 return IPC_FAIL(this, "aURI must not be null.");
6037 nsHyphenationManager::Instance()->ShareHyphDictToProcess(
6038 aURI, Pid(), aOutHandle, aOutSize);
6039 return IPC_OK();
6042 mozilla::ipc::IPCResult ContentParent::RecvGraphicsError(
6043 const nsACString& aError) {
6044 if (gfx::LogForwarder* lf = gfx::Factory::GetLogForwarder()) {
6045 std::stringstream message;
6046 message << "CP+" << aError;
6047 lf->UpdateStringsVector(message.str());
6049 return IPC_OK();
6052 mozilla::ipc::IPCResult ContentParent::RecvBeginDriverCrashGuard(
6053 const uint32_t& aGuardType, bool* aOutCrashed) {
6054 // Only one driver crash guard should be active at a time, per-process.
6055 MOZ_ASSERT(!mDriverCrashGuard);
6057 UniquePtr<gfx::DriverCrashGuard> guard;
6058 switch (gfx::CrashGuardType(aGuardType)) {
6059 case gfx::CrashGuardType::D3D11Layers:
6060 guard = MakeUnique<gfx::D3D11LayersCrashGuard>(this);
6061 break;
6062 case gfx::CrashGuardType::GLContext:
6063 guard = MakeUnique<gfx::GLContextCrashGuard>(this);
6064 break;
6065 case gfx::CrashGuardType::WMFVPXVideo:
6066 guard = MakeUnique<gfx::WMFVPXVideoCrashGuard>(this);
6067 break;
6068 default:
6069 return IPC_FAIL(this, "unknown crash guard type");
6072 if (guard->Crashed()) {
6073 *aOutCrashed = true;
6074 return IPC_OK();
6077 *aOutCrashed = false;
6078 mDriverCrashGuard = std::move(guard);
6079 return IPC_OK();
6082 mozilla::ipc::IPCResult ContentParent::RecvEndDriverCrashGuard(
6083 const uint32_t& aGuardType) {
6084 mDriverCrashGuard = nullptr;
6085 return IPC_OK();
6088 mozilla::ipc::IPCResult ContentParent::RecvNotifyBenchmarkResult(
6089 const nsAString& aCodecName, const uint32_t& aDecodeFPS)
6092 if (aCodecName.EqualsLiteral("VP9")) {
6093 Preferences::SetUint(VP9Benchmark::sBenchmarkFpsPref, aDecodeFPS);
6094 Preferences::SetUint(VP9Benchmark::sBenchmarkFpsVersionCheck,
6095 VP9Benchmark::sBenchmarkVersionID);
6097 return IPC_OK();
6100 mozilla::ipc::IPCResult ContentParent::RecvNotifyPushObservers(
6101 const nsACString& aScope, nsIPrincipal* aPrincipal,
6102 const nsAString& aMessageId) {
6103 if (!aPrincipal) {
6104 return IPC_FAIL(this, "No principal");
6107 if (!ValidatePrincipal(aPrincipal)) {
6108 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
6110 PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId, Nothing());
6111 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
6112 return IPC_OK();
6115 mozilla::ipc::IPCResult ContentParent::RecvNotifyPushObserversWithData(
6116 const nsACString& aScope, nsIPrincipal* aPrincipal,
6117 const nsAString& aMessageId, nsTArray<uint8_t>&& aData) {
6118 if (!aPrincipal) {
6119 return IPC_FAIL(this, "No principal");
6122 if (!ValidatePrincipal(aPrincipal)) {
6123 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
6125 PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId,
6126 Some(std::move(aData)));
6127 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
6128 return IPC_OK();
6131 mozilla::ipc::IPCResult
6132 ContentParent::RecvNotifyPushSubscriptionChangeObservers(
6133 const nsACString& aScope, nsIPrincipal* aPrincipal) {
6134 if (!aPrincipal) {
6135 return IPC_FAIL(this, "No principal");
6138 if (!ValidatePrincipal(aPrincipal)) {
6139 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
6141 PushSubscriptionChangeDispatcher dispatcher(aScope, aPrincipal);
6142 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
6143 return IPC_OK();
6146 mozilla::ipc::IPCResult ContentParent::RecvPushError(const nsACString& aScope,
6147 nsIPrincipal* aPrincipal,
6148 const nsAString& aMessage,
6149 const uint32_t& aFlags) {
6150 if (!aPrincipal) {
6151 return IPC_FAIL(this, "No principal");
6154 if (!ValidatePrincipal(aPrincipal)) {
6155 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
6157 PushErrorDispatcher dispatcher(aScope, aPrincipal, aMessage, aFlags);
6158 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
6159 return IPC_OK();
6162 mozilla::ipc::IPCResult
6163 ContentParent::RecvNotifyPushSubscriptionModifiedObservers(
6164 const nsACString& aScope, nsIPrincipal* aPrincipal) {
6165 if (!aPrincipal) {
6166 return IPC_FAIL(this, "No principal");
6169 if (!ValidatePrincipal(aPrincipal)) {
6170 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
6172 PushSubscriptionModifiedDispatcher dispatcher(aScope, aPrincipal);
6173 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers()));
6174 return IPC_OK();
6177 /* static */
6178 void ContentParent::BroadcastBlobURLRegistration(const nsACString& aURI,
6179 BlobImpl* aBlobImpl,
6180 nsIPrincipal* aPrincipal,
6181 const nsCString& aPartitionKey,
6182 ContentParent* aIgnoreThisCP) {
6183 uint64_t originHash = ComputeLoadedOriginHash(aPrincipal);
6185 bool toBeSent =
6186 BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal);
6188 nsCString uri(aURI);
6190 for (auto* cp : AllProcesses(eLive)) {
6191 if (cp != aIgnoreThisCP) {
6192 if (!toBeSent && !cp->mLoadedOriginHashes.Contains(originHash)) {
6193 continue;
6196 nsresult rv = cp->TransmitPermissionsForPrincipal(aPrincipal);
6197 if (NS_WARN_IF(NS_FAILED(rv))) {
6198 break;
6201 IPCBlob ipcBlob;
6202 rv = IPCBlobUtils::Serialize(aBlobImpl, ipcBlob);
6203 if (NS_WARN_IF(NS_FAILED(rv))) {
6204 break;
6207 Unused << cp->SendBlobURLRegistration(uri, ipcBlob, aPrincipal,
6208 aPartitionKey);
6213 /* static */
6214 void ContentParent::BroadcastBlobURLUnregistration(
6215 const nsACString& aURI, nsIPrincipal* aPrincipal,
6216 ContentParent* aIgnoreThisCP) {
6217 uint64_t originHash = ComputeLoadedOriginHash(aPrincipal);
6219 bool toBeSent =
6220 BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal);
6222 nsCString uri(aURI);
6224 for (auto* cp : AllProcesses(eLive)) {
6225 if (cp != aIgnoreThisCP &&
6226 (toBeSent || cp->mLoadedOriginHashes.Contains(originHash))) {
6227 Unused << cp->SendBlobURLUnregistration(uri);
6232 mozilla::ipc::IPCResult ContentParent::RecvStoreAndBroadcastBlobURLRegistration(
6233 const nsACString& aURI, const IPCBlob& aBlob, nsIPrincipal* aPrincipal,
6234 const nsCString& aPartitionKey) {
6235 if (!aPrincipal) {
6236 return IPC_FAIL(this, "No principal");
6239 if (!ValidatePrincipal(aPrincipal, {ValidatePrincipalOptions::AllowSystem})) {
6240 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
6242 RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(aBlob);
6243 if (NS_WARN_IF(!blobImpl)) {
6244 return IPC_FAIL(this, "Blob deserialization failed.");
6247 BlobURLProtocolHandler::AddDataEntry(aURI, aPrincipal, aPartitionKey,
6248 blobImpl);
6249 BroadcastBlobURLRegistration(aURI, blobImpl, aPrincipal, aPartitionKey, this);
6251 // We want to store this blobURL, so we can unregister it if the child
6252 // crashes.
6253 mBlobURLs.AppendElement(aURI);
6255 return IPC_OK();
6258 mozilla::ipc::IPCResult
6259 ContentParent::RecvUnstoreAndBroadcastBlobURLUnregistration(
6260 const nsACString& aURI, nsIPrincipal* aPrincipal) {
6261 if (!aPrincipal) {
6262 return IPC_FAIL(this, "No principal");
6265 if (!ValidatePrincipal(aPrincipal, {ValidatePrincipalOptions::AllowSystem})) {
6266 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
6268 BlobURLProtocolHandler::RemoveDataEntry(aURI, false /* Don't broadcast */);
6269 BroadcastBlobURLUnregistration(aURI, aPrincipal, this);
6270 mBlobURLs.RemoveElement(aURI);
6271 return IPC_OK();
6274 mozilla::ipc::IPCResult ContentParent::RecvGetFilesRequest(
6275 const nsID& aUUID, const nsAString& aDirectoryPath,
6276 const bool& aRecursiveFlag) {
6277 MOZ_ASSERT(!mGetFilesPendingRequests.GetWeak(aUUID));
6279 if (!mozilla::Preferences::GetBool("dom.filesystem.pathcheck.disabled",
6280 false)) {
6281 RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get();
6282 if (!fss) {
6283 return IPC_FAIL(this, "Failed to get FileSystemSecurity.");
6286 if (!fss->ContentProcessHasAccessTo(ChildID(), aDirectoryPath)) {
6287 return IPC_FAIL(this, "ContentProcessHasAccessTo failed.");
6291 ErrorResult rv;
6292 RefPtr<GetFilesHelper> helper = GetFilesHelperParent::Create(
6293 aUUID, aDirectoryPath, aRecursiveFlag, this, rv);
6295 if (NS_WARN_IF(rv.Failed())) {
6296 if (!SendGetFilesResponse(aUUID,
6297 GetFilesResponseFailure(rv.StealNSResult()))) {
6298 return IPC_FAIL(this, "SendGetFilesResponse failed.");
6300 return IPC_OK();
6303 mGetFilesPendingRequests.InsertOrUpdate(aUUID, std::move(helper));
6304 return IPC_OK();
6307 mozilla::ipc::IPCResult ContentParent::RecvDeleteGetFilesRequest(
6308 const nsID& aUUID) {
6309 mGetFilesPendingRequests.Remove(aUUID);
6310 return IPC_OK();
6313 void ContentParent::SendGetFilesResponseAndForget(
6314 const nsID& aUUID, const GetFilesResponseResult& aResult) {
6315 if (mGetFilesPendingRequests.Remove(aUUID)) {
6316 Unused << SendGetFilesResponse(aUUID, aResult);
6320 void ContentParent::PaintTabWhileInterruptingJS(BrowserParent* aBrowserParent) {
6321 if (!mHangMonitorActor) {
6322 return;
6324 ProcessHangMonitor::PaintWhileInterruptingJS(mHangMonitorActor,
6325 aBrowserParent);
6328 void ContentParent::UnloadLayersWhileInterruptingJS(
6329 BrowserParent* aBrowserParent) {
6330 if (!mHangMonitorActor) {
6331 return;
6333 ProcessHangMonitor::UnloadLayersWhileInterruptingJS(mHangMonitorActor,
6334 aBrowserParent);
6337 void ContentParent::CancelContentJSExecutionIfRunning(
6338 BrowserParent* aBrowserParent, nsIRemoteTab::NavigationType aNavigationType,
6339 const CancelContentJSOptions& aCancelContentJSOptions) {
6340 if (!mHangMonitorActor) {
6341 return;
6344 ProcessHangMonitor::CancelContentJSExecutionIfRunning(
6345 mHangMonitorActor, aBrowserParent, aNavigationType,
6346 aCancelContentJSOptions);
6349 void ContentParent::SetMainThreadQoSPriority(
6350 nsIThread::QoSPriority aQoSPriority) {
6351 if (!mHangMonitorActor) {
6352 return;
6355 ProcessHangMonitor::SetMainThreadQoSPriority(mHangMonitorActor, aQoSPriority);
6358 void ContentParent::UpdateCookieStatus(nsIChannel* aChannel) {
6359 PNeckoParent* neckoParent = LoneManagedOrNullAsserts(ManagedPNeckoParent());
6360 PCookieServiceParent* csParent =
6361 LoneManagedOrNullAsserts(neckoParent->ManagedPCookieServiceParent());
6362 if (csParent) {
6363 auto* cs = static_cast<CookieServiceParent*>(csParent);
6364 cs->TrackCookieLoad(aChannel);
6368 nsresult ContentParent::AboutToLoadHttpDocumentForChild(
6369 nsIChannel* aChannel, bool* aShouldWaitForPermissionCookieUpdate) {
6370 MOZ_ASSERT(aChannel);
6372 if (aShouldWaitForPermissionCookieUpdate) {
6373 *aShouldWaitForPermissionCookieUpdate = false;
6376 nsresult rv;
6377 bool isDocument = aChannel->IsDocument();
6378 if (!isDocument) {
6379 // We may be looking at a nsIHttpChannel which has isMainDocumentChannel set
6380 // (e.g. the internal http channel for a view-source: load.).
6381 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
6382 if (httpChannel) {
6383 rv = httpChannel->GetIsMainDocumentChannel(&isDocument);
6384 NS_ENSURE_SUCCESS(rv, rv);
6387 if (!isDocument) {
6388 return NS_OK;
6391 // Get the principal for the channel result, so that we can get the permission
6392 // key for the document which will be created from this response.
6393 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
6394 if (NS_WARN_IF(!ssm)) {
6395 return NS_ERROR_FAILURE;
6398 nsCOMPtr<nsIPrincipal> principal;
6399 nsCOMPtr<nsIPrincipal> partitionedPrincipal;
6400 rv = ssm->GetChannelResultPrincipals(aChannel, getter_AddRefs(principal),
6401 getter_AddRefs(partitionedPrincipal));
6402 NS_ENSURE_SUCCESS(rv, rv);
6404 // Let the caller know we're going to send main thread IPC for updating
6405 // permisssions/cookies.
6406 if (aShouldWaitForPermissionCookieUpdate) {
6407 *aShouldWaitForPermissionCookieUpdate = true;
6410 TransmitBlobURLsForPrincipal(principal);
6412 // Tranmit permissions for both regular and partitioned principal so that the
6413 // content process can get permissions for the partitioned principal. For
6414 // example, the desk-notification permission for a partitioned service worker.
6415 rv = TransmitPermissionsForPrincipal(principal);
6416 NS_ENSURE_SUCCESS(rv, rv);
6418 rv = TransmitPermissionsForPrincipal(partitionedPrincipal);
6419 NS_ENSURE_SUCCESS(rv, rv);
6421 nsLoadFlags newLoadFlags;
6422 aChannel->GetLoadFlags(&newLoadFlags);
6423 if (newLoadFlags & nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE) {
6424 UpdateCookieStatus(aChannel);
6427 RefPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
6428 RefPtr<BrowsingContext> browsingContext;
6429 rv = loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext));
6430 NS_ENSURE_SUCCESS(rv, rv);
6432 if (!NextGenLocalStorageEnabled()) {
6433 return NS_OK;
6436 if (principal->GetIsContentPrincipal()) {
6437 nsCOMPtr<nsILocalStorageManager> lsm =
6438 do_GetService("@mozilla.org/dom/localStorage-manager;1");
6439 if (NS_WARN_IF(!lsm)) {
6440 return NS_ERROR_FAILURE;
6443 nsCOMPtr<nsIPrincipal> storagePrincipal;
6444 rv = ssm->GetChannelResultStoragePrincipal(
6445 aChannel, getter_AddRefs(storagePrincipal));
6446 NS_ENSURE_SUCCESS(rv, rv);
6448 RefPtr<Promise> dummy;
6449 rv = lsm->Preload(storagePrincipal, nullptr, getter_AddRefs(dummy));
6450 if (NS_FAILED(rv)) {
6451 NS_WARNING("Failed to preload local storage!");
6455 return NS_OK;
6458 nsresult ContentParent::TransmitPermissionsForPrincipal(
6459 nsIPrincipal* aPrincipal) {
6460 // Create the key, and send it down to the content process.
6461 nsTArray<std::pair<nsCString, nsCString>> pairs =
6462 PermissionManager::GetAllKeysForPrincipal(aPrincipal);
6463 MOZ_ASSERT(pairs.Length() >= 1);
6464 for (auto& pair : pairs) {
6465 EnsurePermissionsByKey(pair.first, pair.second);
6468 // We need to add the Site to the secondary keys of interest here.
6469 // This allows site-scoped permission updates to propogate when the
6470 // port is non-standard.
6471 nsAutoCString siteKey;
6472 nsresult rv =
6473 PermissionManager::GetKeyForPrincipal(aPrincipal, false, true, siteKey);
6474 if (NS_SUCCEEDED(rv) && !siteKey.IsEmpty()) {
6475 mActiveSecondaryPermissionKeys.EnsureInserted(siteKey);
6478 return NS_OK;
6481 void ContentParent::TransmitBlobURLsForPrincipal(nsIPrincipal* aPrincipal) {
6482 // If we're already broadcasting BlobURLs with this principal, we don't need
6483 // to send them here.
6484 if (BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal)) {
6485 return;
6488 // We shouldn't have any Blob URLs with expanded principals, so transmit URLs
6489 // for each principal in the AllowList instead.
6490 if (nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(aPrincipal)) {
6491 for (const auto& prin : ep->AllowList()) {
6492 TransmitBlobURLsForPrincipal(prin);
6494 return;
6497 uint64_t originHash = ComputeLoadedOriginHash(aPrincipal);
6499 if (!mLoadedOriginHashes.Contains(originHash)) {
6500 mLoadedOriginHashes.AppendElement(originHash);
6502 nsTArray<BlobURLRegistrationData> registrations;
6503 BlobURLProtocolHandler::ForEachBlobURL(
6504 [&](BlobImpl* aBlobImpl, nsIPrincipal* aBlobPrincipal,
6505 const nsCString& aPartitionKey, const nsACString& aURI,
6506 bool aRevoked) {
6507 // This check uses `ComputeLoadedOriginHash` to compare, rather than
6508 // doing the more accurate `Equals` check, as it needs to match the
6509 // behaviour of the logic to broadcast new registrations.
6510 if (originHash != ComputeLoadedOriginHash(aBlobPrincipal)) {
6511 return true;
6514 IPCBlob ipcBlob;
6515 nsresult rv = IPCBlobUtils::Serialize(aBlobImpl, ipcBlob);
6516 if (NS_WARN_IF(NS_FAILED(rv))) {
6517 return false;
6520 registrations.AppendElement(
6521 BlobURLRegistrationData(nsCString(aURI), ipcBlob, aPrincipal,
6522 nsCString(aPartitionKey), aRevoked));
6524 rv = TransmitPermissionsForPrincipal(aBlobPrincipal);
6525 Unused << NS_WARN_IF(NS_FAILED(rv));
6526 return true;
6529 if (!registrations.IsEmpty()) {
6530 Unused << SendInitBlobURLs(registrations);
6535 void ContentParent::TransmitBlobDataIfBlobURL(nsIURI* aURI) {
6536 MOZ_ASSERT(aURI);
6538 nsCOMPtr<nsIPrincipal> principal;
6539 if (BlobURLProtocolHandler::GetBlobURLPrincipal(aURI,
6540 getter_AddRefs(principal))) {
6541 TransmitBlobURLsForPrincipal(principal);
6545 void ContentParent::EnsurePermissionsByKey(const nsACString& aKey,
6546 const nsACString& aOrigin) {
6547 // NOTE: Make sure to initialize the permission manager before updating the
6548 // mActivePermissionKeys list. If the permission manager is being initialized
6549 // by this call to GetPermissionManager, and we've added the key to
6550 // mActivePermissionKeys, then the permission manager will send down a
6551 // SendAddPermission before receiving the SendSetPermissionsWithKey message.
6552 RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
6553 if (!permManager) {
6554 return;
6557 if (!mActivePermissionKeys.EnsureInserted(aKey)) {
6558 return;
6561 nsTArray<IPC::Permission> perms;
6562 if (permManager->GetPermissionsFromOriginOrKey(aOrigin, aKey, perms)) {
6563 Unused << SendSetPermissionsWithKey(aKey, perms);
6567 bool ContentParent::NeedsPermissionsUpdate(
6568 const nsACString& aPermissionKey) const {
6569 return mActivePermissionKeys.Contains(aPermissionKey);
6572 bool ContentParent::NeedsSecondaryKeyPermissionsUpdate(
6573 const nsACString& aPermissionKey) const {
6574 return mActiveSecondaryPermissionKeys.Contains(aPermissionKey);
6577 mozilla::ipc::IPCResult ContentParent::RecvAccumulateChildHistograms(
6578 nsTArray<HistogramAccumulation>&& aAccumulations) {
6579 TelemetryIPC::AccumulateChildHistograms(GetTelemetryProcessID(mRemoteType),
6580 aAccumulations);
6581 return IPC_OK();
6584 mozilla::ipc::IPCResult ContentParent::RecvAccumulateChildKeyedHistograms(
6585 nsTArray<KeyedHistogramAccumulation>&& aAccumulations) {
6586 TelemetryIPC::AccumulateChildKeyedHistograms(
6587 GetTelemetryProcessID(mRemoteType), aAccumulations);
6588 return IPC_OK();
6591 mozilla::ipc::IPCResult ContentParent::RecvUpdateChildScalars(
6592 nsTArray<ScalarAction>&& aScalarActions) {
6593 TelemetryIPC::UpdateChildScalars(GetTelemetryProcessID(mRemoteType),
6594 aScalarActions);
6595 return IPC_OK();
6598 mozilla::ipc::IPCResult ContentParent::RecvUpdateChildKeyedScalars(
6599 nsTArray<KeyedScalarAction>&& aScalarActions) {
6600 TelemetryIPC::UpdateChildKeyedScalars(GetTelemetryProcessID(mRemoteType),
6601 aScalarActions);
6602 return IPC_OK();
6605 mozilla::ipc::IPCResult ContentParent::RecvRecordChildEvents(
6606 nsTArray<mozilla::Telemetry::ChildEventData>&& aEvents) {
6607 TelemetryIPC::RecordChildEvents(GetTelemetryProcessID(mRemoteType), aEvents);
6608 return IPC_OK();
6611 mozilla::ipc::IPCResult ContentParent::RecvRecordDiscardedData(
6612 const mozilla::Telemetry::DiscardedData& aDiscardedData) {
6613 TelemetryIPC::RecordDiscardedData(GetTelemetryProcessID(mRemoteType),
6614 aDiscardedData);
6615 return IPC_OK();
6618 mozilla::ipc::IPCResult ContentParent::RecvRecordPageLoadEvent(
6619 const mozilla::glean::perf::PageLoadExtra& aPageLoadEventExtra) {
6620 mozilla::glean::perf::page_load.Record(mozilla::Some(aPageLoadEventExtra));
6622 // Send the PageLoadPing after every 30 page loads, or on startup.
6623 if (++sPageLoadEventCounter >= 30) {
6624 NS_SUCCEEDED(NS_DispatchToMainThreadQueue(
6625 NS_NewRunnableFunction(
6626 "PageLoadPingIdleTask",
6627 [] { mozilla::glean_pings::Pageload.Submit("threshold"_ns); }),
6628 EventQueuePriority::Idle));
6629 sPageLoadEventCounter = 0;
6632 return IPC_OK();
6635 //////////////////////////////////////////////////////////////////
6636 // PURLClassifierParent
6638 PURLClassifierParent* ContentParent::AllocPURLClassifierParent(
6639 nsIPrincipal* aPrincipal, bool* aSuccess) {
6640 MOZ_ASSERT(NS_IsMainThread());
6642 *aSuccess = true;
6643 RefPtr<URLClassifierParent> actor = new URLClassifierParent();
6644 return actor.forget().take();
6647 mozilla::ipc::IPCResult ContentParent::RecvPURLClassifierConstructor(
6648 PURLClassifierParent* aActor, nsIPrincipal* aPrincipal, bool* aSuccess) {
6649 MOZ_ASSERT(NS_IsMainThread());
6650 MOZ_ASSERT(aActor);
6651 *aSuccess = false;
6653 auto* actor = static_cast<URLClassifierParent*>(aActor);
6654 nsCOMPtr<nsIPrincipal> principal(aPrincipal);
6655 if (!principal) {
6656 actor->ClassificationFailed();
6657 return IPC_OK();
6659 if (!ValidatePrincipal(aPrincipal)) {
6660 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
6662 return actor->StartClassify(principal, aSuccess);
6665 bool ContentParent::DeallocPURLClassifierParent(PURLClassifierParent* aActor) {
6666 MOZ_ASSERT(NS_IsMainThread());
6667 MOZ_ASSERT(aActor);
6669 RefPtr<URLClassifierParent> actor =
6670 dont_AddRef(static_cast<URLClassifierParent*>(aActor));
6671 return true;
6674 //////////////////////////////////////////////////////////////////
6675 // PURLClassifierLocalParent
6677 PURLClassifierLocalParent* ContentParent::AllocPURLClassifierLocalParent(
6678 nsIURI* aURI, const nsTArray<IPCURLClassifierFeature>& aFeatures) {
6679 MOZ_ASSERT(NS_IsMainThread());
6681 RefPtr<URLClassifierLocalParent> actor = new URLClassifierLocalParent();
6682 return actor.forget().take();
6685 mozilla::ipc::IPCResult ContentParent::RecvPURLClassifierLocalConstructor(
6686 PURLClassifierLocalParent* aActor, nsIURI* aURI,
6687 nsTArray<IPCURLClassifierFeature>&& aFeatures) {
6688 MOZ_ASSERT(NS_IsMainThread());
6689 MOZ_ASSERT(aActor);
6691 nsTArray<IPCURLClassifierFeature> features = std::move(aFeatures);
6693 if (!aURI) {
6694 return IPC_FAIL(this, "aURI should not be null");
6697 auto* actor = static_cast<URLClassifierLocalParent*>(aActor);
6698 return actor->StartClassify(aURI, features);
6701 bool ContentParent::DeallocPURLClassifierLocalParent(
6702 PURLClassifierLocalParent* aActor) {
6703 MOZ_ASSERT(NS_IsMainThread());
6704 MOZ_ASSERT(aActor);
6706 RefPtr<URLClassifierLocalParent> actor =
6707 dont_AddRef(static_cast<URLClassifierLocalParent*>(aActor));
6708 return true;
6711 PSessionStorageObserverParent*
6712 ContentParent::AllocPSessionStorageObserverParent() {
6713 MOZ_ASSERT(NS_IsMainThread());
6715 return mozilla::dom::AllocPSessionStorageObserverParent();
6718 mozilla::ipc::IPCResult ContentParent::RecvPSessionStorageObserverConstructor(
6719 PSessionStorageObserverParent* aActor) {
6720 MOZ_ASSERT(NS_IsMainThread());
6721 MOZ_ASSERT(aActor);
6723 if (!mozilla::dom::RecvPSessionStorageObserverConstructor(aActor)) {
6724 return IPC_FAIL(this, "RecvPSessionStorageObserverConstructor failed.");
6726 return IPC_OK();
6729 bool ContentParent::DeallocPSessionStorageObserverParent(
6730 PSessionStorageObserverParent* aActor) {
6731 MOZ_ASSERT(NS_IsMainThread());
6732 MOZ_ASSERT(aActor);
6734 return mozilla::dom::DeallocPSessionStorageObserverParent(aActor);
6737 mozilla::ipc::IPCResult ContentParent::RecvBHRThreadHang(
6738 const HangDetails& aDetails) {
6739 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
6740 if (obs) {
6741 // Copy the HangDetails recieved over the network into a nsIHangDetails, and
6742 // then fire our own observer notification.
6743 // XXX: We should be able to avoid this potentially expensive copy here by
6744 // moving our deserialized argument.
6745 nsCOMPtr<nsIHangDetails> hangDetails =
6746 new nsHangDetails(HangDetails(aDetails), PersistedToDisk::No);
6747 obs->NotifyObservers(hangDetails, "bhr-thread-hang", nullptr);
6749 return IPC_OK();
6752 mozilla::ipc::IPCResult ContentParent::RecvAddCertException(
6753 nsIX509Cert* aCert, const nsACString& aHostName, int32_t aPort,
6754 const OriginAttributes& aOriginAttributes, bool aIsTemporary,
6755 AddCertExceptionResolver&& aResolver) {
6756 nsCOMPtr<nsICertOverrideService> overrideService =
6757 do_GetService(NS_CERTOVERRIDE_CONTRACTID);
6758 if (!overrideService) {
6759 aResolver(NS_ERROR_FAILURE);
6760 return IPC_OK();
6762 nsresult rv = overrideService->RememberValidityOverride(
6763 aHostName, aPort, aOriginAttributes, aCert, aIsTemporary);
6764 aResolver(rv);
6765 return IPC_OK();
6768 mozilla::ipc::IPCResult
6769 ContentParent::RecvAutomaticStorageAccessPermissionCanBeGranted(
6770 nsIPrincipal* aPrincipal,
6771 AutomaticStorageAccessPermissionCanBeGrantedResolver&& aResolver) {
6772 if (!aPrincipal) {
6773 return IPC_FAIL(this, "No principal");
6776 if (!ValidatePrincipal(aPrincipal)) {
6777 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
6779 aResolver(Document::AutomaticStorageAccessPermissionCanBeGranted(aPrincipal));
6780 return IPC_OK();
6783 mozilla::ipc::IPCResult
6784 ContentParent::RecvStorageAccessPermissionGrantedForOrigin(
6785 uint64_t aTopLevelWindowId,
6786 const MaybeDiscarded<BrowsingContext>& aParentContext,
6787 nsIPrincipal* aTrackingPrincipal, const nsACString& aTrackingOrigin,
6788 const int& aAllowMode,
6789 const Maybe<ContentBlockingNotifier::StorageAccessPermissionGrantedReason>&
6790 aReason,
6791 const bool& aFrameOnly,
6792 StorageAccessPermissionGrantedForOriginResolver&& aResolver) {
6793 if (aParentContext.IsNullOrDiscarded()) {
6794 return IPC_OK();
6797 if (!aTrackingPrincipal) {
6798 return IPC_FAIL(this, "No principal");
6801 // We only report here if we cannot report the console directly in the content
6802 // process. In that case, the `aReason` would be given a value. Otherwise, it
6803 // will be nothing.
6804 if (aReason) {
6805 ContentBlockingNotifier::ReportUnblockingToConsole(
6806 aParentContext.get_canonical(), NS_ConvertUTF8toUTF16(aTrackingOrigin),
6807 aReason.value());
6810 StorageAccessAPIHelper::SaveAccessForOriginOnParentProcess(
6811 aTopLevelWindowId, aParentContext.get_canonical(), aTrackingPrincipal,
6812 aAllowMode, aFrameOnly)
6813 ->Then(GetCurrentSerialEventTarget(), __func__,
6814 [aResolver = std::move(aResolver)](
6815 StorageAccessAPIHelper::ParentAccessGrantPromise::
6816 ResolveOrRejectValue&& aValue) {
6817 bool success =
6818 aValue.IsResolve() && NS_SUCCEEDED(aValue.ResolveValue());
6819 aResolver(success);
6821 return IPC_OK();
6824 mozilla::ipc::IPCResult ContentParent::RecvCompleteAllowAccessFor(
6825 const MaybeDiscarded<BrowsingContext>& aParentContext,
6826 uint64_t aTopLevelWindowId, nsIPrincipal* aTrackingPrincipal,
6827 const nsACString& aTrackingOrigin, uint32_t aCookieBehavior,
6828 const ContentBlockingNotifier::StorageAccessPermissionGrantedReason&
6829 aReason,
6830 CompleteAllowAccessForResolver&& aResolver) {
6831 if (aParentContext.IsNullOrDiscarded()) {
6832 return IPC_OK();
6835 StorageAccessAPIHelper::CompleteAllowAccessForOnParentProcess(
6836 aParentContext.get_canonical(), aTopLevelWindowId, aTrackingPrincipal,
6837 aTrackingOrigin, aCookieBehavior, aReason, nullptr)
6838 ->Then(GetCurrentSerialEventTarget(), __func__,
6839 [aResolver = std::move(aResolver)](
6840 StorageAccessAPIHelper::StorageAccessPermissionGrantPromise::
6841 ResolveOrRejectValue&& aValue) {
6842 Maybe<StorageAccessPromptChoices> choice;
6843 if (aValue.IsResolve()) {
6844 choice.emplace(static_cast<StorageAccessPromptChoices>(
6845 aValue.ResolveValue()));
6847 aResolver(choice);
6849 return IPC_OK();
6852 mozilla::ipc::IPCResult ContentParent::RecvSetAllowStorageAccessRequestFlag(
6853 nsIPrincipal* aEmbeddedPrincipal, nsIURI* aEmbeddingOrigin,
6854 SetAllowStorageAccessRequestFlagResolver&& aResolver) {
6855 MOZ_ASSERT(aEmbeddedPrincipal);
6856 MOZ_ASSERT(aEmbeddingOrigin);
6858 if (!aEmbeddedPrincipal || !aEmbeddingOrigin) {
6859 aResolver(false);
6860 return IPC_OK();
6863 // Get the permission manager and build the key.
6864 RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
6865 if (!permManager) {
6866 aResolver(false);
6867 return IPC_OK();
6869 nsCOMPtr<nsIURI> embeddedURI = aEmbeddedPrincipal->GetURI();
6870 nsCString permissionKey;
6871 bool success = AntiTrackingUtils::CreateStorageRequestPermissionKey(
6872 embeddedURI, permissionKey);
6873 if (!success) {
6874 aResolver(false);
6875 return IPC_OK();
6878 // Set the permission to ALLOW for a prefence specified amount of seconds.
6879 // Time units are inconsistent, be careful
6880 int64_t when = (PR_Now() / PR_USEC_PER_MSEC) +
6881 StaticPrefs::dom_storage_access_forward_declared_lifetime() *
6882 PR_MSEC_PER_SEC;
6883 nsCOMPtr<nsIPrincipal> principal = BasePrincipal::CreateContentPrincipal(
6884 aEmbeddingOrigin, aEmbeddedPrincipal->OriginAttributesRef());
6885 nsresult rv = permManager->AddFromPrincipal(
6886 principal, permissionKey, nsIPermissionManager::ALLOW_ACTION,
6887 nsIPermissionManager::EXPIRE_TIME, when);
6888 if (NS_FAILED(rv)) {
6889 aResolver(false);
6890 return IPC_OK();
6893 // Resolve with success if we set the permission.
6894 aResolver(true);
6895 return IPC_OK();
6898 mozilla::ipc::IPCResult ContentParent::RecvTestAllowStorageAccessRequestFlag(
6899 nsIPrincipal* aEmbeddingPrincipal, nsIURI* aEmbeddedOrigin,
6900 TestAllowStorageAccessRequestFlagResolver&& aResolver) {
6901 MOZ_ASSERT(aEmbeddingPrincipal);
6902 MOZ_ASSERT(aEmbeddedOrigin);
6904 // Get the permission manager and build the key.
6905 RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
6906 if (!permManager) {
6907 aResolver(false);
6908 return IPC_OK();
6910 nsCString requestPermissionKey;
6911 bool success = AntiTrackingUtils::CreateStorageRequestPermissionKey(
6912 aEmbeddedOrigin, requestPermissionKey);
6913 if (!success) {
6914 aResolver(false);
6915 return IPC_OK();
6918 // Get the permission and resolve false if it is not set to ALLOW.
6919 uint32_t access = nsIPermissionManager::UNKNOWN_ACTION;
6920 nsresult rv = permManager->TestPermissionFromPrincipal(
6921 aEmbeddingPrincipal, requestPermissionKey, &access);
6922 if (NS_FAILED(rv)) {
6923 aResolver(false);
6924 return IPC_OK();
6926 if (access != nsIPermissionManager::ALLOW_ACTION) {
6927 aResolver(false);
6928 return IPC_OK();
6931 // Remove the permission, failing if the permission manager fails
6932 rv = permManager->RemoveFromPrincipal(aEmbeddingPrincipal,
6933 requestPermissionKey);
6934 if (NS_FAILED(rv)) {
6935 aResolver(false);
6936 return IPC_OK();
6939 // At this point, signal to our caller that the permission was set
6940 aResolver(true);
6941 return IPC_OK();
6944 mozilla::ipc::IPCResult ContentParent::RecvStoreUserInteractionAsPermission(
6945 nsIPrincipal* aPrincipal) {
6946 if (!aPrincipal) {
6947 return IPC_FAIL(this, "No principal");
6950 if (!ValidatePrincipal(aPrincipal)) {
6951 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
6953 ContentBlockingUserInteraction::Observe(aPrincipal);
6954 return IPC_OK();
6957 mozilla::ipc::IPCResult ContentParent::RecvTestCookiePermissionDecided(
6958 const MaybeDiscarded<BrowsingContext>& aContext, nsIPrincipal* aPrincipal,
6959 const TestCookiePermissionDecidedResolver&& aResolver) {
6960 if (aContext.IsNullOrDiscarded()) {
6961 return IPC_OK();
6964 if (!aPrincipal) {
6965 return IPC_FAIL(this, "No principal");
6968 RefPtr<WindowGlobalParent> wgp =
6969 aContext.get_canonical()->GetCurrentWindowGlobal();
6970 nsCOMPtr<nsICookieJarSettings> cjs = wgp->CookieJarSettings();
6972 Maybe<bool> result =
6973 StorageAccessAPIHelper::CheckCookiesPermittedDecidesStorageAccessAPI(
6974 cjs, aPrincipal);
6975 aResolver(result);
6976 return IPC_OK();
6979 mozilla::ipc::IPCResult ContentParent::RecvTestStorageAccessPermission(
6980 nsIPrincipal* aEmbeddingPrincipal, const nsCString& aEmbeddedOrigin,
6981 const TestStorageAccessPermissionResolver&& aResolver) {
6982 // Get the permission manager and build the key.
6983 RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
6984 if (!permManager) {
6985 aResolver(Nothing());
6986 return IPC_OK();
6988 nsCString requestPermissionKey;
6989 AntiTrackingUtils::CreateStoragePermissionKey(aEmbeddedOrigin,
6990 requestPermissionKey);
6992 // Test the permission
6993 uint32_t access = nsIPermissionManager::UNKNOWN_ACTION;
6994 nsresult rv = permManager->TestPermissionFromPrincipal(
6995 aEmbeddingPrincipal, requestPermissionKey, &access);
6996 if (NS_FAILED(rv)) {
6997 aResolver(Nothing());
6998 return IPC_OK();
7000 if (access == nsIPermissionManager::ALLOW_ACTION) {
7001 aResolver(Some(true));
7002 } else if (access == nsIPermissionManager::DENY_ACTION) {
7003 aResolver(Some(false));
7004 } else {
7005 aResolver(Nothing());
7008 return IPC_OK();
7011 mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaPlaybackChanged(
7012 const MaybeDiscarded<BrowsingContext>& aContext,
7013 MediaPlaybackState aState) {
7014 if (aContext.IsNullOrDiscarded()) {
7015 return IPC_OK();
7017 if (RefPtr<IMediaInfoUpdater> updater =
7018 aContext.get_canonical()->GetMediaController()) {
7019 updater->NotifyMediaPlaybackChanged(aContext.ContextId(), aState);
7021 return IPC_OK();
7024 mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaAudibleChanged(
7025 const MaybeDiscarded<BrowsingContext>& aContext, MediaAudibleState aState) {
7026 if (aContext.IsNullOrDiscarded()) {
7027 return IPC_OK();
7029 if (RefPtr<IMediaInfoUpdater> updater =
7030 aContext.get_canonical()->GetMediaController()) {
7031 updater->NotifyMediaAudibleChanged(aContext.ContextId(), aState);
7033 return IPC_OK();
7036 mozilla::ipc::IPCResult ContentParent::RecvNotifyPictureInPictureModeChanged(
7037 const MaybeDiscarded<BrowsingContext>& aContext, bool aEnabled) {
7038 if (aContext.IsNullOrDiscarded()) {
7039 return IPC_OK();
7041 if (RefPtr<MediaController> controller =
7042 aContext.get_canonical()->GetMediaController()) {
7043 controller->SetIsInPictureInPictureMode(aContext.ContextId(), aEnabled);
7045 return IPC_OK();
7048 mozilla::ipc::IPCResult ContentParent::RecvAbortOtherOrientationPendingPromises(
7049 const MaybeDiscarded<BrowsingContext>& aContext) {
7050 if (aContext.IsNullOrDiscarded()) {
7051 return IPC_OK();
7054 CanonicalBrowsingContext* context = aContext.get_canonical();
7056 context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
7057 Unused << aParent->SendAbortOrientationPendingPromises(context);
7060 return IPC_OK();
7063 mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaSessionUpdated(
7064 const MaybeDiscarded<BrowsingContext>& aContext, bool aIsCreated) {
7065 if (aContext.IsNullOrDiscarded()) {
7066 return IPC_OK();
7069 RefPtr<IMediaInfoUpdater> updater =
7070 aContext.get_canonical()->GetMediaController();
7071 if (!updater) {
7072 return IPC_OK();
7074 if (aIsCreated) {
7075 updater->NotifySessionCreated(aContext->Id());
7076 } else {
7077 updater->NotifySessionDestroyed(aContext->Id());
7079 return IPC_OK();
7082 mozilla::ipc::IPCResult ContentParent::RecvNotifyUpdateMediaMetadata(
7083 const MaybeDiscarded<BrowsingContext>& aContext,
7084 const Maybe<MediaMetadataBase>& aMetadata) {
7085 if (aContext.IsNullOrDiscarded()) {
7086 return IPC_OK();
7088 if (RefPtr<IMediaInfoUpdater> updater =
7089 aContext.get_canonical()->GetMediaController()) {
7090 updater->UpdateMetadata(aContext.ContextId(), aMetadata);
7092 return IPC_OK();
7095 mozilla::ipc::IPCResult
7096 ContentParent::RecvNotifyMediaSessionPlaybackStateChanged(
7097 const MaybeDiscarded<BrowsingContext>& aContext,
7098 MediaSessionPlaybackState aPlaybackState) {
7099 if (aContext.IsNullOrDiscarded()) {
7100 return IPC_OK();
7102 if (RefPtr<IMediaInfoUpdater> updater =
7103 aContext.get_canonical()->GetMediaController()) {
7104 updater->SetDeclaredPlaybackState(aContext.ContextId(), aPlaybackState);
7106 return IPC_OK();
7109 mozilla::ipc::IPCResult
7110 ContentParent::RecvNotifyMediaSessionSupportedActionChanged(
7111 const MaybeDiscarded<BrowsingContext>& aContext, MediaSessionAction aAction,
7112 bool aEnabled) {
7113 if (aContext.IsNullOrDiscarded()) {
7114 return IPC_OK();
7116 RefPtr<IMediaInfoUpdater> updater =
7117 aContext.get_canonical()->GetMediaController();
7118 if (!updater) {
7119 return IPC_OK();
7121 if (aEnabled) {
7122 updater->EnableAction(aContext.ContextId(), aAction);
7123 } else {
7124 updater->DisableAction(aContext.ContextId(), aAction);
7126 return IPC_OK();
7129 mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaFullScreenState(
7130 const MaybeDiscarded<BrowsingContext>& aContext, bool aIsInFullScreen) {
7131 if (aContext.IsNullOrDiscarded()) {
7132 return IPC_OK();
7134 if (RefPtr<IMediaInfoUpdater> updater =
7135 aContext.get_canonical()->GetMediaController()) {
7136 updater->NotifyMediaFullScreenState(aContext.ContextId(), aIsInFullScreen);
7138 return IPC_OK();
7141 mozilla::ipc::IPCResult ContentParent::RecvNotifyPositionStateChanged(
7142 const MaybeDiscarded<BrowsingContext>& aContext,
7143 const Maybe<PositionState>& aState) {
7144 if (aContext.IsNullOrDiscarded()) {
7145 return IPC_OK();
7147 if (RefPtr<IMediaInfoUpdater> updater =
7148 aContext.get_canonical()->GetMediaController()) {
7149 updater->UpdatePositionState(aContext.ContextId(), aState);
7151 return IPC_OK();
7154 mozilla::ipc::IPCResult ContentParent::RecvAddOrRemovePageAwakeRequest(
7155 const MaybeDiscarded<BrowsingContext>& aContext,
7156 const bool& aShouldAddCount) {
7157 if (aContext.IsNullOrDiscarded()) {
7158 return IPC_OK();
7160 if (aShouldAddCount) {
7161 aContext.get_canonical()->AddPageAwakeRequest();
7162 } else {
7163 aContext.get_canonical()->RemovePageAwakeRequest();
7165 return IPC_OK();
7168 #if defined(XP_WIN)
7169 mozilla::ipc::IPCResult ContentParent::RecvGetModulesTrust(
7170 ModulePaths&& aModPaths, bool aRunAtNormalPriority,
7171 GetModulesTrustResolver&& aResolver) {
7172 RefPtr<DllServices> dllSvc(DllServices::Get());
7173 dllSvc->GetModulesTrust(std::move(aModPaths), aRunAtNormalPriority)
7174 ->Then(
7175 GetMainThreadSerialEventTarget(), __func__,
7176 [aResolver](ModulesMapResult&& aResult) {
7177 aResolver(Some(ModulesMapResult(std::move(aResult))));
7179 [aResolver](nsresult aRv) { aResolver(Nothing()); });
7180 return IPC_OK();
7182 #endif // defined(XP_WIN)
7184 mozilla::ipc::IPCResult ContentParent::RecvCreateBrowsingContext(
7185 uint64_t aGroupId, BrowsingContext::IPCInitializer&& aInit) {
7186 RefPtr<WindowGlobalParent> parent;
7187 if (aInit.mParentId != 0) {
7188 parent = WindowGlobalParent::GetByInnerWindowId(aInit.mParentId);
7189 if (!parent) {
7190 return IPC_FAIL(this, "Parent doesn't exist in parent process");
7194 if (parent && parent->GetContentParent() != this) {
7195 // We're trying attach a child BrowsingContext to a parent
7196 // WindowContext in another process. This is illegal since the
7197 // only thing that could create that child BrowsingContext is the parent
7198 // window's process.
7199 return IPC_FAIL(this,
7200 "Must create BrowsingContext from the parent's process");
7203 RefPtr<BrowsingContext> opener;
7204 if (aInit.GetOpenerId() != 0) {
7205 opener = BrowsingContext::Get(aInit.GetOpenerId());
7206 if (!opener) {
7207 return IPC_FAIL(this, "Opener doesn't exist in parent process");
7211 RefPtr<BrowsingContext> child = BrowsingContext::Get(aInit.mId);
7212 if (child) {
7213 // This is highly suspicious. BrowsingContexts should only be created once,
7214 // so finding one indicates that someone is doing something they shouldn't.
7215 return IPC_FAIL(this, "A BrowsingContext with this ID already exists");
7218 // Ensure that the passed-in BrowsingContextGroup is valid.
7219 RefPtr<BrowsingContextGroup> group =
7220 BrowsingContextGroup::GetOrCreate(aGroupId);
7221 if (parent && parent->Group() != group) {
7222 if (parent->Group()->Id() != aGroupId) {
7223 return IPC_FAIL(this, "Parent has different group ID");
7224 } else {
7225 return IPC_FAIL(this, "Parent has different group object");
7228 if (opener && opener->Group() != group) {
7229 if (opener->Group()->Id() != aGroupId) {
7230 return IPC_FAIL(this, "Opener has different group ID");
7231 } else {
7232 return IPC_FAIL(this, "Opener has different group object");
7235 if (!parent && !opener && !group->Toplevels().IsEmpty()) {
7236 return IPC_FAIL(this, "Unrelated context from child in stale group");
7239 return BrowsingContext::CreateFromIPC(std::move(aInit), group, this);
7242 bool ContentParent::CheckBrowsingContextEmbedder(CanonicalBrowsingContext* aBC,
7243 const char* aOperation) const {
7244 if (!aBC->IsEmbeddedInProcess(ChildID())) {
7245 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
7246 ("ParentIPC: Trying to %s out of process context 0x%08" PRIx64,
7247 aOperation, aBC->Id()));
7248 return false;
7250 return true;
7253 mozilla::ipc::IPCResult ContentParent::RecvDiscardBrowsingContext(
7254 const MaybeDiscarded<BrowsingContext>& aContext, bool aDoDiscard,
7255 DiscardBrowsingContextResolver&& aResolve) {
7256 if (CanonicalBrowsingContext* context =
7257 CanonicalBrowsingContext::Cast(aContext.GetMaybeDiscarded())) {
7258 if (aDoDiscard && !context->IsDiscarded()) {
7259 if (!CheckBrowsingContextEmbedder(context, "discard")) {
7260 return IPC_FAIL(this, "Illegal Discard attempt");
7263 context->Detach(/* aFromIPC */ true);
7265 context->AddFinalDiscardListener(aResolve);
7266 return IPC_OK();
7269 // Resolve the promise, as we've received and handled the message. This will
7270 // allow the content process to fully-discard references to this BC.
7271 aResolve(true);
7272 return IPC_OK();
7275 void ContentParent::UnregisterRemoveWorkerActor() {
7276 MOZ_ASSERT(NS_IsMainThread());
7279 RecursiveMutexAutoLock lock(mThreadsafeHandle->mMutex);
7280 if (--mThreadsafeHandle->mRemoteWorkerActorCount) {
7281 return;
7285 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
7286 ("UnregisterRemoveWorkerActor %p", this));
7287 MaybeBeginShutDown();
7290 mozilla::ipc::IPCResult ContentParent::RecvWindowClose(
7291 const MaybeDiscarded<BrowsingContext>& aContext, bool aTrustedCaller) {
7292 if (aContext.IsNullOrDiscarded()) {
7293 MOZ_LOG(
7294 BrowsingContext::GetLog(), LogLevel::Debug,
7295 ("ParentIPC: Trying to send a message to dead or detached context"));
7296 return IPC_OK();
7298 CanonicalBrowsingContext* context = aContext.get_canonical();
7300 // FIXME Need to check that the sending process has access to the unit of
7301 // related
7302 // browsing contexts of bc.
7304 if (ContentParent* cp = context->GetContentParent()) {
7305 Unused << cp->SendWindowClose(context, aTrustedCaller);
7307 return IPC_OK();
7310 mozilla::ipc::IPCResult ContentParent::RecvWindowFocus(
7311 const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType,
7312 uint64_t aActionId) {
7313 if (aContext.IsNullOrDiscarded()) {
7314 MOZ_LOG(
7315 BrowsingContext::GetLog(), LogLevel::Debug,
7316 ("ParentIPC: Trying to send a message to dead or detached context"));
7317 return IPC_OK();
7319 LOGFOCUS(("ContentParent::RecvWindowFocus actionid: %" PRIu64, aActionId));
7320 CanonicalBrowsingContext* context = aContext.get_canonical();
7322 if (ContentParent* cp = context->GetContentParent()) {
7323 Unused << cp->SendWindowFocus(context, aCallerType, aActionId);
7325 return IPC_OK();
7328 mozilla::ipc::IPCResult ContentParent::RecvWindowBlur(
7329 const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType) {
7330 if (aContext.IsNullOrDiscarded()) {
7331 MOZ_LOG(
7332 BrowsingContext::GetLog(), LogLevel::Debug,
7333 ("ParentIPC: Trying to send a message to dead or detached context"));
7334 return IPC_OK();
7336 CanonicalBrowsingContext* context = aContext.get_canonical();
7338 if (ContentParent* cp = context->GetContentParent()) {
7339 Unused << cp->SendWindowBlur(context, aCallerType);
7341 return IPC_OK();
7344 mozilla::ipc::IPCResult ContentParent::RecvRaiseWindow(
7345 const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType,
7346 uint64_t aActionId) {
7347 if (aContext.IsNullOrDiscarded()) {
7348 MOZ_LOG(
7349 BrowsingContext::GetLog(), LogLevel::Debug,
7350 ("ParentIPC: Trying to send a message to dead or detached context"));
7351 return IPC_OK();
7353 LOGFOCUS(("ContentParent::RecvRaiseWindow actionid: %" PRIu64, aActionId));
7355 CanonicalBrowsingContext* context = aContext.get_canonical();
7357 if (ContentParent* cp = context->GetContentParent()) {
7358 Unused << cp->SendRaiseWindow(context, aCallerType, aActionId);
7360 return IPC_OK();
7363 mozilla::ipc::IPCResult ContentParent::RecvAdjustWindowFocus(
7364 const MaybeDiscarded<BrowsingContext>& aContext, bool aIsVisible,
7365 uint64_t aActionId, bool aShouldClearFocus,
7366 const MaybeDiscarded<BrowsingContext>& aAncestorBrowsingContextToFocus) {
7367 if (aContext.IsNullOrDiscarded()) {
7368 MOZ_LOG(
7369 BrowsingContext::GetLog(), LogLevel::Debug,
7370 ("ParentIPC: Trying to send a message to dead or detached context"));
7371 return IPC_OK();
7373 LOGFOCUS(
7374 ("ContentParent::RecvAdjustWindowFocus isVisible %d actionid: %" PRIu64,
7375 aIsVisible, aActionId));
7377 nsTHashMap<nsPtrHashKey<ContentParent>, bool> processes(2);
7378 processes.InsertOrUpdate(this, true);
7380 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
7381 if (cpm) {
7382 CanonicalBrowsingContext* context = aContext.get_canonical();
7383 while (context) {
7384 BrowsingContext* parent = context->GetParent();
7385 if (!parent) {
7386 break;
7389 CanonicalBrowsingContext* canonicalParent = parent->Canonical();
7390 ContentParent* cp = cpm->GetContentProcessById(
7391 ContentParentId(canonicalParent->OwnerProcessId()));
7392 if (cp && !processes.Get(cp)) {
7393 Unused << cp->SendAdjustWindowFocus(context, aIsVisible, aActionId,
7394 aShouldClearFocus,
7395 aAncestorBrowsingContextToFocus);
7396 processes.InsertOrUpdate(cp, true);
7398 context = canonicalParent;
7401 return IPC_OK();
7404 mozilla::ipc::IPCResult ContentParent::RecvClearFocus(
7405 const MaybeDiscarded<BrowsingContext>& aContext) {
7406 if (aContext.IsNullOrDiscarded()) {
7407 MOZ_LOG(
7408 BrowsingContext::GetLog(), LogLevel::Debug,
7409 ("ParentIPC: Trying to send a message to dead or detached context"));
7410 return IPC_OK();
7412 CanonicalBrowsingContext* context = aContext.get_canonical();
7414 if (ContentParent* cp = context->GetContentParent()) {
7415 Unused << cp->SendClearFocus(context);
7417 return IPC_OK();
7420 mozilla::ipc::IPCResult ContentParent::RecvSetFocusedBrowsingContext(
7421 const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
7422 if (aContext.IsNullOrDiscarded()) {
7423 MOZ_LOG(
7424 BrowsingContext::GetLog(), LogLevel::Debug,
7425 ("ParentIPC: Trying to send a message to dead or detached context"));
7426 return IPC_OK();
7428 LOGFOCUS(("ContentParent::RecvSetFocusedBrowsingContext actionid: %" PRIu64,
7429 aActionId));
7430 CanonicalBrowsingContext* context = aContext.get_canonical();
7432 nsFocusManager* fm = nsFocusManager::GetFocusManager();
7433 if (!fm) {
7434 return IPC_OK();
7437 if (!fm->SetFocusedBrowsingContextInChrome(context, aActionId)) {
7438 LOGFOCUS((
7439 "Ignoring out-of-sequence attempt [%p] to set focused browsing context "
7440 "in parent.",
7441 context));
7442 Unused << SendReviseFocusedBrowsingContext(
7443 aActionId, fm->GetFocusedBrowsingContextInChrome(),
7444 fm->GetActionIdForFocusedBrowsingContextInChrome());
7445 return IPC_OK();
7448 BrowserParent::UpdateFocusFromBrowsingContext();
7450 context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
7451 Unused << aParent->SendSetFocusedBrowsingContext(context, aActionId);
7454 return IPC_OK();
7457 mozilla::ipc::IPCResult ContentParent::RecvSetActiveBrowsingContext(
7458 const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
7459 if (aContext.IsNullOrDiscarded()) {
7460 MOZ_LOG(
7461 BrowsingContext::GetLog(), LogLevel::Debug,
7462 ("ParentIPC: Trying to send a message to dead or detached context"));
7463 return IPC_OK();
7465 LOGFOCUS(("ContentParent::RecvSetActiveBrowsingContext actionid: %" PRIu64,
7466 aActionId));
7467 CanonicalBrowsingContext* context = aContext.get_canonical();
7469 nsFocusManager* fm = nsFocusManager::GetFocusManager();
7470 if (!fm) {
7471 return IPC_OK();
7474 if (!fm->SetActiveBrowsingContextInChrome(context, aActionId)) {
7475 LOGFOCUS(
7476 ("Ignoring out-of-sequence attempt [%p] to set active browsing context "
7477 "in parent.",
7478 context));
7479 Unused << SendReviseActiveBrowsingContext(
7480 aActionId, fm->GetActiveBrowsingContextInChrome(),
7481 fm->GetActionIdForActiveBrowsingContextInChrome());
7482 return IPC_OK();
7485 context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
7486 Unused << aParent->SendSetActiveBrowsingContext(context, aActionId);
7489 return IPC_OK();
7492 mozilla::ipc::IPCResult ContentParent::RecvUnsetActiveBrowsingContext(
7493 const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
7494 if (aContext.IsNullOrDiscarded()) {
7495 MOZ_LOG(
7496 BrowsingContext::GetLog(), LogLevel::Debug,
7497 ("ParentIPC: Trying to send a message to dead or detached context"));
7498 return IPC_OK();
7500 LOGFOCUS(("ContentParent::RecvUnsetActiveBrowsingContext actionid: %" PRIu64,
7501 aActionId));
7502 CanonicalBrowsingContext* context = aContext.get_canonical();
7504 nsFocusManager* fm = nsFocusManager::GetFocusManager();
7505 if (!fm) {
7506 return IPC_OK();
7509 if (!fm->SetActiveBrowsingContextInChrome(nullptr, aActionId)) {
7510 LOGFOCUS(
7511 ("Ignoring out-of-sequence attempt to unset active browsing context in "
7512 "parent [%p].",
7513 context));
7514 Unused << SendReviseActiveBrowsingContext(
7515 aActionId, fm->GetActiveBrowsingContextInChrome(),
7516 fm->GetActionIdForActiveBrowsingContextInChrome());
7517 return IPC_OK();
7520 context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
7521 Unused << aParent->SendUnsetActiveBrowsingContext(context, aActionId);
7524 return IPC_OK();
7527 mozilla::ipc::IPCResult ContentParent::RecvSetFocusedElement(
7528 const MaybeDiscarded<BrowsingContext>& aContext, bool aNeedsFocus) {
7529 if (aContext.IsNullOrDiscarded()) {
7530 MOZ_LOG(
7531 BrowsingContext::GetLog(), LogLevel::Debug,
7532 ("ParentIPC: Trying to send a message to dead or detached context"));
7533 return IPC_OK();
7535 LOGFOCUS(("ContentParent::RecvSetFocusedElement"));
7536 CanonicalBrowsingContext* context = aContext.get_canonical();
7538 if (ContentParent* cp = context->GetContentParent()) {
7539 Unused << cp->SendSetFocusedElement(context, aNeedsFocus);
7541 return IPC_OK();
7544 mozilla::ipc::IPCResult ContentParent::RecvFinalizeFocusOuter(
7545 const MaybeDiscarded<BrowsingContext>& aContext, bool aCanFocus,
7546 CallerType aCallerType) {
7547 if (aContext.IsNullOrDiscarded()) {
7548 MOZ_LOG(
7549 BrowsingContext::GetLog(), LogLevel::Debug,
7550 ("ParentIPC: Trying to send a message to dead or detached context"));
7551 return IPC_OK();
7553 LOGFOCUS(("ContentParent::RecvFinalizeFocusOuter"));
7554 CanonicalBrowsingContext* context = aContext.get_canonical();
7555 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
7556 if (cpm) {
7557 ContentParent* cp = cpm->GetContentProcessById(
7558 ContentParentId(context->EmbedderProcessId()));
7559 if (cp) {
7560 Unused << cp->SendFinalizeFocusOuter(context, aCanFocus, aCallerType);
7563 return IPC_OK();
7566 mozilla::ipc::IPCResult ContentParent::RecvInsertNewFocusActionId(
7567 uint64_t aActionId) {
7568 LOGFOCUS(("ContentParent::RecvInsertNewFocusActionId actionid: %" PRIu64,
7569 aActionId));
7570 nsFocusManager* fm = nsFocusManager::GetFocusManager();
7571 if (fm) {
7572 fm->InsertNewFocusActionId(aActionId);
7574 return IPC_OK();
7577 mozilla::ipc::IPCResult ContentParent::RecvBlurToParent(
7578 const MaybeDiscarded<BrowsingContext>& aFocusedBrowsingContext,
7579 const MaybeDiscarded<BrowsingContext>& aBrowsingContextToClear,
7580 const MaybeDiscarded<BrowsingContext>& aAncestorBrowsingContextToFocus,
7581 bool aIsLeavingDocument, bool aAdjustWidget,
7582 bool aBrowsingContextToClearHandled,
7583 bool aAncestorBrowsingContextToFocusHandled, uint64_t aActionId) {
7584 if (aFocusedBrowsingContext.IsNullOrDiscarded()) {
7585 MOZ_LOG(
7586 BrowsingContext::GetLog(), LogLevel::Debug,
7587 ("ParentIPC: Trying to send a message to dead or detached context"));
7588 return IPC_OK();
7591 LOGFOCUS(
7592 ("ContentParent::RecvBlurToParent isLeavingDocument %d adjustWidget %d "
7593 "browsingContextToClearHandled %d ancestorBrowsingContextToFocusHandled "
7594 "%d actionid: %" PRIu64,
7595 aIsLeavingDocument, aAdjustWidget, aBrowsingContextToClearHandled,
7596 aAncestorBrowsingContextToFocusHandled, aActionId));
7598 CanonicalBrowsingContext* focusedBrowsingContext =
7599 aFocusedBrowsingContext.get_canonical();
7601 // If aBrowsingContextToClear and aAncestorBrowsingContextToFocusHandled
7602 // didn't get handled in the process that sent this IPC message and they
7603 // aren't in the same process as aFocusedBrowsingContext, we need to split
7604 // off their handling here and use SendSetFocusedElement to send them
7605 // elsewhere than the blurring itself.
7607 bool ancestorDifferent =
7608 (!aAncestorBrowsingContextToFocusHandled &&
7609 !aAncestorBrowsingContextToFocus.IsNullOrDiscarded() &&
7610 (focusedBrowsingContext->OwnerProcessId() !=
7611 aAncestorBrowsingContextToFocus.get_canonical()->OwnerProcessId()));
7612 if (!aBrowsingContextToClearHandled &&
7613 !aBrowsingContextToClear.IsNullOrDiscarded() &&
7614 (focusedBrowsingContext->OwnerProcessId() !=
7615 aBrowsingContextToClear.get_canonical()->OwnerProcessId())) {
7616 MOZ_RELEASE_ASSERT(!ancestorDifferent,
7617 "This combination is not supposed to happen.");
7618 if (ContentParent* cp =
7619 aBrowsingContextToClear.get_canonical()->GetContentParent()) {
7620 Unused << cp->SendSetFocusedElement(aBrowsingContextToClear, false);
7622 } else if (ancestorDifferent) {
7623 if (ContentParent* cp = aAncestorBrowsingContextToFocus.get_canonical()
7624 ->GetContentParent()) {
7625 Unused << cp->SendSetFocusedElement(aAncestorBrowsingContextToFocus,
7626 true);
7630 if (ContentParent* cp = focusedBrowsingContext->GetContentParent()) {
7631 Unused << cp->SendBlurToChild(aFocusedBrowsingContext,
7632 aBrowsingContextToClear,
7633 aAncestorBrowsingContextToFocus,
7634 aIsLeavingDocument, aAdjustWidget, aActionId);
7637 return IPC_OK();
7640 mozilla::ipc::IPCResult ContentParent::RecvMaybeExitFullscreen(
7641 const MaybeDiscarded<BrowsingContext>& aContext) {
7642 if (aContext.IsNullOrDiscarded()) {
7643 MOZ_LOG(
7644 BrowsingContext::GetLog(), LogLevel::Debug,
7645 ("ParentIPC: Trying to send a message to dead or detached context"));
7646 return IPC_OK();
7648 CanonicalBrowsingContext* context = aContext.get_canonical();
7650 if (ContentParent* cp = context->GetContentParent()) {
7651 Unused << cp->SendMaybeExitFullscreen(context);
7654 return IPC_OK();
7657 mozilla::ipc::IPCResult ContentParent::RecvWindowPostMessage(
7658 const MaybeDiscarded<BrowsingContext>& aContext,
7659 const ClonedOrErrorMessageData& aMessage, const PostMessageData& aData) {
7660 if (aContext.IsNullOrDiscarded()) {
7661 MOZ_LOG(
7662 BrowsingContext::GetLog(), LogLevel::Debug,
7663 ("ParentIPC: Trying to send a message to dead or detached context"));
7664 return IPC_OK();
7666 CanonicalBrowsingContext* context = aContext.get_canonical();
7668 if (aData.source().IsDiscarded()) {
7669 MOZ_LOG(
7670 BrowsingContext::GetLog(), LogLevel::Debug,
7671 ("ParentIPC: Trying to send a message from dead or detached context"));
7672 return IPC_OK();
7675 RefPtr<ContentParent> cp = context->GetContentParent();
7676 if (!cp) {
7677 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
7678 ("ParentIPC: Trying to send PostMessage to dead content process"));
7679 return IPC_OK();
7682 ClonedOrErrorMessageData message;
7683 StructuredCloneData messageFromChild;
7684 if (aMessage.type() == ClonedOrErrorMessageData::TClonedMessageData) {
7685 UnpackClonedMessageData(aMessage, messageFromChild);
7687 ClonedMessageData clonedMessageData;
7688 if (BuildClonedMessageData(messageFromChild, clonedMessageData)) {
7689 message = std::move(clonedMessageData);
7690 } else {
7691 // FIXME Logging?
7692 message = ErrorMessageData();
7694 } else {
7695 MOZ_ASSERT(aMessage.type() == ClonedOrErrorMessageData::TErrorMessageData);
7696 message = ErrorMessageData();
7699 Unused << cp->SendWindowPostMessage(context, message, aData);
7700 return IPC_OK();
7703 void ContentParent::AddBrowsingContextGroup(BrowsingContextGroup* aGroup) {
7704 MOZ_DIAGNOSTIC_ASSERT(aGroup);
7705 // Ensure that the group has been inserted, and if we're not launching
7706 // anymore, also begin subscribing. Launching processes will be subscribed if
7707 // they finish launching in `LaunchSubprocessResolve`.
7708 if (mGroups.EnsureInserted(aGroup) && !IsLaunching()) {
7709 aGroup->Subscribe(this);
7713 void ContentParent::RemoveBrowsingContextGroup(BrowsingContextGroup* aGroup) {
7714 MOZ_DIAGNOSTIC_ASSERT(aGroup);
7715 // Remove the group from our list. This is called from the
7716 // BrowsingContextGroup when unsubscribing, so we don't need to do it here.
7717 if (mGroups.EnsureRemoved(aGroup) && CanSend()) {
7718 // If we're removing the entry for the first time, tell the content process
7719 // to clean up the group.
7720 Unused << SendDestroyBrowsingContextGroup(aGroup->Id());
7724 mozilla::ipc::IPCResult ContentParent::RecvCommitBrowsingContextTransaction(
7725 const MaybeDiscarded<BrowsingContext>& aContext,
7726 BrowsingContext::BaseTransaction&& aTransaction, uint64_t aEpoch) {
7727 // Record the new BrowsingContextFieldEpoch associated with this transaction.
7728 // This should be done unconditionally, so that we're always in-sync.
7730 // The order the parent process receives transactions is considered the
7731 // "canonical" ordering, so we don't need to worry about doing any
7732 // epoch-related validation.
7733 MOZ_ASSERT(aEpoch == mBrowsingContextFieldEpoch + 1,
7734 "Child process skipped an epoch?");
7735 mBrowsingContextFieldEpoch = aEpoch;
7737 return aTransaction.CommitFromIPC(aContext, this);
7740 mozilla::ipc::IPCResult ContentParent::RecvBlobURLDataRequest(
7741 const nsACString& aBlobURL, nsIPrincipal* aTriggeringPrincipal,
7742 nsIPrincipal* aLoadingPrincipal, const OriginAttributes& aOriginAttributes,
7743 uint64_t aInnerWindowId, const nsCString& aPartitionKey,
7744 BlobURLDataRequestResolver&& aResolver) {
7745 RefPtr<BlobImpl> blobImpl;
7747 // Since revoked blobs are also retrieved, it is possible that the blob no
7748 // longer exists (due to the 5 second timeout) when execution reaches here
7749 if (!BlobURLProtocolHandler::GetDataEntry(
7750 aBlobURL, getter_AddRefs(blobImpl), aLoadingPrincipal,
7751 aTriggeringPrincipal, aOriginAttributes, aInnerWindowId,
7752 aPartitionKey, true /* AlsoIfRevoked */)) {
7753 aResolver(NS_ERROR_DOM_BAD_URI);
7754 return IPC_OK();
7757 IPCBlob ipcBlob;
7758 nsresult rv = IPCBlobUtils::Serialize(blobImpl, ipcBlob);
7760 if (NS_WARN_IF(NS_FAILED(rv))) {
7761 aResolver(rv);
7762 return IPC_OK();
7765 aResolver(ipcBlob);
7766 return IPC_OK();
7769 mozilla::ipc::IPCResult ContentParent::RecvReportServiceWorkerShutdownProgress(
7770 uint32_t aShutdownStateId, ServiceWorkerShutdownState::Progress aProgress) {
7771 RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
7772 MOZ_RELEASE_ASSERT(swm, "ServiceWorkers should shutdown before SWM.");
7774 swm->ReportServiceWorkerShutdownProgress(aShutdownStateId, aProgress);
7776 return IPC_OK();
7779 mozilla::ipc::IPCResult ContentParent::RecvNotifyOnHistoryReload(
7780 const MaybeDiscarded<BrowsingContext>& aContext, const bool& aForceReload,
7781 NotifyOnHistoryReloadResolver&& aResolver) {
7782 bool canReload = false;
7783 Maybe<NotNull<RefPtr<nsDocShellLoadState>>> loadState;
7784 Maybe<bool> reloadActiveEntry;
7785 if (!aContext.IsNullOrDiscarded()) {
7786 aContext.get_canonical()->NotifyOnHistoryReload(
7787 aForceReload, canReload, loadState, reloadActiveEntry);
7789 aResolver(
7790 std::tuple<const bool&,
7791 const Maybe<NotNull<RefPtr<nsDocShellLoadState>>>&,
7792 const Maybe<bool>&>(canReload, loadState, reloadActiveEntry));
7793 return IPC_OK();
7796 mozilla::ipc::IPCResult ContentParent::RecvHistoryCommit(
7797 const MaybeDiscarded<BrowsingContext>& aContext, const uint64_t& aLoadID,
7798 const nsID& aChangeID, const uint32_t& aLoadType, const bool& aPersist,
7799 const bool& aCloneEntryChildren, const bool& aChannelExpired,
7800 const uint32_t& aCacheKey) {
7801 if (!aContext.IsDiscarded()) {
7802 CanonicalBrowsingContext* canonical = aContext.get_canonical();
7803 if (!canonical) {
7804 return IPC_FAIL(
7805 this, "Could not get canonical. aContext.get_canonical() fails.");
7807 canonical->SessionHistoryCommit(aLoadID, aChangeID, aLoadType, aPersist,
7808 aCloneEntryChildren, aChannelExpired,
7809 aCacheKey);
7811 return IPC_OK();
7814 mozilla::ipc::IPCResult ContentParent::RecvHistoryGo(
7815 const MaybeDiscarded<BrowsingContext>& aContext, int32_t aOffset,
7816 uint64_t aHistoryEpoch, bool aRequireUserInteraction, bool aUserActivation,
7817 HistoryGoResolver&& aResolveRequestedIndex) {
7818 if (!aContext.IsNullOrDiscarded()) {
7819 RefPtr<CanonicalBrowsingContext> canonical = aContext.get_canonical();
7820 aResolveRequestedIndex(
7821 canonical->HistoryGo(aOffset, aHistoryEpoch, aRequireUserInteraction,
7822 aUserActivation, Some(ChildID())));
7824 return IPC_OK();
7827 mozilla::ipc::IPCResult ContentParent::RecvSynchronizeLayoutHistoryState(
7828 const MaybeDiscarded<BrowsingContext>& aContext,
7829 nsILayoutHistoryState* aState) {
7830 if (aContext.IsNull()) {
7831 return IPC_OK();
7834 BrowsingContext* bc = aContext.GetMaybeDiscarded();
7835 if (!bc) {
7836 return IPC_OK();
7838 SessionHistoryEntry* entry = bc->Canonical()->GetActiveSessionHistoryEntry();
7839 if (entry) {
7840 entry->SetLayoutHistoryState(aState);
7842 return IPC_OK();
7845 mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryTitle(
7846 const MaybeDiscarded<BrowsingContext>& aContext, const nsAString& aTitle) {
7847 if (aContext.IsNullOrDiscarded()) {
7848 return IPC_OK();
7851 SessionHistoryEntry* entry =
7852 aContext.get_canonical()->GetActiveSessionHistoryEntry();
7853 if (entry) {
7854 entry->SetTitle(aTitle);
7856 return IPC_OK();
7859 mozilla::ipc::IPCResult
7860 ContentParent::RecvSessionHistoryEntryScrollRestorationIsManual(
7861 const MaybeDiscarded<BrowsingContext>& aContext, const bool& aIsManual) {
7862 if (aContext.IsNullOrDiscarded()) {
7863 return IPC_OK();
7866 SessionHistoryEntry* entry =
7867 aContext.get_canonical()->GetActiveSessionHistoryEntry();
7868 if (entry) {
7869 entry->SetScrollRestorationIsManual(aIsManual);
7871 return IPC_OK();
7874 mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryScrollPosition(
7875 const MaybeDiscarded<BrowsingContext>& aContext, const int32_t& aX,
7876 const int32_t& aY) {
7877 if (aContext.IsNullOrDiscarded()) {
7878 return IPC_OK();
7881 SessionHistoryEntry* entry =
7882 aContext.get_canonical()->GetActiveSessionHistoryEntry();
7883 if (entry) {
7884 entry->SetScrollPosition(aX, aY);
7886 return IPC_OK();
7889 mozilla::ipc::IPCResult
7890 ContentParent::RecvSessionHistoryEntryStoreWindowNameInContiguousEntries(
7891 const MaybeDiscarded<BrowsingContext>& aContext, const nsAString& aName) {
7892 if (aContext.IsNullOrDiscarded()) {
7893 return IPC_OK();
7896 // Per https://html.spec.whatwg.org/#history-traversal 4.2.1, we need to set
7897 // the name to all contiguous entries. This has to be called before
7898 // CanonicalBrowsingContext::SessionHistoryCommit(), so the active entry is
7899 // still the old entry that we want to set.
7901 SessionHistoryEntry* entry =
7902 aContext.get_canonical()->GetActiveSessionHistoryEntry();
7904 if (entry) {
7905 nsSHistory::WalkContiguousEntries(
7906 entry, [&](nsISHEntry* aEntry) { aEntry->SetName(aName); });
7909 return IPC_OK();
7912 mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryCacheKey(
7913 const MaybeDiscarded<BrowsingContext>& aContext,
7914 const uint32_t& aCacheKey) {
7915 if (aContext.IsNullOrDiscarded()) {
7916 return IPC_OK();
7919 SessionHistoryEntry* entry =
7920 aContext.get_canonical()->GetActiveSessionHistoryEntry();
7921 if (entry) {
7922 entry->SetCacheKey(aCacheKey);
7924 return IPC_OK();
7927 mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryWireframe(
7928 const MaybeDiscarded<BrowsingContext>& aContext,
7929 const Wireframe& aWireframe) {
7930 if (aContext.IsNull()) {
7931 return IPC_OK();
7934 BrowsingContext* bc = aContext.GetMaybeDiscarded();
7935 if (!bc) {
7936 return IPC_OK();
7939 SessionHistoryEntry* entry = bc->Canonical()->GetActiveSessionHistoryEntry();
7940 if (entry) {
7941 entry->SetWireframe(Some(aWireframe));
7943 return IPC_OK();
7946 mozilla::ipc::IPCResult
7947 ContentParent::RecvGetLoadingSessionHistoryInfoFromParent(
7948 const MaybeDiscarded<BrowsingContext>& aContext,
7949 GetLoadingSessionHistoryInfoFromParentResolver&& aResolver) {
7950 if (aContext.IsNullOrDiscarded()) {
7951 return IPC_OK();
7954 Maybe<LoadingSessionHistoryInfo> info;
7955 aContext.get_canonical()->GetLoadingSessionHistoryInfoFromParent(info);
7956 aResolver(info);
7958 return IPC_OK();
7961 mozilla::ipc::IPCResult ContentParent::RecvRemoveFromBFCache(
7962 const MaybeDiscarded<BrowsingContext>& aContext) {
7963 if (aContext.IsNullOrDiscarded()) {
7964 return IPC_OK();
7967 nsCOMPtr<nsFrameLoaderOwner> owner =
7968 do_QueryInterface(aContext.get_canonical()->GetEmbedderElement());
7969 if (!owner) {
7970 return IPC_OK();
7973 RefPtr<nsFrameLoader> frameLoader = owner->GetFrameLoader();
7974 if (!frameLoader || !frameLoader->GetMaybePendingBrowsingContext()) {
7975 return IPC_OK();
7978 nsCOMPtr<nsISHistory> shistory = frameLoader->GetMaybePendingBrowsingContext()
7979 ->Canonical()
7980 ->GetSessionHistory();
7981 if (!shistory) {
7982 return IPC_OK();
7985 uint32_t count = shistory->GetCount();
7986 for (uint32_t i = 0; i < count; ++i) {
7987 nsCOMPtr<nsISHEntry> entry;
7988 shistory->GetEntryAtIndex(i, getter_AddRefs(entry));
7989 nsCOMPtr<SessionHistoryEntry> she = do_QueryInterface(entry);
7990 if (she) {
7991 if (RefPtr<nsFrameLoader> frameLoader = she->GetFrameLoader()) {
7992 if (frameLoader->GetMaybePendingBrowsingContext() == aContext.get()) {
7993 she->SetFrameLoader(nullptr);
7994 frameLoader->Destroy();
7995 break;
8001 return IPC_OK();
8004 mozilla::ipc::IPCResult ContentParent::RecvSetActiveSessionHistoryEntry(
8005 const MaybeDiscarded<BrowsingContext>& aContext,
8006 const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo&& aInfo,
8007 uint32_t aLoadType, uint32_t aUpdatedCacheKey, const nsID& aChangeID) {
8008 if (!aContext.IsNullOrDiscarded()) {
8009 aContext.get_canonical()->SetActiveSessionHistoryEntry(
8010 aPreviousScrollPos, &aInfo, aLoadType, aUpdatedCacheKey, aChangeID);
8012 return IPC_OK();
8015 mozilla::ipc::IPCResult ContentParent::RecvReplaceActiveSessionHistoryEntry(
8016 const MaybeDiscarded<BrowsingContext>& aContext,
8017 SessionHistoryInfo&& aInfo) {
8018 if (!aContext.IsNullOrDiscarded()) {
8019 aContext.get_canonical()->ReplaceActiveSessionHistoryEntry(&aInfo);
8021 return IPC_OK();
8024 mozilla::ipc::IPCResult
8025 ContentParent::RecvRemoveDynEntriesFromActiveSessionHistoryEntry(
8026 const MaybeDiscarded<BrowsingContext>& aContext) {
8027 if (!aContext.IsNullOrDiscarded()) {
8028 aContext.get_canonical()->RemoveDynEntriesFromActiveSessionHistoryEntry();
8030 return IPC_OK();
8033 mozilla::ipc::IPCResult ContentParent::RecvRemoveFromSessionHistory(
8034 const MaybeDiscarded<BrowsingContext>& aContext, const nsID& aChangeID) {
8035 if (!aContext.IsNullOrDiscarded()) {
8036 aContext.get_canonical()->RemoveFromSessionHistory(aChangeID);
8038 return IPC_OK();
8041 mozilla::ipc::IPCResult ContentParent::RecvHistoryReload(
8042 const MaybeDiscarded<BrowsingContext>& aContext,
8043 const uint32_t aReloadFlags) {
8044 if (!aContext.IsNullOrDiscarded()) {
8045 nsCOMPtr<nsISHistory> shistory =
8046 aContext.get_canonical()->GetSessionHistory();
8047 if (shistory) {
8048 shistory->Reload(aReloadFlags);
8051 return IPC_OK();
8054 mozilla::ipc::IPCResult ContentParent::RecvCommitWindowContextTransaction(
8055 const MaybeDiscarded<WindowContext>& aContext,
8056 WindowContext::BaseTransaction&& aTransaction, uint64_t aEpoch) {
8057 // Record the new BrowsingContextFieldEpoch associated with this transaction.
8058 // This should be done unconditionally, so that we're always in-sync.
8060 // The order the parent process receives transactions is considered the
8061 // "canonical" ordering, so we don't need to worry about doing any
8062 // epoch-related validation.
8063 MOZ_ASSERT(aEpoch == mBrowsingContextFieldEpoch + 1,
8064 "Child process skipped an epoch?");
8065 mBrowsingContextFieldEpoch = aEpoch;
8067 return aTransaction.CommitFromIPC(aContext, this);
8070 NS_IMETHODIMP ContentParent::GetChildID(uint64_t* aOut) {
8071 *aOut = this->ChildID();
8072 return NS_OK;
8075 NS_IMETHODIMP ContentParent::GetOsPid(int32_t* aOut) {
8076 *aOut = Pid();
8077 return NS_OK;
8080 NS_IMETHODIMP ContentParent::GetRemoteType(nsACString& aRemoteType) {
8081 aRemoteType = GetRemoteType();
8082 return NS_OK;
8085 IPCResult ContentParent::RecvRawMessage(
8086 const JSActorMessageMeta& aMeta, const Maybe<ClonedMessageData>& aData,
8087 const Maybe<ClonedMessageData>& aStack) {
8088 Maybe<StructuredCloneData> data;
8089 if (aData) {
8090 data.emplace();
8091 data->BorrowFromClonedMessageData(*aData);
8093 Maybe<StructuredCloneData> stack;
8094 if (aStack) {
8095 stack.emplace();
8096 stack->BorrowFromClonedMessageData(*aStack);
8098 MMPrinter::Print("ContentParent::RecvRawMessage", aMeta.actorName(),
8099 aMeta.messageName(), aData);
8100 ReceiveRawMessage(aMeta, std::move(data), std::move(stack));
8101 return IPC_OK();
8104 NS_IMETHODIMP ContentParent::GetActor(const nsACString& aName, JSContext* aCx,
8105 JSProcessActorParent** retval) {
8106 ErrorResult error;
8107 RefPtr<JSProcessActorParent> actor =
8108 JSActorManager::GetActor(aCx, aName, error)
8109 .downcast<JSProcessActorParent>();
8110 if (error.MaybeSetPendingException(aCx)) {
8111 return NS_ERROR_FAILURE;
8113 actor.forget(retval);
8114 return NS_OK;
8117 NS_IMETHODIMP ContentParent::GetExistingActor(const nsACString& aName,
8118 JSProcessActorParent** retval) {
8119 RefPtr<JSProcessActorParent> actor =
8120 JSActorManager::GetExistingActor(aName).downcast<JSProcessActorParent>();
8121 actor.forget(retval);
8122 return NS_OK;
8125 already_AddRefed<JSActor> ContentParent::InitJSActor(
8126 JS::Handle<JSObject*> aMaybeActor, const nsACString& aName,
8127 ErrorResult& aRv) {
8128 RefPtr<JSProcessActorParent> actor;
8129 if (aMaybeActor.get()) {
8130 aRv = UNWRAP_OBJECT(JSProcessActorParent, aMaybeActor.get(), actor);
8131 if (aRv.Failed()) {
8132 return nullptr;
8134 } else {
8135 actor = new JSProcessActorParent();
8138 MOZ_RELEASE_ASSERT(!actor->Manager(),
8139 "mManager was already initialized once!");
8140 actor->Init(aName, this);
8141 return actor.forget();
8144 IPCResult ContentParent::RecvFOGData(ByteBuf&& buf) {
8145 glean::FOGData(std::move(buf));
8146 return IPC_OK();
8149 mozilla::ipc::IPCResult ContentParent::RecvSetContainerFeaturePolicy(
8150 const MaybeDiscardedBrowsingContext& aContainerContext,
8151 FeaturePolicy* aContainerFeaturePolicy) {
8152 if (aContainerContext.IsNullOrDiscarded()) {
8153 return IPC_OK();
8156 auto* context = aContainerContext.get_canonical();
8157 context->SetContainerFeaturePolicy(aContainerFeaturePolicy);
8159 return IPC_OK();
8162 NS_IMETHODIMP ContentParent::GetCanSend(bool* aCanSend) {
8163 *aCanSend = CanSend();
8164 return NS_OK;
8167 ContentParent* ContentParent::AsContentParent() { return this; }
8169 JSActorManager* ContentParent::AsJSActorManager() { return this; }
8171 IPCResult ContentParent::RecvGetSystemIcon(nsIURI* aURI,
8172 GetSystemIconResolver&& aResolver) {
8173 using ResolverArgs = std::tuple<const nsresult&, mozilla::Maybe<ByteBuf>&&>;
8175 if (!aURI) {
8176 Maybe<ByteBuf> bytebuf = Nothing();
8177 aResolver(ResolverArgs(NS_ERROR_NULL_POINTER, std::move(bytebuf)));
8178 return IPC_OK();
8181 #if defined(MOZ_WIDGET_GTK)
8182 Maybe<ByteBuf> bytebuf = Some(ByteBuf{});
8183 nsresult rv = nsIconChannel::GetIcon(aURI, bytebuf.ptr());
8184 if (NS_WARN_IF(NS_FAILED(rv))) {
8185 bytebuf = Nothing();
8187 aResolver(ResolverArgs(rv, std::move(bytebuf)));
8188 return IPC_OK();
8189 #elif defined(XP_WIN)
8190 nsIconChannel::GetIconAsync(aURI)->Then(
8191 GetCurrentSerialEventTarget(), __func__,
8192 [aResolver](ByteBuf&& aByteBuf) {
8193 Maybe<ByteBuf> bytebuf = Some(std::move(aByteBuf));
8194 aResolver(ResolverArgs(NS_OK, std::move(bytebuf)));
8196 [aResolver](nsresult aErr) {
8197 Maybe<ByteBuf> bytebuf = Nothing();
8198 aResolver(ResolverArgs(aErr, std::move(bytebuf)));
8200 return IPC_OK();
8201 #else
8202 MOZ_CRASH(
8203 "This message is currently implemented only on GTK and Windows "
8204 "platforms");
8205 #endif
8208 #ifdef FUZZING_SNAPSHOT
8209 IPCResult ContentParent::RecvSignalFuzzingReady() {
8210 // No action needed here, we already observe this message directly
8211 // on the channel and act accordingly.
8212 return IPC_OK();
8214 #endif
8216 nsCString ThreadsafeContentParentHandle::GetRemoteType() {
8217 RecursiveMutexAutoLock lock(mMutex);
8218 return mRemoteType;
8221 bool ThreadsafeContentParentHandle::MaybeRegisterRemoteWorkerActor(
8222 MoveOnlyFunction<bool(uint32_t, bool)> aCallback) {
8223 RecursiveMutexAutoLock lock(mMutex);
8224 if (aCallback(mRemoteWorkerActorCount, mShutdownStarted)) {
8225 // TODO: I'd wish we could assert here that our ContentParent is alive.
8226 ++mRemoteWorkerActorCount;
8227 return true;
8229 return false;
8232 } // namespace dom
8233 } // namespace mozilla
8235 NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
8237 NS_IMETHODIMP
8238 ParentIdleListener::Observe(nsISupports*, const char* aTopic,
8239 const char16_t* aData) {
8240 mozilla::Unused << mParent->SendNotifyIdleObserver(
8241 mObserver, nsDependentCString(aTopic), nsDependentString(aData));
8242 return NS_OK;
8245 #undef LOGPDM