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