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