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