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