1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #ifdef MOZ_WIDGET_ANDROID
8 # include "AndroidDecoderModule.h"
9 #endif
10
11 #include "mozilla/DebugOnly.h"
12
13 #include "base/basictypes.h"
14 #include "base/shared_memory.h"
15
16 #include "ContentParent.h"
17 #include "mozilla/ipc/ProcessUtils.h"
18 #include "mozilla/CmdLineAndEnvUtils.h"
19 #include "BrowserParent.h"
20
21 #include "chrome/common/process_watcher.h"
22 #include "mozilla/Result.h"
23 #include "mozilla/XREAppData.h"
24 #include "nsComponentManagerUtils.h"
25 #include "nsIBrowserDOMWindow.h"
26
27 #ifdef ACCESSIBILITY
28 # include "mozilla/a11y/PDocAccessible.h"
29 #endif
30 #include "GMPServiceParent.h"
31 #include "HandlerServiceParent.h"
32 #include "IHistory.h"
33 #if defined(XP_WIN) && defined(ACCESSIBILITY)
34 # include "mozilla/a11y/AccessibleWrap.h"
35 # include "mozilla/a11y/Compatibility.h"
36 # include "mozilla/mscom/ActCtxResource.h"
37 # include "mozilla/StaticPrefs_accessibility.h"
38 #endif
39 #include <map>
40 #include <utility>
41
42 #include "ContentProcessManager.h"
43 #include "GeckoProfiler.h"
44 #include "Geolocation.h"
45 #include "GfxInfoBase.h"
46 #include "MMPrinter.h"
47 #include "PreallocatedProcessManager.h"
48 #include "ProcessPriorityManager.h"
49 #include "ProfilerParent.h"
50 #include "SandboxHal.h"
51 #include "SourceSurfaceRawData.h"
52 #include "mozilla/ipc/URIUtils.h"
53 #include "gfxPlatform.h"
54 #include "gfxPlatformFontList.h"
55 #include "mozilla/AutoRestore.h"
56 #include "mozilla/ContentBlocking.h"
57 #include "mozilla/BasePrincipal.h"
58 #include "mozilla/BenchmarkStorageParent.h"
59 #include "mozilla/ContentBlockingUserInteraction.h"
60 #include "mozilla/ClearOnShutdown.h"
61 #include "mozilla/FOGIPC.h"
62 #include "mozilla/GlobalStyleSheetCache.h"
63 #include "mozilla/GeckoArgs.h"
64 #include "mozilla/HangDetails.h"
65 #include "mozilla/LoginReputationIPC.h"
66 #include "mozilla/LookAndFeel.h"
67 #include "mozilla/Maybe.h"
68 #include "mozilla/NullPrincipal.h"
69 #include "mozilla/PerformanceMetricsCollector.h"
70 #include "mozilla/Preferences.h"
71 #include "mozilla/PresShell.h"
72 #include "mozilla/ProcessHangMonitor.h"
73 #include "mozilla/ProcessHangMonitorIPC.h"
74 #include "mozilla/ProfilerLabels.h"
75 #include "mozilla/ProfilerMarkers.h"
76 #include "mozilla/ScopeExit.h"
77 #include "mozilla/ScriptPreloader.h"
78 #include "mozilla/Components.h"
79 #include "mozilla/Sprintf.h"
80 #include "mozilla/StaticPrefs_dom.h"
81 #include "mozilla/StaticPrefs_media.h"
82 #include "mozilla/StaticPrefs_widget.h"
83 #include "mozilla/StyleSheet.h"
84 #include "mozilla/StyleSheetInlines.h"
85 #include "mozilla/Telemetry.h"
86 #include "mozilla/TelemetryIPC.h"
87 #include "mozilla/Unused.h"
88 #include "mozilla/WebBrowserPersistDocumentParent.h"
89 #include "mozilla/devtools/HeapSnapshotTempFileHelperParent.h"
90 #include "mozilla/dom/BlobURLProtocolHandler.h"
91 #include "mozilla/dom/BrowserHost.h"
92 #include "mozilla/dom/BrowsingContext.h"
93 #include "mozilla/dom/BrowsingContextGroup.h"
94 #include "mozilla/dom/CancelContentJSOptionsBinding.h"
95 #include "mozilla/dom/CanonicalBrowsingContext.h"
96 #include "mozilla/dom/ClientManager.h"
97 #include "mozilla/dom/ContentChild.h"
98 #include "mozilla/dom/DataTransfer.h"
99 #include "mozilla/dom/Document.h"
100 #include "mozilla/dom/Element.h"
101 #include "mozilla/dom/ExternalHelperAppParent.h"
102 #include "mozilla/dom/File.h"
103 #include "mozilla/dom/FileSystemSecurity.h"
104 #include "mozilla/dom/GeolocationBinding.h"
105 #include "mozilla/dom/GeolocationPositionError.h"
106 #include "mozilla/dom/GetFilesHelper.h"
107 #include "mozilla/dom/IPCBlobUtils.h"
108 #include "mozilla/dom/JSActorService.h"
109 #include "mozilla/dom/JSProcessActorBinding.h"
110 #include "mozilla/dom/LocalStorageCommon.h"
111 #include "mozilla/dom/MediaController.h"
112 #include "mozilla/dom/MemoryReportRequest.h"
113 #include "mozilla/dom/MediaStatusManager.h"
114 #include "mozilla/dom/Notification.h"
115 #include "mozilla/dom/PContentPermissionRequestParent.h"
116 #include "mozilla/dom/PCycleCollectWithLogsParent.h"
117 #include "mozilla/dom/ParentProcessMessageManager.h"
118 #include "mozilla/dom/Permissions.h"
119 #include "mozilla/dom/ProcessMessageManager.h"
120 #include "mozilla/dom/PushNotifier.h"
121 #include "mozilla/dom/ServiceWorkerManager.h"
122 #include "mozilla/dom/ServiceWorkerRegistrar.h"
123 #include "mozilla/dom/ServiceWorkerUtils.h"
124 #include "mozilla/dom/SessionHistoryEntry.h"
125 #include "mozilla/dom/SessionStorageManager.h"
126 #include "mozilla/dom/StorageIPC.h"
127 #include "mozilla/dom/URLClassifierParent.h"
128 #include "mozilla/dom/WakeLock.h"
129 #include "mozilla/dom/WindowGlobalParent.h"
130 #include "mozilla/dom/ipc/SharedMap.h"
131 #include "mozilla/dom/ipc/StructuredCloneData.h"
132 #include "mozilla/dom/nsMixedContentBlocker.h"
133 #include "mozilla/dom/power/PowerManagerService.h"
134 #include "mozilla/dom/quota/QuotaManagerService.h"
135 #include "mozilla/embedding/printingui/PrintingParent.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/hal_sandbox/PHalParent.h"
141 #include "mozilla/intl/L10nRegistry.h"
142 #include "mozilla/intl/LocaleService.h"
143 #include "mozilla/ipc/BackgroundChild.h"
144 #include "mozilla/ipc/BackgroundParent.h"
145 #include "mozilla/ipc/ByteBuf.h"
146 #include "mozilla/ipc/CrashReporterHost.h"
147 #include "mozilla/ipc/Endpoint.h"
148 #include "mozilla/ipc/FileDescriptorSetParent.h"
149 #include "mozilla/ipc/FileDescriptorUtils.h"
150 #include "mozilla/ipc/IPCStreamAlloc.h"
151 #include "mozilla/ipc/IPCStreamDestination.h"
152 #include "mozilla/ipc/IPCStreamSource.h"
153 #include "mozilla/ipc/IPCStreamUtils.h"
154 #include "mozilla/ipc/PChildToParentStreamParent.h"
155 #include "mozilla/ipc/TestShellParent.h"
156 #include "mozilla/layers/CompositorThread.h"
157 #include "mozilla/layers/ImageBridgeParent.h"
158 #include "mozilla/layers/LayerTreeOwnerTracker.h"
159 #include "mozilla/layers/PAPZParent.h"
160 #include "mozilla/loader/ScriptCacheActors.h"
161 #include "mozilla/media/MediaParent.h"
162 #include "mozilla/mozSpellChecker.h"
163 #include "mozilla/net/CookieServiceParent.h"
164 #include "mozilla/net/NeckoMessageUtils.h"
165 #include "mozilla/net/NeckoParent.h"
166 #include "mozilla/net/PCookieServiceParent.h"
167 #include "mozilla/TelemetryComms.h"
168 #include "mozilla/TelemetryEventEnums.h"
169 #include "mozilla/RemoteLazyInputStreamParent.h"
170 #include "mozilla/widget/RemoteLookAndFeel.h"
171 #include "mozilla/widget/ScreenManager.h"
172 #include "nsAnonymousTemporaryFile.h"
173 #include "nsAppRunner.h"
174 #include "nsCExternalHandlerService.h"
175 #include "nsCOMPtr.h"
176 #include "nsChromeRegistryChrome.h"
177 #include "nsConsoleMessage.h"
178 #include "nsConsoleService.h"
179 #include "nsContentPermissionHelper.h"
180 #include "nsContentUtils.h"
181 #include "nsCRT.h"
182 #include "nsDebugImpl.h"
183 #include "nsDirectoryServiceDefs.h"
184 #include "nsDocShell.h"
185 #include "nsEmbedCID.h"
186 #include "nsFocusManager.h"
187 #include "nsFrameLoader.h"
188 #include "nsFrameMessageManager.h"
189 #include "nsHashPropertyBag.h"
190 #include "nsHyphenationManager.h"
191 #include "nsIAlertsService.h"
192 #include "nsIAppStartup.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 "nsIDOMChromeWindow.h"
205 #include "nsIDocShell.h"
206 #include "nsIDocShellTreeOwner.h"
207 #include "nsIDragService.h"
208 #include "nsIExternalProtocolService.h"
209 #include "nsIGfxInfo.h"
210 #include "nsIUserIdleService.h"
211 #include "nsIInterfaceRequestorUtils.h"
212 #include "nsILocalStorageManager.h"
213 #include "nsIMemoryInfoDumper.h"
214 #include "nsIMemoryReporter.h"
215 #include "nsIMozBrowserFrame.h"
216 #include "nsINetworkLinkService.h"
217 #include "nsIObserverService.h"
218 #include "nsIParentChannel.h"
219 #include "nsIScriptError.h"
220 #include "nsIScriptSecurityManager.h"
221 #include "nsIServiceWorkerManager.h"
222 #include "nsISiteSecurityService.h"
223 #include "nsISound.h"
224 #include "nsIStringBundle.h"
225 #include "nsITimer.h"
226 #include "nsIURL.h"
227 #include "nsIWebBrowserChrome.h"
228 #include "nsIX509Cert.h"
229 #include "nsIXULRuntime.h"
230 #if defined(MOZ_WIDGET_GTK) || defined(XP_WIN)
231 # include "nsIconChannel.h"
232 #endif
233 #include "nsMemoryInfoDumper.h"
234 #include "nsMemoryReporterManager.h"
235 #include "nsOpenURIInFrameParams.h"
236 #include "nsPIWindowWatcher.h"
237 #include "nsPluginHost.h"
238 #include "nsPluginTags.h"
239 #include "nsQueryObject.h"
240 #include "nsReadableUtils.h"
241 #include "nsSHistory.h"
242 #include "nsScriptError.h"
243 #include "nsSerializationHelper.h"
244 #include "nsServiceManagerUtils.h"
245 #include "nsStreamUtils.h"
246 #include "nsStyleSheetService.h"
247 #include "nsThread.h"
248 #include "nsThreadUtils.h"
249 #include "nsWidgetsCID.h"
250 #include "nsWindowWatcher.h"
251 #include "prio.h"
252 #include "private/pprio.h"
253 #include "xpcpublic.h"
254 #include "nsOpenWindowInfo.h"
255 #include "nsFrameLoaderOwner.h"
256
257 #ifdef MOZ_WEBRTC
258 # include "jsapi/WebrtcGlobalParent.h"
259 #endif
260
261 #if defined(XP_MACOSX)
262 # include "nsMacUtilsImpl.h"
263 # include "mozilla/AvailableMemoryWatcher.h"
264 #endif
265
266 #if defined(ANDROID) || defined(LINUX)
267 # include "nsSystemInfo.h"
268 #endif
269
270 #if defined(XP_LINUX)
271 # include "mozilla/Hal.h"
272 #endif
273
274 #ifdef ANDROID
275 # include "gfxAndroidPlatform.h"
276 #endif
277
278 #include "mozilla/PermissionManager.h"
279
280 #ifdef MOZ_WIDGET_ANDROID
281 # include "AndroidBridge.h"
282 # include "mozilla/java/GeckoProcessManagerWrappers.h"
283 # include "mozilla/java/GeckoProcessTypeWrappers.h"
284 #endif
285
286 #ifdef MOZ_WIDGET_GTK
287 # include <gdk/gdk.h>
288 # include "mozilla/WidgetUtilsGtk.h"
289 #endif
290
291 #include "mozilla/RemoteSpellCheckEngineParent.h"
292
293 #include "Crypto.h"
294
295 #ifdef MOZ_WEBSPEECH
296 # include "mozilla/dom/SpeechSynthesisParent.h"
297 #endif
298
299 #if defined(MOZ_SANDBOX)
300 # include "mozilla/SandboxSettings.h"
301 # if defined(XP_LINUX)
302 # include "mozilla/SandboxInfo.h"
303 # include "mozilla/SandboxBroker.h"
304 # include "mozilla/SandboxBrokerPolicyFactory.h"
305 # endif
306 # if defined(XP_MACOSX)
307 # include "mozilla/Sandbox.h"
308 # endif
309 #endif
310
311 #ifdef XP_WIN
312 # include "mozilla/widget/AudioSession.h"
313 # include "mozilla/widget/WinContentSystemParameters.h"
314 # include "mozilla/WinDllServices.h"
315 #endif
316
317 #ifdef ACCESSIBILITY
318 # include "nsAccessibilityService.h"
319 #endif
320
321 #ifdef MOZ_CODE_COVERAGE
322 # include "mozilla/CodeCoverageHandler.h"
323 #endif
324
325 // For VP9Benchmark::sBenchmarkFpsPref
326 #include "Benchmark.h"
327
328 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
329
330 using base::KillProcess;
331
332 using namespace CrashReporter;
333 using namespace mozilla::dom::power;
334 using namespace mozilla::media;
335 using namespace mozilla::embedding;
336 using namespace mozilla::gfx;
337 using namespace mozilla::gmp;
338 using namespace mozilla::hal;
339 using namespace mozilla::ipc;
340 using namespace mozilla::intl;
341 using namespace mozilla::layers;
342 using namespace mozilla::layout;
343 using namespace mozilla::net;
344 using namespace mozilla::psm;
345 using namespace mozilla::widget;
346 using namespace mozilla::Telemetry;
347 using mozilla::loader::PScriptCacheParent;
348 using mozilla::Telemetry::ProcessID;
349
350 extern mozilla::LazyLogModule gFocusLog;
351
352 #define LOGFOCUS(args) MOZ_LOG(gFocusLog, mozilla::LogLevel::Debug, args)
353
354 // XXX Workaround for bug 986973 to maintain the existing broken semantics
355 template <>
356 struct nsIConsoleService::COMTypeInfo<nsConsoleService, void> {
357 static const nsIID kIID;
358 };
359 const nsIID nsIConsoleService::COMTypeInfo<nsConsoleService, void>::kIID =
360 NS_ICONSOLESERVICE_IID;
361
362 namespace mozilla {
363 namespace CubebUtils {
364 extern FileDescriptor CreateAudioIPCConnection();
365 }
366
367 namespace dom {
368
369 LazyLogModule gProcessLog("Process");
370
371 static std::map<RemoteDecodeIn, PDMFactory::MediaCodecsSupported>
372 sCodecsSupported;
373
374 /* static */
375 uint32_t ContentParent::sMaxContentProcesses = 0;
376
377 /* static */
378 Maybe<TimeStamp> ContentParent::sLastContentProcessLaunch = Nothing();
379
380 /* static */
GetLog()381 LogModule* ContentParent::GetLog() { return gProcessLog; }
382
383 #define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
384 #define NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC "ipc:network:set-connectivity"
385
386 // IPC receiver for remote GC/CC logging.
387 class CycleCollectWithLogsParent final : public PCycleCollectWithLogsParent {
388 public:
MOZ_COUNTED_DTOR(CycleCollectWithLogsParent)389 MOZ_COUNTED_DTOR(CycleCollectWithLogsParent)
390
391 static bool AllocAndSendConstructor(ContentParent* aManager,
392 bool aDumpAllTraces,
393 nsICycleCollectorLogSink* aSink,
394 nsIDumpGCAndCCLogsCallback* aCallback) {
395 CycleCollectWithLogsParent* actor;
396 FILE* gcLog;
397 FILE* ccLog;
398 nsresult rv;
399
400 actor = new CycleCollectWithLogsParent(aSink, aCallback);
401 rv = actor->mSink->Open(&gcLog, &ccLog);
402 if (NS_WARN_IF(NS_FAILED(rv))) {
403 delete actor;
404 return false;
405 }
406
407 return aManager->SendPCycleCollectWithLogsConstructor(
408 actor, aDumpAllTraces, FILEToFileDescriptor(gcLog),
409 FILEToFileDescriptor(ccLog));
410 }
411
412 private:
RecvCloseGCLog()413 virtual mozilla::ipc::IPCResult RecvCloseGCLog() override {
414 Unused << mSink->CloseGCLog();
415 return IPC_OK();
416 }
417
RecvCloseCCLog()418 virtual mozilla::ipc::IPCResult RecvCloseCCLog() override {
419 Unused << mSink->CloseCCLog();
420 return IPC_OK();
421 }
422
Recv__delete__()423 virtual mozilla::ipc::IPCResult Recv__delete__() override {
424 // Report completion to mCallback only on successful
425 // completion of the protocol.
426 nsCOMPtr<nsIFile> gcLog, ccLog;
427 mSink->GetGcLog(getter_AddRefs(gcLog));
428 mSink->GetCcLog(getter_AddRefs(ccLog));
429 Unused << mCallback->OnDump(gcLog, ccLog, /* parent = */ false);
430 return IPC_OK();
431 }
432
ActorDestroy(ActorDestroyReason aReason)433 virtual void ActorDestroy(ActorDestroyReason aReason) override {
434 // If the actor is unexpectedly destroyed, we deliberately
435 // don't call Close[GC]CLog on the sink, because the logs may
436 // be incomplete. See also the nsCycleCollectorLogSinkToFile
437 // implementaiton of those methods, and its destructor.
438 }
439
CycleCollectWithLogsParent(nsICycleCollectorLogSink * aSink,nsIDumpGCAndCCLogsCallback * aCallback)440 CycleCollectWithLogsParent(nsICycleCollectorLogSink* aSink,
441 nsIDumpGCAndCCLogsCallback* aCallback)
442 : mSink(aSink), mCallback(aCallback) {
443 MOZ_COUNT_CTOR(CycleCollectWithLogsParent);
444 }
445
446 nsCOMPtr<nsICycleCollectorLogSink> mSink;
447 nsCOMPtr<nsIDumpGCAndCCLogsCallback> mCallback;
448 };
449
450 // A memory reporter for ContentParent objects themselves.
451 class ContentParentsMemoryReporter final : public nsIMemoryReporter {
452 ~ContentParentsMemoryReporter() = default;
453
454 public:
455 NS_DECL_ISUPPORTS
456 NS_DECL_NSIMEMORYREPORTER
457 };
458
NS_IMPL_ISUPPORTS(ContentParentsMemoryReporter,nsIMemoryReporter)459 NS_IMPL_ISUPPORTS(ContentParentsMemoryReporter, nsIMemoryReporter)
460
461 NS_IMETHODIMP
462 ContentParentsMemoryReporter::CollectReports(
463 nsIHandleReportCallback* aHandleReport, nsISupports* aData,
464 bool aAnonymize) {
465 AutoTArray<ContentParent*, 16> cps;
466 ContentParent::GetAllEvenIfDead(cps);
467
468 for (uint32_t i = 0; i < cps.Length(); i++) {
469 ContentParent* cp = cps[i];
470 MessageChannel* channel = cp->GetIPCChannel();
471
472 nsString friendlyName;
473 cp->FriendlyName(friendlyName, aAnonymize);
474
475 cp->AddRef();
476 nsrefcnt refcnt = cp->Release();
477
478 const char* channelStr = "no channel";
479 uint32_t numQueuedMessages = 0;
480 if (channel) {
481 if (channel->IsClosed()) {
482 channelStr = "closed channel";
483 } else {
484 channelStr = "open channel";
485 }
486 numQueuedMessages =
487 0; // XXX was channel->Unsound_NumQueuedMessages(); Bug 1754876
488 }
489
490 nsPrintfCString path(
491 "queued-ipc-messages/content-parent"
492 "(%s, pid=%d, %s, 0x%p, refcnt=%" PRIuPTR ")",
493 NS_ConvertUTF16toUTF8(friendlyName).get(), cp->Pid(), channelStr,
494 static_cast<nsIObserver*>(cp), refcnt);
495
496 constexpr auto desc =
497 "The number of unset IPC messages held in this ContentParent's "
498 "channel. A large value here might indicate that we're leaking "
499 "messages. Similarly, a ContentParent object for a process that's no "
500 "longer running could indicate that we're leaking ContentParents."_ns;
501
502 aHandleReport->Callback(/* process */ ""_ns, path, KIND_OTHER, UNITS_COUNT,
503 numQueuedMessages, desc, aData);
504 }
505
506 return NS_OK;
507 }
508
509 // A hashtable (by type) of processes/ContentParents. This includes
510 // processes that are in the Preallocator cache (which would be type
511 // 'prealloc'), and recycled processes ('web' and in the future
512 // eTLD+1-locked) processes).
513 nsClassHashtable<nsCStringHashKey, nsTArray<ContentParent*>>*
514 ContentParent::sBrowserContentParents;
515
516 namespace {
517
ComputeLoadedOriginHash(nsIPrincipal * aPrincipal)518 uint64_t ComputeLoadedOriginHash(nsIPrincipal* aPrincipal) {
519 uint32_t originNoSuffix =
520 BasePrincipal::Cast(aPrincipal)->GetOriginNoSuffixHash();
521 uint32_t originSuffix =
522 BasePrincipal::Cast(aPrincipal)->GetOriginSuffixHash();
523
524 return ((uint64_t)originNoSuffix) << 32 | originSuffix;
525 }
526
527 class ScriptableCPInfo final : public nsIContentProcessInfo {
528 public:
ScriptableCPInfo(ContentParent * aParent)529 explicit ScriptableCPInfo(ContentParent* aParent) : mContentParent(aParent) {
530 MOZ_ASSERT(mContentParent);
531 }
532
533 NS_DECL_ISUPPORTS
534 NS_DECL_NSICONTENTPROCESSINFO
535
ProcessDied()536 void ProcessDied() { mContentParent = nullptr; }
537
538 private:
~ScriptableCPInfo()539 ~ScriptableCPInfo() { MOZ_ASSERT(!mContentParent, "must call ProcessDied"); }
540
541 ContentParent* mContentParent;
542 };
543
NS_IMPL_ISUPPORTS(ScriptableCPInfo,nsIContentProcessInfo)544 NS_IMPL_ISUPPORTS(ScriptableCPInfo, nsIContentProcessInfo)
545
546 NS_IMETHODIMP
547 ScriptableCPInfo::GetIsAlive(bool* aIsAlive) {
548 *aIsAlive = mContentParent != nullptr;
549 return NS_OK;
550 }
551
552 NS_IMETHODIMP
GetProcessId(int32_t * aPID)553 ScriptableCPInfo::GetProcessId(int32_t* aPID) {
554 if (!mContentParent) {
555 *aPID = -1;
556 return NS_ERROR_NOT_INITIALIZED;
557 }
558
559 *aPID = mContentParent->Pid();
560 if (*aPID == -1) {
561 return NS_ERROR_FAILURE;
562 }
563
564 return NS_OK;
565 }
566
567 NS_IMETHODIMP
GetTabCount(int32_t * aTabCount)568 ScriptableCPInfo::GetTabCount(int32_t* aTabCount) {
569 if (!mContentParent) {
570 return NS_ERROR_NOT_INITIALIZED;
571 }
572
573 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
574 *aTabCount = cpm->GetBrowserParentCountByProcessId(mContentParent->ChildID());
575
576 return NS_OK;
577 }
578
579 NS_IMETHODIMP
GetMessageManager(nsISupports ** aMessenger)580 ScriptableCPInfo::GetMessageManager(nsISupports** aMessenger) {
581 *aMessenger = nullptr;
582 if (!mContentParent) {
583 return NS_ERROR_NOT_INITIALIZED;
584 }
585
586 RefPtr<ProcessMessageManager> manager = mContentParent->GetMessageManager();
587 manager.forget(aMessenger);
588 return NS_OK;
589 }
590
GetTelemetryProcessID(const nsACString & remoteType)591 ProcessID GetTelemetryProcessID(const nsACString& remoteType) {
592 // OOP WebExtensions run in a content process.
593 // For Telemetry though we want to break out collected data from the
594 // WebExtensions process into a separate bucket, to make sure we can analyze
595 // it separately and avoid skewing normal content process metrics.
596 return remoteType == EXTENSION_REMOTE_TYPE ? ProcessID::Extension
597 : ProcessID::Content;
598 }
599
600 } // anonymous namespace
601
602 UniquePtr<nsTHashMap<nsUint32HashKey, ContentParent*>>
603 ContentParent::sJSPluginContentParents;
604 UniquePtr<nsTArray<ContentParent*>> ContentParent::sPrivateContent;
605 UniquePtr<LinkedList<ContentParent>> ContentParent::sContentParents;
606 StaticRefPtr<ContentParent> ContentParent::sRecycledE10SProcess;
607 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
608 UniquePtr<SandboxBrokerPolicyFactory>
609 ContentParent::sSandboxBrokerPolicyFactory;
610 #endif
611 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
612 UniquePtr<std::vector<std::string>> ContentParent::sMacSandboxParams;
613 #endif
614
615 // This is true when subprocess launching is enabled. This is the
616 // case between StartUp() and ShutDown().
617 static bool sCanLaunchSubprocesses;
618
619 // Set to true when the first content process gets created.
620 static bool sCreatedFirstContentProcess = false;
621
622 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
623 // True when we're running the process selection code, and do not expect to
624 // enter code paths where processes may die.
625 static bool sInProcessSelector = false;
626 #endif
627
628 // The first content child has ID 1, so the chrome process can have ID 0.
629 static uint64_t gContentChildID = 1;
630
631 static const char* sObserverTopics[] = {
632 NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
633 NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
634 NS_IPC_CAPTIVE_PORTAL_SET_STATE,
635 "application-background",
636 "application-foreground",
637 "memory-pressure",
638 "child-gc-request",
639 "child-cc-request",
640 "child-mmu-request",
641 "child-ghost-request",
642 "last-pb-context-exited",
643 "file-watcher-update",
644 #ifdef ACCESSIBILITY
645 "a11y-init-or-shutdown",
646 #endif
647 "cacheservice:empty-cache",
648 "intl:app-locales-changed",
649 "intl:requested-locales-changed",
650 "cookie-changed",
651 "private-cookie-changed",
652 NS_NETWORK_LINK_TYPE_TOPIC,
653 "network:socket-process-crashed",
654 };
655
656 // PreallocateProcess is called by the PreallocatedProcessManager.
657 // ContentParent then takes this process back within GetNewOrUsedBrowserProcess.
658 /*static*/ already_AddRefed<ContentParent>
MakePreallocProcess()659 ContentParent::MakePreallocProcess() {
660 RefPtr<ContentParent> process = new ContentParent(PREALLOC_REMOTE_TYPE);
661 return process.forget();
662 }
663
664 /*static*/
StartUp()665 void ContentParent::StartUp() {
666 // We could launch sub processes from content process
667 // FIXME Bug 1023701 - Stop using ContentParent static methods in
668 // child process
669 sCanLaunchSubprocesses = true;
670
671 if (!XRE_IsParentProcess()) {
672 return;
673 }
674
675 // From this point on, NS_WARNING, NS_ASSERTION, etc. should print out the
676 // PID along with the warning.
677 nsDebugImpl::SetMultiprocessMode("Parent");
678
679 // Note: This reporter measures all ContentParents.
680 RegisterStrongMemoryReporter(new ContentParentsMemoryReporter());
681
682 BackgroundChild::Startup();
683 ClientManager::Startup();
684
685 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
686 sSandboxBrokerPolicyFactory = MakeUnique<SandboxBrokerPolicyFactory>();
687 #endif
688
689 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
690 sMacSandboxParams = MakeUnique<std::vector<std::string>>();
691 #endif
692 }
693
694 /*static*/
ShutDown()695 void ContentParent::ShutDown() {
696 // No-op for now. We rely on normal process shutdown and
697 // ClearOnShutdown() to clean up our state.
698 sCanLaunchSubprocesses = false;
699
700 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
701 sSandboxBrokerPolicyFactory = nullptr;
702 #endif
703
704 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
705 sMacSandboxParams = nullptr;
706 #endif
707 }
708
709 /*static*/
GetPoolSize(const nsACString & aContentProcessType)710 uint32_t ContentParent::GetPoolSize(const nsACString& aContentProcessType) {
711 if (!sBrowserContentParents) {
712 return 0;
713 }
714
715 nsTArray<ContentParent*>* parents =
716 sBrowserContentParents->Get(aContentProcessType);
717
718 return parents ? parents->Length() : 0;
719 }
720
GetOrCreatePool(const nsACString & aContentProcessType)721 /*static*/ nsTArray<ContentParent*>& ContentParent::GetOrCreatePool(
722 const nsACString& aContentProcessType) {
723 if (!sBrowserContentParents) {
724 sBrowserContentParents =
725 new nsClassHashtable<nsCStringHashKey, nsTArray<ContentParent*>>;
726 }
727
728 return *sBrowserContentParents->GetOrInsertNew(aContentProcessType);
729 }
730
RemoteTypePrefix(const nsACString & aContentProcessType)731 const nsDependentCSubstring RemoteTypePrefix(
732 const nsACString& aContentProcessType) {
733 // The suffix after a `=` in a remoteType is dynamic, and used to control the
734 // process pool to use.
735 int32_t equalIdx = aContentProcessType.FindChar(L'=');
736 if (equalIdx == kNotFound) {
737 equalIdx = aContentProcessType.Length();
738 }
739 return StringHead(aContentProcessType, equalIdx);
740 }
741
IsWebRemoteType(const nsACString & aContentProcessType)742 bool IsWebRemoteType(const nsACString& aContentProcessType) {
743 // Note: matches webIsolated as well as web (and webLargeAllocation, and
744 // webCOOP+COEP)
745 return StringBeginsWith(aContentProcessType, DEFAULT_REMOTE_TYPE);
746 }
747
IsWebCoopCoepRemoteType(const nsACString & aContentProcessType)748 bool IsWebCoopCoepRemoteType(const nsACString& aContentProcessType) {
749 return StringBeginsWith(aContentProcessType,
750 WITH_COOP_COEP_REMOTE_TYPE_PREFIX);
751 }
752
IsPrivilegedMozillaRemoteType(const nsACString & aContentProcessType)753 bool IsPrivilegedMozillaRemoteType(const nsACString& aContentProcessType) {
754 return aContentProcessType == PRIVILEGEDMOZILLA_REMOTE_TYPE;
755 }
756
IsExtensionRemoteType(const nsACString & aContentProcessType)757 bool IsExtensionRemoteType(const nsACString& aContentProcessType) {
758 return aContentProcessType == EXTENSION_REMOTE_TYPE;
759 }
760
761 /*static*/
GetMaxProcessCount(const nsACString & aContentProcessType)762 uint32_t ContentParent::GetMaxProcessCount(
763 const nsACString& aContentProcessType) {
764 // Max process count is based only on the prefix.
765 const nsDependentCSubstring processTypePrefix =
766 RemoteTypePrefix(aContentProcessType);
767
768 // Check for the default remote type of "web", as it uses different prefs.
769 if (processTypePrefix == DEFAULT_REMOTE_TYPE) {
770 return GetMaxWebProcessCount();
771 }
772
773 // Read the pref controling this remote type. `dom.ipc.processCount` is not
774 // used as a fallback, as it is intended to control the number of "web"
775 // content processes, checked in `mozilla::GetMaxWebProcessCount()`.
776 nsAutoCString processCountPref("dom.ipc.processCount.");
777 processCountPref.Append(processTypePrefix);
778
779 int32_t maxContentParents = Preferences::GetInt(processCountPref.get(), 1);
780 if (maxContentParents < 1) {
781 maxContentParents = 1;
782 }
783
784 return static_cast<uint32_t>(maxContentParents);
785 }
786
787 /*static*/
IsMaxProcessCountReached(const nsACString & aContentProcessType)788 bool ContentParent::IsMaxProcessCountReached(
789 const nsACString& aContentProcessType) {
790 return GetPoolSize(aContentProcessType) >=
791 GetMaxProcessCount(aContentProcessType);
792 }
793
794 // Really more ReleaseUnneededProcesses()
795 /*static*/
ReleaseCachedProcesses()796 void ContentParent::ReleaseCachedProcesses() {
797 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
798 ("ReleaseCachedProcesses:"));
799 if (!sBrowserContentParents) {
800 return;
801 }
802
803 #ifdef DEBUG
804 for (const auto& cps : *sBrowserContentParents) {
805 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
806 ("%s: %zu processes", PromiseFlatCString(cps.GetKey()).get(),
807 cps.GetData()->Length()));
808 }
809 #endif
810 // We process the toRelease array outside of the iteration to avoid modifying
811 // the list (via RemoveFromList()) while we're iterating it.
812 nsTArray<ContentParent*> toRelease;
813 for (const auto& contentParents : sBrowserContentParents->Values()) {
814 // Shutting down these processes will change the array so let's use another
815 // array for the removal.
816 for (auto* cp : *contentParents) {
817 if (cp->ManagedPBrowserParent().Count() == 0 &&
818 !cp->HasActiveWorkerOrJSPlugin() &&
819 cp->mRemoteType == DEFAULT_REMOTE_TYPE) {
820 toRelease.AppendElement(cp);
821 } else {
822 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
823 (" Skipping %p (%s), count %d, HasActiveWorkerOrJSPlugin %d",
824 cp, cp->mRemoteType.get(), cp->ManagedPBrowserParent().Count(),
825 cp->HasActiveWorkerOrJSPlugin()));
826 }
827 }
828 }
829
830 for (auto* cp : toRelease) {
831 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
832 (" Shutdown %p (%s)", cp, cp->mRemoteType.get()));
833 PreallocatedProcessManager::Erase(cp);
834 // Start a soft shutdown.
835 cp->ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
836 // Make sure we don't select this process for new tabs.
837 cp->MarkAsDead();
838 // Make sure that this process is no longer accessible from JS by its
839 // message manager.
840 cp->ShutDownMessageManager();
841 }
842 }
843
844 /*static*/
MinTabSelect(const nsTArray<ContentParent * > & aContentParents,int32_t aMaxContentParents)845 already_AddRefed<ContentParent> ContentParent::MinTabSelect(
846 const nsTArray<ContentParent*>& aContentParents,
847 int32_t aMaxContentParents) {
848 uint32_t maxSelectable =
849 std::min(static_cast<uint32_t>(aContentParents.Length()),
850 static_cast<uint32_t>(aMaxContentParents));
851 uint32_t min = INT_MAX;
852 RefPtr<ContentParent> candidate;
853 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
854
855 for (uint32_t i = 0; i < maxSelectable; i++) {
856 ContentParent* p = aContentParents[i];
857 MOZ_DIAGNOSTIC_ASSERT(!p->IsDead());
858
859 uint32_t tabCount = cpm->GetBrowserParentCountByProcessId(p->ChildID());
860 if (tabCount < min) {
861 candidate = p;
862 min = tabCount;
863 }
864 }
865
866 // If all current processes have at least one tab and we have not yet reached
867 // the maximum, use a new process.
868 if (min > 0 &&
869 aContentParents.Length() < static_cast<uint32_t>(aMaxContentParents)) {
870 return nullptr;
871 }
872
873 // Otherwise we return candidate.
874 return candidate.forget();
875 }
876
877 /* static */
878 already_AddRefed<nsIPrincipal>
CreateRemoteTypeIsolationPrincipal(const nsACString & aRemoteType)879 ContentParent::CreateRemoteTypeIsolationPrincipal(
880 const nsACString& aRemoteType) {
881 if ((RemoteTypePrefix(aRemoteType) != FISSION_WEB_REMOTE_TYPE) &&
882 !StringBeginsWith(aRemoteType, WITH_COOP_COEP_REMOTE_TYPE_PREFIX)) {
883 return nullptr;
884 }
885
886 int32_t offset = aRemoteType.FindChar('=') + 1;
887 MOZ_ASSERT(offset > 1, "can not extract origin from that remote type");
888 nsAutoCString origin(
889 Substring(aRemoteType, offset, aRemoteType.Length() - offset));
890
891 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
892 nsCOMPtr<nsIPrincipal> principal;
893 ssm->CreateContentPrincipalFromOrigin(origin, getter_AddRefs(principal));
894 return principal.forget();
895 }
896
897 /*static*/
GetUsedBrowserProcess(const nsACString & aRemoteType,nsTArray<ContentParent * > & aContentParents,uint32_t aMaxContentParents,bool aPreferUsed,ProcessPriority aPriority)898 already_AddRefed<ContentParent> ContentParent::GetUsedBrowserProcess(
899 const nsACString& aRemoteType, nsTArray<ContentParent*>& aContentParents,
900 uint32_t aMaxContentParents, bool aPreferUsed, ProcessPriority aPriority) {
901 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
902 AutoRestore ar(sInProcessSelector);
903 sInProcessSelector = true;
904 #endif
905
906 uint32_t numberOfParents = aContentParents.Length();
907 nsTArray<RefPtr<nsIContentProcessInfo>> infos(numberOfParents);
908 for (auto* cp : aContentParents) {
909 infos.AppendElement(cp->mScriptableHelper);
910 }
911
912 if (aPreferUsed && numberOfParents) {
913 // If we prefer re-using existing content processes, we don't want to create
914 // a new process, and instead re-use an existing one, so pretend the process
915 // limit is at the current number of processes.
916 aMaxContentParents = numberOfParents;
917 }
918
919 nsCOMPtr<nsIContentProcessProvider> cpp =
920 do_GetService("@mozilla.org/ipc/processselector;1");
921 int32_t index;
922 if (cpp && NS_SUCCEEDED(cpp->ProvideProcess(aRemoteType, infos,
923 aMaxContentParents, &index))) {
924 // If the provider returned an existing ContentParent, use that one.
925 if (0 <= index && static_cast<uint32_t>(index) <= aMaxContentParents) {
926 RefPtr<ContentParent> retval = aContentParents[index];
927 if (profiler_thread_is_being_profiled_for_markers()) {
928 nsPrintfCString marker("Reused process %u",
929 (unsigned int)retval->ChildID());
930 PROFILER_MARKER_TEXT("Process", DOM, {}, marker);
931 }
932 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
933 ("GetUsedProcess: Reused process %p (%u) for %s", retval.get(),
934 (unsigned int)retval->ChildID(),
935 PromiseFlatCString(aRemoteType).get()));
936 retval->AssertAlive();
937 retval->StopRecycling();
938 return retval.forget();
939 }
940 } else {
941 // If there was a problem with the JS chooser, fall back to a random
942 // selection.
943 NS_WARNING("nsIContentProcessProvider failed to return a process");
944 RefPtr<ContentParent> random;
945 if ((random = MinTabSelect(aContentParents, aMaxContentParents))) {
946 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
947 ("GetUsedProcess: Reused random process %p (%d) for %s",
948 random.get(), (unsigned int)random->ChildID(),
949 PromiseFlatCString(aRemoteType).get()));
950 random->AssertAlive();
951 random->StopRecycling();
952 return random.forget();
953 }
954 }
955
956 // If we are loading into the "web" remote type, are choosing to launch a new
957 // tab, and have a recycled E10S process, we should launch into that process.
958 if (aRemoteType == DEFAULT_REMOTE_TYPE && sRecycledE10SProcess) {
959 RefPtr<ContentParent> recycled = sRecycledE10SProcess;
960 MOZ_DIAGNOSTIC_ASSERT(recycled->GetRemoteType() == DEFAULT_REMOTE_TYPE);
961 recycled->AssertAlive();
962 recycled->StopRecycling();
963
964 if (profiler_thread_is_being_profiled_for_markers()) {
965 nsPrintfCString marker("Recycled process %u (%p)",
966 (unsigned int)recycled->ChildID(), recycled.get());
967 PROFILER_MARKER_TEXT("Process", DOM, {}, marker);
968 }
969 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
970 ("Recycled process %p", recycled.get()));
971
972 return recycled.forget();
973 }
974
975 // Try to take a preallocated process except for certain remote types.
976 // Note: this process may not have finished launching yet
977 RefPtr<ContentParent> preallocated;
978 if (aRemoteType != FILE_REMOTE_TYPE &&
979 aRemoteType != EXTENSION_REMOTE_TYPE && // Bug 1638119
980 (preallocated = PreallocatedProcessManager::Take(aRemoteType))) {
981 MOZ_DIAGNOSTIC_ASSERT(preallocated->GetRemoteType() ==
982 PREALLOC_REMOTE_TYPE);
983 MOZ_DIAGNOSTIC_ASSERT(sRecycledE10SProcess != preallocated);
984 preallocated->AssertAlive();
985
986 if (profiler_thread_is_being_profiled_for_markers()) {
987 nsPrintfCString marker(
988 "Assigned preallocated process %u%s",
989 (unsigned int)preallocated->ChildID(),
990 preallocated->IsLaunching() ? " (still launching)" : "");
991 PROFILER_MARKER_TEXT("Process", DOM, {}, marker);
992 }
993 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
994 ("Adopted preallocated process %p for type %s%s",
995 preallocated.get(), PromiseFlatCString(aRemoteType).get(),
996 preallocated->IsLaunching() ? " (still launching)" : ""));
997
998 // This ensures that the preallocator won't shut down the process once
999 // it finishes starting
1000 preallocated->mRemoteType.Assign(aRemoteType);
1001 preallocated->mRemoteTypeIsolationPrincipal =
1002 CreateRemoteTypeIsolationPrincipal(aRemoteType);
1003 preallocated->mActivateTS = TimeStamp::Now();
1004 preallocated->AddToPool(aContentParents);
1005
1006 // rare, but will happen
1007 if (!preallocated->IsLaunching()) {
1008 // Specialize this process for the appropriate remote type, and activate
1009 // it.
1010 Unused << preallocated->SendRemoteType(preallocated->mRemoteType);
1011
1012 nsCOMPtr<nsIObserverService> obs =
1013 mozilla::services::GetObserverService();
1014 if (obs) {
1015 nsAutoString cpId;
1016 cpId.AppendInt(static_cast<uint64_t>(preallocated->ChildID()));
1017 obs->NotifyObservers(static_cast<nsIObserver*>(preallocated),
1018 "process-type-set", cpId.get());
1019 preallocated->AssertAlive();
1020 }
1021 }
1022 return preallocated.forget();
1023 }
1024
1025 return nullptr;
1026 }
1027
1028 /*static*/
1029 already_AddRefed<ContentParent>
GetNewOrUsedLaunchingBrowserProcess(const nsACString & aRemoteType,BrowsingContextGroup * aGroup,ProcessPriority aPriority,bool aPreferUsed)1030 ContentParent::GetNewOrUsedLaunchingBrowserProcess(
1031 const nsACString& aRemoteType, BrowsingContextGroup* aGroup,
1032 ProcessPriority aPriority, bool aPreferUsed) {
1033 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1034 ("GetNewOrUsedProcess for type %s",
1035 PromiseFlatCString(aRemoteType).get()));
1036
1037 // If we have an existing host process attached to this BrowsingContextGroup,
1038 // always return it, as we can never have multiple host processes within a
1039 // single BrowsingContextGroup.
1040 RefPtr<ContentParent> contentParent;
1041 if (aGroup) {
1042 contentParent = aGroup->GetHostProcess(aRemoteType);
1043 if (contentParent) {
1044 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1045 ("GetNewOrUsedProcess: Existing host process %p (launching %d)",
1046 contentParent.get(), contentParent->IsLaunching()));
1047 contentParent->AssertAlive();
1048 contentParent->StopRecycling();
1049 return contentParent.forget();
1050 }
1051 }
1052
1053 nsTArray<ContentParent*>& contentParents = GetOrCreatePool(aRemoteType);
1054 uint32_t maxContentParents = GetMaxProcessCount(aRemoteType);
1055 // We never want to re-use Large-Allocation processes.
1056 if (aRemoteType == LARGE_ALLOCATION_REMOTE_TYPE &&
1057 contentParents.Length() >= maxContentParents) {
1058 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1059 ("GetNewOrUsedProcess: returning Large Used process"));
1060 return GetNewOrUsedLaunchingBrowserProcess(DEFAULT_REMOTE_TYPE, aGroup,
1061 aPriority,
1062 /*aPreferUsed =*/false);
1063 }
1064
1065 // Let's try and reuse an existing process.
1066 contentParent = GetUsedBrowserProcess(
1067 aRemoteType, contentParents, maxContentParents, aPreferUsed, aPriority);
1068
1069 if (!contentParent) {
1070 // No reusable process. Let's create and launch one.
1071 // The life cycle will be set to `LifecycleState::LAUNCHING`.
1072 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1073 ("Launching new process immediately for type %s",
1074 PromiseFlatCString(aRemoteType).get()));
1075
1076 contentParent = new ContentParent(aRemoteType);
1077 if (NS_WARN_IF(!contentParent->BeginSubprocessLaunch(aPriority))) {
1078 // Launch aborted because of shutdown. Bailout.
1079 contentParent->LaunchSubprocessReject();
1080 return nullptr;
1081 }
1082 // Until the new process is ready let's not allow to start up any
1083 // preallocated processes. The blocker will be removed once we receive
1084 // the first idle message.
1085 contentParent->mIsAPreallocBlocker = true;
1086 PreallocatedProcessManager::AddBlocker(aRemoteType, contentParent);
1087
1088 // Store this process for future reuse.
1089 contentParent->AddToPool(contentParents);
1090
1091 MOZ_LOG(
1092 ContentParent::GetLog(), LogLevel::Debug,
1093 ("GetNewOrUsedProcess: new immediate process %p", contentParent.get()));
1094 }
1095 // else we have an existing or preallocated process (which may be
1096 // still launching)
1097
1098 contentParent->AssertAlive();
1099 contentParent->StopRecycling();
1100 if (aGroup) {
1101 aGroup->EnsureHostProcess(contentParent);
1102 }
1103 return contentParent.forget();
1104 }
1105
1106 /*static*/
1107 RefPtr<ContentParent::LaunchPromise>
GetNewOrUsedBrowserProcessAsync(const nsACString & aRemoteType,BrowsingContextGroup * aGroup,ProcessPriority aPriority,bool aPreferUsed)1108 ContentParent::GetNewOrUsedBrowserProcessAsync(const nsACString& aRemoteType,
1109 BrowsingContextGroup* aGroup,
1110 ProcessPriority aPriority,
1111 bool aPreferUsed) {
1112 // Obtain a `ContentParent` launched asynchronously.
1113 RefPtr<ContentParent> contentParent = GetNewOrUsedLaunchingBrowserProcess(
1114 aRemoteType, aGroup, aPriority, aPreferUsed);
1115 if (!contentParent) {
1116 // In case of launch error, stop here.
1117 return LaunchPromise::CreateAndReject(LaunchError(), __func__);
1118 }
1119 return contentParent->WaitForLaunchAsync(aPriority);
1120 }
1121
1122 /*static*/
GetNewOrUsedBrowserProcess(const nsACString & aRemoteType,BrowsingContextGroup * aGroup,ProcessPriority aPriority,bool aPreferUsed)1123 already_AddRefed<ContentParent> ContentParent::GetNewOrUsedBrowserProcess(
1124 const nsACString& aRemoteType, BrowsingContextGroup* aGroup,
1125 ProcessPriority aPriority, bool aPreferUsed) {
1126 RefPtr<ContentParent> contentParent = GetNewOrUsedLaunchingBrowserProcess(
1127 aRemoteType, aGroup, aPriority, aPreferUsed);
1128 if (!contentParent || !contentParent->WaitForLaunchSync(aPriority)) {
1129 // In case of launch error, stop here.
1130 return nullptr;
1131 }
1132 return contentParent.forget();
1133 }
1134
WaitForLaunchAsync(ProcessPriority aPriority)1135 RefPtr<ContentParent::LaunchPromise> ContentParent::WaitForLaunchAsync(
1136 ProcessPriority aPriority) {
1137 MOZ_DIAGNOSTIC_ASSERT(!IsDead());
1138 if (!IsLaunching()) {
1139 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1140 ("WaitForLaunchAsync: launched"));
1141 return LaunchPromise::CreateAndResolve(this, __func__);
1142 }
1143
1144 // We've started an async content process launch.
1145 Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC, 0);
1146
1147 // We have located a process that hasn't finished initializing, then attempt
1148 // to finish initializing. Both `LaunchSubprocessResolve` and
1149 // `LaunchSubprocessReject` are safe to call multiple times if we race with
1150 // other `WaitForLaunchAsync` callbacks.
1151 return mSubprocess->WhenProcessHandleReady()->Then(
1152 GetCurrentSerialEventTarget(), __func__,
1153 [self = RefPtr{this}, aPriority] {
1154 if (self->LaunchSubprocessResolve(/* aIsSync = */ false, aPriority)) {
1155 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1156 ("WaitForLaunchAsync: async, now launched"));
1157 self->mActivateTS = TimeStamp::Now();
1158 return LaunchPromise::CreateAndResolve(self, __func__);
1159 }
1160
1161 self->LaunchSubprocessReject();
1162 return LaunchPromise::CreateAndReject(LaunchError(), __func__);
1163 },
1164 [self = RefPtr{this}] {
1165 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1166 ("WaitForLaunchAsync: async, rejected"));
1167 self->LaunchSubprocessReject();
1168 return LaunchPromise::CreateAndReject(LaunchError(), __func__);
1169 });
1170 }
1171
WaitForLaunchSync(ProcessPriority aPriority)1172 bool ContentParent::WaitForLaunchSync(ProcessPriority aPriority) {
1173 MOZ_DIAGNOSTIC_ASSERT(!IsDead());
1174 if (!IsLaunching()) {
1175 return true;
1176 }
1177
1178 // We've started a sync content process launch.
1179 Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC, 1);
1180
1181 // We're a process which hasn't finished initializing. We may be racing
1182 // against whoever launched it (and whoever else is already racing). Since
1183 // we're sync, we win the race and finish the initialization.
1184 bool launchSuccess = mSubprocess->WaitForProcessHandle();
1185 if (launchSuccess &&
1186 LaunchSubprocessResolve(/* aIsSync = */ true, aPriority)) {
1187 mActivateTS = TimeStamp::Now();
1188 return true;
1189 }
1190 // In case of failure.
1191 LaunchSubprocessReject();
1192 return false;
1193 }
1194
1195 /*static*/
GetNewOrUsedJSPluginProcess(uint32_t aPluginID,const hal::ProcessPriority & aPriority)1196 already_AddRefed<ContentParent> ContentParent::GetNewOrUsedJSPluginProcess(
1197 uint32_t aPluginID, const hal::ProcessPriority& aPriority) {
1198 RefPtr<ContentParent> p;
1199 if (sJSPluginContentParents) {
1200 p = sJSPluginContentParents->Get(aPluginID);
1201 } else {
1202 sJSPluginContentParents =
1203 MakeUnique<nsTHashMap<nsUint32HashKey, ContentParent*>>();
1204 }
1205
1206 if (p) {
1207 return p.forget();
1208 }
1209
1210 p = new ContentParent(aPluginID);
1211
1212 if (!p->LaunchSubprocessSync(aPriority)) {
1213 return nullptr;
1214 }
1215
1216 sJSPluginContentParents->InsertOrUpdate(aPluginID, p);
1217
1218 return p.forget();
1219 }
1220
1221 #if defined(XP_WIN)
1222 /*static*/
SendAsyncUpdate(nsIWidget * aWidget)1223 void ContentParent::SendAsyncUpdate(nsIWidget* aWidget) {}
1224 #endif // defined(XP_WIN)
1225
GetOpenerDocShellHelper(Element * aFrameElement)1226 static nsIDocShell* GetOpenerDocShellHelper(Element* aFrameElement) {
1227 // Propagate the private-browsing status of the element's parent
1228 // docshell to the remote docshell, via the chrome flags.
1229 MOZ_ASSERT(aFrameElement);
1230 nsPIDOMWindowOuter* win = aFrameElement->OwnerDoc()->GetWindow();
1231 if (!win) {
1232 NS_WARNING("Remote frame has no window");
1233 return nullptr;
1234 }
1235 nsIDocShell* docShell = win->GetDocShell();
1236 if (!docShell) {
1237 NS_WARNING("Remote frame has no docshell");
1238 return nullptr;
1239 }
1240
1241 return docShell;
1242 }
1243
RecvCreateGMPService()1244 mozilla::ipc::IPCResult ContentParent::RecvCreateGMPService() {
1245 Endpoint<PGMPServiceParent> parent;
1246 Endpoint<PGMPServiceChild> child;
1247
1248 nsresult rv;
1249 rv = PGMPService::CreateEndpoints(base::GetCurrentProcId(), OtherPid(),
1250 &parent, &child);
1251 if (NS_FAILED(rv)) {
1252 MOZ_ASSERT(false, "CreateEndpoints failed");
1253 return IPC_FAIL_NO_REASON(this);
1254 }
1255
1256 if (!GMPServiceParent::Create(std::move(parent))) {
1257 MOZ_ASSERT(false, "GMPServiceParent::Create failed");
1258 return IPC_FAIL_NO_REASON(this);
1259 }
1260
1261 if (!SendInitGMPService(std::move(child))) {
1262 MOZ_ASSERT(false, "SendInitGMPService failed");
1263 return IPC_FAIL_NO_REASON(this);
1264 }
1265
1266 return IPC_OK();
1267 }
1268
RecvUngrabPointer(const uint32_t & aTime)1269 mozilla::ipc::IPCResult ContentParent::RecvUngrabPointer(
1270 const uint32_t& aTime) {
1271 #if !defined(MOZ_WIDGET_GTK)
1272 MOZ_CRASH("This message only makes sense on GTK platforms");
1273 #else
1274 gdk_pointer_ungrab(aTime);
1275 return IPC_OK();
1276 #endif
1277 }
1278
1279 Atomic<bool, mozilla::Relaxed> sContentParentTelemetryEventEnabled(false);
1280
1281 /*static*/
LogAndAssertFailedPrincipalValidationInfo(nsIPrincipal * aPrincipal,const char * aMethod)1282 void ContentParent::LogAndAssertFailedPrincipalValidationInfo(
1283 nsIPrincipal* aPrincipal, const char* aMethod) {
1284 // nsContentSecurityManager may also enable this same event, but that's okay
1285 if (!sContentParentTelemetryEventEnabled.exchange(true)) {
1286 sContentParentTelemetryEventEnabled = true;
1287 Telemetry::SetEventRecordingEnabled("security"_ns, true);
1288 }
1289
1290 // Send Telemetry
1291 nsAutoCString principalScheme, principalType, spec;
1292 CopyableTArray<EventExtraEntry> extra(2);
1293
1294 if (!aPrincipal) {
1295 principalType.AssignLiteral("NullPtr");
1296 } else if (aPrincipal->IsSystemPrincipal()) {
1297 principalType.AssignLiteral("SystemPrincipal");
1298 } else if (aPrincipal->GetIsExpandedPrincipal()) {
1299 principalType.AssignLiteral("ExpandedPrincipal");
1300 } else if (aPrincipal->GetIsContentPrincipal()) {
1301 principalType.AssignLiteral("ContentPrincipal");
1302 aPrincipal->GetSpec(spec);
1303 aPrincipal->GetScheme(principalScheme);
1304
1305 extra.AppendElement(EventExtraEntry{"scheme"_ns, principalScheme});
1306 } else {
1307 principalType.AssignLiteral("Unknown");
1308 }
1309
1310 extra.AppendElement(EventExtraEntry{"principalType"_ns, principalType});
1311
1312 // Do not send telemetry when chrome-debugging is enabled
1313 bool isChromeDebuggingEnabled =
1314 Preferences::GetBool("devtools.chrome.enabled", false);
1315 if (!isChromeDebuggingEnabled) {
1316 Telemetry::EventID eventType =
1317 Telemetry::EventID::Security_Fissionprincipals_Contentparent;
1318 Telemetry::RecordEvent(eventType, mozilla::Some(aMethod),
1319 mozilla::Some(extra));
1320 }
1321
1322 // And log it
1323 MOZ_LOG(
1324 ContentParent::GetLog(), LogLevel::Error,
1325 (" Receiving unexpected Principal (%s) within %s",
1326 aPrincipal && aPrincipal->GetIsContentPrincipal() ? spec.get()
1327 : principalType.get(),
1328 aMethod));
1329
1330 #ifdef DEBUG
1331 // Not only log but also ensure we do not receive an unexpected
1332 // principal when running in debug mode.
1333 MOZ_ASSERT(false, "Receiving unexpected Principal");
1334 #endif
1335 }
1336
ValidatePrincipal(nsIPrincipal * aPrincipal,const EnumSet<ValidatePrincipalOptions> & aOptions)1337 bool ContentParent::ValidatePrincipal(
1338 nsIPrincipal* aPrincipal,
1339 const EnumSet<ValidatePrincipalOptions>& aOptions) {
1340 // If the pref says we should not validate, then there is nothing to do
1341 if (!StaticPrefs::dom_security_enforceIPCBasedPrincipalVetting()) {
1342 return true;
1343 }
1344
1345 // If there is no principal, then there is nothing to validate!
1346 if (!aPrincipal) {
1347 return aOptions.contains(ValidatePrincipalOptions::AllowNullPtr);
1348 }
1349
1350 // We currently do not track relationships between specific null principals
1351 // and content processes, so we can not validate much here - just allow all
1352 // null principals we see because they are generally safe anyway!
1353 if (aPrincipal->GetIsNullPrincipal()) {
1354 return true;
1355 }
1356
1357 // Only allow the system principal if the passed in options flags
1358 // request permitting the system principal.
1359 if (aPrincipal->IsSystemPrincipal()) {
1360 return aOptions.contains(ValidatePrincipalOptions::AllowSystem);
1361 }
1362
1363 // XXXckerschb: we should eliminate the resource carve-out here and always
1364 // validate the Principal, see Bug 1686200: Investigate Principal for pdf.js
1365 if (aPrincipal->SchemeIs("resource")) {
1366 return true;
1367 }
1368
1369 // Validate each inner principal individually, allowing us to catch expanded
1370 // principals containing the system principal, etc.
1371 if (aPrincipal->GetIsExpandedPrincipal()) {
1372 if (!aOptions.contains(ValidatePrincipalOptions::AllowExpanded)) {
1373 return false;
1374 }
1375 // FIXME: There are more constraints on expanded principals in-practice,
1376 // such as the structure of extension expanded principals. This may need
1377 // to be investigated more in the future.
1378 nsCOMPtr<nsIExpandedPrincipal> expandedPrincipal =
1379 do_QueryInterface(aPrincipal);
1380 const auto& allowList = expandedPrincipal->AllowList();
1381 for (const auto& innerPrincipal : allowList) {
1382 if (!ValidatePrincipal(innerPrincipal, aOptions)) {
1383 return false;
1384 }
1385 }
1386 return true;
1387 }
1388
1389 // A URI with a file:// scheme can never load in a non-file content process
1390 // due to sandboxing.
1391 if (aPrincipal->SchemeIs("file")) {
1392 // If we don't support a separate 'file' process, then we can return here.
1393 if (!StaticPrefs::browser_tabs_remote_separateFileUriProcess()) {
1394 return true;
1395 }
1396 return mRemoteType == FILE_REMOTE_TYPE;
1397 }
1398
1399 if (aPrincipal->SchemeIs("about")) {
1400 uint32_t flags = 0;
1401 if (NS_FAILED(aPrincipal->GetAboutModuleFlags(&flags))) {
1402 return false;
1403 }
1404
1405 // Block principals for about: URIs which can't load in this process.
1406 if (!(flags & (nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
1407 nsIAboutModule::URI_MUST_LOAD_IN_CHILD))) {
1408 return false;
1409 }
1410 if (flags & nsIAboutModule::URI_MUST_LOAD_IN_EXTENSION_PROCESS) {
1411 return mRemoteType == EXTENSION_REMOTE_TYPE;
1412 }
1413 return true;
1414 }
1415
1416 if (!mRemoteTypeIsolationPrincipal ||
1417 RemoteTypePrefix(mRemoteType) != FISSION_WEB_REMOTE_TYPE) {
1418 return true;
1419 }
1420
1421 // Web content can contain extension content frames, so a content process may
1422 // send us an extension's principal.
1423 auto* addonPolicy = BasePrincipal::Cast(aPrincipal)->AddonPolicy();
1424 if (addonPolicy) {
1425 return true;
1426 }
1427
1428 // Ensure that the expected site-origin matches the one specified by our
1429 // mRemoteTypeIsolationPrincipal.
1430 nsAutoCString siteOriginNoSuffix;
1431 if (NS_FAILED(aPrincipal->GetSiteOriginNoSuffix(siteOriginNoSuffix))) {
1432 return false;
1433 }
1434 nsAutoCString remoteTypeSiteOriginNoSuffix;
1435 if (NS_FAILED(mRemoteTypeIsolationPrincipal->GetSiteOriginNoSuffix(
1436 remoteTypeSiteOriginNoSuffix))) {
1437 return false;
1438 }
1439
1440 return remoteTypeSiteOriginNoSuffix.Equals(siteOriginNoSuffix);
1441 }
1442
RecvRemovePermission(const IPC::Principal & aPrincipal,const nsCString & aPermissionType,nsresult * aRv)1443 mozilla::ipc::IPCResult ContentParent::RecvRemovePermission(
1444 const IPC::Principal& aPrincipal, const nsCString& aPermissionType,
1445 nsresult* aRv) {
1446 if (!ValidatePrincipal(aPrincipal)) {
1447 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
1448 }
1449 *aRv = Permissions::RemovePermission(aPrincipal, aPermissionType);
1450 return IPC_OK();
1451 }
1452
1453 /*static*/
CreateBrowser(const TabContext & aContext,Element * aFrameElement,const nsACString & aRemoteType,BrowsingContext * aBrowsingContext,ContentParent * aOpenerContentParent)1454 already_AddRefed<RemoteBrowser> ContentParent::CreateBrowser(
1455 const TabContext& aContext, Element* aFrameElement,
1456 const nsACString& aRemoteType, BrowsingContext* aBrowsingContext,
1457 ContentParent* aOpenerContentParent) {
1458 AUTO_PROFILER_LABEL("ContentParent::CreateBrowser", OTHER);
1459
1460 MOZ_DIAGNOSTIC_ASSERT(
1461 !aBrowsingContext->Canonical()->GetBrowserParent(),
1462 "BrowsingContext must not have BrowserParent, or have previous "
1463 "BrowserParent cleared");
1464
1465 if (!sCanLaunchSubprocesses) {
1466 return nullptr;
1467 }
1468
1469 nsAutoCString remoteType(aRemoteType);
1470 if (remoteType.IsEmpty()) {
1471 remoteType = DEFAULT_REMOTE_TYPE;
1472 }
1473
1474 TabId tabId(nsContentUtils::GenerateTabId());
1475
1476 nsIDocShell* docShell = GetOpenerDocShellHelper(aFrameElement);
1477 TabId openerTabId;
1478 if (docShell) {
1479 openerTabId = BrowserParent::GetTabIdFrom(docShell);
1480 }
1481
1482 RefPtr<ContentParent> constructorSender;
1483 MOZ_RELEASE_ASSERT(XRE_IsParentProcess(),
1484 "Cannot allocate BrowserParent in content process");
1485 if (aOpenerContentParent && aOpenerContentParent->IsAlive()) {
1486 constructorSender = aOpenerContentParent;
1487 } else {
1488 if (aContext.IsJSPlugin()) {
1489 constructorSender = GetNewOrUsedJSPluginProcess(
1490 aContext.JSPluginId(), PROCESS_PRIORITY_FOREGROUND);
1491 } else {
1492 constructorSender = GetNewOrUsedBrowserProcess(
1493 remoteType, aBrowsingContext->Group(), PROCESS_PRIORITY_FOREGROUND);
1494 }
1495 if (!constructorSender) {
1496 return nullptr;
1497 }
1498 }
1499
1500 aBrowsingContext->SetEmbedderElement(aFrameElement);
1501
1502 // Ensure that the process which we're using to launch is set as the host
1503 // process for this BrowsingContextGroup.
1504 aBrowsingContext->Group()->EnsureHostProcess(constructorSender);
1505
1506 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
1507 docShell->GetTreeOwner(getter_AddRefs(treeOwner));
1508 if (!treeOwner) {
1509 return nullptr;
1510 }
1511
1512 nsCOMPtr<nsIWebBrowserChrome> wbc = do_GetInterface(treeOwner);
1513 if (!wbc) {
1514 return nullptr;
1515 }
1516 uint32_t chromeFlags = 0;
1517 wbc->GetChromeFlags(&chromeFlags);
1518
1519 nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
1520 if (loadContext && loadContext->UsePrivateBrowsing()) {
1521 chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
1522 }
1523 if (loadContext && loadContext->UseRemoteTabs()) {
1524 chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
1525 }
1526 if (loadContext && loadContext->UseRemoteSubframes()) {
1527 chromeFlags |= nsIWebBrowserChrome::CHROME_FISSION_WINDOW;
1528 }
1529
1530 if (tabId == 0) {
1531 return nullptr;
1532 }
1533
1534 aBrowsingContext->Canonical()->SetOwnerProcessId(
1535 constructorSender->ChildID());
1536
1537 RefPtr<BrowserParent> browserParent =
1538 new BrowserParent(constructorSender, tabId, aContext,
1539 aBrowsingContext->Canonical(), chromeFlags);
1540
1541 // Open a remote endpoint for our PBrowser actor.
1542 ManagedEndpoint<PBrowserChild> childEp =
1543 constructorSender->OpenPBrowserEndpoint(browserParent);
1544 if (NS_WARN_IF(!childEp.IsValid())) {
1545 return nullptr;
1546 }
1547
1548 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
1549 cpm->RegisterRemoteFrame(browserParent);
1550
1551 nsCOMPtr<nsIPrincipal> initialPrincipal =
1552 NullPrincipal::Create(aBrowsingContext->OriginAttributesRef());
1553 WindowGlobalInit windowInit = WindowGlobalActor::AboutBlankInitializer(
1554 aBrowsingContext, initialPrincipal);
1555
1556 RefPtr<WindowGlobalParent> windowParent =
1557 WindowGlobalParent::CreateDisconnected(windowInit);
1558 if (NS_WARN_IF(!windowParent)) {
1559 return nullptr;
1560 }
1561
1562 // Open a remote endpoint for the initial PWindowGlobal actor.
1563 ManagedEndpoint<PWindowGlobalChild> windowEp =
1564 browserParent->OpenPWindowGlobalEndpoint(windowParent);
1565 if (NS_WARN_IF(!windowEp.IsValid())) {
1566 return nullptr;
1567 }
1568
1569 // Tell the content process to set up its PBrowserChild.
1570 bool ok = constructorSender->SendConstructBrowser(
1571 std::move(childEp), std::move(windowEp), tabId,
1572 aContext.AsIPCTabContext(), windowInit, chromeFlags,
1573 constructorSender->ChildID(), constructorSender->IsForBrowser(),
1574 /* aIsTopLevel */ true);
1575 if (NS_WARN_IF(!ok)) {
1576 return nullptr;
1577 }
1578
1579 // Ensure that we're marked as the current BrowserParent on our
1580 // CanonicalBrowsingContext.
1581 aBrowsingContext->Canonical()->SetCurrentBrowserParent(browserParent);
1582
1583 windowParent->Init();
1584
1585 RefPtr<BrowserHost> browserHost = new BrowserHost(browserParent);
1586 browserParent->SetOwnerElement(aFrameElement);
1587 return browserHost.forget();
1588 }
1589
GetAll(nsTArray<ContentParent * > & aArray)1590 void ContentParent::GetAll(nsTArray<ContentParent*>& aArray) {
1591 aArray.Clear();
1592
1593 for (auto* cp : AllProcesses(eLive)) {
1594 aArray.AppendElement(cp);
1595 }
1596 }
1597
GetAllEvenIfDead(nsTArray<ContentParent * > & aArray)1598 void ContentParent::GetAllEvenIfDead(nsTArray<ContentParent*>& aArray) {
1599 aArray.Clear();
1600
1601 for (auto* cp : AllProcesses(eAll)) {
1602 aArray.AppendElement(cp);
1603 }
1604 }
1605
BroadcastStringBundle(const StringBundleDescriptor & aBundle)1606 void ContentParent::BroadcastStringBundle(
1607 const StringBundleDescriptor& aBundle) {
1608 AutoTArray<StringBundleDescriptor, 1> array;
1609 array.AppendElement(aBundle);
1610
1611 for (auto* cp : AllProcesses(eLive)) {
1612 Unused << cp->SendRegisterStringBundles(array);
1613 }
1614 }
1615
BroadcastFontListChanged()1616 void ContentParent::BroadcastFontListChanged() {
1617 for (auto* cp : AllProcesses(eLive)) {
1618 Unused << cp->SendFontListChanged();
1619 }
1620 }
1621
BroadcastShmBlockAdded(uint32_t aGeneration,uint32_t aIndex)1622 void ContentParent::BroadcastShmBlockAdded(uint32_t aGeneration,
1623 uint32_t aIndex) {
1624 auto* pfl = gfxPlatformFontList::PlatformFontList();
1625 for (auto* cp : AllProcesses(eLive)) {
1626 base::SharedMemoryHandle handle =
1627 pfl->ShareShmBlockToProcess(aIndex, cp->Pid());
1628 if (handle == base::SharedMemory::NULLHandle()) {
1629 // If something went wrong here, we just skip it; the child will need to
1630 // request the block as needed, at some performance cost.
1631 continue;
1632 }
1633 Unused << cp->SendFontListShmBlockAdded(aGeneration, aIndex,
1634 std::move(handle));
1635 }
1636 }
1637
BroadcastThemeUpdate(widget::ThemeChangeKind aKind)1638 void ContentParent::BroadcastThemeUpdate(widget::ThemeChangeKind aKind) {
1639 const FullLookAndFeel& lnf = *RemoteLookAndFeel::ExtractData();
1640 for (auto* cp : AllProcesses(eLive)) {
1641 Unused << cp->SendThemeChanged(lnf, aKind);
1642 }
1643 }
1644
1645 /*static */
BroadcastMediaCodecsSupportedUpdate(RemoteDecodeIn aLocation,const PDMFactory::MediaCodecsSupported & aSupported)1646 void ContentParent::BroadcastMediaCodecsSupportedUpdate(
1647 RemoteDecodeIn aLocation,
1648 const PDMFactory::MediaCodecsSupported& aSupported) {
1649 sCodecsSupported[aLocation] = aSupported;
1650 for (auto* cp : AllProcesses(eAll)) {
1651 Unused << cp->SendUpdateMediaCodecsSupported(aLocation, aSupported);
1652 }
1653 }
1654
GetRemoteType() const1655 const nsACString& ContentParent::GetRemoteType() const { return mRemoteType; }
1656
Init()1657 void ContentParent::Init() {
1658 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
1659 if (obs) {
1660 size_t length = ArrayLength(sObserverTopics);
1661 for (size_t i = 0; i < length; ++i) {
1662 obs->AddObserver(this, sObserverTopics[i], false);
1663 }
1664 }
1665
1666 AddShutdownBlockers();
1667
1668 if (obs) {
1669 nsAutoString cpId;
1670 cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
1671 obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-created",
1672 cpId.get());
1673 }
1674
1675 #ifdef ACCESSIBILITY
1676 // If accessibility is running in chrome process then start it in content
1677 // process.
1678 if (PresShell::IsAccessibilityActive()) {
1679 # if defined(XP_WIN)
1680 // Don't init content a11y if we detect an incompat version of JAWS in use.
1681 if (!mozilla::a11y::Compatibility::IsOldJAWS()) {
1682 Unused << SendActivateA11y(
1683 ::GetCurrentThreadId(),
1684 a11y::MsaaAccessible::GetContentProcessIdFor(ChildID()));
1685 }
1686 # else
1687 Unused << SendActivateA11y(0, 0);
1688 # endif
1689 }
1690 #endif // #ifdef ACCESSIBILITY
1691
1692 Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
1693
1694 RefPtr<GeckoMediaPluginServiceParent> gmps(
1695 GeckoMediaPluginServiceParent::GetSingleton());
1696 gmps->UpdateContentProcessGMPCapabilities();
1697
1698 // Flush any pref updates that happened during launch and weren't
1699 // included in the blobs set up in BeginSubprocessLaunch.
1700 for (const Pref& pref : mQueuedPrefs) {
1701 Unused << NS_WARN_IF(!SendPreferenceUpdate(pref));
1702 }
1703 mQueuedPrefs.Clear();
1704
1705 Unused << SendInitNextGenLocalStorageEnabled(NextGenLocalStorageEnabled());
1706 }
1707
MaybeBeginShutDown(uint32_t aExpectedBrowserCount,bool aSendShutDown)1708 void ContentParent::MaybeBeginShutDown(uint32_t aExpectedBrowserCount,
1709 bool aSendShutDown) {
1710 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
1711 ("MaybeBeginShutdown %p, %u vs %u", this,
1712 ManagedPBrowserParent().Count(), aExpectedBrowserCount));
1713 MOZ_ASSERT(NS_IsMainThread());
1714
1715 if (ManagedPBrowserParent().Count() != aExpectedBrowserCount ||
1716 ShouldKeepProcessAlive() || TryToRecycle()) {
1717 return;
1718 }
1719
1720 MOZ_LOG(
1721 ContentParent::GetLog(), LogLevel::Debug,
1722 ("Beginning ContentParent Shutdown %p (%s)", this, mRemoteType.get()));
1723
1724 // We're dying now, prevent anything from re-using this process.
1725 MarkAsDead();
1726 StartForceKillTimer();
1727
1728 if (aSendShutDown) {
1729 MaybeAsyncSendShutDownMessage();
1730 }
1731 }
1732
MaybeAsyncSendShutDownMessage()1733 void ContentParent::MaybeAsyncSendShutDownMessage() {
1734 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
1735 ("MaybeAsyncSendShutDownMessage %p", this));
1736 MOZ_ASSERT(NS_IsMainThread());
1737 MOZ_ASSERT(sRecycledE10SProcess != this);
1738
1739 #ifdef DEBUG
1740 // Calling this below while the lock is acquired will deadlock.
1741 bool shouldKeepProcessAlive = ShouldKeepProcessAlive();
1742 #endif
1743
1744 auto lock = mRemoteWorkerActorData.Lock();
1745 MOZ_ASSERT_IF(!lock->mCount, !shouldKeepProcessAlive);
1746
1747 if (lock->mCount) {
1748 return;
1749 }
1750
1751 MOZ_ASSERT(!lock->mShutdownStarted);
1752 lock->mShutdownStarted = true;
1753
1754 // In the case of normal shutdown, send a shutdown message to child to
1755 // allow it to perform shutdown tasks.
1756 GetCurrentSerialEventTarget()->Dispatch(NewRunnableMethod<ShutDownMethod>(
1757 "dom::ContentParent::ShutDownProcess", this,
1758 &ContentParent::ShutDownProcess, SEND_SHUTDOWN_MESSAGE));
1759 }
1760
ShutDownProcess(ShutDownMethod aMethod)1761 void ContentParent::ShutDownProcess(ShutDownMethod aMethod) {
1762 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
1763 ("ShutDownProcess: %p", this));
1764 // NB: must MarkAsDead() here so that this isn't accidentally
1765 // returned from Get*() while in the midst of shutdown.
1766 MarkAsDead();
1767
1768 // Shutting down by sending a shutdown message works differently than the
1769 // other methods. We first call Shutdown() in the child. After the child is
1770 // ready, it calls FinishShutdown() on us. Then we close the channel.
1771 if (aMethod == SEND_SHUTDOWN_MESSAGE) {
1772 if (CanSend() && !mShutdownPending) {
1773 // Stop sending input events with input priority when shutting down.
1774 SetInputPriorityEventEnabled(false);
1775 // Send a high priority announcement first. If this fails, SendShutdown
1776 // will also fail.
1777 Unused << SendShutdownConfirmedHP();
1778 // Send the definite message with normal priority.
1779 if (SendShutdown()) {
1780 mShutdownPending = true;
1781 // Start the force-kill timer if we haven't already.
1782 StartForceKillTimer();
1783 }
1784 }
1785 // If call was not successful, the channel must have been broken
1786 // somehow, and we will clean up the error in ActorDestroy.
1787 return;
1788 }
1789
1790 using mozilla::dom::quota::QuotaManagerService;
1791
1792 if (QuotaManagerService* qms = QuotaManagerService::GetOrCreate()) {
1793 qms->AbortOperationsForProcess(mChildID);
1794 }
1795
1796 // If Close() fails with an error, we'll end up back in this function, but
1797 // with aMethod = CLOSE_CHANNEL_WITH_ERROR.
1798
1799 if (aMethod == CLOSE_CHANNEL && !mCalledClose) {
1800 // Close() can only be called once: It kicks off the destruction
1801 // sequence.
1802 mCalledClose = true;
1803 Close();
1804 }
1805
1806 // A ContentParent object might not get freed until after XPCOM shutdown has
1807 // shut down the cycle collector. But by then it's too late to release any
1808 // CC'ed objects, so we need to null them out here, while we still can. See
1809 // bug 899761.
1810 ShutDownMessageManager();
1811 }
1812
RecvFinishShutdown()1813 mozilla::ipc::IPCResult ContentParent::RecvFinishShutdown() {
1814 // At this point, we already called ShutDownProcess once with
1815 // SEND_SHUTDOWN_MESSAGE. To actually close the channel, we call
1816 // ShutDownProcess again with CLOSE_CHANNEL.
1817 MOZ_ASSERT(mShutdownPending);
1818 ShutDownProcess(CLOSE_CHANNEL);
1819 return IPC_OK();
1820 }
1821
ShutDownMessageManager()1822 void ContentParent::ShutDownMessageManager() {
1823 if (!mMessageManager) {
1824 return;
1825 }
1826
1827 mMessageManager->ReceiveMessage(mMessageManager, nullptr,
1828 CHILD_PROCESS_SHUTDOWN_MESSAGE, false,
1829 nullptr, nullptr, IgnoreErrors());
1830
1831 mMessageManager->SetOsPid(-1);
1832 mMessageManager->Disconnect();
1833 mMessageManager = nullptr;
1834 }
1835
AddToPool(nsTArray<ContentParent * > & aPool)1836 void ContentParent::AddToPool(nsTArray<ContentParent*>& aPool) {
1837 MOZ_DIAGNOSTIC_ASSERT(!mIsInPool);
1838 AssertAlive();
1839 MOZ_DIAGNOSTIC_ASSERT(!mCalledKillHard);
1840 aPool.AppendElement(this);
1841 mIsInPool = true;
1842 }
1843
RemoveFromPool(nsTArray<ContentParent * > & aPool)1844 void ContentParent::RemoveFromPool(nsTArray<ContentParent*>& aPool) {
1845 MOZ_DIAGNOSTIC_ASSERT(mIsInPool);
1846 aPool.RemoveElement(this);
1847 mIsInPool = false;
1848 }
1849
AssertNotInPool()1850 void ContentParent::AssertNotInPool() {
1851 MOZ_RELEASE_ASSERT(!mIsInPool);
1852
1853 MOZ_RELEASE_ASSERT(!sPrivateContent || !sPrivateContent->Contains(this));
1854 MOZ_RELEASE_ASSERT(sRecycledE10SProcess != this);
1855 if (IsForJSPlugin()) {
1856 MOZ_RELEASE_ASSERT(!sJSPluginContentParents ||
1857 !sJSPluginContentParents->Get(mJSPluginID));
1858 } else {
1859 MOZ_RELEASE_ASSERT(
1860 !sBrowserContentParents ||
1861 !sBrowserContentParents->Contains(mRemoteType) ||
1862 !sBrowserContentParents->Get(mRemoteType)->Contains(this) ||
1863 !sCanLaunchSubprocesses); // aka in shutdown - avoid timing issues
1864
1865 for (const auto& group : mGroups) {
1866 MOZ_RELEASE_ASSERT(group->GetHostProcess(mRemoteType) != this,
1867 "still a host process for one of our groups?");
1868 }
1869 }
1870 }
1871
AssertAlive()1872 void ContentParent::AssertAlive() { MOZ_DIAGNOSTIC_ASSERT(!IsDead()); }
1873
RemoveFromList()1874 void ContentParent::RemoveFromList() {
1875 if (IsForJSPlugin()) {
1876 if (sJSPluginContentParents) {
1877 sJSPluginContentParents->Remove(mJSPluginID);
1878 if (!sJSPluginContentParents->Count()) {
1879 sJSPluginContentParents = nullptr;
1880 }
1881 }
1882 return;
1883 }
1884
1885 if (sPrivateContent) {
1886 sPrivateContent->RemoveElement(this);
1887 if (!sPrivateContent->Length()) {
1888 sPrivateContent = nullptr;
1889 }
1890 }
1891
1892 if (!mIsInPool) {
1893 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1894 AssertNotInPool();
1895 #endif
1896 return;
1897 }
1898
1899 // Ensure that this BrowsingContextGroup is no longer used to host new
1900 // documents from any associated BrowsingContextGroups. It may become a host
1901 // again in the future, if it is restored to the pool.
1902 for (const auto& group : mGroups) {
1903 group->RemoveHostProcess(this);
1904 }
1905
1906 StopRecycling(/* aForeground */ false);
1907
1908 if (sBrowserContentParents) {
1909 if (auto entry = sBrowserContentParents->Lookup(mRemoteType)) {
1910 const auto& contentParents = entry.Data();
1911 RemoveFromPool(*contentParents);
1912 if (contentParents->IsEmpty()) {
1913 entry.Remove();
1914 }
1915 }
1916 if (sBrowserContentParents->IsEmpty()) {
1917 delete sBrowserContentParents;
1918 sBrowserContentParents = nullptr;
1919 }
1920 }
1921 }
1922
MarkAsDead()1923 void ContentParent::MarkAsDead() {
1924 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
1925 ("Marking ContentProcess %p as dead", this));
1926 MOZ_DIAGNOSTIC_ASSERT(!sInProcessSelector);
1927 RemoveFromList();
1928
1929 PreallocatedProcessManager::Erase(this);
1930
1931 #ifdef MOZ_WIDGET_ANDROID
1932 if (IsAlive()) {
1933 // We're intentionally killing the content process at this point to ensure
1934 // that we never have a "dead" content process sitting around and occupying
1935 // an Android Service.
1936 nsCOMPtr<nsIEventTarget> launcherThread(GetIPCLauncher());
1937 MOZ_ASSERT(launcherThread);
1938
1939 auto procType = java::GeckoProcessType::CONTENT();
1940 auto selector =
1941 java::GeckoProcessManager::Selector::New(procType, OtherPid());
1942
1943 launcherThread->Dispatch(NS_NewRunnableFunction(
1944 "ContentParent::MarkAsDead",
1945 [selector =
1946 java::GeckoProcessManager::Selector::GlobalRef(selector)]() {
1947 java::GeckoProcessManager::ShutdownProcess(selector);
1948 }));
1949 }
1950 #endif
1951
1952 if (mScriptableHelper) {
1953 static_cast<ScriptableCPInfo*>(mScriptableHelper.get())->ProcessDied();
1954 mScriptableHelper = nullptr;
1955 }
1956
1957 mLifecycleState = LifecycleState::DEAD;
1958 }
1959
OnChannelError()1960 void ContentParent::OnChannelError() {
1961 RefPtr<ContentParent> kungFuDeathGrip(this);
1962 PContentParent::OnChannelError();
1963 }
1964
ProcessingError(Result aCode,const char * aReason)1965 void ContentParent::ProcessingError(Result aCode, const char* aReason) {
1966 if (MsgDropped == aCode) {
1967 return;
1968 }
1969 #ifndef FUZZING
1970 // Other errors are big deals.
1971 KillHard(aReason);
1972 #endif
1973 }
1974
ActorDestroy(ActorDestroyReason why)1975 void ContentParent::ActorDestroy(ActorDestroyReason why) {
1976 MOZ_RELEASE_ASSERT(mSelfRef);
1977
1978 if (mForceKillTimer) {
1979 mForceKillTimer->Cancel();
1980 mForceKillTimer = nullptr;
1981 }
1982
1983 // Signal shutdown completion regardless of error state, so we can
1984 // finish waiting in the xpcom-shutdown/profile-before-change observer.
1985 RemoveShutdownBlockers();
1986
1987 if (mHangMonitorActor) {
1988 ProcessHangMonitor::RemoveProcess(mHangMonitorActor);
1989 mHangMonitorActor = nullptr;
1990 }
1991
1992 RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get();
1993 if (fss) {
1994 fss->Forget(ChildID());
1995 }
1996
1997 if (why == NormalShutdown && !mCalledClose) {
1998 // If we shut down normally but haven't called Close, assume somebody
1999 // else called Close on us. In that case, we still need to call
2000 // ShutDownProcess below to perform other necessary clean up.
2001 mCalledClose = true;
2002 }
2003
2004 // Make sure we always clean up.
2005 ShutDownProcess(why == NormalShutdown ? CLOSE_CHANNEL
2006 : CLOSE_CHANNEL_WITH_ERROR);
2007
2008 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
2009 if (obs) {
2010 size_t length = ArrayLength(sObserverTopics);
2011 for (size_t i = 0; i < length; ++i) {
2012 obs->RemoveObserver(static_cast<nsIObserver*>(this), sObserverTopics[i]);
2013 }
2014 }
2015
2016 // remove the global remote preferences observers
2017 Preferences::RemoveObserver(this, "");
2018 gfxVars::RemoveReceiver(this);
2019
2020 if (GPUProcessManager* gpu = GPUProcessManager::Get()) {
2021 // Note: the manager could have shutdown already.
2022 gpu->RemoveListener(this);
2023 }
2024
2025 RecvRemoveGeolocationListener();
2026
2027 // Destroy our JSProcessActors, and reject any pending queries.
2028 JSActorDidDestroy();
2029
2030 if (obs) {
2031 RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
2032
2033 props->SetPropertyAsUint64(u"childID"_ns, mChildID);
2034
2035 if (AbnormalShutdown == why) {
2036 Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT, "content"_ns,
2037 1);
2038
2039 props->SetPropertyAsBool(u"abnormal"_ns, true);
2040
2041 nsAutoString dumpID;
2042 // There's a window in which child processes can crash
2043 // after IPC is established, but before a crash reporter
2044 // is created.
2045 if (mCrashReporter) {
2046 // if mCreatedPairedMinidumps is true, we've already generated
2047 // parent/child dumps for desktop crashes.
2048 if (!mCreatedPairedMinidumps) {
2049 #if defined(XP_MACOSX)
2050 RefPtr<nsAvailableMemoryWatcherBase> memWatcher;
2051 memWatcher = nsAvailableMemoryWatcherBase::GetSingleton();
2052 memWatcher->AddChildAnnotations(mCrashReporter);
2053 #endif
2054
2055 if (mCrashReporter->GenerateCrashReport(OtherPid())) {
2056 // Propagate `isLikelyOOM`.
2057 Unused << props->SetPropertyAsBool(u"isLikelyOOM"_ns,
2058 mCrashReporter->IsLikelyOOM());
2059 }
2060 }
2061
2062 if (mCrashReporter->HasMinidump()) {
2063 dumpID = mCrashReporter->MinidumpID();
2064 }
2065 } else {
2066 HandleOrphanedMinidump(&dumpID);
2067 }
2068
2069 if (!dumpID.IsEmpty()) {
2070 props->SetPropertyAsAString(u"dumpID"_ns, dumpID);
2071 }
2072 }
2073 nsAutoString cpId;
2074 cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
2075 obs->NotifyObservers((nsIPropertyBag2*)props, "ipc:content-shutdown",
2076 cpId.get());
2077 }
2078
2079 // Remove any and all idle listeners.
2080 nsCOMPtr<nsIUserIdleService> idleService =
2081 do_GetService("@mozilla.org/widget/useridleservice;1");
2082 MOZ_ASSERT(idleService);
2083 RefPtr<ParentIdleListener> listener;
2084 for (int32_t i = mIdleListeners.Length() - 1; i >= 0; --i) {
2085 listener = static_cast<ParentIdleListener*>(mIdleListeners[i].get());
2086 idleService->RemoveIdleObserver(listener, listener->mTime);
2087 }
2088 mIdleListeners.Clear();
2089
2090 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
2091 ("destroying Subprocess in ActorDestroy: ContentParent %p "
2092 "mSubprocess %p handle %" PRIuPTR,
2093 this, mSubprocess,
2094 mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
2095 // FIXME (bug 1520997): does this really need an additional dispatch?
2096 GetCurrentSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
2097 "DelayedDeleteSubprocessRunnable", [subprocess = mSubprocess] {
2098 MOZ_LOG(
2099 ContentParent::GetLog(), LogLevel::Debug,
2100 ("destroyed Subprocess in ActorDestroy: Subprocess %p handle "
2101 "%" PRIuPTR,
2102 subprocess,
2103 subprocess ? (uintptr_t)subprocess->GetChildProcessHandle() : -1));
2104 subprocess->Destroy();
2105 }));
2106 mSubprocess = nullptr;
2107
2108 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
2109 cpm->RemoveContentProcess(this->ChildID());
2110
2111 if (mDriverCrashGuard) {
2112 mDriverCrashGuard->NotifyCrashed();
2113 }
2114
2115 // Unregister all the BlobURLs registered by the ContentChild.
2116 for (uint32_t i = 0; i < mBlobURLs.Length(); ++i) {
2117 BlobURLProtocolHandler::RemoveDataEntry(mBlobURLs[i]);
2118 }
2119
2120 mBlobURLs.Clear();
2121
2122 #if defined(XP_WIN) && defined(ACCESSIBILITY)
2123 a11y::MsaaAccessible::ReleaseContentProcessIdFor(ChildID());
2124 #endif
2125
2126 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2127 AssertNotInPool();
2128 #endif
2129
2130 // As this process is going away, ensure that every BrowsingContext hosted by
2131 // it has been detached, and every BrowsingContextGroup has been fully
2132 // unsubscribed.
2133 BrowsingContext::DiscardFromContentParent(this);
2134
2135 const nsTHashSet<RefPtr<BrowsingContextGroup>> groups = std::move(mGroups);
2136 for (const auto& group : groups) {
2137 group->Unsubscribe(this);
2138 }
2139 MOZ_DIAGNOSTIC_ASSERT(mGroups.IsEmpty());
2140 }
2141
ActorDealloc()2142 void ContentParent::ActorDealloc() { mSelfRef = nullptr; }
2143
TryToRecycle()2144 bool ContentParent::TryToRecycle() {
2145 // Only try to recycle "web" content processes, as other remote types are
2146 // generally more unique, and cannot be effectively re-used. This is disabled
2147 // with Fission, as "web" content processes are no longer frequently used.
2148 //
2149 // Disabling the process pre-allocator will also disable process recycling,
2150 // allowing for more consistent process counts under testing.
2151 if (mRemoteType != DEFAULT_REMOTE_TYPE || mozilla::FissionAutostart() ||
2152 !PreallocatedProcessManager::Enabled()) {
2153 return false;
2154 }
2155
2156 // This life time check should be replaced by a memory health check (memory
2157 // usage + fragmentation).
2158
2159 // Note that this is specifically to help with edge cases that rapidly
2160 // create-and-destroy processes
2161 const double kMaxLifeSpan = 5;
2162 MOZ_LOG(
2163 ContentParent::GetLog(), LogLevel::Debug,
2164 ("TryToRecycle ContentProcess %p (%u) with lifespan %f seconds", this,
2165 (unsigned int)ChildID(), (TimeStamp::Now() - mActivateTS).ToSeconds()));
2166
2167 if (mCalledKillHard || !IsAlive() ||
2168 (TimeStamp::Now() - mActivateTS).ToSeconds() > kMaxLifeSpan) {
2169 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2170 ("TryToRecycle did not recycle %p", this));
2171
2172 // It's possible that the process was already cached, and we're being called
2173 // from a different path, and we're now past kMaxLifeSpan (or some other).
2174 // Ensure that if we're going to kill this process we don't recycle it.
2175 StopRecycling(/* aForeground */ false);
2176 return false;
2177 }
2178
2179 if (!sRecycledE10SProcess) {
2180 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2181 ("TryToRecycle began recycling %p", this));
2182 sRecycledE10SProcess = this;
2183
2184 ProcessPriorityManager::SetProcessPriority(this,
2185 PROCESS_PRIORITY_BACKGROUND);
2186 return true;
2187 }
2188
2189 if (sRecycledE10SProcess == this) {
2190 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2191 ("TryToRecycle continue recycling %p", this));
2192 return true;
2193 }
2194
2195 // Some other process is already being recycled, just shut this one down.
2196 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2197 ("TryToRecycle did not recycle %p (already recycling %p)", this,
2198 sRecycledE10SProcess.get()));
2199 return false;
2200 }
2201
StopRecycling(bool aForeground)2202 void ContentParent::StopRecycling(bool aForeground) {
2203 if (sRecycledE10SProcess != this) {
2204 return;
2205 }
2206
2207 sRecycledE10SProcess = nullptr;
2208 if (aForeground) {
2209 ProcessPriorityManager::SetProcessPriority(this,
2210 PROCESS_PRIORITY_FOREGROUND);
2211 }
2212 }
2213
HasActiveWorkerOrJSPlugin()2214 bool ContentParent::HasActiveWorkerOrJSPlugin() {
2215 if (IsForJSPlugin()) {
2216 return true;
2217 }
2218
2219 // If we have active workers, we need to stay alive.
2220 {
2221 const auto lock = mRemoteWorkerActorData.Lock();
2222 if (lock->mCount) {
2223 return true;
2224 }
2225 }
2226 return false;
2227 }
2228
ShouldKeepProcessAlive()2229 bool ContentParent::ShouldKeepProcessAlive() {
2230 if (HasActiveWorkerOrJSPlugin()) {
2231 return true;
2232 }
2233
2234 if (mNumKeepaliveCalls > 0) {
2235 return true;
2236 }
2237
2238 if (IsLaunching()) {
2239 return true;
2240 }
2241
2242 // If we have already been marked as dead, don't prevent shutdown.
2243 if (IsDead()) {
2244 return false;
2245 }
2246
2247 if (!sBrowserContentParents) {
2248 return false;
2249 }
2250
2251 auto contentParents = sBrowserContentParents->Get(mRemoteType);
2252 if (!contentParents) {
2253 return false;
2254 }
2255
2256 // We might want to keep some content processes alive for performance reasons.
2257 // e.g. test runs and privileged content process for some about: pages.
2258 // We don't want to alter behavior if the pref is not set, so default to 0.
2259 int32_t processesToKeepAlive = 0;
2260
2261 nsAutoCString keepAlivePref("dom.ipc.keepProcessesAlive.");
2262
2263 if (StringBeginsWith(mRemoteType, FISSION_WEB_REMOTE_TYPE) &&
2264 xpc::IsInAutomation()) {
2265 keepAlivePref.Append(FISSION_WEB_REMOTE_TYPE);
2266 keepAlivePref.AppendLiteral(".perOrigin");
2267 } else {
2268 keepAlivePref.Append(mRemoteType);
2269 }
2270 if (NS_FAILED(
2271 Preferences::GetInt(keepAlivePref.get(), &processesToKeepAlive))) {
2272 return false;
2273 }
2274
2275 int32_t numberOfAliveProcesses = contentParents->Length();
2276
2277 return numberOfAliveProcesses <= processesToKeepAlive;
2278 }
2279
NotifyTabDestroying()2280 void ContentParent::NotifyTabDestroying() {
2281 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2282 ("NotifyTabDestroying %p:", this));
2283 // There can be more than one PBrowser for a given app process
2284 // because of popup windows. PBrowsers can also destroy
2285 // concurrently. When all the PBrowsers are destroying, kick off
2286 // another task to ensure the child process *really* shuts down,
2287 // even if the PBrowsers themselves never finish destroying.
2288 ++mNumDestroyingTabs;
2289
2290 /**
2291 * We intentionally skip this code on Android:
2292 * 1. Android has a fixed upper bound on the number of content processes, so
2293 * we prefer to re-use them whenever possible (as opposed to letting an
2294 * old process wind down while we launch a new one).
2295 * 2. GeckoView always hard-kills content processes (and if it does not,
2296 * Android itself will), so we don't concern ourselves with the ForceKill
2297 * timer either.
2298 */
2299 #if !defined(MOZ_WIDGET_ANDROID)
2300 MaybeBeginShutDown(/* aExpectedBrowserCount */ mNumDestroyingTabs,
2301 /* aSendShutDown */ false);
2302 #endif // !defined(MOZ_WIDGET_ANDROID)
2303 }
2304
AddKeepAlive()2305 void ContentParent::AddKeepAlive() {
2306 // Something wants to keep this content process alive.
2307 ++mNumKeepaliveCalls;
2308 }
2309
RemoveKeepAlive()2310 void ContentParent::RemoveKeepAlive() {
2311 MOZ_DIAGNOSTIC_ASSERT(mNumKeepaliveCalls > 0);
2312 --mNumKeepaliveCalls;
2313
2314 MaybeBeginShutDown();
2315 }
2316
StartForceKillTimer()2317 void ContentParent::StartForceKillTimer() {
2318 if (mForceKillTimer || !CanSend()) {
2319 return;
2320 }
2321
2322 NotifyImpendingShutdown();
2323
2324 int32_t timeoutSecs = StaticPrefs::dom_ipc_tabs_shutdownTimeoutSecs();
2325 if (timeoutSecs > 0) {
2326 NS_NewTimerWithFuncCallback(getter_AddRefs(mForceKillTimer),
2327 ContentParent::ForceKillTimerCallback, this,
2328 timeoutSecs * 1000, nsITimer::TYPE_ONE_SHOT,
2329 "dom::ContentParent::StartForceKillTimer");
2330 MOZ_ASSERT(mForceKillTimer);
2331 }
2332 }
2333
NotifyTabDestroyed(const TabId & aTabId,bool aNotifiedDestroying)2334 void ContentParent::NotifyTabDestroyed(const TabId& aTabId,
2335 bool aNotifiedDestroying) {
2336 if (aNotifiedDestroying) {
2337 --mNumDestroyingTabs;
2338 }
2339
2340 nsTArray<PContentPermissionRequestParent*> parentArray =
2341 nsContentPermissionUtils::GetContentPermissionRequestParentById(aTabId);
2342
2343 // Need to close undeleted ContentPermissionRequestParents before tab is
2344 // closed.
2345 for (auto& permissionRequestParent : parentArray) {
2346 Unused << PContentPermissionRequestParent::Send__delete__(
2347 permissionRequestParent);
2348 }
2349
2350 // There can be more than one PBrowser for a given app process
2351 // because of popup windows. When the last one closes, shut
2352 // us down.
2353 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
2354 ("NotifyTabDestroyed %p", this));
2355
2356 MaybeBeginShutDown(/* aExpectedBrowserCount */ 1);
2357 }
2358
CreateTestShell()2359 TestShellParent* ContentParent::CreateTestShell() {
2360 return static_cast<TestShellParent*>(SendPTestShellConstructor());
2361 }
2362
DestroyTestShell(TestShellParent * aTestShell)2363 bool ContentParent::DestroyTestShell(TestShellParent* aTestShell) {
2364 return PTestShellParent::Send__delete__(aTestShell);
2365 }
2366
GetTestShellSingleton()2367 TestShellParent* ContentParent::GetTestShellSingleton() {
2368 PTestShellParent* p = LoneManagedOrNullAsserts(ManagedPTestShellParent());
2369 return static_cast<TestShellParent*>(p);
2370 }
2371
2372 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
2373 // Append the sandbox command line parameters that are not static. i.e.,
2374 // parameters that can be different for different child processes.
AppendDynamicSandboxParams(std::vector<std::string> & aArgs)2375 void ContentParent::AppendDynamicSandboxParams(
2376 std::vector<std::string>& aArgs) {
2377 // For file content processes
2378 if (GetRemoteType() == FILE_REMOTE_TYPE) {
2379 MacSandboxInfo::AppendFileAccessParam(aArgs, true);
2380 }
2381 }
2382
2383 // Generate the static sandbox command line parameters and store
2384 // them in the provided params vector to be used each time a new
2385 // content process is launched.
CacheSandboxParams(std::vector<std::string> & aCachedParams)2386 static void CacheSandboxParams(std::vector<std::string>& aCachedParams) {
2387 // This must only be called once and we should
2388 // be starting with an empty list of parameters.
2389 MOZ_ASSERT(aCachedParams.empty());
2390
2391 MacSandboxInfo info;
2392 info.type = MacSandboxType_Content;
2393 info.level = GetEffectiveContentSandboxLevel();
2394
2395 // Sandbox logging
2396 if (Preferences::GetBool("security.sandbox.logging.enabled") ||
2397 PR_GetEnv("MOZ_SANDBOX_LOGGING")) {
2398 info.shouldLog = true;
2399 }
2400
2401 // Audio access
2402 if (!StaticPrefs::media_cubeb_sandbox()) {
2403 info.hasAudio = true;
2404 }
2405
2406 // Window server access. If the disconnect-windowserver pref is not
2407 // "true" or out-of-process WebGL is not enabled, allow window server
2408 // access in the sandbox policy.
2409 if (!Preferences::GetBool(
2410 "security.sandbox.content.mac.disconnect-windowserver") ||
2411 !Preferences::GetBool("webgl.out-of-process")) {
2412 info.hasWindowServer = true;
2413 }
2414
2415 // .app path (normalized)
2416 nsAutoCString appPath;
2417 if (!nsMacUtilsImpl::GetAppPath(appPath)) {
2418 MOZ_CRASH("Failed to get app dir paths");
2419 }
2420 info.appPath = appPath.get();
2421
2422 // TESTING_READ_PATH1
2423 nsAutoCString testingReadPath1;
2424 Preferences::GetCString("security.sandbox.content.mac.testing_read_path1",
2425 testingReadPath1);
2426 if (!testingReadPath1.IsEmpty()) {
2427 info.testingReadPath1 = testingReadPath1.get();
2428 }
2429
2430 // TESTING_READ_PATH2
2431 nsAutoCString testingReadPath2;
2432 Preferences::GetCString("security.sandbox.content.mac.testing_read_path2",
2433 testingReadPath2);
2434 if (!testingReadPath2.IsEmpty()) {
2435 info.testingReadPath2 = testingReadPath2.get();
2436 }
2437
2438 // TESTING_READ_PATH3, TESTING_READ_PATH4. In development builds,
2439 // these are used to whitelist the repo dir and object dir respectively.
2440 nsresult rv;
2441 if (mozilla::IsDevelopmentBuild()) {
2442 // Repo dir
2443 nsCOMPtr<nsIFile> repoDir;
2444 rv = nsMacUtilsImpl::GetRepoDir(getter_AddRefs(repoDir));
2445 if (NS_FAILED(rv)) {
2446 MOZ_CRASH("Failed to get path to repo dir");
2447 }
2448 nsCString repoDirPath;
2449 Unused << repoDir->GetNativePath(repoDirPath);
2450 info.testingReadPath3 = repoDirPath.get();
2451
2452 // Object dir
2453 nsCOMPtr<nsIFile> objDir;
2454 rv = nsMacUtilsImpl::GetObjDir(getter_AddRefs(objDir));
2455 if (NS_FAILED(rv)) {
2456 MOZ_CRASH("Failed to get path to build object dir");
2457 }
2458 nsCString objDirPath;
2459 Unused << objDir->GetNativePath(objDirPath);
2460 info.testingReadPath4 = objDirPath.get();
2461 }
2462
2463 // DEBUG_WRITE_DIR
2464 # ifdef DEBUG
2465 // For bloat/leak logging or when a content process dies intentionally
2466 // (|NoteIntentionalCrash|) for tests, it wants to log that it did this.
2467 // Allow writing to this location.
2468 nsAutoCString bloatLogDirPath;
2469 if (NS_SUCCEEDED(nsMacUtilsImpl::GetBloatLogDir(bloatLogDirPath))) {
2470 info.debugWriteDir = bloatLogDirPath.get();
2471 }
2472 # endif // DEBUG
2473
2474 info.AppendAsParams(aCachedParams);
2475 }
2476
2477 // Append sandboxing command line parameters.
AppendSandboxParams(std::vector<std::string> & aArgs)2478 void ContentParent::AppendSandboxParams(std::vector<std::string>& aArgs) {
2479 MOZ_ASSERT(sMacSandboxParams != nullptr);
2480
2481 // An empty sMacSandboxParams indicates this is the
2482 // first invocation and we don't have cached params yet.
2483 if (sMacSandboxParams->empty()) {
2484 CacheSandboxParams(*sMacSandboxParams);
2485 MOZ_ASSERT(!sMacSandboxParams->empty());
2486 }
2487
2488 // Append cached arguments.
2489 aArgs.insert(aArgs.end(), sMacSandboxParams->begin(),
2490 sMacSandboxParams->end());
2491
2492 // Append remaining arguments.
2493 AppendDynamicSandboxParams(aArgs);
2494 }
2495 #endif // XP_MACOSX && MOZ_SANDBOX
2496
BeginSubprocessLaunch(ProcessPriority aPriority)2497 bool ContentParent::BeginSubprocessLaunch(ProcessPriority aPriority) {
2498 AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess", OTHER);
2499
2500 if (!ContentProcessManager::GetSingleton()) {
2501 NS_WARNING(
2502 "Shutdown has begun, we shouldn't spawn any more child processes");
2503 return false;
2504 }
2505
2506 std::vector<std::string> extraArgs;
2507 geckoargs::sChildID.Put(mChildID, extraArgs);
2508 geckoargs::sIsForBrowser.Put(IsForBrowser(), extraArgs);
2509 geckoargs::sNotForBrowser.Put(!IsForBrowser(), extraArgs);
2510
2511 // Prefs information is passed via anonymous shared memory to avoid bloating
2512 // the command line.
2513
2514 // Instantiate the pref serializer. It will be cleaned up in
2515 // `LaunchSubprocessReject`/`LaunchSubprocessResolve`.
2516 mPrefSerializer = MakeUnique<mozilla::ipc::SharedPreferenceSerializer>(
2517 ShouldSyncPreference);
2518 if (!mPrefSerializer->SerializeToSharedMemory()) {
2519 NS_WARNING("SharedPreferenceSerializer::SerializeToSharedMemory failed");
2520 MarkAsDead();
2521 return false;
2522 }
2523 mPrefSerializer->AddSharedPrefCmdLineArgs(*mSubprocess, extraArgs);
2524
2525 // The JS engine does some computation during the initialization which can be
2526 // shared across processes. We add command line arguments to pass a file
2527 // handle and its content length, to minimize the startup time of content
2528 // processes.
2529 ::mozilla::ipc::ExportSharedJSInit(*mSubprocess, extraArgs);
2530
2531 #if defined(XP_WIN) && defined(ACCESSIBILITY)
2532 // Determining the accessibility resource ID causes problems with the sandbox,
2533 // so we pass it on the command line as it is required very early in process
2534 // start up. It is not required when the caching mechanism is being used.
2535 if (!StaticPrefs::accessibility_cache_enabled_AtStartup()) {
2536 // The accessibility resource ID may not be set in some cases, for example
2537 // in xpcshell tests.
2538 auto resourceId = mscom::ActCtxResource::GetAccessibilityResourceId();
2539 if (resourceId) {
2540 geckoargs::sA11yResourceId.Put(resourceId, extraArgs);
2541 }
2542 }
2543 #endif
2544
2545 // Register ContentParent as an observer for changes to any pref
2546 // whose prefix matches the empty string, i.e. all of them. The
2547 // observation starts here in order to capture pref updates that
2548 // happen during async launch.
2549 Preferences::AddStrongObserver(this, "");
2550
2551 if (gSafeMode) {
2552 geckoargs::sSafeMode.Put(extraArgs);
2553 }
2554
2555 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
2556 if (IsContentSandboxEnabled()) {
2557 AppendSandboxParams(extraArgs);
2558 mSubprocess->DisableOSActivityMode();
2559 }
2560 #endif
2561
2562 nsCString parentBuildID(mozilla::PlatformBuildID());
2563 geckoargs::sParentBuildID.Put(parentBuildID.get(), extraArgs);
2564
2565 #ifdef MOZ_WIDGET_GTK
2566 // This is X11-only pending a solution for WebGL in Wayland mode.
2567 if (StaticPrefs::dom_ipc_avoid_gtk() &&
2568 StaticPrefs::widget_non_native_theme_enabled() &&
2569 widget::GdkIsX11Display()) {
2570 mSubprocess->SetEnv("MOZ_HEADLESS", "1");
2571 }
2572 #endif
2573
2574 // See also ActorDealloc.
2575 mSelfRef = this;
2576 mLaunchYieldTS = TimeStamp::Now();
2577 return mSubprocess->AsyncLaunch(std::move(extraArgs));
2578 }
2579
LaunchSubprocessReject()2580 void ContentParent::LaunchSubprocessReject() {
2581 NS_WARNING("failed to launch child in the parent");
2582 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
2583 ("failed to launch child in the parent"));
2584 // Now that communication with the child is complete, we can cleanup
2585 // the preference serializer.
2586 mPrefSerializer = nullptr;
2587 if (mIsAPreallocBlocker) {
2588 PreallocatedProcessManager::RemoveBlocker(mRemoteType, this);
2589 mIsAPreallocBlocker = false;
2590 }
2591 MarkAsDead();
2592 }
2593
LaunchSubprocessResolve(bool aIsSync,ProcessPriority aPriority)2594 bool ContentParent::LaunchSubprocessResolve(bool aIsSync,
2595 ProcessPriority aPriority) {
2596 AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess::resolve", OTHER);
2597
2598 if (mLaunchResolved) {
2599 // We've already been called, return.
2600 MOZ_ASSERT(sCreatedFirstContentProcess);
2601 MOZ_ASSERT(!mPrefSerializer);
2602 MOZ_ASSERT(mLifecycleState != LifecycleState::LAUNCHING);
2603 return mLaunchResolvedOk;
2604 }
2605 mLaunchResolved = true;
2606
2607 // Now that communication with the child is complete, we can cleanup
2608 // the preference serializer.
2609 mPrefSerializer = nullptr;
2610
2611 const auto launchResumeTS = TimeStamp::Now();
2612 if (profiler_thread_is_being_profiled_for_markers()) {
2613 nsPrintfCString marker("Process start%s for %u",
2614 mIsAPreallocBlocker ? " (immediate)" : "",
2615 (unsigned int)ChildID());
2616 PROFILER_MARKER_TEXT(
2617 mIsAPreallocBlocker ? ProfilerString8View("Process Immediate Launch")
2618 : ProfilerString8View("Process Launch"),
2619 DOM, MarkerTiming::Interval(mLaunchTS, launchResumeTS), marker);
2620 }
2621
2622 if (!sCreatedFirstContentProcess) {
2623 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
2624 obs->NotifyObservers(nullptr, "ipc:first-content-process-created", nullptr);
2625 sCreatedFirstContentProcess = true;
2626 }
2627
2628 base::ProcessId procId =
2629 base::GetProcId(mSubprocess->GetChildProcessHandle());
2630 Open(mSubprocess->TakeInitialPort(), procId);
2631
2632 ContentProcessManager::GetSingleton()->AddContentProcess(this);
2633
2634 #ifdef MOZ_CODE_COVERAGE
2635 Unused << SendShareCodeCoverageMutex(
2636 CodeCoverageHandler::Get()->GetMutexHandle());
2637 #endif
2638
2639 // We must be in the LAUNCHING state still. If we've somehow already been
2640 // marked as DEAD, fail the process launch, and immediately begin tearing down
2641 // the content process.
2642 if (IsDead()) {
2643 NS_WARNING("immediately shutting-down already-dead process");
2644 ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
2645 return false;
2646 }
2647 MOZ_ASSERT(mLifecycleState == LifecycleState::LAUNCHING);
2648 mLifecycleState = LifecycleState::ALIVE;
2649
2650 if (!InitInternal(aPriority)) {
2651 NS_WARNING("failed to initialize child in the parent");
2652 // We've already called Open() by this point, so we need to close the
2653 // channel to avoid leaking the process.
2654 ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
2655 return false;
2656 }
2657
2658 mHangMonitorActor = ProcessHangMonitor::AddProcess(this);
2659
2660 // Set a reply timeout for CPOWs.
2661 SetReplyTimeoutMs(StaticPrefs::dom_ipc_cpow_timeout());
2662
2663 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
2664 if (obs) {
2665 nsAutoString cpId;
2666 cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
2667 obs->NotifyObservers(static_cast<nsIObserver*>(this),
2668 "ipc:content-initializing", cpId.get());
2669 }
2670
2671 Init();
2672
2673 mLifecycleState = LifecycleState::INITIALIZED;
2674
2675 if (aIsSync) {
2676 Telemetry::AccumulateTimeDelta(Telemetry::CONTENT_PROCESS_SYNC_LAUNCH_MS,
2677 mLaunchTS);
2678 } else {
2679 Telemetry::AccumulateTimeDelta(Telemetry::CONTENT_PROCESS_LAUNCH_TOTAL_MS,
2680 mLaunchTS);
2681
2682 Telemetry::Accumulate(
2683 Telemetry::CONTENT_PROCESS_LAUNCH_MAINTHREAD_MS,
2684 static_cast<uint32_t>(
2685 ((mLaunchYieldTS - mLaunchTS) + (TimeStamp::Now() - launchResumeTS))
2686 .ToMilliseconds()));
2687 }
2688
2689 mLaunchResolvedOk = true;
2690 return true;
2691 }
2692
LaunchSubprocessSync(hal::ProcessPriority aInitialPriority)2693 bool ContentParent::LaunchSubprocessSync(
2694 hal::ProcessPriority aInitialPriority) {
2695 // We've started a sync content process launch.
2696 Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC, 1);
2697
2698 if (!BeginSubprocessLaunch(aInitialPriority)) {
2699 return false;
2700 }
2701 const bool ok = mSubprocess->WaitForProcessHandle();
2702 if (ok && LaunchSubprocessResolve(/* aIsSync = */ true, aInitialPriority)) {
2703 ContentParent::DidLaunchSubprocess();
2704 return true;
2705 }
2706 LaunchSubprocessReject();
2707 return false;
2708 }
2709
LaunchSubprocessAsync(hal::ProcessPriority aInitialPriority)2710 RefPtr<ContentParent::LaunchPromise> ContentParent::LaunchSubprocessAsync(
2711 hal::ProcessPriority aInitialPriority) {
2712 // We've started an async content process launch.
2713 Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_IS_SYNC, 0);
2714
2715 if (!BeginSubprocessLaunch(aInitialPriority)) {
2716 // Launch aborted because of shutdown. Bailout.
2717 LaunchSubprocessReject();
2718 return LaunchPromise::CreateAndReject(LaunchError(), __func__);
2719 }
2720
2721 // Otherwise, wait until the process is ready.
2722 RefPtr<ProcessHandlePromise> ready = mSubprocess->WhenProcessHandleReady();
2723 RefPtr<ContentParent> self = this;
2724 mLaunchYieldTS = TimeStamp::Now();
2725
2726 return ready->Then(
2727 GetCurrentSerialEventTarget(), __func__,
2728 [self, aInitialPriority](
2729 const ProcessHandlePromise::ResolveOrRejectValue& aValue) {
2730 if (aValue.IsResolve() &&
2731 self->LaunchSubprocessResolve(/* aIsSync = */ false,
2732 aInitialPriority)) {
2733 ContentParent::DidLaunchSubprocess();
2734 return LaunchPromise::CreateAndResolve(self, __func__);
2735 }
2736 self->LaunchSubprocessReject();
2737 return LaunchPromise::CreateAndReject(LaunchError(), __func__);
2738 });
2739 }
2740
ContentParent(const nsACString & aRemoteType,int32_t aJSPluginID)2741 ContentParent::ContentParent(const nsACString& aRemoteType, int32_t aJSPluginID)
2742 : mSelfRef(nullptr),
2743 mSubprocess(nullptr),
2744 mLaunchTS(TimeStamp::Now()),
2745 mLaunchYieldTS(mLaunchTS),
2746 mActivateTS(mLaunchTS),
2747 mIsAPreallocBlocker(false),
2748 mRemoteType(aRemoteType),
2749 mChildID(gContentChildID++),
2750 mGeolocationWatchID(-1),
2751 mJSPluginID(aJSPluginID),
2752 mRemoteWorkerActorData("ContentParent::mRemoteWorkerActorData"),
2753 mNumDestroyingTabs(0),
2754 mNumKeepaliveCalls(0),
2755 mLifecycleState(LifecycleState::LAUNCHING),
2756 mIsForBrowser(!mRemoteType.IsEmpty()),
2757 mCalledClose(false),
2758 mCalledKillHard(false),
2759 mCreatedPairedMinidumps(false),
2760 mShutdownPending(false),
2761 mLaunchResolved(false),
2762 mLaunchResolvedOk(false),
2763 mIsRemoteInputEventQueueEnabled(false),
2764 mIsInputPriorityEventEnabled(false),
2765 mIsInPool(false),
2766 mHangMonitorActor(nullptr) {
2767 MOZ_DIAGNOSTIC_ASSERT(!IsForJSPlugin(),
2768 "XXX(nika): How are we creating a JSPlugin?");
2769
2770 mRemoteTypeIsolationPrincipal =
2771 CreateRemoteTypeIsolationPrincipal(aRemoteType);
2772
2773 // Insert ourselves into the global linked list of ContentParent objects.
2774 if (!sContentParents) {
2775 sContentParents = MakeUnique<LinkedList<ContentParent>>();
2776 }
2777 sContentParents->insertBack(this);
2778
2779 mMessageManager = nsFrameMessageManager::NewProcessMessageManager(true);
2780
2781 #if defined(XP_WIN)
2782 // Request Windows message deferral behavior on our side of the PContent
2783 // channel. Generally only applies to the situation where we get caught in
2784 // a deadlock with the plugin process when sending CPOWs.
2785 GetIPCChannel()->SetChannelFlags(
2786 MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
2787 #endif
2788
2789 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2790 bool isFile = mRemoteType == FILE_REMOTE_TYPE;
2791 mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content, isFile);
2792 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
2793 ("CreateSubprocess: ContentParent %p mSubprocess %p handle %" PRIuPTR,
2794 this, mSubprocess,
2795 mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
2796
2797 // This is safe to do in the constructor, as it doesn't take a strong
2798 // reference.
2799 mScriptableHelper = new ScriptableCPInfo(this);
2800 }
2801
~ContentParent()2802 ContentParent::~ContentParent() {
2803 if (mForceKillTimer) {
2804 mForceKillTimer->Cancel();
2805 }
2806
2807 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2808
2809 if (mIsAPreallocBlocker) {
2810 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2811 ("Removing blocker on ContentProcess destruction"));
2812 PreallocatedProcessManager::RemoveBlocker(mRemoteType, this);
2813 mIsAPreallocBlocker = false;
2814 }
2815
2816 // We should be removed from all these lists in ActorDestroy.
2817 AssertNotInPool();
2818
2819 // Normally mSubprocess is destroyed in ActorDestroy, but that won't
2820 // happen if the process wasn't launched or if it failed to launch.
2821 if (mSubprocess) {
2822 MOZ_LOG(
2823 ContentParent::GetLog(), LogLevel::Verbose,
2824 ("DestroySubprocess: ContentParent %p mSubprocess %p handle %" PRIuPTR,
2825 this, mSubprocess,
2826 mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
2827 mSubprocess->Destroy();
2828 }
2829
2830 // Make sure to clear the connection from `mScriptableHelper` if it hasn't
2831 // been cleared yet.
2832 if (mScriptableHelper) {
2833 static_cast<ScriptableCPInfo*>(mScriptableHelper.get())->ProcessDied();
2834 mScriptableHelper = nullptr;
2835 }
2836 }
2837
InitInternal(ProcessPriority aInitialPriority)2838 bool ContentParent::InitInternal(ProcessPriority aInitialPriority) {
2839 // We can't access the locale service after shutdown has started. Since we
2840 // can't init the process without it, and since we're going to be canceling
2841 // whatever load attempt that initiated this process creation anyway, just
2842 // bail out now if shutdown has already started.
2843 if (PastShutdownPhase(ShutdownPhase::XPCOMShutdown)) {
2844 return false;
2845 }
2846
2847 XPCOMInitData xpcomInit;
2848
2849 MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
2850 ("ContentParent::InitInternal: %p", (void*)this));
2851 nsCOMPtr<nsIIOService> io(do_GetIOService());
2852 MOZ_ASSERT(io, "No IO service?");
2853 DebugOnly<nsresult> rv = io->GetOffline(&xpcomInit.isOffline());
2854 MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting offline?");
2855
2856 rv = io->GetConnectivity(&xpcomInit.isConnected());
2857 MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting connectivity?");
2858
2859 xpcomInit.captivePortalState() = nsICaptivePortalService::UNKNOWN;
2860 nsCOMPtr<nsICaptivePortalService> cps =
2861 do_GetService(NS_CAPTIVEPORTAL_CONTRACTID);
2862 if (cps) {
2863 cps->GetState(&xpcomInit.captivePortalState());
2864 }
2865
2866 nsIBidiKeyboard* bidi = nsContentUtils::GetBidiKeyboard();
2867
2868 xpcomInit.isLangRTL() = false;
2869 xpcomInit.haveBidiKeyboards() = false;
2870 if (bidi) {
2871 bidi->IsLangRTL(&xpcomInit.isLangRTL());
2872 bidi->GetHaveBidiKeyboards(&xpcomInit.haveBidiKeyboards());
2873 }
2874
2875 RefPtr<mozSpellChecker> spellChecker(mozSpellChecker::Create());
2876 MOZ_ASSERT(spellChecker, "No spell checker?");
2877
2878 spellChecker->GetDictionaryList(&xpcomInit.dictionaries());
2879
2880 LocaleService::GetInstance()->GetAppLocalesAsBCP47(xpcomInit.appLocales());
2881 LocaleService::GetInstance()->GetRequestedLocales(
2882 xpcomInit.requestedLocales());
2883
2884 L10nRegistry::GetParentProcessFileSourceDescriptors(
2885 xpcomInit.l10nFileSources());
2886
2887 nsCOMPtr<nsIClipboard> clipboard(
2888 do_GetService("@mozilla.org/widget/clipboard;1"));
2889 MOZ_ASSERT(clipboard, "No clipboard?");
2890
2891 rv = clipboard->SupportsSelectionClipboard(
2892 &xpcomInit.clipboardCaps().supportsSelectionClipboard());
2893 MOZ_ASSERT(NS_SUCCEEDED(rv));
2894
2895 rv = clipboard->SupportsFindClipboard(
2896 &xpcomInit.clipboardCaps().supportsFindClipboard());
2897 MOZ_ASSERT(NS_SUCCEEDED(rv));
2898
2899 // Let's copy the domain policy from the parent to the child (if it's active).
2900 StructuredCloneData initialData;
2901 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
2902 if (ssm) {
2903 ssm->CloneDomainPolicy(&xpcomInit.domainPolicy());
2904
2905 if (ParentProcessMessageManager* mm =
2906 nsFrameMessageManager::sParentProcessManager) {
2907 AutoJSAPI jsapi;
2908 if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) {
2909 MOZ_CRASH();
2910 }
2911 JS::RootedValue init(jsapi.cx());
2912 // We'll crash on failure, so use a IgnoredErrorResult (which also
2913 // auto-suppresses exceptions).
2914 IgnoredErrorResult rv;
2915 mm->GetInitialProcessData(jsapi.cx(), &init, rv);
2916 if (NS_WARN_IF(rv.Failed())) {
2917 MOZ_CRASH();
2918 }
2919
2920 initialData.Write(jsapi.cx(), init, rv);
2921 if (NS_WARN_IF(rv.Failed())) {
2922 MOZ_CRASH();
2923 }
2924 }
2925 }
2926 // This is only implemented (returns a non-empty list) by MacOSX and Linux
2927 // at present.
2928 SystemFontList fontList;
2929 gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList);
2930
2931 const FullLookAndFeel& lnf = *RemoteLookAndFeel::ExtractData();
2932
2933 // If the shared fontlist is in use, collect its shmem block handles to pass
2934 // to the child.
2935 nsTArray<SharedMemoryHandle> sharedFontListBlocks;
2936 gfxPlatformFontList::PlatformFontList()->ShareFontListToProcess(
2937 &sharedFontListBlocks, OtherPid());
2938
2939 // Content processes have no permission to access profile directory, so we
2940 // send the file URL instead.
2941 auto* sheetCache = GlobalStyleSheetCache::Singleton();
2942 if (StyleSheet* ucs = sheetCache->GetUserContentSheet()) {
2943 xpcomInit.userContentSheetURL() = ucs->GetSheetURI();
2944 } else {
2945 xpcomInit.userContentSheetURL() = nullptr;
2946 }
2947
2948 // 1. Build ContentDeviceData first, as it may affect some gfxVars.
2949 gfxPlatform::GetPlatform()->BuildContentDeviceData(
2950 &xpcomInit.contentDeviceData());
2951 // 2. Gather non-default gfxVars.
2952 xpcomInit.gfxNonDefaultVarUpdates() = gfxVars::FetchNonDefaultVars();
2953 // 3. Start listening for gfxVars updates, to notify content process later on.
2954 gfxVars::AddReceiver(this);
2955
2956 nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
2957 if (gfxInfo) {
2958 GfxInfoBase* gfxInfoRaw = static_cast<GfxInfoBase*>(gfxInfo.get());
2959 xpcomInit.gfxFeatureStatus() = gfxInfoRaw->GetAllFeatures();
2960 }
2961
2962 #ifdef XP_WIN
2963 xpcomInit.systemParameters() =
2964 widget::WinContentSystemParameters::GetSingleton()->GetParentValues();
2965 #endif
2966
2967 // Send the dynamic scalar definitions to the new process.
2968 TelemetryIPC::GetDynamicScalarDefinitions(xpcomInit.dynamicScalarDefs());
2969
2970 for (auto const& [location, supported] : sCodecsSupported) {
2971 Unused << SendUpdateMediaCodecsSupported(location, supported);
2972 }
2973
2974 #ifdef MOZ_WIDGET_ANDROID
2975 Unused << SendDecoderSupportedMimeTypes(
2976 AndroidDecoderModule::GetSupportedMimeTypes());
2977 #endif
2978
2979 // Must send screen info before send initialData
2980 ScreenManager& screenManager = ScreenManager::GetSingleton();
2981 screenManager.CopyScreensToRemote(this);
2982
2983 // Send the UA sheet shared memory buffer and the address it is mapped at.
2984 Maybe<SharedMemoryHandle> sharedUASheetHandle;
2985 uintptr_t sharedUASheetAddress = sheetCache->GetSharedMemoryAddress();
2986
2987 if (SharedMemoryHandle handle = sheetCache->CloneHandle()) {
2988 sharedUASheetHandle.emplace(std::move(handle));
2989 } else {
2990 sharedUASheetAddress = 0;
2991 }
2992
2993 bool isReadyForBackgroundProcessing = false;
2994 #if defined(XP_WIN)
2995 RefPtr<DllServices> dllSvc(DllServices::Get());
2996 isReadyForBackgroundProcessing = dllSvc->IsReadyForBackgroundProcessing();
2997 #endif
2998
2999 Unused << SendSetXPCOMProcessAttributes(
3000 xpcomInit, initialData, lnf, fontList, std::move(sharedUASheetHandle),
3001 sharedUASheetAddress, std::move(sharedFontListBlocks),
3002 isReadyForBackgroundProcessing);
3003
3004 ipc::WritableSharedMap* sharedData =
3005 nsFrameMessageManager::sParentProcessManager->SharedData();
3006 sharedData->Flush();
3007 sharedData->SendTo(this);
3008
3009 nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
3010 nsChromeRegistryChrome* chromeRegistry =
3011 static_cast<nsChromeRegistryChrome*>(registrySvc.get());
3012 chromeRegistry->SendRegisteredChrome(this);
3013
3014 nsCOMPtr<nsIStringBundleService> stringBundleService =
3015 components::StringBundle::Service();
3016 stringBundleService->SendContentBundles(this);
3017
3018 if (gAppData) {
3019 nsCString version(gAppData->version);
3020 nsCString buildID(gAppData->buildID);
3021 nsCString name(gAppData->name);
3022 nsCString UAName(gAppData->UAName);
3023 nsCString ID(gAppData->ID);
3024 nsCString vendor(gAppData->vendor);
3025 nsCString sourceURL(gAppData->sourceURL);
3026 nsCString updateURL(gAppData->updateURL);
3027
3028 // Sending all information to content process.
3029 Unused << SendAppInfo(version, buildID, name, UAName, ID, vendor, sourceURL,
3030 updateURL);
3031 }
3032
3033 // Send the child its remote type. On Mac, this needs to be sent prior
3034 // to the message we send to enable the Sandbox (SendStartProcessSandbox)
3035 // because different remote types require different sandbox privileges.
3036 Unused << SendRemoteType(mRemoteType);
3037
3038 ScriptPreloader::InitContentChild(*this);
3039
3040 // Initialize the message manager (and load delayed scripts) now that we
3041 // have established communications with the child.
3042 mMessageManager->InitWithCallback(this);
3043 mMessageManager->SetOsPid(Pid());
3044
3045 // Set the subprocess's priority. We do this early on because we're likely
3046 // /lowering/ the process's CPU and memory priority, which it has inherited
3047 // from this process.
3048 //
3049 // This call can cause us to send IPC messages to the child process, so it
3050 // must come after the Open() call above.
3051 ProcessPriorityManager::SetProcessPriority(this, aInitialPriority);
3052
3053 // NB: internally, this will send an IPC message to the child
3054 // process to get it to create the CompositorBridgeChild. This
3055 // message goes through the regular IPC queue for this
3056 // channel, so delivery will happen-before any other messages
3057 // we send. The CompositorBridgeChild must be created before any
3058 // PBrowsers are created, because they rely on the Compositor
3059 // already being around. (Creation is async, so can't happen
3060 // on demand.)
3061 GPUProcessManager* gpm = GPUProcessManager::Get();
3062
3063 Endpoint<PCompositorManagerChild> compositor;
3064 Endpoint<PImageBridgeChild> imageBridge;
3065 Endpoint<PVRManagerChild> vrBridge;
3066 Endpoint<PRemoteDecoderManagerChild> videoManager;
3067 AutoTArray<uint32_t, 3> namespaces;
3068
3069 if (!gpm->CreateContentBridges(OtherPid(), &compositor, &imageBridge,
3070 &vrBridge, &videoManager, &namespaces)) {
3071 // This can fail if we've already started shutting down the compositor
3072 // thread. See Bug 1562763 comment 8.
3073 return false;
3074 }
3075
3076 Unused << SendInitRendering(std::move(compositor), std::move(imageBridge),
3077 std::move(vrBridge), std::move(videoManager),
3078 namespaces);
3079
3080 gpm->AddListener(this);
3081
3082 nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
3083 if (sheetService) {
3084 // This looks like a lot of work, but in a normal browser session we just
3085 // send two loads.
3086 //
3087 // The URIs of the Gecko and Servo sheets should be the same, so it
3088 // shouldn't matter which we look at.
3089
3090 for (StyleSheet* sheet : *sheetService->AgentStyleSheets()) {
3091 Unused << SendLoadAndRegisterSheet(sheet->GetSheetURI(),
3092 nsIStyleSheetService::AGENT_SHEET);
3093 }
3094
3095 for (StyleSheet* sheet : *sheetService->UserStyleSheets()) {
3096 Unused << SendLoadAndRegisterSheet(sheet->GetSheetURI(),
3097 nsIStyleSheetService::USER_SHEET);
3098 }
3099
3100 for (StyleSheet* sheet : *sheetService->AuthorStyleSheets()) {
3101 Unused << SendLoadAndRegisterSheet(sheet->GetSheetURI(),
3102 nsIStyleSheetService::AUTHOR_SHEET);
3103 }
3104 }
3105
3106 #ifdef MOZ_SANDBOX
3107 bool shouldSandbox = true;
3108 Maybe<FileDescriptor> brokerFd;
3109 // XXX: Checking the pref here makes it possible to enable/disable sandboxing
3110 // during an active session. Currently the pref is only used for testing
3111 // purpose. If the decision is made to permanently rely on the pref, this
3112 // should be changed so that it is required to restart firefox for the change
3113 // of value to take effect. Always send SetProcessSandbox message on macOS.
3114 # if !defined(XP_MACOSX)
3115 shouldSandbox = IsContentSandboxEnabled();
3116 # endif
3117
3118 # ifdef XP_LINUX
3119 if (shouldSandbox) {
3120 MOZ_ASSERT(!mSandboxBroker);
3121 bool isFileProcess = mRemoteType == FILE_REMOTE_TYPE;
3122 UniquePtr<SandboxBroker::Policy> policy =
3123 sSandboxBrokerPolicyFactory->GetContentPolicy(Pid(), isFileProcess);
3124 if (policy) {
3125 brokerFd = Some(FileDescriptor());
3126 mSandboxBroker =
3127 SandboxBroker::Create(std::move(policy), Pid(), brokerFd.ref());
3128 if (!mSandboxBroker) {
3129 KillHard("SandboxBroker::Create failed");
3130 return false;
3131 }
3132 MOZ_ASSERT(brokerFd.ref().IsValid());
3133 }
3134 }
3135 # endif
3136 if (shouldSandbox && !SendSetProcessSandbox(brokerFd)) {
3137 KillHard("SandboxInitFailed");
3138 }
3139 #endif
3140
3141 // Ensure that the default set of permissions are avaliable in the content
3142 // process before we try to load any URIs in it.
3143 //
3144 // NOTE: All default permissions has to be transmitted to the child process
3145 // before the blob urls in the for loop below (See Bug 1738713 comment 12).
3146 EnsurePermissionsByKey(""_ns, ""_ns);
3147
3148 {
3149 nsTArray<BlobURLRegistrationData> registrations;
3150 BlobURLProtocolHandler::ForEachBlobURL(
3151 [&](BlobImpl* aBlobImpl, nsIPrincipal* aPrincipal,
3152 const Maybe<nsID>& aAgentClusterId, const nsACString& aURI,
3153 bool aRevoked) {
3154 // We send all moz-extension Blob URL's to all content processes
3155 // because content scripts mean that a moz-extension can live in any
3156 // process. Same thing for system principal Blob URLs. Content Blob
3157 // URL's are sent for content principals on-demand by
3158 // AboutToLoadHttpFtpDocumentForChild and RemoteWorkerManager.
3159 if (!BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(
3160 aPrincipal)) {
3161 return true;
3162 }
3163
3164 IPCBlob ipcBlob;
3165 nsresult rv = IPCBlobUtils::Serialize(aBlobImpl, this, ipcBlob);
3166 if (NS_WARN_IF(NS_FAILED(rv))) {
3167 return false;
3168 }
3169
3170 registrations.AppendElement(BlobURLRegistrationData(
3171 nsCString(aURI), ipcBlob, aPrincipal, aAgentClusterId, aRevoked));
3172
3173 rv = TransmitPermissionsForPrincipal(aPrincipal);
3174 Unused << NS_WARN_IF(NS_FAILED(rv));
3175 return true;
3176 });
3177
3178 if (!registrations.IsEmpty()) {
3179 Unused << SendInitBlobURLs(registrations);
3180 }
3181 }
3182
3183 // Send down { Parent, Window }ActorOptions at startup to content process.
3184 RefPtr<JSActorService> actorSvc = JSActorService::GetSingleton();
3185 if (actorSvc) {
3186 nsTArray<JSProcessActorInfo> contentInfos;
3187 actorSvc->GetJSProcessActorInfos(contentInfos);
3188
3189 nsTArray<JSWindowActorInfo> windowInfos;
3190 actorSvc->GetJSWindowActorInfos(windowInfos);
3191
3192 Unused << SendInitJSActorInfos(contentInfos, windowInfos);
3193 }
3194
3195 // Begin subscribing to any BrowsingContextGroups which were hosted by this
3196 // process before it finished launching.
3197 for (const auto& group : mGroups) {
3198 group->Subscribe(this);
3199 }
3200
3201 MaybeEnableRemoteInputEventQueue();
3202
3203 return true;
3204 }
3205
IsAlive() const3206 bool ContentParent::IsAlive() const {
3207 return mLifecycleState == LifecycleState::ALIVE ||
3208 mLifecycleState == LifecycleState::INITIALIZED;
3209 }
3210
IsInitialized() const3211 bool ContentParent::IsInitialized() const {
3212 return mLifecycleState == LifecycleState::INITIALIZED;
3213 }
3214
Pid() const3215 int32_t ContentParent::Pid() const {
3216 if (!mSubprocess || !mSubprocess->GetChildProcessHandle()) {
3217 return -1;
3218 }
3219 return base::GetProcId(mSubprocess->GetChildProcessHandle());
3220 }
3221
RecvGetGfxVars(nsTArray<GfxVarUpdate> * aVars)3222 mozilla::ipc::IPCResult ContentParent::RecvGetGfxVars(
3223 nsTArray<GfxVarUpdate>* aVars) {
3224 // Ensure gfxVars is initialized (for xpcshell tests).
3225 gfxVars::Initialize();
3226
3227 *aVars = gfxVars::FetchNonDefaultVars();
3228
3229 // Now that content has initialized gfxVars, we can start listening for
3230 // updates.
3231 gfxVars::AddReceiver(this);
3232 return IPC_OK();
3233 }
3234
OnCompositorUnexpectedShutdown()3235 void ContentParent::OnCompositorUnexpectedShutdown() {
3236 GPUProcessManager* gpm = GPUProcessManager::Get();
3237
3238 Endpoint<PCompositorManagerChild> compositor;
3239 Endpoint<PImageBridgeChild> imageBridge;
3240 Endpoint<PVRManagerChild> vrBridge;
3241 Endpoint<PRemoteDecoderManagerChild> videoManager;
3242 AutoTArray<uint32_t, 3> namespaces;
3243
3244 DebugOnly<bool> opened =
3245 gpm->CreateContentBridges(OtherPid(), &compositor, &imageBridge,
3246 &vrBridge, &videoManager, &namespaces);
3247 MOZ_ASSERT(opened);
3248
3249 Unused << SendReinitRendering(std::move(compositor), std::move(imageBridge),
3250 std::move(vrBridge), std::move(videoManager),
3251 namespaces);
3252 }
3253
OnCompositorDeviceReset()3254 void ContentParent::OnCompositorDeviceReset() {
3255 Unused << SendReinitRenderingForDeviceReset();
3256 }
3257
MaybeEnableRemoteInputEventQueue()3258 void ContentParent::MaybeEnableRemoteInputEventQueue() {
3259 MOZ_ASSERT(!mIsRemoteInputEventQueueEnabled);
3260 if (!IsInputEventQueueSupported()) {
3261 return;
3262 }
3263 mIsRemoteInputEventQueueEnabled = true;
3264 Unused << SendSetInputEventQueueEnabled();
3265 SetInputPriorityEventEnabled(true);
3266 }
3267
SetInputPriorityEventEnabled(bool aEnabled)3268 void ContentParent::SetInputPriorityEventEnabled(bool aEnabled) {
3269 if (!IsInputEventQueueSupported() || !mIsRemoteInputEventQueueEnabled ||
3270 mIsInputPriorityEventEnabled == aEnabled) {
3271 return;
3272 }
3273 mIsInputPriorityEventEnabled = aEnabled;
3274 // Send IPC messages to flush the pending events in the input event queue and
3275 // the normal event queue. See PContent.ipdl for more details.
3276 Unused << SendSuspendInputEventQueue();
3277 Unused << SendFlushInputEventQueue();
3278 Unused << SendResumeInputEventQueue();
3279 }
3280
3281 /*static*/
IsInputEventQueueSupported()3282 bool ContentParent::IsInputEventQueueSupported() {
3283 static bool sSupported = false;
3284 static bool sInitialized = false;
3285 if (!sInitialized) {
3286 MOZ_ASSERT(Preferences::IsServiceAvailable());
3287 sSupported = Preferences::GetBool("input_event_queue.supported", false);
3288 sInitialized = true;
3289 }
3290 return sSupported;
3291 }
3292
OnVarChanged(const GfxVarUpdate & aVar)3293 void ContentParent::OnVarChanged(const GfxVarUpdate& aVar) {
3294 if (!CanSend()) {
3295 return;
3296 }
3297 Unused << SendVarUpdate(aVar);
3298 }
3299
RecvSetClipboard(const IPCDataTransfer & aDataTransfer,const bool & aIsPrivateData,const IPC::Principal & aRequestingPrincipal,const nsContentPolicyType & aContentPolicyType,const int32_t & aWhichClipboard)3300 mozilla::ipc::IPCResult ContentParent::RecvSetClipboard(
3301 const IPCDataTransfer& aDataTransfer, const bool& aIsPrivateData,
3302 const IPC::Principal& aRequestingPrincipal,
3303 const nsContentPolicyType& aContentPolicyType,
3304 const int32_t& aWhichClipboard) {
3305 if (!ValidatePrincipal(aRequestingPrincipal,
3306 {ValidatePrincipalOptions::AllowNullPtr})) {
3307 LogAndAssertFailedPrincipalValidationInfo(aRequestingPrincipal, __func__);
3308 }
3309
3310 nsresult rv;
3311 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
3312 NS_ENSURE_SUCCESS(rv, IPC_OK());
3313
3314 nsCOMPtr<nsITransferable> trans =
3315 do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
3316 NS_ENSURE_SUCCESS(rv, IPC_OK());
3317 trans->Init(nullptr);
3318
3319 rv = nsContentUtils::IPCTransferableToTransferable(
3320 aDataTransfer, aIsPrivateData, aRequestingPrincipal, aContentPolicyType,
3321 trans, this, nullptr);
3322 NS_ENSURE_SUCCESS(rv, IPC_OK());
3323
3324 clipboard->SetData(trans, nullptr, aWhichClipboard);
3325 return IPC_OK();
3326 }
3327
RecvGetClipboard(nsTArray<nsCString> && aTypes,const int32_t & aWhichClipboard,IPCDataTransfer * aDataTransfer)3328 mozilla::ipc::IPCResult ContentParent::RecvGetClipboard(
3329 nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
3330 IPCDataTransfer* aDataTransfer) {
3331 nsresult rv = GetDataFromClipboard(aTypes, aWhichClipboard,
3332 true /* aInSyncMessage */, aDataTransfer);
3333 NS_ENSURE_SUCCESS(rv, IPC_OK());
3334 return IPC_OK();
3335 }
3336
RecvEmptyClipboard(const int32_t & aWhichClipboard)3337 mozilla::ipc::IPCResult ContentParent::RecvEmptyClipboard(
3338 const int32_t& aWhichClipboard) {
3339 nsresult rv;
3340 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
3341 NS_ENSURE_SUCCESS(rv, IPC_OK());
3342
3343 clipboard->EmptyClipboard(aWhichClipboard);
3344
3345 return IPC_OK();
3346 }
3347
RecvClipboardHasType(nsTArray<nsCString> && aTypes,const int32_t & aWhichClipboard,bool * aHasType)3348 mozilla::ipc::IPCResult ContentParent::RecvClipboardHasType(
3349 nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
3350 bool* aHasType) {
3351 nsresult rv;
3352 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
3353 NS_ENSURE_SUCCESS(rv, IPC_OK());
3354
3355 clipboard->HasDataMatchingFlavors(aTypes, aWhichClipboard, aHasType);
3356
3357 return IPC_OK();
3358 }
3359
RecvGetExternalClipboardFormats(const int32_t & aWhichClipboard,const bool & aPlainTextOnly,nsTArray<nsCString> * aTypes)3360 mozilla::ipc::IPCResult ContentParent::RecvGetExternalClipboardFormats(
3361 const int32_t& aWhichClipboard, const bool& aPlainTextOnly,
3362 nsTArray<nsCString>* aTypes) {
3363 MOZ_ASSERT(aTypes);
3364 DataTransfer::GetExternalClipboardFormats(aWhichClipboard, aPlainTextOnly,
3365 aTypes);
3366 return IPC_OK();
3367 }
3368
GetDataFromClipboard(const nsTArray<nsCString> & aTypes,const int32_t aWhichClipboard,const bool aInSyncMessage,IPCDataTransfer * aDataTransfer)3369 nsresult ContentParent::GetDataFromClipboard(const nsTArray<nsCString>& aTypes,
3370 const int32_t aWhichClipboard,
3371 const bool aInSyncMessage,
3372 IPCDataTransfer* aDataTransfer) {
3373 nsresult rv;
3374 // Retrieve clipboard
3375 nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
3376 if (NS_FAILED(rv)) {
3377 return rv;
3378 }
3379
3380 // Create transferable
3381 nsCOMPtr<nsITransferable> trans =
3382 do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
3383 if (NS_FAILED(rv)) {
3384 return rv;
3385 }
3386 trans->Init(nullptr);
3387
3388 // The private flag is only used to prevent the data from being cached to the
3389 // disk. The flag is not exported to the IPCDataTransfer object.
3390 // The flag is set because we are not sure whether the clipboard data is used
3391 // in a private browsing context. The transferable is only used in this scope,
3392 // so the cache would not reduce memory consumption anyway.
3393 trans->SetIsPrivateData(true);
3394
3395 // Fill out flavors for transferable
3396 for (uint32_t t = 0; t < aTypes.Length(); t++) {
3397 trans->AddDataFlavor(aTypes[t].get());
3398 }
3399
3400 // Get data from clipboard
3401 clipboard->GetData(trans, aWhichClipboard);
3402
3403 nsContentUtils::TransferableToIPCTransferable(trans, aDataTransfer,
3404 aInSyncMessage, nullptr, this);
3405 return NS_OK;
3406 }
3407
RecvGetClipboardAsync(nsTArray<nsCString> && aTypes,const int32_t & aWhichClipboard,GetClipboardAsyncResolver && aResolver)3408 mozilla::ipc::IPCResult ContentParent::RecvGetClipboardAsync(
3409 nsTArray<nsCString>&& aTypes, const int32_t& aWhichClipboard,
3410 GetClipboardAsyncResolver&& aResolver) {
3411 IPCDataTransfer ipcDataTransfer;
3412
3413 nsresult rv = GetDataFromClipboard(
3414 aTypes, aWhichClipboard, false /* aInSyncMessage */, &ipcDataTransfer);
3415 if (NS_FAILED(rv)) {
3416 return IPC_FAIL(this, "RecvGetClipboardAsync failed.");
3417 }
3418
3419 // Resolve the promise
3420 aResolver(ipcDataTransfer);
3421 return IPC_OK();
3422 }
3423
RecvPlaySound(nsIURI * aURI)3424 mozilla::ipc::IPCResult ContentParent::RecvPlaySound(nsIURI* aURI) {
3425 // If the check here fails, it can only mean that this message was spoofed.
3426 if (!aURI || !aURI->SchemeIs("chrome")) {
3427 // PlaySound only accepts a valid chrome URI.
3428 return IPC_FAIL_NO_REASON(this);
3429 }
3430 nsCOMPtr<nsIURL> soundURL(do_QueryInterface(aURI));
3431 if (!soundURL) {
3432 return IPC_OK();
3433 }
3434
3435 nsresult rv;
3436 nsCOMPtr<nsISound> sound(do_GetService(NS_SOUND_CID, &rv));
3437 NS_ENSURE_SUCCESS(rv, IPC_OK());
3438
3439 sound->Play(soundURL);
3440
3441 return IPC_OK();
3442 }
3443
RecvBeep()3444 mozilla::ipc::IPCResult ContentParent::RecvBeep() {
3445 nsresult rv;
3446 nsCOMPtr<nsISound> sound(do_GetService(NS_SOUND_CID, &rv));
3447 NS_ENSURE_SUCCESS(rv, IPC_OK());
3448
3449 sound->Beep();
3450
3451 return IPC_OK();
3452 }
3453
RecvPlayEventSound(const uint32_t & aEventId)3454 mozilla::ipc::IPCResult ContentParent::RecvPlayEventSound(
3455 const uint32_t& aEventId) {
3456 nsresult rv;
3457 nsCOMPtr<nsISound> sound(do_GetService(NS_SOUND_CID, &rv));
3458 NS_ENSURE_SUCCESS(rv, IPC_OK());
3459
3460 sound->PlayEventSound(aEventId);
3461
3462 return IPC_OK();
3463 }
3464
RecvGetIconForExtension(const nsCString & aFileExt,const uint32_t & aIconSize,nsTArray<uint8_t> * bits)3465 mozilla::ipc::IPCResult ContentParent::RecvGetIconForExtension(
3466 const nsCString& aFileExt, const uint32_t& aIconSize,
3467 nsTArray<uint8_t>* bits) {
3468 #ifdef MOZ_WIDGET_ANDROID
3469 NS_ASSERTION(AndroidBridge::Bridge() != nullptr,
3470 "AndroidBridge is not available");
3471 if (AndroidBridge::Bridge() == nullptr) {
3472 // Do not fail - just no icon will be shown
3473 return IPC_OK();
3474 }
3475
3476 bits->AppendElements(aIconSize * aIconSize * 4);
3477
3478 AndroidBridge::Bridge()->GetIconForExtension(aFileExt, aIconSize,
3479 bits->Elements());
3480 #endif
3481 return IPC_OK();
3482 }
3483
RecvFirstIdle()3484 mozilla::ipc::IPCResult ContentParent::RecvFirstIdle() {
3485 // When the ContentChild goes idle, it sends us a FirstIdle message
3486 // which we use as a good time to signal the PreallocatedProcessManager
3487 // that it can start allocating processes from now on.
3488 if (mIsAPreallocBlocker) {
3489 MOZ_LOG(
3490 ContentParent::GetLog(), LogLevel::Verbose,
3491 ("RecvFirstIdle %p: Removing Blocker for %s", this, mRemoteType.get()));
3492 PreallocatedProcessManager::RemoveBlocker(mRemoteType, this);
3493 mIsAPreallocBlocker = false;
3494 }
3495 return IPC_OK();
3496 }
3497
3498 // We want ContentParent to show up in CC logs for debugging purposes, but we
3499 // don't actually cycle collect it.
3500 NS_IMPL_CYCLE_COLLECTION_0(ContentParent)
3501
NS_IMPL_CYCLE_COLLECTING_ADDREF(ContentParent)3502 NS_IMPL_CYCLE_COLLECTING_ADDREF(ContentParent)
3503 NS_IMPL_CYCLE_COLLECTING_RELEASE(ContentParent)
3504
3505 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ContentParent)
3506 NS_INTERFACE_MAP_ENTRY_CONCRETE(ContentParent)
3507 NS_INTERFACE_MAP_ENTRY(nsIDOMProcessParent)
3508 NS_INTERFACE_MAP_ENTRY(nsIObserver)
3509 NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionCallback)
3510 NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionErrorCallback)
3511 NS_INTERFACE_MAP_ENTRY(nsIAsyncShutdownBlocker)
3512 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
3513 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMProcessParent)
3514 NS_INTERFACE_MAP_END
3515
3516 // Async shutdown blocker
3517 NS_IMETHODIMP
3518 ContentParent::BlockShutdown(nsIAsyncShutdownClient* aClient) {
3519 // Make sure that our process will get scheduled.
3520 ProcessPriorityManager::SetProcessPriority(this, PROCESS_PRIORITY_FOREGROUND);
3521
3522 // Okay to call ShutDownProcess multiple times.
3523 ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
3524 MarkAsDead();
3525
3526 return NS_OK;
3527 }
3528
3529 NS_IMETHODIMP
GetName(nsAString & aName)3530 ContentParent::GetName(nsAString& aName) {
3531 aName.AssignLiteral("ContentParent:");
3532 aName.AppendPrintf(" id=%p", this);
3533 return NS_OK;
3534 }
3535
3536 NS_IMETHODIMP
GetState(nsIPropertyBag ** aResult)3537 ContentParent::GetState(nsIPropertyBag** aResult) {
3538 auto props = MakeRefPtr<nsHashPropertyBag>();
3539 props->SetPropertyAsACString(u"remoteTypePrefix"_ns,
3540 RemoteTypePrefix(mRemoteType));
3541 *aResult = props.forget().downcast<nsIWritablePropertyBag>().take();
3542 return NS_OK;
3543 }
3544
3545 static StaticRefPtr<nsIAsyncShutdownClient> sXPCOMShutdownClient;
3546 static StaticRefPtr<nsIAsyncShutdownClient> sProfileBeforeChangeClient;
3547
InitClients()3548 static void InitClients() {
3549 if (!sXPCOMShutdownClient) {
3550 nsresult rv;
3551 nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdownService();
3552
3553 nsCOMPtr<nsIAsyncShutdownClient> client;
3554 rv = svc->GetXpcomWillShutdown(getter_AddRefs(client));
3555 sXPCOMShutdownClient = client.forget();
3556 ClearOnShutdown(&sXPCOMShutdownClient);
3557 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv), "XPCOMShutdown shutdown blocker");
3558
3559 rv = svc->GetProfileBeforeChange(getter_AddRefs(client));
3560 sProfileBeforeChangeClient = client.forget();
3561 ClearOnShutdown(&sProfileBeforeChangeClient);
3562 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv),
3563 "profileBeforeChange shutdown blocker");
3564 }
3565 }
3566
AddShutdownBlockers()3567 void ContentParent::AddShutdownBlockers() {
3568 InitClients();
3569
3570 sXPCOMShutdownClient->AddBlocker(
3571 this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
3572 sProfileBeforeChangeClient->AddBlocker(
3573 this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
3574 }
3575
RemoveShutdownBlockers()3576 void ContentParent::RemoveShutdownBlockers() {
3577 Unused << sXPCOMShutdownClient->RemoveBlocker(this);
3578 Unused << sProfileBeforeChangeClient->RemoveBlocker(this);
3579 }
3580
3581 NS_IMETHODIMP
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * aData)3582 ContentParent::Observe(nsISupports* aSubject, const char* aTopic,
3583 const char16_t* aData) {
3584 if (IsDead() || !mSubprocess) {
3585 return NS_OK;
3586 }
3587
3588 if (!strcmp(aTopic, "nsPref:changed")) {
3589 // We know prefs are ASCII here.
3590 NS_LossyConvertUTF16toASCII strData(aData);
3591
3592 // A pref changed. If it is useful to do so, inform child processes.
3593 if (!ShouldSyncPreference(strData.Data())) {
3594 return NS_OK;
3595 }
3596
3597 Pref pref(strData, /* isLocked */ false, Nothing(), Nothing());
3598 Preferences::GetPreference(&pref);
3599 if (IsInitialized()) {
3600 MOZ_ASSERT(mQueuedPrefs.IsEmpty());
3601 if (!SendPreferenceUpdate(pref)) {
3602 return NS_ERROR_NOT_AVAILABLE;
3603 }
3604 } else {
3605 MOZ_ASSERT(!IsDead());
3606 mQueuedPrefs.AppendElement(pref);
3607 }
3608 }
3609
3610 if (!IsAlive()) {
3611 return NS_OK;
3612 }
3613
3614 // listening for memory pressure event
3615 if (!strcmp(aTopic, "memory-pressure")) {
3616 Unused << SendFlushMemory(nsDependentString(aData));
3617 } else if (!strcmp(aTopic, "application-background")) {
3618 Unused << SendApplicationBackground();
3619 } else if (!strcmp(aTopic, "application-foreground")) {
3620 Unused << SendApplicationForeground();
3621 } else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC)) {
3622 NS_ConvertUTF16toUTF8 dataStr(aData);
3623 const char* offline = dataStr.get();
3624 if (!SendSetOffline(!strcmp(offline, "true"))) {
3625 return NS_ERROR_NOT_AVAILABLE;
3626 }
3627 } else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC)) {
3628 if (!SendSetConnectivity(u"true"_ns.Equals(aData))) {
3629 return NS_ERROR_NOT_AVAILABLE;
3630 }
3631 } else if (!strcmp(aTopic, NS_IPC_CAPTIVE_PORTAL_SET_STATE)) {
3632 nsCOMPtr<nsICaptivePortalService> cps = do_QueryInterface(aSubject);
3633 MOZ_ASSERT(cps, "Should QI to a captive portal service");
3634 if (!cps) {
3635 return NS_ERROR_FAILURE;
3636 }
3637 int32_t state;
3638 cps->GetState(&state);
3639 if (!SendSetCaptivePortalState(state)) {
3640 return NS_ERROR_NOT_AVAILABLE;
3641 }
3642 }
3643 // listening for alert notifications
3644 else if (!strcmp(aTopic, "alertfinished") ||
3645 !strcmp(aTopic, "alertclickcallback") ||
3646 !strcmp(aTopic, "alertshow") ||
3647 !strcmp(aTopic, "alertdisablecallback") ||
3648 !strcmp(aTopic, "alertsettingscallback")) {
3649 if (!SendNotifyAlertsObserver(nsDependentCString(aTopic),
3650 nsDependentString(aData)))
3651 return NS_ERROR_NOT_AVAILABLE;
3652 } else if (!strcmp(aTopic, "child-gc-request")) {
3653 Unused << SendGarbageCollect();
3654 } else if (!strcmp(aTopic, "child-cc-request")) {
3655 Unused << SendCycleCollect();
3656 } else if (!strcmp(aTopic, "child-mmu-request")) {
3657 Unused << SendMinimizeMemoryUsage();
3658 } else if (!strcmp(aTopic, "child-ghost-request")) {
3659 Unused << SendUnlinkGhosts();
3660 } else if (!strcmp(aTopic, "last-pb-context-exited")) {
3661 Unused << SendLastPrivateDocShellDestroyed();
3662 }
3663 #ifdef ACCESSIBILITY
3664 else if (aData && !strcmp(aTopic, "a11y-init-or-shutdown")) {
3665 if (*aData == '1') {
3666 // Make sure accessibility is running in content process when
3667 // accessibility gets initiated in chrome process.
3668 # if defined(XP_WIN)
3669 // Don't init content a11y if we detect an incompat version of JAWS in
3670 // use.
3671 if (!mozilla::a11y::Compatibility::IsOldJAWS()) {
3672 Unused << SendActivateA11y(
3673 ::GetCurrentThreadId(),
3674 a11y::MsaaAccessible::GetContentProcessIdFor(ChildID()));
3675 }
3676 # else
3677 Unused << SendActivateA11y(0, 0);
3678 # endif
3679 } else {
3680 // If possible, shut down accessibility in content process when
3681 // accessibility gets shutdown in chrome process.
3682 Unused << SendShutdownA11y();
3683 }
3684 }
3685 #endif
3686 else if (!strcmp(aTopic, "cacheservice:empty-cache")) {
3687 Unused << SendNotifyEmptyHTTPCache();
3688 } else if (!strcmp(aTopic, "intl:app-locales-changed")) {
3689 nsTArray<nsCString> appLocales;
3690 LocaleService::GetInstance()->GetAppLocalesAsBCP47(appLocales);
3691 Unused << SendUpdateAppLocales(appLocales);
3692 } else if (!strcmp(aTopic, "intl:requested-locales-changed")) {
3693 nsTArray<nsCString> requestedLocales;
3694 LocaleService::GetInstance()->GetRequestedLocales(requestedLocales);
3695 Unused << SendUpdateRequestedLocales(requestedLocales);
3696 } else if (!strcmp(aTopic, "cookie-changed") ||
3697 !strcmp(aTopic, "private-cookie-changed")) {
3698 if (!aData) {
3699 return NS_ERROR_UNEXPECTED;
3700 }
3701 PNeckoParent* neckoParent = LoneManagedOrNullAsserts(ManagedPNeckoParent());
3702 if (!neckoParent) {
3703 return NS_OK;
3704 }
3705 PCookieServiceParent* csParent =
3706 LoneManagedOrNullAsserts(neckoParent->ManagedPCookieServiceParent());
3707 if (!csParent) {
3708 return NS_OK;
3709 }
3710 auto* cs = static_cast<CookieServiceParent*>(csParent);
3711 // Do not push these cookie updates to the same process they originated
3712 // from.
3713 if (cs->ProcessingCookie()) {
3714 return NS_OK;
3715 }
3716 if (!nsCRT::strcmp(aData, u"batch-deleted")) {
3717 nsCOMPtr<nsIArray> cookieList = do_QueryInterface(aSubject);
3718 NS_ASSERTION(cookieList, "couldn't get cookie list");
3719 cs->RemoveBatchDeletedCookies(cookieList);
3720 return NS_OK;
3721 }
3722
3723 if (!nsCRT::strcmp(aData, u"cleared")) {
3724 cs->RemoveAll();
3725 return NS_OK;
3726 }
3727
3728 nsCOMPtr<nsICookie> xpcCookie = do_QueryInterface(aSubject);
3729 NS_ASSERTION(xpcCookie, "couldn't get cookie");
3730 if (!nsCRT::strcmp(aData, u"deleted")) {
3731 cs->RemoveCookie(xpcCookie);
3732 } else if ((!nsCRT::strcmp(aData, u"added")) ||
3733 (!nsCRT::strcmp(aData, u"changed"))) {
3734 cs->AddCookie(xpcCookie);
3735 }
3736 } else if (!strcmp(aTopic, NS_NETWORK_LINK_TYPE_TOPIC)) {
3737 UpdateNetworkLinkType();
3738 } else if (!strcmp(aTopic, "network:socket-process-crashed")) {
3739 Unused << SendSocketProcessCrashed();
3740 }
3741
3742 return NS_OK;
3743 }
3744
3745 /* static */
ShouldSyncPreference(const char * aPref)3746 bool ContentParent::ShouldSyncPreference(const char* aPref) {
3747 #define PARENT_ONLY_PREF_LIST_ENTRY(s) \
3748 { s, (sizeof(s) / sizeof(char)) - 1 }
3749 struct ParentOnlyPrefListEntry {
3750 const char* mPrefBranch;
3751 size_t mLen;
3752 };
3753 // These prefs are not useful in child processes.
3754 static const ParentOnlyPrefListEntry sParentOnlyPrefBranchList[] = {
3755 PARENT_ONLY_PREF_LIST_ENTRY("app.update.lastUpdateTime."),
3756 PARENT_ONLY_PREF_LIST_ENTRY("datareporting.policy."),
3757 PARENT_ONLY_PREF_LIST_ENTRY("browser.safebrowsing.provider."),
3758 PARENT_ONLY_PREF_LIST_ENTRY("browser.shell."),
3759 PARENT_ONLY_PREF_LIST_ENTRY("browser.slowStartup."),
3760 PARENT_ONLY_PREF_LIST_ENTRY("browser.startup."),
3761 PARENT_ONLY_PREF_LIST_ENTRY("extensions.getAddons.cache."),
3762 PARENT_ONLY_PREF_LIST_ENTRY("media.gmp-manager."),
3763 PARENT_ONLY_PREF_LIST_ENTRY("media.gmp-gmpopenh264."),
3764 PARENT_ONLY_PREF_LIST_ENTRY("privacy.sanitize."),
3765 };
3766 #undef PARENT_ONLY_PREF_LIST_ENTRY
3767
3768 for (const auto& entry : sParentOnlyPrefBranchList) {
3769 if (strncmp(entry.mPrefBranch, aPref, entry.mLen) == 0) {
3770 return false;
3771 }
3772 }
3773 return true;
3774 }
3775
UpdateNetworkLinkType()3776 void ContentParent::UpdateNetworkLinkType() {
3777 nsresult rv;
3778 nsCOMPtr<nsINetworkLinkService> nls =
3779 do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv);
3780 if (NS_FAILED(rv)) {
3781 return;
3782 }
3783
3784 uint32_t linkType = nsINetworkLinkService::LINK_TYPE_UNKNOWN;
3785 rv = nls->GetLinkType(&linkType);
3786 if (NS_FAILED(rv)) {
3787 return;
3788 }
3789
3790 Unused << SendNetworkLinkTypeChange(linkType);
3791 }
3792
3793 NS_IMETHODIMP
GetInterface(const nsIID & aIID,void ** aResult)3794 ContentParent::GetInterface(const nsIID& aIID, void** aResult) {
3795 NS_ENSURE_ARG_POINTER(aResult);
3796
3797 if (aIID.Equals(NS_GET_IID(nsIMessageSender))) {
3798 nsCOMPtr<nsIMessageSender> mm = GetMessageManager();
3799 mm.forget(aResult);
3800 return NS_OK;
3801 }
3802
3803 return NS_NOINTERFACE;
3804 }
3805
RecvInitBackground(Endpoint<PBackgroundStarterParent> && aEndpoint)3806 mozilla::ipc::IPCResult ContentParent::RecvInitBackground(
3807 Endpoint<PBackgroundStarterParent>&& aEndpoint) {
3808 if (!BackgroundParent::AllocStarter(this, std::move(aEndpoint))) {
3809 NS_WARNING("BackgroundParent::Alloc failed");
3810 }
3811
3812 return IPC_OK();
3813 }
3814
CanOpenBrowser(const IPCTabContext & aContext)3815 bool ContentParent::CanOpenBrowser(const IPCTabContext& aContext) {
3816 // (PopupIPCTabContext lets the child process prove that it has access to
3817 // the app it's trying to open.)
3818 // On e10s we also allow UnsafeTabContext to allow service workers to open
3819 // windows. This is enforced in MaybeInvalidTabContext.
3820 if (aContext.type() != IPCTabContext::TPopupIPCTabContext) {
3821 MOZ_CRASH_UNLESS_FUZZING(
3822 "Unexpected IPCTabContext type. Aborting AllocPBrowserParent.");
3823 return false;
3824 }
3825
3826 if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
3827 const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext();
3828
3829 auto opener = BrowserParent::GetFrom(popupContext.openerParent());
3830 if (!opener) {
3831 MOZ_CRASH_UNLESS_FUZZING(
3832 "Got null opener from child; aborting AllocPBrowserParent.");
3833 return false;
3834 }
3835 }
3836
3837 MaybeInvalidTabContext tc(aContext);
3838 if (!tc.IsValid()) {
3839 NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext. (%s) "
3840 "Aborting AllocPBrowserParent.",
3841 tc.GetInvalidReason())
3842 .get());
3843 return false;
3844 }
3845
3846 return true;
3847 }
3848
CloneIsLegal(ContentParent * aCp,CanonicalBrowsingContext & aSource,CanonicalBrowsingContext & aTarget)3849 static bool CloneIsLegal(ContentParent* aCp, CanonicalBrowsingContext& aSource,
3850 CanonicalBrowsingContext& aTarget) {
3851 // Source and target must be in the same BCG
3852 if (NS_WARN_IF(aSource.Group() != aTarget.Group())) {
3853 return false;
3854 }
3855 // The source and target must be in different toplevel <browser>s
3856 if (NS_WARN_IF(aSource.Top() == aTarget.Top())) {
3857 return false;
3858 }
3859
3860 // Neither source nor target must be toplevel.
3861 if (NS_WARN_IF(aSource.IsTop()) || NS_WARN_IF(aTarget.IsTop())) {
3862 return false;
3863 }
3864
3865 // Both should be embedded by the same process.
3866 auto* sourceEmbedder = aSource.GetParentWindowContext();
3867 if (NS_WARN_IF(!sourceEmbedder) ||
3868 NS_WARN_IF(sourceEmbedder->GetContentParent() != aCp)) {
3869 return false;
3870 }
3871
3872 auto* targetEmbedder = aSource.GetParentWindowContext();
3873 if (NS_WARN_IF(!targetEmbedder) ||
3874 NS_WARN_IF(targetEmbedder->GetContentParent() != aCp)) {
3875 return false;
3876 }
3877
3878 // All seems sane.
3879 return true;
3880 }
3881
RecvCloneDocumentTreeInto(const MaybeDiscarded<BrowsingContext> & aSource,const MaybeDiscarded<BrowsingContext> & aTarget,PrintData && aPrintData)3882 mozilla::ipc::IPCResult ContentParent::RecvCloneDocumentTreeInto(
3883 const MaybeDiscarded<BrowsingContext>& aSource,
3884 const MaybeDiscarded<BrowsingContext>& aTarget, PrintData&& aPrintData) {
3885 if (aSource.IsNullOrDiscarded() || aTarget.IsNullOrDiscarded()) {
3886 return IPC_OK();
3887 }
3888
3889 auto* source = aSource.get_canonical();
3890 auto* target = aTarget.get_canonical();
3891
3892 if (!CloneIsLegal(this, *source, *target)) {
3893 return IPC_FAIL(this, "Illegal subframe clone");
3894 }
3895
3896 ContentParent* cp = source->GetContentParent();
3897 if (NS_WARN_IF(!cp)) {
3898 return IPC_OK();
3899 }
3900
3901 if (NS_WARN_IF(cp->GetRemoteType() == GetRemoteType())) {
3902 // Wanted to switch to a target browsing context that's already local again.
3903 // See bug 1676996 for how this can happen.
3904 //
3905 // Dropping the switch on the floor seems fine for this case, though we
3906 // could also try to clone the local document.
3907 //
3908 // If the remote type matches & it's in the same group (which was confirmed
3909 // by CloneIsLegal), it must be the exact same process.
3910 MOZ_DIAGNOSTIC_ASSERT(cp == this);
3911 return IPC_OK();
3912 }
3913
3914 target->CloneDocumentTreeInto(source, cp->GetRemoteType(),
3915 std::move(aPrintData));
3916 return IPC_OK();
3917 }
3918
RecvUpdateRemotePrintSettings(const MaybeDiscarded<BrowsingContext> & aTarget,PrintData && aPrintData)3919 mozilla::ipc::IPCResult ContentParent::RecvUpdateRemotePrintSettings(
3920 const MaybeDiscarded<BrowsingContext>& aTarget, PrintData&& aPrintData) {
3921 if (aTarget.IsNullOrDiscarded()) {
3922 return IPC_OK();
3923 }
3924
3925 auto* target = aTarget.get_canonical();
3926 auto* bp = target->GetBrowserParent();
3927 if (NS_WARN_IF(!bp)) {
3928 return IPC_OK();
3929 }
3930
3931 Unused << bp->SendUpdateRemotePrintSettings(std::move(aPrintData));
3932 return IPC_OK();
3933 }
3934
RecvConstructPopupBrowser(ManagedEndpoint<PBrowserParent> && aBrowserEp,ManagedEndpoint<PWindowGlobalParent> && aWindowEp,const TabId & aTabId,const IPCTabContext & aContext,const WindowGlobalInit & aInitialWindowInit,const uint32_t & aChromeFlags)3935 mozilla::ipc::IPCResult ContentParent::RecvConstructPopupBrowser(
3936 ManagedEndpoint<PBrowserParent>&& aBrowserEp,
3937 ManagedEndpoint<PWindowGlobalParent>&& aWindowEp, const TabId& aTabId,
3938 const IPCTabContext& aContext, const WindowGlobalInit& aInitialWindowInit,
3939 const uint32_t& aChromeFlags) {
3940 MOZ_ASSERT(XRE_IsParentProcess());
3941
3942 if (!CanOpenBrowser(aContext)) {
3943 return IPC_FAIL(this, "CanOpenBrowser Failed");
3944 }
3945
3946 RefPtr<CanonicalBrowsingContext> browsingContext =
3947 CanonicalBrowsingContext::Get(
3948 aInitialWindowInit.context().mBrowsingContextId);
3949 if (!browsingContext || browsingContext->IsDiscarded()) {
3950 return IPC_FAIL(this, "Null or discarded initial BrowsingContext");
3951 }
3952 if (!aInitialWindowInit.principal()) {
3953 return IPC_FAIL(this, "Cannot create without valid initial principal");
3954 }
3955
3956 if (!ValidatePrincipal(aInitialWindowInit.principal())) {
3957 LogAndAssertFailedPrincipalValidationInfo(aInitialWindowInit.principal(),
3958 __func__);
3959 }
3960
3961 if (browsingContext->GetBrowserParent()) {
3962 return IPC_FAIL(this, "BrowsingContext already has a BrowserParent");
3963 }
3964
3965 uint32_t chromeFlags = aChromeFlags;
3966 TabId openerTabId(0);
3967 ContentParentId openerCpId(0);
3968 if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
3969 // CanOpenBrowser has ensured that the IPCTabContext is of
3970 // type PopupIPCTabContext, and that the opener BrowserParent is
3971 // reachable.
3972 const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext();
3973 auto opener = BrowserParent::GetFrom(popupContext.openerParent());
3974 openerTabId = opener->GetTabId();
3975 openerCpId = opener->Manager()->ChildID();
3976
3977 // We must ensure that the private browsing and remoteness flags
3978 // match those of the opener.
3979 nsCOMPtr<nsILoadContext> loadContext = opener->GetLoadContext();
3980 if (!loadContext) {
3981 return IPC_FAIL(this, "Missing Opener LoadContext");
3982 }
3983 if (loadContext->UsePrivateBrowsing()) {
3984 chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
3985 }
3986 if (loadContext->UseRemoteSubframes()) {
3987 chromeFlags |= nsIWebBrowserChrome::CHROME_FISSION_WINDOW;
3988 }
3989 }
3990
3991 // And because we're allocating a remote browser, of course the
3992 // window is remote.
3993 chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
3994
3995 if (NS_WARN_IF(!browsingContext->IsOwnedByProcess(ChildID()))) {
3996 return IPC_FAIL(this, "BrowsingContext Owned by Incorrect Process!");
3997 }
3998
3999 MaybeInvalidTabContext tc(aContext);
4000 MOZ_ASSERT(tc.IsValid());
4001
4002 RefPtr<WindowGlobalParent> initialWindow =
4003 WindowGlobalParent::CreateDisconnected(aInitialWindowInit);
4004 if (!initialWindow) {
4005 return IPC_FAIL(this, "Failed to create WindowGlobalParent");
4006 }
4007
4008 auto parent = MakeRefPtr<BrowserParent>(this, aTabId, tc.GetTabContext(),
4009 browsingContext, chromeFlags);
4010
4011 // Bind the created BrowserParent to IPC to actually link the actor.
4012 if (NS_WARN_IF(!BindPBrowserEndpoint(std::move(aBrowserEp), parent))) {
4013 return IPC_FAIL(this, "BindPBrowserEndpoint failed");
4014 }
4015
4016 // XXX: Why are we checking these requirements? It seems we should register
4017 // the created frame unconditionally?
4018 if (openerTabId > 0) {
4019 // The creation of PBrowser was triggered from content process through
4020 // window.open().
4021 // We need to register remote frame with the child generated tab id.
4022 auto* cpm = ContentProcessManager::GetSingleton();
4023 if (!cpm->RegisterRemoteFrame(parent)) {
4024 return IPC_FAIL(this, "RegisterRemoteFrame Failed");
4025 }
4026 }
4027
4028 if (NS_WARN_IF(!parent->BindPWindowGlobalEndpoint(std::move(aWindowEp),
4029 initialWindow))) {
4030 return IPC_FAIL(this, "BindPWindowGlobalEndpoint failed");
4031 }
4032
4033 browsingContext->SetCurrentBrowserParent(parent);
4034
4035 initialWindow->Init();
4036
4037 // When enabling input event prioritization, input events may preempt other
4038 // normal priority IPC messages. To prevent the input events preempt
4039 // PBrowserConstructor, we use an IPC 'RemoteIsReadyToHandleInputEvents' to
4040 // notify parent that BrowserChild is created. In this case, PBrowser is
4041 // initiated from content so that we can set BrowserParent as ready to handle
4042 // input
4043 parent->SetReadyToHandleInputEvents();
4044 return IPC_OK();
4045 }
4046
4047 mozilla::PRemoteSpellcheckEngineParent*
AllocPRemoteSpellcheckEngineParent()4048 ContentParent::AllocPRemoteSpellcheckEngineParent() {
4049 mozilla::RemoteSpellcheckEngineParent* parent =
4050 new mozilla::RemoteSpellcheckEngineParent();
4051 return parent;
4052 }
4053
DeallocPRemoteSpellcheckEngineParent(PRemoteSpellcheckEngineParent * parent)4054 bool ContentParent::DeallocPRemoteSpellcheckEngineParent(
4055 PRemoteSpellcheckEngineParent* parent) {
4056 delete parent;
4057 return true;
4058 }
4059
4060 /* static */
ForceKillTimerCallback(nsITimer * aTimer,void * aClosure)4061 void ContentParent::ForceKillTimerCallback(nsITimer* aTimer, void* aClosure) {
4062 // We don't want to time out the content process during XPCShell tests. This
4063 // is the easiest way to ensure that.
4064 if (PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR")) {
4065 return;
4066 }
4067
4068 auto self = static_cast<ContentParent*>(aClosure);
4069 self->KillHard("ShutDownKill");
4070 }
4071
GeneratePairedMinidump(const char * aReason)4072 void ContentParent::GeneratePairedMinidump(const char* aReason) {
4073 // We're about to kill the child process associated with this content.
4074 // Something has gone wrong to get us here, so we generate a minidump
4075 // of the parent and child for submission to the crash server unless we're
4076 // already shutting down.
4077 nsCOMPtr<nsIAppStartup> appStartup = components::AppStartup::Service();
4078 if (mCrashReporter && !appStartup->GetShuttingDown() &&
4079 StaticPrefs::dom_ipc_tabs_createKillHardCrashReports_AtStartup()) {
4080 // GeneratePairedMinidump creates two minidumps for us - the main
4081 // one is for the content process we're about to kill, and the other
4082 // one is for the main browser process. That second one is the extra
4083 // minidump tagging along, so we have to tell the crash reporter that
4084 // it exists and is being appended.
4085 nsAutoCString additionalDumps("browser");
4086 mCrashReporter->AddAnnotation(
4087 CrashReporter::Annotation::additional_minidumps, additionalDumps);
4088 nsDependentCString reason(aReason);
4089 mCrashReporter->AddAnnotation(CrashReporter::Annotation::ipc_channel_error,
4090 reason);
4091
4092 // Generate the report and insert into the queue for submittal.
4093 if (mCrashReporter->GenerateMinidumpAndPair(this, nullptr, "browser"_ns)) {
4094 mCreatedPairedMinidumps = mCrashReporter->FinalizeCrashReport();
4095 }
4096 }
4097 }
4098
HandleOrphanedMinidump(nsString * aDumpId)4099 void ContentParent::HandleOrphanedMinidump(nsString* aDumpId) {
4100 if (CrashReporter::FinalizeOrphanedMinidump(
4101 OtherPid(), GeckoProcessType_Content, aDumpId)) {
4102 CrashReporterHost::RecordCrash(GeckoProcessType_Content,
4103 nsICrashService::CRASH_TYPE_CRASH, *aDumpId);
4104 } else {
4105 NS_WARNING(nsPrintfCString("content process pid = %d crashed without "
4106 "leaving a minidump behind",
4107 OtherPid())
4108 .get());
4109 }
4110 }
4111
4112 // WARNING: aReason appears in telemetry, so any new value passed in requires
4113 // data review.
KillHard(const char * aReason)4114 void ContentParent::KillHard(const char* aReason) {
4115 AUTO_PROFILER_LABEL("ContentParent::KillHard", OTHER);
4116
4117 // On Windows, calling KillHard multiple times causes problems - the
4118 // process handle becomes invalid on the first call, causing a second call
4119 // to crash our process - more details in bug 890840.
4120 if (mCalledKillHard) {
4121 return;
4122 }
4123 mCalledKillHard = true;
4124 mForceKillTimer = nullptr;
4125
4126 RemoveShutdownBlockers();
4127
4128 GeneratePairedMinidump(aReason);
4129
4130 nsDependentCString reason(aReason);
4131 Telemetry::Accumulate(Telemetry::SUBPROCESS_KILL_HARD, reason, 1);
4132
4133 ProcessHandle otherProcessHandle;
4134 if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle)) {
4135 NS_ERROR("Failed to open child process when attempting kill.");
4136 return;
4137 }
4138
4139 if (!KillProcess(otherProcessHandle, base::PROCESS_END_KILLED_BY_USER)) {
4140 NS_WARNING("failed to kill subprocess!");
4141 }
4142
4143 if (mSubprocess) {
4144 MOZ_LOG(
4145 ContentParent::GetLog(), LogLevel::Verbose,
4146 ("KillHard Subprocess(%s): ContentParent %p mSubprocess %p handle "
4147 "%" PRIuPTR,
4148 aReason, this, mSubprocess,
4149 mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
4150 mSubprocess->SetAlreadyDead();
4151 }
4152
4153 // EnsureProcessTerminated has responsibilty for closing otherProcessHandle.
4154 XRE_GetIOMessageLoop()->PostTask(
4155 NewRunnableFunction("EnsureProcessTerminatedRunnable",
4156 &ProcessWatcher::EnsureProcessTerminated,
4157 otherProcessHandle, /*force=*/true));
4158 }
4159
FriendlyName(nsAString & aName,bool aAnonymize)4160 void ContentParent::FriendlyName(nsAString& aName, bool aAnonymize) {
4161 aName.Truncate();
4162 if (mIsForBrowser) {
4163 aName.AssignLiteral("Browser");
4164 } else if (aAnonymize) {
4165 aName.AssignLiteral("<anonymized-name>");
4166 } else {
4167 aName.AssignLiteral("???");
4168 }
4169 }
4170
RecvInitCrashReporter(const NativeThreadId & aThreadId)4171 mozilla::ipc::IPCResult ContentParent::RecvInitCrashReporter(
4172 const NativeThreadId& aThreadId) {
4173 mCrashReporter =
4174 MakeUnique<CrashReporterHost>(GeckoProcessType_Content, aThreadId);
4175
4176 return IPC_OK();
4177 }
4178
AllocPHalParent()4179 hal_sandbox::PHalParent* ContentParent::AllocPHalParent() {
4180 return hal_sandbox::CreateHalParent();
4181 }
4182
DeallocPHalParent(hal_sandbox::PHalParent * aHal)4183 bool ContentParent::DeallocPHalParent(hal_sandbox::PHalParent* aHal) {
4184 delete aHal;
4185 return true;
4186 }
4187
4188 devtools::PHeapSnapshotTempFileHelperParent*
AllocPHeapSnapshotTempFileHelperParent()4189 ContentParent::AllocPHeapSnapshotTempFileHelperParent() {
4190 return devtools::HeapSnapshotTempFileHelperParent::Create();
4191 }
4192
DeallocPHeapSnapshotTempFileHelperParent(devtools::PHeapSnapshotTempFileHelperParent * aHeapSnapshotHelper)4193 bool ContentParent::DeallocPHeapSnapshotTempFileHelperParent(
4194 devtools::PHeapSnapshotTempFileHelperParent* aHeapSnapshotHelper) {
4195 delete aHeapSnapshotHelper;
4196 return true;
4197 }
4198
SendRequestMemoryReport(const uint32_t & aGeneration,const bool & aAnonymize,const bool & aMinimizeMemoryUsage,const Maybe<FileDescriptor> & aDMDFile)4199 bool ContentParent::SendRequestMemoryReport(
4200 const uint32_t& aGeneration, const bool& aAnonymize,
4201 const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile) {
4202 // This automatically cancels the previous request.
4203 mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
4204 // If we run the callback in response to a reply, then by definition |this|
4205 // is still alive, so the ref pointer is redundant, but it seems easier
4206 // to hold a strong reference than to worry about that.
4207 RefPtr<ContentParent> self(this);
4208 PContentParent::SendRequestMemoryReport(
4209 aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile,
4210 [&, self](const uint32_t& aGeneration2) {
4211 if (self->mMemoryReportRequest) {
4212 self->mMemoryReportRequest->Finish(aGeneration2);
4213 self->mMemoryReportRequest = nullptr;
4214 }
4215 },
4216 [&, self](mozilla::ipc::ResponseRejectReason) {
4217 self->mMemoryReportRequest = nullptr;
4218 });
4219 return IPC_OK();
4220 }
4221
RecvAddMemoryReport(const MemoryReport & aReport)4222 mozilla::ipc::IPCResult ContentParent::RecvAddMemoryReport(
4223 const MemoryReport& aReport) {
4224 if (mMemoryReportRequest) {
4225 mMemoryReportRequest->RecvReport(aReport);
4226 }
4227 return IPC_OK();
4228 }
4229
RecvAddPerformanceMetrics(const nsID & aID,nsTArray<PerformanceInfo> && aMetrics)4230 mozilla::ipc::IPCResult ContentParent::RecvAddPerformanceMetrics(
4231 const nsID& aID, nsTArray<PerformanceInfo>&& aMetrics) {
4232 nsresult rv = PerformanceMetricsCollector::DataReceived(aID, aMetrics);
4233 Unused << NS_WARN_IF(NS_FAILED(rv));
4234 return IPC_OK();
4235 }
4236
AllocPCycleCollectWithLogsParent(const bool & aDumpAllTraces,const FileDescriptor & aGCLog,const FileDescriptor & aCCLog)4237 PCycleCollectWithLogsParent* ContentParent::AllocPCycleCollectWithLogsParent(
4238 const bool& aDumpAllTraces, const FileDescriptor& aGCLog,
4239 const FileDescriptor& aCCLog) {
4240 MOZ_CRASH("Don't call this; use ContentParent::CycleCollectWithLogs");
4241 }
4242
DeallocPCycleCollectWithLogsParent(PCycleCollectWithLogsParent * aActor)4243 bool ContentParent::DeallocPCycleCollectWithLogsParent(
4244 PCycleCollectWithLogsParent* aActor) {
4245 delete aActor;
4246 return true;
4247 }
4248
CycleCollectWithLogs(bool aDumpAllTraces,nsICycleCollectorLogSink * aSink,nsIDumpGCAndCCLogsCallback * aCallback)4249 bool ContentParent::CycleCollectWithLogs(
4250 bool aDumpAllTraces, nsICycleCollectorLogSink* aSink,
4251 nsIDumpGCAndCCLogsCallback* aCallback) {
4252 return CycleCollectWithLogsParent::AllocAndSendConstructor(
4253 this, aDumpAllTraces, aSink, aCallback);
4254 }
4255
AllocPTestShellParent()4256 PTestShellParent* ContentParent::AllocPTestShellParent() {
4257 return new TestShellParent();
4258 }
4259
DeallocPTestShellParent(PTestShellParent * shell)4260 bool ContentParent::DeallocPTestShellParent(PTestShellParent* shell) {
4261 delete shell;
4262 return true;
4263 }
4264
AllocPScriptCacheParent(const FileDescOrError & cacheFile,const bool & wantCacheData)4265 PScriptCacheParent* ContentParent::AllocPScriptCacheParent(
4266 const FileDescOrError& cacheFile, const bool& wantCacheData) {
4267 return new loader::ScriptCacheParent(wantCacheData);
4268 }
4269
DeallocPScriptCacheParent(PScriptCacheParent * cache)4270 bool ContentParent::DeallocPScriptCacheParent(PScriptCacheParent* cache) {
4271 delete static_cast<loader::ScriptCacheParent*>(cache);
4272 return true;
4273 }
4274
AllocPNeckoParent()4275 already_AddRefed<PNeckoParent> ContentParent::AllocPNeckoParent() {
4276 RefPtr<NeckoParent> actor = new NeckoParent();
4277 return actor.forget();
4278 }
4279
AllocPPrintingParent()4280 PPrintingParent* ContentParent::AllocPPrintingParent() {
4281 #ifdef NS_PRINTING
4282 if (mPrintingParent) {
4283 // Only one PrintingParent should be created per process.
4284 return nullptr;
4285 }
4286
4287 // Create the printing singleton for this process.
4288 mPrintingParent = new PrintingParent();
4289
4290 // Take another reference for IPDL code.
4291 mPrintingParent.get()->AddRef();
4292
4293 return mPrintingParent.get();
4294 #else
4295 MOZ_ASSERT_UNREACHABLE("Should never be created if no printing.");
4296 return nullptr;
4297 #endif
4298 }
4299
DeallocPPrintingParent(PPrintingParent * printing)4300 bool ContentParent::DeallocPPrintingParent(PPrintingParent* printing) {
4301 #ifdef NS_PRINTING
4302 MOZ_RELEASE_ASSERT(
4303 mPrintingParent == printing,
4304 "Only one PrintingParent should have been created per process.");
4305
4306 // Release reference taken for IPDL code.
4307 static_cast<PrintingParent*>(printing)->Release();
4308
4309 mPrintingParent = nullptr;
4310 #else
4311 MOZ_ASSERT_UNREACHABLE("Should never have been created if no printing.");
4312 #endif
4313 return true;
4314 }
4315
4316 #ifdef NS_PRINTING
GetPrintingParent()4317 already_AddRefed<embedding::PrintingParent> ContentParent::GetPrintingParent() {
4318 MOZ_ASSERT(mPrintingParent);
4319
4320 RefPtr<embedding::PrintingParent> printingParent = mPrintingParent;
4321 return printingParent.forget();
4322 }
4323 #endif
4324
RecvInitStreamFilter(const uint64_t & aChannelId,const nsString & aAddonId,InitStreamFilterResolver && aResolver)4325 mozilla::ipc::IPCResult ContentParent::RecvInitStreamFilter(
4326 const uint64_t& aChannelId, const nsString& aAddonId,
4327 InitStreamFilterResolver&& aResolver) {
4328 extensions::StreamFilterParent::Create(this, aChannelId, aAddonId)
4329 ->Then(
4330 GetCurrentSerialEventTarget(), __func__,
4331 [aResolver](mozilla::ipc::Endpoint<PStreamFilterChild>&& aEndpoint) {
4332 aResolver(std::move(aEndpoint));
4333 },
4334 [aResolver](bool aDummy) {
4335 aResolver(mozilla::ipc::Endpoint<PStreamFilterChild>());
4336 });
4337
4338 return IPC_OK();
4339 }
4340
AllocPChildToParentStreamParent()4341 PChildToParentStreamParent* ContentParent::AllocPChildToParentStreamParent() {
4342 return mozilla::ipc::AllocPChildToParentStreamParent();
4343 }
4344
DeallocPChildToParentStreamParent(PChildToParentStreamParent * aActor)4345 bool ContentParent::DeallocPChildToParentStreamParent(
4346 PChildToParentStreamParent* aActor) {
4347 delete aActor;
4348 return true;
4349 }
4350
AllocPParentToChildStreamParent()4351 PParentToChildStreamParent* ContentParent::AllocPParentToChildStreamParent() {
4352 MOZ_CRASH(
4353 "PParentToChildStreamParent actors should be manually constructed!");
4354 }
4355
DeallocPParentToChildStreamParent(PParentToChildStreamParent * aActor)4356 bool ContentParent::DeallocPParentToChildStreamParent(
4357 PParentToChildStreamParent* aActor) {
4358 delete aActor;
4359 return true;
4360 }
4361
RecvAddSecurityState(const MaybeDiscarded<WindowContext> & aContext,uint32_t aStateFlags)4362 mozilla::ipc::IPCResult ContentParent::RecvAddSecurityState(
4363 const MaybeDiscarded<WindowContext>& aContext, uint32_t aStateFlags) {
4364 if (aContext.IsNullOrDiscarded()) {
4365 return IPC_OK();
4366 }
4367
4368 aContext.get()->AddSecurityState(aStateFlags);
4369 return IPC_OK();
4370 }
4371
4372 already_AddRefed<PExternalHelperAppParent>
AllocPExternalHelperAppParent(nsIURI * uri,const Maybe<mozilla::net::LoadInfoArgs> & aLoadInfoArgs,const nsCString & aMimeContentType,const nsCString & aContentDisposition,const uint32_t & aContentDispositionHint,const nsString & aContentDispositionFilename,const bool & aForceSave,const int64_t & aContentLength,const bool & aWasFileChannel,nsIURI * aReferrer,const MaybeDiscarded<BrowsingContext> & aContext,const bool & aShouldCloseWindow)4373 ContentParent::AllocPExternalHelperAppParent(
4374 nsIURI* uri, const Maybe<mozilla::net::LoadInfoArgs>& aLoadInfoArgs,
4375 const nsCString& aMimeContentType, const nsCString& aContentDisposition,
4376 const uint32_t& aContentDispositionHint,
4377 const nsString& aContentDispositionFilename, const bool& aForceSave,
4378 const int64_t& aContentLength, const bool& aWasFileChannel,
4379 nsIURI* aReferrer, const MaybeDiscarded<BrowsingContext>& aContext,
4380 const bool& aShouldCloseWindow) {
4381 RefPtr<ExternalHelperAppParent> parent = new ExternalHelperAppParent(
4382 uri, aContentLength, aWasFileChannel, aContentDisposition,
4383 aContentDispositionHint, aContentDispositionFilename);
4384 return parent.forget();
4385 }
4386
RecvPExternalHelperAppConstructor(PExternalHelperAppParent * actor,nsIURI * uri,const Maybe<LoadInfoArgs> & loadInfoArgs,const nsCString & aMimeContentType,const nsCString & aContentDisposition,const uint32_t & aContentDispositionHint,const nsString & aContentDispositionFilename,const bool & aForceSave,const int64_t & aContentLength,const bool & aWasFileChannel,nsIURI * aReferrer,const MaybeDiscarded<BrowsingContext> & aContext,const bool & aShouldCloseWindow)4387 mozilla::ipc::IPCResult ContentParent::RecvPExternalHelperAppConstructor(
4388 PExternalHelperAppParent* actor, nsIURI* uri,
4389 const Maybe<LoadInfoArgs>& loadInfoArgs, const nsCString& aMimeContentType,
4390 const nsCString& aContentDisposition,
4391 const uint32_t& aContentDispositionHint,
4392 const nsString& aContentDispositionFilename, const bool& aForceSave,
4393 const int64_t& aContentLength, const bool& aWasFileChannel,
4394 nsIURI* aReferrer, const MaybeDiscarded<BrowsingContext>& aContext,
4395 const bool& aShouldCloseWindow) {
4396 BrowsingContext* context = aContext.IsDiscarded() ? nullptr : aContext.get();
4397 static_cast<ExternalHelperAppParent*>(actor)->Init(
4398 loadInfoArgs, aMimeContentType, aForceSave, aReferrer, context,
4399 aShouldCloseWindow);
4400 return IPC_OK();
4401 }
4402
4403 already_AddRefed<PHandlerServiceParent>
AllocPHandlerServiceParent()4404 ContentParent::AllocPHandlerServiceParent() {
4405 RefPtr<HandlerServiceParent> actor = new HandlerServiceParent();
4406 return actor.forget();
4407 }
4408
AllocPMediaParent()4409 media::PMediaParent* ContentParent::AllocPMediaParent() {
4410 return media::AllocPMediaParent();
4411 }
4412
DeallocPMediaParent(media::PMediaParent * aActor)4413 bool ContentParent::DeallocPMediaParent(media::PMediaParent* aActor) {
4414 return media::DeallocPMediaParent(aActor);
4415 }
4416
AllocPBenchmarkStorageParent()4417 PBenchmarkStorageParent* ContentParent::AllocPBenchmarkStorageParent() {
4418 return new BenchmarkStorageParent;
4419 }
4420
DeallocPBenchmarkStorageParent(PBenchmarkStorageParent * aActor)4421 bool ContentParent::DeallocPBenchmarkStorageParent(
4422 PBenchmarkStorageParent* aActor) {
4423 delete aActor;
4424 return true;
4425 }
4426
4427 #ifdef MOZ_WEBSPEECH
AllocPSpeechSynthesisParent()4428 PSpeechSynthesisParent* ContentParent::AllocPSpeechSynthesisParent() {
4429 return new mozilla::dom::SpeechSynthesisParent();
4430 }
4431
DeallocPSpeechSynthesisParent(PSpeechSynthesisParent * aActor)4432 bool ContentParent::DeallocPSpeechSynthesisParent(
4433 PSpeechSynthesisParent* aActor) {
4434 delete aActor;
4435 return true;
4436 }
4437
RecvPSpeechSynthesisConstructor(PSpeechSynthesisParent * aActor)4438 mozilla::ipc::IPCResult ContentParent::RecvPSpeechSynthesisConstructor(
4439 PSpeechSynthesisParent* aActor) {
4440 if (!static_cast<SpeechSynthesisParent*>(aActor)->SendInit()) {
4441 return IPC_FAIL_NO_REASON(this);
4442 }
4443 return IPC_OK();
4444 }
4445 #endif
4446
RecvStartVisitedQueries(const nsTArray<RefPtr<nsIURI>> & aUris)4447 mozilla::ipc::IPCResult ContentParent::RecvStartVisitedQueries(
4448 const nsTArray<RefPtr<nsIURI>>& aUris) {
4449 nsCOMPtr<IHistory> history = components::History::Service();
4450 if (!history) {
4451 return IPC_OK();
4452 }
4453 for (const auto& uri : aUris) {
4454 if (NS_WARN_IF(!uri)) {
4455 continue;
4456 }
4457 history->ScheduleVisitedQuery(uri, this);
4458 }
4459 return IPC_OK();
4460 }
4461
RecvSetURITitle(nsIURI * uri,const nsString & title)4462 mozilla::ipc::IPCResult ContentParent::RecvSetURITitle(nsIURI* uri,
4463 const nsString& title) {
4464 if (!uri) {
4465 return IPC_FAIL_NO_REASON(this);
4466 }
4467 nsCOMPtr<IHistory> history = components::History::Service();
4468 if (history) {
4469 history->SetURITitle(uri, title);
4470 }
4471 return IPC_OK();
4472 }
4473
RecvIsSecureURI(nsIURI * aURI,const uint32_t & aFlags,const OriginAttributes & aOriginAttributes,bool * aIsSecureURI)4474 mozilla::ipc::IPCResult ContentParent::RecvIsSecureURI(
4475 nsIURI* aURI, const uint32_t& aFlags,
4476 const OriginAttributes& aOriginAttributes, bool* aIsSecureURI) {
4477 nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID));
4478 if (!sss) {
4479 return IPC_FAIL_NO_REASON(this);
4480 }
4481 if (!aURI) {
4482 return IPC_FAIL_NO_REASON(this);
4483 }
4484 nsresult rv = sss->IsSecureURI(aURI, aFlags, aOriginAttributes, nullptr,
4485 nullptr, aIsSecureURI);
4486 if (NS_FAILED(rv)) {
4487 return IPC_FAIL_NO_REASON(this);
4488 }
4489 return IPC_OK();
4490 }
4491
RecvAccumulateMixedContentHSTS(nsIURI * aURI,const bool & aActive,const OriginAttributes & aOriginAttributes)4492 mozilla::ipc::IPCResult ContentParent::RecvAccumulateMixedContentHSTS(
4493 nsIURI* aURI, const bool& aActive,
4494 const OriginAttributes& aOriginAttributes) {
4495 if (!aURI) {
4496 return IPC_FAIL_NO_REASON(this);
4497 }
4498 nsMixedContentBlocker::AccumulateMixedContentHSTS(aURI, aActive,
4499 aOriginAttributes);
4500 return IPC_OK();
4501 }
4502
RecvLoadURIExternal(nsIURI * uri,nsIPrincipal * aTriggeringPrincipal,nsIPrincipal * aRedirectPrincipal,const MaybeDiscarded<BrowsingContext> & aContext,bool aWasExternallyTriggered)4503 mozilla::ipc::IPCResult ContentParent::RecvLoadURIExternal(
4504 nsIURI* uri, nsIPrincipal* aTriggeringPrincipal,
4505 nsIPrincipal* aRedirectPrincipal,
4506 const MaybeDiscarded<BrowsingContext>& aContext,
4507 bool aWasExternallyTriggered) {
4508 if (aContext.IsDiscarded()) {
4509 return IPC_OK();
4510 }
4511
4512 nsCOMPtr<nsIExternalProtocolService> extProtService(
4513 do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
4514 if (!extProtService) {
4515 return IPC_OK();
4516 }
4517
4518 if (!uri) {
4519 return IPC_FAIL_NO_REASON(this);
4520 }
4521
4522 BrowsingContext* bc = aContext.get();
4523 extProtService->LoadURI(uri, aTriggeringPrincipal, aRedirectPrincipal, bc,
4524 aWasExternallyTriggered);
4525 return IPC_OK();
4526 }
4527
RecvExtProtocolChannelConnectParent(const uint64_t & registrarId)4528 mozilla::ipc::IPCResult ContentParent::RecvExtProtocolChannelConnectParent(
4529 const uint64_t& registrarId) {
4530 nsresult rv;
4531
4532 // First get the real channel created before redirect on the parent.
4533 nsCOMPtr<nsIChannel> channel;
4534 rv = NS_LinkRedirectChannels(registrarId, nullptr, getter_AddRefs(channel));
4535 NS_ENSURE_SUCCESS(rv, IPC_OK());
4536
4537 nsCOMPtr<nsIParentChannel> parent = do_QueryInterface(channel, &rv);
4538 NS_ENSURE_SUCCESS(rv, IPC_OK());
4539
4540 // The channel itself is its own (faked) parent, link it.
4541 rv = NS_LinkRedirectChannels(registrarId, parent, getter_AddRefs(channel));
4542 NS_ENSURE_SUCCESS(rv, IPC_OK());
4543
4544 // Signal the parent channel that it's a redirect-to parent. This will
4545 // make AsyncOpen on it do nothing (what we want).
4546 // Yes, this is a bit of a hack, but I don't think it's necessary to invent
4547 // a new interface just to set this flag on the channel.
4548 parent->SetParentListener(nullptr);
4549
4550 return IPC_OK();
4551 }
4552
RecvShowAlert(nsIAlertNotification * aAlert)4553 mozilla::ipc::IPCResult ContentParent::RecvShowAlert(
4554 nsIAlertNotification* aAlert) {
4555 if (!aAlert) {
4556 return IPC_FAIL_NO_REASON(this);
4557 }
4558 nsCOMPtr<nsIAlertsService> sysAlerts(components::Alerts::Service());
4559 if (sysAlerts) {
4560 sysAlerts->ShowAlert(aAlert, this);
4561 }
4562 return IPC_OK();
4563 }
4564
RecvCloseAlert(const nsString & aName)4565 mozilla::ipc::IPCResult ContentParent::RecvCloseAlert(const nsString& aName) {
4566 nsCOMPtr<nsIAlertsService> sysAlerts(components::Alerts::Service());
4567 if (sysAlerts) {
4568 sysAlerts->CloseAlert(aName);
4569 }
4570
4571 return IPC_OK();
4572 }
4573
RecvDisableNotifications(const IPC::Principal & aPrincipal)4574 mozilla::ipc::IPCResult ContentParent::RecvDisableNotifications(
4575 const IPC::Principal& aPrincipal) {
4576 if (!ValidatePrincipal(aPrincipal)) {
4577 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
4578 }
4579 Unused << Notification::RemovePermission(aPrincipal);
4580 return IPC_OK();
4581 }
4582
RecvOpenNotificationSettings(const IPC::Principal & aPrincipal)4583 mozilla::ipc::IPCResult ContentParent::RecvOpenNotificationSettings(
4584 const IPC::Principal& aPrincipal) {
4585 if (!ValidatePrincipal(aPrincipal)) {
4586 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
4587 }
4588 Unused << Notification::OpenSettings(aPrincipal);
4589 return IPC_OK();
4590 }
4591
RecvNotificationEvent(const nsString & aType,const NotificationEventData & aData)4592 mozilla::ipc::IPCResult ContentParent::RecvNotificationEvent(
4593 const nsString& aType, const NotificationEventData& aData) {
4594 nsCOMPtr<nsIServiceWorkerManager> swm =
4595 mozilla::components::ServiceWorkerManager::Service();
4596 if (NS_WARN_IF(!swm)) {
4597 // Probably shouldn't happen, but no need to crash the child process.
4598 return IPC_OK();
4599 }
4600
4601 if (aType.EqualsLiteral("click")) {
4602 nsresult rv = swm->SendNotificationClickEvent(
4603 aData.originSuffix(), aData.scope(), aData.ID(), aData.title(),
4604 aData.dir(), aData.lang(), aData.body(), aData.tag(), aData.icon(),
4605 aData.data(), aData.behavior());
4606 Unused << NS_WARN_IF(NS_FAILED(rv));
4607 } else {
4608 MOZ_ASSERT(aType.EqualsLiteral("close"));
4609 nsresult rv = swm->SendNotificationCloseEvent(
4610 aData.originSuffix(), aData.scope(), aData.ID(), aData.title(),
4611 aData.dir(), aData.lang(), aData.body(), aData.tag(), aData.icon(),
4612 aData.data(), aData.behavior());
4613 Unused << NS_WARN_IF(NS_FAILED(rv));
4614 }
4615
4616 return IPC_OK();
4617 }
4618
RecvSyncMessage(const nsString & aMsg,const ClonedMessageData & aData,nsTArray<StructuredCloneData> * aRetvals)4619 mozilla::ipc::IPCResult ContentParent::RecvSyncMessage(
4620 const nsString& aMsg, const ClonedMessageData& aData,
4621 nsTArray<StructuredCloneData>* aRetvals) {
4622 AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("ContentParent::RecvSyncMessage",
4623 OTHER, aMsg);
4624 MMPrinter::Print("ContentParent::RecvSyncMessage", aMsg, aData);
4625
4626 RefPtr<nsFrameMessageManager> ppm = mMessageManager;
4627 if (ppm) {
4628 ipc::StructuredCloneData data;
4629 ipc::UnpackClonedMessageDataForParent(aData, data);
4630
4631 ppm->ReceiveMessage(ppm, nullptr, aMsg, true, &data, aRetvals,
4632 IgnoreErrors());
4633 }
4634 return IPC_OK();
4635 }
4636
RecvAsyncMessage(const nsString & aMsg,const ClonedMessageData & aData)4637 mozilla::ipc::IPCResult ContentParent::RecvAsyncMessage(
4638 const nsString& aMsg, const ClonedMessageData& aData) {
4639 AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("ContentParent::RecvAsyncMessage",
4640 OTHER, aMsg);
4641 MMPrinter::Print("ContentParent::RecvAsyncMessage", aMsg, aData);
4642
4643 RefPtr<nsFrameMessageManager> ppm = mMessageManager;
4644 if (ppm) {
4645 ipc::StructuredCloneData data;
4646 ipc::UnpackClonedMessageDataForParent(aData, data);
4647
4648 ppm->ReceiveMessage(ppm, nullptr, aMsg, false, &data, nullptr,
4649 IgnoreErrors());
4650 }
4651 return IPC_OK();
4652 }
4653
4654 MOZ_CAN_RUN_SCRIPT
AddGeolocationListener(nsIDOMGeoPositionCallback * watcher,nsIDOMGeoPositionErrorCallback * errorCallBack,bool highAccuracy)4655 static int32_t AddGeolocationListener(
4656 nsIDOMGeoPositionCallback* watcher,
4657 nsIDOMGeoPositionErrorCallback* errorCallBack, bool highAccuracy) {
4658 RefPtr<Geolocation> geo = Geolocation::NonWindowSingleton();
4659
4660 UniquePtr<PositionOptions> options = MakeUnique<PositionOptions>();
4661 options->mTimeout = 0;
4662 options->mMaximumAge = 0;
4663 options->mEnableHighAccuracy = highAccuracy;
4664 return geo->WatchPosition(watcher, errorCallBack, std::move(options));
4665 }
4666
RecvAddGeolocationListener(const bool & aHighAccuracy)4667 mozilla::ipc::IPCResult ContentParent::RecvAddGeolocationListener(
4668 const bool& aHighAccuracy) {
4669 // To ensure no geolocation updates are skipped, we always force the
4670 // creation of a new listener.
4671 RecvRemoveGeolocationListener();
4672 mGeolocationWatchID = AddGeolocationListener(this, this, aHighAccuracy);
4673 return IPC_OK();
4674 }
4675
RecvRemoveGeolocationListener()4676 mozilla::ipc::IPCResult ContentParent::RecvRemoveGeolocationListener() {
4677 if (mGeolocationWatchID != -1) {
4678 RefPtr<Geolocation> geo = Geolocation::NonWindowSingleton();
4679 geo->ClearWatch(mGeolocationWatchID);
4680 mGeolocationWatchID = -1;
4681 }
4682 return IPC_OK();
4683 }
4684
RecvSetGeolocationHigherAccuracy(const bool & aEnable)4685 mozilla::ipc::IPCResult ContentParent::RecvSetGeolocationHigherAccuracy(
4686 const bool& aEnable) {
4687 // This should never be called without a listener already present,
4688 // so this check allows us to forgo securing privileges.
4689 if (mGeolocationWatchID != -1) {
4690 RecvRemoveGeolocationListener();
4691 mGeolocationWatchID = AddGeolocationListener(this, this, aEnable);
4692 }
4693 return IPC_OK();
4694 }
4695
4696 NS_IMETHODIMP
HandleEvent(nsIDOMGeoPosition * postion)4697 ContentParent::HandleEvent(nsIDOMGeoPosition* postion) {
4698 Unused << SendGeolocationUpdate(postion);
4699 return NS_OK;
4700 }
4701
4702 NS_IMETHODIMP
HandleEvent(GeolocationPositionError * positionError)4703 ContentParent::HandleEvent(GeolocationPositionError* positionError) {
4704 Unused << SendGeolocationError(positionError->Code());
4705 return NS_OK;
4706 }
4707
RecvConsoleMessage(const nsString & aMessage)4708 mozilla::ipc::IPCResult ContentParent::RecvConsoleMessage(
4709 const nsString& aMessage) {
4710 nsresult rv;
4711 nsCOMPtr<nsIConsoleService> consoleService =
4712 do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
4713 if (NS_SUCCEEDED(rv)) {
4714 RefPtr<nsConsoleMessage> msg(new nsConsoleMessage(aMessage.get()));
4715 msg->SetIsForwardedFromContentProcess(true);
4716 consoleService->LogMessageWithMode(msg, nsIConsoleService::SuppressLog);
4717 }
4718 return IPC_OK();
4719 }
4720
RecvReportFrameTimingData(uint64_t aInnerWindowId,const nsString & entryName,const nsString & initiatorType,UniquePtr<PerformanceTimingData> && aData)4721 mozilla::ipc::IPCResult ContentParent::RecvReportFrameTimingData(
4722 uint64_t aInnerWindowId, const nsString& entryName,
4723 const nsString& initiatorType, UniquePtr<PerformanceTimingData>&& aData) {
4724 if (!aData) {
4725 return IPC_FAIL(this, "aData should not be null");
4726 }
4727
4728 RefPtr<WindowGlobalParent> parent =
4729 WindowGlobalParent::GetByInnerWindowId(aInnerWindowId);
4730 if (!parent || !parent->GetContentParent()) {
4731 return IPC_OK();
4732 }
4733
4734 MOZ_ASSERT(parent->GetContentParent() != this,
4735 "No need to bounce around if in the same process");
4736
4737 Unused << parent->GetContentParent()->SendReportFrameTimingData(
4738 aInnerWindowId, entryName, initiatorType, std::move(aData));
4739 return IPC_OK();
4740 }
4741
RecvScriptError(const nsString & aMessage,const nsString & aSourceName,const nsString & aSourceLine,const uint32_t & aLineNumber,const uint32_t & aColNumber,const uint32_t & aFlags,const nsCString & aCategory,const bool & aFromPrivateWindow,const uint64_t & aInnerWindowId,const bool & aFromChromeContext)4742 mozilla::ipc::IPCResult ContentParent::RecvScriptError(
4743 const nsString& aMessage, const nsString& aSourceName,
4744 const nsString& aSourceLine, const uint32_t& aLineNumber,
4745 const uint32_t& aColNumber, const uint32_t& aFlags,
4746 const nsCString& aCategory, const bool& aFromPrivateWindow,
4747 const uint64_t& aInnerWindowId, const bool& aFromChromeContext) {
4748 return RecvScriptErrorInternal(aMessage, aSourceName, aSourceLine,
4749 aLineNumber, aColNumber, aFlags, aCategory,
4750 aFromPrivateWindow, aFromChromeContext);
4751 }
4752
RecvScriptErrorWithStack(const nsString & aMessage,const nsString & aSourceName,const nsString & aSourceLine,const uint32_t & aLineNumber,const uint32_t & aColNumber,const uint32_t & aFlags,const nsCString & aCategory,const bool & aFromPrivateWindow,const bool & aFromChromeContext,const ClonedMessageData & aFrame)4753 mozilla::ipc::IPCResult ContentParent::RecvScriptErrorWithStack(
4754 const nsString& aMessage, const nsString& aSourceName,
4755 const nsString& aSourceLine, const uint32_t& aLineNumber,
4756 const uint32_t& aColNumber, const uint32_t& aFlags,
4757 const nsCString& aCategory, const bool& aFromPrivateWindow,
4758 const bool& aFromChromeContext, const ClonedMessageData& aFrame) {
4759 return RecvScriptErrorInternal(
4760 aMessage, aSourceName, aSourceLine, aLineNumber, aColNumber, aFlags,
4761 aCategory, aFromPrivateWindow, aFromChromeContext, &aFrame);
4762 }
4763
RecvScriptErrorInternal(const nsString & aMessage,const nsString & aSourceName,const nsString & aSourceLine,const uint32_t & aLineNumber,const uint32_t & aColNumber,const uint32_t & aFlags,const nsCString & aCategory,const bool & aFromPrivateWindow,const bool & aFromChromeContext,const ClonedMessageData * aStack)4764 mozilla::ipc::IPCResult ContentParent::RecvScriptErrorInternal(
4765 const nsString& aMessage, const nsString& aSourceName,
4766 const nsString& aSourceLine, const uint32_t& aLineNumber,
4767 const uint32_t& aColNumber, const uint32_t& aFlags,
4768 const nsCString& aCategory, const bool& aFromPrivateWindow,
4769 const bool& aFromChromeContext, const ClonedMessageData* aStack) {
4770 nsresult rv;
4771 nsCOMPtr<nsIConsoleService> consoleService =
4772 do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
4773 if (NS_FAILED(rv)) {
4774 return IPC_OK();
4775 }
4776
4777 nsCOMPtr<nsIScriptError> msg;
4778
4779 if (aStack) {
4780 StructuredCloneData data;
4781 UnpackClonedMessageDataForParent(*aStack, data);
4782
4783 AutoJSAPI jsapi;
4784 if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) {
4785 MOZ_CRASH();
4786 }
4787 JSContext* cx = jsapi.cx();
4788
4789 JS::RootedValue stack(cx);
4790 ErrorResult rv;
4791 data.Read(cx, &stack, rv);
4792 if (rv.Failed() || !stack.isObject()) {
4793 rv.SuppressException();
4794 return IPC_OK();
4795 }
4796
4797 JS::RootedObject stackObj(cx, &stack.toObject());
4798 MOZ_ASSERT(JS::IsUnwrappedSavedFrame(stackObj));
4799
4800 JS::RootedObject stackGlobal(cx, JS::GetNonCCWObjectGlobal(stackObj));
4801 msg = new nsScriptErrorWithStack(JS::NothingHandleValue, stackObj,
4802 stackGlobal);
4803 } else {
4804 msg = new nsScriptError();
4805 }
4806
4807 rv = msg->Init(aMessage, aSourceName, aSourceLine, aLineNumber, aColNumber,
4808 aFlags, aCategory.get(), aFromPrivateWindow,
4809 aFromChromeContext);
4810 if (NS_FAILED(rv)) return IPC_OK();
4811
4812 msg->SetIsForwardedFromContentProcess(true);
4813
4814 consoleService->LogMessageWithMode(msg, nsIConsoleService::SuppressLog);
4815 return IPC_OK();
4816 }
4817
DoLoadMessageManagerScript(const nsAString & aURL,bool aRunInGlobalScope)4818 bool ContentParent::DoLoadMessageManagerScript(const nsAString& aURL,
4819 bool aRunInGlobalScope) {
4820 MOZ_ASSERT(!aRunInGlobalScope);
4821 return SendLoadProcessScript(nsString(aURL));
4822 }
4823
DoSendAsyncMessage(const nsAString & aMessage,StructuredCloneData & aHelper)4824 nsresult ContentParent::DoSendAsyncMessage(const nsAString& aMessage,
4825 StructuredCloneData& aHelper) {
4826 ClonedMessageData data;
4827 if (!BuildClonedMessageDataForParent(this, aHelper, data)) {
4828 return NS_ERROR_DOM_DATA_CLONE_ERR;
4829 }
4830 if (!SendAsyncMessage(nsString(aMessage), data)) {
4831 return NS_ERROR_UNEXPECTED;
4832 }
4833 return NS_OK;
4834 }
4835
RecvCopyFavicon(nsIURI * aOldURI,nsIURI * aNewURI,const bool & aInPrivateBrowsing)4836 mozilla::ipc::IPCResult ContentParent::RecvCopyFavicon(
4837 nsIURI* aOldURI, nsIURI* aNewURI, const bool& aInPrivateBrowsing) {
4838 if (!aOldURI) {
4839 return IPC_FAIL(this, "aOldURI should not be null");
4840 }
4841 if (!aNewURI) {
4842 return IPC_FAIL(this, "aNewURI should not be null");
4843 }
4844
4845 nsDocShell::CopyFavicon(aOldURI, aNewURI, aInPrivateBrowsing);
4846 return IPC_OK();
4847 }
4848
ShouldContinueFromReplyTimeout()4849 bool ContentParent::ShouldContinueFromReplyTimeout() {
4850 RefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
4851 return !monitor || !monitor->ShouldTimeOutCPOWs();
4852 }
4853
RecvRecordingDeviceEvents(const nsString & aRecordingStatus,const nsString & aPageURL,const bool & aIsAudio,const bool & aIsVideo)4854 mozilla::ipc::IPCResult ContentParent::RecvRecordingDeviceEvents(
4855 const nsString& aRecordingStatus, const nsString& aPageURL,
4856 const bool& aIsAudio, const bool& aIsVideo) {
4857 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
4858 if (obs) {
4859 // recording-device-ipc-events needs to gather more information from content
4860 // process
4861 RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
4862 props->SetPropertyAsUint64(u"childID"_ns, ChildID());
4863 props->SetPropertyAsBool(u"isAudio"_ns, aIsAudio);
4864 props->SetPropertyAsBool(u"isVideo"_ns, aIsVideo);
4865 props->SetPropertyAsAString(u"requestURL"_ns, aPageURL);
4866
4867 obs->NotifyObservers((nsIPropertyBag2*)props, "recording-device-ipc-events",
4868 aRecordingStatus.get());
4869 } else {
4870 NS_WARNING(
4871 "Could not get the Observer service for "
4872 "ContentParent::RecvRecordingDeviceEvents.");
4873 }
4874 return IPC_OK();
4875 }
4876
RecvAddIdleObserver(const uint64_t & aObserver,const uint32_t & aIdleTimeInS)4877 mozilla::ipc::IPCResult ContentParent::RecvAddIdleObserver(
4878 const uint64_t& aObserver, const uint32_t& aIdleTimeInS) {
4879 nsresult rv;
4880 nsCOMPtr<nsIUserIdleService> idleService =
4881 do_GetService("@mozilla.org/widget/useridleservice;1", &rv);
4882 NS_ENSURE_SUCCESS(rv, IPC_FAIL_NO_REASON(this));
4883
4884 RefPtr<ParentIdleListener> listener =
4885 new ParentIdleListener(this, aObserver, aIdleTimeInS);
4886 rv = idleService->AddIdleObserver(listener, aIdleTimeInS);
4887 NS_ENSURE_SUCCESS(rv, IPC_FAIL_NO_REASON(this));
4888 mIdleListeners.AppendElement(listener);
4889 return IPC_OK();
4890 }
4891
RecvRemoveIdleObserver(const uint64_t & aObserver,const uint32_t & aIdleTimeInS)4892 mozilla::ipc::IPCResult ContentParent::RecvRemoveIdleObserver(
4893 const uint64_t& aObserver, const uint32_t& aIdleTimeInS) {
4894 RefPtr<ParentIdleListener> listener;
4895 for (int32_t i = mIdleListeners.Length() - 1; i >= 0; --i) {
4896 listener = static_cast<ParentIdleListener*>(mIdleListeners[i].get());
4897 if (listener->mObserver == aObserver && listener->mTime == aIdleTimeInS) {
4898 nsresult rv;
4899 nsCOMPtr<nsIUserIdleService> idleService =
4900 do_GetService("@mozilla.org/widget/useridleservice;1", &rv);
4901 NS_ENSURE_SUCCESS(rv, IPC_FAIL_NO_REASON(this));
4902 idleService->RemoveIdleObserver(listener, aIdleTimeInS);
4903 mIdleListeners.RemoveElementAt(i);
4904 break;
4905 }
4906 }
4907 return IPC_OK();
4908 }
4909
RecvBackUpXResources(const FileDescriptor & aXSocketFd)4910 mozilla::ipc::IPCResult ContentParent::RecvBackUpXResources(
4911 const FileDescriptor& aXSocketFd) {
4912 #ifndef MOZ_X11
4913 MOZ_CRASH("This message only makes sense on X11 platforms");
4914 #else
4915 MOZ_ASSERT(0 > mChildXSocketFdDup.get(), "Already backed up X resources??");
4916 if (aXSocketFd.IsValid()) {
4917 auto rawFD = aXSocketFd.ClonePlatformHandle();
4918 mChildXSocketFdDup.reset(rawFD.release());
4919 }
4920 #endif
4921 return IPC_OK();
4922 }
4923
4924 class AnonymousTemporaryFileRequestor final : public Runnable {
4925 public:
AnonymousTemporaryFileRequestor(ContentParent * aCP,const uint64_t & aID)4926 AnonymousTemporaryFileRequestor(ContentParent* aCP, const uint64_t& aID)
4927 : Runnable("dom::AnonymousTemporaryFileRequestor"),
4928 mCP(aCP),
4929 mID(aID),
4930 mRv(NS_OK),
4931 mPRFD(nullptr) {}
4932
Run()4933 NS_IMETHOD Run() override {
4934 if (NS_IsMainThread()) {
4935 FileDescOrError result;
4936 if (NS_WARN_IF(NS_FAILED(mRv))) {
4937 // Returning false will kill the child process; instead
4938 // propagate the error and let the child handle it.
4939 result = mRv;
4940 } else {
4941 result = FileDescriptor(FileDescriptor::PlatformHandleType(
4942 PR_FileDesc2NativeHandle(mPRFD)));
4943 // The FileDescriptor object owns a duplicate of the file handle; we
4944 // must close the original (and clean up the NSPR descriptor).
4945 PR_Close(mPRFD);
4946 }
4947 Unused << mCP->SendProvideAnonymousTemporaryFile(mID, result);
4948 // It's important to release this reference while wr're on the main
4949 // thread!
4950 mCP = nullptr;
4951 } else {
4952 mRv = NS_OpenAnonymousTemporaryFile(&mPRFD);
4953 NS_DispatchToMainThread(this);
4954 }
4955 return NS_OK;
4956 }
4957
4958 private:
4959 RefPtr<ContentParent> mCP;
4960 uint64_t mID;
4961 nsresult mRv;
4962 PRFileDesc* mPRFD;
4963 };
4964
RecvRequestAnonymousTemporaryFile(const uint64_t & aID)4965 mozilla::ipc::IPCResult ContentParent::RecvRequestAnonymousTemporaryFile(
4966 const uint64_t& aID) {
4967 // Make sure to send a callback to the child if we bail out early.
4968 nsresult rv = NS_OK;
4969 RefPtr<ContentParent> self(this);
4970 auto autoNotifyChildOnError = MakeScopeExit([&, self]() {
4971 if (NS_FAILED(rv)) {
4972 FileDescOrError result(rv);
4973 Unused << self->SendProvideAnonymousTemporaryFile(aID, result);
4974 }
4975 });
4976
4977 // We use a helper runnable to open the anonymous temporary file on the IO
4978 // thread. The same runnable will call us back on the main thread when the
4979 // file has been opened.
4980 nsCOMPtr<nsIEventTarget> target =
4981 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
4982 if (!target) {
4983 return IPC_OK();
4984 }
4985
4986 rv = target->Dispatch(new AnonymousTemporaryFileRequestor(this, aID),
4987 NS_DISPATCH_NORMAL);
4988 if (NS_WARN_IF(NS_FAILED(rv))) {
4989 return IPC_OK();
4990 }
4991
4992 rv = NS_OK;
4993 return IPC_OK();
4994 }
4995
RecvCreateAudioIPCConnection(CreateAudioIPCConnectionResolver && aResolver)4996 mozilla::ipc::IPCResult ContentParent::RecvCreateAudioIPCConnection(
4997 CreateAudioIPCConnectionResolver&& aResolver) {
4998 FileDescriptor fd = CubebUtils::CreateAudioIPCConnection();
4999 FileDescOrError result;
5000 if (fd.IsValid()) {
5001 result = fd;
5002 } else {
5003 result = NS_ERROR_FAILURE;
5004 }
5005 aResolver(std::move(result));
5006 return IPC_OK();
5007 }
5008
5009 already_AddRefed<extensions::PExtensionsParent>
AllocPExtensionsParent()5010 ContentParent::AllocPExtensionsParent() {
5011 return MakeAndAddRef<extensions::ExtensionsParent>();
5012 }
5013
AllocPFileDescriptorSetParent(const FileDescriptor & aFD)5014 PFileDescriptorSetParent* ContentParent::AllocPFileDescriptorSetParent(
5015 const FileDescriptor& aFD) {
5016 return new FileDescriptorSetParent(aFD);
5017 }
5018
DeallocPFileDescriptorSetParent(PFileDescriptorSetParent * aActor)5019 bool ContentParent::DeallocPFileDescriptorSetParent(
5020 PFileDescriptorSetParent* aActor) {
5021 delete static_cast<FileDescriptorSetParent*>(aActor);
5022 return true;
5023 }
5024
NotifyUpdatedDictionaries()5025 void ContentParent::NotifyUpdatedDictionaries() {
5026 RefPtr<mozSpellChecker> spellChecker(mozSpellChecker::Create());
5027 MOZ_ASSERT(spellChecker, "No spell checker?");
5028
5029 nsTArray<nsCString> dictionaries;
5030 spellChecker->GetDictionaryList(&dictionaries);
5031
5032 for (auto* cp : AllProcesses(eLive)) {
5033 Unused << cp->SendUpdateDictionaryList(dictionaries);
5034 }
5035 }
5036
NotifyUpdatedFonts(bool aFullRebuild)5037 void ContentParent::NotifyUpdatedFonts(bool aFullRebuild) {
5038 if (gfxPlatformFontList::PlatformFontList()->SharedFontList()) {
5039 for (auto* cp : AllProcesses(eLive)) {
5040 Unused << cp->SendRebuildFontList(aFullRebuild);
5041 }
5042 return;
5043 }
5044
5045 SystemFontList fontList;
5046 gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList);
5047
5048 for (auto* cp : AllProcesses(eLive)) {
5049 Unused << cp->SendUpdateFontList(fontList);
5050 }
5051 }
5052
5053 #ifdef MOZ_WEBRTC
AllocPWebrtcGlobalParent()5054 PWebrtcGlobalParent* ContentParent::AllocPWebrtcGlobalParent() {
5055 return WebrtcGlobalParent::Alloc();
5056 }
5057
DeallocPWebrtcGlobalParent(PWebrtcGlobalParent * aActor)5058 bool ContentParent::DeallocPWebrtcGlobalParent(PWebrtcGlobalParent* aActor) {
5059 WebrtcGlobalParent::Dealloc(static_cast<WebrtcGlobalParent*>(aActor));
5060 return true;
5061 }
5062 #endif
5063
RecvSetOfflinePermission(const Principal & aPrincipal)5064 mozilla::ipc::IPCResult ContentParent::RecvSetOfflinePermission(
5065 const Principal& aPrincipal) {
5066 return IPC_OK();
5067 }
5068
MaybeInvokeDragSession(BrowserParent * aParent)5069 void ContentParent::MaybeInvokeDragSession(BrowserParent* aParent) {
5070 // dnd uses IPCBlob to transfer data to the content process and the IPC
5071 // message is sent as normal priority. When sending input events with input
5072 // priority, the message may be preempted by the later dnd events. To make
5073 // sure the input events and the blob message are processed in time order
5074 // on the content process, we temporarily send the input events with normal
5075 // priority when there is an active dnd session.
5076 SetInputPriorityEventEnabled(false);
5077
5078 nsCOMPtr<nsIDragService> dragService =
5079 do_GetService("@mozilla.org/widget/dragservice;1");
5080 if (dragService && dragService->MaybeAddChildProcess(this)) {
5081 // We need to send transferable data to child process.
5082 nsCOMPtr<nsIDragSession> session;
5083 dragService->GetCurrentSession(getter_AddRefs(session));
5084 if (session) {
5085 nsTArray<IPCDataTransfer> dataTransfers;
5086 RefPtr<DataTransfer> transfer = session->GetDataTransfer();
5087 if (!transfer) {
5088 // Pass eDrop to get DataTransfer with external
5089 // drag formats cached.
5090 transfer = new DataTransfer(nullptr, eDrop, true, -1);
5091 session->SetDataTransfer(transfer);
5092 }
5093 // Note, even though this fills the DataTransfer object with
5094 // external data, the data is usually transfered over IPC lazily when
5095 // needed.
5096 transfer->FillAllExternalData();
5097 nsCOMPtr<nsILoadContext> lc =
5098 aParent ? aParent->GetLoadContext() : nullptr;
5099 nsCOMPtr<nsIArray> transferables = transfer->GetTransferables(lc);
5100 nsContentUtils::TransferablesToIPCTransferables(
5101 transferables, dataTransfers, false, nullptr, this);
5102 uint32_t action;
5103 session->GetDragAction(&action);
5104
5105 RefPtr<WindowContext> sourceWC;
5106 session->GetSourceWindowContext(getter_AddRefs(sourceWC));
5107 mozilla::Unused << SendInvokeDragSession(sourceWC, dataTransfers, action);
5108 }
5109 }
5110 }
5111
RecvUpdateDropEffect(const uint32_t & aDragAction,const uint32_t & aDropEffect)5112 mozilla::ipc::IPCResult ContentParent::RecvUpdateDropEffect(
5113 const uint32_t& aDragAction, const uint32_t& aDropEffect) {
5114 nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
5115 if (dragSession) {
5116 dragSession->SetDragAction(aDragAction);
5117 RefPtr<DataTransfer> dt = dragSession->GetDataTransfer();
5118 if (dt) {
5119 dt->SetDropEffectInt(aDropEffect);
5120 }
5121 dragSession->UpdateDragEffect();
5122 }
5123 return IPC_OK();
5124 }
5125
5126 PContentPermissionRequestParent*
AllocPContentPermissionRequestParent(const nsTArray<PermissionRequest> & aRequests,const IPC::Principal & aPrincipal,const IPC::Principal & aTopLevelPrincipal,const bool & aIsHandlingUserInput,const bool & aMaybeUnsafePermissionDelegate,const TabId & aTabId)5127 ContentParent::AllocPContentPermissionRequestParent(
5128 const nsTArray<PermissionRequest>& aRequests,
5129 const IPC::Principal& aPrincipal, const IPC::Principal& aTopLevelPrincipal,
5130 const bool& aIsHandlingUserInput,
5131 const bool& aMaybeUnsafePermissionDelegate, const TabId& aTabId) {
5132 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
5133 RefPtr<BrowserParent> tp =
5134 cpm->GetTopLevelBrowserParentByProcessAndTabId(this->ChildID(), aTabId);
5135 if (!tp) {
5136 return nullptr;
5137 }
5138
5139 nsIPrincipal* topPrincipal = aTopLevelPrincipal;
5140 if (!topPrincipal) {
5141 nsCOMPtr<nsIPrincipal> principal = tp->GetContentPrincipal();
5142 topPrincipal = principal;
5143 }
5144 return nsContentPermissionUtils::CreateContentPermissionRequestParent(
5145 aRequests, tp->GetOwnerElement(), aPrincipal, topPrincipal,
5146 aIsHandlingUserInput, aMaybeUnsafePermissionDelegate, aTabId);
5147 }
5148
DeallocPContentPermissionRequestParent(PContentPermissionRequestParent * actor)5149 bool ContentParent::DeallocPContentPermissionRequestParent(
5150 PContentPermissionRequestParent* actor) {
5151 nsContentPermissionUtils::NotifyRemoveContentPermissionRequestParent(actor);
5152 delete actor;
5153 return true;
5154 }
5155
5156 PWebBrowserPersistDocumentParent*
AllocPWebBrowserPersistDocumentParent(PBrowserParent * aBrowser,const MaybeDiscarded<BrowsingContext> & aContext)5157 ContentParent::AllocPWebBrowserPersistDocumentParent(
5158 PBrowserParent* aBrowser, const MaybeDiscarded<BrowsingContext>& aContext) {
5159 return new WebBrowserPersistDocumentParent();
5160 }
5161
DeallocPWebBrowserPersistDocumentParent(PWebBrowserPersistDocumentParent * aActor)5162 bool ContentParent::DeallocPWebBrowserPersistDocumentParent(
5163 PWebBrowserPersistDocumentParent* aActor) {
5164 delete aActor;
5165 return true;
5166 }
5167
CommonCreateWindow(PBrowserParent * aThisTab,BrowsingContext & aParent,bool aSetOpener,const uint32_t & aChromeFlags,const bool & aCalledFromJS,const bool & aForPrinting,const bool & aForWindowDotPrint,nsIURI * aURIToLoad,const nsCString & aFeatures,BrowserParent * aNextRemoteBrowser,const nsString & aName,nsresult & aResult,nsCOMPtr<nsIRemoteTab> & aNewRemoteTab,bool * aWindowIsNew,int32_t & aOpenLocation,nsIPrincipal * aTriggeringPrincipal,nsIReferrerInfo * aReferrerInfo,bool aLoadURI,nsIContentSecurityPolicy * aCsp,const OriginAttributes & aOriginAttributes)5168 mozilla::ipc::IPCResult ContentParent::CommonCreateWindow(
5169 PBrowserParent* aThisTab, BrowsingContext& aParent, bool aSetOpener,
5170 const uint32_t& aChromeFlags, const bool& aCalledFromJS,
5171 const bool& aForPrinting, const bool& aForWindowDotPrint,
5172 nsIURI* aURIToLoad, const nsCString& aFeatures,
5173 BrowserParent* aNextRemoteBrowser, const nsString& aName, nsresult& aResult,
5174 nsCOMPtr<nsIRemoteTab>& aNewRemoteTab, bool* aWindowIsNew,
5175 int32_t& aOpenLocation, nsIPrincipal* aTriggeringPrincipal,
5176 nsIReferrerInfo* aReferrerInfo, bool aLoadURI,
5177 nsIContentSecurityPolicy* aCsp, const OriginAttributes& aOriginAttributes) {
5178 // The content process should never be in charge of computing whether or
5179 // not a window should be private - the parent will do that.
5180 const uint32_t badFlags = nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW |
5181 nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW |
5182 nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME;
5183 if (!!(aChromeFlags & badFlags)) {
5184 return IPC_FAIL(this, "Forbidden aChromeFlags passed");
5185 }
5186
5187 RefPtr<nsOpenWindowInfo> openInfo = new nsOpenWindowInfo();
5188 openInfo->mForceNoOpener = !aSetOpener;
5189 openInfo->mParent = &aParent;
5190 openInfo->mIsRemote = true;
5191 openInfo->mIsForPrinting = aForPrinting;
5192 openInfo->mIsForWindowDotPrint = aForWindowDotPrint;
5193 openInfo->mNextRemoteBrowser = aNextRemoteBrowser;
5194 openInfo->mOriginAttributes = aOriginAttributes;
5195
5196 MOZ_ASSERT_IF(aForWindowDotPrint, aForPrinting);
5197
5198 RefPtr<BrowserParent> topParent = BrowserParent::GetFrom(aThisTab);
5199 while (topParent && topParent->GetBrowserBridgeParent()) {
5200 topParent = topParent->GetBrowserBridgeParent()->Manager();
5201 }
5202 RefPtr<BrowserHost> thisBrowserHost =
5203 topParent ? topParent->GetBrowserHost() : nullptr;
5204 MOZ_ASSERT_IF(topParent, thisBrowserHost);
5205 RefPtr<BrowsingContext> topBC =
5206 topParent ? topParent->GetBrowsingContext() : nullptr;
5207 MOZ_ASSERT_IF(topParent, topBC);
5208
5209 // The content process should have set its remote and fission flags correctly.
5210 if (topBC) {
5211 if ((!!(aChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) !=
5212 topBC->UseRemoteTabs()) ||
5213 (!!(aChromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW) !=
5214 topBC->UseRemoteSubframes())) {
5215 return IPC_FAIL(this, "Unexpected aChromeFlags passed");
5216 }
5217
5218 if (!aOriginAttributes.EqualsIgnoringFPD(topBC->OriginAttributesRef())) {
5219 return IPC_FAIL(this, "Passed-in OriginAttributes does not match opener");
5220 }
5221 }
5222
5223 nsCOMPtr<nsIContent> frame;
5224 if (topParent) {
5225 frame = topParent->GetOwnerElement();
5226 }
5227
5228 nsCOMPtr<nsPIDOMWindowOuter> outerWin;
5229 if (frame) {
5230 outerWin = frame->OwnerDoc()->GetWindow();
5231
5232 // If our chrome window is in the process of closing, don't try to open a
5233 // new tab in it.
5234 if (outerWin && outerWin->Closed()) {
5235 outerWin = nullptr;
5236 }
5237 }
5238
5239 nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
5240 if (topParent) {
5241 browserDOMWin = topParent->GetBrowserDOMWindow();
5242 }
5243
5244 // If we haven't found a chrome window to open in, just use the most recently
5245 // opened one.
5246 if (!outerWin) {
5247 outerWin = nsContentUtils::GetMostRecentNonPBWindow();
5248 if (NS_WARN_IF(!outerWin)) {
5249 aResult = NS_ERROR_FAILURE;
5250 return IPC_OK();
5251 }
5252
5253 nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(outerWin);
5254 if (rootChromeWin) {
5255 rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
5256 }
5257 }
5258
5259 aOpenLocation = nsWindowWatcher::GetWindowOpenLocation(
5260 outerWin, aChromeFlags, aCalledFromJS, aForPrinting);
5261
5262 MOZ_ASSERT(aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
5263 aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWWINDOW ||
5264 aOpenLocation == nsIBrowserDOMWindow::OPEN_PRINT_BROWSER);
5265
5266 if (NS_WARN_IF(!browserDOMWin)) {
5267 // Opening in the same window or headless requires an nsIBrowserDOMWindow.
5268 aOpenLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
5269 }
5270
5271 if (aOpenLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
5272 aOpenLocation == nsIBrowserDOMWindow::OPEN_PRINT_BROWSER) {
5273 RefPtr<Element> openerElement = do_QueryObject(frame);
5274
5275 nsCOMPtr<nsIOpenURIInFrameParams> params =
5276 new nsOpenURIInFrameParams(openInfo, openerElement);
5277 params->SetReferrerInfo(aReferrerInfo);
5278 MOZ_ASSERT(aTriggeringPrincipal, "need a valid triggeringPrincipal");
5279 params->SetTriggeringPrincipal(aTriggeringPrincipal);
5280 params->SetCsp(aCsp);
5281
5282 RefPtr<Element> el;
5283
5284 if (aLoadURI) {
5285 aResult = browserDOMWin->OpenURIInFrame(aURIToLoad, params, aOpenLocation,
5286 nsIBrowserDOMWindow::OPEN_NEW,
5287 aName, getter_AddRefs(el));
5288 } else {
5289 aResult = browserDOMWin->CreateContentWindowInFrame(
5290 aURIToLoad, params, aOpenLocation, nsIBrowserDOMWindow::OPEN_NEW,
5291 aName, getter_AddRefs(el));
5292 }
5293 RefPtr<nsFrameLoaderOwner> frameLoaderOwner = do_QueryObject(el);
5294 if (NS_SUCCEEDED(aResult) && frameLoaderOwner) {
5295 RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
5296 if (frameLoader) {
5297 aNewRemoteTab = frameLoader->GetRemoteTab();
5298 // At this point, it's possible the inserted frameloader hasn't gone
5299 // through layout yet. To ensure that the dimensions that we send down
5300 // when telling the frameloader to display will be correct (instead of
5301 // falling back to a 10x10 default), we force layout if necessary to get
5302 // the most up-to-date dimensions. See bug 1358712 for details.
5303 frameLoader->ForceLayoutIfNecessary();
5304 }
5305 } else if (NS_SUCCEEDED(aResult) && !frameLoaderOwner) {
5306 // Fall through to the normal window opening code path when there is no
5307 // window which we can open a new tab in.
5308 aOpenLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
5309 } else {
5310 *aWindowIsNew = false;
5311 }
5312
5313 // If we didn't retarget our window open into a new window, we should return
5314 // now.
5315 if (aOpenLocation != nsIBrowserDOMWindow::OPEN_NEWWINDOW) {
5316 return IPC_OK();
5317 }
5318 }
5319
5320 nsCOMPtr<nsPIWindowWatcher> pwwatch =
5321 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &aResult);
5322 if (NS_WARN_IF(NS_FAILED(aResult))) {
5323 return IPC_OK();
5324 }
5325
5326 aResult = pwwatch->OpenWindowWithRemoteTab(
5327 thisBrowserHost, aFeatures, aCalledFromJS, aParent.FullZoom(), openInfo,
5328 getter_AddRefs(aNewRemoteTab));
5329 if (NS_WARN_IF(NS_FAILED(aResult))) {
5330 return IPC_OK();
5331 }
5332
5333 MOZ_ASSERT(aNewRemoteTab);
5334 RefPtr<BrowserHost> newBrowserHost = BrowserHost::GetFrom(aNewRemoteTab);
5335 RefPtr<BrowserParent> newBrowserParent = newBrowserHost->GetActor();
5336
5337 // At this point, it's possible the inserted frameloader hasn't gone through
5338 // layout yet. To ensure that the dimensions that we send down when telling
5339 // the frameloader to display will be correct (instead of falling back to a
5340 // 10x10 default), we force layout if necessary to get the most up-to-date
5341 // dimensions. See bug 1358712 for details.
5342 //
5343 // This involves doing a bit of gymnastics in order to get at the FrameLoader,
5344 // so we scope this to avoid polluting the main function scope.
5345 {
5346 nsCOMPtr<Element> frameElement = newBrowserHost->GetOwnerElement();
5347 MOZ_ASSERT(frameElement);
5348 RefPtr<nsFrameLoaderOwner> frameLoaderOwner = do_QueryObject(frameElement);
5349 MOZ_ASSERT(frameLoaderOwner);
5350 RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
5351 MOZ_ASSERT(frameLoader);
5352 frameLoader->ForceLayoutIfNecessary();
5353 }
5354
5355 // If we were passed a name for the window which would override the default,
5356 // we should send it down to the new tab.
5357 if (nsContentUtils::IsOverridingWindowName(aName)) {
5358 MOZ_ALWAYS_SUCCEEDS(newBrowserHost->GetBrowsingContext()->SetName(aName));
5359 }
5360
5361 MOZ_ASSERT(newBrowserHost->GetBrowsingContext()->OriginAttributesRef() ==
5362 aOriginAttributes);
5363
5364 if (aURIToLoad && aLoadURI) {
5365 nsCOMPtr<mozIDOMWindowProxy> openerWindow;
5366 if (aSetOpener && topParent) {
5367 openerWindow = topParent->GetParentWindowOuter();
5368 }
5369 nsCOMPtr<nsIBrowserDOMWindow> newBrowserDOMWin =
5370 newBrowserParent->GetBrowserDOMWindow();
5371 if (NS_WARN_IF(!newBrowserDOMWin)) {
5372 aResult = NS_ERROR_ABORT;
5373 return IPC_OK();
5374 }
5375 RefPtr<BrowsingContext> bc;
5376 aResult = newBrowserDOMWin->OpenURI(
5377 aURIToLoad, openInfo, nsIBrowserDOMWindow::OPEN_CURRENTWINDOW,
5378 nsIBrowserDOMWindow::OPEN_NEW, aTriggeringPrincipal, aCsp,
5379 getter_AddRefs(bc));
5380 }
5381
5382 return IPC_OK();
5383 }
5384
RecvCreateWindow(PBrowserParent * aThisTab,const MaybeDiscarded<BrowsingContext> & aParent,PBrowserParent * aNewTab,const uint32_t & aChromeFlags,const bool & aCalledFromJS,const bool & aForPrinting,const bool & aForPrintPreview,nsIURI * aURIToLoad,const nsCString & aFeatures,const IPC::Principal & aTriggeringPrincipal,nsIContentSecurityPolicy * aCsp,nsIReferrerInfo * aReferrerInfo,const OriginAttributes & aOriginAttributes,CreateWindowResolver && aResolve)5385 mozilla::ipc::IPCResult ContentParent::RecvCreateWindow(
5386 PBrowserParent* aThisTab, const MaybeDiscarded<BrowsingContext>& aParent,
5387 PBrowserParent* aNewTab, const uint32_t& aChromeFlags,
5388 const bool& aCalledFromJS, const bool& aForPrinting,
5389 const bool& aForPrintPreview, nsIURI* aURIToLoad,
5390 const nsCString& aFeatures, const IPC::Principal& aTriggeringPrincipal,
5391 nsIContentSecurityPolicy* aCsp, nsIReferrerInfo* aReferrerInfo,
5392 const OriginAttributes& aOriginAttributes,
5393 CreateWindowResolver&& aResolve) {
5394 if (!ValidatePrincipal(aTriggeringPrincipal)) {
5395 LogAndAssertFailedPrincipalValidationInfo(aTriggeringPrincipal, __func__);
5396 }
5397
5398 nsresult rv = NS_OK;
5399 CreatedWindowInfo cwi;
5400
5401 // We always expect to open a new window here. If we don't, it's an error.
5402 cwi.windowOpened() = true;
5403 cwi.maxTouchPoints() = 0;
5404 cwi.hasSiblings() = false;
5405
5406 // Make sure to resolve the resolver when this function exits, even if we
5407 // failed to generate a valid response.
5408 auto resolveOnExit = MakeScopeExit([&] {
5409 // Copy over the nsresult, and then resolve.
5410 cwi.rv() = rv;
5411 aResolve(cwi);
5412 });
5413
5414 RefPtr<BrowserParent> thisTab = BrowserParent::GetFrom(aThisTab);
5415 RefPtr<BrowserParent> newTab = BrowserParent::GetFrom(aNewTab);
5416 MOZ_ASSERT(newTab);
5417
5418 auto destroyNewTabOnError = MakeScopeExit([&] {
5419 // We always expect to open a new window here. If we don't, it's an error.
5420 if (!cwi.windowOpened() || NS_FAILED(rv)) {
5421 if (newTab) {
5422 newTab->Destroy();
5423 }
5424 }
5425 });
5426
5427 // Don't continue to try to create a new window if we've been fully discarded.
5428 RefPtr<BrowsingContext> parent = aParent.GetMaybeDiscarded();
5429 if (NS_WARN_IF(!parent)) {
5430 rv = NS_ERROR_FAILURE;
5431 return IPC_OK();
5432 }
5433
5434 // Validate that our new BrowsingContext looks as we would expect it.
5435 RefPtr<BrowsingContext> newBC = newTab->GetBrowsingContext();
5436 if (!newBC) {
5437 return IPC_FAIL(this, "Missing BrowsingContext for new tab");
5438 }
5439
5440 uint64_t newBCOpenerId = newBC->GetOpenerId();
5441 if (newBCOpenerId != 0 && parent->Id() != newBCOpenerId) {
5442 return IPC_FAIL(this, "Invalid opener BrowsingContext for new tab");
5443 }
5444 if (newBC->GetParent() != nullptr) {
5445 return IPC_FAIL(this,
5446 "Unexpected non-toplevel BrowsingContext for new tab");
5447 }
5448 if (!!(aChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW) !=
5449 newBC->UseRemoteTabs() ||
5450 !!(aChromeFlags & nsIWebBrowserChrome::CHROME_FISSION_WINDOW) !=
5451 newBC->UseRemoteSubframes()) {
5452 return IPC_FAIL(this, "Unexpected aChromeFlags passed");
5453 }
5454 if (!aOriginAttributes.EqualsIgnoringFPD(newBC->OriginAttributesRef())) {
5455 return IPC_FAIL(this, "Opened tab has mismatched OriginAttributes");
5456 }
5457
5458 if (thisTab && BrowserParent::GetFrom(thisTab)->GetBrowsingContext()) {
5459 BrowsingContext* thisTabBC = thisTab->GetBrowsingContext();
5460 if (thisTabBC->UseRemoteTabs() != newBC->UseRemoteTabs() ||
5461 thisTabBC->UseRemoteSubframes() != newBC->UseRemoteSubframes() ||
5462 thisTabBC->UsePrivateBrowsing() != newBC->UsePrivateBrowsing()) {
5463 return IPC_FAIL(this, "New BrowsingContext has mismatched LoadContext");
5464 }
5465 }
5466
5467 BrowserParent::AutoUseNewTab aunt(newTab);
5468
5469 nsCOMPtr<nsIRemoteTab> newRemoteTab;
5470 int32_t openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
5471 mozilla::ipc::IPCResult ipcResult = CommonCreateWindow(
5472 aThisTab, *parent, newBCOpenerId != 0, aChromeFlags, aCalledFromJS,
5473 aForPrinting, aForPrintPreview, aURIToLoad, aFeatures, newTab,
5474 VoidString(), rv, newRemoteTab, &cwi.windowOpened(), openLocation,
5475 aTriggeringPrincipal, aReferrerInfo, /* aLoadUri = */ false, aCsp,
5476 aOriginAttributes);
5477 if (!ipcResult) {
5478 return ipcResult;
5479 }
5480
5481 if (NS_WARN_IF(NS_FAILED(rv)) || !newRemoteTab) {
5482 return IPC_OK();
5483 }
5484
5485 MOZ_ASSERT(BrowserHost::GetFrom(newRemoteTab.get()) ==
5486 newTab->GetBrowserHost());
5487
5488 newTab->SwapFrameScriptsFrom(cwi.frameScripts());
5489 newTab->MaybeShowFrame();
5490
5491 nsCOMPtr<nsIWidget> widget = newTab->GetWidget();
5492 if (widget) {
5493 cwi.dimensions() = newTab->GetDimensionInfo();
5494 }
5495
5496 cwi.maxTouchPoints() = newTab->GetMaxTouchPoints();
5497 cwi.hasSiblings() = (openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB);
5498
5499 return IPC_OK();
5500 }
5501
RecvCreateWindowInDifferentProcess(PBrowserParent * aThisTab,const MaybeDiscarded<BrowsingContext> & aParent,const uint32_t & aChromeFlags,const bool & aCalledFromJS,nsIURI * aURIToLoad,const nsCString & aFeatures,const nsString & aName,nsIPrincipal * aTriggeringPrincipal,nsIContentSecurityPolicy * aCsp,nsIReferrerInfo * aReferrerInfo,const OriginAttributes & aOriginAttributes)5502 mozilla::ipc::IPCResult ContentParent::RecvCreateWindowInDifferentProcess(
5503 PBrowserParent* aThisTab, const MaybeDiscarded<BrowsingContext>& aParent,
5504 const uint32_t& aChromeFlags, const bool& aCalledFromJS, nsIURI* aURIToLoad,
5505 const nsCString& aFeatures, const nsString& aName,
5506 nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp,
5507 nsIReferrerInfo* aReferrerInfo, const OriginAttributes& aOriginAttributes) {
5508 MOZ_DIAGNOSTIC_ASSERT(!nsContentUtils::IsSpecialName(aName));
5509
5510 // Don't continue to try to create a new window if we've been fully discarded.
5511 RefPtr<BrowsingContext> parent = aParent.GetMaybeDiscarded();
5512 if (NS_WARN_IF(!parent)) {
5513 return IPC_OK();
5514 }
5515
5516 nsCOMPtr<nsIRemoteTab> newRemoteTab;
5517 bool windowIsNew;
5518 int32_t openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
5519
5520 // If we have enough data, check the schemes of the loader and loadee
5521 // to make sure they make sense.
5522 if (aURIToLoad && aURIToLoad->SchemeIs("file") &&
5523 GetRemoteType() != FILE_REMOTE_TYPE &&
5524 Preferences::GetBool("browser.tabs.remote.enforceRemoteTypeRestrictions",
5525 false)) {
5526 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
5527 # ifdef DEBUG
5528 nsAutoCString uriToLoadStr;
5529 nsAutoCString triggeringUriStr;
5530 aURIToLoad->GetAsciiSpec(uriToLoadStr);
5531 aTriggeringPrincipal->GetAsciiSpec(triggeringUriStr);
5532
5533 NS_WARNING(nsPrintfCString(
5534 "RecvCreateWindowInDifferentProcess blocked loading file "
5535 "scheme from non-file remotetype: %s tried to load %s",
5536 triggeringUriStr.get(), uriToLoadStr.get())
5537 .get());
5538 # endif
5539 MOZ_CRASH(
5540 "RecvCreateWindowInDifferentProcess blocked loading improper scheme");
5541 #endif
5542 return IPC_OK();
5543 }
5544
5545 nsresult rv;
5546 mozilla::ipc::IPCResult ipcResult = CommonCreateWindow(
5547 aThisTab, *parent, /* aSetOpener = */ false, aChromeFlags, aCalledFromJS,
5548 /* aForPrinting = */ false,
5549 /* aForPrintPreview = */ false, aURIToLoad, aFeatures,
5550 /* aNextRemoteBrowser = */ nullptr, aName, rv, newRemoteTab, &windowIsNew,
5551 openLocation, aTriggeringPrincipal, aReferrerInfo,
5552 /* aLoadUri = */ true, aCsp, aOriginAttributes);
5553 if (!ipcResult) {
5554 return ipcResult;
5555 }
5556
5557 if (NS_FAILED(rv)) {
5558 NS_WARNING("Call to CommonCreateWindow failed.");
5559 }
5560
5561 return IPC_OK();
5562 }
5563
RecvShutdownProfile(const nsCString & aProfile)5564 mozilla::ipc::IPCResult ContentParent::RecvShutdownProfile(
5565 const nsCString& aProfile) {
5566 profiler_received_exit_profile(aProfile);
5567 return IPC_OK();
5568 }
5569
RecvGetGraphicsDeviceInitData(ContentDeviceData * aOut)5570 mozilla::ipc::IPCResult ContentParent::RecvGetGraphicsDeviceInitData(
5571 ContentDeviceData* aOut) {
5572 gfxPlatform::GetPlatform()->BuildContentDeviceData(aOut);
5573 return IPC_OK();
5574 }
5575
RecvGetOutputColorProfileData(nsTArray<uint8_t> * aOutputColorProfileData)5576 mozilla::ipc::IPCResult ContentParent::RecvGetOutputColorProfileData(
5577 nsTArray<uint8_t>* aOutputColorProfileData) {
5578 (*aOutputColorProfileData) =
5579 gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfileData();
5580 return IPC_OK();
5581 }
5582
RecvGetFontListShmBlock(const uint32_t & aGeneration,const uint32_t & aIndex,base::SharedMemoryHandle * aOut)5583 mozilla::ipc::IPCResult ContentParent::RecvGetFontListShmBlock(
5584 const uint32_t& aGeneration, const uint32_t& aIndex,
5585 base::SharedMemoryHandle* aOut) {
5586 auto* fontList = gfxPlatformFontList::PlatformFontList();
5587 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
5588 fontList->ShareFontListShmBlockToProcess(aGeneration, aIndex, Pid(), aOut);
5589 return IPC_OK();
5590 }
5591
RecvInitializeFamily(const uint32_t & aGeneration,const uint32_t & aFamilyIndex,const bool & aLoadCmaps)5592 mozilla::ipc::IPCResult ContentParent::RecvInitializeFamily(
5593 const uint32_t& aGeneration, const uint32_t& aFamilyIndex,
5594 const bool& aLoadCmaps) {
5595 auto* fontList = gfxPlatformFontList::PlatformFontList();
5596 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
5597 fontList->InitializeFamily(aGeneration, aFamilyIndex, aLoadCmaps);
5598 return IPC_OK();
5599 }
5600
RecvSetCharacterMap(const uint32_t & aGeneration,const mozilla::fontlist::Pointer & aFacePtr,const gfxSparseBitSet & aMap)5601 mozilla::ipc::IPCResult ContentParent::RecvSetCharacterMap(
5602 const uint32_t& aGeneration, const mozilla::fontlist::Pointer& aFacePtr,
5603 const gfxSparseBitSet& aMap) {
5604 auto* fontList = gfxPlatformFontList::PlatformFontList();
5605 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
5606 fontList->SetCharacterMap(aGeneration, aFacePtr, aMap);
5607 return IPC_OK();
5608 }
5609
RecvInitOtherFamilyNames(const uint32_t & aGeneration,const bool & aDefer,bool * aLoaded)5610 mozilla::ipc::IPCResult ContentParent::RecvInitOtherFamilyNames(
5611 const uint32_t& aGeneration, const bool& aDefer, bool* aLoaded) {
5612 auto* fontList = gfxPlatformFontList::PlatformFontList();
5613 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
5614 *aLoaded = fontList->InitOtherFamilyNames(aGeneration, aDefer);
5615 return IPC_OK();
5616 }
5617
RecvSetupFamilyCharMap(const uint32_t & aGeneration,const mozilla::fontlist::Pointer & aFamilyPtr)5618 mozilla::ipc::IPCResult ContentParent::RecvSetupFamilyCharMap(
5619 const uint32_t& aGeneration, const mozilla::fontlist::Pointer& aFamilyPtr) {
5620 auto* fontList = gfxPlatformFontList::PlatformFontList();
5621 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
5622 fontList->SetupFamilyCharMap(aGeneration, aFamilyPtr);
5623 return IPC_OK();
5624 }
5625
RecvStartCmapLoading(const uint32_t & aGeneration,const uint32_t & aStartIndex)5626 mozilla::ipc::IPCResult ContentParent::RecvStartCmapLoading(
5627 const uint32_t& aGeneration, const uint32_t& aStartIndex) {
5628 auto* fontList = gfxPlatformFontList::PlatformFontList();
5629 MOZ_RELEASE_ASSERT(fontList, "gfxPlatformFontList not initialized?");
5630 fontList->StartCmapLoading(aGeneration, aStartIndex);
5631 return IPC_OK();
5632 }
5633
RecvGetHyphDict(nsIURI * aURI,base::SharedMemoryHandle * aOutHandle,uint32_t * aOutSize)5634 mozilla::ipc::IPCResult ContentParent::RecvGetHyphDict(
5635 nsIURI* aURI, base::SharedMemoryHandle* aOutHandle, uint32_t* aOutSize) {
5636 if (!aURI) {
5637 return IPC_FAIL_NO_REASON(this);
5638 }
5639 nsHyphenationManager::Instance()->ShareHyphDictToProcess(
5640 aURI, Pid(), aOutHandle, aOutSize);
5641 return IPC_OK();
5642 }
5643
RecvGraphicsError(const nsCString & aError)5644 mozilla::ipc::IPCResult ContentParent::RecvGraphicsError(
5645 const nsCString& aError) {
5646 gfx::LogForwarder* lf = gfx::Factory::GetLogForwarder();
5647 if (lf) {
5648 std::stringstream message;
5649 message << "CP+" << aError.get();
5650 lf->UpdateStringsVector(message.str());
5651 }
5652 return IPC_OK();
5653 }
5654
RecvBeginDriverCrashGuard(const uint32_t & aGuardType,bool * aOutCrashed)5655 mozilla::ipc::IPCResult ContentParent::RecvBeginDriverCrashGuard(
5656 const uint32_t& aGuardType, bool* aOutCrashed) {
5657 // Only one driver crash guard should be active at a time, per-process.
5658 MOZ_ASSERT(!mDriverCrashGuard);
5659
5660 UniquePtr<gfx::DriverCrashGuard> guard;
5661 switch (gfx::CrashGuardType(aGuardType)) {
5662 case gfx::CrashGuardType::D3D11Layers:
5663 guard = MakeUnique<gfx::D3D11LayersCrashGuard>(this);
5664 break;
5665 case gfx::CrashGuardType::GLContext:
5666 guard = MakeUnique<gfx::GLContextCrashGuard>(this);
5667 break;
5668 case gfx::CrashGuardType::WMFVPXVideo:
5669 guard = MakeUnique<gfx::WMFVPXVideoCrashGuard>(this);
5670 break;
5671 default:
5672 MOZ_ASSERT_UNREACHABLE("unknown crash guard type");
5673 return IPC_FAIL_NO_REASON(this);
5674 }
5675
5676 if (guard->Crashed()) {
5677 *aOutCrashed = true;
5678 return IPC_OK();
5679 }
5680
5681 *aOutCrashed = false;
5682 mDriverCrashGuard = std::move(guard);
5683 return IPC_OK();
5684 }
5685
RecvEndDriverCrashGuard(const uint32_t & aGuardType)5686 mozilla::ipc::IPCResult ContentParent::RecvEndDriverCrashGuard(
5687 const uint32_t& aGuardType) {
5688 mDriverCrashGuard = nullptr;
5689 return IPC_OK();
5690 }
5691
RecvNotifyBenchmarkResult(const nsString & aCodecName,const uint32_t & aDecodeFPS)5692 mozilla::ipc::IPCResult ContentParent::RecvNotifyBenchmarkResult(
5693 const nsString& aCodecName, const uint32_t& aDecodeFPS)
5694
5695 {
5696 if (aCodecName.EqualsLiteral("VP9")) {
5697 Preferences::SetUint(VP9Benchmark::sBenchmarkFpsPref, aDecodeFPS);
5698 Preferences::SetUint(VP9Benchmark::sBenchmarkFpsVersionCheck,
5699 VP9Benchmark::sBenchmarkVersionID);
5700 }
5701 return IPC_OK();
5702 }
5703
RecvNotifyPushObservers(const nsCString & aScope,const IPC::Principal & aPrincipal,const nsString & aMessageId)5704 mozilla::ipc::IPCResult ContentParent::RecvNotifyPushObservers(
5705 const nsCString& aScope, const IPC::Principal& aPrincipal,
5706 const nsString& aMessageId) {
5707 if (!ValidatePrincipal(aPrincipal)) {
5708 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
5709 }
5710 PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId, Nothing());
5711 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
5712 return IPC_OK();
5713 }
5714
RecvNotifyPushObserversWithData(const nsCString & aScope,const IPC::Principal & aPrincipal,const nsString & aMessageId,nsTArray<uint8_t> && aData)5715 mozilla::ipc::IPCResult ContentParent::RecvNotifyPushObserversWithData(
5716 const nsCString& aScope, const IPC::Principal& aPrincipal,
5717 const nsString& aMessageId, nsTArray<uint8_t>&& aData) {
5718 if (!ValidatePrincipal(aPrincipal)) {
5719 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
5720 }
5721 PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId,
5722 Some(std::move(aData)));
5723 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
5724 return IPC_OK();
5725 }
5726
5727 mozilla::ipc::IPCResult
RecvNotifyPushSubscriptionChangeObservers(const nsCString & aScope,const IPC::Principal & aPrincipal)5728 ContentParent::RecvNotifyPushSubscriptionChangeObservers(
5729 const nsCString& aScope, const IPC::Principal& aPrincipal) {
5730 if (!ValidatePrincipal(aPrincipal)) {
5731 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
5732 }
5733 PushSubscriptionChangeDispatcher dispatcher(aScope, aPrincipal);
5734 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
5735 return IPC_OK();
5736 }
5737
RecvPushError(const nsCString & aScope,const IPC::Principal & aPrincipal,const nsString & aMessage,const uint32_t & aFlags)5738 mozilla::ipc::IPCResult ContentParent::RecvPushError(
5739 const nsCString& aScope, const IPC::Principal& aPrincipal,
5740 const nsString& aMessage, const uint32_t& aFlags) {
5741 if (!ValidatePrincipal(aPrincipal)) {
5742 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
5743 }
5744 PushErrorDispatcher dispatcher(aScope, aPrincipal, aMessage, aFlags);
5745 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
5746 return IPC_OK();
5747 }
5748
5749 mozilla::ipc::IPCResult
RecvNotifyPushSubscriptionModifiedObservers(const nsCString & aScope,const IPC::Principal & aPrincipal)5750 ContentParent::RecvNotifyPushSubscriptionModifiedObservers(
5751 const nsCString& aScope, const IPC::Principal& aPrincipal) {
5752 if (!ValidatePrincipal(aPrincipal)) {
5753 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
5754 }
5755 PushSubscriptionModifiedDispatcher dispatcher(aScope, aPrincipal);
5756 Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers()));
5757 return IPC_OK();
5758 }
5759
5760 /* static */
BroadcastBlobURLRegistration(const nsACString & aURI,BlobImpl * aBlobImpl,nsIPrincipal * aPrincipal,const Maybe<nsID> & aAgentClusterId,ContentParent * aIgnoreThisCP)5761 void ContentParent::BroadcastBlobURLRegistration(
5762 const nsACString& aURI, BlobImpl* aBlobImpl, nsIPrincipal* aPrincipal,
5763 const Maybe<nsID>& aAgentClusterId, ContentParent* aIgnoreThisCP) {
5764 uint64_t originHash = ComputeLoadedOriginHash(aPrincipal);
5765
5766 bool toBeSent =
5767 BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal);
5768
5769 nsCString uri(aURI);
5770 IPC::Principal principal(aPrincipal);
5771
5772 for (auto* cp : AllProcesses(eLive)) {
5773 if (cp != aIgnoreThisCP) {
5774 if (!toBeSent && !cp->mLoadedOriginHashes.Contains(originHash)) {
5775 continue;
5776 }
5777
5778 nsresult rv = cp->TransmitPermissionsForPrincipal(principal);
5779 if (NS_WARN_IF(NS_FAILED(rv))) {
5780 break;
5781 }
5782
5783 IPCBlob ipcBlob;
5784 rv = IPCBlobUtils::Serialize(aBlobImpl, cp, ipcBlob);
5785 if (NS_WARN_IF(NS_FAILED(rv))) {
5786 break;
5787 }
5788
5789 Unused << cp->SendBlobURLRegistration(uri, ipcBlob, principal,
5790 aAgentClusterId);
5791 }
5792 }
5793 }
5794
5795 /* static */
BroadcastBlobURLUnregistration(const nsACString & aURI,nsIPrincipal * aPrincipal,ContentParent * aIgnoreThisCP)5796 void ContentParent::BroadcastBlobURLUnregistration(
5797 const nsACString& aURI, nsIPrincipal* aPrincipal,
5798 ContentParent* aIgnoreThisCP) {
5799 uint64_t originHash = ComputeLoadedOriginHash(aPrincipal);
5800
5801 bool toBeSent =
5802 BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal);
5803
5804 nsCString uri(aURI);
5805
5806 for (auto* cp : AllProcesses(eLive)) {
5807 if (cp != aIgnoreThisCP &&
5808 (toBeSent || cp->mLoadedOriginHashes.Contains(originHash))) {
5809 Unused << cp->SendBlobURLUnregistration(uri);
5810 }
5811 }
5812 }
5813
RecvStoreAndBroadcastBlobURLRegistration(const nsCString & aURI,const IPCBlob & aBlob,const Principal & aPrincipal,const Maybe<nsID> & aAgentClusterId)5814 mozilla::ipc::IPCResult ContentParent::RecvStoreAndBroadcastBlobURLRegistration(
5815 const nsCString& aURI, const IPCBlob& aBlob, const Principal& aPrincipal,
5816 const Maybe<nsID>& aAgentClusterId) {
5817 if (!ValidatePrincipal(aPrincipal, {ValidatePrincipalOptions::AllowSystem})) {
5818 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
5819 }
5820 RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(aBlob);
5821 if (NS_WARN_IF(!blobImpl)) {
5822 return IPC_FAIL_NO_REASON(this);
5823 }
5824
5825 BlobURLProtocolHandler::AddDataEntry(aURI, aPrincipal, aAgentClusterId,
5826 blobImpl);
5827 BroadcastBlobURLRegistration(aURI, blobImpl, aPrincipal, aAgentClusterId,
5828 this);
5829
5830 // We want to store this blobURL, so we can unregister it if the child
5831 // crashes.
5832 mBlobURLs.AppendElement(aURI);
5833
5834 return IPC_OK();
5835 }
5836
5837 mozilla::ipc::IPCResult
RecvUnstoreAndBroadcastBlobURLUnregistration(const nsCString & aURI,const Principal & aPrincipal)5838 ContentParent::RecvUnstoreAndBroadcastBlobURLUnregistration(
5839 const nsCString& aURI, const Principal& aPrincipal) {
5840 if (!ValidatePrincipal(aPrincipal, {ValidatePrincipalOptions::AllowSystem})) {
5841 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
5842 }
5843 BlobURLProtocolHandler::RemoveDataEntry(aURI, false /* Don't broadcast */);
5844 BroadcastBlobURLUnregistration(aURI, aPrincipal, this);
5845 mBlobURLs.RemoveElement(aURI);
5846 return IPC_OK();
5847 }
5848
RecvGetA11yContentId(uint32_t * aContentId)5849 mozilla::ipc::IPCResult ContentParent::RecvGetA11yContentId(
5850 uint32_t* aContentId) {
5851 #if defined(XP_WIN) && defined(ACCESSIBILITY)
5852 *aContentId = a11y::MsaaAccessible::GetContentProcessIdFor(ChildID());
5853 MOZ_ASSERT(*aContentId);
5854 return IPC_OK();
5855 #else
5856 return IPC_FAIL_NO_REASON(this);
5857 #endif
5858 }
5859
RecvA11yHandlerControl(const uint32_t & aPid,const IHandlerControlHolder & aHandlerControl)5860 mozilla::ipc::IPCResult ContentParent::RecvA11yHandlerControl(
5861 const uint32_t& aPid, const IHandlerControlHolder& aHandlerControl) {
5862 #if defined(XP_WIN) && defined(ACCESSIBILITY)
5863 MOZ_ASSERT(!aHandlerControl.IsNull());
5864 RefPtr<IHandlerControl> proxy(aHandlerControl.Get());
5865 a11y::AccessibleWrap::SetHandlerControl(aPid, std::move(proxy));
5866 return IPC_OK();
5867 #else
5868 return IPC_FAIL_NO_REASON(this);
5869 #endif
5870 }
5871
HandleWindowsMessages(const Message & aMsg) const5872 bool ContentParent::HandleWindowsMessages(const Message& aMsg) const {
5873 MOZ_ASSERT(aMsg.is_sync());
5874
5875 #ifdef ACCESSIBILITY
5876 // a11y messages can be triggered by windows messages, which means if we
5877 // allow handling windows messages while we wait for the response to a sync
5878 // a11y message we can reenter the ipc message sending code.
5879 if (a11y::PDocAccessible::PDocAccessibleStart < aMsg.type() &&
5880 a11y::PDocAccessible::PDocAccessibleEnd > aMsg.type()) {
5881 return false;
5882 }
5883 #endif
5884
5885 return true;
5886 }
5887
RecvGetFilesRequest(const nsID & aUUID,const nsString & aDirectoryPath,const bool & aRecursiveFlag)5888 mozilla::ipc::IPCResult ContentParent::RecvGetFilesRequest(
5889 const nsID& aUUID, const nsString& aDirectoryPath,
5890 const bool& aRecursiveFlag) {
5891 MOZ_ASSERT(!mGetFilesPendingRequests.GetWeak(aUUID));
5892
5893 if (!mozilla::Preferences::GetBool("dom.filesystem.pathcheck.disabled",
5894 false)) {
5895 RefPtr<FileSystemSecurity> fss = FileSystemSecurity::Get();
5896 if (NS_WARN_IF(!fss || !fss->ContentProcessHasAccessTo(ChildID(),
5897 aDirectoryPath))) {
5898 return IPC_FAIL_NO_REASON(this);
5899 }
5900 }
5901
5902 ErrorResult rv;
5903 RefPtr<GetFilesHelper> helper = GetFilesHelperParent::Create(
5904 aUUID, aDirectoryPath, aRecursiveFlag, this, rv);
5905
5906 if (NS_WARN_IF(rv.Failed())) {
5907 if (!SendGetFilesResponse(aUUID,
5908 GetFilesResponseFailure(rv.StealNSResult()))) {
5909 return IPC_FAIL_NO_REASON(this);
5910 }
5911 return IPC_OK();
5912 }
5913
5914 mGetFilesPendingRequests.InsertOrUpdate(aUUID, std::move(helper));
5915 return IPC_OK();
5916 }
5917
RecvDeleteGetFilesRequest(const nsID & aUUID)5918 mozilla::ipc::IPCResult ContentParent::RecvDeleteGetFilesRequest(
5919 const nsID& aUUID) {
5920 mGetFilesPendingRequests.Remove(aUUID);
5921 return IPC_OK();
5922 }
5923
SendGetFilesResponseAndForget(const nsID & aUUID,const GetFilesResponseResult & aResult)5924 void ContentParent::SendGetFilesResponseAndForget(
5925 const nsID& aUUID, const GetFilesResponseResult& aResult) {
5926 if (mGetFilesPendingRequests.Remove(aUUID)) {
5927 Unused << SendGetFilesResponse(aUUID, aResult);
5928 }
5929 }
5930
PaintTabWhileInterruptingJS(BrowserParent * aBrowserParent,const layers::LayersObserverEpoch & aEpoch)5931 void ContentParent::PaintTabWhileInterruptingJS(
5932 BrowserParent* aBrowserParent, const layers::LayersObserverEpoch& aEpoch) {
5933 if (!mHangMonitorActor) {
5934 return;
5935 }
5936 ProcessHangMonitor::PaintWhileInterruptingJS(mHangMonitorActor,
5937 aBrowserParent, aEpoch);
5938 }
5939
CancelContentJSExecutionIfRunning(BrowserParent * aBrowserParent,nsIRemoteTab::NavigationType aNavigationType,const CancelContentJSOptions & aCancelContentJSOptions)5940 void ContentParent::CancelContentJSExecutionIfRunning(
5941 BrowserParent* aBrowserParent, nsIRemoteTab::NavigationType aNavigationType,
5942 const CancelContentJSOptions& aCancelContentJSOptions) {
5943 if (!mHangMonitorActor) {
5944 return;
5945 }
5946
5947 ProcessHangMonitor::CancelContentJSExecutionIfRunning(
5948 mHangMonitorActor, aBrowserParent, aNavigationType,
5949 aCancelContentJSOptions);
5950 }
5951
UpdateCookieStatus(nsIChannel * aChannel)5952 void ContentParent::UpdateCookieStatus(nsIChannel* aChannel) {
5953 PNeckoParent* neckoParent = LoneManagedOrNullAsserts(ManagedPNeckoParent());
5954 PCookieServiceParent* csParent =
5955 LoneManagedOrNullAsserts(neckoParent->ManagedPCookieServiceParent());
5956 if (csParent) {
5957 auto* cs = static_cast<CookieServiceParent*>(csParent);
5958 cs->TrackCookieLoad(aChannel);
5959 }
5960 }
5961
AboutToLoadHttpFtpDocumentForChild(nsIChannel * aChannel,bool * aShouldWaitForPermissionCookieUpdate)5962 nsresult ContentParent::AboutToLoadHttpFtpDocumentForChild(
5963 nsIChannel* aChannel, bool* aShouldWaitForPermissionCookieUpdate) {
5964 MOZ_ASSERT(aChannel);
5965
5966 if (aShouldWaitForPermissionCookieUpdate) {
5967 *aShouldWaitForPermissionCookieUpdate = false;
5968 }
5969
5970 nsresult rv;
5971 bool isDocument = aChannel->IsDocument();
5972 if (!isDocument) {
5973 // We may be looking at a nsIHttpChannel which has isMainDocumentChannel set
5974 // (e.g. the internal http channel for a view-source: load.).
5975 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
5976 if (httpChannel) {
5977 rv = httpChannel->GetIsMainDocumentChannel(&isDocument);
5978 NS_ENSURE_SUCCESS(rv, rv);
5979 }
5980 }
5981 if (!isDocument) {
5982 return NS_OK;
5983 }
5984
5985 // Get the principal for the channel result, so that we can get the permission
5986 // key for the document which will be created from this response.
5987 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
5988 if (NS_WARN_IF(!ssm)) {
5989 return NS_ERROR_FAILURE;
5990 }
5991
5992 nsCOMPtr<nsIPrincipal> principal;
5993 nsCOMPtr<nsIPrincipal> partitionedPrincipal;
5994 rv = ssm->GetChannelResultPrincipals(aChannel, getter_AddRefs(principal),
5995 getter_AddRefs(partitionedPrincipal));
5996 NS_ENSURE_SUCCESS(rv, rv);
5997
5998 // Let the caller know we're going to send main thread IPC for updating
5999 // permisssions/cookies.
6000 if (aShouldWaitForPermissionCookieUpdate) {
6001 *aShouldWaitForPermissionCookieUpdate = true;
6002 }
6003
6004 TransmitBlobURLsForPrincipal(principal);
6005
6006 // Tranmit permissions for both regular and partitioned principal so that the
6007 // content process can get permissions for the partitioned principal. For
6008 // example, the desk-notification permission for a partitioned service worker.
6009 rv = TransmitPermissionsForPrincipal(principal);
6010 NS_ENSURE_SUCCESS(rv, rv);
6011
6012 rv = TransmitPermissionsForPrincipal(partitionedPrincipal);
6013 NS_ENSURE_SUCCESS(rv, rv);
6014
6015 nsLoadFlags newLoadFlags;
6016 aChannel->GetLoadFlags(&newLoadFlags);
6017 if (newLoadFlags & nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE) {
6018 UpdateCookieStatus(aChannel);
6019 }
6020
6021 RefPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
6022 RefPtr<BrowsingContext> browsingContext;
6023 rv = loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext));
6024 NS_ENSURE_SUCCESS(rv, rv);
6025
6026 if (!NextGenLocalStorageEnabled()) {
6027 return NS_OK;
6028 }
6029
6030 if (principal->GetIsContentPrincipal()) {
6031 nsCOMPtr<nsILocalStorageManager> lsm =
6032 do_GetService("@mozilla.org/dom/localStorage-manager;1");
6033 if (NS_WARN_IF(!lsm)) {
6034 return NS_ERROR_FAILURE;
6035 }
6036
6037 nsCOMPtr<nsIPrincipal> storagePrincipal;
6038 rv = ssm->GetChannelResultStoragePrincipal(
6039 aChannel, getter_AddRefs(storagePrincipal));
6040 NS_ENSURE_SUCCESS(rv, rv);
6041
6042 RefPtr<Promise> dummy;
6043 rv = lsm->Preload(storagePrincipal, nullptr, getter_AddRefs(dummy));
6044 if (NS_FAILED(rv)) {
6045 NS_WARNING("Failed to preload local storage!");
6046 }
6047 }
6048
6049 return NS_OK;
6050 }
6051
TransmitPermissionsForPrincipal(nsIPrincipal * aPrincipal)6052 nsresult ContentParent::TransmitPermissionsForPrincipal(
6053 nsIPrincipal* aPrincipal) {
6054 // Create the key, and send it down to the content process.
6055 nsTArray<std::pair<nsCString, nsCString>> pairs =
6056 PermissionManager::GetAllKeysForPrincipal(aPrincipal);
6057 MOZ_ASSERT(pairs.Length() >= 1);
6058 for (auto& pair : pairs) {
6059 EnsurePermissionsByKey(pair.first, pair.second);
6060 }
6061
6062 return NS_OK;
6063 }
6064
TransmitBlobURLsForPrincipal(nsIPrincipal * aPrincipal)6065 void ContentParent::TransmitBlobURLsForPrincipal(nsIPrincipal* aPrincipal) {
6066 // If we're already broadcasting BlobURLs with this principal, we don't need
6067 // to send them here.
6068 if (BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal)) {
6069 return;
6070 }
6071
6072 // We shouldn't have any Blob URLs with expanded principals, so transmit URLs
6073 // for each principal in the AllowList instead.
6074 if (nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(aPrincipal)) {
6075 for (const auto& prin : ep->AllowList()) {
6076 TransmitBlobURLsForPrincipal(prin);
6077 }
6078 return;
6079 }
6080
6081 uint64_t originHash = ComputeLoadedOriginHash(aPrincipal);
6082
6083 if (!mLoadedOriginHashes.Contains(originHash)) {
6084 mLoadedOriginHashes.AppendElement(originHash);
6085
6086 nsTArray<BlobURLRegistrationData> registrations;
6087 BlobURLProtocolHandler::ForEachBlobURL(
6088 [&](BlobImpl* aBlobImpl, nsIPrincipal* aBlobPrincipal,
6089 const Maybe<nsID>& aAgentClusterId, const nsACString& aURI,
6090 bool aRevoked) {
6091 // This check uses `ComputeLoadedOriginHash` to compare, rather than
6092 // doing the more accurate `Equals` check, as it needs to match the
6093 // behaviour of the logic to broadcast new registrations.
6094 if (originHash != ComputeLoadedOriginHash(aBlobPrincipal)) {
6095 return true;
6096 }
6097
6098 IPCBlob ipcBlob;
6099 nsresult rv = IPCBlobUtils::Serialize(aBlobImpl, this, ipcBlob);
6100 if (NS_WARN_IF(NS_FAILED(rv))) {
6101 return false;
6102 }
6103
6104 registrations.AppendElement(
6105 BlobURLRegistrationData(nsCString(aURI), ipcBlob, aBlobPrincipal,
6106 aAgentClusterId, aRevoked));
6107
6108 rv = TransmitPermissionsForPrincipal(aBlobPrincipal);
6109 Unused << NS_WARN_IF(NS_FAILED(rv));
6110 return true;
6111 });
6112
6113 if (!registrations.IsEmpty()) {
6114 Unused << SendInitBlobURLs(registrations);
6115 }
6116 }
6117 }
6118
TransmitBlobDataIfBlobURL(nsIURI * aURI)6119 void ContentParent::TransmitBlobDataIfBlobURL(nsIURI* aURI) {
6120 MOZ_ASSERT(aURI);
6121
6122 nsCOMPtr<nsIPrincipal> principal;
6123 if (BlobURLProtocolHandler::GetBlobURLPrincipal(aURI,
6124 getter_AddRefs(principal))) {
6125 TransmitBlobURLsForPrincipal(principal);
6126 }
6127 }
6128
EnsurePermissionsByKey(const nsCString & aKey,const nsCString & aOrigin)6129 void ContentParent::EnsurePermissionsByKey(const nsCString& aKey,
6130 const nsCString& aOrigin) {
6131 // NOTE: Make sure to initialize the permission manager before updating the
6132 // mActivePermissionKeys list. If the permission manager is being initialized
6133 // by this call to GetPermissionManager, and we've added the key to
6134 // mActivePermissionKeys, then the permission manager will send down a
6135 // SendAddPermission before receiving the SendSetPermissionsWithKey message.
6136 RefPtr<PermissionManager> permManager = PermissionManager::GetInstance();
6137 if (!permManager) {
6138 return;
6139 }
6140
6141 if (!mActivePermissionKeys.EnsureInserted(aKey)) {
6142 return;
6143 }
6144
6145 nsTArray<IPC::Permission> perms;
6146 if (permManager->GetPermissionsFromOriginOrKey(aOrigin, aKey, perms)) {
6147 Unused << SendSetPermissionsWithKey(aKey, perms);
6148 }
6149 }
6150
NeedsPermissionsUpdate(const nsACString & aPermissionKey) const6151 bool ContentParent::NeedsPermissionsUpdate(
6152 const nsACString& aPermissionKey) const {
6153 return mActivePermissionKeys.Contains(aPermissionKey);
6154 }
6155
RecvAccumulateChildHistograms(nsTArray<HistogramAccumulation> && aAccumulations)6156 mozilla::ipc::IPCResult ContentParent::RecvAccumulateChildHistograms(
6157 nsTArray<HistogramAccumulation>&& aAccumulations) {
6158 TelemetryIPC::AccumulateChildHistograms(GetTelemetryProcessID(mRemoteType),
6159 aAccumulations);
6160 return IPC_OK();
6161 }
6162
RecvAccumulateChildKeyedHistograms(nsTArray<KeyedHistogramAccumulation> && aAccumulations)6163 mozilla::ipc::IPCResult ContentParent::RecvAccumulateChildKeyedHistograms(
6164 nsTArray<KeyedHistogramAccumulation>&& aAccumulations) {
6165 TelemetryIPC::AccumulateChildKeyedHistograms(
6166 GetTelemetryProcessID(mRemoteType), aAccumulations);
6167 return IPC_OK();
6168 }
6169
RecvUpdateChildScalars(nsTArray<ScalarAction> && aScalarActions)6170 mozilla::ipc::IPCResult ContentParent::RecvUpdateChildScalars(
6171 nsTArray<ScalarAction>&& aScalarActions) {
6172 TelemetryIPC::UpdateChildScalars(GetTelemetryProcessID(mRemoteType),
6173 aScalarActions);
6174 return IPC_OK();
6175 }
6176
RecvUpdateChildKeyedScalars(nsTArray<KeyedScalarAction> && aScalarActions)6177 mozilla::ipc::IPCResult ContentParent::RecvUpdateChildKeyedScalars(
6178 nsTArray<KeyedScalarAction>&& aScalarActions) {
6179 TelemetryIPC::UpdateChildKeyedScalars(GetTelemetryProcessID(mRemoteType),
6180 aScalarActions);
6181 return IPC_OK();
6182 }
6183
RecvRecordChildEvents(nsTArray<mozilla::Telemetry::ChildEventData> && aEvents)6184 mozilla::ipc::IPCResult ContentParent::RecvRecordChildEvents(
6185 nsTArray<mozilla::Telemetry::ChildEventData>&& aEvents) {
6186 TelemetryIPC::RecordChildEvents(GetTelemetryProcessID(mRemoteType), aEvents);
6187 return IPC_OK();
6188 }
6189
RecvRecordDiscardedData(const mozilla::Telemetry::DiscardedData & aDiscardedData)6190 mozilla::ipc::IPCResult ContentParent::RecvRecordDiscardedData(
6191 const mozilla::Telemetry::DiscardedData& aDiscardedData) {
6192 TelemetryIPC::RecordDiscardedData(GetTelemetryProcessID(mRemoteType),
6193 aDiscardedData);
6194 return IPC_OK();
6195 }
6196
6197 //////////////////////////////////////////////////////////////////
6198 // PURLClassifierParent
6199
AllocPURLClassifierParent(const Principal & aPrincipal,bool * aSuccess)6200 PURLClassifierParent* ContentParent::AllocPURLClassifierParent(
6201 const Principal& aPrincipal, bool* aSuccess) {
6202 MOZ_ASSERT(NS_IsMainThread());
6203
6204 *aSuccess = true;
6205 RefPtr<URLClassifierParent> actor = new URLClassifierParent();
6206 return actor.forget().take();
6207 }
6208
RecvPURLClassifierConstructor(PURLClassifierParent * aActor,const Principal & aPrincipal,bool * aSuccess)6209 mozilla::ipc::IPCResult ContentParent::RecvPURLClassifierConstructor(
6210 PURLClassifierParent* aActor, const Principal& aPrincipal, bool* aSuccess) {
6211 MOZ_ASSERT(NS_IsMainThread());
6212 MOZ_ASSERT(aActor);
6213 *aSuccess = false;
6214
6215 auto* actor = static_cast<URLClassifierParent*>(aActor);
6216 nsCOMPtr<nsIPrincipal> principal(aPrincipal);
6217 if (!principal) {
6218 actor->ClassificationFailed();
6219 return IPC_OK();
6220 }
6221 if (!ValidatePrincipal(aPrincipal)) {
6222 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
6223 }
6224 return actor->StartClassify(principal, aSuccess);
6225 }
6226
DeallocPURLClassifierParent(PURLClassifierParent * aActor)6227 bool ContentParent::DeallocPURLClassifierParent(PURLClassifierParent* aActor) {
6228 MOZ_ASSERT(NS_IsMainThread());
6229 MOZ_ASSERT(aActor);
6230
6231 RefPtr<URLClassifierParent> actor =
6232 dont_AddRef(static_cast<URLClassifierParent*>(aActor));
6233 return true;
6234 }
6235
6236 //////////////////////////////////////////////////////////////////
6237 // PURLClassifierLocalParent
6238
AllocPURLClassifierLocalParent(nsIURI * aURI,const nsTArray<IPCURLClassifierFeature> & aFeatures)6239 PURLClassifierLocalParent* ContentParent::AllocPURLClassifierLocalParent(
6240 nsIURI* aURI, const nsTArray<IPCURLClassifierFeature>& aFeatures) {
6241 MOZ_ASSERT(NS_IsMainThread());
6242
6243 RefPtr<URLClassifierLocalParent> actor = new URLClassifierLocalParent();
6244 return actor.forget().take();
6245 }
6246
RecvPURLClassifierLocalConstructor(PURLClassifierLocalParent * aActor,nsIURI * aURI,nsTArray<IPCURLClassifierFeature> && aFeatures)6247 mozilla::ipc::IPCResult ContentParent::RecvPURLClassifierLocalConstructor(
6248 PURLClassifierLocalParent* aActor, nsIURI* aURI,
6249 nsTArray<IPCURLClassifierFeature>&& aFeatures) {
6250 MOZ_ASSERT(NS_IsMainThread());
6251 MOZ_ASSERT(aActor);
6252
6253 nsTArray<IPCURLClassifierFeature> features = std::move(aFeatures);
6254
6255 if (!aURI) {
6256 NS_WARNING("aURI should not be null");
6257 return IPC_FAIL_NO_REASON(this);
6258 }
6259
6260 auto* actor = static_cast<URLClassifierLocalParent*>(aActor);
6261 return actor->StartClassify(aURI, features);
6262 }
6263
DeallocPURLClassifierLocalParent(PURLClassifierLocalParent * aActor)6264 bool ContentParent::DeallocPURLClassifierLocalParent(
6265 PURLClassifierLocalParent* aActor) {
6266 MOZ_ASSERT(NS_IsMainThread());
6267 MOZ_ASSERT(aActor);
6268
6269 RefPtr<URLClassifierLocalParent> actor =
6270 dont_AddRef(static_cast<URLClassifierLocalParent*>(aActor));
6271 return true;
6272 }
6273
AllocPLoginReputationParent(nsIURI * aURI)6274 PLoginReputationParent* ContentParent::AllocPLoginReputationParent(
6275 nsIURI* aURI) {
6276 MOZ_ASSERT(NS_IsMainThread());
6277
6278 RefPtr<LoginReputationParent> actor = new LoginReputationParent();
6279 return actor.forget().take();
6280 }
6281
RecvPLoginReputationConstructor(PLoginReputationParent * aActor,nsIURI * aURI)6282 mozilla::ipc::IPCResult ContentParent::RecvPLoginReputationConstructor(
6283 PLoginReputationParent* aActor, nsIURI* aURI) {
6284 MOZ_ASSERT(NS_IsMainThread());
6285 MOZ_ASSERT(aActor);
6286
6287 if (!aURI) {
6288 return IPC_FAIL_NO_REASON(this);
6289 }
6290
6291 auto* actor = static_cast<LoginReputationParent*>(aActor);
6292 return actor->QueryReputation(aURI);
6293 }
6294
DeallocPLoginReputationParent(PLoginReputationParent * aActor)6295 bool ContentParent::DeallocPLoginReputationParent(
6296 PLoginReputationParent* aActor) {
6297 MOZ_ASSERT(NS_IsMainThread());
6298 MOZ_ASSERT(aActor);
6299
6300 RefPtr<LoginReputationParent> actor =
6301 dont_AddRef(static_cast<LoginReputationParent*>(aActor));
6302 return true;
6303 }
6304
6305 PSessionStorageObserverParent*
AllocPSessionStorageObserverParent()6306 ContentParent::AllocPSessionStorageObserverParent() {
6307 MOZ_ASSERT(NS_IsMainThread());
6308
6309 return mozilla::dom::AllocPSessionStorageObserverParent();
6310 }
6311
RecvPSessionStorageObserverConstructor(PSessionStorageObserverParent * aActor)6312 mozilla::ipc::IPCResult ContentParent::RecvPSessionStorageObserverConstructor(
6313 PSessionStorageObserverParent* aActor) {
6314 MOZ_ASSERT(NS_IsMainThread());
6315 MOZ_ASSERT(aActor);
6316
6317 if (!mozilla::dom::RecvPSessionStorageObserverConstructor(aActor)) {
6318 return IPC_FAIL_NO_REASON(this);
6319 }
6320 return IPC_OK();
6321 }
6322
DeallocPSessionStorageObserverParent(PSessionStorageObserverParent * aActor)6323 bool ContentParent::DeallocPSessionStorageObserverParent(
6324 PSessionStorageObserverParent* aActor) {
6325 MOZ_ASSERT(NS_IsMainThread());
6326 MOZ_ASSERT(aActor);
6327
6328 return mozilla::dom::DeallocPSessionStorageObserverParent(aActor);
6329 }
6330
RecvDeviceReset()6331 mozilla::ipc::IPCResult ContentParent::RecvDeviceReset() {
6332 GPUProcessManager* pm = GPUProcessManager::Get();
6333 if (pm) {
6334 pm->SimulateDeviceReset();
6335 }
6336
6337 return IPC_OK();
6338 }
6339
RecvBHRThreadHang(const HangDetails & aDetails)6340 mozilla::ipc::IPCResult ContentParent::RecvBHRThreadHang(
6341 const HangDetails& aDetails) {
6342 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
6343 if (obs) {
6344 // Copy the HangDetails recieved over the network into a nsIHangDetails, and
6345 // then fire our own observer notification.
6346 // XXX: We should be able to avoid this potentially expensive copy here by
6347 // moving our deserialized argument.
6348 nsCOMPtr<nsIHangDetails> hangDetails =
6349 new nsHangDetails(HangDetails(aDetails), PersistedToDisk::No);
6350 obs->NotifyObservers(hangDetails, "bhr-thread-hang", nullptr);
6351 }
6352 return IPC_OK();
6353 }
6354
RecvAddCertException(const nsACString & aSerializedCert,uint32_t aFlags,const nsACString & aHostName,int32_t aPort,const OriginAttributes & aOriginAttributes,bool aIsTemporary,AddCertExceptionResolver && aResolver)6355 mozilla::ipc::IPCResult ContentParent::RecvAddCertException(
6356 const nsACString& aSerializedCert, uint32_t aFlags,
6357 const nsACString& aHostName, int32_t aPort,
6358 const OriginAttributes& aOriginAttributes, bool aIsTemporary,
6359 AddCertExceptionResolver&& aResolver) {
6360 nsCOMPtr<nsISupports> certObj;
6361 nsresult rv = NS_DeserializeObject(aSerializedCert, getter_AddRefs(certObj));
6362 if (NS_SUCCEEDED(rv)) {
6363 nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(certObj);
6364 if (!cert) {
6365 rv = NS_ERROR_INVALID_ARG;
6366 } else {
6367 nsCOMPtr<nsICertOverrideService> overrideService =
6368 do_GetService(NS_CERTOVERRIDE_CONTRACTID);
6369 if (!overrideService) {
6370 rv = NS_ERROR_FAILURE;
6371 } else {
6372 rv = overrideService->RememberValidityOverride(
6373 aHostName, aPort, aOriginAttributes, cert, aFlags, aIsTemporary);
6374 }
6375 }
6376 }
6377 aResolver(rv);
6378 return IPC_OK();
6379 }
6380
6381 mozilla::ipc::IPCResult
RecvAutomaticStorageAccessPermissionCanBeGranted(const Principal & aPrincipal,AutomaticStorageAccessPermissionCanBeGrantedResolver && aResolver)6382 ContentParent::RecvAutomaticStorageAccessPermissionCanBeGranted(
6383 const Principal& aPrincipal,
6384 AutomaticStorageAccessPermissionCanBeGrantedResolver&& aResolver) {
6385 if (!ValidatePrincipal(aPrincipal)) {
6386 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
6387 }
6388 aResolver(Document::AutomaticStorageAccessPermissionCanBeGranted(aPrincipal));
6389 return IPC_OK();
6390 }
6391
6392 mozilla::ipc::IPCResult
RecvStorageAccessPermissionGrantedForOrigin(uint64_t aTopLevelWindowId,const MaybeDiscarded<BrowsingContext> & aParentContext,const Principal & aTrackingPrincipal,const nsCString & aTrackingOrigin,const int & aAllowMode,const Maybe<ContentBlockingNotifier::StorageAccessPermissionGrantedReason> & aReason,StorageAccessPermissionGrantedForOriginResolver && aResolver)6393 ContentParent::RecvStorageAccessPermissionGrantedForOrigin(
6394 uint64_t aTopLevelWindowId,
6395 const MaybeDiscarded<BrowsingContext>& aParentContext,
6396 const Principal& aTrackingPrincipal, const nsCString& aTrackingOrigin,
6397 const int& aAllowMode,
6398 const Maybe<ContentBlockingNotifier::StorageAccessPermissionGrantedReason>&
6399 aReason,
6400 StorageAccessPermissionGrantedForOriginResolver&& aResolver) {
6401 if (aParentContext.IsNullOrDiscarded()) {
6402 return IPC_OK();
6403 }
6404
6405 // We only report here if we cannot report the console directly in the content
6406 // process. In that case, the `aReason` would be given a value. Otherwise, it
6407 // will be nothing.
6408 if (aReason) {
6409 ContentBlockingNotifier::ReportUnblockingToConsole(
6410 aParentContext.get_canonical(), NS_ConvertUTF8toUTF16(aTrackingOrigin),
6411 aReason.value());
6412 }
6413
6414 ContentBlocking::SaveAccessForOriginOnParentProcess(
6415 aTopLevelWindowId, aParentContext.get_canonical(), aTrackingPrincipal,
6416 aAllowMode)
6417 ->Then(
6418 GetCurrentSerialEventTarget(), __func__,
6419 [aResolver = std::move(aResolver)](
6420 ContentBlocking::ParentAccessGrantPromise::ResolveOrRejectValue&&
6421 aValue) {
6422 bool success =
6423 aValue.IsResolve() && NS_SUCCEEDED(aValue.ResolveValue());
6424 aResolver(success);
6425 });
6426 return IPC_OK();
6427 }
6428
RecvCompleteAllowAccessFor(const MaybeDiscarded<BrowsingContext> & aParentContext,uint64_t aTopLevelWindowId,const Principal & aTrackingPrincipal,const nsCString & aTrackingOrigin,uint32_t aCookieBehavior,const ContentBlockingNotifier::StorageAccessPermissionGrantedReason & aReason,CompleteAllowAccessForResolver && aResolver)6429 mozilla::ipc::IPCResult ContentParent::RecvCompleteAllowAccessFor(
6430 const MaybeDiscarded<BrowsingContext>& aParentContext,
6431 uint64_t aTopLevelWindowId, const Principal& aTrackingPrincipal,
6432 const nsCString& aTrackingOrigin, uint32_t aCookieBehavior,
6433 const ContentBlockingNotifier::StorageAccessPermissionGrantedReason&
6434 aReason,
6435 CompleteAllowAccessForResolver&& aResolver) {
6436 if (aParentContext.IsNullOrDiscarded()) {
6437 return IPC_OK();
6438 }
6439
6440 ContentBlocking::CompleteAllowAccessFor(
6441 aParentContext.get_canonical(), aTopLevelWindowId, aTrackingPrincipal,
6442 aTrackingOrigin, aCookieBehavior, aReason, nullptr)
6443 ->Then(GetCurrentSerialEventTarget(), __func__,
6444 [aResolver = std::move(aResolver)](
6445 ContentBlocking::StorageAccessPermissionGrantPromise::
6446 ResolveOrRejectValue&& aValue) {
6447 Maybe<StorageAccessPromptChoices> choice;
6448 if (aValue.IsResolve()) {
6449 choice.emplace(static_cast<StorageAccessPromptChoices>(
6450 aValue.ResolveValue()));
6451 }
6452 aResolver(choice);
6453 });
6454 return IPC_OK();
6455 }
6456
RecvStoreUserInteractionAsPermission(const Principal & aPrincipal)6457 mozilla::ipc::IPCResult ContentParent::RecvStoreUserInteractionAsPermission(
6458 const Principal& aPrincipal) {
6459 if (!ValidatePrincipal(aPrincipal)) {
6460 LogAndAssertFailedPrincipalValidationInfo(aPrincipal, __func__);
6461 }
6462 ContentBlockingUserInteraction::Observe(aPrincipal);
6463 return IPC_OK();
6464 }
6465
RecvAsyncShouldAllowAccessFor(const MaybeDiscarded<BrowsingContext> & aTopContext,const Principal & aPrincipal,const AsyncShouldAllowAccessForResolver && aResolver)6466 mozilla::ipc::IPCResult ContentParent::RecvAsyncShouldAllowAccessFor(
6467 const MaybeDiscarded<BrowsingContext>& aTopContext,
6468 const Principal& aPrincipal,
6469 const AsyncShouldAllowAccessForResolver&& aResolver) {
6470 if (aTopContext.IsNullOrDiscarded()) {
6471 return IPC_OK();
6472 }
6473
6474 ContentBlocking::AsyncShouldAllowAccessFor(aTopContext.get_canonical(),
6475 aPrincipal)
6476 ->Then(GetCurrentSerialEventTarget(), __func__,
6477 [aResolver](ContentBlocking::AsyncShouldAllowAccessForPromise::
6478 ResolveOrRejectValue&& aValue) {
6479 bool allowed = aValue.IsResolve();
6480
6481 aResolver(Tuple<const bool&, const uint32_t&>(
6482 allowed, allowed ? 0 : aValue.RejectValue()));
6483 });
6484
6485 return IPC_OK();
6486 }
6487
RecvNotifyMediaPlaybackChanged(const MaybeDiscarded<BrowsingContext> & aContext,MediaPlaybackState aState)6488 mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaPlaybackChanged(
6489 const MaybeDiscarded<BrowsingContext>& aContext,
6490 MediaPlaybackState aState) {
6491 if (aContext.IsNullOrDiscarded()) {
6492 return IPC_OK();
6493 }
6494 if (RefPtr<IMediaInfoUpdater> updater =
6495 aContext.get_canonical()->GetMediaController()) {
6496 updater->NotifyMediaPlaybackChanged(aContext.ContextId(), aState);
6497 }
6498 return IPC_OK();
6499 }
6500
RecvNotifyMediaAudibleChanged(const MaybeDiscarded<BrowsingContext> & aContext,MediaAudibleState aState)6501 mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaAudibleChanged(
6502 const MaybeDiscarded<BrowsingContext>& aContext, MediaAudibleState aState) {
6503 if (aContext.IsNullOrDiscarded()) {
6504 return IPC_OK();
6505 }
6506 if (RefPtr<IMediaInfoUpdater> updater =
6507 aContext.get_canonical()->GetMediaController()) {
6508 updater->NotifyMediaAudibleChanged(aContext.ContextId(), aState);
6509 }
6510 return IPC_OK();
6511 }
6512
RecvNotifyPictureInPictureModeChanged(const MaybeDiscarded<BrowsingContext> & aContext,bool aEnabled)6513 mozilla::ipc::IPCResult ContentParent::RecvNotifyPictureInPictureModeChanged(
6514 const MaybeDiscarded<BrowsingContext>& aContext, bool aEnabled) {
6515 if (aContext.IsNullOrDiscarded()) {
6516 return IPC_OK();
6517 }
6518 if (RefPtr<MediaController> controller =
6519 aContext.get_canonical()->GetMediaController()) {
6520 controller->SetIsInPictureInPictureMode(aContext.ContextId(), aEnabled);
6521 }
6522 return IPC_OK();
6523 }
6524
RecvAbortOtherOrientationPendingPromises(const MaybeDiscarded<BrowsingContext> & aContext)6525 mozilla::ipc::IPCResult ContentParent::RecvAbortOtherOrientationPendingPromises(
6526 const MaybeDiscarded<BrowsingContext>& aContext) {
6527 if (aContext.IsNullOrDiscarded()) {
6528 return IPC_OK();
6529 }
6530
6531 CanonicalBrowsingContext* context = aContext.get_canonical();
6532
6533 context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
6534 Unused << aParent->SendAbortOrientationPendingPromises(context);
6535 });
6536
6537 return IPC_OK();
6538 }
6539
RecvNotifyMediaSessionUpdated(const MaybeDiscarded<BrowsingContext> & aContext,bool aIsCreated)6540 mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaSessionUpdated(
6541 const MaybeDiscarded<BrowsingContext>& aContext, bool aIsCreated) {
6542 if (aContext.IsNullOrDiscarded()) {
6543 return IPC_OK();
6544 }
6545
6546 RefPtr<IMediaInfoUpdater> updater =
6547 aContext.get_canonical()->GetMediaController();
6548 if (!updater) {
6549 return IPC_OK();
6550 }
6551 if (aIsCreated) {
6552 updater->NotifySessionCreated(aContext->Id());
6553 } else {
6554 updater->NotifySessionDestroyed(aContext->Id());
6555 }
6556 return IPC_OK();
6557 }
6558
RecvNotifyUpdateMediaMetadata(const MaybeDiscarded<BrowsingContext> & aContext,const Maybe<MediaMetadataBase> & aMetadata)6559 mozilla::ipc::IPCResult ContentParent::RecvNotifyUpdateMediaMetadata(
6560 const MaybeDiscarded<BrowsingContext>& aContext,
6561 const Maybe<MediaMetadataBase>& aMetadata) {
6562 if (aContext.IsNullOrDiscarded()) {
6563 return IPC_OK();
6564 }
6565 if (RefPtr<IMediaInfoUpdater> updater =
6566 aContext.get_canonical()->GetMediaController()) {
6567 updater->UpdateMetadata(aContext.ContextId(), aMetadata);
6568 }
6569 return IPC_OK();
6570 }
6571
6572 mozilla::ipc::IPCResult
RecvNotifyMediaSessionPlaybackStateChanged(const MaybeDiscarded<BrowsingContext> & aContext,MediaSessionPlaybackState aPlaybackState)6573 ContentParent::RecvNotifyMediaSessionPlaybackStateChanged(
6574 const MaybeDiscarded<BrowsingContext>& aContext,
6575 MediaSessionPlaybackState aPlaybackState) {
6576 if (aContext.IsNullOrDiscarded()) {
6577 return IPC_OK();
6578 }
6579 if (RefPtr<IMediaInfoUpdater> updater =
6580 aContext.get_canonical()->GetMediaController()) {
6581 updater->SetDeclaredPlaybackState(aContext.ContextId(), aPlaybackState);
6582 }
6583 return IPC_OK();
6584 }
6585
6586 mozilla::ipc::IPCResult
RecvNotifyMediaSessionSupportedActionChanged(const MaybeDiscarded<BrowsingContext> & aContext,MediaSessionAction aAction,bool aEnabled)6587 ContentParent::RecvNotifyMediaSessionSupportedActionChanged(
6588 const MaybeDiscarded<BrowsingContext>& aContext, MediaSessionAction aAction,
6589 bool aEnabled) {
6590 if (aContext.IsNullOrDiscarded()) {
6591 return IPC_OK();
6592 }
6593 RefPtr<IMediaInfoUpdater> updater =
6594 aContext.get_canonical()->GetMediaController();
6595 if (!updater) {
6596 return IPC_OK();
6597 }
6598 if (aEnabled) {
6599 updater->EnableAction(aContext.ContextId(), aAction);
6600 } else {
6601 updater->DisableAction(aContext.ContextId(), aAction);
6602 }
6603 return IPC_OK();
6604 }
6605
RecvNotifyMediaFullScreenState(const MaybeDiscarded<BrowsingContext> & aContext,bool aIsInFullScreen)6606 mozilla::ipc::IPCResult ContentParent::RecvNotifyMediaFullScreenState(
6607 const MaybeDiscarded<BrowsingContext>& aContext, bool aIsInFullScreen) {
6608 if (aContext.IsNullOrDiscarded()) {
6609 return IPC_OK();
6610 }
6611 if (RefPtr<IMediaInfoUpdater> updater =
6612 aContext.get_canonical()->GetMediaController()) {
6613 updater->NotifyMediaFullScreenState(aContext.ContextId(), aIsInFullScreen);
6614 }
6615 return IPC_OK();
6616 }
6617
RecvNotifyPositionStateChanged(const MaybeDiscarded<BrowsingContext> & aContext,const PositionState & aState)6618 mozilla::ipc::IPCResult ContentParent::RecvNotifyPositionStateChanged(
6619 const MaybeDiscarded<BrowsingContext>& aContext,
6620 const PositionState& aState) {
6621 if (aContext.IsNullOrDiscarded()) {
6622 return IPC_OK();
6623 }
6624 if (RefPtr<IMediaInfoUpdater> updater =
6625 aContext.get_canonical()->GetMediaController()) {
6626 updater->UpdatePositionState(aContext.ContextId(), aState);
6627 }
6628 return IPC_OK();
6629 }
6630
RecvAddOrRemovePageAwakeRequest(const MaybeDiscarded<BrowsingContext> & aContext,const bool & aShouldAddCount)6631 mozilla::ipc::IPCResult ContentParent::RecvAddOrRemovePageAwakeRequest(
6632 const MaybeDiscarded<BrowsingContext>& aContext,
6633 const bool& aShouldAddCount) {
6634 if (aContext.IsNullOrDiscarded()) {
6635 return IPC_OK();
6636 }
6637 if (aShouldAddCount) {
6638 aContext.get_canonical()->AddPageAwakeRequest();
6639 } else {
6640 aContext.get_canonical()->RemovePageAwakeRequest();
6641 }
6642 return IPC_OK();
6643 }
6644
6645 #if defined(XP_WIN)
RecvGetModulesTrust(ModulePaths && aModPaths,bool aRunAtNormalPriority,GetModulesTrustResolver && aResolver)6646 mozilla::ipc::IPCResult ContentParent::RecvGetModulesTrust(
6647 ModulePaths&& aModPaths, bool aRunAtNormalPriority,
6648 GetModulesTrustResolver&& aResolver) {
6649 RefPtr<DllServices> dllSvc(DllServices::Get());
6650 dllSvc->GetModulesTrust(std::move(aModPaths), aRunAtNormalPriority)
6651 ->Then(
6652 GetMainThreadSerialEventTarget(), __func__,
6653 [aResolver](ModulesMapResult&& aResult) {
6654 aResolver(Some(ModulesMapResult(std::move(aResult))));
6655 },
6656 [aResolver](nsresult aRv) { aResolver(Nothing()); });
6657 return IPC_OK();
6658 }
6659 #endif // defined(XP_WIN)
6660
RecvCreateBrowsingContext(uint64_t aGroupId,BrowsingContext::IPCInitializer && aInit)6661 mozilla::ipc::IPCResult ContentParent::RecvCreateBrowsingContext(
6662 uint64_t aGroupId, BrowsingContext::IPCInitializer&& aInit) {
6663 RefPtr<WindowGlobalParent> parent;
6664 if (aInit.mParentId != 0) {
6665 parent = WindowGlobalParent::GetByInnerWindowId(aInit.mParentId);
6666 if (!parent) {
6667 return IPC_FAIL(this, "Parent doesn't exist in parent process");
6668 }
6669 }
6670
6671 if (parent && parent->GetContentParent() != this) {
6672 // We're trying attach a child BrowsingContext to a parent
6673 // WindowContext in another process. This is illegal since the
6674 // only thing that could create that child BrowsingContext is the parent
6675 // window's process.
6676 return IPC_FAIL(this,
6677 "Must create BrowsingContext from the parent's process");
6678 }
6679
6680 RefPtr<BrowsingContext> opener;
6681 if (aInit.GetOpenerId() != 0) {
6682 opener = BrowsingContext::Get(aInit.GetOpenerId());
6683 if (!opener) {
6684 return IPC_FAIL(this, "Opener doesn't exist in parent process");
6685 }
6686 }
6687
6688 RefPtr<BrowsingContext> child = BrowsingContext::Get(aInit.mId);
6689 if (child) {
6690 // This is highly suspicious. BrowsingContexts should only be created once,
6691 // so finding one indicates that someone is doing something they shouldn't.
6692 return IPC_FAIL(this, "A BrowsingContext with this ID already exists");
6693 }
6694
6695 // Ensure that the passed-in BrowsingContextGroup is valid.
6696 RefPtr<BrowsingContextGroup> group =
6697 BrowsingContextGroup::GetOrCreate(aGroupId);
6698 if (parent && parent->Group() != group) {
6699 if (parent->Group()->Id() != aGroupId) {
6700 return IPC_FAIL(this, "Parent has different group ID");
6701 } else {
6702 return IPC_FAIL(this, "Parent has different group object");
6703 }
6704 }
6705 if (opener && opener->Group() != group) {
6706 if (opener->Group()->Id() != aGroupId) {
6707 return IPC_FAIL(this, "Opener has different group ID");
6708 } else {
6709 return IPC_FAIL(this, "Opener has different group object");
6710 }
6711 }
6712 if (!parent && !opener && !group->Toplevels().IsEmpty()) {
6713 return IPC_FAIL(this, "Unrelated context from child in stale group");
6714 }
6715
6716 BrowsingContext::CreateFromIPC(std::move(aInit), group, this);
6717 return IPC_OK();
6718 }
6719
CheckBrowsingContextEmbedder(CanonicalBrowsingContext * aBC,const char * aOperation) const6720 bool ContentParent::CheckBrowsingContextEmbedder(CanonicalBrowsingContext* aBC,
6721 const char* aOperation) const {
6722 if (!aBC->IsEmbeddedInProcess(ChildID())) {
6723 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
6724 ("ParentIPC: Trying to %s out of process context 0x%08" PRIx64,
6725 aOperation, aBC->Id()));
6726 return false;
6727 }
6728 return true;
6729 }
6730
RecvDiscardBrowsingContext(const MaybeDiscarded<BrowsingContext> & aContext,bool aDoDiscard,DiscardBrowsingContextResolver && aResolve)6731 mozilla::ipc::IPCResult ContentParent::RecvDiscardBrowsingContext(
6732 const MaybeDiscarded<BrowsingContext>& aContext, bool aDoDiscard,
6733 DiscardBrowsingContextResolver&& aResolve) {
6734 if (CanonicalBrowsingContext* context =
6735 CanonicalBrowsingContext::Cast(aContext.GetMaybeDiscarded())) {
6736 if (aDoDiscard && !context->IsDiscarded()) {
6737 if (!CheckBrowsingContextEmbedder(context, "discard")) {
6738 return IPC_FAIL(this, "Illegal Discard attempt");
6739 }
6740
6741 context->Detach(/* aFromIPC */ true);
6742 }
6743 context->AddFinalDiscardListener(aResolve);
6744 return IPC_OK();
6745 }
6746
6747 // Resolve the promise, as we've received and handled the message. This will
6748 // allow the content process to fully-discard references to this BC.
6749 aResolve(true);
6750 return IPC_OK();
6751 }
6752
RegisterRemoteWorkerActor()6753 void ContentParent::RegisterRemoteWorkerActor() {
6754 auto lock = mRemoteWorkerActorData.Lock();
6755 ++lock->mCount;
6756 }
6757
UnregisterRemoveWorkerActor()6758 void ContentParent::UnregisterRemoveWorkerActor() {
6759 MOZ_ASSERT(NS_IsMainThread());
6760
6761 {
6762 auto lock = mRemoteWorkerActorData.Lock();
6763 if (--lock->mCount) {
6764 return;
6765 }
6766 }
6767
6768 MOZ_LOG(ContentParent::GetLog(), LogLevel::Verbose,
6769 ("UnregisterRemoveWorkerActor %p", this));
6770 MaybeBeginShutDown();
6771 }
6772
RecvWindowClose(const MaybeDiscarded<BrowsingContext> & aContext,bool aTrustedCaller)6773 mozilla::ipc::IPCResult ContentParent::RecvWindowClose(
6774 const MaybeDiscarded<BrowsingContext>& aContext, bool aTrustedCaller) {
6775 if (aContext.IsNullOrDiscarded()) {
6776 MOZ_LOG(
6777 BrowsingContext::GetLog(), LogLevel::Debug,
6778 ("ParentIPC: Trying to send a message to dead or detached context"));
6779 return IPC_OK();
6780 }
6781 CanonicalBrowsingContext* context = aContext.get_canonical();
6782
6783 // FIXME Need to check that the sending process has access to the unit of
6784 // related
6785 // browsing contexts of bc.
6786
6787 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
6788 ContentParent* cp =
6789 cpm->GetContentProcessById(ContentParentId(context->OwnerProcessId()));
6790 Unused << cp->SendWindowClose(context, aTrustedCaller);
6791 return IPC_OK();
6792 }
6793
RecvWindowFocus(const MaybeDiscarded<BrowsingContext> & aContext,CallerType aCallerType,uint64_t aActionId)6794 mozilla::ipc::IPCResult ContentParent::RecvWindowFocus(
6795 const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType,
6796 uint64_t aActionId) {
6797 if (aContext.IsNullOrDiscarded()) {
6798 MOZ_LOG(
6799 BrowsingContext::GetLog(), LogLevel::Debug,
6800 ("ParentIPC: Trying to send a message to dead or detached context"));
6801 return IPC_OK();
6802 }
6803 LOGFOCUS(("ContentParent::RecvWindowFocus actionid: %" PRIu64, aActionId));
6804 CanonicalBrowsingContext* context = aContext.get_canonical();
6805
6806 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
6807 ContentParent* cp =
6808 cpm->GetContentProcessById(ContentParentId(context->OwnerProcessId()));
6809 Unused << cp->SendWindowFocus(context, aCallerType, aActionId);
6810 return IPC_OK();
6811 }
6812
RecvWindowBlur(const MaybeDiscarded<BrowsingContext> & aContext,CallerType aCallerType)6813 mozilla::ipc::IPCResult ContentParent::RecvWindowBlur(
6814 const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType) {
6815 if (aContext.IsNullOrDiscarded()) {
6816 MOZ_LOG(
6817 BrowsingContext::GetLog(), LogLevel::Debug,
6818 ("ParentIPC: Trying to send a message to dead or detached context"));
6819 return IPC_OK();
6820 }
6821 CanonicalBrowsingContext* context = aContext.get_canonical();
6822
6823 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
6824 ContentParent* cp =
6825 cpm->GetContentProcessById(ContentParentId(context->OwnerProcessId()));
6826 Unused << cp->SendWindowBlur(context, aCallerType);
6827 return IPC_OK();
6828 }
6829
RecvRaiseWindow(const MaybeDiscarded<BrowsingContext> & aContext,CallerType aCallerType,uint64_t aActionId)6830 mozilla::ipc::IPCResult ContentParent::RecvRaiseWindow(
6831 const MaybeDiscarded<BrowsingContext>& aContext, CallerType aCallerType,
6832 uint64_t aActionId) {
6833 if (aContext.IsNullOrDiscarded()) {
6834 MOZ_LOG(
6835 BrowsingContext::GetLog(), LogLevel::Debug,
6836 ("ParentIPC: Trying to send a message to dead or detached context"));
6837 return IPC_OK();
6838 }
6839 LOGFOCUS(("ContentParent::RecvRaiseWindow actionid: %" PRIu64, aActionId));
6840
6841 CanonicalBrowsingContext* context = aContext.get_canonical();
6842
6843 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
6844 ContentParent* cp =
6845 cpm->GetContentProcessById(ContentParentId(context->OwnerProcessId()));
6846 Unused << cp->SendRaiseWindow(context, aCallerType, aActionId);
6847 return IPC_OK();
6848 }
6849
RecvAdjustWindowFocus(const MaybeDiscarded<BrowsingContext> & aContext,bool aIsVisible,uint64_t aActionId)6850 mozilla::ipc::IPCResult ContentParent::RecvAdjustWindowFocus(
6851 const MaybeDiscarded<BrowsingContext>& aContext, bool aIsVisible,
6852 uint64_t aActionId) {
6853 if (aContext.IsNullOrDiscarded()) {
6854 MOZ_LOG(
6855 BrowsingContext::GetLog(), LogLevel::Debug,
6856 ("ParentIPC: Trying to send a message to dead or detached context"));
6857 return IPC_OK();
6858 }
6859 LOGFOCUS(
6860 ("ContentParent::RecvAdjustWindowFocus isVisible %d actionid: %" PRIu64,
6861 aIsVisible, aActionId));
6862
6863 nsTHashMap<nsPtrHashKey<ContentParent>, bool> processes(2);
6864 processes.InsertOrUpdate(this, true);
6865
6866 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
6867 CanonicalBrowsingContext* context = aContext.get_canonical();
6868 while (context) {
6869 BrowsingContext* parent = context->GetParent();
6870 if (!parent) {
6871 break;
6872 }
6873
6874 CanonicalBrowsingContext* canonicalParent = parent->Canonical();
6875 ContentParent* cp = cpm->GetContentProcessById(
6876 ContentParentId(canonicalParent->OwnerProcessId()));
6877 if (cp && !processes.Get(cp)) {
6878 Unused << cp->SendAdjustWindowFocus(context, aIsVisible, aActionId);
6879 processes.InsertOrUpdate(cp, true);
6880 }
6881 context = canonicalParent;
6882 }
6883 return IPC_OK();
6884 }
6885
RecvClearFocus(const MaybeDiscarded<BrowsingContext> & aContext)6886 mozilla::ipc::IPCResult ContentParent::RecvClearFocus(
6887 const MaybeDiscarded<BrowsingContext>& aContext) {
6888 if (aContext.IsNullOrDiscarded()) {
6889 MOZ_LOG(
6890 BrowsingContext::GetLog(), LogLevel::Debug,
6891 ("ParentIPC: Trying to send a message to dead or detached context"));
6892 return IPC_OK();
6893 }
6894 CanonicalBrowsingContext* context = aContext.get_canonical();
6895
6896 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
6897 ContentParent* cp =
6898 cpm->GetContentProcessById(ContentParentId(context->OwnerProcessId()));
6899 Unused << cp->SendClearFocus(context);
6900 return IPC_OK();
6901 }
6902
RecvSetFocusedBrowsingContext(const MaybeDiscarded<BrowsingContext> & aContext,uint64_t aActionId)6903 mozilla::ipc::IPCResult ContentParent::RecvSetFocusedBrowsingContext(
6904 const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
6905 if (aContext.IsNullOrDiscarded()) {
6906 MOZ_LOG(
6907 BrowsingContext::GetLog(), LogLevel::Debug,
6908 ("ParentIPC: Trying to send a message to dead or detached context"));
6909 return IPC_OK();
6910 }
6911 LOGFOCUS(("ContentParent::RecvSetFocusedBrowsingContext actionid: %" PRIu64,
6912 aActionId));
6913 CanonicalBrowsingContext* context = aContext.get_canonical();
6914
6915 nsFocusManager* fm = nsFocusManager::GetFocusManager();
6916 if (!fm) {
6917 return IPC_OK();
6918 }
6919
6920 if (!fm->SetFocusedBrowsingContextInChrome(context, aActionId)) {
6921 LOGFOCUS((
6922 "Ignoring out-of-sequence attempt [%p] to set focused browsing context "
6923 "in parent.",
6924 context));
6925 Unused << SendReviseFocusedBrowsingContext(
6926 aActionId, fm->GetFocusedBrowsingContextInChrome(),
6927 fm->GetActionIdForFocusedBrowsingContextInChrome());
6928 return IPC_OK();
6929 }
6930
6931 BrowserParent::UpdateFocusFromBrowsingContext();
6932
6933 context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
6934 Unused << aParent->SendSetFocusedBrowsingContext(context, aActionId);
6935 });
6936
6937 return IPC_OK();
6938 }
6939
RecvSetActiveBrowsingContext(const MaybeDiscarded<BrowsingContext> & aContext,uint64_t aActionId)6940 mozilla::ipc::IPCResult ContentParent::RecvSetActiveBrowsingContext(
6941 const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
6942 if (aContext.IsNullOrDiscarded()) {
6943 MOZ_LOG(
6944 BrowsingContext::GetLog(), LogLevel::Debug,
6945 ("ParentIPC: Trying to send a message to dead or detached context"));
6946 return IPC_OK();
6947 }
6948 LOGFOCUS(("ContentParent::RecvSetActiveBrowsingContext actionid: %" PRIu64,
6949 aActionId));
6950 CanonicalBrowsingContext* context = aContext.get_canonical();
6951
6952 nsFocusManager* fm = nsFocusManager::GetFocusManager();
6953 if (!fm) {
6954 return IPC_OK();
6955 }
6956
6957 if (!fm->SetActiveBrowsingContextInChrome(context, aActionId)) {
6958 LOGFOCUS(
6959 ("Ignoring out-of-sequence attempt [%p] to set active browsing context "
6960 "in parent.",
6961 context));
6962 Unused << SendReviseActiveBrowsingContext(
6963 aActionId, fm->GetActiveBrowsingContextInChrome(),
6964 fm->GetActionIdForActiveBrowsingContextInChrome());
6965 return IPC_OK();
6966 }
6967
6968 context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
6969 Unused << aParent->SendSetActiveBrowsingContext(context, aActionId);
6970 });
6971
6972 return IPC_OK();
6973 }
6974
RecvUnsetActiveBrowsingContext(const MaybeDiscarded<BrowsingContext> & aContext,uint64_t aActionId)6975 mozilla::ipc::IPCResult ContentParent::RecvUnsetActiveBrowsingContext(
6976 const MaybeDiscarded<BrowsingContext>& aContext, uint64_t aActionId) {
6977 if (aContext.IsNullOrDiscarded()) {
6978 MOZ_LOG(
6979 BrowsingContext::GetLog(), LogLevel::Debug,
6980 ("ParentIPC: Trying to send a message to dead or detached context"));
6981 return IPC_OK();
6982 }
6983 LOGFOCUS(("ContentParent::RecvUnsetActiveBrowsingContext actionid: %" PRIu64,
6984 aActionId));
6985 CanonicalBrowsingContext* context = aContext.get_canonical();
6986
6987 nsFocusManager* fm = nsFocusManager::GetFocusManager();
6988 if (!fm) {
6989 return IPC_OK();
6990 }
6991
6992 if (!fm->SetActiveBrowsingContextInChrome(nullptr, aActionId)) {
6993 LOGFOCUS(
6994 ("Ignoring out-of-sequence attempt to unset active browsing context in "
6995 "parent [%p].",
6996 context));
6997 Unused << SendReviseActiveBrowsingContext(
6998 aActionId, fm->GetActiveBrowsingContextInChrome(),
6999 fm->GetActionIdForActiveBrowsingContextInChrome());
7000 return IPC_OK();
7001 }
7002
7003 context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
7004 Unused << aParent->SendUnsetActiveBrowsingContext(context, aActionId);
7005 });
7006
7007 return IPC_OK();
7008 }
7009
RecvSetFocusedElement(const MaybeDiscarded<BrowsingContext> & aContext,bool aNeedsFocus)7010 mozilla::ipc::IPCResult ContentParent::RecvSetFocusedElement(
7011 const MaybeDiscarded<BrowsingContext>& aContext, bool aNeedsFocus) {
7012 if (aContext.IsNullOrDiscarded()) {
7013 MOZ_LOG(
7014 BrowsingContext::GetLog(), LogLevel::Debug,
7015 ("ParentIPC: Trying to send a message to dead or detached context"));
7016 return IPC_OK();
7017 }
7018 LOGFOCUS(("ContentParent::RecvSetFocusedElement"));
7019 CanonicalBrowsingContext* context = aContext.get_canonical();
7020
7021 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
7022
7023 ContentParent* cp =
7024 cpm->GetContentProcessById(ContentParentId(context->OwnerProcessId()));
7025 Unused << cp->SendSetFocusedElement(context, aNeedsFocus);
7026
7027 return IPC_OK();
7028 }
7029
RecvFinalizeFocusOuter(const MaybeDiscarded<BrowsingContext> & aContext,bool aCanFocus,CallerType aCallerType)7030 mozilla::ipc::IPCResult ContentParent::RecvFinalizeFocusOuter(
7031 const MaybeDiscarded<BrowsingContext>& aContext, bool aCanFocus,
7032 CallerType aCallerType) {
7033 if (aContext.IsNullOrDiscarded()) {
7034 MOZ_LOG(
7035 BrowsingContext::GetLog(), LogLevel::Debug,
7036 ("ParentIPC: Trying to send a message to dead or detached context"));
7037 return IPC_OK();
7038 }
7039 LOGFOCUS(("ContentParent::RecvFinalizeFocusOuter"));
7040 CanonicalBrowsingContext* context = aContext.get_canonical();
7041 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
7042
7043 ContentParent* cp =
7044 cpm->GetContentProcessById(ContentParentId(context->EmbedderProcessId()));
7045 if (cp) {
7046 Unused << cp->SendFinalizeFocusOuter(context, aCanFocus, aCallerType);
7047 }
7048 return IPC_OK();
7049 }
7050
RecvInsertNewFocusActionId(uint64_t aActionId)7051 mozilla::ipc::IPCResult ContentParent::RecvInsertNewFocusActionId(
7052 uint64_t aActionId) {
7053 LOGFOCUS(("ContentParent::RecvInsertNewFocusActionId actionid: %" PRIu64,
7054 aActionId));
7055 nsFocusManager* fm = nsFocusManager::GetFocusManager();
7056 if (fm) {
7057 fm->InsertNewFocusActionId(aActionId);
7058 }
7059 return IPC_OK();
7060 }
7061
RecvBlurToParent(const MaybeDiscarded<BrowsingContext> & aFocusedBrowsingContext,const MaybeDiscarded<BrowsingContext> & aBrowsingContextToClear,const MaybeDiscarded<BrowsingContext> & aAncestorBrowsingContextToFocus,bool aIsLeavingDocument,bool aAdjustWidget,bool aBrowsingContextToClearHandled,bool aAncestorBrowsingContextToFocusHandled,uint64_t aActionId)7062 mozilla::ipc::IPCResult ContentParent::RecvBlurToParent(
7063 const MaybeDiscarded<BrowsingContext>& aFocusedBrowsingContext,
7064 const MaybeDiscarded<BrowsingContext>& aBrowsingContextToClear,
7065 const MaybeDiscarded<BrowsingContext>& aAncestorBrowsingContextToFocus,
7066 bool aIsLeavingDocument, bool aAdjustWidget,
7067 bool aBrowsingContextToClearHandled,
7068 bool aAncestorBrowsingContextToFocusHandled, uint64_t aActionId) {
7069 if (aFocusedBrowsingContext.IsNullOrDiscarded()) {
7070 MOZ_LOG(
7071 BrowsingContext::GetLog(), LogLevel::Debug,
7072 ("ParentIPC: Trying to send a message to dead or detached context"));
7073 return IPC_OK();
7074 }
7075
7076 LOGFOCUS(
7077 ("ContentParent::RecvBlurToParent isLeavingDocument %d adjustWidget %d "
7078 "browsingContextToClearHandled %d ancestorBrowsingContextToFocusHandled "
7079 "%d actionid: %" PRIu64,
7080 aIsLeavingDocument, aAdjustWidget, aBrowsingContextToClearHandled,
7081 aAncestorBrowsingContextToFocusHandled, aActionId));
7082
7083 CanonicalBrowsingContext* focusedBrowsingContext =
7084 aFocusedBrowsingContext.get_canonical();
7085
7086 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
7087
7088 // If aBrowsingContextToClear and aAncestorBrowsingContextToFocusHandled
7089 // didn't get handled in the process that sent this IPC message and they
7090 // aren't in the same process as aFocusedBrowsingContext, we need to split
7091 // off their handling here and use SendSetFocusedElement to send them
7092 // elsewhere than the blurring itself.
7093
7094 bool ancestorDifferent =
7095 (!aAncestorBrowsingContextToFocusHandled &&
7096 !aAncestorBrowsingContextToFocus.IsNullOrDiscarded() &&
7097 (focusedBrowsingContext->OwnerProcessId() !=
7098 aAncestorBrowsingContextToFocus.get_canonical()->OwnerProcessId()));
7099 if (!aBrowsingContextToClearHandled &&
7100 !aBrowsingContextToClear.IsNullOrDiscarded() &&
7101 (focusedBrowsingContext->OwnerProcessId() !=
7102 aBrowsingContextToClear.get_canonical()->OwnerProcessId())) {
7103 MOZ_RELEASE_ASSERT(!ancestorDifferent,
7104 "This combination is not supposed to happen.");
7105 ContentParent* cp = cpm->GetContentProcessById(ContentParentId(
7106 aBrowsingContextToClear.get_canonical()->OwnerProcessId()));
7107 Unused << cp->SendSetFocusedElement(aBrowsingContextToClear, false);
7108 } else if (ancestorDifferent) {
7109 ContentParent* cp = cpm->GetContentProcessById(ContentParentId(
7110 aAncestorBrowsingContextToFocus.get_canonical()->OwnerProcessId()));
7111 Unused << cp->SendSetFocusedElement(aAncestorBrowsingContextToFocus, true);
7112 }
7113
7114 ContentParent* cp = cpm->GetContentProcessById(
7115 ContentParentId(focusedBrowsingContext->OwnerProcessId()));
7116 Unused << cp->SendBlurToChild(aFocusedBrowsingContext,
7117 aBrowsingContextToClear,
7118 aAncestorBrowsingContextToFocus,
7119 aIsLeavingDocument, aAdjustWidget, aActionId);
7120 return IPC_OK();
7121 }
7122
RecvMaybeExitFullscreen(const MaybeDiscarded<BrowsingContext> & aContext)7123 mozilla::ipc::IPCResult ContentParent::RecvMaybeExitFullscreen(
7124 const MaybeDiscarded<BrowsingContext>& aContext) {
7125 if (aContext.IsNullOrDiscarded()) {
7126 MOZ_LOG(
7127 BrowsingContext::GetLog(), LogLevel::Debug,
7128 ("ParentIPC: Trying to send a message to dead or detached context"));
7129 return IPC_OK();
7130 }
7131 CanonicalBrowsingContext* context = aContext.get_canonical();
7132
7133 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
7134
7135 ContentParent* cp =
7136 cpm->GetContentProcessById(ContentParentId(context->OwnerProcessId()));
7137 Unused << cp->SendMaybeExitFullscreen(context);
7138
7139 return IPC_OK();
7140 }
7141
RecvWindowPostMessage(const MaybeDiscarded<BrowsingContext> & aContext,const ClonedOrErrorMessageData & aMessage,const PostMessageData & aData)7142 mozilla::ipc::IPCResult ContentParent::RecvWindowPostMessage(
7143 const MaybeDiscarded<BrowsingContext>& aContext,
7144 const ClonedOrErrorMessageData& aMessage, const PostMessageData& aData) {
7145 if (aContext.IsNullOrDiscarded()) {
7146 MOZ_LOG(
7147 BrowsingContext::GetLog(), LogLevel::Debug,
7148 ("ParentIPC: Trying to send a message to dead or detached context"));
7149 return IPC_OK();
7150 }
7151 CanonicalBrowsingContext* context = aContext.get_canonical();
7152
7153 if (aData.source().IsDiscarded()) {
7154 MOZ_LOG(
7155 BrowsingContext::GetLog(), LogLevel::Debug,
7156 ("ParentIPC: Trying to send a message from dead or detached context"));
7157 return IPC_OK();
7158 }
7159
7160 RefPtr<ContentParent> cp = context->GetContentParent();
7161 if (!cp) {
7162 MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
7163 ("ParentIPC: Trying to send PostMessage to dead content process"));
7164 return IPC_OK();
7165 }
7166
7167 ClonedOrErrorMessageData message;
7168 StructuredCloneData messageFromChild;
7169 if (aMessage.type() == ClonedOrErrorMessageData::TClonedMessageData) {
7170 UnpackClonedMessageDataForParent(aMessage, messageFromChild);
7171
7172 ClonedMessageData clonedMessageData;
7173 if (BuildClonedMessageDataForParent(cp, messageFromChild,
7174 clonedMessageData)) {
7175 message = std::move(clonedMessageData);
7176 } else {
7177 // FIXME Logging?
7178 message = ErrorMessageData();
7179 }
7180 } else {
7181 MOZ_ASSERT(aMessage.type() == ClonedOrErrorMessageData::TErrorMessageData);
7182 message = ErrorMessageData();
7183 }
7184
7185 Unused << cp->SendWindowPostMessage(context, message, aData);
7186 return IPC_OK();
7187 }
7188
AddBrowsingContextGroup(BrowsingContextGroup * aGroup)7189 void ContentParent::AddBrowsingContextGroup(BrowsingContextGroup* aGroup) {
7190 MOZ_DIAGNOSTIC_ASSERT(aGroup);
7191 // Ensure that the group has been inserted, and if we're not launching
7192 // anymore, also begin subscribing. Launching processes will be subscribed if
7193 // they finish launching in `LaunchSubprocessResolve`.
7194 if (mGroups.EnsureInserted(aGroup) && !IsLaunching()) {
7195 aGroup->Subscribe(this);
7196 }
7197 }
7198
RemoveBrowsingContextGroup(BrowsingContextGroup * aGroup)7199 void ContentParent::RemoveBrowsingContextGroup(BrowsingContextGroup* aGroup) {
7200 MOZ_DIAGNOSTIC_ASSERT(aGroup);
7201 // Remove the group from our list. This is called from the
7202 // BrowsingContextGroup when unsubscribing, so we don't need to do it here.
7203 if (mGroups.EnsureRemoved(aGroup) && CanSend()) {
7204 // If we're removing the entry for the first time, tell the content process
7205 // to clean up the group.
7206 Unused << SendDestroyBrowsingContextGroup(aGroup->Id());
7207 }
7208 }
7209
RecvCommitBrowsingContextTransaction(const MaybeDiscarded<BrowsingContext> & aContext,BrowsingContext::BaseTransaction && aTransaction,uint64_t aEpoch)7210 mozilla::ipc::IPCResult ContentParent::RecvCommitBrowsingContextTransaction(
7211 const MaybeDiscarded<BrowsingContext>& aContext,
7212 BrowsingContext::BaseTransaction&& aTransaction, uint64_t aEpoch) {
7213 // Record the new BrowsingContextFieldEpoch associated with this transaction.
7214 // This should be done unconditionally, so that we're always in-sync.
7215 //
7216 // The order the parent process receives transactions is considered the
7217 // "canonical" ordering, so we don't need to worry about doing any
7218 // epoch-related validation.
7219 MOZ_ASSERT(aEpoch == mBrowsingContextFieldEpoch + 1,
7220 "Child process skipped an epoch?");
7221 mBrowsingContextFieldEpoch = aEpoch;
7222
7223 return aTransaction.CommitFromIPC(aContext, this);
7224 }
7225
SendPParentToChildStreamConstructor(PParentToChildStreamParent * aActor)7226 PParentToChildStreamParent* ContentParent::SendPParentToChildStreamConstructor(
7227 PParentToChildStreamParent* aActor) {
7228 MOZ_ASSERT(NS_IsMainThread());
7229 return PContentParent::SendPParentToChildStreamConstructor(aActor);
7230 }
7231
SendPFileDescriptorSetConstructor(const FileDescriptor & aFD)7232 PFileDescriptorSetParent* ContentParent::SendPFileDescriptorSetConstructor(
7233 const FileDescriptor& aFD) {
7234 MOZ_ASSERT(NS_IsMainThread());
7235 return PContentParent::SendPFileDescriptorSetConstructor(aFD);
7236 }
7237
RecvBlobURLDataRequest(const nsCString & aBlobURL,nsIPrincipal * aTriggeringPrincipal,nsIPrincipal * aLoadingPrincipal,const OriginAttributes & aOriginAttributes,uint64_t aInnerWindowId,const Maybe<nsID> & aAgentClusterId,BlobURLDataRequestResolver && aResolver)7238 mozilla::ipc::IPCResult ContentParent::RecvBlobURLDataRequest(
7239 const nsCString& aBlobURL, nsIPrincipal* aTriggeringPrincipal,
7240 nsIPrincipal* aLoadingPrincipal, const OriginAttributes& aOriginAttributes,
7241 uint64_t aInnerWindowId, const Maybe<nsID>& aAgentClusterId,
7242 BlobURLDataRequestResolver&& aResolver) {
7243 RefPtr<BlobImpl> blobImpl;
7244
7245 // Since revoked blobs are also retrieved, it is possible that the blob no
7246 // longer exists (due to the 5 second timeout) when execution reaches here
7247 if (!BlobURLProtocolHandler::GetDataEntry(
7248 aBlobURL, getter_AddRefs(blobImpl), aLoadingPrincipal,
7249 aTriggeringPrincipal, aOriginAttributes, aInnerWindowId,
7250 aAgentClusterId, true /* AlsoIfRevoked */)) {
7251 aResolver(NS_ERROR_DOM_BAD_URI);
7252 return IPC_OK();
7253 }
7254
7255 IPCBlob ipcBlob;
7256 nsresult rv = IPCBlobUtils::Serialize(blobImpl, this, ipcBlob);
7257
7258 if (NS_WARN_IF(NS_FAILED(rv))) {
7259 aResolver(rv);
7260 return IPC_OK();
7261 }
7262
7263 aResolver(ipcBlob);
7264 return IPC_OK();
7265 }
7266
RecvReportServiceWorkerShutdownProgress(uint32_t aShutdownStateId,ServiceWorkerShutdownState::Progress aProgress)7267 mozilla::ipc::IPCResult ContentParent::RecvReportServiceWorkerShutdownProgress(
7268 uint32_t aShutdownStateId, ServiceWorkerShutdownState::Progress aProgress) {
7269 RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
7270 MOZ_RELEASE_ASSERT(swm, "ServiceWorkers should shutdown before SWM.");
7271
7272 swm->ReportServiceWorkerShutdownProgress(aShutdownStateId, aProgress);
7273
7274 return IPC_OK();
7275 }
7276
RecvNotifyOnHistoryReload(const MaybeDiscarded<BrowsingContext> & aContext,const bool & aForceReload,NotifyOnHistoryReloadResolver && aResolver)7277 mozilla::ipc::IPCResult ContentParent::RecvNotifyOnHistoryReload(
7278 const MaybeDiscarded<BrowsingContext>& aContext, const bool& aForceReload,
7279 NotifyOnHistoryReloadResolver&& aResolver) {
7280 bool canReload = false;
7281 Maybe<RefPtr<nsDocShellLoadState>> loadState;
7282 Maybe<bool> reloadActiveEntry;
7283 if (!aContext.IsDiscarded()) {
7284 aContext.get_canonical()->NotifyOnHistoryReload(
7285 aForceReload, canReload, loadState, reloadActiveEntry);
7286 }
7287 aResolver(Tuple<const bool&, const Maybe<RefPtr<nsDocShellLoadState>>&,
7288 const Maybe<bool>&>(canReload, loadState, reloadActiveEntry));
7289 return IPC_OK();
7290 }
7291
RecvHistoryCommit(const MaybeDiscarded<BrowsingContext> & aContext,const uint64_t & aLoadID,const nsID & aChangeID,const uint32_t & aLoadType,const bool & aPersist,const bool & aCloneEntryChildren,const bool & aChannelExpired,const uint32_t & aCacheKey)7292 mozilla::ipc::IPCResult ContentParent::RecvHistoryCommit(
7293 const MaybeDiscarded<BrowsingContext>& aContext, const uint64_t& aLoadID,
7294 const nsID& aChangeID, const uint32_t& aLoadType, const bool& aPersist,
7295 const bool& aCloneEntryChildren, const bool& aChannelExpired,
7296 const uint32_t& aCacheKey) {
7297 if (!aContext.IsDiscarded()) {
7298 aContext.get_canonical()->SessionHistoryCommit(
7299 aLoadID, aChangeID, aLoadType, aPersist, aCloneEntryChildren,
7300 aChannelExpired, aCacheKey);
7301 }
7302
7303 return IPC_OK();
7304 }
7305
RecvHistoryGo(const MaybeDiscarded<BrowsingContext> & aContext,int32_t aOffset,uint64_t aHistoryEpoch,bool aRequireUserInteraction,bool aUserActivation,HistoryGoResolver && aResolveRequestedIndex)7306 mozilla::ipc::IPCResult ContentParent::RecvHistoryGo(
7307 const MaybeDiscarded<BrowsingContext>& aContext, int32_t aOffset,
7308 uint64_t aHistoryEpoch, bool aRequireUserInteraction, bool aUserActivation,
7309 HistoryGoResolver&& aResolveRequestedIndex) {
7310 if (!aContext.IsDiscarded()) {
7311 aContext.get_canonical()->HistoryGo(
7312 aOffset, aHistoryEpoch, aRequireUserInteraction, aUserActivation,
7313 Some(ChildID()), std::move(aResolveRequestedIndex));
7314 }
7315 return IPC_OK();
7316 }
7317
RecvSynchronizeLayoutHistoryState(const MaybeDiscarded<BrowsingContext> & aContext,nsILayoutHistoryState * aState)7318 mozilla::ipc::IPCResult ContentParent::RecvSynchronizeLayoutHistoryState(
7319 const MaybeDiscarded<BrowsingContext>& aContext,
7320 nsILayoutHistoryState* aState) {
7321 if (aContext.IsNull()) {
7322 return IPC_OK();
7323 }
7324
7325 SessionHistoryEntry* entry =
7326 aContext.GetMaybeDiscarded()->Canonical()->GetActiveSessionHistoryEntry();
7327 if (entry) {
7328 entry->SetLayoutHistoryState(aState);
7329 }
7330 return IPC_OK();
7331 }
7332
RecvSessionHistoryEntryTitle(const MaybeDiscarded<BrowsingContext> & aContext,const nsString & aTitle)7333 mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryTitle(
7334 const MaybeDiscarded<BrowsingContext>& aContext, const nsString& aTitle) {
7335 if (aContext.IsNullOrDiscarded()) {
7336 return IPC_OK();
7337 }
7338
7339 SessionHistoryEntry* entry =
7340 aContext.get_canonical()->GetActiveSessionHistoryEntry();
7341 if (entry) {
7342 entry->SetTitle(aTitle);
7343 }
7344 return IPC_OK();
7345 }
7346
7347 mozilla::ipc::IPCResult
RecvSessionHistoryEntryScrollRestorationIsManual(const MaybeDiscarded<BrowsingContext> & aContext,const bool & aIsManual)7348 ContentParent::RecvSessionHistoryEntryScrollRestorationIsManual(
7349 const MaybeDiscarded<BrowsingContext>& aContext, const bool& aIsManual) {
7350 if (aContext.IsNullOrDiscarded()) {
7351 return IPC_OK();
7352 }
7353
7354 SessionHistoryEntry* entry =
7355 aContext.get_canonical()->GetActiveSessionHistoryEntry();
7356 if (entry) {
7357 entry->SetScrollRestorationIsManual(aIsManual);
7358 }
7359 return IPC_OK();
7360 }
7361
RecvSessionHistoryEntryScrollPosition(const MaybeDiscarded<BrowsingContext> & aContext,const int32_t & aX,const int32_t & aY)7362 mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryScrollPosition(
7363 const MaybeDiscarded<BrowsingContext>& aContext, const int32_t& aX,
7364 const int32_t& aY) {
7365 if (aContext.IsNullOrDiscarded()) {
7366 return IPC_OK();
7367 }
7368
7369 SessionHistoryEntry* entry =
7370 aContext.get_canonical()->GetActiveSessionHistoryEntry();
7371 if (entry) {
7372 entry->SetScrollPosition(aX, aY);
7373 }
7374 return IPC_OK();
7375 }
7376
7377 mozilla::ipc::IPCResult
RecvSessionHistoryEntryStoreWindowNameInContiguousEntries(const MaybeDiscarded<BrowsingContext> & aContext,const nsString & aName)7378 ContentParent::RecvSessionHistoryEntryStoreWindowNameInContiguousEntries(
7379 const MaybeDiscarded<BrowsingContext>& aContext, const nsString& aName) {
7380 if (aContext.IsNullOrDiscarded()) {
7381 return IPC_OK();
7382 }
7383
7384 // Per https://html.spec.whatwg.org/#history-traversal 4.2.1, we need to set
7385 // the name to all contiguous entries. This has to be called before
7386 // CanonicalBrowsingContext::SessionHistoryCommit(), so the active entry is
7387 // still the old entry that we want to set.
7388
7389 SessionHistoryEntry* entry =
7390 aContext.get_canonical()->GetActiveSessionHistoryEntry();
7391
7392 if (entry) {
7393 nsSHistory::WalkContiguousEntries(
7394 entry, [&](nsISHEntry* aEntry) { aEntry->SetName(aName); });
7395 }
7396
7397 return IPC_OK();
7398 }
7399
RecvSessionHistoryEntryCacheKey(const MaybeDiscarded<BrowsingContext> & aContext,const uint32_t & aCacheKey)7400 mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryCacheKey(
7401 const MaybeDiscarded<BrowsingContext>& aContext,
7402 const uint32_t& aCacheKey) {
7403 if (aContext.IsNullOrDiscarded()) {
7404 return IPC_OK();
7405 }
7406
7407 SessionHistoryEntry* entry =
7408 aContext.get_canonical()->GetActiveSessionHistoryEntry();
7409 if (entry) {
7410 entry->SetCacheKey(aCacheKey);
7411 }
7412 return IPC_OK();
7413 }
7414
RecvSessionHistoryEntryWireframe(const MaybeDiscarded<BrowsingContext> & aContext,const Wireframe & aWireframe)7415 mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryWireframe(
7416 const MaybeDiscarded<BrowsingContext>& aContext,
7417 const Wireframe& aWireframe) {
7418 if (aContext.IsNullOrDiscarded()) {
7419 return IPC_OK();
7420 }
7421
7422 SessionHistoryEntry* entry =
7423 aContext.get_canonical()->GetActiveSessionHistoryEntry();
7424 if (entry) {
7425 entry->SetWireframe(Some(aWireframe));
7426 }
7427 return IPC_OK();
7428 }
7429
7430 mozilla::ipc::IPCResult
RecvGetLoadingSessionHistoryInfoFromParent(const MaybeDiscarded<BrowsingContext> & aContext,GetLoadingSessionHistoryInfoFromParentResolver && aResolver)7431 ContentParent::RecvGetLoadingSessionHistoryInfoFromParent(
7432 const MaybeDiscarded<BrowsingContext>& aContext,
7433 GetLoadingSessionHistoryInfoFromParentResolver&& aResolver) {
7434 if (aContext.IsNullOrDiscarded()) {
7435 return IPC_OK();
7436 }
7437
7438 Maybe<LoadingSessionHistoryInfo> info;
7439 aContext.get_canonical()->GetLoadingSessionHistoryInfoFromParent(info);
7440 aResolver(info);
7441
7442 return IPC_OK();
7443 }
7444
RecvRemoveFromBFCache(const MaybeDiscarded<BrowsingContext> & aContext)7445 mozilla::ipc::IPCResult ContentParent::RecvRemoveFromBFCache(
7446 const MaybeDiscarded<BrowsingContext>& aContext) {
7447 if (aContext.IsNullOrDiscarded()) {
7448 return IPC_OK();
7449 }
7450
7451 nsCOMPtr<nsFrameLoaderOwner> owner =
7452 do_QueryInterface(aContext.get_canonical()->GetEmbedderElement());
7453 if (!owner) {
7454 return IPC_OK();
7455 }
7456
7457 RefPtr<nsFrameLoader> frameLoader = owner->GetFrameLoader();
7458 if (!frameLoader || !frameLoader->GetMaybePendingBrowsingContext()) {
7459 return IPC_OK();
7460 }
7461
7462 nsCOMPtr<nsISHistory> shistory = frameLoader->GetMaybePendingBrowsingContext()
7463 ->Canonical()
7464 ->GetSessionHistory();
7465 if (!shistory) {
7466 return IPC_OK();
7467 }
7468
7469 uint32_t count = shistory->GetCount();
7470 for (uint32_t i = 0; i < count; ++i) {
7471 nsCOMPtr<nsISHEntry> entry;
7472 shistory->GetEntryAtIndex(i, getter_AddRefs(entry));
7473 nsCOMPtr<SessionHistoryEntry> she = do_QueryInterface(entry);
7474 if (she) {
7475 if (RefPtr<nsFrameLoader> frameLoader = she->GetFrameLoader()) {
7476 if (frameLoader->GetMaybePendingBrowsingContext() == aContext.get()) {
7477 she->SetFrameLoader(nullptr);
7478 frameLoader->Destroy();
7479 break;
7480 }
7481 }
7482 }
7483 }
7484
7485 return IPC_OK();
7486 }
7487
RecvSetActiveSessionHistoryEntry(const MaybeDiscarded<BrowsingContext> & aContext,const Maybe<nsPoint> & aPreviousScrollPos,SessionHistoryInfo && aInfo,uint32_t aLoadType,uint32_t aUpdatedCacheKey,const nsID & aChangeID)7488 mozilla::ipc::IPCResult ContentParent::RecvSetActiveSessionHistoryEntry(
7489 const MaybeDiscarded<BrowsingContext>& aContext,
7490 const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo&& aInfo,
7491 uint32_t aLoadType, uint32_t aUpdatedCacheKey, const nsID& aChangeID) {
7492 if (!aContext.IsDiscarded()) {
7493 aContext.get_canonical()->SetActiveSessionHistoryEntry(
7494 aPreviousScrollPos, &aInfo, aLoadType, aUpdatedCacheKey, aChangeID);
7495 }
7496 return IPC_OK();
7497 }
7498
RecvReplaceActiveSessionHistoryEntry(const MaybeDiscarded<BrowsingContext> & aContext,SessionHistoryInfo && aInfo)7499 mozilla::ipc::IPCResult ContentParent::RecvReplaceActiveSessionHistoryEntry(
7500 const MaybeDiscarded<BrowsingContext>& aContext,
7501 SessionHistoryInfo&& aInfo) {
7502 if (!aContext.IsDiscarded()) {
7503 aContext.get_canonical()->ReplaceActiveSessionHistoryEntry(&aInfo);
7504 }
7505 return IPC_OK();
7506 }
7507
7508 mozilla::ipc::IPCResult
RecvRemoveDynEntriesFromActiveSessionHistoryEntry(const MaybeDiscarded<BrowsingContext> & aContext)7509 ContentParent::RecvRemoveDynEntriesFromActiveSessionHistoryEntry(
7510 const MaybeDiscarded<BrowsingContext>& aContext) {
7511 if (!aContext.IsDiscarded()) {
7512 aContext.get_canonical()->RemoveDynEntriesFromActiveSessionHistoryEntry();
7513 }
7514 return IPC_OK();
7515 }
7516
RecvRemoveFromSessionHistory(const MaybeDiscarded<BrowsingContext> & aContext,const nsID & aChangeID)7517 mozilla::ipc::IPCResult ContentParent::RecvRemoveFromSessionHistory(
7518 const MaybeDiscarded<BrowsingContext>& aContext, const nsID& aChangeID) {
7519 if (!aContext.IsDiscarded()) {
7520 aContext.get_canonical()->RemoveFromSessionHistory(aChangeID);
7521 }
7522 return IPC_OK();
7523 }
7524
RecvHistoryReload(const MaybeDiscarded<BrowsingContext> & aContext,const uint32_t aReloadFlags)7525 mozilla::ipc::IPCResult ContentParent::RecvHistoryReload(
7526 const MaybeDiscarded<BrowsingContext>& aContext,
7527 const uint32_t aReloadFlags) {
7528 if (!aContext.IsDiscarded()) {
7529 nsISHistory* shistory = aContext.get_canonical()->GetSessionHistory();
7530 if (shistory) {
7531 shistory->Reload(aReloadFlags);
7532 }
7533 }
7534 return IPC_OK();
7535 }
7536
RecvCommitWindowContextTransaction(const MaybeDiscarded<WindowContext> & aContext,WindowContext::BaseTransaction && aTransaction,uint64_t aEpoch)7537 mozilla::ipc::IPCResult ContentParent::RecvCommitWindowContextTransaction(
7538 const MaybeDiscarded<WindowContext>& aContext,
7539 WindowContext::BaseTransaction&& aTransaction, uint64_t aEpoch) {
7540 // Record the new BrowsingContextFieldEpoch associated with this transaction.
7541 // This should be done unconditionally, so that we're always in-sync.
7542 //
7543 // The order the parent process receives transactions is considered the
7544 // "canonical" ordering, so we don't need to worry about doing any
7545 // epoch-related validation.
7546 MOZ_ASSERT(aEpoch == mBrowsingContextFieldEpoch + 1,
7547 "Child process skipped an epoch?");
7548 mBrowsingContextFieldEpoch = aEpoch;
7549
7550 return aTransaction.CommitFromIPC(aContext, this);
7551 }
7552
GetChildID(uint64_t * aOut)7553 NS_IMETHODIMP ContentParent::GetChildID(uint64_t* aOut) {
7554 *aOut = this->ChildID();
7555 return NS_OK;
7556 }
7557
GetOsPid(int32_t * aOut)7558 NS_IMETHODIMP ContentParent::GetOsPid(int32_t* aOut) {
7559 *aOut = Pid();
7560 return NS_OK;
7561 }
7562
GetRemoteType(nsACString & aRemoteType)7563 NS_IMETHODIMP ContentParent::GetRemoteType(nsACString& aRemoteType) {
7564 aRemoteType = GetRemoteType();
7565 return NS_OK;
7566 }
7567
RecvRawMessage(const JSActorMessageMeta & aMeta,const Maybe<ClonedMessageData> & aData,const Maybe<ClonedMessageData> & aStack)7568 IPCResult ContentParent::RecvRawMessage(
7569 const JSActorMessageMeta& aMeta, const Maybe<ClonedMessageData>& aData,
7570 const Maybe<ClonedMessageData>& aStack) {
7571 Maybe<StructuredCloneData> data;
7572 if (aData) {
7573 data.emplace();
7574 data->BorrowFromClonedMessageDataForParent(*aData);
7575 }
7576 Maybe<StructuredCloneData> stack;
7577 if (aStack) {
7578 stack.emplace();
7579 stack->BorrowFromClonedMessageDataForParent(*aStack);
7580 }
7581 ReceiveRawMessage(aMeta, std::move(data), std::move(stack));
7582 return IPC_OK();
7583 }
7584
GetActor(const nsACString & aName,JSContext * aCx,JSProcessActorParent ** retval)7585 NS_IMETHODIMP ContentParent::GetActor(const nsACString& aName, JSContext* aCx,
7586 JSProcessActorParent** retval) {
7587 ErrorResult error;
7588 RefPtr<JSProcessActorParent> actor =
7589 JSActorManager::GetActor(aCx, aName, error)
7590 .downcast<JSProcessActorParent>();
7591 if (error.MaybeSetPendingException(aCx)) {
7592 return NS_ERROR_FAILURE;
7593 }
7594 actor.forget(retval);
7595 return NS_OK;
7596 }
7597
GetExistingActor(const nsACString & aName,JSProcessActorParent ** retval)7598 NS_IMETHODIMP ContentParent::GetExistingActor(const nsACString& aName,
7599 JSProcessActorParent** retval) {
7600 RefPtr<JSProcessActorParent> actor =
7601 JSActorManager::GetExistingActor(aName).downcast<JSProcessActorParent>();
7602 actor.forget(retval);
7603 return NS_OK;
7604 }
7605
InitJSActor(JS::HandleObject aMaybeActor,const nsACString & aName,ErrorResult & aRv)7606 already_AddRefed<JSActor> ContentParent::InitJSActor(
7607 JS::HandleObject aMaybeActor, const nsACString& aName, ErrorResult& aRv) {
7608 RefPtr<JSProcessActorParent> actor;
7609 if (aMaybeActor.get()) {
7610 aRv = UNWRAP_OBJECT(JSProcessActorParent, aMaybeActor.get(), actor);
7611 if (aRv.Failed()) {
7612 return nullptr;
7613 }
7614 } else {
7615 actor = new JSProcessActorParent();
7616 }
7617
7618 MOZ_RELEASE_ASSERT(!actor->Manager(),
7619 "mManager was already initialized once!");
7620 actor->Init(aName, this);
7621 return actor.forget();
7622 }
7623
RecvFOGData(ByteBuf && buf)7624 IPCResult ContentParent::RecvFOGData(ByteBuf&& buf) {
7625 glean::FOGData(std::move(buf));
7626 return IPC_OK();
7627 }
7628
RecvSetContainerFeaturePolicy(const MaybeDiscardedBrowsingContext & aContainerContext,FeaturePolicy * aContainerFeaturePolicy)7629 mozilla::ipc::IPCResult ContentParent::RecvSetContainerFeaturePolicy(
7630 const MaybeDiscardedBrowsingContext& aContainerContext,
7631 FeaturePolicy* aContainerFeaturePolicy) {
7632 if (aContainerContext.IsNullOrDiscarded()) {
7633 return IPC_OK();
7634 }
7635
7636 auto* context = aContainerContext.get_canonical();
7637 context->SetContainerFeaturePolicy(aContainerFeaturePolicy);
7638
7639 return IPC_OK();
7640 }
7641
GetCanSend(bool * aCanSend)7642 NS_IMETHODIMP ContentParent::GetCanSend(bool* aCanSend) {
7643 *aCanSend = CanSend();
7644 return NS_OK;
7645 }
7646
AsContentParent()7647 ContentParent* ContentParent::AsContentParent() { return this; }
7648
AsJSActorManager()7649 JSActorManager* ContentParent::AsJSActorManager() { return this; }
7650
7651 /* static */
DidLaunchSubprocess()7652 void ContentParent::DidLaunchSubprocess() {
7653 TimeStamp now = TimeStamp::Now();
7654 uint32_t count = 0;
7655 for (auto* parent : ContentParent::AllProcesses(ContentParent::eLive)) {
7656 Unused << parent;
7657 count += 1;
7658 }
7659
7660 if (count > sMaxContentProcesses) {
7661 sMaxContentProcesses = count;
7662
7663 Telemetry::ScalarSet(Telemetry::ScalarID::CONTENT_PROCESS_MAX_PRECISE,
7664 count);
7665 }
7666
7667 if (sLastContentProcessLaunch) {
7668 TimeStamp last = *sLastContentProcessLaunch;
7669
7670 Telemetry::AccumulateTimeDelta(
7671 Telemetry::CONTENT_PROCESS_TIME_SINCE_LAST_LAUNCH_MS, last, now);
7672 }
7673 sLastContentProcessLaunch = Some(now);
7674 }
7675
RecvGetSystemIcon(nsIURI * aURI,GetSystemIconResolver && aResolver)7676 IPCResult ContentParent::RecvGetSystemIcon(nsIURI* aURI,
7677 GetSystemIconResolver&& aResolver) {
7678 #if defined(MOZ_WIDGET_GTK)
7679 Maybe<ByteBuf> bytebuf = Some(ByteBuf{});
7680 nsresult rv = nsIconChannel::GetIcon(aURI, bytebuf.ptr());
7681 if (NS_WARN_IF(NS_FAILED(rv))) {
7682 bytebuf = Nothing();
7683 }
7684 using ResolverArgs = Tuple<const nsresult&, mozilla::Maybe<ByteBuf>&&>;
7685 aResolver(ResolverArgs(rv, std::move(bytebuf)));
7686 return IPC_OK();
7687 #elif defined(XP_WIN)
7688 using ResolverArgs = Tuple<const nsresult&, mozilla::Maybe<ByteBuf>&&>;
7689 nsIconChannel::GetIconAsync(aURI)->Then(
7690 GetCurrentSerialEventTarget(), __func__,
7691 [aResolver](ByteBuf&& aByteBuf) {
7692 Maybe<ByteBuf> bytebuf = Some(std::move(aByteBuf));
7693 aResolver(ResolverArgs(NS_OK, std::move(bytebuf)));
7694 },
7695 [aResolver](nsresult aErr) {
7696 Maybe<ByteBuf> bytebuf = Nothing();
7697 aResolver(ResolverArgs(aErr, std::move(bytebuf)));
7698 });
7699 return IPC_OK();
7700 #else
7701 MOZ_CRASH(
7702 "This message is currently implemented only on GTK and Windows "
7703 "platforms");
7704 #endif
7705 }
7706
7707 } // namespace dom
7708 } // namespace mozilla
7709
NS_IMPL_ISUPPORTS(ParentIdleListener,nsIObserver)7710 NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
7711
7712 NS_IMETHODIMP
7713 ParentIdleListener::Observe(nsISupports*, const char* aTopic,
7714 const char16_t* aData) {
7715 mozilla::Unused << mParent->SendNotifyIdleObserver(
7716 mObserver, nsDependentCString(aTopic), nsDependentString(aData));
7717 return NS_OK;
7718 }
7719